Rizin
unix-like reverse engineering framework and cli tools
lzxd.c File Reference
#include <system.h>
#include <lzx.h>
#include <readbits.h>
#include <readhuff.h>

Go to the source code of this file.

Macros

#define BITS_TYPE   struct lzxd_stream
 
#define BITS_VAR   lzx
 
#define BITS_ORDER_MSB
 
#define READ_BYTES
 
#define TABLEBITS(tbl)   LZX_##tbl##_TABLEBITS
 
#define MAXSYMBOLS(tbl)   LZX_##tbl##_MAXSYMBOLS
 
#define HUFF_TABLE(tbl, idx)   lzx->tbl##_table[idx]
 
#define HUFF_LEN(tbl, idx)   lzx->tbl##_len[idx]
 
#define HUFF_ERROR   return lzx->error = MSPACK_ERR_DECRUNCH
 
#define BUILD_TABLE(tbl)
 
#define BUILD_TABLE_MAYBE_EMPTY(tbl)
 
#define READ_LENGTHS(tbl, first, last)
 

Functions

static int lzxd_read_lens (struct lzxd_stream *lzx, unsigned char *lens, unsigned int first, unsigned int last)
 
static void lzxd_reset_state (struct lzxd_stream *lzx)
 
struct lzxd_streamlzxd_init (struct mspack_system *system, struct mspack_file *input, struct mspack_file *output, int window_bits, int reset_interval, int input_buffer_size, off_t output_length, char is_delta)
 
int lzxd_set_reference_data (struct lzxd_stream *lzx, struct mspack_system *system, struct mspack_file *input, unsigned int length)
 
void lzxd_set_output_length (struct lzxd_stream *lzx, off_t out_bytes)
 
int lzxd_decompress (struct lzxd_stream *lzx, off_t out_bytes)
 
void lzxd_free (struct lzxd_stream *lzx)
 

Variables

static const unsigned int position_slots [11]
 
static const unsigned char extra_bits [36]
 
static const unsigned int position_base [290]
 

Macro Definition Documentation

◆ BITS_ORDER_MSB

#define BITS_ORDER_MSB

Definition at line 85 of file lzxd.c.

◆ BITS_TYPE

#define BITS_TYPE   struct lzxd_stream

Definition at line 83 of file lzxd.c.

◆ BITS_VAR

#define BITS_VAR   lzx

Definition at line 84 of file lzxd.c.

◆ BUILD_TABLE

#define BUILD_TABLE (   tbl)
Value:
&HUFF_LEN(tbl,0), &HUFF_TABLE(tbl,0))) \
{ \
D(("failed to build %s table", #tbl)) \
return lzx->error = MSPACK_ERR_DECRUNCH; \
}
#define HUFF_TABLE(tbl, idx)
Definition: lzxd.c:97
#define MAXSYMBOLS(tbl)
Definition: lzxd.c:96
#define HUFF_LEN(tbl, idx)
Definition: lzxd.c:98
#define TABLEBITS(tbl)
Definition: lzxd.c:95
#define MSPACK_ERR_DECRUNCH
Definition: mspack.h:507
static int make_decode_table(unsigned int nsyms, unsigned int nbits, unsigned char *length, unsigned short *table)
Definition: readhuff.h:78

Definition at line 103 of file lzxd.c.

◆ BUILD_TABLE_MAYBE_EMPTY

#define BUILD_TABLE_MAYBE_EMPTY (   tbl)
Value:
do { \
lzx->tbl##_empty = 0; \
&HUFF_LEN(tbl,0), &HUFF_TABLE(tbl,0))) \
{ \
for (i = 0; i < MAXSYMBOLS(tbl); i++) { \
if (HUFF_LEN(tbl, i) > 0) { \
D(("failed to build %s table", #tbl)) \
return lzx->error = MSPACK_ERR_DECRUNCH; \
} \
} \
/* empty tree - allow it, but don't decode symbols with it */ \
lzx->tbl##_empty = 1; \
} \
} while (0)
lzma_index ** i
Definition: index.h:629

Definition at line 111 of file lzxd.c.

◆ HUFF_ERROR

#define HUFF_ERROR   return lzx->error = MSPACK_ERR_DECRUNCH

Definition at line 99 of file lzxd.c.

◆ HUFF_LEN

#define HUFF_LEN (   tbl,
  idx 
)    lzx->tbl##_len[idx]

Definition at line 98 of file lzxd.c.

◆ HUFF_TABLE

#define HUFF_TABLE (   tbl,
  idx 
)    lzx->tbl##_table[idx]

Definition at line 97 of file lzxd.c.

◆ MAXSYMBOLS

#define MAXSYMBOLS (   tbl)    LZX_##tbl##_MAXSYMBOLS

Definition at line 96 of file lzxd.c.

◆ READ_BYTES

#define READ_BYTES
Value:
do { \
unsigned char b0, b1; \
READ_IF_NEEDED; b0 = *i_ptr++; \
READ_IF_NEEDED; b1 = *i_ptr++; \
INJECT_BITS((b1 << 8) | b0, 16); \
} while (0)

Definition at line 86 of file lzxd.c.

