Print this page
10144 BZ2_bzDecompressReset() gets NULL check wrong
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/common/bzip2/bzlib.c
+++ new/usr/src/common/bzip2/bzlib.c
1 1
2 2 /*-------------------------------------------------------------*/
3 3 /*--- Library top-level functions. ---*/
4 4 /*--- bzlib.c ---*/
5 5 /*-------------------------------------------------------------*/
6 6
7 7 /* ------------------------------------------------------------------
8 8 This file is part of bzip2/libbzip2, a program and library for
9 9 lossless, block-sorting data compression.
10 10
11 11 bzip2/libbzip2 version 1.0.6 of 6 September 2010
12 12 Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org>
13 13
14 14 Please read the WARNING, DISCLAIMER and PATENTS sections in the
15 15 README file.
16 16
17 17 This program is released under the terms of the license contained
18 18 in the file LICENSE.
19 19 ------------------------------------------------------------------ */
20 20
21 21 /* CHANGES
22 22 0.9.0 -- original version.
23 23 0.9.0a/b -- no changes in this file.
24 24 0.9.0c -- made zero-length BZ_FLUSH work correctly in bzCompress().
25 25 fixed bzWrite/bzRead to ignore zero-length requests.
26 26 fixed bzread to correctly handle read requests after EOF.
27 27 wrong parameter order in call to bzDecompressInit in
28 28 bzBuffToBuffDecompress. Fixed.
29 29 */
30 30
31 31 #include "bzlib_private.h"
32 32
33 33 #ifndef BZ_NO_COMPRESS
34 34
35 35 /*---------------------------------------------------*/
36 36 /*--- Compression stuff ---*/
37 37 /*---------------------------------------------------*/
38 38
39 39
40 40 /*---------------------------------------------------*/
41 41 #ifndef BZ_NO_STDIO
42 42 void BZ2_bz__AssertH__fail ( int errcode )
43 43 {
44 44 fprintf(stderr,
45 45 "\n\nbzip2/libbzip2: internal error number %d.\n"
46 46 "This is a bug in bzip2/libbzip2, %s.\n"
47 47 "Please report it to me at: jseward@bzip.org. If this happened\n"
48 48 "when you were using some program which uses libbzip2 as a\n"
49 49 "component, you should also report this bug to the author(s)\n"
50 50 "of that program. Please make an effort to report this bug;\n"
51 51 "timely and accurate bug reports eventually lead to higher\n"
52 52 "quality software. Thanks. Julian Seward, 10 December 2007.\n\n",
53 53 errcode,
54 54 BZ2_bzlibVersion()
55 55 );
56 56
57 57 if (errcode == 1007) {
58 58 fprintf(stderr,
59 59 "\n*** A special note about internal error number 1007 ***\n"
60 60 "\n"
61 61 "Experience suggests that a common cause of i.e. 1007\n"
62 62 "is unreliable memory or other hardware. The 1007 assertion\n"
63 63 "just happens to cross-check the results of huge numbers of\n"
64 64 "memory reads/writes, and so acts (unintendedly) as a stress\n"
65 65 "test of your memory system.\n"
66 66 "\n"
67 67 "I suggest the following: try compressing the file again,\n"
68 68 "possibly monitoring progress in detail with the -vv flag.\n"
69 69 "\n"
70 70 "* If the error cannot be reproduced, and/or happens at different\n"
71 71 " points in compression, you may have a flaky memory system.\n"
72 72 " Try a memory-test program. I have used Memtest86\n"
73 73 " (www.memtest86.com). At the time of writing it is free (GPLd).\n"
74 74 " Memtest86 tests memory much more thorougly than your BIOSs\n"
75 75 " power-on test, and may find failures that the BIOS doesn't.\n"
76 76 "\n"
77 77 "* If the error can be repeatably reproduced, this is a bug in\n"
78 78 " bzip2, and I would very much like to hear about it. Please\n"
79 79 " let me know, and, ideally, save a copy of the file causing the\n"
80 80 " problem -- without which I will be unable to investigate it.\n"
81 81 "\n"
82 82 );
83 83 }
84 84
85 85 exit(3);
86 86 }
87 87 #endif
88 88
89 89 #endif /* BZ_NO_COMPRESS */
90 90
91 91 /*---------------------------------------------------*/
92 92 static
93 93 int bz_config_ok ( void )
94 94 {
95 95 if (sizeof(int) != 4) return 0;
96 96 if (sizeof(short) != 2) return 0;
97 97 if (sizeof(char) != 1) return 0;
98 98 return 1;
99 99 }
100 100
101 101 /*
102 102 * Added for Solaris kernel
103 103 */
104 104 #define BZES \
105 105 BZE(BZ_OK) \
106 106 BZE(BZ_RUN_OK) \
107 107 BZE(BZ_FLUSH_OK) \
108 108 BZE(BZ_FINISH_OK) \
109 109 BZE(BZ_STREAM_END) \
110 110 BZE(BZ_SEQUENCE_ERROR) \
111 111 BZE(BZ_PARAM_ERROR) \
112 112 BZE(BZ_MEM_ERROR) \
113 113 BZE(BZ_DATA_ERROR) \
114 114 BZE(BZ_DATA_ERROR_MAGIC) \
115 115 BZE(BZ_IO_ERROR) \
116 116 BZE(BZ_UNEXPECTED_EOF) \
117 117 BZE(BZ_OUTBUFF_FULL) \
118 118 BZE(BZ_CONFIG_ERROR)
119 119
120 120 BZ_EXTERN const char * BZ_API(BZ2_bzErrorString) (
121 121 int error_code
122 122 )
123 123 {
124 124 switch (error_code)
125 125 {
126 126 #define BZE(x) case x: return (#x);
127 127 BZES
128 128 #undef BZE
129 129 }
130 130 return ("BZ_UNKNOWN_ERROR");
131 131 }
132 132
133 133 #ifndef BZ_LOADER
134 134 #include <sys/sysmacros.h>
135 135 #endif
136 136
137 137 #ifdef _KERNEL
138 138
139 139 #include <sys/types.h>
140 140 #include <sys/cmn_err.h>
141 141 #include <sys/kmem.h>
142 142
143 143 void
144 144 bz_internal_error(int errcode)
145 145 {
146 146 panic("bzip2 internal error: %s\n", BZ2_bzErrorString(errcode));
147 147 }
148 148
149 149 /*---------------------------------------------------*/
150 150 typedef struct {
151 151 char *buf;
152 152 size_t sz;
153 153 } bzap;
154 154
155 155 static
156 156 void* default_bzalloc ( void* opaque, Int32 items, Int32 size )
157 157 {
158 158 size_t sz = sizeof (bzap) + BZ2_BZALLOC_ALIGN + (items * size);
159 159 uintptr_t p = (uintptr_t)kmem_alloc(sz, KM_SLEEP);
160 160
161 161 if (p != NULL) {
162 162 bzap *pp = (bzap *)((p + sizeof (bzap) + BZ2_BZALLOC_ALIGN - 1) &
163 163 -BZ2_BZALLOC_ALIGN);
164 164 pp[-1].buf = (void *)p;
165 165 pp[-1].sz = sz;
166 166 return (pp);
167 167 }
168 168 return (NULL);
169 169 }
170 170
171 171 static
172 172 void default_bzfree ( void* opaque, void* addr )
173 173 {
174 174 if (addr != NULL) {
175 175 bzap *pp = (bzap *)addr - 1;
176 176 kmem_free(pp->buf, pp->sz);
177 177 }
178 178 }
179 179
180 180 #else
181 181
182 182 /*---------------------------------------------------*/
183 183 static
184 184 void* default_bzalloc ( void* opaque, Int32 items, Int32 size )
185 185 {
186 186 void* v = malloc ( items * size );
187 187 return v;
188 188 }
189 189
190 190 static
191 191 void default_bzfree ( void* opaque, void* addr )
192 192 {
193 193 if (addr != NULL) free ( addr );
194 194 }
195 195 #endif /* _KERNEL */
196 196
197 197 /*---------------------------------------------------*/
198 198 #ifndef BZ_NO_COMPRESS
199 199 static
200 200 void prepare_new_block ( EState* s )
201 201 {
202 202 Int32 i;
203 203 s->nblock = 0;
204 204 s->numZ = 0;
205 205 s->state_out_pos = 0;
206 206 BZ_INITIALISE_CRC ( s->blockCRC );
207 207 for (i = 0; i < 256; i++) s->inUse[i] = False;
208 208 s->blockNo++;
209 209 }
210 210
211 211
212 212 /*---------------------------------------------------*/
213 213 static
214 214 void init_RL ( EState* s )
215 215 {
216 216 s->state_in_ch = 256;
217 217 s->state_in_len = 0;
218 218 }
219 219
220 220
221 221 static
222 222 Bool isempty_RL ( EState* s )
223 223 {
224 224 if (s->state_in_ch < 256 && s->state_in_len > 0)
225 225 return False; else
226 226 return True;
227 227 }
228 228
229 229
230 230 /*---------------------------------------------------*/
231 231 int BZ_API(BZ2_bzCompressInit)
232 232 ( bz_stream* strm,
233 233 int blockSize100k,
234 234 int verbosity,
235 235 int workFactor )
236 236 {
237 237 Int32 n;
238 238 EState* s;
239 239
240 240 if (!bz_config_ok()) return BZ_CONFIG_ERROR;
241 241
242 242 if (strm == NULL ||
243 243 blockSize100k < 1 || blockSize100k > 9 ||
244 244 workFactor < 0 || workFactor > 250)
245 245 return BZ_PARAM_ERROR;
246 246
247 247 if (workFactor == 0) workFactor = 30;
248 248 if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc;
249 249 if (strm->bzfree == NULL) strm->bzfree = default_bzfree;
250 250
251 251 s = BZALLOC( sizeof(EState) );
252 252 if (s == NULL) return BZ_MEM_ERROR;
253 253 s->strm = strm;
254 254
255 255 s->arr1 = NULL;
256 256 s->arr2 = NULL;
257 257 s->ftab = NULL;
258 258
259 259 n = 100000 * blockSize100k;
260 260 s->arr1 = BZALLOC( n * sizeof(UInt32) );
261 261 s->arr2 = BZALLOC( (n+BZ_N_OVERSHOOT) * sizeof(UInt32) );
262 262 s->ftab = BZALLOC( 65537 * sizeof(UInt32) );
263 263
264 264 if (s->arr1 == NULL || s->arr2 == NULL || s->ftab == NULL) {
265 265 if (s->arr1 != NULL) BZFREE(s->arr1);
266 266 if (s->arr2 != NULL) BZFREE(s->arr2);
267 267 if (s->ftab != NULL) BZFREE(s->ftab);
268 268 if (s != NULL) BZFREE(s);
269 269 return BZ_MEM_ERROR;
270 270 }
271 271
272 272 s->blockNo = 0;
273 273 s->state = BZ_S_INPUT;
274 274 s->mode = BZ_M_RUNNING;
275 275 s->combinedCRC = 0;
276 276 s->blockSize100k = blockSize100k;
277 277 s->nblockMAX = 100000 * blockSize100k - 19;
278 278 s->verbosity = verbosity;
279 279 s->workFactor = workFactor;
280 280
281 281 s->block = (UChar*)s->arr2;
282 282 s->mtfv = (UInt16*)s->arr1;
283 283 s->zbits = NULL;
284 284 s->ptr = (UInt32*)s->arr1;
285 285
286 286 strm->state = s;
287 287 strm->total_in_lo32 = 0;
288 288 strm->total_in_hi32 = 0;
289 289 strm->total_out_lo32 = 0;
290 290 strm->total_out_hi32 = 0;
291 291 init_RL ( s );
292 292 prepare_new_block ( s );
293 293 return BZ_OK;
294 294 }
295 295
296 296 /*---------------------------------------------------*/
297 297 /*
298 298 * returns the BZALLOC size needed for bzCompressInit
299 299 */
300 300 int BZ_API(BZ2_bzCompressInitSize) (
301 301 int blockSize100k)
302 302 {
303 303 Int32 n, t;
304 304
305 305 n = 100000 * blockSize100k;
306 306 t = 0;
307 307 t += ( sizeof(EState) );
308 308 t = P2ROUNDUP(t, BZ2_BZALLOC_ALIGN);
309 309 t += ( n * sizeof(UInt32) );
310 310 t = P2ROUNDUP(t, BZ2_BZALLOC_ALIGN);
311 311 t += ( (n+BZ_N_OVERSHOOT) * sizeof(UInt32) );
312 312 t = P2ROUNDUP(t, BZ2_BZALLOC_ALIGN);
313 313 t += ( 65537 * sizeof(UInt32) );
314 314 t = P2ROUNDUP(t, BZ2_BZALLOC_ALIGN);
315 315 return (t);
316 316 }
317 317
318 318 /*---------------------------------------------------*/
319 319 /*
320 320 * added to allow reuse of bz_stream without malloc/free
321 321 */
322 322 int BZ_API(BZ2_bzCompressReset) ( bz_stream *strm )
323 323 {
324 324 EState* s = strm->state;
325 325
326 326 if (!bz_config_ok()) return BZ_CONFIG_ERROR;
327 327
328 328 if (s == NULL) return BZ_MEM_ERROR;
329 329 s->strm = strm;
330 330
331 331 s->blockNo = 0;
332 332 s->state = BZ_S_INPUT;
333 333 s->mode = BZ_M_RUNNING;
334 334 s->combinedCRC = 0;
335 335 s->nblockMAX = 100000 * s->blockSize100k - 19;
336 336
337 337 s->block = (UChar*)s->arr2;
338 338 s->mtfv = (UInt16*)s->arr1;
339 339 s->zbits = NULL;
340 340 s->ptr = (UInt32*)s->arr1;
341 341
342 342 strm->state = s;
343 343 strm->total_in_lo32 = 0;
344 344 strm->total_in_hi32 = 0;
345 345 strm->total_out_lo32 = 0;
346 346 strm->total_out_hi32 = 0;
347 347 init_RL ( s );
348 348 prepare_new_block ( s );
349 349 return BZ_OK;
350 350 }
351 351
352 352
353 353 /*---------------------------------------------------*/
354 354 static
355 355 void add_pair_to_block ( EState* s )
356 356 {
357 357 Int32 i;
358 358 UChar ch = (UChar)(s->state_in_ch);
359 359 for (i = 0; i < s->state_in_len; i++) {
360 360 BZ_UPDATE_CRC( s->blockCRC, ch );
361 361 }
362 362 s->inUse[s->state_in_ch] = True;
363 363 switch (s->state_in_len) {
364 364 case 1:
365 365 s->block[s->nblock] = (UChar)ch; s->nblock++;
366 366 break;
367 367 case 2:
368 368 s->block[s->nblock] = (UChar)ch; s->nblock++;
369 369 s->block[s->nblock] = (UChar)ch; s->nblock++;
370 370 break;
371 371 case 3:
372 372 s->block[s->nblock] = (UChar)ch; s->nblock++;
373 373 s->block[s->nblock] = (UChar)ch; s->nblock++;
374 374 s->block[s->nblock] = (UChar)ch; s->nblock++;
375 375 break;
376 376 default:
377 377 s->inUse[s->state_in_len-4] = True;
378 378 s->block[s->nblock] = (UChar)ch; s->nblock++;
379 379 s->block[s->nblock] = (UChar)ch; s->nblock++;
380 380 s->block[s->nblock] = (UChar)ch; s->nblock++;
381 381 s->block[s->nblock] = (UChar)ch; s->nblock++;
382 382 s->block[s->nblock] = ((UChar)(s->state_in_len-4));
383 383 s->nblock++;
384 384 break;
385 385 }
386 386 }
387 387
388 388
389 389 /*---------------------------------------------------*/
390 390 static
391 391 void flush_RL ( EState* s )
392 392 {
393 393 if (s->state_in_ch < 256) add_pair_to_block ( s );
394 394 init_RL ( s );
395 395 }
396 396
397 397
398 398 /*---------------------------------------------------*/
399 399 #define ADD_CHAR_TO_BLOCK(zs,zchh0) \
400 400 { \
401 401 UInt32 zchh = (UInt32)(zchh0); \
402 402 /*-- fast track the common case --*/ \
403 403 if (zchh != zs->state_in_ch && \
404 404 zs->state_in_len == 1) { \
405 405 UChar ch = (UChar)(zs->state_in_ch); \
406 406 BZ_UPDATE_CRC( zs->blockCRC, ch ); \
407 407 zs->inUse[zs->state_in_ch] = True; \
408 408 zs->block[zs->nblock] = (UChar)ch; \
409 409 zs->nblock++; \
410 410 zs->state_in_ch = zchh; \
411 411 } \
412 412 else \
413 413 /*-- general, uncommon cases --*/ \
414 414 if (zchh != zs->state_in_ch || \
415 415 zs->state_in_len == 255) { \
416 416 if (zs->state_in_ch < 256) \
417 417 add_pair_to_block ( zs ); \
418 418 zs->state_in_ch = zchh; \
419 419 zs->state_in_len = 1; \
420 420 } else { \
421 421 zs->state_in_len++; \
422 422 } \
423 423 }
424 424
425 425
426 426 /*---------------------------------------------------*/
427 427 static
428 428 Bool copy_input_until_stop ( EState* s )
429 429 {
430 430 Bool progress_in = False;
431 431
432 432 if (s->mode == BZ_M_RUNNING) {
433 433
434 434 /*-- fast track the common case --*/
435 435 while (True) {
436 436 /*-- block full? --*/
437 437 if (s->nblock >= s->nblockMAX) break;
438 438 /*-- no input? --*/
439 439 if (s->strm->avail_in == 0) break;
440 440 progress_in = True;
441 441 ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) );
442 442 s->strm->next_in++;
443 443 s->strm->avail_in--;
444 444 s->strm->total_in_lo32++;
445 445 if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++;
446 446 }
447 447
448 448 } else {
449 449
450 450 /*-- general, uncommon case --*/
451 451 while (True) {
452 452 /*-- block full? --*/
453 453 if (s->nblock >= s->nblockMAX) break;
454 454 /*-- no input? --*/
455 455 if (s->strm->avail_in == 0) break;
456 456 /*-- flush/finish end? --*/
457 457 if (s->avail_in_expect == 0) break;
458 458 progress_in = True;
459 459 ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) );
460 460 s->strm->next_in++;
461 461 s->strm->avail_in--;
462 462 s->strm->total_in_lo32++;
463 463 if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++;
464 464 s->avail_in_expect--;
465 465 }
466 466 }
467 467 return progress_in;
468 468 }
469 469
470 470
471 471 /*---------------------------------------------------*/
472 472 static
473 473 Bool copy_output_until_stop ( EState* s )
474 474 {
475 475 Bool progress_out = False;
476 476
477 477 while (True) {
478 478
479 479 /*-- no output space? --*/
480 480 if (s->strm->avail_out == 0) break;
481 481
482 482 /*-- block done? --*/
483 483 if (s->state_out_pos >= s->numZ) break;
484 484
485 485 progress_out = True;
486 486 *(s->strm->next_out) = s->zbits[s->state_out_pos];
487 487 s->state_out_pos++;
488 488 s->strm->avail_out--;
489 489 s->strm->next_out++;
490 490 s->strm->total_out_lo32++;
491 491 if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
492 492 }
493 493
494 494 return progress_out;
495 495 }
496 496
497 497
498 498 /*---------------------------------------------------*/
499 499 static
500 500 Bool handle_compress ( bz_stream* strm )
501 501 {
502 502 Bool progress_in = False;
503 503 Bool progress_out = False;
504 504 EState* s = strm->state;
505 505
506 506 while (True) {
507 507
508 508 if (s->state == BZ_S_OUTPUT) {
509 509 progress_out |= copy_output_until_stop ( s );
510 510 if (s->state_out_pos < s->numZ) break;
511 511 if (s->mode == BZ_M_FINISHING &&
512 512 s->avail_in_expect == 0 &&
513 513 isempty_RL(s)) break;
514 514 prepare_new_block ( s );
515 515 s->state = BZ_S_INPUT;
516 516 if (s->mode == BZ_M_FLUSHING &&
517 517 s->avail_in_expect == 0 &&
518 518 isempty_RL(s)) break;
519 519 }
520 520
521 521 if (s->state == BZ_S_INPUT) {
522 522 progress_in |= copy_input_until_stop ( s );
523 523 if (s->mode != BZ_M_RUNNING && s->avail_in_expect == 0) {
524 524 flush_RL ( s );
525 525 BZ2_compressBlock ( s, (Bool)(s->mode == BZ_M_FINISHING) );
526 526 s->state = BZ_S_OUTPUT;
527 527 }
528 528 else
529 529 if (s->nblock >= s->nblockMAX) {
530 530 BZ2_compressBlock ( s, False );
531 531 s->state = BZ_S_OUTPUT;
532 532 }
533 533 else
534 534 if (s->strm->avail_in == 0) {
535 535 break;
536 536 }
537 537 }
538 538
539 539 }
540 540
541 541 return progress_in || progress_out;
542 542 }
543 543
544 544
545 545 /*---------------------------------------------------*/
546 546 int BZ_API(BZ2_bzCompress) ( bz_stream *strm, int action )
547 547 {
548 548 Bool progress;
549 549 EState* s;
550 550 if (strm == NULL) return BZ_PARAM_ERROR;
551 551 s = strm->state;
552 552 if (s == NULL) return BZ_PARAM_ERROR;
553 553 if (s->strm != strm) return BZ_PARAM_ERROR;
554 554
555 555 preswitch:
556 556 switch (s->mode) {
557 557
558 558 case BZ_M_IDLE:
559 559 return BZ_SEQUENCE_ERROR;
560 560
561 561 case BZ_M_RUNNING:
562 562 if (action == BZ_RUN) {
563 563 progress = handle_compress ( strm );
564 564 return progress ? BZ_RUN_OK : BZ_PARAM_ERROR;
565 565 }
566 566 else
567 567 if (action == BZ_FLUSH) {
568 568 s->avail_in_expect = strm->avail_in;
569 569 s->mode = BZ_M_FLUSHING;
570 570 goto preswitch;
571 571 }
572 572 else
573 573 if (action == BZ_FINISH) {
574 574 s->avail_in_expect = strm->avail_in;
575 575 s->mode = BZ_M_FINISHING;
576 576 goto preswitch;
577 577 }
578 578 else
579 579 return BZ_PARAM_ERROR;
580 580
581 581 case BZ_M_FLUSHING:
582 582 if (action != BZ_FLUSH) return BZ_SEQUENCE_ERROR;
583 583 if (s->avail_in_expect != s->strm->avail_in)
584 584 return BZ_SEQUENCE_ERROR;
585 585 progress = handle_compress ( strm );
586 586 if (s->avail_in_expect > 0 || !isempty_RL(s) ||
587 587 s->state_out_pos < s->numZ) return BZ_FLUSH_OK;
588 588 s->mode = BZ_M_RUNNING;
589 589 return BZ_RUN_OK;
590 590
591 591 case BZ_M_FINISHING:
592 592 if (action != BZ_FINISH) return BZ_SEQUENCE_ERROR;
593 593 if (s->avail_in_expect != s->strm->avail_in)
594 594 return BZ_SEQUENCE_ERROR;
595 595 progress = handle_compress ( strm );
596 596 if (!progress) return BZ_SEQUENCE_ERROR;
597 597 if (s->avail_in_expect > 0 || !isempty_RL(s) ||
598 598 s->state_out_pos < s->numZ) return BZ_FINISH_OK;
599 599 s->mode = BZ_M_IDLE;
600 600 return BZ_STREAM_END;
601 601 }
602 602 return BZ_OK; /*--not reached--*/
603 603 }
604 604
605 605
606 606 /*---------------------------------------------------*/
607 607 int BZ_API(BZ2_bzCompressEnd) ( bz_stream *strm )
608 608 {
609 609 EState* s;
610 610 if (strm == NULL) return BZ_PARAM_ERROR;
611 611 s = strm->state;
612 612 if (s == NULL) return BZ_PARAM_ERROR;
613 613 if (s->strm != strm) return BZ_PARAM_ERROR;
614 614
615 615 if (s->arr1 != NULL) BZFREE(s->arr1);
616 616 if (s->arr2 != NULL) BZFREE(s->arr2);
617 617 if (s->ftab != NULL) BZFREE(s->ftab);
618 618 BZFREE(strm->state);
619 619
620 620 strm->state = NULL;
621 621
622 622 return BZ_OK;
623 623 }
624 624
625 625 #endif /* BZ_NO_COMPRESS */
626 626
627 627 /*---------------------------------------------------*/
628 628 /*--- Decompression stuff ---*/
629 629 /*---------------------------------------------------*/
630 630
631 631 /*---------------------------------------------------*/
632 632 int BZ_API(BZ2_bzDecompressInit)
633 633 ( bz_stream* strm,
634 634 int verbosity,
635 635 int small )
636 636 {
637 637 DState* s;
638 638
639 639 if (!bz_config_ok()) return BZ_CONFIG_ERROR;
640 640
641 641 if (strm == NULL) return BZ_PARAM_ERROR;
642 642 if (small != 0 && small != 1) return BZ_PARAM_ERROR;
643 643 if (verbosity < 0 || verbosity > 4) return BZ_PARAM_ERROR;
644 644
645 645 if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc;
646 646 if (strm->bzfree == NULL) strm->bzfree = default_bzfree;
647 647
648 648 s = BZALLOC( sizeof(DState) );
649 649 if (s == NULL) return BZ_MEM_ERROR;
650 650 s->strm = strm;
651 651 strm->state = s;
652 652 s->state = BZ_X_MAGIC_1;
653 653 s->bsLive = 0;
654 654 s->bsBuff = 0;
655 655 s->calculatedCombinedCRC = 0;
656 656 strm->total_in_lo32 = 0;
657 657 strm->total_in_hi32 = 0;
658 658 strm->total_out_lo32 = 0;
659 659 strm->total_out_hi32 = 0;
660 660 s->smallDecompress = (Bool)small;
661 661 s->ll4 = NULL;
662 662 s->ll16 = NULL;
663 663 s->tt = NULL;
664 664 s->currBlockNo = 0;
665 665 s->verbosity = verbosity;
↓ open down ↓ |
665 lines elided |
↑ open up ↑ |
666 666
667 667 return BZ_OK;
668 668 }
669 669
670 670 /*---------------------------------------------------*/
671 671 /*
672 672 * added to allow reuse of bz_stream without malloc/free
673 673 */
674 674 int BZ_API(BZ2_bzDecompressReset) ( bz_stream* strm )
675 675 {
676 - DState* s = strm->state;
676 + DState* s;
677 677
678 678 if (!bz_config_ok()) return BZ_CONFIG_ERROR;
679 679
680 680 if (strm == NULL) return BZ_PARAM_ERROR;
681 681
682 + s = strm->state;
682 683 s->strm = strm;
683 684
684 685 s->state = BZ_X_MAGIC_1;
685 686 s->bsLive = 0;
686 687 s->bsBuff = 0;
687 688 s->calculatedCombinedCRC = 0;
688 689 strm->total_in_lo32 = 0;
689 690 strm->total_in_hi32 = 0;
690 691 strm->total_out_lo32 = 0;
691 692 strm->total_out_hi32 = 0;
692 693
693 694 s->ll4 = NULL;
694 695 s->ll16 = NULL;
695 696 s->tt = NULL;
696 697 s->currBlockNo = 0;
697 698
698 699
699 700 return BZ_OK;
700 701 }
701 702
702 703
703 704 /*---------------------------------------------------*/
704 705 /* Return True iff data corruption is discovered.
705 706 Returns False if there is no problem.
706 707 */
707 708 static
708 709 Bool unRLE_obuf_to_output_FAST ( DState* s )
709 710 {
710 711 UChar k1;
711 712
712 713 if (s->blockRandomised) {
713 714
714 715 while (True) {
715 716 /* try to finish existing run */
716 717 while (True) {
717 718 if (s->strm->avail_out == 0) return False;
718 719 if (s->state_out_len == 0) break;
719 720 *( (UChar*)(s->strm->next_out) ) = s->state_out_ch;
720 721 BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch );
721 722 s->state_out_len--;
722 723 s->strm->next_out++;
723 724 s->strm->avail_out--;
724 725 s->strm->total_out_lo32++;
725 726 if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
726 727 }
727 728
728 729 /* can a new run be started? */
729 730 if (s->nblock_used == s->save_nblock+1) return False;
730 731
731 732 /* Only caused by corrupt data stream? */
732 733 if (s->nblock_used > s->save_nblock+1)
733 734 return True;
734 735
735 736 s->state_out_len = 1;
736 737 s->state_out_ch = s->k0;
737 738 BZ_GET_FAST(k1); BZ_RAND_UPD_MASK;
738 739 k1 ^= BZ_RAND_MASK; s->nblock_used++;
739 740 if (s->nblock_used == s->save_nblock+1) continue;
740 741 if (k1 != s->k0) { s->k0 = k1; continue; };
741 742
742 743 s->state_out_len = 2;
743 744 BZ_GET_FAST(k1); BZ_RAND_UPD_MASK;
744 745 k1 ^= BZ_RAND_MASK; s->nblock_used++;
745 746 if (s->nblock_used == s->save_nblock+1) continue;
746 747 if (k1 != s->k0) { s->k0 = k1; continue; };
747 748
748 749 s->state_out_len = 3;
749 750 BZ_GET_FAST(k1); BZ_RAND_UPD_MASK;
750 751 k1 ^= BZ_RAND_MASK; s->nblock_used++;
751 752 if (s->nblock_used == s->save_nblock+1) continue;
752 753 if (k1 != s->k0) { s->k0 = k1; continue; };
753 754
754 755 BZ_GET_FAST(k1); BZ_RAND_UPD_MASK;
755 756 k1 ^= BZ_RAND_MASK; s->nblock_used++;
756 757 s->state_out_len = ((Int32)k1) + 4;
757 758 BZ_GET_FAST(s->k0); BZ_RAND_UPD_MASK;
758 759 s->k0 ^= BZ_RAND_MASK; s->nblock_used++;
759 760 }
760 761
761 762 } else {
762 763
763 764 /* restore */
764 765 UInt32 c_calculatedBlockCRC = s->calculatedBlockCRC;
765 766 UChar c_state_out_ch = s->state_out_ch;
766 767 Int32 c_state_out_len = s->state_out_len;
767 768 Int32 c_nblock_used = s->nblock_used;
768 769 Int32 c_k0 = s->k0;
769 770 UInt32* c_tt = s->tt;
770 771 UInt32 c_tPos = s->tPos;
771 772 char* cs_next_out = s->strm->next_out;
772 773 unsigned int cs_avail_out = s->strm->avail_out;
773 774 Int32 ro_blockSize100k = s->blockSize100k;
774 775 /* end restore */
775 776
776 777 UInt32 avail_out_INIT = cs_avail_out;
777 778 Int32 s_save_nblockPP = s->save_nblock+1;
778 779 unsigned int total_out_lo32_old;
779 780
780 781 while (True) {
781 782
782 783 /* try to finish existing run */
783 784 if (c_state_out_len > 0) {
784 785 while (True) {
785 786 if (cs_avail_out == 0) goto return_notr;
786 787 if (c_state_out_len == 1) break;
787 788 *( (UChar*)(cs_next_out) ) = c_state_out_ch;
788 789 BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch );
789 790 c_state_out_len--;
790 791 cs_next_out++;
791 792 cs_avail_out--;
792 793 }
793 794 s_state_out_len_eq_one:
794 795 {
795 796 if (cs_avail_out == 0) {
796 797 c_state_out_len = 1; goto return_notr;
797 798 };
798 799 *( (UChar*)(cs_next_out) ) = c_state_out_ch;
799 800 BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch );
800 801 cs_next_out++;
801 802 cs_avail_out--;
802 803 }
803 804 }
804 805 /* Only caused by corrupt data stream? */
805 806 if (c_nblock_used > s_save_nblockPP)
806 807 return True;
807 808
808 809 /* can a new run be started? */
809 810 if (c_nblock_used == s_save_nblockPP) {
810 811 c_state_out_len = 0; goto return_notr;
811 812 };
812 813 c_state_out_ch = c_k0;
813 814 BZ_GET_FAST_C(k1); c_nblock_used++;
814 815 if (k1 != c_k0) {
815 816 c_k0 = k1; goto s_state_out_len_eq_one;
816 817 };
817 818 if (c_nblock_used == s_save_nblockPP)
818 819 goto s_state_out_len_eq_one;
819 820
820 821 c_state_out_len = 2;
821 822 BZ_GET_FAST_C(k1); c_nblock_used++;
822 823 if (c_nblock_used == s_save_nblockPP) continue;
823 824 if (k1 != c_k0) { c_k0 = k1; continue; };
824 825
825 826 c_state_out_len = 3;
826 827 BZ_GET_FAST_C(k1); c_nblock_used++;
827 828 if (c_nblock_used == s_save_nblockPP) continue;
828 829 if (k1 != c_k0) { c_k0 = k1; continue; };
829 830
830 831 BZ_GET_FAST_C(k1); c_nblock_used++;
831 832 c_state_out_len = ((Int32)k1) + 4;
832 833 BZ_GET_FAST_C(c_k0); c_nblock_used++;
833 834 }
834 835
835 836 return_notr:
836 837 total_out_lo32_old = s->strm->total_out_lo32;
837 838 s->strm->total_out_lo32 += (avail_out_INIT - cs_avail_out);
838 839 if (s->strm->total_out_lo32 < total_out_lo32_old)
839 840 s->strm->total_out_hi32++;
840 841
841 842 /* save */
842 843 s->calculatedBlockCRC = c_calculatedBlockCRC;
843 844 s->state_out_ch = c_state_out_ch;
844 845 s->state_out_len = c_state_out_len;
845 846 s->nblock_used = c_nblock_used;
846 847 s->k0 = c_k0;
847 848 s->tt = c_tt;
848 849 s->tPos = c_tPos;
849 850 s->strm->next_out = cs_next_out;
850 851 s->strm->avail_out = cs_avail_out;
851 852 /* end save */
852 853 }
853 854 return False;
854 855 }
855 856
856 857
857 858
858 859 /*---------------------------------------------------*/
859 860 __inline__ Int32 BZ2_indexIntoF ( Int32 indx, Int32 *cftab )
860 861 {
861 862 Int32 nb, na, mid;
862 863 nb = 0;
863 864 na = 256;
864 865 do {
865 866 mid = (nb + na) >> 1;
866 867 if (indx >= cftab[mid]) nb = mid; else na = mid;
867 868 }
868 869 while (na - nb != 1);
869 870 return nb;
870 871 }
871 872
872 873
873 874 /*---------------------------------------------------*/
874 875 /* Return True iff data corruption is discovered.
875 876 Returns False if there is no problem.
876 877 */
877 878 static
878 879 Bool unRLE_obuf_to_output_SMALL ( DState* s )
879 880 {
880 881 UChar k1;
881 882
882 883 if (s->blockRandomised) {
883 884
884 885 while (True) {
885 886 /* try to finish existing run */
886 887 while (True) {
887 888 if (s->strm->avail_out == 0) return False;
888 889 if (s->state_out_len == 0) break;
889 890 *( (UChar*)(s->strm->next_out) ) = s->state_out_ch;
890 891 BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch );
891 892 s->state_out_len--;
892 893 s->strm->next_out++;
893 894 s->strm->avail_out--;
894 895 s->strm->total_out_lo32++;
895 896 if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
896 897 }
897 898
898 899 /* can a new run be started? */
899 900 if (s->nblock_used == s->save_nblock+1) return False;
900 901
901 902 /* Only caused by corrupt data stream? */
902 903 if (s->nblock_used > s->save_nblock+1)
903 904 return True;
904 905
905 906 s->state_out_len = 1;
906 907 s->state_out_ch = s->k0;
907 908 BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK;
908 909 k1 ^= BZ_RAND_MASK; s->nblock_used++;
909 910 if (s->nblock_used == s->save_nblock+1) continue;
910 911 if (k1 != s->k0) { s->k0 = k1; continue; };
911 912
912 913 s->state_out_len = 2;
913 914 BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK;
914 915 k1 ^= BZ_RAND_MASK; s->nblock_used++;
915 916 if (s->nblock_used == s->save_nblock+1) continue;
916 917 if (k1 != s->k0) { s->k0 = k1; continue; };
917 918
918 919 s->state_out_len = 3;
919 920 BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK;
920 921 k1 ^= BZ_RAND_MASK; s->nblock_used++;
921 922 if (s->nblock_used == s->save_nblock+1) continue;
922 923 if (k1 != s->k0) { s->k0 = k1; continue; };
923 924
924 925 BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK;
925 926 k1 ^= BZ_RAND_MASK; s->nblock_used++;
926 927 s->state_out_len = ((Int32)k1) + 4;
927 928 BZ_GET_SMALL(s->k0); BZ_RAND_UPD_MASK;
928 929 s->k0 ^= BZ_RAND_MASK; s->nblock_used++;
929 930 }
930 931
931 932 } else {
932 933
933 934 while (True) {
934 935 /* try to finish existing run */
935 936 while (True) {
936 937 if (s->strm->avail_out == 0) return False;
937 938 if (s->state_out_len == 0) break;
938 939 *( (UChar*)(s->strm->next_out) ) = s->state_out_ch;
939 940 BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch );
940 941 s->state_out_len--;
941 942 s->strm->next_out++;
942 943 s->strm->avail_out--;
943 944 s->strm->total_out_lo32++;
944 945 if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
945 946 }
946 947
947 948 /* can a new run be started? */
948 949 if (s->nblock_used == s->save_nblock+1) return False;
949 950
950 951 /* Only caused by corrupt data stream? */
951 952 if (s->nblock_used > s->save_nblock+1)
952 953 return True;
953 954
954 955 s->state_out_len = 1;
955 956 s->state_out_ch = s->k0;
956 957 BZ_GET_SMALL(k1); s->nblock_used++;
957 958 if (s->nblock_used == s->save_nblock+1) continue;
958 959 if (k1 != s->k0) { s->k0 = k1; continue; };
959 960
960 961 s->state_out_len = 2;
961 962 BZ_GET_SMALL(k1); s->nblock_used++;
962 963 if (s->nblock_used == s->save_nblock+1) continue;
963 964 if (k1 != s->k0) { s->k0 = k1; continue; };
964 965
965 966 s->state_out_len = 3;
966 967 BZ_GET_SMALL(k1); s->nblock_used++;
967 968 if (s->nblock_used == s->save_nblock+1) continue;
968 969 if (k1 != s->k0) { s->k0 = k1; continue; };
969 970
970 971 BZ_GET_SMALL(k1); s->nblock_used++;
971 972 s->state_out_len = ((Int32)k1) + 4;
972 973 BZ_GET_SMALL(s->k0); s->nblock_used++;
973 974 }
974 975
975 976 }
976 977 }
977 978
978 979
979 980 /*---------------------------------------------------*/
980 981 int BZ_API(BZ2_bzDecompress) ( bz_stream *strm )
981 982 {
982 983 Bool corrupt;
983 984 DState* s;
984 985 if (strm == NULL) return BZ_PARAM_ERROR;
985 986 s = strm->state;
986 987 if (s == NULL) return BZ_PARAM_ERROR;
987 988 if (s->strm != strm) return BZ_PARAM_ERROR;
988 989
989 990 while (True) {
990 991 if (s->state == BZ_X_IDLE) return BZ_SEQUENCE_ERROR;
991 992 if (s->state == BZ_X_OUTPUT) {
992 993 if (s->smallDecompress)
993 994 corrupt = unRLE_obuf_to_output_SMALL ( s ); else
994 995 corrupt = unRLE_obuf_to_output_FAST ( s );
995 996 if (corrupt) return BZ_DATA_ERROR;
996 997 if (s->nblock_used == s->save_nblock+1 && s->state_out_len == 0) {
997 998 BZ_FINALISE_CRC ( s->calculatedBlockCRC );
998 999 if (s->verbosity >= 3)
999 1000 VPrintf2 ( " {0x%08x, 0x%08x}", s->storedBlockCRC,
1000 1001 s->calculatedBlockCRC );
1001 1002 if (s->verbosity >= 2) VPrintf0 ( "]" );
1002 1003 if (s->calculatedBlockCRC != s->storedBlockCRC)
1003 1004 return BZ_DATA_ERROR;
1004 1005 s->calculatedCombinedCRC
1005 1006 = (s->calculatedCombinedCRC << 1) |
1006 1007 (s->calculatedCombinedCRC >> 31);
1007 1008 s->calculatedCombinedCRC ^= s->calculatedBlockCRC;
1008 1009 s->state = BZ_X_BLKHDR_1;
1009 1010 } else {
1010 1011 return BZ_OK;
1011 1012 }
1012 1013 }
1013 1014 if (s->state >= BZ_X_MAGIC_1) {
1014 1015 Int32 r = BZ2_decompress ( s );
1015 1016 if (r == BZ_STREAM_END) {
1016 1017 if (s->verbosity >= 3)
1017 1018 VPrintf2 ( "\n combined CRCs: stored = 0x%08x, computed = 0x%08x",
1018 1019 s->storedCombinedCRC, s->calculatedCombinedCRC );
1019 1020 if (s->calculatedCombinedCRC != s->storedCombinedCRC)
1020 1021 return BZ_DATA_ERROR;
1021 1022 return r;
1022 1023 }
1023 1024 if (s->state != BZ_X_OUTPUT) return r;
1024 1025 }
1025 1026 }
1026 1027
1027 1028 #if 0
1028 1029 AssertH ( 0, 6001 );
1029 1030
1030 1031 return 0; /*NOTREACHED*/
1031 1032 #endif
1032 1033 }
1033 1034
1034 1035
1035 1036 /*---------------------------------------------------*/
1036 1037 int BZ_API(BZ2_bzDecompressEnd) ( bz_stream *strm )
1037 1038 {
1038 1039 DState* s;
1039 1040 if (strm == NULL) return BZ_PARAM_ERROR;
1040 1041 s = strm->state;
1041 1042 if (s == NULL) return BZ_PARAM_ERROR;
1042 1043 if (s->strm != strm) return BZ_PARAM_ERROR;
1043 1044
1044 1045 if (s->tt != NULL) BZFREE(s->tt);
1045 1046 if (s->ll16 != NULL) BZFREE(s->ll16);
1046 1047 if (s->ll4 != NULL) BZFREE(s->ll4);
1047 1048
1048 1049 BZFREE(strm->state);
1049 1050 strm->state = NULL;
1050 1051
1051 1052 return BZ_OK;
1052 1053 }
1053 1054
1054 1055 #ifndef BZ_NO_COMPRESS
1055 1056
1056 1057 #ifndef BZ_NO_STDIO
1057 1058 /*---------------------------------------------------*/
1058 1059 /*--- File I/O stuff ---*/
1059 1060 /*---------------------------------------------------*/
1060 1061
1061 1062 #define BZ_SETERR(eee) \
1062 1063 { \
1063 1064 if (bzerror != NULL) *bzerror = eee; \
1064 1065 if (bzf != NULL) bzf->lastErr = eee; \
1065 1066 }
1066 1067
1067 1068 typedef
1068 1069 struct {
1069 1070 FILE* handle;
1070 1071 Char buf[BZ_MAX_UNUSED];
1071 1072 Int32 bufN;
1072 1073 Bool writing;
1073 1074 bz_stream strm;
1074 1075 Int32 lastErr;
1075 1076 Bool initialisedOk;
1076 1077 }
1077 1078 bzFile;
1078 1079
1079 1080
1080 1081 /*---------------------------------------------*/
1081 1082 static Bool myfeof ( FILE* f )
1082 1083 {
1083 1084 Int32 c = fgetc ( f );
1084 1085 if (c == EOF) return True;
1085 1086 ungetc ( c, f );
1086 1087 return False;
1087 1088 }
1088 1089
1089 1090
1090 1091 /*---------------------------------------------------*/
1091 1092 BZFILE* BZ_API(BZ2_bzWriteOpen)
1092 1093 ( int* bzerror,
1093 1094 FILE* f,
1094 1095 int blockSize100k,
1095 1096 int verbosity,
1096 1097 int workFactor )
1097 1098 {
1098 1099 Int32 ret;
1099 1100 bzFile* bzf = NULL;
1100 1101
1101 1102 BZ_SETERR(BZ_OK);
1102 1103
1103 1104 if (f == NULL ||
1104 1105 (blockSize100k < 1 || blockSize100k > 9) ||
1105 1106 (workFactor < 0 || workFactor > 250) ||
1106 1107 (verbosity < 0 || verbosity > 4))
1107 1108 { BZ_SETERR(BZ_PARAM_ERROR); return NULL; };
1108 1109
1109 1110 if (ferror(f))
1110 1111 { BZ_SETERR(BZ_IO_ERROR); return NULL; };
1111 1112
1112 1113 bzf = malloc ( sizeof(bzFile) );
1113 1114 if (bzf == NULL)
1114 1115 { BZ_SETERR(BZ_MEM_ERROR); return NULL; };
1115 1116
1116 1117 BZ_SETERR(BZ_OK);
1117 1118 bzf->initialisedOk = False;
1118 1119 bzf->bufN = 0;
1119 1120 bzf->handle = f;
1120 1121 bzf->writing = True;
1121 1122 bzf->strm.bzalloc = NULL;
1122 1123 bzf->strm.bzfree = NULL;
1123 1124 bzf->strm.opaque = NULL;
1124 1125
1125 1126 if (workFactor == 0) workFactor = 30;
1126 1127 ret = BZ2_bzCompressInit ( &(bzf->strm), blockSize100k,
1127 1128 verbosity, workFactor );
1128 1129 if (ret != BZ_OK)
1129 1130 { BZ_SETERR(ret); free(bzf); return NULL; };
1130 1131
1131 1132 bzf->strm.avail_in = 0;
1132 1133 bzf->initialisedOk = True;
1133 1134 return bzf;
1134 1135 }
1135 1136
1136 1137
1137 1138
1138 1139 /*---------------------------------------------------*/
1139 1140 void BZ_API(BZ2_bzWrite)
1140 1141 ( int* bzerror,
1141 1142 BZFILE* b,
1142 1143 void* buf,
1143 1144 int len )
1144 1145 {
1145 1146 Int32 n, n2, ret;
1146 1147 bzFile* bzf = (bzFile*)b;
1147 1148
1148 1149 BZ_SETERR(BZ_OK);
1149 1150 if (bzf == NULL || buf == NULL || len < 0)
1150 1151 { BZ_SETERR(BZ_PARAM_ERROR); return; };
1151 1152 if (!(bzf->writing))
1152 1153 { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
1153 1154 if (ferror(bzf->handle))
1154 1155 { BZ_SETERR(BZ_IO_ERROR); return; };
1155 1156
1156 1157 if (len == 0)
1157 1158 { BZ_SETERR(BZ_OK); return; };
1158 1159
1159 1160 bzf->strm.avail_in = len;
1160 1161 bzf->strm.next_in = buf;
1161 1162
1162 1163 while (True) {
1163 1164 bzf->strm.avail_out = BZ_MAX_UNUSED;
1164 1165 bzf->strm.next_out = bzf->buf;
1165 1166 ret = BZ2_bzCompress ( &(bzf->strm), BZ_RUN );
1166 1167 if (ret != BZ_RUN_OK)
1167 1168 { BZ_SETERR(ret); return; };
1168 1169
1169 1170 if (bzf->strm.avail_out < BZ_MAX_UNUSED) {
1170 1171 n = BZ_MAX_UNUSED - bzf->strm.avail_out;
1171 1172 n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar),
1172 1173 n, bzf->handle );
1173 1174 if (n != n2 || ferror(bzf->handle))
1174 1175 { BZ_SETERR(BZ_IO_ERROR); return; };
1175 1176 }
1176 1177
1177 1178 if (bzf->strm.avail_in == 0)
1178 1179 { BZ_SETERR(BZ_OK); return; };
1179 1180 }
1180 1181 }
1181 1182
1182 1183
1183 1184 /*---------------------------------------------------*/
1184 1185 void BZ_API(BZ2_bzWriteClose)
1185 1186 ( int* bzerror,
1186 1187 BZFILE* b,
1187 1188 int abandon,
1188 1189 unsigned int* nbytes_in,
1189 1190 unsigned int* nbytes_out )
1190 1191 {
1191 1192 BZ2_bzWriteClose64 ( bzerror, b, abandon,
1192 1193 nbytes_in, NULL, nbytes_out, NULL );
1193 1194 }
1194 1195
1195 1196
1196 1197 void BZ_API(BZ2_bzWriteClose64)
1197 1198 ( int* bzerror,
1198 1199 BZFILE* b,
1199 1200 int abandon,
1200 1201 unsigned int* nbytes_in_lo32,
1201 1202 unsigned int* nbytes_in_hi32,
1202 1203 unsigned int* nbytes_out_lo32,
1203 1204 unsigned int* nbytes_out_hi32 )
1204 1205 {
1205 1206 Int32 n, n2, ret;
1206 1207 bzFile* bzf = (bzFile*)b;
1207 1208
1208 1209 if (bzf == NULL)
1209 1210 { BZ_SETERR(BZ_OK); return; };
1210 1211 if (!(bzf->writing))
1211 1212 { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
1212 1213 if (ferror(bzf->handle))
1213 1214 { BZ_SETERR(BZ_IO_ERROR); return; };
1214 1215
1215 1216 if (nbytes_in_lo32 != NULL) *nbytes_in_lo32 = 0;
1216 1217 if (nbytes_in_hi32 != NULL) *nbytes_in_hi32 = 0;
1217 1218 if (nbytes_out_lo32 != NULL) *nbytes_out_lo32 = 0;
1218 1219 if (nbytes_out_hi32 != NULL) *nbytes_out_hi32 = 0;
1219 1220
1220 1221 if ((!abandon) && bzf->lastErr == BZ_OK) {
1221 1222 while (True) {
1222 1223 bzf->strm.avail_out = BZ_MAX_UNUSED;
1223 1224 bzf->strm.next_out = bzf->buf;
1224 1225 ret = BZ2_bzCompress ( &(bzf->strm), BZ_FINISH );
1225 1226 if (ret != BZ_FINISH_OK && ret != BZ_STREAM_END)
1226 1227 { BZ_SETERR(ret); return; };
1227 1228
1228 1229 if (bzf->strm.avail_out < BZ_MAX_UNUSED) {
1229 1230 n = BZ_MAX_UNUSED - bzf->strm.avail_out;
1230 1231 n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar),
1231 1232 n, bzf->handle );
1232 1233 if (n != n2 || ferror(bzf->handle))
1233 1234 { BZ_SETERR(BZ_IO_ERROR); return; };
1234 1235 }
1235 1236
1236 1237 if (ret == BZ_STREAM_END) break;
1237 1238 }
1238 1239 }
1239 1240
1240 1241 if ( !abandon && !ferror ( bzf->handle ) ) {
1241 1242 fflush ( bzf->handle );
1242 1243 if (ferror(bzf->handle))
1243 1244 { BZ_SETERR(BZ_IO_ERROR); return; };
1244 1245 }
1245 1246
1246 1247 if (nbytes_in_lo32 != NULL)
1247 1248 *nbytes_in_lo32 = bzf->strm.total_in_lo32;
1248 1249 if (nbytes_in_hi32 != NULL)
1249 1250 *nbytes_in_hi32 = bzf->strm.total_in_hi32;
1250 1251 if (nbytes_out_lo32 != NULL)
1251 1252 *nbytes_out_lo32 = bzf->strm.total_out_lo32;
1252 1253 if (nbytes_out_hi32 != NULL)
1253 1254 *nbytes_out_hi32 = bzf->strm.total_out_hi32;
1254 1255
1255 1256 BZ_SETERR(BZ_OK);
1256 1257 (void) BZ2_bzCompressEnd ( &(bzf->strm) );
1257 1258 free ( bzf );
1258 1259 }
1259 1260
1260 1261
1261 1262 /*---------------------------------------------------*/
1262 1263 BZFILE* BZ_API(BZ2_bzReadOpen)
1263 1264 ( int* bzerror,
1264 1265 FILE* f,
1265 1266 int verbosity,
1266 1267 int small,
1267 1268 void* unused,
1268 1269 int nUnused )
1269 1270 {
1270 1271 bzFile* bzf = NULL;
1271 1272 int ret;
1272 1273
1273 1274 BZ_SETERR(BZ_OK);
1274 1275
1275 1276 if (f == NULL ||
1276 1277 (small != 0 && small != 1) ||
1277 1278 (verbosity < 0 || verbosity > 4) ||
1278 1279 (unused == NULL && nUnused != 0) ||
1279 1280 (unused != NULL && (nUnused < 0 || nUnused > BZ_MAX_UNUSED)))
1280 1281 { BZ_SETERR(BZ_PARAM_ERROR); return NULL; };
1281 1282
1282 1283 if (ferror(f))
1283 1284 { BZ_SETERR(BZ_IO_ERROR); return NULL; };
1284 1285
1285 1286 bzf = malloc ( sizeof(bzFile) );
1286 1287 if (bzf == NULL)
1287 1288 { BZ_SETERR(BZ_MEM_ERROR); return NULL; };
1288 1289
1289 1290 BZ_SETERR(BZ_OK);
1290 1291
1291 1292 bzf->initialisedOk = False;
1292 1293 bzf->handle = f;
1293 1294 bzf->bufN = 0;
1294 1295 bzf->writing = False;
1295 1296 bzf->strm.bzalloc = NULL;
1296 1297 bzf->strm.bzfree = NULL;
1297 1298 bzf->strm.opaque = NULL;
1298 1299
1299 1300 while (nUnused > 0) {
1300 1301 bzf->buf[bzf->bufN] = *((UChar*)(unused)); bzf->bufN++;
1301 1302 unused = ((void*)( 1 + ((UChar*)(unused)) ));
1302 1303 nUnused--;
1303 1304 }
1304 1305
1305 1306 ret = BZ2_bzDecompressInit ( &(bzf->strm), verbosity, small );
1306 1307 if (ret != BZ_OK)
1307 1308 { BZ_SETERR(ret); free(bzf); return NULL; };
1308 1309
1309 1310 bzf->strm.avail_in = bzf->bufN;
1310 1311 bzf->strm.next_in = bzf->buf;
1311 1312
1312 1313 bzf->initialisedOk = True;
1313 1314 return bzf;
1314 1315 }
1315 1316
1316 1317
1317 1318 /*---------------------------------------------------*/
1318 1319 void BZ_API(BZ2_bzReadClose) ( int *bzerror, BZFILE *b )
1319 1320 {
1320 1321 bzFile* bzf = (bzFile*)b;
1321 1322
1322 1323 BZ_SETERR(BZ_OK);
1323 1324 if (bzf == NULL)
1324 1325 { BZ_SETERR(BZ_OK); return; };
1325 1326
1326 1327 if (bzf->writing)
1327 1328 { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
1328 1329
1329 1330 if (bzf->initialisedOk)
1330 1331 (void) BZ2_bzDecompressEnd ( &(bzf->strm) );
1331 1332 free ( bzf );
1332 1333 }
1333 1334
1334 1335
1335 1336 /*---------------------------------------------------*/
1336 1337 int BZ_API(BZ2_bzRead)
1337 1338 ( int* bzerror,
1338 1339 BZFILE* b,
1339 1340 void* buf,
1340 1341 int len )
1341 1342 {
1342 1343 Int32 n, ret;
1343 1344 bzFile* bzf = (bzFile*)b;
1344 1345
1345 1346 BZ_SETERR(BZ_OK);
1346 1347
1347 1348 if (bzf == NULL || buf == NULL || len < 0)
1348 1349 { BZ_SETERR(BZ_PARAM_ERROR); return 0; };
1349 1350
1350 1351 if (bzf->writing)
1351 1352 { BZ_SETERR(BZ_SEQUENCE_ERROR); return 0; };
1352 1353
1353 1354 if (len == 0)
1354 1355 { BZ_SETERR(BZ_OK); return 0; };
1355 1356
1356 1357 bzf->strm.avail_out = len;
1357 1358 bzf->strm.next_out = buf;
1358 1359
1359 1360 while (True) {
1360 1361
1361 1362 if (ferror(bzf->handle))
1362 1363 { BZ_SETERR(BZ_IO_ERROR); return 0; };
1363 1364
1364 1365 if (bzf->strm.avail_in == 0 && !myfeof(bzf->handle)) {
1365 1366 n = fread ( bzf->buf, sizeof(UChar),
1366 1367 BZ_MAX_UNUSED, bzf->handle );
1367 1368 if (ferror(bzf->handle))
1368 1369 { BZ_SETERR(BZ_IO_ERROR); return 0; };
1369 1370 bzf->bufN = n;
1370 1371 bzf->strm.avail_in = bzf->bufN;
1371 1372 bzf->strm.next_in = bzf->buf;
1372 1373 }
1373 1374
1374 1375 ret = BZ2_bzDecompress ( &(bzf->strm) );
1375 1376
1376 1377 if (ret != BZ_OK && ret != BZ_STREAM_END)
1377 1378 { BZ_SETERR(ret); return 0; };
1378 1379
1379 1380 if (ret == BZ_OK && myfeof(bzf->handle) &&
1380 1381 bzf->strm.avail_in == 0 && bzf->strm.avail_out > 0)
1381 1382 { BZ_SETERR(BZ_UNEXPECTED_EOF); return 0; };
1382 1383
1383 1384 if (ret == BZ_STREAM_END)
1384 1385 { BZ_SETERR(BZ_STREAM_END);
1385 1386 return len - bzf->strm.avail_out; };
1386 1387 if (bzf->strm.avail_out == 0)
1387 1388 { BZ_SETERR(BZ_OK); return len; };
1388 1389
1389 1390 }
1390 1391
1391 1392 return 0; /*not reached*/
1392 1393 }
1393 1394
1394 1395
1395 1396 /*---------------------------------------------------*/
1396 1397 void BZ_API(BZ2_bzReadGetUnused)
1397 1398 ( int* bzerror,
1398 1399 BZFILE* b,
1399 1400 void** unused,
1400 1401 int* nUnused )
1401 1402 {
1402 1403 bzFile* bzf = (bzFile*)b;
1403 1404 if (bzf == NULL)
1404 1405 { BZ_SETERR(BZ_PARAM_ERROR); return; };
1405 1406 if (bzf->lastErr != BZ_STREAM_END)
1406 1407 { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
1407 1408 if (unused == NULL || nUnused == NULL)
1408 1409 { BZ_SETERR(BZ_PARAM_ERROR); return; };
1409 1410
1410 1411 BZ_SETERR(BZ_OK);
1411 1412 *nUnused = bzf->strm.avail_in;
1412 1413 *unused = bzf->strm.next_in;
1413 1414 }
1414 1415 #endif
1415 1416
1416 1417
1417 1418 /*---------------------------------------------------*/
1418 1419 /*--- Misc convenience stuff ---*/
1419 1420 /*---------------------------------------------------*/
1420 1421
1421 1422 /*---------------------------------------------------*/
1422 1423 int BZ_API(BZ2_bzBuffToBuffCompress)
1423 1424 ( char* dest,
1424 1425 unsigned int* destLen,
1425 1426 char* source,
1426 1427 unsigned int sourceLen,
1427 1428 int blockSize100k,
1428 1429 int verbosity,
1429 1430 int workFactor )
1430 1431 {
1431 1432 bz_stream strm;
1432 1433 int ret;
1433 1434
1434 1435 if (dest == NULL || destLen == NULL ||
1435 1436 source == NULL ||
1436 1437 blockSize100k < 1 || blockSize100k > 9 ||
1437 1438 verbosity < 0 || verbosity > 4 ||
1438 1439 workFactor < 0 || workFactor > 250)
1439 1440 return BZ_PARAM_ERROR;
1440 1441
1441 1442 if (workFactor == 0) workFactor = 30;
1442 1443 strm.bzalloc = NULL;
1443 1444 strm.bzfree = NULL;
1444 1445 strm.opaque = NULL;
1445 1446 ret = BZ2_bzCompressInit ( &strm, blockSize100k,
1446 1447 verbosity, workFactor );
1447 1448 if (ret != BZ_OK) return ret;
1448 1449
1449 1450 strm.next_in = source;
1450 1451 strm.next_out = dest;
1451 1452 strm.avail_in = sourceLen;
1452 1453 strm.avail_out = *destLen;
1453 1454
1454 1455 ret = BZ2_bzCompress ( &strm, BZ_FINISH );
1455 1456 if (ret == BZ_FINISH_OK) goto output_overflow;
1456 1457 if (ret != BZ_STREAM_END) goto errhandler;
1457 1458
1458 1459 /* normal termination */
1459 1460 *destLen -= strm.avail_out;
1460 1461 (void) BZ2_bzCompressEnd ( &strm );
1461 1462 return BZ_OK;
1462 1463
1463 1464 output_overflow:
1464 1465 (void) BZ2_bzCompressEnd ( &strm );
1465 1466 return BZ_OUTBUFF_FULL;
1466 1467
1467 1468 errhandler:
1468 1469 (void) BZ2_bzCompressEnd ( &strm );
1469 1470 return ret;
1470 1471 }
1471 1472
1472 1473
1473 1474 /*---------------------------------------------------*/
1474 1475 int BZ_API(BZ2_bzBuffToBuffDecompress)
1475 1476 ( char* dest,
1476 1477 unsigned int* destLen,
1477 1478 char* source,
1478 1479 unsigned int sourceLen,
1479 1480 int small,
1480 1481 int verbosity )
1481 1482 {
1482 1483 bz_stream strm;
1483 1484 int ret;
1484 1485
1485 1486 if (dest == NULL || destLen == NULL ||
1486 1487 source == NULL ||
1487 1488 (small != 0 && small != 1) ||
1488 1489 verbosity < 0 || verbosity > 4)
1489 1490 return BZ_PARAM_ERROR;
1490 1491
1491 1492 strm.bzalloc = NULL;
1492 1493 strm.bzfree = NULL;
1493 1494 strm.opaque = NULL;
1494 1495 ret = BZ2_bzDecompressInit ( &strm, verbosity, small );
1495 1496 if (ret != BZ_OK) return ret;
1496 1497
1497 1498 strm.next_in = source;
1498 1499 strm.next_out = dest;
1499 1500 strm.avail_in = sourceLen;
1500 1501 strm.avail_out = *destLen;
1501 1502
1502 1503 ret = BZ2_bzDecompress ( &strm );
1503 1504 if (ret == BZ_OK) goto output_overflow_or_eof;
1504 1505 if (ret != BZ_STREAM_END) goto errhandler;
1505 1506
1506 1507 /* normal termination */
1507 1508 *destLen -= strm.avail_out;
1508 1509 (void) BZ2_bzDecompressEnd ( &strm );
1509 1510 return BZ_OK;
1510 1511
1511 1512 output_overflow_or_eof:
1512 1513 if (strm.avail_out > 0) {
1513 1514 (void) BZ2_bzDecompressEnd ( &strm );
1514 1515 return BZ_UNEXPECTED_EOF;
1515 1516 } else {
1516 1517 (void) BZ2_bzDecompressEnd ( &strm );
1517 1518 return BZ_OUTBUFF_FULL;
1518 1519 }
1519 1520
1520 1521 errhandler:
1521 1522 (void) BZ2_bzDecompressEnd ( &strm );
1522 1523 return ret;
1523 1524 }
1524 1525
1525 1526
1526 1527 /*---------------------------------------------------*/
1527 1528 /*--
1528 1529 Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp)
1529 1530 to support better zlib compatibility.
1530 1531 This code is not _officially_ part of libbzip2 (yet);
1531 1532 I haven't tested it, documented it, or considered the
1532 1533 threading-safeness of it.
1533 1534 If this code breaks, please contact both Yoshioka and me.
1534 1535 --*/
1535 1536 /*---------------------------------------------------*/
1536 1537
1537 1538 /*---------------------------------------------------*/
1538 1539 /*--
1539 1540 return version like "0.9.5d, 4-Sept-1999".
1540 1541 --*/
1541 1542 const char * BZ_API(BZ2_bzlibVersion)(void)
1542 1543 {
1543 1544 return BZ_VERSION;
1544 1545 }
1545 1546
1546 1547
1547 1548 #ifndef BZ_NO_STDIO
1548 1549 /*---------------------------------------------------*/
1549 1550
1550 1551 #if defined(_WIN32) || defined(OS2) || defined(MSDOS)
1551 1552 # include <fcntl.h>
1552 1553 # include <io.h>
1553 1554 # define SET_BINARY_MODE(file) setmode(fileno(file),O_BINARY)
1554 1555 #else
1555 1556 # define SET_BINARY_MODE(file)
1556 1557 #endif
1557 1558 static
1558 1559 BZFILE * bzopen_or_bzdopen
1559 1560 ( const char *path, /* no use when bzdopen */
1560 1561 int fd, /* no use when bzdopen */
1561 1562 const char *mode,
1562 1563 int open_mode) /* bzopen: 0, bzdopen:1 */
1563 1564 {
1564 1565 int bzerr;
1565 1566 char unused[BZ_MAX_UNUSED];
1566 1567 int blockSize100k = 9;
1567 1568 int writing = 0;
1568 1569 char mode2[10] = "";
1569 1570 FILE *fp = NULL;
1570 1571 BZFILE *bzfp = NULL;
1571 1572 int verbosity = 0;
1572 1573 int workFactor = 30;
1573 1574 int smallMode = 0;
1574 1575 int nUnused = 0;
1575 1576
1576 1577 if (mode == NULL) return NULL;
1577 1578 while (*mode) {
1578 1579 switch (*mode) {
1579 1580 case 'r':
1580 1581 writing = 0; break;
1581 1582 case 'w':
1582 1583 writing = 1; break;
1583 1584 case 's':
1584 1585 smallMode = 1; break;
1585 1586 default:
1586 1587 if (isdigit((int)(*mode))) {
1587 1588 blockSize100k = *mode-BZ_HDR_0;
1588 1589 }
1589 1590 }
1590 1591 mode++;
1591 1592 }
1592 1593 strcat(mode2, writing ? "w" : "r" );
1593 1594 strcat(mode2,"b"); /* binary mode */
1594 1595
1595 1596 if (open_mode==0) {
1596 1597 if (path==NULL || strcmp(path,"")==0) {
1597 1598 fp = (writing ? stdout : stdin);
1598 1599 SET_BINARY_MODE(fp);
1599 1600 } else {
1600 1601 fp = fopen(path,mode2);
1601 1602 }
1602 1603 } else {
1603 1604 #ifdef BZ_STRICT_ANSI
1604 1605 fp = NULL;
1605 1606 #else
1606 1607 fp = fdopen(fd,mode2);
1607 1608 #endif
1608 1609 }
1609 1610 if (fp == NULL) return NULL;
1610 1611
1611 1612 if (writing) {
1612 1613 /* Guard against total chaos and anarchy -- JRS */
1613 1614 if (blockSize100k < 1) blockSize100k = 1;
1614 1615 if (blockSize100k > 9) blockSize100k = 9;
1615 1616 bzfp = BZ2_bzWriteOpen(&bzerr,fp,blockSize100k,
1616 1617 verbosity,workFactor);
1617 1618 } else {
1618 1619 bzfp = BZ2_bzReadOpen(&bzerr,fp,verbosity,smallMode,
1619 1620 unused,nUnused);
1620 1621 }
1621 1622 if (bzfp == NULL) {
1622 1623 if (fp != stdin && fp != stdout) fclose(fp);
1623 1624 return NULL;
1624 1625 }
1625 1626 return bzfp;
1626 1627 }
1627 1628
1628 1629
1629 1630 /*---------------------------------------------------*/
1630 1631 /*--
1631 1632 open file for read or write.
1632 1633 ex) bzopen("file","w9")
1633 1634 case path="" or NULL => use stdin or stdout.
1634 1635 --*/
1635 1636 BZFILE * BZ_API(BZ2_bzopen)
1636 1637 ( const char *path,
1637 1638 const char *mode )
1638 1639 {
1639 1640 return bzopen_or_bzdopen(path,-1,mode,/*bzopen*/0);
1640 1641 }
1641 1642
1642 1643
1643 1644 /*---------------------------------------------------*/
1644 1645 BZFILE * BZ_API(BZ2_bzdopen)
1645 1646 ( int fd,
1646 1647 const char *mode )
1647 1648 {
1648 1649 return bzopen_or_bzdopen(NULL,fd,mode,/*bzdopen*/1);
1649 1650 }
1650 1651
1651 1652
1652 1653 /*---------------------------------------------------*/
1653 1654 int BZ_API(BZ2_bzread) (BZFILE* b, void* buf, int len )
1654 1655 {
1655 1656 int bzerr, nread;
1656 1657 if (((bzFile*)b)->lastErr == BZ_STREAM_END) return 0;
1657 1658 nread = BZ2_bzRead(&bzerr,b,buf,len);
1658 1659 if (bzerr == BZ_OK || bzerr == BZ_STREAM_END) {
1659 1660 return nread;
1660 1661 } else {
1661 1662 return -1;
1662 1663 }
1663 1664 }
1664 1665
1665 1666
1666 1667 /*---------------------------------------------------*/
1667 1668 int BZ_API(BZ2_bzwrite) (BZFILE* b, void* buf, int len )
1668 1669 {
1669 1670 int bzerr;
1670 1671
1671 1672 BZ2_bzWrite(&bzerr,b,buf,len);
1672 1673 if(bzerr == BZ_OK){
1673 1674 return len;
1674 1675 }else{
1675 1676 return -1;
1676 1677 }
1677 1678 }
1678 1679
1679 1680
1680 1681 /*---------------------------------------------------*/
1681 1682 int BZ_API(BZ2_bzflush) (BZFILE *b)
1682 1683 {
1683 1684 /* do nothing now... */
1684 1685 return 0;
1685 1686 }
1686 1687
1687 1688
1688 1689 /*---------------------------------------------------*/
1689 1690 void BZ_API(BZ2_bzclose) (BZFILE* b)
1690 1691 {
1691 1692 int bzerr;
1692 1693 FILE *fp;
1693 1694
1694 1695 if (b==NULL) {return;}
1695 1696 fp = ((bzFile *)b)->handle;
1696 1697 if(((bzFile*)b)->writing){
1697 1698 BZ2_bzWriteClose(&bzerr,b,0,NULL,NULL);
1698 1699 if(bzerr != BZ_OK){
1699 1700 BZ2_bzWriteClose(NULL,b,1,NULL,NULL);
1700 1701 }
1701 1702 }else{
1702 1703 BZ2_bzReadClose(&bzerr,b);
1703 1704 }
1704 1705 if(fp!=stdin && fp!=stdout){
1705 1706 fclose(fp);
1706 1707 }
1707 1708 }
1708 1709
1709 1710
1710 1711 /*---------------------------------------------------*/
1711 1712 /*--
1712 1713 return last error code
1713 1714 --*/
1714 1715 static const char *bzerrorstrings[] = {
1715 1716 "OK"
1716 1717 ,"SEQUENCE_ERROR"
1717 1718 ,"PARAM_ERROR"
1718 1719 ,"MEM_ERROR"
1719 1720 ,"DATA_ERROR"
1720 1721 ,"DATA_ERROR_MAGIC"
1721 1722 ,"IO_ERROR"
1722 1723 ,"UNEXPECTED_EOF"
1723 1724 ,"OUTBUFF_FULL"
1724 1725 ,"CONFIG_ERROR"
1725 1726 ,"???" /* for future */
1726 1727 ,"???" /* for future */
1727 1728 ,"???" /* for future */
1728 1729 ,"???" /* for future */
1729 1730 ,"???" /* for future */
1730 1731 ,"???" /* for future */
1731 1732 };
1732 1733
1733 1734
1734 1735 const char * BZ_API(BZ2_bzerror) (BZFILE *b, int *errnum)
1735 1736 {
1736 1737 int err = ((bzFile *)b)->lastErr;
1737 1738
1738 1739 if(err>0) err = 0;
1739 1740 *errnum = err;
1740 1741 return bzerrorstrings[err*-1];
1741 1742 }
1742 1743 #endif
1743 1744
1744 1745 #endif /* BZ_NO_COMPRESS */
1745 1746
1746 1747 /*-------------------------------------------------------------*/
1747 1748 /*--- end bzlib.c ---*/
1748 1749 /*-------------------------------------------------------------*/
↓ open down ↓ |
1057 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX