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