summaryrefslogtreecommitdiffstats
path: root/netwerk/cache2/CacheHashUtils.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'netwerk/cache2/CacheHashUtils.cpp')
-rw-r--r--netwerk/cache2/CacheHashUtils.cpp206
1 files changed, 206 insertions, 0 deletions
diff --git a/netwerk/cache2/CacheHashUtils.cpp b/netwerk/cache2/CacheHashUtils.cpp
new file mode 100644
index 000000000..1f816e347
--- /dev/null
+++ b/netwerk/cache2/CacheHashUtils.cpp
@@ -0,0 +1,206 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "CacheHashUtils.h"
+
+#include "mozilla/BasePrincipal.h"
+#include "plstr.h"
+
+namespace mozilla {
+namespace net {
+
+/**
+ * CacheHash::Hash(const char * key, uint32_t initval)
+ *
+ * See http://burtleburtle.net/bob/hash/evahash.html for more information
+ * about this hash function.
+ *
+ * This algorithm is used to check the data integrity.
+ */
+
+static inline void hashmix(uint32_t& a, uint32_t& b, uint32_t& c)
+{
+ a -= b; a -= c; a ^= (c>>13);
+ b -= c; b -= a; b ^= (a<<8);
+ c -= a; c -= b; c ^= (b>>13);
+ a -= b; a -= c; a ^= (c>>12);
+ b -= c; b -= a; b ^= (a<<16);
+ c -= a; c -= b; c ^= (b>>5);
+ a -= b; a -= c; a ^= (c>>3);
+ b -= c; b -= a; b ^= (a<<10);
+ c -= a; c -= b; c ^= (b>>15);
+}
+
+CacheHash::Hash32_t
+CacheHash::Hash(const char *aData, uint32_t aSize, uint32_t aInitval)
+{
+ const uint8_t *k = reinterpret_cast<const uint8_t*>(aData);
+ uint32_t a, b, c, len;
+
+// length = PL_strlen(key);
+ /* Set up the internal state */
+ len = aSize;
+ a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */
+ c = aInitval; /* variable initialization of internal state */
+
+ /*---------------------------------------- handle most of the key */
+ while (len >= 12)
+ {
+ a += k[0] + (uint32_t(k[1])<<8) + (uint32_t(k[2])<<16) + (uint32_t(k[3])<<24);
+ b += k[4] + (uint32_t(k[5])<<8) + (uint32_t(k[6])<<16) + (uint32_t(k[7])<<24);
+ c += k[8] + (uint32_t(k[9])<<8) + (uint32_t(k[10])<<16) + (uint32_t(k[11])<<24);
+ hashmix(a, b, c);
+ k += 12; len -= 12;
+ }
+
+ /*------------------------------------- handle the last 11 bytes */
+ c += aSize;
+ switch(len) { /* all the case statements fall through */
+ case 11: c += (uint32_t(k[10])<<24); MOZ_FALLTHROUGH;
+ case 10: c += (uint32_t(k[9])<<16); MOZ_FALLTHROUGH;
+ case 9 : c += (uint32_t(k[8])<<8); MOZ_FALLTHROUGH;
+ /* the low-order byte of c is reserved for the length */
+ case 8 : b += (uint32_t(k[7])<<24); MOZ_FALLTHROUGH;
+ case 7 : b += (uint32_t(k[6])<<16); MOZ_FALLTHROUGH;
+ case 6 : b += (uint32_t(k[5])<<8); MOZ_FALLTHROUGH;
+ case 5 : b += k[4]; MOZ_FALLTHROUGH;
+ case 4 : a += (uint32_t(k[3])<<24); MOZ_FALLTHROUGH;
+ case 3 : a += (uint32_t(k[2])<<16); MOZ_FALLTHROUGH;
+ case 2 : a += (uint32_t(k[1])<<8); MOZ_FALLTHROUGH;
+ case 1 : a += k[0];
+ /* case 0: nothing left to add */
+ }
+ hashmix(a, b, c);
+
+ return c;
+}
+
+CacheHash::Hash16_t
+CacheHash::Hash16(const char *aData, uint32_t aSize, uint32_t aInitval)
+{
+ Hash32_t hash = Hash(aData, aSize, aInitval);
+ return (hash & 0xFFFF);
+}
+
+NS_IMPL_ISUPPORTS0(CacheHash)
+
+CacheHash::CacheHash(uint32_t aInitval)
+ : mA(0x9e3779b9)
+ , mB(0x9e3779b9)
+ , mC(aInitval)
+ , mPos(0)
+ , mBuf(0)
+ , mBufPos(0)
+ , mLength(0)
+ , mFinalized(false)
+{}
+
+void
+CacheHash::Feed(uint32_t aVal, uint8_t aLen)
+{
+ switch (mPos) {
+ case 0:
+ mA += aVal;
+ mPos ++;
+ break;
+
+ case 1:
+ mB += aVal;
+ mPos ++;
+ break;
+
+ case 2:
+ mPos = 0;
+ if (aLen == 4) {
+ mC += aVal;
+ hashmix(mA, mB, mC);
+ }
+ else {
+ mC += aVal << 8;
+ }
+ }
+
+ mLength += aLen;
+}
+
+void
+CacheHash::Update(const char *aData, uint32_t aLen)
+{
+ const uint8_t *data = reinterpret_cast<const uint8_t*>(aData);
+
+ MOZ_ASSERT(!mFinalized);
+
+ if (mBufPos) {
+ while (mBufPos != 4 && aLen) {
+ mBuf += uint32_t(*data) << 8*mBufPos;
+ data++;
+ mBufPos++;
+ aLen--;
+ }
+
+ if (mBufPos == 4) {
+ mBufPos = 0;
+ Feed(mBuf);
+ mBuf = 0;
+ }
+ }
+
+ if (!aLen)
+ return;
+
+ while (aLen >= 4) {
+ Feed(data[0] + (uint32_t(data[1]) << 8) + (uint32_t(data[2]) << 16) +
+ (uint32_t(data[3]) << 24));
+ data += 4;
+ aLen -= 4;
+ }
+
+ switch (aLen) {
+ case 3: mBuf += data[2] << 16; MOZ_FALLTHROUGH;
+ case 2: mBuf += data[1] << 8; MOZ_FALLTHROUGH;
+ case 1: mBuf += data[0];
+ }
+
+ mBufPos = aLen;
+}
+
+CacheHash::Hash32_t
+CacheHash::GetHash()
+{
+ if (!mFinalized)
+ {
+ if (mBufPos) {
+ Feed(mBuf, mBufPos);
+ }
+ mC += mLength;
+ hashmix(mA, mB, mC);
+ mFinalized = true;
+ }
+
+ return mC;
+}
+
+CacheHash::Hash16_t
+CacheHash::GetHash16()
+{
+ Hash32_t hash = GetHash();
+ return (hash & 0xFFFF);
+}
+
+OriginAttrsHash
+GetOriginAttrsHash(const mozilla::OriginAttributes &aOA)
+{
+ nsAutoCString suffix;
+ aOA.CreateSuffix(suffix);
+
+ SHA1Sum sum;
+ SHA1Sum::Hash hash;
+ sum.update(suffix.BeginReading(), suffix.Length());
+ sum.finish(hash);
+
+ return BigEndian::readUint64(&hash);
+}
+
+} // namespace net
+} // namespace mozilla