◆ READ_LENGTHS

#define READ_LENGTHS (   tbl,
  first,
  last 
)
Value:
do { \
STORE_BITS; \
if (lzxd_read_lens(lzx, &HUFF_LEN(tbl, 0), (first), \
(unsigned int)(last))) return lzx->error; \
RESTORE_BITS; \
} while (0)
static int lzxd_read_lens(struct lzxd_stream *lzx, unsigned char *lens, unsigned int first, unsigned int last)
Definition: lzxd.c:138

Definition at line 131 of file lzxd.c.

◆ TABLEBITS

#define TABLEBITS (   tbl)    LZX_##tbl##_TABLEBITS

Definition at line 95 of file lzxd.c.

Function Documentation

◆ lzxd_decompress()

int lzxd_decompress ( struct lzxd_stream lzx,
off_t  out_bytes 
)

Decompresses entire or partial LZX streams.

The number of bytes of data that should be decompressed is given as the out_bytes parameter. If more bytes are decoded than are needed, they will be kept over for a later invocation.

The output bytes will be passed to the system->write() function given in lzxd_init(), using the output file handle given in lzxd_init(). More than one call may be made to system->write().

Input bytes will be read in as necessary using the system->read() function given in lzxd_init(), using the input file handle given in lzxd_init(). This will continue until system->read() returns 0 bytes, or an error. Errors will be passed out of the function as MSPACK_ERR_READ errors. Input streams should convey an "end of input stream" by refusing to supply all the bytes that LZX asks for when they reach the end of the stream, rather than return an error code.

If any error code other than MSPACK_ERR_OK is returned, the stream should be considered unusable and lzxd_decompress() should not be called again on this stream.

Parameters
lzxLZX decompression state, as allocated by lzxd_init().
out_bytesthe number of bytes of data to decompress.
Returns
an error code, or MSPACK_ERR_OK if successful

Definition at line 393 of file lzxd.c.

