LCOV - app.info - netwerk/cache/nsCacheEntryDescriptor.cpp

LCOV - code coverage report
| Current view: | directory - netwerk/cache - nsCacheEntryDescriptor.cpp (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 460 | 232 | 50.4 %
| Date: | 2012-04-21 | Functions: | 72 | 42 | 58.3 %

           1                 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
           2                 :  *
           3                 :  * ***** BEGIN LICENSE BLOCK *****
           4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
           5                 :  *
           6                 :  * The contents of this file are subject to the Mozilla Public License Version
           7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
           8                 :  * the License. You may obtain a copy of the License at
           9                 :  * http://www.mozilla.org/MPL/
          10                 :  *
          11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
          12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
          13                 :  * for the specific language governing rights and limitations under the
          14                 :  * License.
          15                 :  *
          16                 :  * The Original Code is nsCacheEntryDescriptor.cpp, released
          17                 :  * February 22, 2001.
          18                 :  *
          19                 :  * The Initial Developer of the Original Code is
          20                 :  * Netscape Communications Corporation.
          21                 :  * Portions created by the Initial Developer are Copyright (C) 2001
          22                 :  * the Initial Developer. All Rights Reserved.
          23                 :  *
          24                 :  * Contributor(s):
          25                 :  *   Gordon Sheridan, 22-February-2001
          26                 :  *
          27                 :  * Alternatively, the contents of this file may be used under the terms of
          28                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
          29                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
          30                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
          31                 :  * of those above. If you wish to allow use of your version of this file only
          32                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
          33                 :  * use your version of this file under the terms of the MPL, indicate your
          34                 :  * decision by deleting the provisions above and replace them with the notice
          35                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
          36                 :  * the provisions above, a recipient may use your version of this file under
          37                 :  * the terms of any one of the MPL, the GPL or the LGPL.
          38                 :  *
          39                 :  * ***** END LICENSE BLOCK ***** */
          40                 :
          41                 : #include "nsICache.h"
          42                 : #include "nsCache.h"
          43                 : #include "nsCacheService.h"
          44                 : #include "nsCacheEntryDescriptor.h"
          45                 : #include "nsCacheEntry.h"
          46                 : #include "nsReadableUtils.h"
          47                 : #include "nsIOutputStream.h"
          48                 : #include "nsCRT.h"
          49                 :
          50                 : #define kMinDecompressReadBufLen 1024
          51                 : #define kMinCompressWriteBufLen  1024
          52                 :
          53           17642 : NS_IMPL_THREADSAFE_ISUPPORTS2(nsCacheEntryDescriptor,
          54                 :                               nsICacheEntryDescriptor,
          55                 :                               nsICacheEntryInfo)
          56                 :
          57            1778 : nsCacheEntryDescriptor::nsCacheEntryDescriptor(nsCacheEntry * entry,
          58                 :                                                nsCacheAccessMode accessGranted)
          59                 :     : mCacheEntry(entry),
          60                 :       mAccessGranted(accessGranted),
          61            1778 :       mOutput(nsnull)
          62                 : {
          63            1778 :     PR_INIT_CLIST(this);
          64            1778 :     NS_ADDREF(nsCacheService::GlobalInstance());  // ensure it lives for the lifetime of the descriptor
          65            1778 : }
          66                 :
          67                 :
          68            3556 : nsCacheEntryDescriptor::~nsCacheEntryDescriptor()
          69                 : {
          70                 :     // No need to close if the cache entry has already been severed.  This
          71                 :     // helps avoid a shutdown assertion (bug 285519) that is caused when
          72                 :     // consumers end up holding onto these objects past xpcom-shutdown.  It's
          73                 :     // okay for them to do that because the cache service calls our Close
          74                 :     // method during xpcom-shutdown, so we don't need to complain about it.
          75            1778 :     if (mCacheEntry)
          76            1725 :         Close();
          77                 :
          78            1778 :     nsCacheService * service = nsCacheService::GlobalInstance();
          79            1778 :     NS_RELEASE(service);
          80            7112 : }
          81                 :
          82                 :
          83                 : NS_IMETHODIMP
          84               0 : nsCacheEntryDescriptor::GetClientID(char ** result)
          85                 : {
          86               0 :     NS_ENSURE_ARG_POINTER(result);
          87                 :
          88               0 :     nsCacheServiceAutoLock lock;
          89               0 :     if (!mCacheEntry)  return NS_ERROR_NOT_AVAILABLE;
          90                 :
          91               0 :     return ClientIDFromCacheKey(*(mCacheEntry->Key()), result);
          92                 : }
          93                 :
          94                 :
          95                 : NS_IMETHODIMP
          96            1488 : nsCacheEntryDescriptor::GetDeviceID(char ** aDeviceID)
          97                 : {
          98            1488 :     NS_ENSURE_ARG_POINTER(aDeviceID);
          99            2976 :     nsCacheServiceAutoLock lock;
         100            1488 :     if (!mCacheEntry)  return NS_ERROR_NOT_AVAILABLE;
         101                 :
         102            1488 :     const char* deviceID = mCacheEntry->GetDeviceID();
         103            1488 :     if (!deviceID) {
         104             901 :         *aDeviceID = nsnull;
         105             901 :         return NS_OK;
         106                 :     }
         107                 :
         108             587 :     *aDeviceID = NS_strdup(deviceID);
         109             587 :     return *aDeviceID ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
         110                 : }
         111                 :
         112                 :
         113                 : NS_IMETHODIMP
         114               0 : nsCacheEntryDescriptor::GetKey(nsACString &result)
         115                 : {
         116               0 :     nsCacheServiceAutoLock lock;
         117               0 :     if (!mCacheEntry)  return NS_ERROR_NOT_AVAILABLE;
         118                 :
         119               0 :     return ClientKeyFromCacheKey(*(mCacheEntry->Key()), result);
         120                 : }
         121                 :
         122                 :
         123                 : NS_IMETHODIMP
         124               0 : nsCacheEntryDescriptor::GetFetchCount(PRInt32 *result)
         125                 : {
         126               0 :     NS_ENSURE_ARG_POINTER(result);
         127               0 :     nsCacheServiceAutoLock lock;
         128               0 :     if (!mCacheEntry)  return NS_ERROR_NOT_AVAILABLE;
         129                 :
         130               0 :     *result = mCacheEntry->FetchCount();
         131               0 :     return NS_OK;
         132                 : }
         133                 :
         134                 :
         135                 : NS_IMETHODIMP
         136               0 : nsCacheEntryDescriptor::GetLastFetched(PRUint32 *result)
         137                 : {
         138               0 :     NS_ENSURE_ARG_POINTER(result);
         139               0 :     nsCacheServiceAutoLock lock;
         140               0 :     if (!mCacheEntry)  return NS_ERROR_NOT_AVAILABLE;
         141                 :
         142               0 :     *result = mCacheEntry->LastFetched();
         143               0 :     return NS_OK;
         144                 : }
         145                 :
         146                 :
         147                 : NS_IMETHODIMP
         148             567 : nsCacheEntryDescriptor::GetLastModified(PRUint32 *result)
         149                 : {
         150             567 :     NS_ENSURE_ARG_POINTER(result);
         151            1134 :     nsCacheServiceAutoLock lock;
         152             567 :     if (!mCacheEntry)  return NS_ERROR_NOT_AVAILABLE;
         153                 :
         154             567 :     *result = mCacheEntry->LastModified();
         155             567 :     return NS_OK;
         156                 : }
         157                 :
         158                 :
         159                 : NS_IMETHODIMP
         160             288 : nsCacheEntryDescriptor::GetExpirationTime(PRUint32 *result)
         161                 : {
         162             288 :     NS_ENSURE_ARG_POINTER(result);
         163             576 :     nsCacheServiceAutoLock lock;
         164             288 :     if (!mCacheEntry)  return NS_ERROR_NOT_AVAILABLE;
         165                 :
         166             288 :     *result = mCacheEntry->ExpirationTime();
         167             288 :     return NS_OK;
         168                 : }
         169                 :
         170                 :
         171                 : NS_IMETHODIMP
         172            1357 : nsCacheEntryDescriptor::SetExpirationTime(PRUint32 expirationTime)
         173                 : {
         174            2714 :     nsCacheServiceAutoLock lock;
         175            1357 :     if (!mCacheEntry)  return NS_ERROR_NOT_AVAILABLE;
         176                 :
         177            1357 :     mCacheEntry->SetExpirationTime(expirationTime);
         178            1357 :     mCacheEntry->MarkEntryDirty();
         179            1357 :     return NS_OK;
         180                 : }
         181                 :
         182                 :
         183               0 : NS_IMETHODIMP nsCacheEntryDescriptor::IsStreamBased(bool *result)
         184                 : {
         185               0 :     NS_ENSURE_ARG_POINTER(result);
         186               0 :     nsCacheServiceAutoLock lock;
         187               0 :     if (!mCacheEntry)  return NS_ERROR_NOT_AVAILABLE;
         188                 :
         189               0 :     *result = mCacheEntry->IsStreamData();
         190               0 :     return NS_OK;
         191                 : }
         192                 :
         193               0 : NS_IMETHODIMP nsCacheEntryDescriptor::GetPredictedDataSize(PRInt64 *result)
         194                 : {
         195               0 :     NS_ENSURE_ARG_POINTER(result);
         196               0 :     nsCacheServiceAutoLock lock;
         197               0 :     if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
         198                 :
         199               0 :     *result = mCacheEntry->PredictedDataSize();
         200               0 :     return NS_OK;
         201                 : }
         202                 :
         203            1363 : NS_IMETHODIMP nsCacheEntryDescriptor::SetPredictedDataSize(PRInt64
         204                 :                                                            predictedSize)
         205                 : {
         206            2726 :     nsCacheServiceAutoLock lock;
         207            1363 :     if (!mCacheEntry)  return NS_ERROR_NOT_AVAILABLE;
         208                 :
         209            1363 :     mCacheEntry->SetPredictedDataSize(predictedSize);
         210            1363 :     return NS_OK;
         211                 : }
         212                 :
         213             536 : NS_IMETHODIMP nsCacheEntryDescriptor::GetDataSize(PRUint32 *result)
         214                 : {
         215             536 :     NS_ENSURE_ARG_POINTER(result);
         216            1072 :     nsCacheServiceAutoLock lock;
         217             536 :     if (!mCacheEntry)  return NS_ERROR_NOT_AVAILABLE;
         218                 :
         219             536 :     const char* val = mCacheEntry->GetMetaDataElement("uncompressed-len");
         220             536 :     if (!val) {
         221             536 :         *result = mCacheEntry->DataSize();
         222                 :     } else {
         223               0 :         *result = atol(val);
         224                 :     }
         225                 :
         226             536 :     return NS_OK;
         227                 : }
         228                 :
         229                 :
         230               2 : NS_IMETHODIMP nsCacheEntryDescriptor::GetStorageDataSize(PRUint32 *result)
         231                 : {
         232               2 :     NS_ENSURE_ARG_POINTER(result);
         233               4 :     nsCacheServiceAutoLock lock;
         234               2 :     if (!mCacheEntry)  return NS_ERROR_NOT_AVAILABLE;
         235                 :
         236               2 :     *result = mCacheEntry->DataSize();
         237                 :
         238               2 :     return NS_OK;
         239                 : }
         240                 :
         241                 :
         242                 : nsresult
         243            1515 : nsCacheEntryDescriptor::RequestDataSizeChange(PRInt32 deltaSize)
         244                 : {
         245            3030 :     nsCacheServiceAutoLock lock;
         246            1515 :     if (!mCacheEntry)  return NS_ERROR_NOT_AVAILABLE;
         247                 :
         248                 :     nsresult  rv;
         249            1515 :     rv = nsCacheService::OnDataSizeChange(mCacheEntry, deltaSize);
         250            1515 :     if (NS_SUCCEEDED(rv)) {
         251                 :         // XXX review for signed/unsigned math errors
         252            1515 :         PRUint32  newDataSize = mCacheEntry->DataSize() + deltaSize;
         253            1515 :         mCacheEntry->SetDataSize(newDataSize);
         254            1515 :         mCacheEntry->TouchData();
         255                 :     }
         256            1515 :     return rv;
         257                 : }
         258                 :
         259                 :
         260                 : NS_IMETHODIMP
         261               0 : nsCacheEntryDescriptor::SetDataSize(PRUint32 dataSize)
         262                 : {
         263               0 :     nsCacheServiceAutoLock lock;
         264               0 :     if (!mCacheEntry)  return NS_ERROR_NOT_AVAILABLE;
         265                 :
         266                 :     // XXX review for signed/unsigned math errors
         267               0 :     PRInt32  deltaSize = dataSize - mCacheEntry->DataSize();
         268                 :
         269                 :     nsresult  rv;
         270               0 :     rv = nsCacheService::OnDataSizeChange(mCacheEntry, deltaSize);
         271                 :     // this had better be NS_OK, this call instance is advisory for memory cache objects
         272               0 :     if (NS_SUCCEEDED(rv)) {
         273                 :         // XXX review for signed/unsigned math errors
         274               0 :         PRUint32  newDataSize = mCacheEntry->DataSize() + deltaSize;
         275               0 :         mCacheEntry->SetDataSize(newDataSize);
         276               0 :         mCacheEntry->TouchData();
         277                 :     } else {
         278               0 :         NS_WARNING("failed SetDataSize() on memory cache object!");
         279                 :     }
         280                 :
         281               0 :     return rv;
         282                 : }
         283                 :
         284                 :
         285                 : NS_IMETHODIMP
         286             242 : nsCacheEntryDescriptor::OpenInputStream(PRUint32 offset, nsIInputStream ** result)
         287                 : {
         288             242 :     NS_ENSURE_ARG_POINTER(result);
         289                 :
         290                 :     {
         291             484 :         nsCacheServiceAutoLock lock;
         292             242 :         if (!mCacheEntry)                  return NS_ERROR_NOT_AVAILABLE;
         293             242 :         if (!mCacheEntry->IsStreamData())  return NS_ERROR_CACHE_DATA_IS_NOT_STREAM;
         294                 :
         295                 :         // ensure valid permissions
         296             242 :         if (!(mAccessGranted & nsICache::ACCESS_READ))
         297               0 :             return NS_ERROR_CACHE_READ_ACCESS_DENIED;
         298                 :     }
         299                 :
         300             242 :     nsInputStreamWrapper* cacheInput = nsnull;
         301                 :     const char *val;
         302             242 :     val = mCacheEntry->GetMetaDataElement("uncompressed-len");
         303             242 :     if (val) {
         304               0 :         cacheInput = new nsDecompressInputStreamWrapper(this, offset);
         305                 :     } else {
         306             242 :         cacheInput = new nsInputStreamWrapper(this, offset);
         307                 :     }
         308             242 :     if (!cacheInput) return NS_ERROR_OUT_OF_MEMORY;
         309                 :
         310             242 :     NS_ADDREF(*result = cacheInput);
         311             242 :     return NS_OK;
         312                 : }
         313                 :
         314                 : NS_IMETHODIMP
         315            1194 : nsCacheEntryDescriptor::OpenOutputStream(PRUint32 offset, nsIOutputStream ** result)
         316                 : {
         317            1194 :     NS_ENSURE_ARG_POINTER(result);
         318                 :
         319                 :     {
         320            2388 :         nsCacheServiceAutoLock lock;
         321            1194 :         if (!mCacheEntry)                  return NS_ERROR_NOT_AVAILABLE;
         322            1194 :         if (!mCacheEntry->IsStreamData())  return NS_ERROR_CACHE_DATA_IS_NOT_STREAM;
         323                 :
         324                 :         // ensure valid permissions
         325            1194 :         if (!(mAccessGranted & nsICache::ACCESS_WRITE))
         326               0 :             return NS_ERROR_CACHE_WRITE_ACCESS_DENIED;
         327                 :     }
         328                 :
         329            1194 :     nsOutputStreamWrapper* cacheOutput = nsnull;
         330            1194 :     PRInt32 compressionLevel = nsCacheService::CacheCompressionLevel();
         331                 :     const char *val;
         332            1194 :     val = mCacheEntry->GetMetaDataElement("uncompressed-len");
         333            1194 :     if ((compressionLevel > 0) && val) {
         334               0 :         cacheOutput = new nsCompressOutputStreamWrapper(this, offset);
         335                 :     } else {
         336                 :         // clear compression flag when compression disabled - see bug #715198
         337            1194 :         if (val) {
         338             903 :             mCacheEntry->SetMetaDataElement("uncompressed-len", nsnull);
         339                 :         }
         340            1194 :         cacheOutput = new nsOutputStreamWrapper(this, offset);
         341                 :     }
         342            1194 :     if (!cacheOutput) return NS_ERROR_OUT_OF_MEMORY;
         343                 :
         344            1194 :     NS_ADDREF(*result = cacheOutput);
         345            1194 :     return NS_OK;
         346                 : }
         347                 :
         348                 :
         349                 : NS_IMETHODIMP
         350               0 : nsCacheEntryDescriptor::GetCacheElement(nsISupports ** result)
         351                 : {
         352               0 :     NS_ENSURE_ARG_POINTER(result);
         353               0 :     nsCacheServiceAutoLock lock;
         354               0 :     if (!mCacheEntry)                 return NS_ERROR_NOT_AVAILABLE;
         355               0 :     if (mCacheEntry->IsStreamData())  return NS_ERROR_CACHE_DATA_IS_STREAM;
         356                 :
         357               0 :     NS_IF_ADDREF(*result = mCacheEntry->Data());
         358               0 :     return NS_OK;
         359                 : }
         360                 :
         361                 :
         362                 : NS_IMETHODIMP
         363               0 : nsCacheEntryDescriptor::SetCacheElement(nsISupports * cacheElement)
         364                 : {
         365               0 :     nsCacheServiceAutoLock lock;
         366               0 :     if (!mCacheEntry)                 return NS_ERROR_NOT_AVAILABLE;
         367               0 :     if (mCacheEntry->IsStreamData())  return NS_ERROR_CACHE_DATA_IS_STREAM;
         368                 :
         369               0 :     return nsCacheService::SetCacheElement(mCacheEntry, cacheElement);
         370                 : }
         371                 :
         372                 :
         373                 : NS_IMETHODIMP
         374            1580 : nsCacheEntryDescriptor::GetAccessGranted(nsCacheAccessMode *result)
         375                 : {
         376            1580 :     NS_ENSURE_ARG_POINTER(result);
         377            1580 :     *result = mAccessGranted;
         378            1580 :     return NS_OK;
         379                 : }
         380                 :
         381                 :
         382                 : NS_IMETHODIMP
         383            2244 : nsCacheEntryDescriptor::GetStoragePolicy(nsCacheStoragePolicy *result)
         384                 : {
         385            2244 :     NS_ENSURE_ARG_POINTER(result);
         386            4488 :     nsCacheServiceAutoLock lock;
         387            2244 :     if (!mCacheEntry)  return NS_ERROR_NOT_AVAILABLE;
         388                 :
         389            2244 :     *result = mCacheEntry->StoragePolicy();
         390            2244 :     return NS_OK;
         391                 : }
         392                 :
         393                 :
         394                 : NS_IMETHODIMP
         395               6 : nsCacheEntryDescriptor::SetStoragePolicy(nsCacheStoragePolicy policy)
         396                 : {
         397              12 :     nsCacheServiceAutoLock lock;
         398               6 :     if (!mCacheEntry)  return NS_ERROR_NOT_AVAILABLE;
         399                 :     // XXX validate policy against session?
         400                 :
         401               6 :     bool        storageEnabled = false;
         402               6 :     storageEnabled = nsCacheService::IsStorageEnabledForPolicy_Locked(policy);
         403               6 :     if (!storageEnabled)    return NS_ERROR_FAILURE;
         404                 :
         405                 :     // Don't change the storage policy of entries we can't write
         406               5 :     if (!(mAccessGranted & nsICache::ACCESS_WRITE))
         407               0 :         return NS_ERROR_NOT_AVAILABLE;
         408                 :
         409                 :     // Don't allow a cache entry to move from memory-only to anything else
         410               5 :     if (mCacheEntry->StoragePolicy() == nsICache::STORE_IN_MEMORY &&
         411                 :         policy != nsICache::STORE_IN_MEMORY)
         412               0 :         return NS_ERROR_NOT_AVAILABLE;
         413                 :
         414               5 :     mCacheEntry->SetStoragePolicy(policy);
         415               5 :     mCacheEntry->MarkEntryDirty();
         416               5 :     return NS_OK;
         417                 : }
         418                 :
         419                 :
         420                 : NS_IMETHODIMP
         421               0 : nsCacheEntryDescriptor::GetFile(nsIFile ** result)
         422                 : {
         423               0 :     NS_ENSURE_ARG_POINTER(result);
         424               0 :     nsCacheServiceAutoLock lock;
         425               0 :     if (!mCacheEntry)  return NS_ERROR_NOT_AVAILABLE;
         426                 :
         427               0 :     return nsCacheService::GetFileForEntry(mCacheEntry, result);
         428                 : }
         429                 :
         430                 :
         431                 : NS_IMETHODIMP
         432             228 : nsCacheEntryDescriptor::GetSecurityInfo(nsISupports ** result)
         433                 : {
         434             228 :     NS_ENSURE_ARG_POINTER(result);
         435             456 :     nsCacheServiceAutoLock lock;
         436             228 :     if (!mCacheEntry)  return NS_ERROR_NOT_AVAILABLE;
         437                 :
         438             228 :     *result = mCacheEntry->SecurityInfo();
         439             228 :     NS_IF_ADDREF(*result);
         440             228 :     return NS_OK;
         441                 : }
         442                 :
         443                 :
         444                 : NS_IMETHODIMP
         445               4 : nsCacheEntryDescriptor::SetSecurityInfo(nsISupports * securityInfo)
         446                 : {
         447               8 :     nsCacheServiceAutoLock lock;
         448               4 :     if (!mCacheEntry)  return NS_ERROR_NOT_AVAILABLE;
         449                 :
         450               4 :     mCacheEntry->SetSecurityInfo(securityInfo);
         451               4 :     mCacheEntry->MarkEntryDirty();
         452               4 :     return NS_OK;
         453                 : }
         454                 :
         455                 :
         456                 : NS_IMETHODIMP
         457             252 : nsCacheEntryDescriptor::Doom()
         458                 : {
         459             504 :     nsCacheServiceAutoLock lock;
         460             252 :     if (!mCacheEntry)  return NS_ERROR_NOT_AVAILABLE;
         461                 :
         462             244 :     return nsCacheService::DoomEntry(mCacheEntry);
         463                 : }
         464                 :
         465                 :
         466                 : NS_IMETHODIMP
         467               0 : nsCacheEntryDescriptor::DoomAndFailPendingRequests(nsresult status)
         468                 : {
         469               0 :     nsCacheServiceAutoLock lock;
         470               0 :     if (!mCacheEntry)  return NS_ERROR_NOT_AVAILABLE;
         471                 :
         472               0 :     return NS_ERROR_NOT_IMPLEMENTED;
         473                 : }
         474                 :
         475                 :
         476                 : NS_IMETHODIMP
         477             212 : nsCacheEntryDescriptor::MarkValid()
         478                 : {
         479             424 :     nsCacheServiceAutoLock lock;
         480             212 :     if (!mCacheEntry)  return NS_ERROR_NOT_AVAILABLE;
         481                 :
         482             212 :     nsresult  rv = nsCacheService::ValidateEntry(mCacheEntry);
         483             212 :     return rv;
         484                 : }
         485                 :
         486                 :
         487                 : NS_IMETHODIMP
         488            1768 : nsCacheEntryDescriptor::Close()
         489                 : {
         490            3536 :     nsCacheServiceAutoLock lock;
         491            1768 :     if (!mCacheEntry)  return NS_ERROR_NOT_AVAILABLE;
         492                 :
         493                 :     // XXX perhaps closing descriptors should clear/sever transports
         494                 :
         495                 :     // tell nsCacheService we're going away
         496            1768 :     nsCacheService::CloseDescriptor(this);
         497            1768 :     NS_ASSERTION(mCacheEntry == nsnull, "mCacheEntry not null");
         498                 :
         499            1768 :     return NS_OK;
         500                 : }
         501                 :
         502                 :
         503                 : NS_IMETHODIMP
         504            1395 : nsCacheEntryDescriptor::GetMetaDataElement(const char *key, char **result)
         505                 : {
         506            1395 :     NS_ENSURE_ARG_POINTER(key);
         507            1395 :     *result = nsnull;
         508                 :
         509            2790 :     nsCacheServiceAutoLock lock;
         510            1395 :     NS_ENSURE_TRUE(mCacheEntry, NS_ERROR_NOT_AVAILABLE);
         511                 :
         512                 :     const char *value;
         513                 :
         514            1395 :     value = mCacheEntry->GetMetaDataElement(key);
         515            1395 :     if (!value) return NS_ERROR_NOT_AVAILABLE;
         516                 :
         517            1177 :     *result = NS_strdup(value);
         518            1177 :     if (!*result) return NS_ERROR_OUT_OF_MEMORY;
         519                 :
         520            1177 :     return NS_OK;
         521                 : }
         522                 :
         523                 :
         524                 : NS_IMETHODIMP
         525            3945 : nsCacheEntryDescriptor::SetMetaDataElement(const char *key, const char *value)
         526                 : {
         527            3945 :     NS_ENSURE_ARG_POINTER(key);
         528                 :
         529            7890 :     nsCacheServiceAutoLock lock;
         530            3945 :     NS_ENSURE_TRUE(mCacheEntry, NS_ERROR_NOT_AVAILABLE);
         531                 :
         532                 :     // XXX allow null value, for clearing key?
         533                 :
         534            3945 :     nsresult rv = mCacheEntry->SetMetaDataElement(key, value);
         535            3945 :     if (NS_SUCCEEDED(rv))
         536            3945 :         mCacheEntry->TouchMetaData();
         537            3945 :     return rv;
         538                 : }
         539                 :
         540                 :
         541                 : NS_IMETHODIMP
         542               0 : nsCacheEntryDescriptor::VisitMetaData(nsICacheMetaDataVisitor * visitor)
         543                 : {
         544               0 :     nsCacheServiceAutoLock lock;  // XXX check callers, we're calling out of module
         545               0 :     NS_ENSURE_ARG_POINTER(visitor);
         546               0 :     if (!mCacheEntry)  return NS_ERROR_NOT_AVAILABLE;
         547                 :
         548               0 :     return mCacheEntry->VisitMetaDataElements(visitor);
         549                 : }
         550                 :
         551                 :
         552                 : /******************************************************************************
         553                 :  * nsCacheInputStream - a wrapper for nsIInputStream keeps the cache entry
         554                 :  *                      open while referenced.
         555                 :  ******************************************************************************/
         556                 :
         557            3601 : NS_IMPL_THREADSAFE_ISUPPORTS1(nsCacheEntryDescriptor::nsInputStreamWrapper,
         558                 :                               nsIInputStream)
         559                 :
         560             242 : nsresult nsCacheEntryDescriptor::
         561                 : nsInputStreamWrapper::LazyInit()
         562                 : {
         563             484 :     nsCacheServiceAutoLock lock;
         564                 :
         565                 :     nsCacheAccessMode mode;
         566             242 :     nsresult rv = mDescriptor->GetAccessGranted(&mode);
         567             242 :     if (NS_FAILED(rv)) return rv;
         568                 :
         569             242 :     NS_ENSURE_TRUE(mode & nsICache::ACCESS_READ, NS_ERROR_UNEXPECTED);
         570                 :
         571             242 :     nsCacheEntry* cacheEntry = mDescriptor->CacheEntry();
         572             242 :     if (!cacheEntry) return NS_ERROR_NOT_AVAILABLE;
         573                 :
         574                 :     rv = nsCacheService::OpenInputStreamForEntry(cacheEntry, mode,
         575                 :                                                  mStartOffset,
         576             242 :                                                  getter_AddRefs(mInput));
         577             242 :     if (NS_FAILED(rv)) return rv;
         578                 :
         579             242 :     mInitialized = true;
         580             242 :     return NS_OK;
         581                 : }
         582                 :
         583             242 : nsresult nsCacheEntryDescriptor::
         584                 : nsInputStreamWrapper::Close()
         585                 : {
         586             242 :     nsresult rv = EnsureInit();
         587             242 :     if (NS_FAILED(rv)) return rv;
         588                 :
         589             242 :     return mInput->Close();
         590                 : }
         591                 :
         592              16 : nsresult nsCacheEntryDescriptor::
         593                 : nsInputStreamWrapper::Available(PRUint32 *avail)
         594                 : {
         595              16 :     nsresult rv = EnsureInit();
         596              16 :     if (NS_FAILED(rv)) return rv;
         597                 :
         598              16 :     return mInput->Available(avail);
         599                 : }
         600                 :
         601             476 : nsresult nsCacheEntryDescriptor::
         602                 : nsInputStreamWrapper::Read(char *buf, PRUint32 count, PRUint32 *countRead)
         603                 : {
         604             476 :     nsresult rv = EnsureInit();
         605             476 :     if (NS_FAILED(rv)) return rv;
         606                 :
         607             476 :     return mInput->Read(buf, count, countRead);
         608                 : }
         609                 :
         610               0 : nsresult nsCacheEntryDescriptor::
         611                 : nsInputStreamWrapper::ReadSegments(nsWriteSegmentFun writer, void *closure,
         612                 :                                    PRUint32 count, PRUint32 *countRead)
         613                 : {
         614                 :     // cache stream not buffered
         615               0 :     return NS_ERROR_NOT_IMPLEMENTED;
         616                 : }
         617                 :
         618             217 : nsresult nsCacheEntryDescriptor::
         619                 : nsInputStreamWrapper::IsNonBlocking(bool *result)
         620                 : {
         621                 :     // cache streams will never return NS_BASE_STREAM_WOULD_BLOCK
         622             217 :     *result = false;
         623             217 :     return NS_OK;
         624                 : }
         625                 :
         626                 :
         627                 : /******************************************************************************
         628                 :  * nsDecompressInputStreamWrapper - an input stream wrapper that decompresses
         629                 :  ******************************************************************************/
         630                 :
         631               0 : NS_IMPL_THREADSAFE_ISUPPORTS1(nsCacheEntryDescriptor::nsDecompressInputStreamWrapper,
         632                 :                               nsIInputStream)
         633                 :
         634               0 : NS_IMETHODIMP nsCacheEntryDescriptor::
         635                 : nsDecompressInputStreamWrapper::Read(char *    buf,
         636                 :                                      PRUint32  count,
         637                 :                                      PRUint32 *countRead)
         638                 : {
         639               0 :     int zerr = Z_OK;
         640               0 :     nsresult rv = NS_OK;
         641                 :
         642               0 :     if (!mStreamInitialized) {
         643               0 :         rv = InitZstream();
         644               0 :         if (NS_FAILED(rv)) {
         645               0 :             return rv;
         646                 :         }
         647                 :     }
         648                 :
         649               0 :     mZstream.next_out = (Bytef*)buf;
         650               0 :     mZstream.avail_out = count;
         651                 :
         652               0 :     if (mReadBufferLen < count) {
         653                 :         // Allocate a buffer for reading from the input stream. This will
         654                 :         // determine the max number of compressed bytes read from the
         655                 :         // input stream at one time. Making the buffer size proportional
         656                 :         // to the request size is not necessary, but helps minimize the
         657                 :         // number of read requests to the input stream.
         658               0 :         PRUint32 newBufLen = NS_MAX(count, (PRUint32)kMinDecompressReadBufLen);
         659                 :         unsigned char* newBuf;
         660                 :         newBuf = (unsigned char*)nsMemory::Realloc(mReadBuffer,
         661               0 :             newBufLen);
         662               0 :         if (newBuf) {
         663               0 :             mReadBuffer = newBuf;
         664               0 :             mReadBufferLen = newBufLen;
         665                 :         }
         666               0 :         if (!mReadBuffer) {
         667               0 :             mReadBufferLen = 0;
         668               0 :             return NS_ERROR_OUT_OF_MEMORY;
         669                 :         }
         670                 :     }
         671                 :
         672                 :     // read and inflate data until the output buffer is full, or
         673                 :     // there is no more data to read
         674               0 :     while (NS_SUCCEEDED(rv) &&
         675                 :            zerr == Z_OK &&
         676                 :            mZstream.avail_out > 0 &&
         677                 :            count > 0) {
         678               0 :         if (mZstream.avail_in == 0) {
         679                 :             rv = nsInputStreamWrapper::Read((char*)mReadBuffer,
         680                 :                                             mReadBufferLen,
         681               0 :                                             &mZstream.avail_in);
         682               0 :             if (NS_FAILED(rv) || !mZstream.avail_in) {
         683               0 :                 break;
         684                 :             }
         685               0 :             mZstream.next_in = mReadBuffer;
         686                 :         }
         687               0 :         zerr = inflate(&mZstream, Z_NO_FLUSH);
         688               0 :         if (zerr == Z_STREAM_END) {
         689                 :             // The compressed data may have been stored in multiple
         690                 :             // chunks/streams. To allow for this case, re-initialize
         691                 :             // the inflate stream and continue decompressing from
         692                 :             // the next byte.
         693               0 :             Bytef * saveNextIn = mZstream.next_in;
         694               0 :             unsigned int saveAvailIn = mZstream.avail_in;
         695               0 :             Bytef * saveNextOut = mZstream.next_out;
         696               0 :             unsigned int saveAvailOut = mZstream.avail_out;
         697               0 :             inflateReset(&mZstream);
         698               0 :             mZstream.next_in = saveNextIn;
         699               0 :             mZstream.avail_in = saveAvailIn;
         700               0 :             mZstream.next_out = saveNextOut;
         701               0 :             mZstream.avail_out = saveAvailOut;
         702               0 :             zerr = Z_OK;
         703               0 :         } else if (zerr != Z_OK) {
         704               0 :             rv = NS_ERROR_INVALID_CONTENT_ENCODING;
         705                 :         }
         706                 :     }
         707               0 :     if (NS_SUCCEEDED(rv)) {
         708               0 :         *countRead = count - mZstream.avail_out;
         709                 :     }
         710               0 :     return rv;
         711                 : }
         712                 :
         713               0 : nsresult nsCacheEntryDescriptor::
         714                 : nsDecompressInputStreamWrapper::Close()
         715                 : {
         716               0 :     EndZstream();
         717               0 :     if (mReadBuffer) {
         718               0 :         nsMemory::Free(mReadBuffer);
         719               0 :         mReadBuffer = 0;
         720               0 :         mReadBufferLen = 0;
         721                 :     }
         722               0 :     return nsInputStreamWrapper::Close();
         723                 : }
         724                 :
         725               0 : nsresult nsCacheEntryDescriptor::
         726                 : nsDecompressInputStreamWrapper::InitZstream()
         727                 : {
         728                 :     // Initialize zlib inflate stream
         729               0 :     mZstream.zalloc = Z_NULL;
         730               0 :     mZstream.zfree = Z_NULL;
         731               0 :     mZstream.opaque = Z_NULL;
         732               0 :     mZstream.next_out = Z_NULL;
         733               0 :     mZstream.avail_out = 0;
         734               0 :     mZstream.next_in = Z_NULL;
         735               0 :     mZstream.avail_in = 0;
         736               0 :     if (inflateInit(&mZstream) != Z_OK) {
         737               0 :         return NS_ERROR_FAILURE;
         738                 :     }
         739               0 :     mStreamInitialized = PR_TRUE;
         740               0 :     return NS_OK;
         741                 : }
         742                 :
         743               0 : nsresult nsCacheEntryDescriptor::
         744                 : nsDecompressInputStreamWrapper::EndZstream()
         745                 : {
         746               0 :     if (mStreamInitialized && !mStreamEnded) {
         747               0 :         inflateEnd(&mZstream);
         748               0 :         mStreamEnded = PR_TRUE;
         749                 :     }
         750               0 :     return NS_OK;
         751                 : }
         752                 :
         753                 :
         754                 : /******************************************************************************
         755                 :  * nsOutputStreamWrapper - a wrapper for nsIOutputstream to track the amount of
         756                 :  *                         data written to a cache entry.
         757                 :  *                       - also keeps the cache entry open while referenced.
         758                 :  ******************************************************************************/
         759                 :
         760           24349 : NS_IMPL_THREADSAFE_ISUPPORTS1(nsCacheEntryDescriptor::nsOutputStreamWrapper,
         761                 :                               nsIOutputStream)
         762                 :
         763            1254 : nsresult nsCacheEntryDescriptor::
         764                 : nsOutputStreamWrapper::LazyInit()
         765                 : {
         766            2508 :     nsCacheServiceAutoLock lock;
         767                 :
         768                 :     nsCacheAccessMode mode;
         769            1254 :     nsresult rv = mDescriptor->GetAccessGranted(&mode);
         770            1254 :     if (NS_FAILED(rv)) return rv;
         771                 :
         772            1254 :     NS_ENSURE_TRUE(mode & nsICache::ACCESS_WRITE, NS_ERROR_UNEXPECTED);
         773                 :
         774            1254 :     nsCacheEntry* cacheEntry = mDescriptor->CacheEntry();
         775            1254 :     if (!cacheEntry) return NS_ERROR_NOT_AVAILABLE;
         776                 :
         777            1251 :     NS_ASSERTION(mOutput == nsnull, "mOutput set in LazyInit");
         778                 :
         779            2502 :     nsCOMPtr<nsIOutputStream> stream;
         780                 :     rv = nsCacheService::OpenOutputStreamForEntry(cacheEntry, mode, mStartOffset,
         781            1251 :                                                   getter_AddRefs(stream));
         782            1251 :     if (NS_FAILED(rv))
         783             119 :         return rv;
         784                 :
         785            1132 :     nsCacheDevice* device = cacheEntry->CacheDevice();
         786            1132 :     if (device) {
         787                 :         // the entry has been truncated to mStartOffset bytes, inform device
         788            1132 :         PRInt32 size = cacheEntry->DataSize();
         789            1132 :         rv = device->OnDataSizeChange(cacheEntry, mStartOffset - size);
         790            1132 :         if (NS_SUCCEEDED(rv))
         791            1130 :             cacheEntry->SetDataSize(mStartOffset);
         792                 :     } else {
         793               0 :         rv = NS_ERROR_NOT_AVAILABLE;
         794                 :     }
         795                 :
         796                 :     // If anything above failed, clean up internal state and get out of here
         797                 :     // (see bug #654926)...
         798            1132 :     if (NS_FAILED(rv)) {
         799               2 :         mDescriptor->InternalCleanup(stream);
         800               2 :         return rv;
         801                 :     }
         802                 :
         803                 :     // ... otherwise, set members and mark initialized
         804            1130 :     mDescriptor->mOutput = mOutput = stream;
         805            1130 :     mInitialized = true;
         806            1130 :     return NS_OK;
         807                 : }
         808                 :
         809            1515 : nsresult nsCacheEntryDescriptor::
         810                 : nsOutputStreamWrapper::OnWrite(PRUint32 count)
         811                 : {
         812            1515 :     if (count > PR_INT32_MAX)  return NS_ERROR_UNEXPECTED;
         813            1515 :     return mDescriptor->RequestDataSizeChange((PRInt32)count);
         814                 : }
         815                 :
         816            1230 : NS_IMETHODIMP nsCacheEntryDescriptor::
         817                 : nsOutputStreamWrapper::Close()
         818                 : {
         819            1230 :     nsresult rv = EnsureInit();
         820            1230 :     if (NS_FAILED(rv)) return rv;
         821                 :
         822            1165 :     return mOutput->Close();
         823                 : }
         824                 :
         825               0 : NS_IMETHODIMP nsCacheEntryDescriptor::
         826                 : nsOutputStreamWrapper::Flush()
         827                 : {
         828               0 :     nsresult rv = EnsureInit();
         829               0 :     if (NS_FAILED(rv)) return rv;
         830                 :
         831               0 :     return mOutput->Flush();
         832                 : }
         833                 :
         834            1574 : NS_IMETHODIMP nsCacheEntryDescriptor::
         835                 : nsOutputStreamWrapper::Write(const char * buf,
         836                 :                              PRUint32     count,
         837                 :                              PRUint32 *   result)
         838                 : {
         839            1574 :     nsresult rv = EnsureInit();
         840            1574 :     if (NS_FAILED(rv)) return rv;
         841                 :
         842            1515 :     rv = OnWrite(count);
         843            1515 :     if (NS_FAILED(rv)) return rv;
         844                 :
         845            1515 :     return mOutput->Write(buf, count, result);
         846                 : }
         847                 :
         848               0 : NS_IMETHODIMP nsCacheEntryDescriptor::
         849                 : nsOutputStreamWrapper::WriteFrom(nsIInputStream * inStr,
         850                 :                                  PRUint32         count,
         851                 :                                  PRUint32 *       result)
         852                 : {
         853               0 :     return NS_ERROR_NOT_IMPLEMENTED;
         854                 : }
         855                 :
         856               0 : NS_IMETHODIMP nsCacheEntryDescriptor::
         857                 : nsOutputStreamWrapper::WriteSegments(nsReadSegmentFun  reader,
         858                 :                                      void *            closure,
         859                 :                                      PRUint32          count,
         860                 :                                      PRUint32 *        result)
         861                 : {
         862               0 :     return NS_ERROR_NOT_IMPLEMENTED;
         863                 : }
         864                 :
         865            2453 : NS_IMETHODIMP nsCacheEntryDescriptor::
         866                 : nsOutputStreamWrapper::IsNonBlocking(bool *result)
         867                 : {
         868                 :     // cache streams will never return NS_BASE_STREAM_WOULD_BLOCK
         869            2453 :     *result = false;
         870            2453 :     return NS_OK;
         871                 : }
         872                 :
         873                 :
         874                 : /******************************************************************************
         875                 :  * nsCompressOutputStreamWrapper - an output stream wrapper that compresses
         876                 :  *   data before it is written
         877                 :  ******************************************************************************/
         878                 :
         879               0 : NS_IMPL_THREADSAFE_ISUPPORTS1(nsCacheEntryDescriptor::nsCompressOutputStreamWrapper,
         880                 :                               nsIOutputStream)
         881                 :
         882               0 : NS_IMETHODIMP nsCacheEntryDescriptor::
         883                 : nsCompressOutputStreamWrapper::Write(const char * buf,
         884                 :                                      PRUint32     count,
         885                 :                                      PRUint32 *   result)
         886                 : {
         887               0 :     int zerr = Z_OK;
         888               0 :     nsresult rv = NS_OK;
         889                 :
         890               0 :     if (!mStreamInitialized) {
         891               0 :         rv = InitZstream();
         892               0 :         if (NS_FAILED(rv)) {
         893               0 :             return rv;
         894                 :         }
         895                 :     }
         896                 :
         897               0 :     if (!mWriteBuffer) {
         898                 :         // Once allocated, this buffer is referenced by the zlib stream and
         899                 :         // cannot be grown. We use 2x(initial write request) to approximate
         900                 :         // a stream buffer size proportional to request buffers.
         901               0 :         mWriteBufferLen = NS_MAX(count*2, (PRUint32)kMinCompressWriteBufLen);
         902               0 :         mWriteBuffer = (unsigned char*)nsMemory::Alloc(mWriteBufferLen);
         903               0 :         if (!mWriteBuffer) {
         904               0 :             mWriteBufferLen = 0;
         905               0 :             return NS_ERROR_OUT_OF_MEMORY;
         906                 :         }
         907               0 :         mZstream.next_out = mWriteBuffer;
         908               0 :         mZstream.avail_out = mWriteBufferLen;
         909                 :     }
         910                 :
         911                 :     // Compress (deflate) the requested buffer. Keep going
         912                 :     // until the entire buffer has been deflated.
         913               0 :     mZstream.avail_in = count;
         914               0 :     mZstream.next_in = (Bytef*)buf;
         915               0 :     while (mZstream.avail_in > 0) {
         916               0 :         zerr = deflate(&mZstream, Z_NO_FLUSH);
         917               0 :         if (zerr == Z_STREAM_ERROR) {
         918               0 :             deflateEnd(&mZstream);
         919               0 :             mStreamInitialized = PR_FALSE;
         920               0 :             return NS_ERROR_FAILURE;
         921                 :         }
         922                 :         // Note: Z_BUF_ERROR is non-fatal and sometimes expected here.
         923                 :
         924                 :         // If the compression stream output buffer is filled, write
         925                 :         // it out to the underlying stream wrapper.
         926               0 :         if (mZstream.avail_out == 0) {
         927               0 :             rv = WriteBuffer();
         928               0 :             if (NS_FAILED(rv)) {
         929               0 :                 deflateEnd(&mZstream);
         930               0 :                 mStreamInitialized = PR_FALSE;
         931               0 :                 return rv;
         932                 :             }
         933                 :         }
         934                 :     }
         935               0 :     *result = count;
         936               0 :     mUncompressedCount += *result;
         937               0 :     return NS_OK;
         938                 : }
         939                 :
         940               0 : NS_IMETHODIMP nsCacheEntryDescriptor::
         941                 : nsCompressOutputStreamWrapper::Close()
         942                 : {
         943               0 :     nsresult rv = NS_OK;
         944               0 :     int zerr = 0;
         945                 :
         946               0 :     if (mStreamInitialized) {
         947                 :         // complete compression of any data remaining in the zlib stream
         948               0 :         do {
         949               0 :             zerr = deflate(&mZstream, Z_FINISH);
         950               0 :             rv = WriteBuffer();
         951                 :         } while (zerr == Z_OK && rv == NS_OK);
         952               0 :         deflateEnd(&mZstream);
         953                 :     }
         954                 :
         955               0 :     if (mDescriptor->CacheEntry()) {
         956               0 :         nsCAutoString uncompressedLenStr;
         957                 :         rv = mDescriptor->GetMetaDataElement("uncompressed-len",
         958               0 :                                              getter_Copies(uncompressedLenStr));
         959               0 :         if (NS_SUCCEEDED(rv)) {
         960               0 :             PRInt32 oldCount = uncompressedLenStr.ToInteger(&rv);
         961               0 :             if (NS_SUCCEEDED(rv)) {
         962               0 :                 mUncompressedCount += oldCount;
         963                 :             }
         964                 :         }
         965               0 :         uncompressedLenStr.Adopt(0);
         966               0 :         uncompressedLenStr.AppendInt(mUncompressedCount);
         967                 :         rv = mDescriptor->SetMetaDataElement("uncompressed-len",
         968               0 :             uncompressedLenStr.get());
         969                 :     }
         970                 :
         971               0 :     if (mWriteBuffer) {
         972               0 :         nsMemory::Free(mWriteBuffer);
         973               0 :         mWriteBuffer = 0;
         974               0 :         mWriteBufferLen = 0;
         975                 :     }
         976                 :
         977               0 :     return nsOutputStreamWrapper::Close();
         978                 : }
         979                 :
         980               0 : nsresult nsCacheEntryDescriptor::
         981                 : nsCompressOutputStreamWrapper::InitZstream()
         982                 : {
         983                 :     // Determine compression level: Aggressive compression
         984                 :     // may impact performance on mobile devices, while a
         985                 :     // lower compression level still provides substantial
         986                 :     // space savings for many text streams.
         987               0 :     PRInt32 compressionLevel = nsCacheService::CacheCompressionLevel();
         988                 :
         989                 :     // Initialize zlib deflate stream
         990               0 :     mZstream.zalloc = Z_NULL;
         991               0 :     mZstream.zfree = Z_NULL;
         992               0 :     mZstream.opaque = Z_NULL;
         993               0 :     if (deflateInit2(&mZstream, compressionLevel, Z_DEFLATED,
         994                 :                      MAX_WBITS, 8, Z_DEFAULT_STRATEGY) != Z_OK) {
         995               0 :         return NS_ERROR_FAILURE;
         996                 :     }
         997               0 :     mZstream.next_in = Z_NULL;
         998               0 :     mZstream.avail_in = 0;
         999                 :
        1000               0 :     mStreamInitialized = PR_TRUE;
        1001                 :
        1002               0 :     return NS_OK;
        1003                 : }
        1004                 :
        1005               0 : nsresult nsCacheEntryDescriptor::
        1006                 : nsCompressOutputStreamWrapper::WriteBuffer()
        1007                 : {
        1008               0 :     PRUint32 bytesToWrite = mWriteBufferLen - mZstream.avail_out;
        1009               0 :     PRUint32 result = 0;
        1010                 :     nsresult rv = nsCacheEntryDescriptor::nsOutputStreamWrapper::Write(
        1011               0 :         (const char *)mWriteBuffer, bytesToWrite, &result);
        1012               0 :     mZstream.next_out = mWriteBuffer;
        1013               0 :     mZstream.avail_out = mWriteBufferLen;
        1014               0 :     return rv;
        1015                 : }
        1016                 :

Generated by: LCOV version 1.7