Back to index

lightning-sunbird  0.9+nobinonly
nsCacheMetaData.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is nsCacheMetaData.cpp, released
00017  * February 22, 2001.
00018  *
00019  * The Initial Developer of the Original Code is
00020  * Netscape Communications Corporation.
00021  * Portions created by the Initial Developer are Copyright (C) 2001
00022  * the Initial Developer. All Rights Reserved.
00023  *
00024  * Contributor(s):
00025  *   Gordon Sheridan <gordon@netscape.com>
00026  *
00027  * Alternatively, the contents of this file may be used under the terms of
00028  * either the GNU General Public License Version 2 or later (the "GPL"), or
00029  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00030  * in which case the provisions of the GPL or the LGPL are applicable instead
00031  * of those above. If you wish to allow use of your version of this file only
00032  * under the terms of either the GPL or the LGPL, and not to allow others to
00033  * use your version of this file under the terms of the MPL, indicate your
00034  * decision by deleting the provisions above and replace them with the notice
00035  * and other provisions required by the GPL or the LGPL. If you do not delete
00036  * the provisions above, a recipient may use your version of this file under
00037  * the terms of any one of the MPL, the GPL or the LGPL.
00038  *
00039  * ***** END LICENSE BLOCK ***** */
00040 
00041 #include "nsCacheMetaData.h"
00042 #include "nsICacheEntryDescriptor.h"
00043 #include "nsString.h"
00044 #include "nsReadableUtils.h"
00045 #include "plstr.h"
00046 
00047 nsCacheMetaData::nsCacheMetaData()
00048     : mData(nsnull), mMetaSize(0)
00049 {
00050 }
00051 
00052 void
00053 nsCacheMetaData::Clear()
00054 {
00055     mMetaSize = 0;
00056     MetaElement * elem;
00057     while (mData) {
00058         elem = mData->mNext;
00059         delete mData;
00060         mData = elem;
00061     }
00062 }
00063 
00064 const char *
00065 nsCacheMetaData::GetElement(const char * key)
00066 {
00067     // We assume the number of meta data elements will be very small, so
00068     // we keep it real simple.  Singly-linked list, linearly searched.
00069 
00070     nsCOMPtr<nsIAtom> keyAtom = do_GetAtom(key);
00071 
00072     MetaElement * elem = mData;
00073     while (elem) {
00074         if (elem->mKey == keyAtom)
00075             return elem->mValue;
00076         elem = elem->mNext;
00077     }
00078     return nsnull;
00079 }
00080 
00081 
00082 nsresult
00083 nsCacheMetaData::SetElement(const char * key,
00084                             const char * value)
00085 {
00086     nsCOMPtr<nsIAtom> keyAtom = do_GetAtom(key);
00087     if (!keyAtom)
00088         return NS_ERROR_OUT_OF_MEMORY;
00089 
00090     PRUint32 keySize = strlen(key);
00091     PRUint32 valueSize = value ? strlen(value) : 0;
00092 
00093     // find and remove or update old meta data element
00094     MetaElement * elem = mData, * last = nsnull;
00095     while (elem) {
00096         if (elem->mKey == keyAtom) {
00097             // Get length of old value
00098             PRUint32 oldValueLen = strlen(elem->mValue);
00099             if (valueSize == oldValueLen) {
00100                 // Just replace value
00101                 memcpy(elem->mValue, value, valueSize);
00102                 return NS_OK;
00103             }
00104             // remove elem
00105             if (last)
00106                 last->mNext = elem->mNext;
00107             else
00108                 mData = elem->mNext;
00109             // 2 for the zero bytes of both strings
00110             mMetaSize -= 2 + keySize + oldValueLen;
00111             delete elem;
00112             break;
00113         }
00114         last = elem;
00115         elem = elem->mNext;
00116     }
00117 
00118     // allocate new meta data element
00119     if (value) {
00120         elem = new (value, valueSize) MetaElement;
00121         if (!elem)
00122             return NS_ERROR_OUT_OF_MEMORY;
00123         elem->mKey = keyAtom;
00124 
00125         // insert after last or as first element...
00126         if (last) {
00127             elem->mNext = last->mNext;
00128             last->mNext = elem;
00129         }
00130         else {
00131             elem->mNext = mData;
00132             mData = elem;
00133         }
00134 
00135         // Adjust CacheMetaData size, 2 for the zero bytes of both strings
00136         mMetaSize += 2 + keySize + valueSize;
00137     }
00138 
00139     return NS_OK;
00140 }
00141 
00142 nsresult
00143 nsCacheMetaData::FlattenMetaData(char * buffer, PRUint32 bufSize)
00144 {
00145     const char *key;
00146 
00147     if (mMetaSize > bufSize) {
00148         NS_ERROR("buffer size too small for meta data.");
00149         return NS_ERROR_OUT_OF_MEMORY;
00150     }
00151 
00152     MetaElement * elem = mData;
00153     while (elem) {
00154         elem->mKey->GetUTF8String(&key);
00155 
00156         PRUint32 keySize = 1 + strlen(key);
00157         memcpy(buffer, key, keySize);
00158         buffer += keySize;
00159 
00160         PRUint32 valSize = 1 + strlen(elem->mValue);
00161         memcpy(buffer, elem->mValue, valSize);
00162         buffer += valSize;
00163 
00164         elem = elem->mNext;
00165     }
00166     return NS_OK;
00167 }
00168 
00169 nsresult
00170 nsCacheMetaData::UnflattenMetaData(const char * data, PRUint32 size)
00171 {
00172     if (size == 0) return NS_OK;
00173 
00174     const char* limit = data + size;
00175     MetaElement * last = nsnull;
00176 
00177     while (data < limit) {
00178         const char* key = data;
00179         PRUint32 keySize = strlen(key);
00180         data += 1 + keySize;
00181         if (data < limit) {
00182             nsCOMPtr<nsIAtom> keyAtom = do_GetAtom(key);
00183             if (!keyAtom)
00184                 return NS_ERROR_OUT_OF_MEMORY;
00185 
00186             PRUint32 valueSize = strlen(data);
00187             MetaElement *elem = new (data, valueSize) MetaElement;
00188             if (!elem)
00189                  return NS_ERROR_OUT_OF_MEMORY;
00190             elem->mKey = keyAtom;
00191 
00192             // insert after last or as first element...
00193             if (last) {
00194                 elem->mNext = last->mNext;
00195                 last->mNext = elem;
00196             }
00197             else {
00198                 elem->mNext = mData;
00199                 mData = elem;
00200             }
00201 
00202             last = elem;
00203             data += 1 + valueSize;
00204 
00205             // Adjust CacheMetaData size, 2 for the zero bytes of both strings
00206             mMetaSize += 2 + keySize + valueSize;
00207         }
00208     }
00209     return NS_OK;
00210 }
00211 
00212 nsresult
00213 nsCacheMetaData::VisitElements(nsICacheMetaDataVisitor * visitor)
00214 {
00215     const char *key;
00216 
00217     MetaElement * elem = mData;
00218     while (elem) {
00219         elem->mKey->GetUTF8String(&key);
00220 
00221         PRBool keepGoing;
00222         nsresult rv = visitor->VisitMetaDataElement(key, elem->mValue, &keepGoing);
00223 
00224         if (NS_FAILED(rv) || !keepGoing)
00225             break;
00226 
00227         elem = elem->mNext;
00228     }
00229 
00230     return NS_OK;
00231 }
00232 
00233 void *
00234 nsCacheMetaData::MetaElement::operator new(size_t size,
00235                                            const char *value,
00236                                            PRUint32 valueSize) CPP_THROW_NEW
00237 {
00238     size += valueSize;
00239 
00240     MetaElement *elem = (MetaElement *) ::operator new(size);
00241     if (!elem)
00242         return nsnull;
00243 
00244     memcpy(elem->mValue, value, valueSize);
00245     elem->mValue[valueSize] = 0;
00246 
00247     return elem;
00248 }