185 lines
4.4 KiB
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;
|
|
}
|