Index: src/utils/SkHashDigest.h |
=================================================================== |
--- src/utils/SkHashDigest.h (revision 0) |
+++ src/utils/SkHashDigest.h (revision 0) |
@@ -0,0 +1,149 @@ |
+/* |
+ * Copyright 2013 Google Inc. |
+ * |
+ * Use of this source code is governed by a BSD-style license that can be |
+ * found in the LICENSE file. |
+ */ |
+ |
+#ifndef SkHashDigest_DEFINED |
+#define SkHashDigest_DEFINED |
+ |
+#include "SkData.h" |
+#include "SkRefCnt.h" |
+#include "SkString.h" |
+ |
+/** |
+ * A mutable hash digest; it can be filled with a bytearray of any |
+ * length, anytime. |
+ */ |
+class SkHashDigest { |
+public: |
+ SkHashDigest() : fSkDataRef(SkData::NewEmpty()) {} |
+ SkHashDigest(const void *data, size_t length) : fSkDataRef(SkData::NewWithCopy(data, length)) {} |
+ |
+ /** |
+ * Destructor: if this object is the only one with a reference to the data |
+ * that makes up the hash digest, then that data will be freed. |
+ */ |
+ ~SkHashDigest() { |
+ } |
+ |
+ /** |
+ * Replace the hash digest data held by this object with a copy of the |
+ * data from this pointer/length. |
+ */ |
+ void copyFrom(const void *data, size_t length) { |
+ fSkDataRef = SkData::NewWithCopy(data, length); |
+ } |
+ |
+ /** |
+ * Convert a single hexadecimal character [0-9a-fA-F] into its integer value |
+ * |
+ * @param c the hexadecimal character to convert |
+ * @param result where the integer value will be written |
+ * Returns true if the conversion succeeded. |
+ */ |
+ static bool hexCharValue(const char c, uint8_t *result) { |
+ if ((c >= '0') && (c <= '9')) { |
+ *result = c - '0'; |
+ } else if ((c >= 'a') && (c <= 'f')) { |
+ *result = c - ('a' - 10); |
+ } else if ((c >= 'A') && (c <= 'F')) { |
+ *result = c - ('A' - 10); |
+ } else { |
+ // EPOGER: add unittest that exercises this |
+ SkDEBUGF(("unrecognized hexChar '%c'\n", c)); |
+ return false; |
+ } |
+ return true; |
+ } |
+ |
+ /** |
+ * Fill in the hash digest data from a null-terminated hexadecimal string. |
+ * |
+ * Returns true if it was able to properly parse the hexadecimal string. |
+ */ |
+ bool copyFromHexString(const char *hexString) { |
+ const int stringLen = strlen(hexString); |
+ if (0 != stringLen % 2) { |
+ // EPOGER: add unittest that exercises this |
+ SkDEBUGF(("hexString '%s' has odd length %d\n", hexString, stringLen)); |
+ return false; |
+ } |
+ const int digestLen = stringLen / 2; |
+ |
+ // EPOGER: rewrite in a way that doesn't need this temporary array and memcpy? |
+ uint8_t digest[digestLen]; |
+ uint8_t *digestPtr = digest; |
+ uint8_t *pastDigestEnd = digest + digestLen; |
+ const char *hexStringPtr = hexString; |
+ while (digestPtr < pastDigestEnd) { |
+ uint8_t nybble1, nybble2; |
+ if (!hexCharValue(*hexStringPtr++, &nybble1)) { |
+ return false; |
+ } |
+ if (!hexCharValue(*hexStringPtr++, &nybble2)) { |
+ return false; |
+ } |
+ *digestPtr++ = (nybble1 << 4) + nybble2; |
+ } |
+ |
+ this->copyFrom(digest, digestLen); |
+ return true; |
+ } |
+ |
+ /** |
+ * Return a pointer to the SkData object holding the hash digest data. |
+ * |
+ * The SkData object's reference counter will be bumped to account for this call, |
+ * so the caller must call unref() on it once it is no longer needed! |
+ * |
+ * For example: |
+ * { |
+ * SkData *skDataPtr = digest.skDataPtr(); |
+ * const uint8_t* bytes = skDataPtr->bytes(); |
+ * ... |
+ * skDataPtr->unref(); |
+ * } |
+ */ |
+ // EPOGER: try to set it up so that this is never needed, and the caller would just ask for a string representation instead??? |
+ SkData *skDataPtr() const { |
+ return fSkDataRef.get(); |
+ } |
+ |
+ size_t size() const { |
+ return fSkDataRef->size(); |
+ } |
+ |
+ bool equals(const SkHashDigest &other) const { |
+ return fSkDataRef->equals(other.fSkDataRef.get()); |
+ } |
+ friend bool operator==(const SkHashDigest& a, const SkHashDigest& b) { |
+ return a.equals(b); |
+ } |
+ |
+ /** |
+ * Returns a printable SkString representation of the hash digest |
+ * (the bytes in hexadecimal, e.g. "deadbeef49") |
+ */ |
+ SkString toHexString() const { |
+ SkString retval; |
+ const uint8_t *start = fSkDataRef->bytes(); |
+ const uint8_t *pastTheEnd = start + fSkDataRef->size(); |
+ for (const uint8_t *b = start; b < pastTheEnd; b++) { |
+ // EPOGER: faster implementation that doesn't use appendf()? |
+ retval.appendf("%02x", *b); |
+ } |
+ return retval; |
+ } |
+ |
+private: |
+ |
+ // The SkData pointer within fSkDataRef may change over the |
+ // lifetime of the SkHashDigest object, but it will never be set |
+ // to NULL. (Every SkHashDigest constructor initializes it to |
+ // point at *some* SkData object.) |
+ SkRefPtr<SkData> fSkDataRef; |
+}; |
+ |
+#endif |