diff --git a/modules/libpr0n/decoders/jpeg/nsJPEGDecoder.cpp b/modules/libpr0n/decoders/jpeg/nsJPEGDecoder.cpp index b1242b42367c..247889e3319c 100644 --- a/modules/libpr0n/decoders/jpeg/nsJPEGDecoder.cpp +++ b/modules/libpr0n/decoders/jpeg/nsJPEGDecoder.cpp @@ -85,14 +85,15 @@ nsJPEGDecoder::nsJPEGDecoder() { mState = JPEG_HEADER; mReading = PR_TRUE; + mError = NS_OK; mBytesToSkip = 0; memset(&mInfo, 0, sizeof(jpeg_decompress_struct)); memset(&mSourceMgr, 0, sizeof(mSourceMgr)); mInfo.client_data = (void*)this; - mBuffer = nsnull; - mBufferLen = mBufferSize = 0; + mSegment = nsnull; + mSegmentLen = 0; mBackBuffer = nsnull; mBackBufferLen = mBackBufferSize = mBackBufferUnreadLen = 0; @@ -107,7 +108,6 @@ nsJPEGDecoder::nsJPEGDecoder() nsJPEGDecoder::~nsJPEGDecoder() { - PR_FREEIF(mBuffer); PR_FREEIF(mBackBuffer); if (mTransform) cmsDeleteTransform(mTransform); @@ -196,14 +196,17 @@ NS_IMETHODIMP nsJPEGDecoder::Close() PR_LOG(gJPEGlog, PR_LOG_DEBUG, ("[this=%p] nsJPEGDecoder::Close\n", this)); - if (mState != JPEG_DONE && mState != JPEG_SINK_NON_JPEG_TRAILER) - NS_WARNING("Never finished decoding the JPEG."); - /* Step 8: Release JPEG decompression object */ mInfo.src = nsnull; jpeg_destroy_decompress(&mInfo); + if (mState != JPEG_DONE && mState != JPEG_SINK_NON_JPEG_TRAILER) { + NS_WARNING("Never finished decoding the JPEG."); + /* Tell imgLoader that image decoding has failed */ + return NS_ERROR_FAILURE; + } + return NS_OK; } @@ -214,58 +217,57 @@ NS_IMETHODIMP nsJPEGDecoder::Flush() PRUint32 ret; if (mState != JPEG_DONE && mState != JPEG_SINK_NON_JPEG_TRAILER && mState != JPEG_ERROR) - return this->WriteFrom(nsnull, 0, &ret); + return this->ProcessData(nsnull, 0, &ret); return NS_OK; } -/* unsigned long writeFrom (in nsIInputStream inStr, in unsigned long count); */ -NS_IMETHODIMP nsJPEGDecoder::WriteFrom(nsIInputStream *inStr, PRUint32 count, PRUint32 *_retval) +static NS_METHOD ReadDataOut(nsIInputStream* in, + void* closure, + const char* fromRawSegment, + PRUint32 toOffset, + PRUint32 count, + PRUint32 *writeCount) { - LOG_SCOPE_WITH_PARAM(gJPEGlog, "nsJPEGDecoder::WriteFrom", "count", count); + nsJPEGDecoder *decoder = static_cast(closure); + nsresult rv = decoder->ProcessData(fromRawSegment, count, writeCount); + if (NS_FAILED(rv)) { + /* Tell imgLoader that image decoding has failed */ + decoder->mError = rv; + *writeCount = 0; + } - PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG, - ("nsJPEGDecoder::WriteFrom(decoder = %p) {\n" - " image container %s; %u bytes to be added", - this, - mImage ? "exists" : "does not exist", - count)); + return NS_OK; +} - if (inStr) { - if (!mBuffer) { - mBuffer = (JOCTET *)PR_Malloc(count); - if (!mBuffer) { - mState = JPEG_ERROR; - PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG, - ("} (out of memory allocating buffer)")); - return NS_ERROR_OUT_OF_MEMORY; - } - mBufferSize = count; - } else if (count > mBufferSize) { - JOCTET *buf = (JOCTET *)PR_Realloc(mBuffer, count); - if (!buf) { - mState = JPEG_ERROR; - PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG, - ("} (out of memory resizing buffer)")); - return NS_ERROR_OUT_OF_MEMORY; - } - mBuffer = buf; - mBufferSize = count; - } - nsresult rv = inStr->Read((char*)mBuffer, count, &mBufferLen); - NS_ASSERTION(NS_SUCCEEDED(rv), "nsJPEGDecoder::WriteFrom -- inStr->Read failed"); +/* unsigned long writeFrom (in nsIInputStream inStr, in unsigned long count); */ +NS_IMETHODIMP nsJPEGDecoder::WriteFrom(nsIInputStream *inStr, PRUint32 count, PRUint32 *writeCount) +{ + NS_ENSURE_ARG_POINTER(inStr); + NS_ENSURE_ARG_POINTER(writeCount); - PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG, - ("nsJPEGDecoder::WriteFrom(): decoder %p got %u bytes, read %u from the stream (buffer size %u)", - this, - count, - mBufferLen, - mBufferSize)); - - *_retval = mBufferLen; + /* necko doesn't propagate the errors from ReadDataOut */ + nsresult rv = inStr->ReadSegments(ReadDataOut, this, count, writeCount); + if (NS_FAILED(mError)) { + /* Tell imgLoader that image decoding has failed */ + rv = NS_ERROR_FAILURE; + } - nsresult result = mImage->AddRestoreData((char *) mBuffer, count); + return rv; +} + +//****************************************************************************** +nsresult nsJPEGDecoder::ProcessData(const char *data, PRUint32 count, PRUint32 *writeCount) +{ + LOG_SCOPE_WITH_PARAM(gJPEGlog, "nsJPEGDecoder::ProcessData", "count", count); + + mSegment = (const JOCTET *)data; + mSegmentLen = count; + *writeCount = count; + + if (data && count) { + nsresult result = mImage->AddRestoreData((char *) data, count); if (NS_FAILED(result)) { mState = JPEG_ERROR; @@ -301,12 +303,12 @@ NS_IMETHODIMP nsJPEGDecoder::WriteFrom(nsIInputStream *inStr, PRUint32 count, PR } PR_LOG(gJPEGlog, PR_LOG_DEBUG, - ("[this=%p] nsJPEGDecoder::WriteFrom -- processing JPEG data\n", this)); + ("[this=%p] nsJPEGDecoder::ProcessData -- processing JPEG data\n", this)); switch (mState) { case JPEG_HEADER: { - LOG_SCOPE(gJPEGlog, "nsJPEGDecoder::WriteFrom -- entering JPEG_HEADER case"); + LOG_SCOPE(gJPEGlog, "nsJPEGDecoder::ProcessData -- entering JPEG_HEADER case"); /* Step 3: read file parameters with jpeg_read_header() */ if (jpeg_read_header(&mInfo, TRUE) == JPEG_SUSPENDED) { @@ -494,7 +496,7 @@ NS_IMETHODIMP nsJPEGDecoder::WriteFrom(nsIInputStream *inStr, PRUint32 count, PR mImage->AppendFrame(mFrame); PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG, - (" JPEGDecoderAccounting: nsJPEGDecoder::WriteFrom -- created image frame with %ux%u pixels", + (" JPEGDecoderAccounting: nsJPEGDecoder::ProcessData -- created image frame with %ux%u pixels", mInfo.image_width, mInfo.image_height)); } @@ -504,7 +506,7 @@ NS_IMETHODIMP nsJPEGDecoder::WriteFrom(nsIInputStream *inStr, PRUint32 count, PR case JPEG_START_DECOMPRESS: { - LOG_SCOPE(gJPEGlog, "nsJPEGDecoder::WriteFrom -- entering JPEG_START_DECOMPRESS case"); + LOG_SCOPE(gJPEGlog, "nsJPEGDecoder::ProcessData -- entering JPEG_START_DECOMPRESS case"); /* Step 4: set parameters for decompression */ /* FIXME -- Should reset dct_method and dither mode @@ -535,7 +537,7 @@ NS_IMETHODIMP nsJPEGDecoder::WriteFrom(nsIInputStream *inStr, PRUint32 count, PR { if (mState == JPEG_DECOMPRESS_SEQUENTIAL) { - LOG_SCOPE(gJPEGlog, "nsJPEGDecoder::WriteFrom -- JPEG_DECOMPRESS_SEQUENTIAL case"); + LOG_SCOPE(gJPEGlog, "nsJPEGDecoder::ProcessData -- JPEG_DECOMPRESS_SEQUENTIAL case"); if (!OutputScanlines()) { PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG, @@ -553,7 +555,7 @@ NS_IMETHODIMP nsJPEGDecoder::WriteFrom(nsIInputStream *inStr, PRUint32 count, PR { if (mState == JPEG_DECOMPRESS_PROGRESSIVE) { - LOG_SCOPE(gJPEGlog, "nsJPEGDecoder::WriteFrom -- JPEG_DECOMPRESS_PROGRESSIVE case"); + LOG_SCOPE(gJPEGlog, "nsJPEGDecoder::ProcessData -- JPEG_DECOMPRESS_PROGRESSIVE case"); int status; do { @@ -618,7 +620,7 @@ NS_IMETHODIMP nsJPEGDecoder::WriteFrom(nsIInputStream *inStr, PRUint32 count, PR { nsresult result; - LOG_SCOPE(gJPEGlog, "nsJPEGDecoder::WriteFrom -- entering JPEG_DONE case"); + LOG_SCOPE(gJPEGlog, "nsJPEGDecoder::ProcessData -- entering JPEG_DONE case"); /* Step 7: Finish decompression */ @@ -643,13 +645,13 @@ NS_IMETHODIMP nsJPEGDecoder::WriteFrom(nsIInputStream *inStr, PRUint32 count, PR } case JPEG_SINK_NON_JPEG_TRAILER: PR_LOG(gJPEGlog, PR_LOG_DEBUG, - ("[this=%p] nsJPEGDecoder::WriteFrom -- entering JPEG_SINK_NON_JPEG_TRAILER case\n", this)); + ("[this=%p] nsJPEGDecoder::ProcessData -- entering JPEG_SINK_NON_JPEG_TRAILER case\n", this)); break; case JPEG_ERROR: PR_LOG(gJPEGlog, PR_LOG_DEBUG, - ("[this=%p] nsJPEGDecoder::WriteFrom -- entering JPEG_ERROR case\n", this)); + ("[this=%p] nsJPEGDecoder::ProcessData -- entering JPEG_ERROR case\n", this)); break; } @@ -674,7 +676,6 @@ nsJPEGDecoder::OutputScanlines() mFrame->GetImageData(&imageData, &imageDataLength); while ((mInfo.output_scanline < mInfo.output_height)) { - /* Request one scanline. Returns 0 or 1 scanlines. */ PRUint32 *imageRow = ((PRUint32*)imageData) + (mInfo.output_scanline * mInfo.output_width); @@ -686,6 +687,7 @@ nsJPEGDecoder::OutputScanlines() sampleRow += mInfo.output_width; } + /* Request one scanline. Returns 0 or 1 scanlines. */ if (jpeg_read_scanlines(&mInfo, &sampleRow, 1) != 1) { rv = PR_FALSE; /* suspend */ break; @@ -878,13 +880,13 @@ fill_input_buffer (j_decompress_ptr jd) nsJPEGDecoder *decoder = (nsJPEGDecoder *)(jd->client_data); if (decoder->mReading) { - unsigned char *new_buffer = (unsigned char *)decoder->mBuffer; - PRUint32 new_buflen = decoder->mBufferLen; + const JOCTET *new_buffer = decoder->mSegment; + PRUint32 new_buflen = decoder->mSegmentLen; if (!new_buffer || new_buflen == 0) return PR_FALSE; /* suspend */ - decoder->mBufferLen = 0; + decoder->mSegmentLen = 0; if (decoder->mBytesToSkip) { if (decoder->mBytesToSkip < new_buflen) { @@ -908,7 +910,7 @@ fill_input_buffer (j_decompress_ptr jd) return PR_TRUE; } - if (src->next_input_byte != decoder->mBuffer) { + if (src->next_input_byte != decoder->mSegment) { /* Backtrack data has been permanently consumed. */ decoder->mBackBufferUnreadLen = 0; decoder->mBackBufferLen = 0; @@ -919,37 +921,24 @@ fill_input_buffer (j_decompress_ptr jd) /* Make sure backtrack buffer is big enough to hold new data. */ if (decoder->mBackBufferSize < new_backtrack_buflen) { - - - /* Round up to multiple of 256 bytes. */ - const PRUint32 roundup_buflen = ((new_backtrack_buflen + 255) >> 8) << 8; - - if (decoder->mBackBuffer) { - JOCTET *buf = (JOCTET *)PR_REALLOC(decoder->mBackBuffer, roundup_buflen); - /* Check for OOM */ - if (!buf) { - decoder->mInfo.err->msg_code = JERR_OUT_OF_MEMORY; - my_error_exit((j_common_ptr)(&decoder->mInfo)); - } - decoder->mBackBuffer = buf; - } else { - decoder->mBackBuffer = (JOCTET*)PR_MALLOC(roundup_buflen); - /* Check for OOM */ - if (!decoder->mBackBuffer) { - decoder->mInfo.err->msg_code = JERR_OUT_OF_MEMORY; - my_error_exit((j_common_ptr)(&decoder->mInfo)); - } - } - - decoder->mBackBufferSize = (size_t)roundup_buflen; - - /* Check for malformed MARKER segment lengths. */ + /* Check for malformed MARKER segment lengths, before allocating space for it */ if (new_backtrack_buflen > MAX_JPEG_MARKER_LENGTH) { my_error_exit((j_common_ptr)(&decoder->mInfo)); } + + /* Round up to multiple of 256 bytes. */ + const size_t roundup_buflen = ((new_backtrack_buflen + 255) >> 8) << 8; + JOCTET *buf = (JOCTET *)PR_REALLOC(decoder->mBackBuffer, roundup_buflen); + /* Check for OOM */ + if (!buf) { + decoder->mInfo.err->msg_code = JERR_OUT_OF_MEMORY; + my_error_exit((j_common_ptr)(&decoder->mInfo)); + } + decoder->mBackBuffer = buf; + decoder->mBackBufferSize = roundup_buflen; } - /* Copy remainder of netlib buffer into backtrack buffer. */ + /* Copy remainder of netlib segment into backtrack buffer. */ memmove(decoder->mBackBuffer + decoder->mBackBufferLen, src->next_input_byte, src->bytes_in_buffer); diff --git a/modules/libpr0n/decoders/jpeg/nsJPEGDecoder.h b/modules/libpr0n/decoders/jpeg/nsJPEGDecoder.h index dae586fe4c5e..0f285e1d0eab 100644 --- a/modules/libpr0n/decoders/jpeg/nsJPEGDecoder.h +++ b/modules/libpr0n/decoders/jpeg/nsJPEGDecoder.h @@ -91,6 +91,8 @@ public: nsJPEGDecoder(); virtual ~nsJPEGDecoder(); + nsresult ProcessData(const char *data, PRUint32 count, PRUint32 *writeCount); + protected: PRBool OutputScanlines(); @@ -105,12 +107,12 @@ public: struct jpeg_source_mgr mSourceMgr; decoder_error_mgr mErr; jstate mState; + nsresult mError; PRUint32 mBytesToSkip; - JOCTET *mBuffer; - PRUint32 mBufferLen; // amount of data currently in mBuffer - PRUint32 mBufferSize; // size in bytes what mBuffer was created with + const JOCTET *mSegment; // The current segment we are decoding from + PRUint32 mSegmentLen; // amount of data in mSegment JOCTET *mBackBuffer; PRUint32 mBackBufferLen; // Offset of end of active backtrack data @@ -124,10 +126,6 @@ public: cmsHTRANSFORM mTransform; PRPackedBool mReading; - -private: - - nsresult AddToTmpAccumulateBuffer(JOCTET *src, PRUint32 len); }; #endif // nsJPEGDecoder_h__