393  {
394  /* bitstream and huffman reading variables */
395  register unsigned int bit_buffer;
396  register int bits_left, i=0;
397  unsigned char *i_ptr, *i_end;
398  register unsigned short sym;
399 
400  int match_length, length_footer, extra, verbatim_bits, bytes_todo;
401  int this_run, main_element, aligned_bits, j, warned = 0;
402  unsigned char *window, *runsrc, *rundest, buf[12];
403  unsigned int frame_size=0, end_frame, match_offset, window_posn;
404  unsigned int R0, R1, R2;
405 
406  /* easy answers */
407  if (!lzx || (out_bytes < 0)) return MSPACK_ERR_ARGS;
408  if (lzx->error) return lzx->error;
409 
410  /* flush out any stored-up bytes before we begin */
411  i = lzx->o_end - lzx->o_ptr;
412  if ((off_t) i > out_bytes) i = (int) out_bytes;
413  if (i) {
414  if (lzx->sys->write(lzx->output, lzx->o_ptr, i) != i) {
415  return lzx->error = MSPACK_ERR_WRITE;
416  }
417  lzx->o_ptr += i;
418  lzx->offset += i;
419  out_bytes -= i;
420  }
421  if (out_bytes == 0) return MSPACK_ERR_OK;
422 
423  /* restore local state */
424  RESTORE_BITS;
425  window = lzx->window;
426  window_posn = lzx->window_posn;
427  R0 = lzx->R0;
428  R1 = lzx->R1;
429  R2 = lzx->R2;
430 
431  end_frame = (unsigned int)((lzx->offset + out_bytes) / LZX_FRAME_SIZE) + 1;
432 
433  while (lzx->frame < end_frame) {
434  /* have we reached the reset interval? (if there is one?) */
435  if (lzx->reset_interval && ((lzx->frame % lzx->reset_interval) == 0)) {
436  if (lzx->block_remaining) {
437  /* this is a file format error, we can make a best effort to extract what we can */
438  D(("%d bytes remaining at reset interval", lzx->block_remaining))
439  if (!warned) {
440  lzx->sys->message(NULL, "WARNING; invalid reset interval detected during LZX decompression");
441  warned++;
442  }
443  }
444 
445  /* re-read the intel header and reset the huffman lengths */
446  lzxd_reset_state(lzx);
447  R0 = lzx->R0;
448  R1 = lzx->R1;
449  R2 = lzx->R2;
450  }
451 
452  /* LZX DELTA format has chunk_size, not present in LZX format */
453  if (lzx->is_delta) {
454  ENSURE_BITS(16);
455  REMOVE_BITS(16);
456  }
457 
458  /* read header if necessary */
459  if (!lzx->header_read) {
460  /* read 1 bit. if bit=0, intel filesize = 0.
461  * if bit=1, read intel filesize (32 bits) */
462  j = 0; READ_BITS(i, 1); if (i) { READ_BITS(i, 16); READ_BITS(j, 16); }
463  lzx->intel_filesize = (i << 16) | j;
464  lzx->header_read = 1;
465  }
466 
467  /* calculate size of frame: all frames are 32k except the final frame
468  * which is 32kb or less. this can only be calculated when lzx->length
469  * has been filled in. */
470  frame_size = LZX_FRAME_SIZE;
471  if (lzx->length && (lzx->length - lzx->offset) < (off_t)frame_size) {
472  frame_size = lzx->length - lzx->offset;
473  }
474 
475  /* decode until one more frame is available */
476  bytes_todo = lzx->frame_posn + frame_size - window_posn;
477  while (bytes_todo > 0) {
478  /* initialise new block, if one is needed */
479  if (lzx->block_remaining == 0) {
480  /* realign if previous block was an odd-sized UNCOMPRESSED block */
481  if ((lzx->block_type == LZX_BLOCKTYPE_UNCOMPRESSED) &&
482  (lzx->block_length & 1))
483  {
485  i_ptr++;
486  }
487 
488  /* read block type (3 bits) and block length (24 bits) */
489  READ_BITS(lzx->block_type, 3);
490  READ_BITS(i, 16); READ_BITS(j, 8);
491  lzx->block_remaining = lzx->block_length = (i << 8) | j;
492  /*D(("new block t%d len %u", lzx->block_type, lzx->block_length))*/
493 
494  /* read individual block headers */
495  switch (lzx->block_type) {
497  /* read lengths of and build aligned huffman decoding tree */
498  for (i = 0; i < 8; i++) { READ_BITS(j, 3); lzx->ALIGNED_len[i] = j; }
499  BUILD_TABLE(ALIGNED);
500  /* rest of aligned header is same as verbatim */ /*@fallthrough@*/
502  /* read lengths of and build main huffman decoding tree */
503  READ_LENGTHS(MAINTREE, 0, 256);
504  READ_LENGTHS(MAINTREE, 256, LZX_NUM_CHARS + lzx->num_offsets);
505  BUILD_TABLE(MAINTREE);
506  /* if the literal 0xE8 is anywhere in the block... */
507  if (lzx->MAINTREE_len[0xE8] != 0) lzx->intel_started = 1;
508  /* read lengths of and build lengths huffman decoding tree */
511  break;
512 
514  /* because we can't assume otherwise */
515  lzx->intel_started = 1;
516 
517  /* read 1-16 (not 0-15) bits to align to bytes */
518  if (bits_left == 0) ENSURE_BITS(16);
519  bits_left = 0; bit_buffer = 0;
520 
521  /* read 12 bytes of stored R0 / R1 / R2 values */
522  for (rundest = &buf[0], i = 0; i < 12; i++) {
524  *rundest++ = *i_ptr++;
525  }
526  R0 = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
527  R1 = buf[4] | (buf[5] << 8) | (buf[6] << 16) | (buf[7] << 24);
528  R2 = buf[8] | (buf[9] << 8) | (buf[10] << 16) | (buf[11] << 24);
529  break;
530 
531  default:
532  D(("bad block type"))
533  return lzx->error = MSPACK_ERR_DECRUNCH;
534  }
535  }
536 
537  /* decode more of the block:
538  * run = min(what's available, what's needed) */
539  this_run = lzx->block_remaining;
540  if (this_run > bytes_todo) this_run = bytes_todo;
541 
542  /* assume we decode exactly this_run bytes, for now */
543  bytes_todo -= this_run;
544  lzx->block_remaining -= this_run;
545 
546  /* decode at least this_run bytes */
547  switch (lzx->block_type) {
550  while (this_run > 0) {
551  READ_HUFFSYM(MAINTREE, main_element);
552  if (main_element < LZX_NUM_CHARS) {
553  /* literal: 0 to LZX_NUM_CHARS-1 */
554  window[window_posn++] = main_element;
555  this_run--;
556  }
557  else {
558  /* match: LZX_NUM_CHARS + ((slot<<3) | length_header (3 bits)) */
559  main_element -= LZX_NUM_CHARS;
560 
561  /* get match length */
562  match_length = main_element & LZX_NUM_PRIMARY_LENGTHS;
563  if (match_length == LZX_NUM_PRIMARY_LENGTHS) {
564  if (lzx->LENGTH_empty) {
565  D(("LENGTH symbol needed but tree is empty"))
566  return lzx->error = MSPACK_ERR_DECRUNCH;
567  }
568  READ_HUFFSYM(LENGTH, length_footer);
569  match_length += length_footer;
570  }
571  match_length += LZX_MIN_MATCH;
572 
573  /* get match offset */
574  switch ((match_offset = (main_element >> 3))) {
575  case 0: match_offset = R0; break;
576  case 1: match_offset = R1; R1=R0; R0 = match_offset; break;
577  case 2: match_offset = R2; R2=R0; R0 = match_offset; break;
578  default:
579  if (lzx->block_type == LZX_BLOCKTYPE_VERBATIM) {
580  if (match_offset == 3) {
581  match_offset = 1;
582  }
583  else {
584  extra = (match_offset >= 36) ? 17 : extra_bits[match_offset];
585  READ_BITS(verbatim_bits, extra);
586  match_offset = position_base[match_offset] - 2 + verbatim_bits;
587  }
588  }
589  else { /* LZX_BLOCKTYPE_ALIGNED */
590  extra = (match_offset >= 36) ? 17 : extra_bits[match_offset];
591  match_offset = position_base[match_offset] - 2;
592  if (extra > 3) { /* >3: verbatim and aligned bits */
593  extra -= 3;
594  READ_BITS(verbatim_bits, extra);
595  match_offset += (verbatim_bits << 3);
596  READ_HUFFSYM(ALIGNED, aligned_bits);
597  match_offset += aligned_bits;
598  }
599  else if (extra == 3) { /* 3: aligned bits only */
600  READ_HUFFSYM(ALIGNED, aligned_bits);
601  match_offset += aligned_bits;
602  }
603  else if (extra > 0) { /* 1-2: verbatim bits only */
604  READ_BITS(verbatim_bits, extra);
605  match_offset += verbatim_bits;
606  }
607  else { /* 0: not defined in LZX specification! */
608  match_offset = 1;
609  }
610  }
611  /* update repeated offset LRU queue */
612  R2 = R1; R1 = R0; R0 = match_offset;
613  }
614 
615  /* LZX DELTA uses max match length to signal even longer match */
616  if (match_length == LZX_MAX_MATCH && lzx->is_delta) {
617  int extra_len = 0;
618  ENSURE_BITS(3); /* 4 entry huffman tree */
619  if (PEEK_BITS(1) == 0) {
620  REMOVE_BITS(1); /* '0' -> 8 extra length bits */
621  READ_BITS(extra_len, 8);
622  }
623  else if (PEEK_BITS(2) == 2) {
624  REMOVE_BITS(2); /* '10' -> 10 extra length bits + 0x100 */
625  READ_BITS(extra_len, 10);
626  extra_len += 0x100;
627  }
628  else if (PEEK_BITS(3) == 6) {
629  REMOVE_BITS(3); /* '110' -> 12 extra length bits + 0x500 */
630  READ_BITS(extra_len, 12);
631  extra_len += 0x500;
632  }
633  else {
634  REMOVE_BITS(3); /* '111' -> 15 extra length bits */
635  READ_BITS(extra_len, 15);
636  }
637  match_length += extra_len;
638  }
639 
640  if ((window_posn + match_length) > lzx->window_size) {
641  D(("match ran over window wrap"))
642  return lzx->error = MSPACK_ERR_DECRUNCH;
643  }
644 
645  /* copy match */
646  rundest = &window[window_posn];
647  i = match_length;
648  /* does match offset wrap the window? */
649  if (match_offset > window_posn) {
650  if (match_offset > lzx->offset &&
651  (match_offset - window_posn) > lzx->ref_data_size)
652  {
653  D(("match offset beyond LZX stream"))
654  return lzx->error = MSPACK_ERR_DECRUNCH;
655  }
656  /* j = length from match offset to end of window */
657  j = match_offset - window_posn;
658  if (j > (int) lzx->window_size) {
659  D(("match offset beyond window boundaries"))
660  return lzx->error = MSPACK_ERR_DECRUNCH;
661  }
662  runsrc = &window[lzx->window_size - j];
663  if (j < i) {
664  /* if match goes over the window edge, do two copy runs */
665  i -= j; while (j-- > 0) *rundest++ = *runsrc++;
666  runsrc = window;
667  }
668  while (i-- > 0) *rundest++ = *runsrc++;
669  }
670  else {
671  runsrc = rundest - match_offset;
672  while (i-- > 0) *rundest++ = *runsrc++;
673  }
674 
675  this_run -= match_length;
676  window_posn += match_length;
677  }
678  } /* while (this_run > 0) */
679  break;
680 
682  /* as this_run is limited not to wrap a frame, this also means it
683  * won't wrap the window (as the window is a multiple of 32k) */
684  rundest = &window[window_posn];
685  window_posn += this_run;
686  while (this_run > 0) {
687  if ((i = i_end - i_ptr) == 0) {
689  }
690  else {
691  if (i > this_run) i = this_run;
692  lzx->sys->copy(i_ptr, rundest, (size_t) i);
693  rundest += i;
694  i_ptr += i;
695  this_run -= i;
696  }
697  }
698  break;
699 
700  default:
701  return lzx->error = MSPACK_ERR_DECRUNCH; /* might as well */
702  }
703 
704  /* did the final match overrun our desired this_run length? */
705  if (this_run < 0) {
706  if ((unsigned int)(-this_run) > lzx->block_remaining) {
707  D(("overrun went past end of block by %d (%d remaining)",
708  -this_run, lzx->block_remaining ))
709  return lzx->error = MSPACK_ERR_DECRUNCH;
710  }
711  lzx->block_remaining -= -this_run;
712  }
713  } /* while (bytes_todo > 0) */
714 
715  /* streams don't extend over frame boundaries */
716  if ((window_posn - lzx->frame_posn) != frame_size) {
717  D(("decode beyond output frame limits! %d != %d",
718  window_posn - lzx->frame_posn, frame_size))
719  return lzx->error = MSPACK_ERR_DECRUNCH;
720  }
721 
722  /* re-align input bitstream */
723  if (bits_left > 0) ENSURE_BITS(16);
724  if (bits_left & 15) REMOVE_BITS(bits_left & 15);
725 
726  /* check that we've used all of the previous frame first */
727  if (lzx->o_ptr != lzx->o_end) {
728  D(("%ld avail bytes, new %d frame",
729  (long)(lzx->o_end - lzx->o_ptr), frame_size))
730  return lzx->error = MSPACK_ERR_DECRUNCH;
731  }
732 
733  /* does this intel block _really_ need decoding? */
734  if (lzx->intel_started && lzx->intel_filesize &&
735  (lzx->frame < 32768) && (frame_size > 10))
736  {
737  unsigned char *data = &lzx->e8_buf[0];
738  unsigned char *dataend = &lzx->e8_buf[frame_size - 10];
739  signed int curpos = (int) lzx->offset;
740  signed int filesize = lzx->intel_filesize;
741  signed int abs_off, rel_off;
742 
743  /* copy e8 block to the e8 buffer and tweak if needed */
744  lzx->o_ptr = data;
745  lzx->sys->copy(&lzx->window[lzx->frame_posn], data, frame_size);
746 
747  while (data < dataend) {
748  if (*data++ != 0xE8) { curpos++; continue; }
749  abs_off = data[0] | (data[1]<<8) | (data[2]<<16) | (data[3]<<24);
750  if ((abs_off >= -curpos) && (abs_off < filesize)) {
751  rel_off = (abs_off >= 0) ? abs_off - curpos : abs_off + filesize;
752  data[0] = (unsigned char) rel_off;
753  data[1] = (unsigned char) (rel_off >> 8);
754  data[2] = (unsigned char) (rel_off >> 16);
755  data[3] = (unsigned char) (rel_off >> 24);
756  }
757  data += 4;
758  curpos += 5;
759  }
760  }
761  else {
762  lzx->o_ptr = &lzx->window[lzx->frame_posn];
763  }
764  lzx->o_end = &lzx->o_ptr[frame_size];
765 
766  /* write a frame */
767  i = (out_bytes < (off_t)frame_size) ? (unsigned int)out_bytes : frame_size;
768  if (lzx->sys->write(lzx->output, lzx->o_ptr, i) != i) {
769  return lzx->error = MSPACK_ERR_WRITE;
770  }
771  lzx->o_ptr += i;
772  lzx->offset += i;
773  out_bytes -= i;
774 
775  /* advance frame start position */
776  lzx->frame_posn += frame_size;
777  lzx->frame++;
778 
779  /* wrap window / frame position pointers */
780  if (window_posn == lzx->window_size) window_posn = 0;
781  if (lzx->frame_posn == lzx->window_size) lzx->frame_posn = 0;
782 
783  } /* while (lzx->frame < end_frame) */
784 
785  if (out_bytes) {
786  D(("bytes left to output"))
787  return lzx->error = MSPACK_ERR_DECRUNCH;
788  }
789 
790  /* store local state */
791  STORE_BITS;
792  lzx->window_posn = window_posn;
793  lzx->R0 = R0;
794  lzx->R1 = R1;
795  lzx->R2 = R2;
796 
797  return MSPACK_ERR_OK;
798 }
#define D
Definition: block.c:38
#define LZX_NUM_CHARS
Definition: lzx.h:25
#define LZX_BLOCKTYPE_ALIGNED
Definition: lzx.h:28
#define LZX_NUM_SECONDARY_LENGTHS
Definition: lzx.h:33
#define LZX_BLOCKTYPE_VERBATIM
Definition: lzx.h:27
#define LZX_NUM_PRIMARY_LENGTHS
Definition: lzx.h:32
#define LZX_BLOCKTYPE_UNCOMPRESSED
Definition: lzx.h:29
#define LZX_FRAME_SIZE
Definition: lzx.h:46
#define LZX_MAX_MATCH
Definition: lzx.h:24
#define LZX_MIN_MATCH
Definition: lzx.h:23
static void lzxd_reset_state(struct lzxd_stream *lzx)
Definition: lzxd.c:262
#define READ_LENGTHS(tbl, first, last)
Definition: lzxd.c:131
static const unsigned char extra_bits[36]
Definition: lzxd.c:217
static const unsigned int position_base[290]
Definition: lzxd.c:221
#define BUILD_TABLE(tbl)
Definition: lzxd.c:103
#define BUILD_TABLE_MAYBE_EMPTY(tbl)
Definition: lzxd.c:111
#define MSPACK_ERR_OK
Definition: mspack.h:485
#define MSPACK_ERR_WRITE
Definition: mspack.h:493
#define MSPACK_ERR_ARGS
Definition: mspack.h:487
#define ENSURE_BITS(nbits)
Definition: readbits.h:125
#define RESTORE_BITS
Definition: readbits.h:118
#define STORE_BITS
Definition: readbits.h:111
#define REMOVE_BITS(nbits)
Definition: readbits.h:154
#define READ_BITS(val, nbits)
Definition: readbits.h:129
#define READ_IF_NEEDED
Definition: readbits.h:174
#define PEEK_BITS(nbits)
Definition: readbits.h:153
#define READ_HUFFSYM(tbl, var)
Definition: readhuff.h:34
#define NULL
Definition: cris-opc.c:27
@ LENGTH
Definition: inflate.h:48
voidpf void * buf
Definition: ioapi.h:138
static int
Definition: sfsocketcall.h:114
int off_t
Definition: sftypes.h:41
#define R0(i)
Definition: sha256.c:54
#define R2(i)
Definition: sha256.c:55
off_t length
Definition: lzx.h:54
unsigned int R1
Definition: lzx.h:65
unsigned int frame
Definition: lzx.h:62
off_t offset
Definition: lzx.h:53
struct mspack_system * sys
Definition: lzx.h:49
unsigned char intel_started
Definition: lzx.h:71
unsigned int ref_data_size
Definition: lzx.h:58
unsigned char * window
Definition: lzx.h:56
unsigned int R2
Definition: lzx.h:65
struct mspack_file * output
Definition: lzx.h:51
unsigned char * o_end
Definition: lzx.h:80
unsigned int block_remaining
Definition: lzx.h:67
unsigned int window_size
Definition: lzx.h:57
unsigned char ALIGNED_len[LZX_ALIGNED_MAXSYMBOLS+LZX_LENTABLE_SAFETY]
Definition: lzx.h:87
int error
Definition: lzx.h:77
signed int intel_filesize
Definition: lzx.h:69
unsigned char e8_buf[LZX_FRAME_SIZE]
Definition: lzx.h:101
unsigned char * o_ptr
Definition: lzx.h:80
unsigned char MAINTREE_len[LZX_MAINTREE_MAXSYMBOLS+LZX_LENTABLE_SAFETY]
Definition: lzx.h:85
unsigned int reset_interval
Definition: lzx.h:63
unsigned int block_length
Definition: lzx.h:66
unsigned int R0
Definition: lzx.h:65
unsigned int frame_posn
Definition: lzx.h:61
unsigned int num_offsets
Definition: lzx.h:59
unsigned int window_posn
Definition: lzx.h:60
unsigned char LENGTH_empty
Definition: lzx.h:98
unsigned char block_type
Definition: lzx.h:72
unsigned char is_delta
Definition: lzx.h:75
unsigned char header_read
Definition: lzx.h:73
void(* copy)(void *src, void *dest, size_t bytes)
Definition: mspack.h:444
void(* message)(struct mspack_file *file, const char *format,...)
Definition: mspack.h:407
int(* write)(struct mspack_file *file, void *buffer, int bytes)
Definition: mspack.h:353
void error(const char *msg)
Definition: untgz.c:593
if(dbg->bits==RZ_SYS_BITS_64)
Definition: windows-arm64.h:4
struct _window window

