1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/netwerk/cache/nsCacheMetaData.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,162 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "nsCacheMetaData.h" 1.11 +#include "nsICacheEntryDescriptor.h" 1.12 + 1.13 +const char * 1.14 +nsCacheMetaData::GetElement(const char * key) 1.15 +{ 1.16 + const char * data = mBuffer; 1.17 + const char * limit = mBuffer + mMetaSize; 1.18 + 1.19 + while (data < limit) { 1.20 + // Point to the value part 1.21 + const char * value = data + strlen(data) + 1; 1.22 + NS_ABORT_IF_FALSE(value < limit, "Cache Metadata corrupted"); 1.23 + if (strcmp(data, key) == 0) 1.24 + return value; 1.25 + 1.26 + // Skip value part 1.27 + data = value + strlen(value) + 1; 1.28 + } 1.29 + NS_ABORT_IF_FALSE(data == limit, "Metadata corrupted"); 1.30 + return nullptr; 1.31 +} 1.32 + 1.33 + 1.34 +nsresult 1.35 +nsCacheMetaData::SetElement(const char * key, 1.36 + const char * value) 1.37 +{ 1.38 + const uint32_t keySize = strlen(key) + 1; 1.39 + char * pos = (char *)GetElement(key); 1.40 + 1.41 + if (!value) { 1.42 + // No value means remove the key/value pair completely, if existing 1.43 + if (pos) { 1.44 + uint32_t oldValueSize = strlen(pos) + 1; 1.45 + uint32_t offset = pos - mBuffer; 1.46 + uint32_t remainder = mMetaSize - (offset + oldValueSize); 1.47 + 1.48 + memmove(pos - keySize, pos + oldValueSize, remainder); 1.49 + mMetaSize -= keySize + oldValueSize; 1.50 + } 1.51 + return NS_OK; 1.52 + } 1.53 + 1.54 + const uint32_t valueSize = strlen(value) + 1; 1.55 + uint32_t newSize = mMetaSize + valueSize; 1.56 + if (pos) { 1.57 + const uint32_t oldValueSize = strlen(pos) + 1; 1.58 + const uint32_t offset = pos - mBuffer; 1.59 + const uint32_t remainder = mMetaSize - (offset + oldValueSize); 1.60 + 1.61 + // Update the value in place 1.62 + newSize -= oldValueSize; 1.63 + nsresult rv = EnsureBuffer(newSize); 1.64 + NS_ENSURE_SUCCESS(rv, rv); 1.65 + 1.66 + // Move the remainder to the right place 1.67 + pos = mBuffer + offset; 1.68 + memmove(pos + valueSize, pos + oldValueSize, remainder); 1.69 + } else { 1.70 + // allocate new meta data element 1.71 + newSize += keySize; 1.72 + nsresult rv = EnsureBuffer(newSize); 1.73 + NS_ENSURE_SUCCESS(rv, rv); 1.74 + 1.75 + // Add after last element 1.76 + pos = mBuffer + mMetaSize; 1.77 + memcpy(pos, key, keySize); 1.78 + pos += keySize; 1.79 + } 1.80 + 1.81 + // Update value 1.82 + memcpy(pos, value, valueSize); 1.83 + mMetaSize = newSize; 1.84 + 1.85 + return NS_OK; 1.86 +} 1.87 + 1.88 +nsresult 1.89 +nsCacheMetaData::FlattenMetaData(char * buffer, uint32_t bufSize) 1.90 +{ 1.91 + if (mMetaSize > bufSize) { 1.92 + NS_ERROR("buffer size too small for meta data."); 1.93 + return NS_ERROR_OUT_OF_MEMORY; 1.94 + } 1.95 + 1.96 + memcpy(buffer, mBuffer, mMetaSize); 1.97 + return NS_OK; 1.98 +} 1.99 + 1.100 +nsresult 1.101 +nsCacheMetaData::UnflattenMetaData(const char * data, uint32_t size) 1.102 +{ 1.103 + if (data && size) { 1.104 + // Check if the metadata ends with a zero byte. 1.105 + if (data[size-1] != '\0') { 1.106 + NS_ERROR("Cache MetaData is not null terminated"); 1.107 + return NS_ERROR_ILLEGAL_VALUE; 1.108 + } 1.109 + // Check that there are an even number of zero bytes 1.110 + // to match the pattern { key \0 value \0 } 1.111 + bool odd = false; 1.112 + for (uint32_t i = 0; i < size; i++) { 1.113 + if (data[i] == '\0') 1.114 + odd = !odd; 1.115 + } 1.116 + if (odd) { 1.117 + NS_ERROR("Cache MetaData is malformed"); 1.118 + return NS_ERROR_ILLEGAL_VALUE; 1.119 + } 1.120 + 1.121 + nsresult rv = EnsureBuffer(size); 1.122 + NS_ENSURE_SUCCESS(rv, rv); 1.123 + 1.124 + memcpy(mBuffer, data, size); 1.125 + mMetaSize = size; 1.126 + } 1.127 + return NS_OK; 1.128 +} 1.129 + 1.130 +nsresult 1.131 +nsCacheMetaData::VisitElements(nsICacheMetaDataVisitor * visitor) 1.132 +{ 1.133 + const char * data = mBuffer; 1.134 + const char * limit = mBuffer + mMetaSize; 1.135 + 1.136 + while (data < limit) { 1.137 + const char * key = data; 1.138 + // Skip key part 1.139 + data += strlen(data) + 1; 1.140 + NS_ABORT_IF_FALSE(data < limit, "Metadata corrupted"); 1.141 + bool keepGoing; 1.142 + nsresult rv = visitor->VisitMetaDataElement(key, data, &keepGoing); 1.143 + if (NS_FAILED(rv) || !keepGoing) 1.144 + return NS_OK; 1.145 + 1.146 + // Skip value part 1.147 + data += strlen(data) + 1; 1.148 + } 1.149 + NS_ABORT_IF_FALSE(data == limit, "Metadata corrupted"); 1.150 + return NS_OK; 1.151 +} 1.152 + 1.153 +nsresult 1.154 +nsCacheMetaData::EnsureBuffer(uint32_t bufSize) 1.155 +{ 1.156 + if (mBufferSize < bufSize) { 1.157 + char * buf = (char *)moz_realloc(mBuffer, bufSize); 1.158 + if (!buf) { 1.159 + return NS_ERROR_OUT_OF_MEMORY; 1.160 + } 1.161 + mBuffer = buf; 1.162 + mBufferSize = bufSize; 1.163 + } 1.164 + return NS_OK; 1.165 +}