From 1fd361a1ea06e44286c213ca1f814f49306fdc43 Mon Sep 17 00:00:00 2001 From: giraffedata Date: Sat, 19 Aug 2006 03:12:28 +0000 Subject: Create Subversion repository git-svn-id: http://svn.code.sf.net/p/netpbm/code/trunk@1 9d0c8265-081b-0410-96cb-a4ca84ce46f8 --- converter/ppm/ppmtompeg/bitio.c | 536 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 536 insertions(+) create mode 100644 converter/ppm/ppmtompeg/bitio.c (limited to 'converter/ppm/ppmtompeg/bitio.c') diff --git a/converter/ppm/ppmtompeg/bitio.c b/converter/ppm/ppmtompeg/bitio.c new file mode 100644 index 00000000..e0dc4d4e --- /dev/null +++ b/converter/ppm/ppmtompeg/bitio.c @@ -0,0 +1,536 @@ +/*===========================================================================* + * bitio.c + * + * Procedures concerned with the bit-wise I/O + * + * EXPORTED PROCEDURES: + * Bitio_New + * Bitio_Free + * Bitio_Write + * Bitio_Flush + * Bitio_WriteToSocket + * Bitio_BytePad + * + *===========================================================================*/ + +/* + * Copyright (c) 1995 The Regents of the University of California. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose, without fee, and without written agreement is + * hereby granted, provided that the above copyright notice and the following + * two paragraphs appear in all copies of this software. + * + * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT + * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF + * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +/*==============* + * HEADER FILES * + *==============*/ + +#include +#include +#include +#include + +#include "pm.h" +#include "intcode.h" + +#include "all.h" +#include "byteorder.h" +#include "bitio.h" +#include "mtypes.h" + + + +/*==================* + * STATIC VARIABLES * + *==================*/ + +static uint32 lower_mask[33] = { + 0, + 0x1, 0x3, 0x7, 0xf, + 0x1f, 0x3f, 0x7f, 0xff, + 0x1ff, 0x3ff, 0x7ff, 0xfff, + 0x1fff, 0x3fff, 0x7fff, 0xffff, + 0x1ffff, 0x3ffff, 0x7ffff, 0xfffff, + 0x1fffff, 0x3fffff, 0x7fffff, 0xffffff, + 0x1ffffff, 0x3ffffff, 0x7ffffff, 0xfffffff, + 0x1fffffff, 0x3fffffff, 0x7fffffff, 0xffffffff +}; + + +extern time_t IOtime; + + +/*===========================================================================* + * + * Dump + * + * Writes out the first MAX_BITS bits of the bit bucket to the + * appropriate output file + * + * RETURNS: nothing + * + * SIDE EFFECTS: none + * + *===========================================================================*/ +static void +Dump(BitBucket * const bbPtr) { + struct bitBucket *ptr, *tempPtr; + int i, nitems; + int bitsWritten = 0; + time_t tempTimeStart, tempTimeEnd; + + time(&tempTimeStart); + + for (ptr = bbPtr->firstPtr; ptr && (bitsWritten < MAX_BITS); + ptr = ptr->nextPtr) { + + bigend32 buffer[WORDS_PER_BUCKET]; + + if (ptr->bitsleftcur == 32 && ptr->currword == 0) { + continue; /* empty */ + } + + for (i = 0; i <= ptr->currword; ++i) + buffer[i] = pm_bigendFromUint32(ptr->bits[i]); + + nitems = fwrite(buffer, sizeof(buffer[0]), ptr->currword + 1, + bbPtr->filePtr); + if (nitems != ptr->currword+1) { + fprintf(stderr, + "Whoa! Trouble writing %u words (wrote %u words)! " + "Game over, dude!\n", + ptr->currword+1, nitems); + exit(1); + } + + bitsWritten += ((ptr->currword + 1) * 32); + } + + while ( bbPtr->firstPtr != ptr ) { + tempPtr = bbPtr->firstPtr; + bbPtr->firstPtr = tempPtr->nextPtr; + free(tempPtr); + } + + bbPtr->totalbits -= bitsWritten; + bbPtr->bitsWritten += bitsWritten; + + time(&tempTimeEnd); + IOtime += (tempTimeEnd-tempTimeStart); +} + + +/*=====================* + * EXPORTED PROCEDURES * + *=====================*/ + + +/*===========================================================================* + * + * Bitio_New + * + * Create a new bit bucket; filePtr is a pointer to the open file the + * bits should ultimately be written to. + * + * RETURNS: pointer to the resulting bit bucket + * + * SIDE EFFECTS: none + * + *===========================================================================*/ +BitBucket * +Bitio_New(FILE * const filePtr) { + + BitBucket *bbPtr; + + bbPtr = (BitBucket *) malloc(sizeof(BitBucket)); + ERRCHK(bbPtr, "malloc"); + + bbPtr->firstPtr = bbPtr->lastPtr = malloc(sizeof(struct bitBucket)); + ERRCHK(bbPtr->firstPtr, "malloc"); + + bbPtr->totalbits = 0; + bbPtr->cumulativeBits = 0; + bbPtr->bitsWritten = 0; + bbPtr->filePtr = filePtr; + + bbPtr->firstPtr->nextPtr = NULL; + bbPtr->firstPtr->bitsleft = MAXBITS_PER_BUCKET; + bbPtr->firstPtr->bitsleftcur = 32; + bbPtr->firstPtr->currword = 0; + memset((char *)bbPtr->firstPtr->bits, 0, + sizeof(uint32) * WORDS_PER_BUCKET); + + return bbPtr; +} + + + +BitBucket * +Bitio_New_Filename(const char * const fileName) { + + FILE * outputFile; + + outputFile = fopen(fileName, "wb"); + if (outputFile == NULL) + pm_error("Could not open output file '%s'. " + "Errno=%d (%s)", fileName, errno, strerror(errno)); + + return Bitio_New(outputFile); +} + + + +/*===========================================================================* + * + * Bitio_Free + * + * Frees the memory associated with the given bit bucket + * + * RETURNS: nothing + * + * SIDE EFFECTS: none + * + *===========================================================================*/ +void +Bitio_Free(BitBucket * const bbPtr) { + + struct bitBucket *tmpPtr, *nextPtr; + + for (tmpPtr = bbPtr->firstPtr; tmpPtr != NULL; tmpPtr = nextPtr) { + nextPtr = tmpPtr->nextPtr; + free(tmpPtr); + } + free(bbPtr); +} + + +/*===========================================================================* + * + * Bitio_Write + * + * Writes 'nbits' bits from 'bits' into the given bit bucket + * 'nbits' must be between 0 and 32 + * + * RETURNS: nothing + * + * SIDE EFFECTS: if the number of bits in the bit bucket surpasses + * MAX_BITS, then that many bits are flushed to the + * appropriate output file + * + *===========================================================================*/ +void +Bitio_Write(BitBucket * const bbPtr, + uint32 const bits_arg, + int const nbits) { + + register struct bitBucket *lastPtr, *newPtr; + register int delta; + uint32 bits; + + bits=bits_arg; + assert(nbits <= 32 && nbits >= 0); + + /* + * Clear top bits if not part of data, necessary due to down and + * dirty calls of Bitio_Write with unecessary top bits set. + */ + + bits &= lower_mask[nbits]; + bits = bits & lower_mask[nbits]; + + bbPtr->totalbits += nbits; + bbPtr->cumulativeBits += nbits; + lastPtr = bbPtr->lastPtr; + + delta = nbits - lastPtr->bitsleft; + if (delta >= 0) { + /* + * there's not enough room in the current bucket, so we're + * going to have to allocate another bucket + */ + newPtr = lastPtr->nextPtr = (struct bitBucket *) + malloc(sizeof(struct bitBucket)); + ERRCHK(newPtr, "malloc"); + newPtr->nextPtr = NULL; + newPtr->bitsleft = MAXBITS_PER_BUCKET; + newPtr->bitsleftcur = 32; + newPtr->currword = 0; + memset((char *)newPtr->bits, 0, sizeof(uint32) * WORDS_PER_BUCKET); + bbPtr->lastPtr = newPtr; + + assert(lastPtr->currword == WORDS_PER_BUCKET - 1); + lastPtr->bits[WORDS_PER_BUCKET - 1] |= (bits >> delta); + lastPtr->bitsleft = 0; + lastPtr->bitsleftcur = 0; + /* lastPtr->currword++; */ + + if (!delta) { + if ( bbPtr->totalbits > MAX_BITS ) { + Dump(bbPtr); + } + } + + assert(delta <= 32); + newPtr->bits[0] = (bits & lower_mask[delta]) << (32 - delta); + newPtr->bitsleft -= delta; + newPtr->bitsleftcur -= delta; + } else { + /* + * the current bucket will be sufficient + */ + delta = nbits - lastPtr->bitsleftcur; + lastPtr->bitsleftcur -= nbits; + lastPtr->bitsleft -= nbits; + + if (delta >= 0) + { + /* + * these bits will span more than one word + */ + lastPtr->bits[lastPtr->currword] |= (bits >> delta); + lastPtr->currword++; + lastPtr->bits[lastPtr->currword] = + (bits & lower_mask[delta]) << (32 - delta); + lastPtr->bitsleftcur = 32 - delta; + } else { + /* + * these bits will fit, whole + */ + lastPtr->bits[lastPtr->currword] |= (bits << (-delta)); + } + } + + if ( bbPtr->totalbits > MAX_BITS ) /* flush bits */ + Dump(bbPtr); +} + + +/*===========================================================================* + * + * Bitio_Flush + * + * Flushes all of the remaining bits in the given bit bucket to the + * appropriate output file. It will generate up to the nearest 8-bit + * unit of bits, which means that up to 7 extra 0 bits will be appended + * to the end of the file. + * + * RETURNS: nothing + * + * SIDE EFFECTS: frees the bit bucket + * + *===========================================================================*/ +void +Bitio_Flush(BitBucket * const bbPtr) { + + struct bitBucket *ptr, *tempPtr; + uint32 lastWord; + int i, nitems; + int bitsWritten = 0; + int bitsLeft; + unsigned int numWords; + uint8 charBuf[4]; + boolean flushHere = FALSE; + time_t tempTimeStart, tempTimeEnd; + + time(&tempTimeStart); + + bitsLeft = bbPtr->totalbits; + + for (ptr = bbPtr->firstPtr; ptr; ptr = ptr->nextPtr) { + if (ptr->bitsleftcur == 32 && ptr->currword == 0) { + continue; /* empty */ + } + + if ( bitsLeft >= 32 ) { + bigend32 buffer[WORDS_PER_BUCKET]; + + if ( ((ptr->currword + 1) * 32) > bitsLeft ) { + numWords = ptr->currword; + flushHere = TRUE; + } else + numWords = ptr->currword+1; + + for (i = 0; i < numWords; ++i) + buffer[i] = pm_bigendFromUint32(ptr->bits[i]); + + nitems = fwrite(buffer, sizeof(buffer[0]), numWords, + bbPtr->filePtr); + if (nitems != numWords) { + if (ferror(bbPtr->filePtr)) + pm_error("Error writing %u words to flush a bit bucket. " + "fwrite() gives errno %d (%s)", + numWords, errno, strerror(errno)); + else + pm_error("Problem writing %u words " + "to flush a bit bucket. " + "Only %d words transferred.", + numWords, nitems); + } + + bitsWritten += (numWords * 32); + bitsLeft -= (numWords * 32); + } else { + flushHere = TRUE; + } + + if ( (bitsLeft < 32) && flushHere ) { + lastWord = ptr->bits[ptr->currword]; + + /* output the lastPtr word in big-endian order (network) */ + + /* now write out lastPtr bits */ + while ( bitsLeft > 0 ) { + charBuf[0] = (lastWord >> 24); + charBuf[0] &= lower_mask[8]; + fwrite(charBuf, 1, sizeof(uint8), bbPtr->filePtr); + lastWord = (lastWord << 8); + bitsLeft -= 8; + bitsWritten += 8; + } + } + } + fflush(bbPtr->filePtr); + while ( bbPtr->firstPtr != ptr ) { + tempPtr = bbPtr->firstPtr; + bbPtr->firstPtr = tempPtr->nextPtr; + free(tempPtr); + } + + free(bbPtr); + + time(&tempTimeEnd); + IOtime += (tempTimeEnd-tempTimeStart); +} + + + +void +Bitio_Close(BitBucket * const bbPtr) { + + fclose(bbPtr->filePtr); +} + + + +/*===========================================================================* + * + * Bitio_WriteToSocket + * + * Writes all of the remaining bits in the given bit bucket to the + * given socket. May pad the end of the socket stream with extra 0 + * bits as does Bitio_Flush. + * + * RETURNS: nothing + * + * SIDE EFFECTS: frees the bit bucket + * + *===========================================================================*/ +void +Bitio_WriteToSocket(BitBucket * const bbPtr, + int const socket) { + + struct bitBucket *ptr, *tempPtr; + uint32 lastWord; + int i, nitems; + int bitsWritten = 0; + int bitsLeft; + int numWords; + uint8 charBuf[4]; + boolean flushHere = FALSE; + + bitsLeft = bbPtr->totalbits; + + for (ptr = bbPtr->firstPtr; ptr; ptr = ptr->nextPtr) { + if (ptr->bitsleftcur == 32 && ptr->currword == 0) { + continue; /* empty */ + } + + if ( bitsLeft >= 32 ) { + bigend32 buffer[WORDS_PER_BUCKET]; + + if ( ((ptr->currword + 1) * 32) > bitsLeft ) { + numWords = ptr->currword; + flushHere = TRUE; + } else { + numWords = ptr->currword+1; + } + + for (i = 0; i < numWords; ++i) + buffer[i] = pm_bigendFromUint32(ptr->bits[i]); + + nitems = write(socket, buffer, numWords * sizeof(buffer[0])); + if (nitems != numWords*sizeof(uint32)) { + fprintf(stderr, "Whoa! Trouble writing %u bytes " + "(wrote %u bytes)! " + "Game over, dude!\n", + (unsigned)(numWords*sizeof(buffer[0])), nitems); + exit(1); + } + + bitsWritten += (numWords * 32); + bitsLeft -= (numWords * 32); + } else { + flushHere = TRUE; + } + + if ( (bitsLeft < 32) && flushHere ) { + lastWord = ptr->bits[ptr->currword]; + + /* output the lastPtr word in big-endian order (network) */ + + /* now write out lastPtr bits */ + while ( bitsLeft > 0 ) { + charBuf[0] = (lastWord >> 24); + charBuf[0] &= lower_mask[8]; + if ( write(socket, charBuf, 1) != 1 ) { + fprintf(stderr, "ERROR: write of lastPtr bits\n"); + exit(1); + } + lastWord = (lastWord << 8); + bitsLeft -= 8; + bitsWritten += 8; + } + } + } + + while ( bbPtr->firstPtr != ptr ) { + tempPtr = bbPtr->firstPtr; + bbPtr->firstPtr = tempPtr->nextPtr; + free(tempPtr); + } + + free(bbPtr); +} + + +/*===========================================================================* + * + * Bitio_BytePad + * + * Pads the end of the bit bucket to the nearest byte with 0 bits + * + * RETURNS: nothing + * + *===========================================================================*/ +void +Bitio_BytePad(BitBucket * const bbPtr) { + + struct bitBucket *lastPtrPtr = bbPtr->lastPtr; + + if (lastPtrPtr->bitsleftcur % 8) { + Bitio_Write(bbPtr, 0, lastPtrPtr->bitsleftcur % 8); + } +} -- cgit 1.4.1