◆ lzxd_free()

void lzxd_free ( struct lzxd_stream lzx)

Frees all state associated with an LZX data stream. This will call system->free() using the system pointer given in lzxd_init().

Parameters
lzxLZX decompression state to free.

Definition at line 800 of file lzxd.c.

800  {
801  struct mspack_system *sys;
802  if (lzx) {
803  sys = lzx->sys;
804  sys->free(lzx->inbuf);
805  sys->free(lzx->window);
806  sys->free(lzx);
807  }
808 }
unsigned char * inbuf
Definition: lzx.h:80
void(* free)(void *ptr)
Definition: mspack.h:430

◆ lzxd_init()

struct lzxd_stream* lzxd_init ( struct mspack_system system,
struct mspack_file input,
struct mspack_file output,
int  window_bits,
int  reset_interval,
int  input_buffer_size,
off_t  output_length,
char  is_delta 
)

Allocates and initialises LZX decompression state for decoding an LZX stream.

This routine uses system->alloc() to allocate memory. If memory allocation fails, or the parameters to this function are invalid, NULL is returned.

Parameters
systeman mspack_system structure used to read from the input stream and write to the output stream, also to allocate and free memory.
inputan input stream with the LZX data.
outputan output stream to write the decoded data to.
window_bitsthe size of the decoding window, which must be between 15 and 21 inclusive for regular LZX data, or between 17 and 25 inclusive for LZX DELTA data.
reset_intervalthe interval at which the LZX bitstream is reset, in multiples of LZX frames (32678 bytes), e.g. a value of 2 indicates the input stream resets after every 65536 output bytes. A value of 0 indicates that the bitstream never resets, such as in CAB LZX streams.
input_buffer_sizethe number of bytes to use as an input bitstream buffer.
output_lengththe length in bytes of the entirely decompressed output stream, if known in advance. It is used to correctly perform the Intel E8 transformation, which must stop 6 bytes before the very end of the decompressed stream. It is not otherwise used or adhered to. If the full decompressed length is known in advance, set it here. If it is NOT known, use the value 0, and call lzxd_set_output_length() once it is known. If never set, 4 of the final 6 bytes of the output stream may be incorrect.
is_deltashould be zero for all regular LZX data, non-zero for LZX DELTA encoded data.
Returns
a pointer to an initialised lzxd_stream structure, or NULL if there was not enough memory or parameters to the function were wrong.

