/*  
** Copyright (c) 1995 Netsurfer Inc.  All Rights Reserved.
**
** Author: <bbum@friday.com>
*/

/*  This object is included in the MiscKit by permission from the author
**  and its use is governed by the MiscKit license, found in the file
**  "LICENSE.rtf" in the MiscKit distribution.  Please refer to that file
**  for a list of all applicable permissions and restrictions.
*/

#import <appkit/appkit.h>

#import "SurfJPEGSupport.h"
#import "SurfJPEGDecoder.Internal.h"

#ifdef VERBOSE
#undef VERBOSE
#undef METHOD
#undef METHODnl
#endif

#define VERBOSE 		if(_SDFlags.verboseMode)
#define METHOD  		fprintf(stderr, "[%s %s%s] ", \
                                object_getClassName(self), \
                 		        (self == [self class]) ? "+" : "-", \
				                SELNAME(_cmd))
#define METHODnl  		fprintf(stderr, "[%s %s%s]\n", \
                                object_getClassName(self), \
                 		        (self == [self class]) ? "+" : "-", \
				                SELNAME(_cmd))

@interface SurfJPEGDecoder (PrivateAPI)
- _decodeFromStream:(NXStream *) theStream;
@end
	
@implementation SurfJPEGDecoder
/*"
 * Implements a JPEG/JFIF image decoder.
"*/

+ sharedInstance
/*"
 * Shared instance management.  Just for convenience;  not a requirement.
"*/
{
	static id sharedInstance = nil;

	if (!sharedInstance) {
		sharedInstance = [self alloc];
		[sharedInstance init]; 
	}
	return sharedInstance;
}

+ (const char *const *)imageUnfilteredFileTypes;
/*"
 * Returns a NULL terminated array of file extensions instances of this
 * decoder class can decode.
"*/
{
	static const char *const jpegTypes[] = {
		"jpeg",
		"JPEG",
		"jpg",
		"JPG",
		"jfif",
		"JFIF",
		NULL};
	return jpegTypes;
}

+ (BOOL)canLoadFromStream:(NXStream *)stream
/*"
 * Returns YES if an instance of this decoder class can decode the image
 * contained in stream.  This is by no means a definitive answer.  Restores
 * the seek state of stream before returning.
"*/
{
	long startingPosition = NXTell(stream);
	BOOL canRead		  = NO;
	unsigned index;
	unsigned char header[11];
	unsigned short matchbuf[] = {0xff, // marker
								 0xd8, // start-of-input mark
								 0xff, // marker
								 0xe0, // app0 block follows
								 0xfff,// block length (ignored)
								 0xfff,// block length (ignored)
								 0x4a, // 'J'
								 0x46, // 'F'
								 0x49, // 'I'
								 0x46, // 'F'
								 0x00};// NULL 'JFIF' terminator

	if(!NXRead(stream, header, 11))
		goto resetAndReturn;

	for(index = 0;index<11;index++)
		if( (matchbuf[index] != 0xfff) && (header[index] != matchbuf[index]) )
			goto resetAndReturn;

	canRead = YES;
	
resetAndReturn:
    /* Reset stream back to the starting postiion.
     */
	NX_DURING
	NXSeek(stream, startingPosition, NX_FROMSTART);
	NX_HANDLER
	NXLogError("Attempted to NXSeek() a stream that cannot be NXSeek()ed.");
	canRead = NO;
	NX_ENDHANDLER
	
	return canRead;
}

- init
{
	[super init];
	[self setReadCount: 5];
	return self;
}

- free
{
	NX_FREE(rowPtrBuf);
	return [super free];
}

- (void) setReadCount: (unsigned) aNum
/*"
 * Sets the readCount to aNum and reallocates %rowPtrBuf, as necessary.
"*/
{
	if(aNum)
		readCount = aNum;
	else
		readCount = 5;

	if(rowPtrBuf)
		rowPtrBuf = (unsigned char **) NXZoneRealloc([self zone], rowPtrBuf,
													  sizeof(unsigned char *) *
													  readCount);
	else
		rowPtrBuf = (unsigned char **) NXZoneMalloc([self zone], 
													 sizeof(unsigned char *) *
													 readCount);
}

- (unsigned) readCount
/*"
 * Returns the number of rows that will be read during each decoding pass.
"*/
{	
	return readCount;
}
@end
