This is MiscGIFData.m in view mode; [Download] [Up]
/* MiscGIFData.m Copyright 1996 Uwe Hoffmann. Copyright 1996 Netsurfer Inc. This notice may not be removed from this source code. The use and distribution of this software is governed by the terms of the MiscKit license agreement. Refer to the license document included with the MiscKit distribution for the terms. Author: <bbum@friday.com> Converted to OpenStep, September 1996, Uwe Hoffmann. */ /* ** Copyright 1990, 1991, 1993, David Koblas. (koblas@netcom.com) ** ** Permission to use, copy, modify, and distribute this software and its ** documentation for any purpose and without fee is hereby granted, ** provided that the above copyright notice appear in all copies and that ** both that copyright notice and this permission notice appear in ** supporting documentation. This software is provided "as is" without ** express or implied warranty. */ #import "MiscGIFData.h" @interface MiscGIFData(PrivateMethods) /*" * Initialize decompressor. "*/ - (void)_internalLWZInitStateWithCodeSize:(unsigned char)codeSize; /*" * Read a block of compressed image data "*/ - (int)_internalGetDataBlock:(unsigned char *)buf; /*" * Retrieve a single compression code. "*/ - (int)_internalGetCode; @end @implementation MiscGIFData - initWithGIFData:(NSData *)gifData { NSParameterAssert(gifData); [super init]; data = [gifData retain]; length = [data length]; alreadyRead = 0; decompressionState = NSZoneMalloc([self zone], sizeof(MiscLWZState)); return self; } - (void)dealloc { NSZoneFree([self zone], decompressionState); [data release]; return [super dealloc]; } - (void)resetStream { alreadyRead = 0; } - (void)setStream:(unsigned int)aPosition { NSParameterAssert(aPosition <= length); alreadyRead = aPosition; } - (BOOL)atEOS { return alreadyRead >= length ? YES : NO; } - (BOOL)getHeader:(char *)buffer { if(alreadyRead < length){ nbytes = MIN(3, length - alreadyRead); range = NSMakeRange(alreadyRead, nbytes); [data getBytes:buffer range:range]; alreadyRead += nbytes; } else nbytes = 0; return nbytes == 3 ? YES : NO; } - (BOOL)getVersion:(char *)buffer { if(alreadyRead < length){ nbytes = MIN(3, length - alreadyRead); range = NSMakeRange(alreadyRead, nbytes); [data getBytes:buffer range:range]; alreadyRead += nbytes; } else nbytes = 0; return nbytes == 3 ? YES : NO; } - (BOOL)getLSD:(char *)buffer { if(alreadyRead < length){ nbytes = MIN(7, length - alreadyRead); range = NSMakeRange(alreadyRead, nbytes); [data getBytes:buffer range:range]; alreadyRead += nbytes; } else nbytes = 0; return nbytes == 7 ? YES : NO; } - (BOOL)getColorTable16:(MiscColorEntry16 *)buffer size:(unsigned int)tableSize { unsigned int i,n; const char *p; nbytes = MIN(tableSize * 3, length - alreadyRead); n = nbytes / 3; for(i = 0, p = (const char *)[data bytes] + alreadyRead; i < n; i++, p += 3){ buffer[i].red = p[0] >> 4; buffer[i].green = p[1] >> 4; buffer[i].blue = p[2] >> 4; buffer[i].alpha = 0xf; } alreadyRead += nbytes; return nbytes == tableSize * 3 ? YES : NO; } - (BOOL)getColorTable32:(MiscColorEntry32 *)buffer size:(unsigned int)tableSize { unsigned int i,n; const char *p; nbytes = MIN(tableSize * 3, length - alreadyRead); n = nbytes / 3; for(i = 0, p = (const char *)[data bytes] + alreadyRead; i < n; i++, p += 3){ buffer[i].red = p[0]; buffer[i].green = p[1]; buffer[i].blue = p[2]; buffer[i].alpha = 255; } alreadyRead += nbytes; return nbytes == tableSize * 3 ? YES : NO; } - (BOOL)getGCE:(char *)buffer { if(alreadyRead < length){ nbytes = MIN(6, length - alreadyRead); range = NSMakeRange(alreadyRead, nbytes); [data getBytes:buffer range:range]; alreadyRead += nbytes; } else nbytes = 0; return nbytes == 6 ? YES : NO; } - (BOOL)getImageDescriptor:(char *)buffer { if(alreadyRead < length){ nbytes = MIN(9, length - alreadyRead); range = NSMakeRange(alreadyRead, nbytes); [data getBytes:buffer range:range]; alreadyRead += nbytes; } else nbytes = 0; return nbytes == 9 ? YES : NO; } - (BOOL)getCharacter:(unsigned char *)buffer { const char *p; if(alreadyRead >= length) return NO; p = (const char *)[data bytes] + alreadyRead; *buffer = *p; alreadyRead++; return YES; } - (BOOL)startDecompressionEngine { unsigned char lwzCodeSize; const char *p; if(alreadyRead >= length) return NO; p = (const char *)[data bytes] + alreadyRead; lwzCodeSize = *p; alreadyRead++; if(!lwzCodeSize) return NO; bzero(decompressionState, sizeof(*decompressionState)); [self _internalLWZInitStateWithCodeSize:lwzCodeSize]; return YES; } - (int)LWZReadByte { int code, incode; register int i; if (decompressionState->fresh) { decompressionState->fresh = FALSE; do { decompressionState->firstcode = decompressionState->oldcode = [self _internalGetCode]; } while (decompressionState->firstcode == decompressionState->clear_code); return decompressionState->firstcode; } if (decompressionState->stackPtr > decompressionState->stack) { decompressionState->stackPtr--; return *decompressionState->stackPtr; } while ((code = [self _internalGetCode]) >= 0) { if (code == decompressionState->clear_code) { for (i = 0; i < decompressionState->clear_code; ++i) { decompressionState->table[0][i] = 0; decompressionState->table[1][i] = i; } for (; i < (1<<MAX_LWZ_BITS); ++i) decompressionState->table[0][i] = decompressionState->table[1][i] = 0; decompressionState->code_size = decompressionState->set_code_size+1; decompressionState->max_code_size = 2 * decompressionState->clear_code; decompressionState->max_code = decompressionState->clear_code + 2; decompressionState->stackPtr = decompressionState->stack; decompressionState->firstcode = decompressionState->oldcode = [self _internalGetCode]; if(decompressionState->firstcode < LWZ_DONE) fprintf(stderr, "decompressionState->firstcode = miscGetCode() failed w/%d\n", decompressionState->firstcode); return decompressionState->firstcode; } else if (code == decompressionState->end_code) { int count; unsigned char buf[260]; /* Hit end_code -- data should be terminating now. The following boolean test checks to see if the last block read was zero-length. If so, return no error. */ if(decompressionState->zeroDataBlock) return LWZ_NO_ERROR; /* If not, eat next datablock-- it should be a zero block. This will continue eating data blocks until it encounters a zero block. This may or may not be the correct behaviour. */ while ((count = [self _internalGetDataBlock:buf]) > 0) ; if(count < LWZ_DONE) fprintf(stderr, "miscGetDataBlock (no-op while) failed w/%d\n", count); /* if the returned count was less than zero, then it is most likely that we ran off the end of the data [instead of returning data block error]. This is relatively common. */ return (count == 0) ? LWZ_NO_ERROR : LWZ_NO_EOD; } incode = code; if (code >= decompressionState->max_code) { *decompressionState->stackPtr = decompressionState->firstcode; decompressionState->stackPtr++; code = decompressionState->oldcode; } while (code >= decompressionState->clear_code) { *decompressionState->stackPtr = decompressionState->table[1][code]; decompressionState->stackPtr++; if (code == decompressionState->table[0][code]) return LWZ_CIRCULAR_ERR; code = decompressionState->table[0][code]; } *decompressionState->stackPtr = decompressionState->firstcode = decompressionState->table[1][code]; decompressionState->stackPtr++; if ((code = decompressionState->max_code) <(1<<MAX_LWZ_BITS)) { decompressionState->table[0][code] = decompressionState->oldcode; decompressionState->table[1][code] = decompressionState->firstcode; ++decompressionState->max_code; if ((decompressionState->max_code >= decompressionState->max_code_size) && (decompressionState->max_code_size < (1<<MAX_LWZ_BITS))) { decompressionState->max_code_size *= 2; ++decompressionState->code_size; } } decompressionState->oldcode = incode; if (decompressionState->stackPtr > decompressionState->stack) { --decompressionState->stackPtr; return *decompressionState->stackPtr; } } if(code < LWZ_DONE) { fprintf(stderr, "miscGetCode (head of while) failed with %d\n", code); } return code; } - (BOOL)skipDataBlocks { unsigned char blockSize; const char *p; if(alreadyRead >= length) return NO; p = (const char *)[data bytes] + alreadyRead; blockSize = *p; alreadyRead++; nbytes = MIN(blockSize, length - alreadyRead); alreadyRead += nbytes; return nbytes == blockSize ? YES : NO; } @end @implementation MiscGIFData(PrivateMethods) /* Initializes the state of MiscLWZState struct pointed to by 'state'. Includes initialization for both miscLWZReadByte and miscGetCode sections of that particular buffer. */ - (void)_internalLWZInitStateWithCodeSize:(unsigned char)codeSize { int i; /* miscLWZReadByte() initialization */ decompressionState->set_code_size = codeSize; decompressionState->code_size = decompressionState->set_code_size+1; decompressionState->clear_code = 1 << decompressionState->set_code_size; decompressionState->end_code = decompressionState->clear_code + 1; decompressionState->max_code_size = 2 * decompressionState->clear_code; decompressionState->max_code = decompressionState->clear_code + 2; /* miscGetCode() initialization */ decompressionState->curbit = 0; decompressionState->lastbit = 0; decompressionState->done = FALSE; decompressionState->alreadyRead = 0; decompressionState->fresh = TRUE; for (i = 0; i < decompressionState->clear_code; ++i) { decompressionState->table[0][i] = 0; decompressionState->table[1][i] = i; } for (; i < (1<<MAX_LWZ_BITS); ++i) decompressionState->table[0][i] = decompressionState->table[1][0] = 0; decompressionState->stackPtr = decompressionState->stack; } - (int)_internalGetCode { int i, j, ret; short count; if ( (decompressionState->curbit + decompressionState->code_size) >= decompressionState->lastbit) { if (decompressionState->done) { if (decompressionState->curbit >= decompressionState->lastbit) return LWZ_BIT_OVERRUN; return LWZ_DONE; } decompressionState->buf[0] = decompressionState->buf[decompressionState->last_byte-2]; decompressionState->buf[1] = decompressionState->buf[decompressionState->last_byte-1]; if ((count = [self _internalGetDataBlock:&(decompressionState->buf[2])]) == 0) decompressionState->done = TRUE; else if (count < 0) { fprintf(stderr, "miscGetDataBlock failed with code: %d\n", count); return count; } decompressionState->last_byte = 2 + count; decompressionState->curbit = (decompressionState->curbit - decompressionState->lastbit) + 16; decompressionState->lastbit = (2 + count) * 8 ; } ret = 0; for (i = decompressionState->curbit, j = 0; j < decompressionState->code_size; ++i, ++j) ret |= ((decompressionState->buf[ i / 8 ] & (1 << (i % 8))) != 0) << j; decompressionState->curbit += decompressionState->code_size; return ret; } - (int)_internalGetDataBlock:(unsigned char *)buf { unsigned char count; if(alreadyRead < length){ range = NSMakeRange(alreadyRead,1); [data getBytes:&count range:range]; } else return LWZ_DATA_BLOCK_ERR; alreadyRead++; decompressionState->zeroDataBlock = (count == 0); if(count != 0){ if(alreadyRead + count > length) return LWZ_DATA_BLOCK_ERR; range = NSMakeRange(alreadyRead, count); [data getBytes:buf range:range]; alreadyRead += count; } return count; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.