Definition at line 279 of file lzxd.c.

287 {
288  unsigned int window_size = 1 << window_bits;
289  struct lzxd_stream *lzx;
290 
291  if (!system) return NULL;
292 
293  /* LZX DELTA window sizes are between 2^17 (128KiB) and 2^25 (32MiB),
294  * regular LZX windows are between 2^15 (32KiB) and 2^21 (2MiB)
295  */
296  if (is_delta) {
297  if (window_bits < 17 || window_bits > 25) return NULL;
298  }
299  else {
300  if (window_bits < 15 || window_bits > 21) return NULL;
301  }
302 
303  if (reset_interval < 0 || output_length < 0) {
304  D(("reset interval or output length < 0"))
305  return NULL;
306  }
307 
308  /* round up input buffer size to multiple of two */
309  input_buffer_size = (input_buffer_size + 1) & -2;
310  if (input_buffer_size < 2) return NULL;
311 
312  /* allocate decompression state */
313  if (!(lzx = (struct lzxd_stream *) system->alloc(system, sizeof(struct lzxd_stream)))) {
314  return NULL;
315  }
316 
317  /* allocate decompression window and input buffer */
318  lzx->window = (unsigned char *) system->alloc(system, (size_t) window_size);
319  lzx->inbuf = (unsigned char *) system->alloc(system, (size_t) input_buffer_size);
320  if (!lzx->window || !lzx->inbuf) {
321  system->free(lzx->window);
322  system->free(lzx->inbuf);
323  system->free(lzx);
324  return NULL;
325  }
326 
327  /* initialise decompression state */
328  lzx->sys = system;
329  lzx->input = input;
330  lzx->output = output;
331  lzx->offset = 0;
332  lzx->length = output_length;
333 
334  lzx->inbuf_size = input_buffer_size;
335  lzx->window_size = 1 << window_bits;
336  lzx->ref_data_size = 0;
337  lzx->window_posn = 0;
338  lzx->frame_posn = 0;
339  lzx->frame = 0;
341  lzx->intel_filesize = 0;
342  lzx->intel_started = 0;
343  lzx->error = MSPACK_ERR_OK;
344  lzx->num_offsets = position_slots[window_bits - 15] << 3;
345  lzx->is_delta = is_delta;
346 
347  lzx->o_ptr = lzx->o_end = &lzx->e8_buf[0];
348  lzxd_reset_state(lzx);
349  INIT_BITS;
350  return lzx;
351 }
static const unsigned int position_slots[11]
Definition: lzxd.c:214
#define INIT_BITS
Definition: readbits.h:103
struct mspack_file * input
Definition: lzx.h:50
unsigned int inbuf_size
Definition: lzx.h:81
void *(* alloc)(struct mspack_system *self, size_t bytes)
Definition: mspack.h:421
static bool input(void *ud, zip_uint8_t *data, zip_uint64_t length)
diff_output_t output
Definition: zipcmp.c:237

