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-06-02 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