| 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
|
|
|