◆ lzxd_read_lens()

static int lzxd_read_lens ( struct lzxd_stream lzx,
unsigned char *  lens,
unsigned int  first,
unsigned int  last 
)
static

Definition at line 138 of file lzxd.c.

140 {
141  /* bit buffer and huffman symbol decode variables */
142  register unsigned int bit_buffer;
143  register int bits_left, i;
144  register unsigned short sym;
145  unsigned char *i_ptr, *i_end;
146 
147  unsigned int x, y;
148  int z;
149 
150  RESTORE_BITS;
151 
152  /* read lengths for pretree (20 symbols, lengths stored in fixed 4 bits) */
153  for (x = 0; x < 20; x++) {
154  READ_BITS(y, 4);
155  lzx->PRETREE_len[x] = y;
156  }
157  BUILD_TABLE(PRETREE);
158 
159  for (x = first; x < last; ) {
160  READ_HUFFSYM(PRETREE, z);
161  if (z == 17) {
162  /* code = 17, run of ([read 4 bits]+4) zeros */
163  READ_BITS(y, 4); y += 4;
164  while (y--) lens[x++] = 0;
165  }
166  else if (z == 18) {
167  /* code = 18, run of ([read 5 bits]+20) zeros */
168  READ_BITS(y, 5); y += 20;
169  while (y--) lens[x++] = 0;
170  }
171  else if (z == 19) {
172  /* code = 19, run of ([read 1 bit]+4) [read huffman symbol] */
173  READ_BITS(y, 1); y += 4;
174  READ_HUFFSYM(PRETREE, z);
175  z = lens[x] - z; if (z < 0) z += 17;
176  while (y--) lens[x++] = z;
177  }
178  else {
179  /* code = 0 to 16, delta current length entry */
180  z = lens[x] - z; if (z < 0) z += 17;
181  lens[x++] = z;
182  }
183  }
184 
185  STORE_BITS;
186 
187  return MSPACK_ERR_OK;
188 }
int x
Definition: mipsasm.c:20
unsigned char PRETREE_len[LZX_PRETREE_MAXSYMBOLS+LZX_LENTABLE_SAFETY]
Definition: lzx.h:84

