|
|
1.1 root 1: /* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved. */
2: /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T. */
3: /* The copyright notice does not imply actual or intended publication. */
4: /* AUTHORS: */
5: /* H. S. Baird - ATT-BL MH - first versions */
6:
7: /* bitio.h - view a stream file as a sequence of binary values, hiding the
8: bit- and byte-packing format of the file. The format of input and output
9: files may differ. Reading and writing are performed by macroes for speed;
10: the price for this is that the file formats must be fixed at compile time.
11:
12: SYNOPSIS
13: #include <stdio.h>
14: #include "bitio.h"
15:
16: BITFILE *bopen(stream,type);
17: FILE *stream;
18: char *type;
19:
20: int getb(bitfile);
21: BITFILE *bitfile;
22:
23: putb(bit,bitfile);
24: int bit;
25:
26: padb(bitfile,bit,bdy,len);
27: int bit,bdy,len;
28:
29: char *bbuffer(bitfile);
30:
31: unsigned long bsize(bitfile);
32:
33: unsigned long bflush(bitfile);
34:
35: unsigned long bclose(bitfile);
36:
37: COMPILER DEPENDENCIES
38: The compiler's data types must include:
39: unsigned char: 8 bits each
40: unsigned short: 2 unsigned chars each
41: unsigned int: 2 unsigned shorts each
42: DESCRIPTION
43: Bopen views the named stream file as a bit file to be read (if type is "r")
44: or written (if type is "w" or "wb"). The stream file must already have been
45: fopen(3)ed, and the first bit to be read/written will be the first bit in its
46: next byte in getc(3)/putc(3) order. Bopen returns a pointer which identifies
47: the bitfile to the other functions. System or stream I/O to/from the
48: associated stream should not be used until after bclose is called.
49: If bopen's type is "wb", then the entire output stream will be buffered
50: in main memory until bflush or bclose are called. At any time, bbuffer
51: returns this buffer's address and bsize its length in bytes.
52: Getb returns the next bit from the named bitfile. It returns EOF on
53: end of file or read error. EOF may occur on a byte, short, or int boundary,
54: depending on file format.
55: Putb appends the given bit to the named bitfile.
56: Padb writes 'bit' enough times (possibly 0) so that if a bitstring
57: of length 'len' were written next it would end on a 'bdy'-bit boundary
58: (may do the wrong thing if 'bdy' doesn't divide UINT_MAX).
59: Bflush ensures that all written bits have been written to the stream
60: via putc(3). The output is padded with 0 bits to a byte, short, or int
61: boundary, depending on file format. It returns the number of bytes (not bits)
62: written since bopen or the last bflush. The bitfile remains open. It does not
63: fflush(3) the associated stream.
64: Bclose causes a bflush and frees all buffers. It returns the total
65: number of bytes (not bits) read/written since bopen. It fflush(3)'es,
66: but does not fclose(3) the associated stream.
67:
68: Bitfile formats are selected at compile time: see `FORMAT:' at the
69: end of this file. The formats for input and output may differ. Formats
70: include:
71: a each bit is an ASCII character: '0' or '1', in putc(3) order; not padded.
72: 0 the low-order (0001) bit in each byte is first ("little-endian"), and
73: bytes are in putc(3) order; EOF and padding at a byte boundary.
74: 1 the high-order (0200) bit in each byte is first ("big-endian"), and
75: bytes are in putc(3) order; EOF and padding at a byte boundary.
76: 10 the low-order (0001) bit in each byte is first ("little-endian"), but
77: bytes are reversed (in each pair) from putc(3) order; EOF and padding
78: at a short boundary.
79: 11 the high-order (0200) bit in each byte is first ("big-endian"), but
80: bytes are reversed (in each pair) from putc(3) order; EOF and padding
81: at a short boundary.
82: Planned (data structures are in place; code will be implemented if needed):
83: 100 the low-order (0001) bit in each byte is first ("little-endian"), and
84: bytes (in each pair) are in putc(3) order; but shorts (in each pair)
85: are reversed from putc(3) order; EOF and padding at an int boundary.
86: 101, 110, 111 - by obvious analogy
87: BUGS
88: Putting to an input bitfile or getting from an output bitfile is
89: erroneous, but is not checked for.
90: */
91:
92: #define BUFFERED (T) /* enable buffering of output */
93:
94: typedef struct BITFILE {
95: FILE *fp; /* associated stream */
96: char type; /* one of 'r','w' */
97: int ic; /* byte just read */
98: unsigned long nb; /* no. bytes read/written since bopen */
99: unsigned long alloc; /* no. bytes allocated in buffer */
100: char *buf; /* buffer (in malloc space) */
101: char *cp; /* next char in buffer */
102: unsigned int n; /* no. bits written so far (mod UINT_MAX) */
103: unsigned char cm; /* single-bit mask */
104: unsigned short sm; /* single-bit mask */
105: unsigned int im; /* single-bit mask */
106: union { struct { /* used to reorder char & short order */
107: union { struct {
108: unsigned char c0;
109: unsigned char c1;
110: } cc;
111: unsigned short s;
112: } s0;
113: union { struct {
114: unsigned char c0;
115: unsigned char c1;
116: } cc;
117: unsigned short s;
118: } s1;
119: } ss;
120: unsigned int i;
121: } i;
122: } BITFILE;
123: #define Init_BITFILE {NULL,'\0',0,0L,0L,NULL,NULL,0,0,0}
124: #if MAIN
125: BITFILE empty_BITFILE = Init_BITFILE;
126: #else
127: extern BITFILE empty_BITFILE;
128: #endif
129:
130: /* Code common to all formats: */
131: #if MAIN
132: BITFILE *bopen_rw(s,t)
133: FILE *s;
134: char *t;
135: { BITFILE *f;
136: if((f=(BITFILE *)malloc(sizeof(BITFILE)))==NULL) {
137: err("bopen: can't alloc");
138: return(NULL);
139: };
140: *f = empty_BITFILE;
141: f->fp = s;
142: f->type = *t;
143: return(f);
144: }
145: #else
146: BITFILE *bopen_rw();
147: #endif
148:
149: #define bbuffer(f) ((f)->buf)
150: #define bsize(f) ((bbuffer(f)!=NULL)? ((f)->cp - (f)->buf): 0L)
151:
152: #if !BUFFERED
153: #define bputc(c,f) putc((c),(f)->fp)
154: #define bbflush(f) (0L)
155: #else
156: #define BITFILE_incr (512) /* buffer allocations are in these increments */
157:
158: #if MAIN
159: brealloc(f)
160: BITFILE *f;
161: { int nbuf; /* no. bytes in buffer */
162: nbuf = bsize(f);
163: f->alloc += BITFILE_incr;
164: if((f->buf=(char *)realloc(f->buf,f->alloc))==NULL)
165: abort("");
166: f->cp = f->buf + nbuf;
167: }
168: #endif
169:
170: #define bputc(c,f) { \
171: if((f)->buf==NULL) putc((c),(f)->fp); \
172: else { if(bsize(f)==(f)->alloc) brealloc(f); \
173: *(++((f)->cp))=(c); \
174: } \
175: }
176:
177: #if MAIN
178: unsigned long bbflush(f)
179: BITFILE *f; /* f->buf!=NULL && bsize(f)>0 */
180: { register char *cp,*cq;
181: unsigned long nbuf;
182: nbuf = bsize(f);
183: for(cq=(cp=f->buf)+nbuf; cp<cq; cp++) putc(*cp,f->fp);
184: f->cp=f->buf;
185: return(nbuf);
186: }
187: #else
188: unsigned long bbflush();
189: #endif
190: #endif
191:
192: /* Code particular to each format: */
193:
194: /* Format a: ASCII file, one printable char ('0' or '1') per bit: */
195: #define bopen_r_a(s) bopen_rw((s),"r")
196: #define bopen_w_a(s) bopen_rw((s),"w")
197: #define getb_a(f) ( (((f)->ic=getc((f)->fp))!=EOF)? \
198: ((f)->nb++, \
199: ((f)->ic=='0')? \
200: 0: \
201: (((f)->ic=='1')? 1: EOF)): \
202: EOF )
203: #define putb_a(b,f) { if((b)) bputc('1',f); else bputc('0',f); (f)->nb++; }
204: #define bflush_a(f) ( (bsize(f)>0)? bbflush(f): (0L) )
205:
206: /* Format 0: the low-order bit (0001) in each byte is first ("little-endian"),
207: and bytes are in putc(3) order; */
208: #if MAIN
209: BITFILE *bopen_r_0(s)
210: FILE *s;
211: { BITFILE *f;
212: if((f=bopen_rw(s,"r"))!=NULL) {
213: f->cm=0000;
214: };
215: return(f);
216: }
217: #else
218: BITFILE *bopen_r_0();
219: #endif
220: #if MAIN
221: BITFILE *bopen_w_0(s)
222: FILE *s;
223: { BITFILE *f;
224: if((f=bopen_rw(s,"w"))!=NULL) {
225: f->i.ss.s0.cc.c0=0000;
226: f->cm=0001;
227: };
228: return(f);
229: }
230: #else
231: BITFILE *bopen_w_0();
232: #endif
233: #define getb_0(f) ( ((f)->cm)? \
234: ( ((f)->cm&(f)->ic)? \
235: ((f)->cm<<=1,1): \
236: ((f)->cm<<=1,0) ): \
237: ( (((f)->ic=getc((f)->fp))==EOF)? \
238: EOF: \
239: ( (f)->nb++, \
240: (f)->cm=0001, \
241: ((f)->cm&(f)->ic)? \
242: ((f)->cm<<=1,1): \
243: ((f)->cm<<=1,0) ) ) )
244: #define putb_0(b,f) { \
245: if((b)) (f)->i.ss.s0.cc.c0 |= (f)->cm; \
246: if( !((f)->cm<<=1) ) { \
247: bputc((f)->i.ss.s0.cc.c0,f); \
248: (f)->nb++; \
249: (f)->i.ss.s0.cc.c0=0000; (f)->cm=0001; \
250: }; \
251: (f)->n++; \
252: }
253: #define bflush_0(f) (padb((f),0,8,0), (bsize(f)>0)? bbflush(f): 0L)
254:
255: /* Format 1: the high-order bit (0200) in each byte is first ("big-endian"), and
256: bytes are in putc(3) order; */
257: #if MAIN
258: BITFILE *bopen_r_1(s)
259: FILE *s;
260: { BITFILE *f;
261: if((f=bopen_rw(s,"r"))!=NULL) {
262: f->cm=0000;
263: };
264: return(f);
265: }
266: #else
267: BITFILE *bopen_r_1();
268: #endif
269: #if MAIN
270: BITFILE *bopen_w_1(s)
271: FILE *s;
272: { BITFILE *f;
273: if((f=bopen_rw(s,"w"))!=NULL) {
274: f->i.ss.s0.cc.c0=0000;
275: f->cm=0200;
276: };
277: return(f);
278: }
279: #else
280: BITFILE *bopen_w_1();
281: #endif
282: #define getb_1(f) ( ((f)->cm)? \
283: ( ((f)->cm&(f)->ic)? \
284: ((f)->cm>>=1,1): \
285: ((f)->cm>>=1,0) ): \
286: ( (((f)->ic=getc((f)->fp))==EOF)? \
287: EOF: \
288: ( (f)->nb++, \
289: (f)->cm=0200, \
290: ((f)->cm&(f)->ic)? \
291: ((f)->cm>>=1,1): \
292: ((f)->cm>>=1,0) ) ) )
293: #define putb_1(b,f) { \
294: if((b)) (f)->i.ss.s0.cc.c0 |= (f)->cm; \
295: if( !((f)->cm>>=1) ) { \
296: bputc((f)->i.ss.s0.cc.c0,f); \
297: (f)->nb++; \
298: (f)->i.ss.s0.cc.c0=0000; (f)->cm=0200; \
299: }; \
300: (f)->n++; \
301: }
302: #define bflush_1(f) (padb((f),0,8,0), (bsize(f)>0)? bbflush(f): 0L)
303:
304: /* Format 10: the low-order (0001) bit in each byte is first ("little-endian"), and
305: bytes are reversed (in each pair) from putc(3) order;
306: */
307: #if MAIN
308: BITFILE *bopen_r_10(s)
309: FILE *s;
310: { BITFILE *f;
311: if((f=bopen_rw(s,"r"))!=NULL) {
312: f->sm=0000000;
313: };
314: return(f);
315: }
316: #else
317: BITFILE *bopen_r_10();
318: #endif
319: #if MAIN
320: BITFILE *bopen_w_10(s)
321: FILE *s;
322: { BITFILE *f;
323: if((f=bopen_rw(s,"w"))!=NULL) {
324: f->i.ss.s0.s=0000000;
325: f->sm=0000001;
326: };
327: return(f);
328: }
329: #else
330: BITFILE *bopen_w_10();
331: #endif
332: #define getb_10(f) ( ((f)->sm)? \
333: ( ((f)->sm&(f)->i.ss.s0.s)? \
334: ((f)->sm<<=1,1): \
335: ((f)->sm<<=1,0) ): \
336: ( (((f)->ic=getc((f)->fp))==EOF)? \
337: EOF: \
338: ( (f)->nb++, \
339: (f)->i.ss.s0.cc.c1=(f)->ic&0377, \
340: ( (((f)->ic=getc((f)->fp))==EOF)? \
341: EOF: \
342: ( (f)->nb++, \
343: (f)->i.ss.s0.cc.c0=(f)->ic&0377, \
344: (f)->sm=0000001, \
345: ((f)->sm&(f)->i.ss.s0.s)? \
346: ((f)->sm<<=1,1): \
347: ((f)->sm<<=1,0) ) ) ) ) )
348: #define putb_10(b,f) { \
349: if((b)) (f)->i.ss.s0.s |= (f)->sm; \
350: if( !((f)->sm<<=1) ) { \
351: bputc((f)->i.ss.s0.cc.c1,f); \
352: (f)->nb++; \
353: bputc((f)->i.ss.s0.cc.c0,f); \
354: (f)->nb++; \
355: (f)->i.ss.s0.s=0000000; (f)->sm=0000001; \
356: }; \
357: (f)->n++; \
358: }
359: #define bflush_10(f) (padb((f),0,16,0), (bsize(f)>0)? bbflush(f): 0L)
360:
361: /* Format 11: the high-order (0200) bit in each byte is first ("little-endian"),
362: and bytes are reversed (in each pair) from putc(3) order.
363: */
364: #if MAIN
365: BITFILE *bopen_r_11(s)
366: FILE *s;
367: { BITFILE *f;
368: if((f=bopen_rw(s,"r"))!=NULL) {
369: f->sm=0000000;
370: };
371: return(f);
372: }
373: #else
374: BITFILE *bopen_r_11();
375: #endif
376: #if MAIN
377: BITFILE *bopen_w_11(s)
378: FILE *s;
379: { BITFILE *f;
380: if((f=bopen_rw(s,"w"))!=NULL) {
381: f->i.ss.s0.s=0000000;
382: f->sm=0100000;
383: };
384: return(f);
385: }
386: #else
387: BITFILE *bopen_w_11();
388: #endif
389: #define getb_11(f) ( ((f)->sm)? \
390: ( ((f)->sm&(f)->i.ss.s0.s)? \
391: ((f)->sm>>=1,1): \
392: ((f)->sm>>=1,0) ): \
393: ( (((f)->ic=getc((f)->fp))==EOF)? \
394: EOF: \
395: ( (f)->nb++, \
396: (f)->i.ss.s0.cc.c0=(f)->ic&0377, \
397: ( (((f)->ic=getc((f)->fp))==EOF)? \
398: EOF: \
399: ( (f)->nb++, \
400: (f)->i.ss.s0.cc.c1=(f)->ic&0377, \
401: (f)->sm=0100000, \
402: ((f)->sm&(f)->i.ss.s0.s)? \
403: ((f)->sm>>=1,1): \
404: ((f)->sm>>=1,0) ) ) ) ) )
405: #define putb_11(b,f) { \
406: if((b)) (f)->i.ss.s0.s |= (f)->sm; \
407: if( !((f)->sm>>=1) ) { \
408: bputc((f)->i.ss.s0.cc.c0,f); \
409: (f)->nb++; \
410: bputc((f)->i.ss.s0.cc.c1,f); \
411: (f)->nb++; \
412: (f)->i.ss.s0.s=0000000; (f)->sm=0100000; \
413: }; \
414: (f)->n++; \
415: }
416: #define bflush_11(f) (padb((f),0,16,0), (bsize(f)>0)? bbflush(f): 0L)
417:
418: /**************************************************************/
419: /* FORMAT: may be selected here (input and output may differ) */
420:
421: /* Input: */
422: #define bopen_r(s) bopen_r_0((s))
423: #define getb(f) getb_0(f)
424: /* Output: */
425: #define bopen_w(s) bopen_w_0((s))
426: #define putb(b,f) putb_0((b),(f))
427: #define bflush(f) bflush_0(f)
428:
429: /**************************************************************/
430:
431: /* Code common to all formats: */
432: #if MAIN
433: BITFILE *bopen(s,t)
434: FILE *s;
435: char *t;
436: { BITFILE *res;
437: if(*(t)=='r') res=bopen_r(s);
438: else if(*(t)=='w') {
439: res=bopen_w(s);
440: #if BUFFERED
441: if(*(t+1)=='b') {
442: res->alloc = BITFILE_incr;
443: if((res->buf=(char *)malloc(res->alloc))==NULL)
444: abort("bopen: can't alloc buffer");
445: res->cp = res->buf;
446: };
447: #endif
448: }
449: else abort("bopen: bad type: \"%s\"",t);
450: return(res);
451: }
452: #else
453: BITFILE *bopen();
454: #endif
455:
456: #if MAIN
457: padb(f,b,B,l)
458: BITFILE *f;
459: char b;
460: int l,B;
461: { while(((f)->n+(l))%(B)) putb((b),(f));
462: }
463: #endif
464:
465: #if MAIN
466: unsigned long bclose(f)
467: BITFILE *f;
468: { unsigned long nb,nbuf;
469: if(f->type=='w') {
470: nbuf=bflush(f);
471: fflush(f->fp);
472: #if BUFFERED
473: if(f->buf!=NULL) { free(f->buf); f->buf=NULL; }
474: #endif
475: };
476: nb=f->nb;
477: free(f);
478: return(nb);
479: }
480: #else
481: unsigned long bclose();
482: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.