LCOV - code coverage report
Current view: top level - netwerk/streamconv/converters - nsBinHexDecoder.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 213 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 15 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include "nsIOService.h"
       7             : #include "nsBinHexDecoder.h"
       8             : #include "nsIServiceManager.h"
       9             : #include "nsIStreamConverterService.h"
      10             : #include "nsCRT.h"
      11             : #include "nsIPipe.h"
      12             : #include "nsMimeTypes.h"
      13             : #include "netCore.h"
      14             : #include "nsXPIDLString.h"
      15             : #include "prnetdb.h"
      16             : #include "nsIURI.h"
      17             : #include "nsIURL.h"
      18             : 
      19             : #include "nsIMIMEService.h"
      20             : #include "nsMimeTypes.h"
      21             : #include <algorithm>
      22             : 
      23             : namespace mozilla {
      24             : namespace net {
      25             : 
      26           0 : nsBinHexDecoder::nsBinHexDecoder() :
      27             :   mState(0), mCRC(0), mFileCRC(0), mOctetin(26),
      28             :   mDonePos(3), mInCRC(0), mCount(0), mMarker(0), mPosInbuff(0),
      29           0 :   mPosOutputBuff(0)
      30             : {
      31           0 :   mDataBuffer = nullptr;
      32           0 :   mOutgoingBuffer = nullptr;
      33           0 :   mPosInDataBuffer = 0;
      34           0 :   mRlebuf = 0;
      35             : 
      36           0 :   mOctetBuf.val = 0;
      37           0 :   mHeader.type = 0;
      38           0 :   mHeader.creator = 0;
      39           0 :   mHeader.flags = 0;
      40           0 :   mHeader.dlen = 0;
      41           0 :   mHeader.rlen = 0;
      42           0 : }
      43             : 
      44           0 : nsBinHexDecoder::~nsBinHexDecoder()
      45             : {
      46           0 :   if (mDataBuffer)
      47           0 :     free(mDataBuffer);
      48           0 :   if (mOutgoingBuffer)
      49           0 :     free(mOutgoingBuffer);
      50           0 : }
      51             : 
      52           0 : NS_IMPL_ADDREF(nsBinHexDecoder)
      53           0 : NS_IMPL_RELEASE(nsBinHexDecoder)
      54             : 
      55           0 : NS_INTERFACE_MAP_BEGIN(nsBinHexDecoder)
      56           0 :   NS_INTERFACE_MAP_ENTRY(nsIStreamConverter)
      57           0 :   NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
      58           0 :   NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
      59           0 :   NS_INTERFACE_MAP_ENTRY(nsISupports)
      60           0 : NS_INTERFACE_MAP_END
      61             : 
      62             : 
      63             : // The binhex 4.0 decoder table....
      64             : 
      65             : static const signed char binhex_decode[256] =
      66             : {
      67             :   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      68             :   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      69             :   -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, -1, -1,
      70             :   13, 14, 15, 16, 17, 18, 19, -1, 20, 21, -1, -1, -1, -1, -1, -1,
      71             :   22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, -1,
      72             :   37, 38, 39, 40, 41, 42, 43, -1, 44, 45, 46, 47, -1, -1, -1, -1,
      73             :   48, 49, 50, 51, 52, 53, 54, -1, 55, 56, 57, 58, 59, 60, -1, -1,
      74             :   61, 62, 63, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      75             :   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      76             :   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      77             :   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      78             :   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      79             :   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      80             :   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      81             :   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      82             :   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      83             : };
      84             : 
      85             : #define BHEXVAL(c) (binhex_decode[(unsigned char) c])
      86             : 
      87             : //////////////////////////////////////////////////////
      88             : // nsIStreamConverter methods...
      89             : //////////////////////////////////////////////////////
      90             : 
      91             : NS_IMETHODIMP
      92           0 : nsBinHexDecoder::Convert(nsIInputStream *aFromStream,
      93             :                          const char *aFromType,
      94             :                          const char *aToType,
      95             :                          nsISupports *aCtxt,
      96             :                          nsIInputStream **aResultStream)
      97             : {
      98           0 :   return NS_ERROR_NOT_IMPLEMENTED;
      99             : }
     100             : 
     101             : NS_IMETHODIMP
     102           0 : nsBinHexDecoder::AsyncConvertData(const char *aFromType,
     103             :                                   const char *aToType,
     104             :                                   nsIStreamListener *aListener,
     105             :                                   nsISupports *aCtxt)
     106             : {
     107           0 :   NS_ASSERTION(aListener && aFromType && aToType,
     108             :                "null pointer passed into bin hex converter");
     109             : 
     110             :   // hook up our final listener. this guy gets the various On*() calls we want to throw
     111             :   // at him.
     112             :   //
     113           0 :   mNextListener = aListener;
     114           0 :   return (aListener) ? NS_OK : NS_ERROR_FAILURE;
     115             : }
     116             : 
     117             : //////////////////////////////////////////////////////
     118             : // nsIStreamListener methods...
     119             : //////////////////////////////////////////////////////
     120             : NS_IMETHODIMP
     121           0 : nsBinHexDecoder::OnDataAvailable(nsIRequest* request,
     122             :                                  nsISupports *aCtxt,
     123             :                                  nsIInputStream *aStream,
     124             :                                  uint64_t aSourceOffset,
     125             :                                  uint32_t aCount)
     126             : {
     127           0 :   nsresult rv = NS_OK;
     128             : 
     129           0 :   if (mOutputStream && mDataBuffer && aCount > 0)
     130             :   {
     131           0 :     uint32_t numBytesRead = 0;
     132           0 :     while (aCount > 0) // while we still have bytes to copy...
     133             :     {
     134           0 :       aStream->Read(mDataBuffer, std::min(aCount, nsIOService::gDefaultSegmentSize - 1), &numBytesRead);
     135           0 :       if (aCount >= numBytesRead)
     136           0 :         aCount -= numBytesRead; // subtract off the number of bytes we just read
     137             :       else
     138           0 :         aCount = 0;
     139             : 
     140             :       // Process this new chunk of bin hex data...
     141           0 :       ProcessNextChunk(request, aCtxt, numBytesRead);
     142             :     }
     143             :   }
     144             : 
     145           0 :   return rv;
     146             : }
     147             : 
     148           0 : nsresult nsBinHexDecoder::ProcessNextState(nsIRequest * aRequest, nsISupports * aContext)
     149             : {
     150           0 :   nsresult status = NS_OK;
     151             :   uint16_t tmpcrc, cval;
     152           0 :   unsigned char ctmp, c = mRlebuf;
     153             : 
     154             :   /* do CRC */
     155           0 :   ctmp = mInCRC ? c : 0;
     156           0 :   cval = mCRC & 0xf000;
     157           0 :   tmpcrc = ((uint16_t) (mCRC << 4) | (ctmp >> 4)) ^ (cval | (cval >> 7) | (cval >> 12));
     158           0 :   cval = tmpcrc & 0xf000;
     159           0 :   mCRC = ((uint16_t) (tmpcrc << 4) | (ctmp & 0x0f)) ^ (cval | (cval >> 7) | (cval >> 12));
     160             : 
     161             :   /* handle state */
     162           0 :   switch (mState)
     163             :   {
     164             :     case BINHEX_STATE_START:
     165           0 :       mState = BINHEX_STATE_FNAME;
     166           0 :       mCount = 0;
     167             : 
     168             :       // c & 63 returns the length of mName. So if we need the length, that's how
     169             :       // you can figure it out....
     170           0 :       mName.SetLength(c & 63);
     171           0 :       if (mName.Length() != (c & 63)) {
     172             :         /* XXX ProcessNextState/ProcessNextChunk aren't rv checked */
     173           0 :         mState = BINHEX_STATE_DONE;
     174             :       }
     175           0 :       break;
     176             : 
     177             :     case BINHEX_STATE_FNAME:
     178           0 :       if (mCount < mName.Length()) {
     179           0 :         mName.BeginWriting()[mCount] = c;
     180             :       }
     181             : 
     182           0 :       if (++mCount > mName.Length())
     183             :       {
     184             :         // okay we've figured out the file name....set the content type on the channel
     185             :         // based on the file name AND issue our delayed on start request....
     186             : 
     187           0 :         DetectContentType(aRequest, mName);
     188             :         // now propagate the on start request
     189           0 :         mNextListener->OnStartRequest(aRequest, aContext);
     190             : 
     191           0 :         mState = BINHEX_STATE_HEADER;
     192           0 :         mCount = 0;
     193             :       }
     194           0 :       break;
     195             : 
     196             :     case BINHEX_STATE_HEADER:
     197           0 :       ((char *) &mHeader)[mCount] = c;
     198           0 :       if (++mCount == 18)
     199             :       {
     200             :         if (sizeof(binhex_header) != 18)  /* fix an alignment problem in some OSes */
     201             :         {
     202           0 :           char *p = (char *)&mHeader;
     203           0 :           p += 19;
     204           0 :           for (c = 0; c < 8; c++)
     205             :           {
     206           0 :             *p = *(p-2);
     207           0 :             --p;
     208             :           }
     209             :         }
     210             : 
     211           0 :         mState = BINHEX_STATE_HCRC;
     212           0 :         mInCRC = 1;
     213           0 :         mCount = 0;
     214             :       }
     215           0 :       break;
     216             : 
     217             :     case BINHEX_STATE_DFORK:
     218             :     case BINHEX_STATE_RFORK:
     219           0 :       mOutgoingBuffer[mPosOutputBuff++] = c;
     220           0 :       if (--mCount == 0)
     221             :       {
     222             :         /* only output data fork in the non-mac system.      */
     223           0 :         if (mState == BINHEX_STATE_DFORK)
     224             :         {
     225           0 :           uint32_t numBytesWritten = 0;
     226           0 :           mOutputStream->Write(mOutgoingBuffer, mPosOutputBuff, &numBytesWritten);
     227           0 :           if (int32_t(numBytesWritten) != mPosOutputBuff)
     228           0 :             status = NS_ERROR_FAILURE;
     229             : 
     230             :           // now propagate the data we just wrote
     231           0 :           mNextListener->OnDataAvailable(aRequest, aContext, mInputStream, 0, numBytesWritten);
     232             :         }
     233             :         else
     234           0 :           status = NS_OK;        /* do nothing for resource fork.  */
     235             : 
     236           0 :         mPosOutputBuff = 0;
     237             : 
     238           0 :         if (status != NS_OK)
     239           0 :           mState = BINHEX_STATE_DONE;
     240             :         else
     241           0 :           ++mState;
     242             : 
     243           0 :         mInCRC = 1;
     244             :       }
     245           0 :       else if (mPosOutputBuff >= (int32_t) nsIOService::gDefaultSegmentSize)
     246             :       {
     247           0 :         if (mState == BINHEX_STATE_DFORK)
     248             :         {
     249           0 :           uint32_t numBytesWritten = 0;
     250           0 :           mOutputStream->Write(mOutgoingBuffer, mPosOutputBuff, &numBytesWritten);
     251           0 :           if (int32_t(numBytesWritten) != mPosOutputBuff)
     252           0 :             status = NS_ERROR_FAILURE;
     253             : 
     254           0 :           mNextListener->OnDataAvailable(aRequest, aContext, mInputStream, 0, numBytesWritten);
     255           0 :           mPosOutputBuff = 0;
     256             :         }
     257             :       }
     258           0 :       break;
     259             : 
     260             :     case BINHEX_STATE_HCRC:
     261             :     case BINHEX_STATE_DCRC:
     262             :     case BINHEX_STATE_RCRC:
     263           0 :       if (!mCount++)
     264           0 :         mFileCRC = (unsigned short) c << 8;
     265             :       else
     266             :       {
     267           0 :         if ((mFileCRC | c) != mCRC)
     268             :         {
     269           0 :           mState = BINHEX_STATE_DONE;
     270           0 :           break;
     271             :         }
     272             : 
     273             :         /* passed the CRC check!!!*/
     274           0 :         mCRC = 0;
     275           0 :         if (++mState == BINHEX_STATE_FINISH)
     276             :         {
     277             :           // when we reach the finished state...fire an on stop request on the event listener...
     278           0 :           mNextListener->OnStopRequest(aRequest, aContext, NS_OK);
     279           0 :           mNextListener = nullptr;
     280             : 
     281             :           /*   now We are done with everything.  */
     282           0 :           ++mState;
     283           0 :           break;
     284             :         }
     285             : 
     286           0 :         if (mState == BINHEX_STATE_DFORK)
     287           0 :           mCount = PR_ntohl(mHeader.dlen);
     288             :         else
     289             :         {
     290             :           // we aren't processing the resurce Fork. uncomment this line if we make this converter
     291             :           // smart enough to do this in the future.
     292             :           // mCount = PR_ntohl(mHeader.rlen);  /* it should in host byte order */
     293           0 :           mCount = 0;
     294             :         }
     295             : 
     296           0 :         if (mCount) {
     297           0 :           mInCRC = 0;
     298             :         } else {
     299             :           /* nothing inside, so skip to the next state. */
     300           0 :           ++mState;
     301             :         }
     302             :       }
     303           0 :       break;
     304             :   }
     305             : 
     306           0 :   return NS_OK;
     307             : }
     308             : 
     309           0 : nsresult nsBinHexDecoder::ProcessNextChunk(nsIRequest * aRequest, nsISupports * aContext, uint32_t numBytesInBuffer)
     310             : {
     311             :   bool foundStart;
     312           0 :   int16_t octetpos, c = 0;
     313             :   uint32_t val;
     314           0 :   mPosInDataBuffer = 0; // use member variable.
     315             : 
     316           0 :   NS_ENSURE_TRUE(numBytesInBuffer > 0, NS_ERROR_FAILURE);
     317             : 
     318             :   //  if it is the first time, seek to the right start place.
     319           0 :   if (mState == BINHEX_STATE_START)
     320             :   {
     321           0 :     foundStart = false;
     322             :     // go through the line, until we get a ':'
     323           0 :     while (mPosInDataBuffer < numBytesInBuffer)
     324             :     {
     325           0 :       c = mDataBuffer[mPosInDataBuffer++];
     326           0 :       while (c == nsCRT::CR || c == nsCRT::LF)
     327             :       {
     328           0 :         if (mPosInDataBuffer >= numBytesInBuffer)
     329           0 :           break;
     330             : 
     331           0 :         c = mDataBuffer[mPosInDataBuffer++];
     332           0 :         if (c == ':')
     333             :         {
     334           0 :           foundStart = true;
     335           0 :           break;
     336             :         }
     337             :       }
     338           0 :       if (foundStart)  break;    /* we got the start point. */
     339             :     }
     340             : 
     341           0 :     if (mPosInDataBuffer >= numBytesInBuffer)
     342           0 :       return NS_OK;      /* we meet buff end before we get the start point, wait till next fills. */
     343             : 
     344           0 :     if (c != ':')
     345           0 :       return NS_ERROR_FAILURE;    /* can't find the start character.  */
     346             :   }
     347             : 
     348           0 :   while (mState != BINHEX_STATE_DONE)
     349             :   {
     350             :     /* fill in octetbuf */
     351           0 :     do
     352             :     {
     353           0 :       if (mPosInDataBuffer >= numBytesInBuffer)
     354           0 :         return NS_OK;      /* end of buff, go on for the nxet calls. */
     355             : 
     356           0 :       c = GetNextChar(numBytesInBuffer);
     357           0 :       if (c == 0)  return NS_OK;
     358             : 
     359           0 :       if ((val = BHEXVAL(c)) == uint32_t(-1))
     360             :       {
     361             :         /* we incount an invalid character.  */
     362           0 :         if (c)
     363             :         {
     364             :           /* rolling back. */
     365           0 :           --mDonePos;
     366           0 :           if (mOctetin >= 14)
     367           0 :             --mDonePos;
     368           0 :           if (mOctetin >= 20)
     369           0 :             --mDonePos;
     370             :         }
     371           0 :         break;
     372             :       }
     373           0 :       mOctetBuf.val |= val << mOctetin;
     374             :     }
     375           0 :     while ((mOctetin -= 6) > 2);
     376             : 
     377             :     /* handle decoded characters -- run length encoding (rle) detection */
     378             : 
     379             :     // We put decoded chars into mOctetBuf.val in order from high to low (via
     380             :     // bitshifting, above).  But we want to byte-address them, so we want the
     381             :     // first byte to correspond to the high byte.  In other words, we want
     382             :     // these bytes to be in network order.
     383           0 :     mOctetBuf.val = PR_htonl(mOctetBuf.val);
     384             : 
     385           0 :     for (octetpos = 0; octetpos < mDonePos; ++octetpos)
     386             :     {
     387           0 :       c = mOctetBuf.c[octetpos];
     388             : 
     389           0 :       if (c == 0x90 && !mMarker++)
     390           0 :         continue;
     391             : 
     392           0 :       if (mMarker)
     393             :       {
     394           0 :         if (c == 0)
     395             :         {
     396           0 :           mRlebuf = 0x90;
     397           0 :           ProcessNextState(aRequest, aContext);
     398             :         }
     399             :         else
     400             :         {
     401             :           /* we are in the run length mode */
     402           0 :           while (--c > 0)
     403           0 :             ProcessNextState(aRequest, aContext);
     404             :         }
     405           0 :         mMarker = 0;
     406             :       }
     407             :       else
     408             :       {
     409           0 :         mRlebuf = (unsigned char) c;
     410           0 :         ProcessNextState(aRequest, aContext);
     411             :       }
     412             : 
     413           0 :       if (mState >= BINHEX_STATE_DONE)
     414           0 :         break;
     415             :     }
     416             : 
     417             :     /* prepare for next 3 characters.  */
     418           0 :     if (mDonePos < 3 && mState < BINHEX_STATE_DONE)
     419           0 :       mState = BINHEX_STATE_DONE;
     420             : 
     421           0 :     mOctetin = 26;
     422           0 :     mOctetBuf.val = 0;
     423             :   }
     424             : 
     425           0 :   return   NS_OK;
     426             : }
     427             : 
     428           0 : int16_t nsBinHexDecoder::GetNextChar(uint32_t numBytesInBuffer)
     429             : {
     430           0 :   char c = 0;
     431             : 
     432           0 :   while (mPosInDataBuffer < numBytesInBuffer)
     433             :   {
     434           0 :     c = mDataBuffer[mPosInDataBuffer++];
     435           0 :     if (c != nsCRT::LF && c != nsCRT::CR)
     436           0 :       break;
     437             :   }
     438           0 :   return (c == nsCRT::LF || c == nsCRT::CR) ? 0 : (int) c;
     439             : }
     440             : 
     441             : //////////////////////////////////////////////////////
     442             : // nsIRequestObserver methods...
     443             : //////////////////////////////////////////////////////
     444             : 
     445             : NS_IMETHODIMP
     446           0 : nsBinHexDecoder::OnStartRequest(nsIRequest* request, nsISupports *aCtxt)
     447             : {
     448           0 :   nsresult rv = NS_OK;
     449             : 
     450           0 :   NS_ENSURE_TRUE(mNextListener, NS_ERROR_FAILURE);
     451             : 
     452           0 :   mDataBuffer = (char *) malloc((sizeof(char) * nsIOService::gDefaultSegmentSize));
     453           0 :   mOutgoingBuffer = (char *) malloc((sizeof(char) * nsIOService::gDefaultSegmentSize));
     454           0 :   if (!mDataBuffer || !mOutgoingBuffer) return NS_ERROR_FAILURE; // out of memory;
     455             : 
     456             :   // now we want to create a pipe which we'll use to write our converted data...
     457           0 :   rv = NS_NewPipe(getter_AddRefs(mInputStream), getter_AddRefs(mOutputStream),
     458             :                   nsIOService::gDefaultSegmentSize,
     459             :                   nsIOService::gDefaultSegmentSize,
     460           0 :                   true, true);
     461             : 
     462             :   // don't propagate the on start request to mNextListener until we have determined the content type.
     463           0 :   return rv;
     464             : }
     465             : 
     466             : // Given the fileName we discovered inside the bin hex decoding, figure out the
     467             : // content type and set it on the channel associated with the request.  If the
     468             : // filename tells us nothing useful, just report an unknown type and let the
     469             : // unknown decoder handle things.
     470           0 : nsresult nsBinHexDecoder::DetectContentType(nsIRequest* aRequest,
     471             :                                             const nsCString& aFilename)
     472             : {
     473           0 :   if (aFilename.IsEmpty()) {
     474             :     // Nothing to do here.
     475           0 :     return NS_OK;
     476             :   }
     477             : 
     478             :   nsresult rv;
     479           0 :   nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest, &rv));
     480           0 :   NS_ENSURE_SUCCESS(rv, rv);
     481             : 
     482           0 :   nsCOMPtr<nsIMIMEService> mimeService(do_GetService("@mozilla.org/mime;1", &rv));
     483           0 :   NS_ENSURE_SUCCESS(rv, rv);
     484             : 
     485           0 :   nsAutoCString contentType;
     486             : 
     487             :   // extract the extension from aFilename and look it up.
     488           0 :   const char * fileExt = strrchr(aFilename.get(), '.');
     489           0 :   if (!fileExt) {
     490           0 :     return NS_OK;
     491             :   }
     492             : 
     493           0 :   mimeService->GetTypeFromExtension(nsDependentCString(fileExt), contentType);
     494             : 
     495             :   // Only set the type if it's not empty and, to prevent recursive loops, not the binhex type
     496           0 :   if (!contentType.IsEmpty() && !contentType.Equals(APPLICATION_BINHEX)) {
     497           0 :     channel->SetContentType(contentType);
     498             :   } else {
     499           0 :     channel->SetContentType(NS_LITERAL_CSTRING(UNKNOWN_CONTENT_TYPE));
     500             :   }
     501             : 
     502           0 :   return NS_OK;
     503             : }
     504             : 
     505             : 
     506             : NS_IMETHODIMP
     507           0 : nsBinHexDecoder::OnStopRequest(nsIRequest* request, nsISupports *aCtxt,
     508             :                                 nsresult aStatus)
     509             : {
     510           0 :   nsresult rv = NS_OK;
     511             : 
     512           0 :   if (!mNextListener) return NS_ERROR_FAILURE;
     513             :   // don't do anything here...we'll fire our own on stop request when we are done
     514             :   // processing the data....
     515             : 
     516           0 :   return rv;
     517             : }
     518             : 
     519             : } // namespace net
     520             : } // namespace mozilla

Generated by: LCOV version 1.13