References BUILD_TABLE, i, MSPACK_ERR_OK, lzxd_stream::PRETREE_len, READ_BITS, READ_HUFFSYM, RESTORE_BITS, STORE_BITS, and x.

◆ lzxd_reset_state()

static void lzxd_reset_state ( struct lzxd_stream lzx)
static

Definition at line 262 of file lzxd.c.

262  {
263  int i;
264 
265  lzx->R0 = 1;
266  lzx->R1 = 1;
267  lzx->R2 = 1;
268  lzx->header_read = 0;
269  lzx->block_remaining = 0;
271 
272  /* initialise tables to 0 (because deltas will be applied to them) */
273  for (i = 0; i < LZX_MAINTREE_MAXSYMBOLS; i++) lzx->MAINTREE_len[i] = 0;
274  for (i = 0; i < LZX_LENGTH_MAXSYMBOLS; i++) lzx->LENGTH_len[i] = 0;
275 }
#define LZX_BLOCKTYPE_INVALID
Definition: lzx.h:26
#define LZX_MAINTREE_MAXSYMBOLS
Definition: lzx.h:38
#define LZX_LENGTH_MAXSYMBOLS
Definition: lzx.h:40
unsigned char LENGTH_len[LZX_LENGTH_MAXSYMBOLS+LZX_LENTABLE_SAFETY]
Definition: lzx.h:86

