Panda3D
Loading...
Searching...
No Matches
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
19using std::istream;
20using std::ostream;
21
22struct 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
52EXPCL_PANDA_PNMIMAGE struct bitstream *
53pm_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
72EXPCL_PANDA_PNMIMAGE struct bitstream *
73pm_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
102EXPCL_PANDA_PNMIMAGE int
103pm_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
149EXPCL_PANDA_PNMIMAGE int
150pm_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
185EXPCL_PANDA_PNMIMAGE int
186pm_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}