Panda3D
pnmbitio.cxx
1 /*
2  * bitio.c - bitstream I/O
3  *
4  * Works for (sizeof(unsigned long)-1)*8 bits.
5  *
6  * Copyright (C) 1992 by David W. Sanderson.
7  *
8  * Permission to use, copy, modify, and distribute this software and its
9  * documentation for any purpose and without fee is hereby granted,
10  * provided that the above copyright notice appear in all copies and
11  * that both that copyright notice and this permission notice appear
12  * in supporting documentation. This software is provided "as is"
13  * without express or implied warranty.
14  */
15 
16 #include "pnmbitio.h"
17 #include <assert.h>
18 struct bitstream
19 {
20  istream *inf;
21  ostream *outf;
22  unsigned long
23  bitbuf; /* bit buffer */
24  int
25  nbitbuf; /* number of bits in 'bitbuf' */
26  char
27  mode;
28 };
29 
30 #define Mask(n) ((1<<(n))-1)
31 
32 #define BitPut(b,ul,n) ((b)->bitbuf = (((b)->bitbuf<<(n)) \
33  |((ul)&Mask(n))), \
34  (b)->nbitbuf += (n))
35 
36 #define BitGet(b,n) (((b)->bitbuf>>((b)->nbitbuf-=(n))) & Mask(n))
37 
38 /*
39  * pm_bitinit() - allocate and return a struct bitstream * for the
40  * given FILE*.
41  *
42  * mode must be one of "r" or "w", according to whether you will be
43  * reading from or writing to the struct bitstream *.
44  *
45  * Returns 0 on error.
46  */
47 
48 EXPCL_PANDA_PNMIMAGE struct bitstream *
49 pm_bitinit(istream *f, const char *mode)
50 {
51  struct bitstream *ans = (struct bitstream *)0;
52 
53  if(!f || !mode || !*mode)
54  return ans;
55  if(strcmp(mode, "r"))
56  return ans;
57 
58  ans = (struct bitstream *)calloc(1, sizeof(struct bitstream));
59  if(ans)
60  {
61  ans->inf = f;
62  ans->mode = *mode;
63  }
64 
65  return ans;
66 }
67 
68 EXPCL_PANDA_PNMIMAGE struct bitstream *
69 pm_bitinit(ostream *f, const char *mode)
70 {
71  struct bitstream *ans = (struct bitstream *)0;
72 
73  if(!f || !mode || !*mode)
74  return ans;
75  if(strcmp(mode, "w"))
76  return ans;
77 
78  ans = (struct bitstream *)calloc(1, sizeof(struct bitstream));
79  if(ans)
80  {
81  ans->outf = f;
82  ans->mode = *mode;
83  }
84 
85  return ans;
86 }
87 
88 /*
89  * pm_bitfini() - deallocate the given struct bitstream *.
90  *
91  * You must call this after you are done with the struct bitstream *.
92  *
93  * It may flush some bits left in the buffer.
94  *
95  * Returns the number of bytes written, -1 on error.
96  */
97 
98 EXPCL_PANDA_PNMIMAGE int
99 pm_bitfini(struct bitstream *b)
100 {
101  int nbyte = 0;
102 
103  if(!b)
104  return -1;
105 
106  /* flush the output */
107  if(b->mode == 'w')
108  {
109  /* flush the bits */
110  if (b->nbitbuf < 0 || b->nbitbuf >= 8)
111  {
112  /* pm_bitwrite() didn't work */
113  return -1;
114  }
115 
116  /*
117  * If we get to here, nbitbuf is 0..7
118  */
119  if(b->nbitbuf)
120  {
121  char c;
122 
123  BitPut(b, 0, (long)8-(b->nbitbuf));
124  c = (char) BitGet(b, (long)8);
125  if(!b->outf->put(c))
126  {
127  return -1;
128  }
129  nbyte++;
130  }
131  }
132 
133  free(b);
134  return nbyte;
135 }
136 
137 /*
138  * pm_bitread() - read the next nbits into *val from the given file.
139  *
140  * The last pm_bitread() must be followed by a call to pm_bitfini().
141  *
142  * Returns the number of bytes read, -1 on error.
143  */
144 
145 EXPCL_PANDA_PNMIMAGE int
146 pm_bitread(struct bitstream *b, unsigned long nbits, unsigned long *val)
147 {
148  int nbyte = 0;
149  int c;
150 
151  if(!b)
152  return -1;
153 
154  #ifdef _DEBUG
155  assert(((signed long)nbits) > 0);
156  #endif
157 
158  while (b->nbitbuf < (signed long)nbits)
159  {
160  if((c = b->inf->get()) == EOF)
161  {
162  return -1;
163  }
164  nbyte++;
165 
166  BitPut(b, c, (long) 8);
167  }
168 
169  *val = BitGet(b, nbits);
170  return nbyte;
171 }
172 
173 /*
174  * pm_bitwrite() - write the low nbits of val to the given file.
175  *
176  * The last pm_bitwrite() must be followed by a call to pm_bitfini().
177  *
178  * Returns the number of bytes written, -1 on error.
179  */
180 
181 EXPCL_PANDA_PNMIMAGE int
182 pm_bitwrite(struct bitstream *b, unsigned long nbits, unsigned long val)
183 {
184  int nbyte = 0;
185  char c;
186 
187  if(!b)
188  return -1;
189 
190  BitPut(b, val, nbits);
191 
192  while (b->nbitbuf >= 8)
193  {
194  c = (char) BitGet(b, (long)8);
195 
196  if(!b->outf->put(c))
197  {
198  return -1;
199  }
200  nbyte++;
201  }
202 
203  return nbyte;
204 }