dbaron%dbaron.org e071c7ff2a Bug 178643: Remove uses of NS_INIT_ISUPPORTS, since it is no longer needed. r=timeless sr=jag
git-svn-id: svn://10.0.0.236/trunk@136017 18797224-902f-48f8-a5cc-f745e15eee43
2003-01-08 22:05:52 +00:00

389 lines
8.9 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation.
* All Rights Reserved.
*
* Contributor(s):
* Stuart Parmenter <pavlov@netscape.com>
*
*/
/*
* Current limitations:
*
* Doesn't handle PGM and PPM files for which the maximum sample value
* is something other than 255.
*
*/
#include <ctype.h>
#include "nsPPMDecoder.h"
#include "nsIInputStream.h"
#include "imgIContainer.h"
#include "imgIContainerObserver.h"
#include "nspr.h"
#include "plstr.h"
#include "nsIComponentManager.h"
#include "nsRect.h"
NS_IMPL_ISUPPORTS1(nsPPMDecoder, imgIDecoder)
/*
* "F_" stands for "find", so F_TYPE means we're looking for the image type
* digit.
*/
enum ParseState {
F_P,
F_TYPE,
F_WIDTH,
F_HEIGHT,
F_MAXVAL,
F_INITIALIZE,
F_TEXTBITDATA,
F_TEXTDATA,
F_RAWDATA
};
/*
* What kind of white space do we skip.
*/
enum Skip {
NOTHING,
WHITESPACE,
SINGLEWHITESPACE,
TOENDOFLINE
};
/*
* We look up the digit after the initial 'P' in this string to check
* whether it's valid; the index is then used with the following
* constants.
*/
static char ppmTypes[] = "1231456";
enum {
TYPE_PBM = 0,
TYPE_PGM = 1,
TYPE_PPM = 2,
PPMTYPE = 0x3,
PPMRAW = 0x4
};
nsPPMDecoder::nsPPMDecoder() :
mBuffer(nsnull),
mBufferSize(0),
mState(F_P),
mSkip(NOTHING),
mOldSkip(NOTHING),
mType(0),
mRowData(nsnull)
{
}
nsPPMDecoder::~nsPPMDecoder()
{
if (mBuffer != nsnull)
PR_Free(mBuffer);
if (mRowData != nsnull)
PR_Free(mRowData);
}
/** imgIDecoder methods **/
/* void init (in imgILoad aLoad); */
NS_IMETHODIMP nsPPMDecoder::Init(imgILoad *aLoad)
{
mImageLoad = aLoad;
mObserver = do_QueryInterface(aLoad); // we're holding 2 strong refs to the request.
mImage = do_CreateInstance("@mozilla.org/image/container;1");
aLoad->SetImage(mImage);
mFrame = do_CreateInstance("@mozilla.org/gfx/image/frame;2");
if (!mFrame)
return NS_ERROR_FAILURE;
return NS_OK;
}
/* void close (); */
NS_IMETHODIMP nsPPMDecoder::Close()
{
if (mObserver) {
mObserver->OnStopFrame(nsnull, nsnull, mFrame);
mObserver->OnStopContainer(nsnull, nsnull, mImage);
mObserver->OnStopDecode(nsnull, nsnull, NS_OK, nsnull);
}
return NS_OK;
}
/* void flush (); */
NS_IMETHODIMP nsPPMDecoder::Flush()
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* unsigned long writeFrom (in nsIInputStream inStr, in unsigned long count); */
NS_IMETHODIMP nsPPMDecoder::WriteFrom(nsIInputStream *inStr, PRUint32 count, PRUint32 *_retval)
{
nsresult rv;
if (mBuffer == nsnull) {
mBuffer = (char *)PR_Malloc(count);
mBufferSize = count;
} else if (mBuffer != nsnull && mBufferSize != count) {
PR_Free(mBuffer);
mBuffer = (char *)PR_Malloc(count);
mBufferSize = count;
}
if (!mBuffer)
return NS_ERROR_OUT_OF_MEMORY; /* we couldn't allocate the object */
// read the data from the input stream...
PRUint32 readLen;
rv = inStr->Read(mBuffer, count, &readLen);
if (NS_FAILED(rv)) return rv;
if (mState == F_P && mObserver)
mObserver->OnStartDecode(nsnull, nsnull);
char *p = mBuffer;
char *bufferEnd = mBuffer+readLen;
char *s;
int n;
while (p < bufferEnd) {
if (mSkip == WHITESPACE) {
while (p < bufferEnd && *p != '#'
&& (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r'))
p++;
if (p == bufferEnd)
break;
if (*p == '#') {
mOldSkip = WHITESPACE;
mSkip = TOENDOFLINE;
continue;
}
mSkip = NOTHING;
} else if (mSkip == SINGLEWHITESPACE) {
if (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\r')
return NS_ERROR_FAILURE;
p++;
mSkip = NOTHING;
} else if (mSkip == TOENDOFLINE) {
while (p < bufferEnd && *p != '\n')
p++;
if (p == bufferEnd)
break;
mSkip = mOldSkip;
mOldSkip = NOTHING;
if (mSkip != NOTHING)
continue;
}
switch (mState) {
case F_P:
if (*p != 'P')
return NS_ERROR_FAILURE;
p++;
mState = F_TYPE;
break;
case F_TYPE:
if ((s = PL_strchr(ppmTypes, *p)) == NULL)
return NS_ERROR_FAILURE;
mType = s-ppmTypes;
p++;
mState = F_WIDTH;
mDigitCount = 0;
mSkip = WHITESPACE;
break;
case F_WIDTH:
case F_HEIGHT:
case F_MAXVAL:
while (mDigitCount < sizeof(mDigits) && p < bufferEnd && isdigit(*p))
mDigits[mDigitCount++] = *p++;
if (mDigitCount == sizeof(mDigits))
return NS_ERROR_FAILURE; // number too big
if (p == bufferEnd)
break;
if (*p == '#') {
mOldSkip = NOTHING;
mSkip = TOENDOFLINE;
break;
}
mDigits[mDigitCount] = 0;
n = strtol(mDigits, (char **)NULL, 10);
if (mState == F_WIDTH) {
mWidth = n;
mDigitCount = 0;
mState = F_HEIGHT;
mSkip = WHITESPACE;
} else if (mState == F_HEIGHT) {
mHeight = n;
mDigitCount = 0;
if ((mType & PPMTYPE) != TYPE_PBM) {
mState = F_MAXVAL;
mSkip = WHITESPACE;
} else
mState = F_INITIALIZE;
} else if (mState == F_MAXVAL) {
mMaxValue = n;
mDigitCount = 0;
mState = F_INITIALIZE;
}
break;
case F_INITIALIZE:
mImage->Init(mWidth, mHeight, mObserver);
if (mObserver)
mObserver->OnStartContainer(nsnull, nsnull, mImage);
mFrame->Init(0, 0, mWidth, mHeight, gfxIFormats::RGB, 24);
mImage->AppendFrame(mFrame);
if (mObserver)
mObserver->OnStartFrame(nsnull, nsnull, mFrame);
mRow = 0;
mBytesPerRow = 3*mWidth;
mFrame->GetImageBytesPerRow(&mFrameBytesPerRow);
mRowData = (PRUint8 *)PR_Malloc(mFrameBytesPerRow);
mRowDataFill = 0;
if (mType & PPMRAW) {
mState = F_RAWDATA;
mSkip = SINGLEWHITESPACE;
} else if ((mType & PPMTYPE) == TYPE_PBM) {
mState = F_TEXTBITDATA;
mSkip = WHITESPACE;
} else {
mState = F_TEXTDATA;
mSkip = WHITESPACE;
mDigitCount = 0;
}
break;
case F_TEXTBITDATA:
{
PRUint8 c = *p++;
if (c == '1') {
mRowData[mRowDataFill++] = 0;
mRowData[mRowDataFill++] = 0;
mRowData[mRowDataFill++] = 0;
} else {
mRowData[mRowDataFill++] = 255;
mRowData[mRowDataFill++] = 255;
mRowData[mRowDataFill++] = 255;
}
}
mSkip = WHITESPACE;
rv = checkSendRow();
if (NS_FAILED(rv)) return rv;
break;
case F_TEXTDATA:
while (mDigitCount < sizeof(mDigits) && p < bufferEnd && isdigit(*p))
mDigits[mDigitCount++] = *p++;
if (mDigitCount == sizeof(mDigits))
return NS_ERROR_FAILURE; // number too big
if (p == bufferEnd)
break;
mDigits[mDigitCount] = 0;
n = strtol(mDigits, (char **)NULL, 10);
mDigitCount = 0;
switch (mType & PPMTYPE) {
case 1:
mRowData[mRowDataFill++] = n;
mRowData[mRowDataFill++] = n;
mRowData[mRowDataFill++] = n;
break;
case 2:
mRowData[mRowDataFill++] = n;
break;
}
mSkip = WHITESPACE;
rv = checkSendRow();
if (NS_FAILED(rv)) return rv;
break;
case F_RAWDATA:
if (mType & PPMRAW) {
switch (mType & PPMTYPE) {
case TYPE_PBM:
{
PRUint32 c = *p++;
int i = 0;
while (mRowDataFill < mBytesPerRow && i < 8) {
if (c & 0x80) {
mRowData[mRowDataFill++] = 0;
mRowData[mRowDataFill++] = 0;
mRowData[mRowDataFill++] = 0;
} else {
mRowData[mRowDataFill++] = 255;
mRowData[mRowDataFill++] = 255;
mRowData[mRowDataFill++] = 255;
}
c <<= 1;
i++;
}
}
break;
case TYPE_PGM:
{
PRUint8 c = *p++;
mRowData[mRowDataFill++] = c;
mRowData[mRowDataFill++] = c;
mRowData[mRowDataFill++] = c;
}
break;
case TYPE_PPM:
if (mMaxValue == 255) {
PRUint32 bytesInBuffer = bufferEnd-p;
PRUint32 bytesNeeded = mBytesPerRow-mRowDataFill;
PRUint32 chunk = PR_MIN(bytesInBuffer, bytesNeeded);
memcpy(mRowData+mRowDataFill, p, chunk);
p += chunk;
mRowDataFill += chunk;
} else {
mRowData[mRowDataFill++] = *p++;
}
break;
}
rv = checkSendRow();
if (NS_FAILED(rv)) return rv;
}
break;
}
}
return NS_OK;
}
NS_METHOD nsPPMDecoder::checkSendRow()
{
nsresult rv;
if (mRowDataFill == mBytesPerRow) {
rv = mFrame->SetImageData(mRowData, mFrameBytesPerRow, mRow*mFrameBytesPerRow);
if (NS_FAILED(rv)) return rv;
nsRect r(0, mRow, mWidth, 1);
if (mObserver)
mObserver->OnDataAvailable(nsnull, nsnull, mFrame, &r);
mRow++;
mRowDataFill = 0;
}
return NS_OK;
}