/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is nsCacheMetaData.cpp, released * February 22, 2001. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 2001 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Gordon Sheridan * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "nsCacheMetaData.h" #include "nsICacheEntryDescriptor.h" #include "nsString.h" #include "nsReadableUtils.h" #include "plstr.h" nsCacheMetaData::nsCacheMetaData() : mData(nsnull), mMetaSize(0) { } void nsCacheMetaData::Clear() { mMetaSize = 0; MetaElement * elem; while (mData) { elem = mData->mNext; delete mData; mData = elem; } } const char * nsCacheMetaData::GetElement(const char * key) { // We assume the number of meta data elements will be very small, so // we keep it real simple. Singly-linked list, linearly searched. MetaElement * elem = mData; while (elem) { if (elem->mKey.EqualsASCII(key)) return elem->mValue; elem = elem->mNext; } return nsnull; } nsresult nsCacheMetaData::SetElement(const char * key, const char * value) { PRUint32 keySize = strlen(key); PRUint32 valueSize = value ? strlen(value) : 0; // find and remove or update old meta data element MetaElement * elem = mData, * last = nsnull; while (elem) { if (elem->mKey.Equals(key)) { // Get length of old value PRUint32 oldValueLen = strlen(elem->mValue); if (valueSize == oldValueLen) { // Just replace value memcpy(elem->mValue, value, valueSize); return NS_OK; } // remove elem if (last) last->mNext = elem->mNext; else mData = elem->mNext; // 2 for the zero bytes of both strings mMetaSize -= 2 + keySize + oldValueLen; delete elem; break; } last = elem; elem = elem->mNext; } // allocate new meta data element if (value) { elem = new (value, valueSize) MetaElement; if (!elem) return NS_ERROR_OUT_OF_MEMORY; elem->mKey.Assign(key); // insert after last or as first element... if (last) { elem->mNext = last->mNext; last->mNext = elem; } else { elem->mNext = mData; mData = elem; } // Adjust CacheMetaData size, 2 for the zero bytes of both strings mMetaSize += 2 + keySize + valueSize; } return NS_OK; } nsresult nsCacheMetaData::FlattenMetaData(char * buffer, PRUint32 bufSize) { if (mMetaSize > bufSize) { NS_ERROR("buffer size too small for meta data."); return NS_ERROR_OUT_OF_MEMORY; } MetaElement * elem = mData; while (elem) { PRUint32 keySize = 1 + elem->mKey.Length(); memcpy(buffer, elem->mKey.get(), keySize); buffer += keySize; PRUint32 valSize = 1 + strlen(elem->mValue); memcpy(buffer, elem->mValue, valSize); buffer += valSize; elem = elem->mNext; } return NS_OK; } nsresult nsCacheMetaData::UnflattenMetaData(const char * data, PRUint32 size) { if (size == 0) return NS_OK; const char* limit = data + size; MetaElement * last = nsnull; while (data < limit) { const char* key = data; PRUint32 keySize = strlen(key); data += 1 + keySize; if (data < limit) { PRUint32 valueSize = strlen(data); MetaElement *elem = new (data, valueSize) MetaElement; if (!elem) return NS_ERROR_OUT_OF_MEMORY; elem->mKey.Assign(key); // insert after last or as first element... if (last) { elem->mNext = last->mNext; last->mNext = elem; } else { elem->mNext = mData; mData = elem; } last = elem; data += 1 + valueSize; // Adjust CacheMetaData size, 2 for the zero bytes of both strings mMetaSize += 2 + keySize + valueSize; } } return NS_OK; } nsresult nsCacheMetaData::VisitElements(nsICacheMetaDataVisitor * visitor) { MetaElement * elem = mData; while (elem) { PRBool keepGoing; nsresult rv = visitor->VisitMetaDataElement(elem->mKey.get(), elem->mValue, &keepGoing); if (NS_FAILED(rv) || !keepGoing) break; elem = elem->mNext; } return NS_OK; } void * nsCacheMetaData::MetaElement::operator new(size_t size, const char *value, PRUint32 valueSize) CPP_THROW_NEW { size += valueSize; MetaElement *elem = (MetaElement *) ::operator new(size); if (!elem) return nsnull; memcpy(elem->mValue, value, valueSize); elem->mValue[valueSize] = 0; return elem; }