1 /*===========================================================================*
2  * bitio.c								     *
3  *									     *
4  *	Procedures concerned with the bit-wise I/O			     *
5  *									     *
6  * EXPORTED PROCEDURES:							     *
7  *	Bitio_New							     *
8  *	Bitio_Free							     *
9  *	Bitio_Write							     *
10  *	Bitio_Flush							     *
11  *	Bitio_WriteToSocket						     *
12  *	Bitio_BytePad							     *
13  *									     *
14  *===========================================================================*/
15 
16 /*
17  * Copyright (c) 1995 The Regents of the University of California.
18  * All rights reserved.
19  *
20  * Permission to use, copy, modify, and distribute this software and its
21  * documentation for any purpose, without fee, and without written agreement is
22  * hereby granted, provided that the above copyright notice and the following
23  * two paragraphs appear in all copies of this software.
24  *
25  * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
26  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
27  * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
28  * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  *
30  * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
31  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
32  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
33  * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
34  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
35  */
36 
37 /*
38  *  $Header: /n/picasso/project/mm/mpeg/mpeg_dist/mpeg_encode/RCS/bitio.c,v 1.13 1995/06/21 18:36:06 smoot Exp $
39  *  $Log: bitio.c,v $
40  * Revision 1.13  1995/06/21  18:36:06  smoot
41  * added a flush when done with file
42  *
43  * Revision 1.12  1995/01/19  23:07:15  eyhung
44  * Changed copyrights
45  *
46  * Revision 1.11  1994/11/12  02:11:43  keving
47  * nothing
48  *
49  * Revision 1.10  1993/12/22  19:19:01  keving
50  * nothing
51  *
52  * Revision 1.10  1993/12/22  19:19:01  keving
53  * nothing
54  *
55  * Revision 1.9  1993/07/22  22:23:43  keving
56  * nothing
57  *
58  * Revision 1.8  1993/06/30  20:06:09  keving
59  * nothing
60  *
61  * Revision 1.7  1993/06/03  21:08:08  keving
62  * nothing
63  *
64  * Revision 1.6  1993/02/17  23:21:41  dwallach
65  * checkin prior to keving's joining the project
66  *
67  * Revision 1.5  1993/01/18  10:20:02  dwallach
68  * *** empty log message ***
69  *
70  * Revision 1.4  1993/01/18  10:17:29  dwallach
71  * RCS headers installed, code indented uniformly
72  *
73  * Revision 1.4  1993/01/18  10:17:29  dwallach
74  * RCS headers installed, code indented uniformly
75  *
76  */
77 
78 /*==============*
79  * HEADER FILES *
80  *==============*/
81 
82 #include <assert.h>
83 #include <time.h>
84 #include <stdio.h>
85 #include <string.h>
86 #include "all.h"
87 #include "byteorder.h"
88 #include "bitio.h"
89 #include "mtypes.h"
90 
91 /*===============================*
92  * INTERNAL PROCEDURE prototypes *
93  *===============================*/
94 
95 static void Dump _ANSI_ARGS_((BitBucket *bbPtr));
96 
97 
98 /*==================*
99  * STATIC VARIABLES *
100  *==================*/
101 
102 static uint32 lower_mask[33] = {
103     0,
104     0x1, 0x3, 0x7, 0xf,
105     0x1f, 0x3f, 0x7f, 0xff,
106     0x1ff, 0x3ff, 0x7ff, 0xfff,
107     0x1fff, 0x3fff, 0x7fff, 0xffff,
108     0x1ffff, 0x3ffff, 0x7ffff, 0xfffff,
109     0x1fffff, 0x3fffff, 0x7fffff, 0xffffff,
110     0x1ffffff, 0x3ffffff, 0x7ffffff, 0xfffffff,
111     0x1fffffff, 0x3fffffff, 0x7fffffff, 0xffffffff
112 };
113 
114 
115 extern time_t IOtime;
116 
117 
118 /*=====================*
119  * EXPORTED PROCEDURES *
120  *=====================*/
121 
122 
123 /*===========================================================================*
124  *
125  * Bitio_New
126  *
127  *	Create a new bit bucket; filePtr is a pointer to the open file the
128  *	bits should ultimately be written to.
129  *
130  * RETURNS:	pointer to the resulting bit bucket
131  *
132  * SIDE EFFECTS:    none
133  *
134  *===========================================================================*/
135 BitBucket *
Bitio_New(FILE * filePtr)136 Bitio_New(FILE *filePtr)
137 {
138     BitBucket *bbPtr;
139 
140     bbPtr = (BitBucket *) malloc(sizeof(BitBucket));
141     ERRCHK(bbPtr, "malloc");
142 
143     bbPtr->firstPtr = bbPtr->lastPtr = (struct bitBucket *) malloc(sizeof(struct bitBucket));
144     ERRCHK(bbPtr->firstPtr, "malloc");
145 
146     bbPtr->totalbits = 0;
147     bbPtr->cumulativeBits = 0;
148     bbPtr->bitsWritten = 0;
149     bbPtr->filePtr = filePtr;
150 
151     bbPtr->firstPtr->nextPtr = NULL;
152     bbPtr->firstPtr->bitsleft = MAXBITS_PER_BUCKET;
153     bbPtr->firstPtr->bitsleftcur = 32;
154     bbPtr->firstPtr->currword = 0;
155     memset((char *)bbPtr->firstPtr->bits, 0, sizeof(uint32) * WORDS_PER_BUCKET);
156 
157     return bbPtr;
158 }
159 
160 
161 /*===========================================================================*
162  *
163  * Bitio_Free
164  *
165  *	Frees the memory associated with the given bit bucket
166  *
167  * RETURNS:	nothing
168  *
169  * SIDE EFFECTS:    none
170  *
171  *===========================================================================*/
172 void
Bitio_Free(BitBucket * bbPtr)173 Bitio_Free(BitBucket *bbPtr)
174 {
175     struct bitBucket *tmpPtr, *nextPtr;
176 
177     for (tmpPtr = bbPtr->firstPtr; tmpPtr != NULL; tmpPtr = nextPtr) {
178 	nextPtr = tmpPtr->nextPtr;
179 	free(tmpPtr);
180     }
181     free(bbPtr);
182 }
183 
184 
185 /*===========================================================================*
186  *
187  * Bitio_Write
188  *
189  *	Writes 'nbits' bits from 'bits' into the given bit bucket
190  *	'nbits' must be between 0 and 32
191  *
192  * RETURNS:	nothing
193  *
194  * SIDE EFFECTS:    if the number of bits in the bit bucket surpasses
195  *		    MAX_BITS, then that many bits are flushed to the
196  *		    appropriate output file
197  *
198  *===========================================================================*/
199 void
Bitio_Write(BitBucket * bbPtr,uint32 bits,int nbits)200 Bitio_Write(BitBucket *bbPtr,
201             uint32 bits,
202             int nbits)
203 {
204     register struct bitBucket *lastPtr, *newPtr;
205     register int delta;
206 
207     assert(nbits <= 32 && nbits >= 0);
208 
209     /*
210      * Clear top bits if not part of data, necessary due to down and
211      * dirty calls of Bitio_Write with unecessary top bits set.
212      */
213 
214     bits = bits & lower_mask[nbits];
215 
216     bbPtr->totalbits += nbits;
217     bbPtr->cumulativeBits += nbits;
218     lastPtr = bbPtr->lastPtr;
219 
220     delta = nbits - lastPtr->bitsleft;
221     if (delta >= 0) {
222 	/*
223          * there's not enough room in the current bucket, so we're
224          * going to have to allocate another bucket
225     	 */
226 	newPtr = lastPtr->nextPtr = (struct bitBucket *) malloc(sizeof(struct bitBucket));
227 	ERRCHK(newPtr, "malloc");
228 	newPtr->nextPtr = NULL;
229 	newPtr->bitsleft = MAXBITS_PER_BUCKET;
230 	newPtr->bitsleftcur = 32;
231 	newPtr->currword = 0;
232 	memset((char *)newPtr->bits, 0, sizeof(uint32) * WORDS_PER_BUCKET);
233 	bbPtr->lastPtr = newPtr;
234 
235 	assert(lastPtr->currword == WORDS_PER_BUCKET - 1);
236 	lastPtr->bits[WORDS_PER_BUCKET - 1] |= (bits >> delta);
237 	lastPtr->bitsleft = 0;
238 	lastPtr->bitsleftcur = 0;
239 	/* lastPtr->currword++; */
240 
241 	if (!delta) {
242 	    if ( bbPtr->totalbits > MAX_BITS ) {
243 		Dump(bbPtr);
244 	    }
245 	}
246 
247 	assert(delta <= 32);
248 	newPtr->bits[0] = (bits & lower_mask[delta]) << (32 - delta);
249 	newPtr->bitsleft -= delta;
250 	newPtr->bitsleftcur -= delta;
251     } else {
252 	/*
253          * the current bucket will be sufficient
254 	 */
255 	delta = nbits - lastPtr->bitsleftcur;
256 	lastPtr->bitsleftcur -= nbits;
257 	lastPtr->bitsleft -= nbits;
258 
259 	if (delta >= 0)
260 	{
261 	    /*
262 	     * these bits will span more than one word
263 	     */
264 	    lastPtr->bits[lastPtr->currword] |= (bits >> delta);
265 	    lastPtr->currword++;
266 	    lastPtr->bits[lastPtr->currword] = (bits & lower_mask[delta]) << (32 - delta);
267 	    lastPtr->bitsleftcur = 32 - delta;
268 	} else {
269 	    /*
270 	     * these bits will fit, whole
271 	     */
272 	    lastPtr->bits[lastPtr->currword] |= (bits << (-delta));
273 	}
274     }
275 
276     if ( bbPtr->totalbits > MAX_BITS )	/* flush bits */
277 	Dump(bbPtr);
278 }
279 
280 
281 /*===========================================================================*
282  *
283  * Bitio_Flush
284  *
285  *	Flushes all of the remaining bits in the given bit bucket to the
286  *	appropriate output file.  It will generate up to the nearest 8-bit
287  *	unit of bits, which means that up to 7 extra 0 bits will be appended
288  *	to the end of the file.
289  *
290  * RETURNS:	nothing
291  *
292  * SIDE EFFECTS:    frees the bit bucket
293  *
294  *===========================================================================*/
295 void
Bitio_Flush(BitBucket * bbPtr)296 Bitio_Flush(BitBucket *bbPtr)
297 {
298     struct bitBucket *ptr, *tempPtr;
299     uint32 buffer[WORDS_PER_BUCKET];
300     uint32  lastWord;
301     int i, nitems;
302     int	    bitsWritten = 0;
303     int	    bitsLeft;
304     int	    numWords;
305     uint8   charBuf[4];
306     boolean    flushHere = FALSE;
307     time_t  tempTimeStart, tempTimeEnd;
308 
309     time(&tempTimeStart);
310 
311     bitsLeft = bbPtr->totalbits;
312 
313     for (ptr = bbPtr->firstPtr; ptr; ptr = ptr->nextPtr) {
314 	if (ptr->bitsleftcur == 32 && ptr->currword == 0) {
315 	    continue;		/* empty */
316 	}
317 
318 	if ( bitsLeft >= 32 ) {
319 	    if ( ((ptr->currword + 1) * 32) > bitsLeft ) {
320 		numWords = ptr->currword;
321 		flushHere = TRUE;
322 	    } else {
323 		numWords = ptr->currword+1;
324 	    }
325 
326 	    for (i = 0; i < numWords; i++) {
327 		buffer[i] = htonl(ptr->bits[i]);
328 	    }
329 
330 	    nitems = fwrite(buffer, sizeof(uint32), numWords, bbPtr->filePtr);
331 	    if (nitems != numWords) {
332               throw "Whoa!  Trouble writing bytes";
333 	    }
334 
335 	    bitsWritten += (numWords * 32);
336 	    bitsLeft -= (numWords * 32);
337 	} else {
338 	    flushHere = TRUE;
339 	}
340 
341 	if ( (bitsLeft < 32) && flushHere ) {
342 	    lastWord = ptr->bits[ptr->currword];
343 
344 	    /* output the lastPtr word in big-endian order (network) */
345 
346 	    /* now write out lastPtr bits */
347 	    while ( bitsLeft > 0 ) {
348 		charBuf[0] = (lastWord >> 24);
349 		charBuf[0] &= lower_mask[8];
350 		fwrite(charBuf, 1, sizeof(uint8), bbPtr->filePtr);
351 		lastWord = (lastWord << 8);
352 		bitsLeft -= 8;
353 		bitsWritten += 8;
354 	    }
355 	}
356     }
357     fflush(bbPtr->filePtr);
358     while ( bbPtr->firstPtr != ptr ) {
359 	tempPtr = bbPtr->firstPtr;
360 	bbPtr->firstPtr = tempPtr->nextPtr;
361 	free(tempPtr);
362     }
363 
364     free(bbPtr);
365 
366     time(&tempTimeEnd);
367     IOtime += (tempTimeEnd-tempTimeStart);
368 }
369 
370 
371 /*===========================================================================*
372  *
373  * Bitio_WriteToSocket
374  *
375  *	Writes all of the remaining bits in the given bit bucket to the
376  *	given socket.  May pad the end of the socket stream with extra 0
377  *	bits as does Bitio_Flush.
378  *
379  * RETURNS:	nothing
380  *
381  * SIDE EFFECTS:    frees the bit bucket
382  *
383  *===========================================================================*/
384 void
Bitio_WriteToSocket(BitBucket * bbPtr,int socket)385 Bitio_WriteToSocket(BitBucket *bbPtr,
386                     int socket)
387 {
388   throw "WriteToSocket not implemented";
389 }
390 
391 
392 /*===========================================================================*
393  *
394  * Bitio_BytePad
395  *
396  *	Pads the end of the bit bucket to the nearest byte with 0 bits
397  *
398  * RETURNS:	nothing
399  *
400  *===========================================================================*/
401 void
Bitio_BytePad(BitBucket * bbPtr)402 Bitio_BytePad(BitBucket *bbPtr)
403 {
404     struct bitBucket *lastPtrPtr = bbPtr->lastPtr;
405 
406     if (lastPtrPtr->bitsleftcur % 8) {
407 	Bitio_Write(bbPtr, 0, lastPtrPtr->bitsleftcur % 8);
408     }
409 }
410 
411 
412 /*=====================*
413  * INTERNAL PROCEDURES *
414  *=====================*/
415 
416 
417 /*===========================================================================*
418  *
419  * Dump
420  *
421  *	Writes out the first MAX_BITS bits of the bit bucket to the
422  *	appropriate output file
423  *
424  * RETURNS:	nothing
425  *
426  * SIDE EFFECTS:  none
427  *
428  *===========================================================================*/
429 static void
Dump(BitBucket * bbPtr)430 Dump(BitBucket *bbPtr)
431 {
432     struct bitBucket *ptr, *tempPtr;
433     uint32 buffer[WORDS_PER_BUCKET];
434     int i, nitems;
435     int	    bitsWritten = 0;
436     time_t  tempTimeStart, tempTimeEnd;
437 
438     time(&tempTimeStart);
439 
440     for (ptr = bbPtr->firstPtr; ptr && (bitsWritten < MAX_BITS);
441 	 ptr = ptr->nextPtr) {
442 	if (ptr->bitsleftcur == 32 && ptr->currword == 0) {
443 	    continue;		/* empty */
444 	}
445 
446 	for (i = 0; i <= ptr->currword; i++) {
447 	    buffer[i] = htonl(ptr->bits[i]);
448 	}
449 
450 	nitems = fwrite((uint8 *)buffer, sizeof(uint32), (ptr->currword + 1), bbPtr->filePtr);
451 	if (nitems != (ptr->currword+1)) {
452           throw "Whoa!  Trouble writing bytes";
453 	}
454 
455 	bitsWritten += ((ptr->currword + 1) * 32);
456     }
457 
458     while ( bbPtr->firstPtr != ptr ) {
459 	tempPtr = bbPtr->firstPtr;
460 	bbPtr->firstPtr = tempPtr->nextPtr;
461 	free(tempPtr);
462     }
463 
464     bbPtr->totalbits -= bitsWritten;
465     bbPtr->bitsWritten += bitsWritten;
466 
467     time(&tempTimeEnd);
468     IOtime += (tempTimeEnd-tempTimeStart);
469 }
470 
471 
472