LCOV - app.info - netwerk/base/src/nsUnicharStreamLoader.cpp

LCOV - code coverage report
| Current view: | directory - netwerk/base/src - nsUnicharStreamLoader.cpp (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 101 | 33 | 32.7 %
| Date: | 2012-04-21 | Functions: | 12 | 8 | 66.7 %

           1                 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
           2                 : /* ***** BEGIN LICENSE BLOCK *****
           3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
           4                 :  *
           5                 :  * The contents of this file are subject to the Mozilla Public License Version
           6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
           7                 :  * the License. You may obtain a copy of the License at
           8                 :  * http://www.mozilla.org/MPL/
           9                 :  *
          10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
          11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
          12                 :  * for the specific language governing rights and limitations under the
          13                 :  * License.
          14                 :  *
          15                 :  * The Original Code is mozilla.org code.
          16                 :  *
          17                 :  * The Initial Developer of the Original Code is
          18                 :  * Netscape Communications Corporation.
          19                 :  * Portions created by the Initial Developer are Copyright (C) 2002
          20                 :  * the Initial Developer. All Rights Reserved.
          21                 :  *
          22                 :  * Contributor(s):
          23                 :  *    Boris Zbarsky <bzbarsky@mit.edu>  (original author)
          24                 :  *
          25                 :  * Alternatively, the contents of this file may be used under the terms of
          26                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
          27                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
          28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
          29                 :  * of those above. If you wish to allow use of your version of this file only
          30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
          31                 :  * use your version of this file under the terms of the MPL, indicate your
          32                 :  * decision by deleting the provisions above and replace them with the notice
          33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
          34                 :  * the provisions above, a recipient may use your version of this file under
          35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
          36                 :  *
          37                 :  * ***** END LICENSE BLOCK ***** */
          38                 :
          39                 : #include "nsUnicharStreamLoader.h"
          40                 : #include "nsIInputStream.h"
          41                 : #include "nsICharsetConverterManager.h"
          42                 : #include "nsIServiceManager.h"
          43                 :
          44                 : #define SNIFFING_BUFFER_SIZE 512 // specified in draft-abarth-mime-sniff-06
          45                 :
          46                 : NS_IMETHODIMP
          47               2 : nsUnicharStreamLoader::Init(nsIUnicharStreamLoaderObserver *aObserver)
          48                 : {
          49               2 :   NS_ENSURE_ARG_POINTER(aObserver);
          50                 :
          51               2 :   mObserver = aObserver;
          52                 :
          53               2 :   if (!mRawData.SetCapacity(SNIFFING_BUFFER_SIZE))
          54               0 :     return NS_ERROR_OUT_OF_MEMORY;
          55                 :
          56               2 :   return NS_OK;
          57                 : }
          58                 :
          59                 : nsresult
          60               2 : nsUnicharStreamLoader::Create(nsISupports *aOuter,
          61                 :                               REFNSIID aIID,
          62                 :                               void **aResult)
          63                 : {
          64               2 :   if (aOuter) return NS_ERROR_NO_AGGREGATION;
          65                 :
          66               2 :   nsUnicharStreamLoader* it = new nsUnicharStreamLoader();
          67               2 :   NS_ADDREF(it);
          68               2 :   nsresult rv = it->QueryInterface(aIID, aResult);
          69               2 :   NS_RELEASE(it);
          70               2 :   return rv;
          71                 : }
          72                 :
          73              46 : NS_IMPL_ISUPPORTS3(nsUnicharStreamLoader, nsIUnicharStreamLoader,
          74                 :                    nsIRequestObserver, nsIStreamListener)
          75                 :
          76                 : /* readonly attribute nsIChannel channel; */
          77                 : NS_IMETHODIMP
          78               1 : nsUnicharStreamLoader::GetChannel(nsIChannel **aChannel)
          79                 : {
          80               1 :   NS_IF_ADDREF(*aChannel = mChannel);
          81               1 :   return NS_OK;
          82                 : }
          83                 :
          84                 : /* readonly attribute nsACString charset */
          85                 : NS_IMETHODIMP
          86               0 : nsUnicharStreamLoader::GetCharset(nsACString& aCharset)
          87                 : {
          88               0 :   aCharset = mCharset;
          89               0 :   return NS_OK;
          90                 : }
          91                 :
          92                 : /* nsIRequestObserver implementation */
          93                 : NS_IMETHODIMP
          94               1 : nsUnicharStreamLoader::OnStartRequest(nsIRequest*, nsISupports*)
          95                 : {
          96               1 :   return NS_OK;
          97                 : }
          98                 :
          99                 : NS_IMETHODIMP
         100               1 : nsUnicharStreamLoader::OnStopRequest(nsIRequest *aRequest,
         101                 :                                      nsISupports *aContext,
         102                 :                                      nsresult aStatus)
         103                 : {
         104               1 :   if (!mObserver) {
         105               0 :     NS_ERROR("nsUnicharStreamLoader::OnStopRequest called before ::Init");
         106               0 :     return NS_ERROR_UNEXPECTED;
         107                 :   }
         108                 :
         109               1 :   mContext = aContext;
         110               1 :   mChannel = do_QueryInterface(aRequest);
         111                 :
         112               1 :   nsresult rv = NS_OK;
         113               1 :   if (mRawData.Length() > 0 && NS_SUCCEEDED(aStatus)) {
         114               0 :     NS_ABORT_IF_FALSE(mBuffer.Length() == 0,
         115                 :                       "should not have both decoded and raw data");
         116               0 :     rv = DetermineCharset();
         117                 :   }
         118                 :
         119               1 :   if (NS_FAILED(rv)) {
         120                 :     // Call the observer but pass it no data.
         121               0 :     mObserver->OnStreamComplete(this, mContext, rv, EmptyString());
         122                 :   } else {
         123               1 :     mObserver->OnStreamComplete(this, mContext, aStatus, mBuffer);
         124                 :   }
         125                 :
         126               1 :   mObserver = nsnull;
         127               1 :   mDecoder = nsnull;
         128               1 :   mContext = nsnull;
         129               1 :   mChannel = nsnull;
         130               1 :   mCharset.Truncate();
         131               1 :   mBuffer.Truncate();
         132               1 :   return rv;
         133                 : }
         134                 :
         135                 : /* nsIStreamListener implementation */
         136                 : NS_IMETHODIMP
         137               0 : nsUnicharStreamLoader::OnDataAvailable(nsIRequest *aRequest,
         138                 :                                        nsISupports *aContext,
         139                 :                                        nsIInputStream *aInputStream,
         140                 :                                        PRUint32 aSourceOffset,
         141                 :                                        PRUint32 aCount)
         142                 : {
         143               0 :   if (!mObserver) {
         144               0 :     NS_ERROR("nsUnicharStreamLoader::OnDataAvailable called before ::Init");
         145               0 :     return NS_ERROR_UNEXPECTED;
         146                 :   }
         147                 :
         148               0 :   mContext = aContext;
         149               0 :   mChannel = do_QueryInterface(aRequest);
         150                 :
         151               0 :   nsresult rv = NS_OK;
         152               0 :   if (mDecoder) {
         153                 :     // process everything we've got
         154                 :     PRUint32 dummy;
         155               0 :     aInputStream->ReadSegments(WriteSegmentFun, this, aCount, &dummy);
         156                 :   } else {
         157                 :     // no decoder yet.  Read up to SNIFFING_BUFFER_SIZE octets into
         158                 :     // mRawData (this is the cutoff specified in
         159                 :     // draft-abarth-mime-sniff-06).  If we can get that much, then go
         160                 :     // ahead and fire charset detection and read the rest.  Otherwise
         161                 :     // wait for more data.
         162                 :
         163               0 :     PRUint32 haveRead = mRawData.Length();
         164               0 :     PRUint32 toRead = NS_MIN(SNIFFING_BUFFER_SIZE - haveRead, aCount);
         165                 :     PRUint32 n;
         166               0 :     char *here = mRawData.BeginWriting() + haveRead;
         167                 :
         168               0 :     rv = aInputStream->Read(here, toRead, &n);
         169               0 :     if (NS_SUCCEEDED(rv)) {
         170               0 :       mRawData.SetLength(haveRead + n);
         171               0 :       if (mRawData.Length() == SNIFFING_BUFFER_SIZE) {
         172               0 :         rv = DetermineCharset();
         173               0 :         if (NS_SUCCEEDED(rv)) {
         174                 :           // process what's left
         175                 :           PRUint32 dummy;
         176               0 :           aInputStream->ReadSegments(WriteSegmentFun, this, aCount - n, &dummy);
         177                 :         }
         178                 :       } else {
         179               0 :         NS_ABORT_IF_FALSE(n == aCount, "didn't read as much as was available");
         180                 :       }
         181                 :     }
         182                 :   }
         183                 :
         184               0 :   mContext = nsnull;
         185               0 :   mChannel = nsnull;
         186               0 :   return rv;
         187                 : }
         188                 :
         189                 : /* internal */
         190                 : static NS_DEFINE_CID(kCharsetConverterManagerCID,
         191                 :                      NS_ICHARSETCONVERTERMANAGER_CID);
         192                 :
         193                 : nsresult
         194               0 : nsUnicharStreamLoader::DetermineCharset()
         195                 : {
         196               0 :   nsresult rv = mObserver->OnDetermineCharset(this, mContext,
         197               0 :                                               mRawData, mCharset);
         198               0 :   if (NS_FAILED(rv) || mCharset.IsEmpty()) {
         199                 :     // The observer told us nothing useful
         200               0 :     mCharset.AssignLiteral("UTF-8");
         201                 :   }
         202                 :
         203                 :   // Create the decoder for this character set
         204                 :   nsCOMPtr<nsICharsetConverterManager> ccm =
         205               0 :     do_GetService(kCharsetConverterManagerCID, &rv);
         206               0 :   if (NS_FAILED(rv)) return rv;
         207                 :
         208               0 :   rv = ccm->GetUnicodeDecoder(mCharset.get(), getter_AddRefs(mDecoder));
         209               0 :   if (NS_FAILED(rv)) return rv;
         210                 :
         211                 :   // Process the data into mBuffer
         212                 :   PRUint32 dummy;
         213                 :   rv = WriteSegmentFun(nsnull, this,
         214                 :                        mRawData.BeginReading(),
         215                 :                        0, mRawData.Length(),
         216               0 :                        &dummy);
         217               0 :   mRawData.Truncate();
         218               0 :   return rv;
         219                 : }
         220                 :
         221                 : NS_METHOD
         222               0 : nsUnicharStreamLoader::WriteSegmentFun(nsIInputStream *,
         223                 :                                        void *aClosure,
         224                 :                                        const char *aSegment,
         225                 :                                        PRUint32,
         226                 :                                        PRUint32 aCount,
         227                 :                                        PRUint32 *aWriteCount)
         228                 : {
         229               0 :   nsUnicharStreamLoader* self = static_cast<nsUnicharStreamLoader*>(aClosure);
         230                 :
         231               0 :   PRUint32 haveRead = self->mBuffer.Length();
         232               0 :   PRUint32 consumed = 0;
         233                 :   nsresult rv;
         234               0 :   do {
         235               0 :     PRInt32 srcLen = aCount - consumed;
         236                 :     PRInt32 dstLen;
         237               0 :     self->mDecoder->GetMaxLength(aSegment + consumed, srcLen, &dstLen);
         238                 :
         239               0 :     PRUint32 capacity = haveRead + dstLen;
         240               0 :     if (!self->mBuffer.SetCapacity(capacity)) {
         241               0 :       return NS_ERROR_OUT_OF_MEMORY;
         242                 :     }
         243                 :
         244               0 :     rv = self->mDecoder->Convert(aSegment + consumed,
         245                 :                                  &srcLen,
         246               0 :                                  self->mBuffer.BeginWriting() + haveRead,
         247               0 :                                  &dstLen);
         248               0 :     haveRead += dstLen;
         249                 :     // XXX if srcLen is negative, we want to drop the _first_ byte in
         250                 :     // the erroneous byte sequence and try again.  This is not quite
         251                 :     // possible right now -- see bug 160784
         252               0 :     consumed += srcLen;
         253               0 :     if (NS_FAILED(rv)) {
         254               0 :       NS_ASSERTION(0 < capacity - haveRead,
         255                 :                    "Decoder returned an error but filled the output buffer! "
         256                 :                    "Should not happen.");
         257               0 :       self->mBuffer.BeginWriting()[haveRead++] = 0xFFFD;
         258               0 :       ++consumed;
         259                 :       // XXX this is needed to make sure we don't underrun our buffer;
         260                 :       // bug 160784 again
         261               0 :       consumed = NS_MAX<PRUint32>(consumed, 0);
         262               0 :       self->mDecoder->Reset();
         263                 :     }
         264                 :   } while (consumed < aCount);
         265                 :
         266               0 :   self->mBuffer.SetLength(haveRead);
         267               0 :   *aWriteCount = aCount;
         268               0 :   return NS_OK;
         269                 : }

Generated by: LCOV version 1.7