Mercurial > hg > toybox
comparison lib/bunzip.c @ 64:67ee3a0b76e1
In bunzip replace setjmp/longjmp handling with error_exit(), replace string
based handling of a 6-byte header with with two 24-bit integer reads. Use
xmalloc() and xzalloc().
author | Rob Landley <rob@landley.net> |
---|---|
date | Thu, 18 Jan 2007 22:00:12 -0500 |
parents | f41f997c1e73 |
children | b6646155e924 |
comparison
equal
deleted
inserted
replaced
63:69efffcacd70 | 64:67ee3a0b76e1 |
---|---|
25 | 25 |
26 // Status return values | 26 // Status return values |
27 #define RETVAL_OK 0 | 27 #define RETVAL_OK 0 |
28 #define RETVAL_LAST_BLOCK (-1) | 28 #define RETVAL_LAST_BLOCK (-1) |
29 #define RETVAL_NOT_BZIP_DATA (-2) | 29 #define RETVAL_NOT_BZIP_DATA (-2) |
30 #define RETVAL_UNEXPECTED_INPUT_EOF (-3) | 30 #define RETVAL_DATA_ERROR (-3) |
31 #define RETVAL_UNEXPECTED_OUTPUT_EOF (-4) | 31 #define RETVAL_OBSOLETE_INPUT (-4) |
32 #define RETVAL_DATA_ERROR (-5) | |
33 #define RETVAL_OUT_OF_MEMORY (-6) | |
34 #define RETVAL_OBSOLETE_INPUT (-7) | |
35 | 32 |
36 char *bunzip_errors[]={ | 33 char *bunzip_errors[]={ |
37 NULL, | 34 NULL, |
38 "Bad file checksum", | |
39 "Not bzip data", | 35 "Not bzip data", |
40 "Unexpected input EOF", | |
41 "Unexpected output EOF", | |
42 "Data error", | 36 "Data error", |
43 "Out of memory", | 37 "Out of memory", |
44 "Obsolete (pre 0.9.5) bzip format not supported." | 38 "Obsolete (pre 0.9.5) bzip format not supported." |
45 }; | 39 }; |
46 | 40 |
52 | 46 |
53 // Structure holding all the housekeeping data, including IO buffers and | 47 // Structure holding all the housekeeping data, including IO buffers and |
54 // memory that persists between calls to bunzip | 48 // memory that persists between calls to bunzip |
55 typedef struct { | 49 typedef struct { |
56 | 50 |
57 // For I/O error handling | |
58 jmp_buf jmpbuf; | |
59 | |
60 // Input stream, input buffer, input bit buffer | 51 // Input stream, input buffer, input bit buffer |
61 int in_fd, inbufCount, inbufPos; | 52 int in_fd, inbufCount, inbufPos; |
62 char *inbuf; | 53 char *inbuf; |
63 unsigned int inbufBitCount, inbufBits; | 54 unsigned int inbufBitCount, inbufBits; |
64 | 55 |
91 while (bd->inbufBitCount < bits_wanted) { | 82 while (bd->inbufBitCount < bits_wanted) { |
92 | 83 |
93 // If we need to read more data from file into byte buffer, do so | 84 // If we need to read more data from file into byte buffer, do so |
94 if (bd->inbufPos == bd->inbufCount) { | 85 if (bd->inbufPos == bd->inbufCount) { |
95 if (0 >= (bd->inbufCount = read(bd->in_fd, bd->inbuf, IOBUF_SIZE))) | 86 if (0 >= (bd->inbufCount = read(bd->in_fd, bd->inbuf, IOBUF_SIZE))) |
96 longjmp(bd->jmpbuf, RETVAL_UNEXPECTED_INPUT_EOF); | 87 error_exit("Unexpected input EOF"); |
97 bd->inbufPos = 0; | 88 bd->inbufPos = 0; |
98 } | 89 } |
99 | 90 |
100 // Avoid 32-bit overflow (dump bit buffer to top of output) | 91 // Avoid 32-bit overflow (dump bit buffer to top of output) |
101 if (bd->inbufBitCount>=24) { | 92 if (bd->inbufBitCount>=24) { |
126 selector, i, j, k, t, runPos, symCount, symTotal, nSelectors, | 117 selector, i, j, k, t, runPos, symCount, symTotal, nSelectors, |
127 byteCount[256]; | 118 byteCount[256]; |
128 char uc, mtfSymbol[256], symToByte[256], *selectors; | 119 char uc, mtfSymbol[256], symToByte[256], *selectors; |
129 unsigned int *dbuf; | 120 unsigned int *dbuf; |
130 | 121 |
131 // Read in header signature (borrowing mtfSymbol for temp space). | 122 // Read in header signature and CRC (which is stored big endian) |
132 for (i=0; i<6; i++) mtfSymbol[i] = get_bits(bd,8); | 123 i = get_bits(bd, 24); |
133 mtfSymbol[6] = 0; | 124 j = get_bits(bd, 24); |
134 | |
135 // Read CRC (which is stored big endian). | |
136 bd->headerCRC = get_bits(bd,32); | 125 bd->headerCRC = get_bits(bd,32); |
137 | 126 |
138 // Is this the last block (with CRC for file)? | 127 // Is this the EOF block with CRC for whole file? |
139 if (!strcmp(mtfSymbol, "\x17\x72\x45\x38\x50\x90")) | 128 if (i==0x177245 && j==0x385090) return RETVAL_LAST_BLOCK; |
140 return RETVAL_LAST_BLOCK; | 129 |
141 | 130 // Is this a valid data block? |
142 // If it's not a valid data block, barf. | 131 if (i!=0x314159 || j!=0x265359) return RETVAL_NOT_BZIP_DATA; |
143 if (strcmp(mtfSymbol, "\x31\x41\x59\x26\x53\x59")) | |
144 return RETVAL_NOT_BZIP_DATA; | |
145 | 132 |
146 dbuf = bd->dbuf; | 133 dbuf = bd->dbuf; |
147 dbufSize = bd->dbufSize; | 134 dbufSize = bd->dbufSize; |
148 selectors = bd->selectors; | 135 selectors = bd->selectors; |
149 | 136 |
412 // Flush output buffer to disk | 399 // Flush output buffer to disk |
413 void flush_bunzip_outbuf(bunzip_data *bd, int out_fd) | 400 void flush_bunzip_outbuf(bunzip_data *bd, int out_fd) |
414 { | 401 { |
415 if (bd->outbufPos) { | 402 if (bd->outbufPos) { |
416 if (write(out_fd, bd->outbuf, bd->outbufPos) != bd->outbufPos) | 403 if (write(out_fd, bd->outbuf, bd->outbufPos) != bd->outbufPos) |
417 longjmp(bd->jmpbuf,RETVAL_UNEXPECTED_OUTPUT_EOF); | 404 error_exit("Unexpected output EOF"); |
418 bd->outbufPos = 0; | 405 bd->outbufPos = 0; |
419 } | 406 } |
420 } | 407 } |
421 | 408 |
422 // Undo burrows-wheeler transform on intermediate buffer to produce output. | 409 // Undo burrows-wheeler transform on intermediate buffer to produce output. |
524 // Figure out how much data to allocate. | 511 // Figure out how much data to allocate. |
525 i = sizeof(bunzip_data); | 512 i = sizeof(bunzip_data); |
526 if (!len) i += IOBUF_SIZE; | 513 if (!len) i += IOBUF_SIZE; |
527 | 514 |
528 // Allocate bunzip_data. Most fields initialize to zero. | 515 // Allocate bunzip_data. Most fields initialize to zero. |
529 if (!(bd = *bdp = malloc(i))) return RETVAL_OUT_OF_MEMORY; | 516 bd = *bdp = xzalloc(i); |
530 memset(bd,0,sizeof(bunzip_data)); | |
531 if (len) { | 517 if (len) { |
532 bd->inbuf = inbuf; | 518 bd->inbuf = inbuf; |
533 bd->inbufCount = len; | 519 bd->inbufCount = len; |
534 bd->in_fd = -1; | 520 bd->in_fd = -1; |
535 } else { | 521 } else { |
543 for (j=8; j; j--) | 529 for (j=8; j; j--) |
544 c=c&0x80000000 ? (c<<1)^0x04c11db7 : (c<<1); | 530 c=c&0x80000000 ? (c<<1)^0x04c11db7 : (c<<1); |
545 bd->crc32Table[i] = c; | 531 bd->crc32Table[i] = c; |
546 } | 532 } |
547 | 533 |
548 // Setup for I/O error handling via longjmp. | |
549 i = setjmp(bd->jmpbuf); | |
550 if (i) return i; | |
551 | |
552 // Ensure that file starts with "BZh". | 534 // Ensure that file starts with "BZh". |
553 for (i=0;i<3;i++) | 535 for (i=0;i<3;i++) |
554 if (get_bits(bd,8)!="BZh"[i]) return RETVAL_NOT_BZIP_DATA; | 536 if (get_bits(bd,8)!="BZh"[i]) return RETVAL_NOT_BZIP_DATA; |
555 | 537 |
556 // Next byte ascii '1'-'9', indicates block size in units of 100k of | 538 // Next byte ascii '1'-'9', indicates block size in units of 100k of |
557 // uncompressed data. Allocate intermediate buffer for block. | 539 // uncompressed data. Allocate intermediate buffer for block. |
558 i = get_bits(bd, 8); | 540 i = get_bits(bd, 8); |
559 if (i<'1' || i>'9') return RETVAL_NOT_BZIP_DATA; | 541 if (i<'1' || i>'9') return RETVAL_NOT_BZIP_DATA; |
560 bd->dbufSize = 100000*(i-'0'); | 542 bd->dbufSize = 100000*(i-'0'); |
561 if (!(bd->dbuf = malloc(bd->dbufSize * sizeof(int)))) | 543 bd->dbuf = xmalloc(bd->dbufSize * sizeof(int)); |
562 return RETVAL_OUT_OF_MEMORY; | |
563 | 544 |
564 return RETVAL_OK; | 545 return RETVAL_OK; |
565 } | 546 } |
566 | 547 |
567 // Example usage: decompress src_fd to dst_fd. (Stops at end of bzip data, | 548 // Example usage: decompress src_fd to dst_fd. (Stops at end of bzip data, |
568 // not end of file.) | 549 // not end of file.) |
569 char *bunzipStream(int src_fd, int dst_fd) | 550 void bunzipStream(int src_fd, int dst_fd) |
570 { | 551 { |
571 bunzip_data *bd; | 552 bunzip_data *bd; |
572 int i; | 553 int i; |
573 | 554 |
574 if (!(i = start_bunzip(&bd,src_fd,0,0))) { | 555 if (!(i = start_bunzip(&bd,src_fd,0,0))) { |
576 if (i==RETVAL_LAST_BLOCK && bd->headerCRC==bd->totalCRC) i = RETVAL_OK; | 557 if (i==RETVAL_LAST_BLOCK && bd->headerCRC==bd->totalCRC) i = RETVAL_OK; |
577 } | 558 } |
578 flush_bunzip_outbuf(bd,dst_fd); | 559 flush_bunzip_outbuf(bd,dst_fd); |
579 free(bd->dbuf); | 560 free(bd->dbuf); |
580 free(bd); | 561 free(bd); |
581 return bunzip_errors[-i]; | 562 if (i) error_exit(bunzip_errors[-i]); |
582 } | 563 } |