diff options
author | Eric Andersen <andersen@codepoet.org> | 2003-10-18 01:59:46 +0000 |
---|---|---|
committer | Eric Andersen <andersen@codepoet.org> | 2003-10-18 01:59:46 +0000 |
commit | 1acfb72e71a4af7e03da772cd721144b2899c96f (patch) | |
tree | 05f0f27bf3834cf1f9401e604bfa99ed3c7d0c6a | |
parent | 0d6d88a2058d191c34d25a8709aca40311bb0c2e (diff) | |
download | busybox-w32-1acfb72e71a4af7e03da772cd721144b2899c96f.tar.gz busybox-w32-1acfb72e71a4af7e03da772cd721144b2899c96f.tar.bz2 busybox-w32-1acfb72e71a4af7e03da772cd721144b2899c96f.zip |
Manuel Novoa III writes:
Hello Rob,
Here's a patch to your bunzip-3.c file. Nice work btw.
One minor bug fix... checking for error return when read()ing.
Some size/performance optimizations as well. One instance of
memset() seems unnecssary. You might want to take a look.
Anyway, on my machine, decompressing linux-2.6.0-test7.tar.bz2
to /dev/null gave the following times:
bunzip-3.c bzcat (system) bunzip-3.c (patched)
real 0m24.420s 0m22.725s 0m20.701s
user 0m23.930s 0m22.170s 0m20.180s
sys 0m0.070s 0m0.080s 0m0.140s
Size of the patched version is comparable (slightly larger or
smaller depending on compiler flags).
Manuel
-rw-r--r-- | archival/libunarchive/decompress_bunzip2.c | 65 |
1 files changed, 43 insertions, 22 deletions
diff --git a/archival/libunarchive/decompress_bunzip2.c b/archival/libunarchive/decompress_bunzip2.c index 474186a2a..b4bcb0b49 100644 --- a/archival/libunarchive/decompress_bunzip2.c +++ b/archival/libunarchive/decompress_bunzip2.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <stdlib.h> | 15 | #include <stdlib.h> |
16 | #include <string.h> | 16 | #include <string.h> |
17 | #include <unistd.h> | 17 | #include <unistd.h> |
18 | #include <limits.h> | ||
18 | 19 | ||
19 | /* Constants for huffman coding */ | 20 | /* Constants for huffman coding */ |
20 | #define MAX_GROUPS 6 | 21 | #define MAX_GROUPS 6 |
@@ -37,13 +38,14 @@ | |||
37 | /* Other housekeeping constants */ | 38 | /* Other housekeeping constants */ |
38 | #define IOBUF_SIZE 4096 | 39 | #define IOBUF_SIZE 4096 |
39 | 40 | ||
40 | char *bunzip_errors[]={NULL,"Bad file checksum","Not bzip data", | 41 | static char * const bunzip_errors[]={NULL,"Bad file checksum","Not bzip data", |
41 | "Unexpected input EOF","Unexpected output EOF","Data error", | 42 | "Unexpected input EOF","Unexpected output EOF","Data error", |
42 | "Out of memory","Obsolete (pre 0.9.5) bzip format not supported."}; | 43 | "Out of memory","Obsolete (pre 0.9.5) bzip format not supported."}; |
43 | 44 | ||
44 | /* This is what we know about each huffman coding group */ | 45 | /* This is what we know about each huffman coding group */ |
45 | struct group_data { | 46 | struct group_data { |
46 | int limit[MAX_HUFCODE_BITS],base[MAX_HUFCODE_BITS],permute[MAX_SYMBOLS]; | 47 | /* We have an extra slot at the end of limit[] for a sentinal value. */ |
48 | int limit[MAX_HUFCODE_BITS+1],base[MAX_HUFCODE_BITS],permute[MAX_SYMBOLS]; | ||
47 | char minLen, maxLen; | 49 | char minLen, maxLen; |
48 | }; | 50 | }; |
49 | 51 | ||
@@ -82,7 +84,7 @@ static unsigned int get_bits(bunzip_data *bd, char bits_wanted) | |||
82 | while (bd->inbufBitCount<bits_wanted) { | 84 | while (bd->inbufBitCount<bits_wanted) { |
83 | /* If we need to read more data from file into byte buffer, do so */ | 85 | /* If we need to read more data from file into byte buffer, do so */ |
84 | if(bd->inbufPos==bd->inbufCount) { | 86 | if(bd->inbufPos==bd->inbufCount) { |
85 | if(!(bd->inbufCount = read(bd->in_fd, bd->inbuf, IOBUF_SIZE))) | 87 | if((bd->inbufCount = read(bd->in_fd, bd->inbuf, IOBUF_SIZE)) <= 0) |
86 | longjmp(bd->jmpbuf,RETVAL_UNEXPECTED_INPUT_EOF); | 88 | longjmp(bd->jmpbuf,RETVAL_UNEXPECTED_INPUT_EOF); |
87 | bd->inbufPos=0; | 89 | bd->inbufPos=0; |
88 | } | 90 | } |
@@ -104,6 +106,14 @@ static unsigned int get_bits(bunzip_data *bd, char bits_wanted) | |||
104 | return bits; | 106 | return bits; |
105 | } | 107 | } |
106 | 108 | ||
109 | /* At certain times, it pays to have an optimized inline version of | ||
110 | * get_bits() which gets a single bit. */ | ||
111 | #define GET_A_BIT(bd) \ | ||
112 | ((bd->inbufBitCount > 0) \ | ||
113 | ? ((unsigned int)(((bd)->inbufBits >> --(bd)->inbufBitCount) & 1)) \ | ||
114 | : get_bits((bd), 1)) | ||
115 | |||
116 | |||
107 | /* Decompress a block of text to into intermediate buffer */ | 117 | /* Decompress a block of text to into intermediate buffer */ |
108 | 118 | ||
109 | extern int read_bunzip_data(bunzip_data *bd) | 119 | extern int read_bunzip_data(bunzip_data *bd) |
@@ -140,7 +150,10 @@ extern int read_bunzip_data(bunzip_data *bd) | |||
140 | values were present. We make a translation table to convert the symbols | 150 | values were present. We make a translation table to convert the symbols |
141 | back to the corresponding bytes. */ | 151 | back to the corresponding bytes. */ |
142 | t=get_bits(bd, 16); | 152 | t=get_bits(bd, 16); |
153 | #if 0 | ||
154 | /* I don't believe this is necessary. Rob? */ | ||
143 | memset(symToByte,0,256); | 155 | memset(symToByte,0,256); |
156 | #endif | ||
144 | symTotal=0; | 157 | symTotal=0; |
145 | for (i=0;i<16;i++) { | 158 | for (i=0;i<16;i++) { |
146 | if(t&(1<<(15-i))) { | 159 | if(t&(1<<(15-i))) { |
@@ -162,7 +175,13 @@ extern int read_bunzip_data(bunzip_data *bd) | |||
162 | for(j=0;get_bits(bd,1);j++) if (j>=groupCount) return RETVAL_DATA_ERROR; | 175 | for(j=0;get_bits(bd,1);j++) if (j>=groupCount) return RETVAL_DATA_ERROR; |
163 | /* Decode MTF to get the next selector */ | 176 | /* Decode MTF to get the next selector */ |
164 | uc = mtfSymbol[j]; | 177 | uc = mtfSymbol[j]; |
165 | memmove(mtfSymbol+1,mtfSymbol,j); | 178 | /* A very small amount of data to move, so memmove is overkill |
179 | * and bigger at least in my tests. */ | ||
180 | k = j; | ||
181 | while (k) { | ||
182 | mtfSymbol[k] = mtfSymbol[k-1]; | ||
183 | --k; | ||
184 | } | ||
166 | mtfSymbol[0]=selectors[i]=uc; | 185 | mtfSymbol[0]=selectors[i]=uc; |
167 | } | 186 | } |
168 | /* Read the huffman coding tables for each group, which code for symTotal | 187 | /* Read the huffman coding tables for each group, which code for symTotal |
@@ -172,15 +191,15 @@ extern int read_bunzip_data(bunzip_data *bd) | |||
172 | unsigned char length[MAX_SYMBOLS],temp[MAX_HUFCODE_BITS+1]; | 191 | unsigned char length[MAX_SYMBOLS],temp[MAX_HUFCODE_BITS+1]; |
173 | int minLen, maxLen, pp; | 192 | int minLen, maxLen, pp; |
174 | /* Read lengths */ | 193 | /* Read lengths */ |
175 | t=get_bits(bd, 5); | 194 | t=get_bits(bd, 5) - 1; /* This lets us avoid a test in the loop. */ |
176 | for (i = 0; i < symCount; i++) { | 195 | for (i = 0; i < symCount; i++) { |
177 | for(;;) { | 196 | for(;;) { |
178 | if (t < 1 || t > MAX_HUFCODE_BITS) return RETVAL_DATA_ERROR; | 197 | if (((unsigned)t) > (MAX_HUFCODE_BITS-1)) return RETVAL_DATA_ERROR; |
179 | if(!get_bits(bd, 1)) break; | 198 | if(!get_bits(bd, 1)) break; |
180 | if(!get_bits(bd, 1)) t++; | 199 | /* We can avoid an if/else with a little arithmetic. */ |
181 | else t--; | 200 | t += (1 - 2*get_bits(bd, 1)); /* 0 -> t++ ; 1 -> t-- */ |
182 | } | 201 | } |
183 | length[i] = t; | 202 | length[i] = t + 1; /* Correct for the initial -1 adjustment. */ |
184 | } | 203 | } |
185 | /* Find largest and smallest lengths in this group */ | 204 | /* Find largest and smallest lengths in this group */ |
186 | minLen=maxLen=length[0]; | 205 | minLen=maxLen=length[0]; |
@@ -228,6 +247,7 @@ extern int read_bunzip_data(bunzip_data *bd) | |||
228 | pp<<=1; | 247 | pp<<=1; |
229 | base[i+1]=pp-(t+=temp[i]); | 248 | base[i+1]=pp-(t+=temp[i]); |
230 | } | 249 | } |
250 | limit[maxLen+1] = INT_MAX; /* Sentinal value for reading next sym. */ | ||
231 | limit[maxLen]=pp+temp[maxLen]-1; | 251 | limit[maxLen]=pp+temp[maxLen]-1; |
232 | base[minLen]=0; | 252 | base[minLen]=0; |
233 | } | 253 | } |
@@ -252,19 +272,15 @@ extern int read_bunzip_data(bunzip_data *bd) | |||
252 | /* Read next huffman-coded symbol */ | 272 | /* Read next huffman-coded symbol */ |
253 | i = hufGroup->minLen; | 273 | i = hufGroup->minLen; |
254 | j=get_bits(bd, i); | 274 | j=get_bits(bd, i); |
255 | for(;;) { | 275 | while (j > limit[i]) { /* The sentinal allows us to avoid testing i. */ |
256 | if (i > hufGroup->maxLen) return RETVAL_DATA_ERROR; | 276 | j = (j << 1) | GET_A_BIT(bd); |
257 | if (j <= limit[i]) break; | 277 | ++i; |
258 | i++; | ||
259 | |||
260 | j = (j << 1) | get_bits(bd,1); | ||
261 | } | 278 | } |
262 | /* Huffman decode nextSym (with bounds checking) */ | 279 | /* Huffman decode nextSym (with bounds checking) */ |
263 | j-=base[i]; | 280 | if ((i > hufGroup->maxLen) || (((unsigned)(j-=base[i])) >= MAX_SYMBOLS)) return RETVAL_DATA_ERROR; |
264 | if (j < 0 || j >= MAX_SYMBOLS) return RETVAL_DATA_ERROR; | ||
265 | nextSym = hufGroup->permute[j]; | 281 | nextSym = hufGroup->permute[j]; |
266 | /* If this is a repeated run, loop collecting data */ | 282 | /* If this is a repeated run, loop collecting data */ |
267 | if (nextSym == SYMBOL_RUNA || nextSym == SYMBOL_RUNB) { | 283 | if (((unsigned)nextSym) <= SYMBOL_RUNB) { /* RUNA or RUNB */ |
268 | /* If this is the start of a new run, zero out counter */ | 284 | /* If this is the start of a new run, zero out counter */ |
269 | if(!runPos) { | 285 | if(!runPos) { |
270 | runPos = 1; | 286 | runPos = 1; |
@@ -277,8 +293,7 @@ extern int read_bunzip_data(bunzip_data *bd) | |||
277 | the basic or 0/1 method (except all bits 0, which would use no | 293 | the basic or 0/1 method (except all bits 0, which would use no |
278 | symbols, but a run of length 0 doesn't mean anything in this | 294 | symbols, but a run of length 0 doesn't mean anything in this |
279 | context). Thus space is saved. */ | 295 | context). Thus space is saved. */ |
280 | if (nextSym == SYMBOL_RUNA) t += runPos; | 296 | t += (runPos << nextSym); /* +runPos if RUNA; +2*runPos if RUNB */ |
281 | else t += 2*runPos; | ||
282 | runPos <<= 1; | 297 | runPos <<= 1; |
283 | continue; | 298 | continue; |
284 | } | 299 | } |
@@ -305,7 +320,13 @@ extern int read_bunzip_data(bunzip_data *bd) | |||
305 | if(dbufCount>=dbufSize) return RETVAL_DATA_ERROR; | 320 | if(dbufCount>=dbufSize) return RETVAL_DATA_ERROR; |
306 | i = nextSym - 1; | 321 | i = nextSym - 1; |
307 | uc = mtfSymbol[i]; | 322 | uc = mtfSymbol[i]; |
308 | memmove(mtfSymbol+1,mtfSymbol,i); | 323 | /* Since we typically expect to move only a small number of symbols, |
324 | * and are bound by 256 in any case, using memmove here would | ||
325 | * typically be slower due to function call overhead and other | ||
326 | * assorted setup costs. */ | ||
327 | do { | ||
328 | mtfSymbol[i] = mtfSymbol[i-1]; | ||
329 | } while (--i); | ||
309 | mtfSymbol[0] = uc; | 330 | mtfSymbol[0] = uc; |
310 | uc=symToByte[uc]; | 331 | uc=symToByte[uc]; |
311 | /* We have our literal byte. Save it into dbuf. */ | 332 | /* We have our literal byte. Save it into dbuf. */ |
@@ -319,7 +340,7 @@ extern int read_bunzip_data(bunzip_data *bd) | |||
319 | */ | 340 | */ |
320 | 341 | ||
321 | /* Now we know what dbufCount is, do a better sanity check on origPtr. */ | 342 | /* Now we know what dbufCount is, do a better sanity check on origPtr. */ |
322 | if (origPtr<0 || origPtr>=dbufCount) return RETVAL_DATA_ERROR; | 343 | if (((unsigned)origPtr)>=dbufCount) return RETVAL_DATA_ERROR; |
323 | /* Turn byteCount into cumulative occurrence counts of 0 to n-1. */ | 344 | /* Turn byteCount into cumulative occurrence counts of 0 to n-1. */ |
324 | j=0; | 345 | j=0; |
325 | for(i=0;i<256;i++) { | 346 | for(i=0;i<256;i++) { |