References lzxd_stream::block_remaining, lzxd_stream::block_type, lzxd_stream::header_read, i, lzxd_stream::LENGTH_len, LZX_BLOCKTYPE_INVALID, LZX_LENGTH_MAXSYMBOLS, LZX_MAINTREE_MAXSYMBOLS, lzxd_stream::MAINTREE_len, lzxd_stream::R0, lzxd_stream::R1, and lzxd_stream::R2.

Referenced by lzxd_decompress(), and lzxd_init().

◆ lzxd_set_output_length()

void lzxd_set_output_length ( struct lzxd_stream lzx,
off_t  out_bytes 
)

Definition at line 389 of file lzxd.c.

389  {
390  if (lzx && out_bytes > 0) lzx->length = out_bytes;
391 }

◆ lzxd_set_reference_data()

int lzxd_set_reference_data ( struct lzxd_stream lzx,
struct mspack_system system,
struct mspack_file input,
unsigned int  length 
)

Reads LZX DELTA reference data into the window and allows lzxd_decompress() to reference it.

Call this before the first call to lzxd_decompress().

Parameters
lzxthe LZX stream to apply this reference data to
systeman mspack_system implementation to use with the input param. Only read() will be called.
inputan input file handle to read reference data using system->read().
lengththe length of the reference data. Cannot be longer than the LZX window size.
Returns
an error code, or MSPACK_ERR_OK if successful

Definition at line 353 of file lzxd.c.

357 {
358  if (!lzx) return MSPACK_ERR_ARGS;
359 
360  if (!lzx->is_delta) {
361  D(("only LZX DELTA streams support reference data"))
362  return MSPACK_ERR_ARGS;
363  }
364  if (lzx->offset) {
365  D(("too late to set reference data after decoding starts"))
366  return MSPACK_ERR_ARGS;
367  }
368  if (length > lzx->window_size) {
369  D(("reference length (%u) is longer than the window", length))
370  return MSPACK_ERR_ARGS;
371  }
372  if (length > 0 && (!system || !input)) {
373  D(("length > 0 but no system or input"))
374  return MSPACK_ERR_ARGS;
375  }
376 
377  lzx->ref_data_size = length;
378  if (length > 0) {
379  /* copy reference data */
380  unsigned char *pos = &lzx->window[lzx->window_size - length];
381  int bytes = system->read(input, pos, length);
382  /* length can't be more than 2^25, so no signedness problem */
383  if (bytes < (int)length) return MSPACK_ERR_READ;
384  }
385  lzx->ref_data_size = length;
386  return MSPACK_ERR_OK;
387 }
static ut8 bytes[32]
Definition: asm_arc.c:23
#define MSPACK_ERR_READ
Definition: mspack.h:491
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags static arg static fd static protocol static who struct sockaddr static addrlen static backlog struct timeval struct timezone static tz const struct iovec static count static mode const void const struct sockaddr static tolen const char static pathname void static offset struct stat static buf void long static basep static whence static length const void static len static semflg const void static shmflg const struct timespec struct timespec static rem const char static group const void length
Definition: sflib.h:133
voidpf uLong offset
Definition: ioapi.h:144
int(* read)(struct mspack_file *file, void *buffer, int bytes)
Definition: mspack.h:336
int pos
Definition: main.c:11

Variable Documentation

◆ extra_bits

const unsigned char extra_bits[36]
static
Initial value:
= {
0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8,
9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16
}

Definition at line 217 of file lzxd.c.

Referenced by lzxd_decompress().

◆ position_base

const unsigned int position_base[290]
static

Definition at line 221 of file lzxd.c.

Referenced by lzxd_decompress().

◆ position_slots

const unsigned int position_slots[11]
static
Initial value:
= {
30, 32, 34, 36, 38, 42, 50, 66, 98, 162, 290
}

Definition at line 214 of file lzxd.c.

Referenced by lzxd_init().