open_toontown_panda3d/panda/src/pnm/bitio.c

185 lines
4.4 KiB
C

/*
* bitio.c - bitstream I/O
*
* Works for (sizeof(unsigned long)-1)*8 bits.
*
* Copyright (C) 1992 by David W. Sanderson.
*
* 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.
*/
#include "bitio.h"
#include <assert.h>
struct bitstream
{
FILE *
f; /* bytestream */
unsigned long
bitbuf; /* bit buffer */
int
nbitbuf; /* number of bits in 'bitbuf' */
char
mode;
};
#define Mask(n) ((1<<(n))-1)
#define BitPut(b,ul,n) ((b)->bitbuf = (((b)->bitbuf<<(n)) \
|((ul)&Mask(n))), \
(b)->nbitbuf += (n))
#define BitGet(b,n) (((b)->bitbuf>>((b)->nbitbuf-=(n))) & Mask(n))
/*
* pm_bitinit() - allocate and return a struct bitstream * for the
* given FILE*.
*
* mode must be one of "r" or "w", according to whether you will be
* reading from or writing to the struct bitstream *.
*
* Returns 0 on error.
*/
EXPCL_PANDA struct bitstream *
pm_bitinit(FILE *f, char *mode)
{
struct bitstream *ans = (struct bitstream *)0;
if(!f || !mode || !*mode)
return ans;
if(strcmp(mode, "r") && strcmp(mode, "w"))
return ans;
ans = (struct bitstream *)calloc(1, sizeof(struct bitstream));
if(ans)
{
ans->f = f;
ans->mode = *mode;
}
return ans;
}
/*
* pm_bitfini() - deallocate the given struct bitstream *.
*
* You must call this after you are done with the struct bitstream *.
*
* It may flush some bits left in the buffer.
*
* Returns the number of bytes written, -1 on error.
*/
EXPCL_PANDA int
pm_bitfini(struct bitstream *b)
{
int nbyte = 0;
if(!b)
return -1;
/* flush the output */
if(b->mode == 'w')
{
/* flush the bits */
if (b->nbitbuf < 0 || b->nbitbuf >= 8)
{
/* pm_bitwrite() didn't work */
return -1;
}
/*
* If we get to here, nbitbuf is 0..7
*/
if(b->nbitbuf)
{
char c;
BitPut(b, 0, (long)8-(b->nbitbuf));
c = (char) BitGet(b, (long)8);
if(putc(c, b->f) == EOF)
{
return -1;
}
nbyte++;
}
}
free(b);
return nbyte;
}
/*
* pm_bitread() - read the next nbits into *val from the given file.
*
* The last pm_bitread() must be followed by a call to pm_bitfini().
*
* Returns the number of bytes read, -1 on error.
*/
EXPCL_PANDA int
pm_bitread(struct bitstream *b, unsigned long nbits, unsigned long *val)
{
int nbyte = 0;
int c;
if(!b)
return -1;
#ifdef _DEBUG
assert(((signed long)nbits) > 0);
#endif
while (b->nbitbuf < (signed long)nbits)
{
if((c = getc(b->f)) == EOF)
{
return -1;
}
nbyte++;
BitPut(b, c, (long) 8);
}
*val = BitGet(b, nbits);
return nbyte;
}
/*
* pm_bitwrite() - write the low nbits of val to the given file.
*
* The last pm_bitwrite() must be followed by a call to pm_bitfini().
*
* Returns the number of bytes written, -1 on error.
*/
EXPCL_PANDA int
pm_bitwrite(struct bitstream *b, unsigned long nbits, unsigned long val)
{
int nbyte = 0;
char c;
if(!b)
return -1;
BitPut(b, val, nbits);
while (b->nbitbuf >= 8)
{
c = (char) BitGet(b, (long)8);
if(putc(c, b->f) == EOF)
{
return -1;
}
nbyte++;
}
return nbyte;
}