Rizin
unix-like reverse engineering framework and cli tools
qtm.h File Reference

Go to the source code of this file.

Classes

struct  qtmd_modelsym
 
struct  qtmd_model
 
struct  qtmd_stream
 

Macros

#define QTM_FRAME_SIZE   (32768)
 

Functions

struct qtmd_streamqtmd_init (struct mspack_system *system, struct mspack_file *input, struct mspack_file *output, int window_bits, int input_buffer_size)
 
int qtmd_decompress (struct qtmd_stream *qtm, off_t out_bytes)
 
void qtmd_free (struct qtmd_stream *qtm)
 

Macro Definition Documentation

◆ QTM_FRAME_SIZE

#define QTM_FRAME_SIZE   (32768)

Definition at line 22 of file qtm.h.

Function Documentation

◆ qtmd_decompress()

int qtmd_decompress ( struct qtmd_stream qtm,
off_t  out_bytes 
)

Definition at line 256 of file qtmd.c.

256  {
257  unsigned int frame_todo, frame_end, window_posn, match_offset, range;
258  unsigned char *window, *i_ptr, *i_end, *runsrc, *rundest;
259  int i, j, selector, extra, sym, match_length;
260  unsigned short H, L, C, symf;
261 
262  register unsigned int bit_buffer;
263  register unsigned char bits_left;
264 
265  /* easy answers */
266  if (!qtm || (out_bytes < 0)) return MSPACK_ERR_ARGS;
267  if (qtm->error) return qtm->error;
268 
269  /* flush out any stored-up bytes before we begin */
270  i = qtm->o_end - qtm->o_ptr;
271  if ((off_t) i > out_bytes) i = (int) out_bytes;
272  if (i) {
273  if (qtm->sys->write(qtm->output, qtm->o_ptr, i) != i) {
274  return qtm->error = MSPACK_ERR_WRITE;
275  }
276  qtm->o_ptr += i;
277  out_bytes -= i;
278  }
279  if (out_bytes == 0) return MSPACK_ERR_OK;
280 
281  /* restore local state */
282  RESTORE_BITS;
283  window = qtm->window;
284  window_posn = qtm->window_posn;
285  frame_todo = qtm->frame_todo;
286  H = qtm->H;
287  L = qtm->L;
288  C = qtm->C;
289 
290  /* while we do not have enough decoded bytes in reserve: */
291  while ((qtm->o_end - qtm->o_ptr) < out_bytes) {
292  /* read header if necessary. Initialises H, L and C */
293  if (!qtm->header_read) {
294  H = 0xFFFF; L = 0; READ_BITS(C, 16);
295  qtm->header_read = 1;
296  }
297 
298  /* decode more, up to the number of bytes needed, the frame boundary,
299  * or the window boundary, whichever comes first */
300  frame_end = window_posn + (out_bytes - (qtm->o_end - qtm->o_ptr));
301  if ((window_posn + frame_todo) < frame_end) {
302  frame_end = window_posn + frame_todo;
303  }
304  if (frame_end > qtm->window_size) {
305  frame_end = qtm->window_size;
306  }
307 
308  while (window_posn < frame_end) {
309  GET_SYMBOL(qtm->model7, selector);
310  if (selector < 4) {
311  /* literal byte */
312  struct qtmd_model *mdl = (selector == 0) ? &qtm->model0 :
313  ((selector == 1) ? &qtm->model1 :
314  ((selector == 2) ? &qtm->model2 :
315  &qtm->model3));
316  GET_SYMBOL((*mdl), sym);
317  window[window_posn++] = sym;
318  frame_todo--;
319  }
320  else {
321  /* match repeated string */
322  switch (selector) {
323  case 4: /* selector 4 = fixed length match (3 bytes) */
324  GET_SYMBOL(qtm->model4, sym);
325  READ_MANY_BITS(extra, extra_bits[sym]);
326  match_offset = position_base[sym] + extra + 1;
327  match_length = 3;
328  break;
329 
330  case 5: /* selector 5 = fixed length match (4 bytes) */
331  GET_SYMBOL(qtm->model5, sym);
332  READ_MANY_BITS(extra, extra_bits[sym]);
333  match_offset = position_base[sym] + extra + 1;
334  match_length = 4;
335  break;
336 
337  case 6: /* selector 6 = variable length match */
338  GET_SYMBOL(qtm->model6len, sym);
339  READ_MANY_BITS(extra, length_extra[sym]);
340  match_length = length_base[sym] + extra + 5;
341 
342  GET_SYMBOL(qtm->model6, sym);
343  READ_MANY_BITS(extra, extra_bits[sym]);
344  match_offset = position_base[sym] + extra + 1;
345  break;
346 
347  default:
348  /* should be impossible, model7 can only return 0-6 */
349  D(("got %d from selector", selector))
350  return qtm->error = MSPACK_ERR_DECRUNCH;
351  }
352 
353  rundest = &window[window_posn];
354  frame_todo -= match_length;
355 
356  /* does match destination wrap the window? This situation is possible
357  * where the window size is less than the 32k frame size, but matches
358  * must not go beyond a frame boundary */
359  if ((window_posn + match_length) > qtm->window_size) {
360  /* copy first part of match, before window end */
361  i = qtm->window_size - window_posn;
362  j = window_posn - match_offset;
363  while (i--) *rundest++ = window[j++ & (qtm->window_size - 1)];
364 
365  /* flush currently stored data */
366  i = (&window[qtm->window_size] - qtm->o_ptr);
367 
368  /* this should not happen, but if it does then this code
369  * can't handle the situation (can't flush up to the end of
370  * the window, but can't break out either because we haven't
371  * finished writing the match). bail out in this case */
372  if (i > out_bytes) {
373  D(("during window-wrap match; %d bytes to flush but only need %d",
374  i, (int) out_bytes))
375  return qtm->error = MSPACK_ERR_DECRUNCH;
376  }
377  if (qtm->sys->write(qtm->output, qtm->o_ptr, i) != i) {
378  return qtm->error = MSPACK_ERR_WRITE;
379  }
380  out_bytes -= i;
381  qtm->o_ptr = &window[0];
382  qtm->o_end = &window[0];
383 
384  /* copy second part of match, after window wrap */
385  rundest = &window[0];
386  i = match_length - (qtm->window_size - window_posn);
387  while (i--) *rundest++ = window[j++ & (qtm->window_size - 1)];
388  window_posn = window_posn + match_length - qtm->window_size;
389 
390  break; /* because "window_posn < frame_end" has now failed */
391  }
392  else {
393  /* normal match - output won't wrap window or frame end */
394  i = match_length;
395 
396  /* does match _offset_ wrap the window? */
397  if (match_offset > window_posn) {
398  /* j = length from match offset to end of window */
399  j = match_offset - window_posn;
400  if (j > (int) qtm->window_size) {
401  D(("match offset beyond window boundaries"))
402  return qtm->error = MSPACK_ERR_DECRUNCH;
403  }
404  runsrc = &window[qtm->window_size - j];
405  if (j < i) {
406  /* if match goes over the window edge, do two copy runs */
407  i -= j; while (j-- > 0) *rundest++ = *runsrc++;
408  runsrc = window;
409  }
410  while (i-- > 0) *rundest++ = *runsrc++;
411  }
412  else {
413  runsrc = rundest - match_offset;
414  while (i-- > 0) *rundest++ = *runsrc++;
415  }
416  window_posn += match_length;
417  }
418  } /* if (window_posn+match_length > frame_end) */
419  } /* while (window_posn < frame_end) */
420 
421  qtm->o_end = &window[window_posn];
422 
423  /* if we subtracted too much from frame_todo, it will
424  * wrap around past zero and go above its max value */
425  if (frame_todo > QTM_FRAME_SIZE) {
426  D(("overshot frame alignment"))
427  return qtm->error = MSPACK_ERR_DECRUNCH;
428  }
429 
430  /* another frame completed? */
431  if (frame_todo == 0) {
432  /* re-align input */
433  if (bits_left & 7) REMOVE_BITS(bits_left & 7);
434 
435  /* special Quantum hack -- cabd.c injects a trailer byte to allow the
436  * decompressor to realign itself. CAB Quantum blocks, unlike LZX
437  * blocks, can have anything from 0 to 4 trailing null bytes. */
438  do { READ_BITS(i, 8); } while (i != 0xFF);
439 
440  qtm->header_read = 0;
441 
442  frame_todo = QTM_FRAME_SIZE;
443  }
444 
445  /* window wrap? */
446  if (window_posn == qtm->window_size) {
447  /* flush all currently stored data */
448  i = (qtm->o_end - qtm->o_ptr);
449  /* break out if we have more than enough to finish this request */
450  if (i >= out_bytes) break;
451  if (qtm->sys->write(qtm->output, qtm->o_ptr, i) != i) {
452  return qtm->error = MSPACK_ERR_WRITE;
453  }
454  out_bytes -= i;
455  qtm->o_ptr = &window[0];
456  qtm->o_end = &window[0];
457  window_posn = 0;
458  }
459 
460  } /* while (more bytes needed) */
461 
462  if (out_bytes) {
463  i = (int) out_bytes;
464  if (qtm->sys->write(qtm->output, qtm->o_ptr, i) != i) {
465  return qtm->error = MSPACK_ERR_WRITE;
466  }
467  qtm->o_ptr += i;
468  }
469 
470  /* store local state */
471 
472  STORE_BITS;
473  qtm->window_posn = window_posn;
474  qtm->frame_todo = frame_todo;
475  qtm->H = H;
476  qtm->L = L;
477  qtm->C = C;
478 
479  return MSPACK_ERR_OK;
480 }
lzma_index ** i
Definition: index.h:629
#define C(x)
Definition: arc.h:167
#define H(x)
#define D
Definition: block.c:38
#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 MSPACK_ERR_DECRUNCH
Definition: mspack.h:507
#define QTM_FRAME_SIZE
Definition: qtm.h:22
static const unsigned int position_base[42]
Definition: qtmd.c:66
#define GET_SYMBOL(model, var)
Definition: qtmd.c:92
static const unsigned char length_extra[27]
Definition: qtmd.c:79
static const unsigned char extra_bits[42]
Definition: qtmd.c:71
static const unsigned char length_base[27]
Definition: qtmd.c:75
#define RESTORE_BITS
Definition: readbits.h:118
#define STORE_BITS
Definition: readbits.h:111
#define REMOVE_BITS(nbits)
Definition: readbits.h:154
#define READ_MANY_BITS(val, bits)
Definition: readbits.h:135
#define READ_BITS(val, nbits)
Definition: readbits.h:129
static int
Definition: sfsocketcall.h:114
int off_t
Definition: sftypes.h:41
int(* write)(struct mspack_file *file, void *buffer, int bytes)
Definition: mspack.h:353
Definition: qtm.h:28
unsigned short H
Definition: qtm.h:43
struct qtmd_model model7
Definition: qtm.h:67
unsigned char * o_end
Definition: qtm.h:49
struct mspack_system * sys
Definition: qtm.h:34
struct qtmd_model model0 model1 model2 model3
Definition: qtm.h:58
int error
Definition: qtm.h:46
unsigned char * window
Definition: qtm.h:38
struct mspack_file * output
Definition: qtm.h:36
unsigned char * o_ptr
Definition: qtm.h:49
unsigned int frame_todo
Definition: qtm.h:41
unsigned char header_read
Definition: qtm.h:44
unsigned int window_size
Definition: qtm.h:39
unsigned short C
Definition: qtm.h:43
unsigned short L
Definition: qtm.h:43
struct qtmd_model model4 model5 model6 model6len
Definition: qtm.h:64
unsigned int window_posn
Definition: qtm.h:40
void error(const char *msg)
Definition: untgz.c:593
if(dbg->bits==RZ_SYS_BITS_64)
Definition: windows-arm64.h:4
struct _window window
#define L
Definition: zip_err_str.c:7

References qtmd_stream::bit_buffer, qtmd_stream::bits_left, C, qtmd_stream::C, D, qtmd_stream::error, extra_bits, qtmd_stream::frame_todo, GET_SYMBOL, H, qtmd_stream::H, qtmd_stream::header_read, i, qtmd_stream::i_end, qtmd_stream::i_ptr, int, L, qtmd_stream::L, length_base, length_extra, qtmd_stream::model3, qtmd_stream::model6len, qtmd_stream::model7, MSPACK_ERR_ARGS, MSPACK_ERR_DECRUNCH, MSPACK_ERR_OK, MSPACK_ERR_WRITE, qtmd_stream::o_end, qtmd_stream::o_ptr, qtmd_stream::output, position_base, QTM_FRAME_SIZE, capstone::range, READ_BITS, READ_MANY_BITS, REMOVE_BITS, RESTORE_BITS, STORE_BITS, qtmd_stream::sys, qtmd_stream::window, qtmd_stream::window_posn, qtmd_stream::window_size, and mspack_system::write.

Referenced by cabd_init_decomp().

◆ qtmd_free()

void qtmd_free ( struct qtmd_stream qtm)

Definition at line 482 of file qtmd.c.

482  {
483  struct mspack_system *sys;
484  if (qtm) {
485  sys = qtm->sys;
486  sys->free(qtm->window);
487  sys->free(qtm->inbuf);
488  sys->free(qtm);
489  }
490 }
void(* free)(void *ptr)
Definition: mspack.h:430
unsigned char * inbuf
Definition: qtm.h:49

References mspack_system::free, qtmd_stream::inbuf, qtmd_stream::sys, and qtmd_stream::window.

Referenced by cabd_free_decomp().

◆ qtmd_init()

struct qtmd_stream* qtmd_init ( struct mspack_system system,
struct mspack_file input,
struct mspack_file output,
int  window_bits,
int  input_buffer_size 
)

Definition at line 186 of file qtmd.c.

190 {
191  unsigned int window_size = 1 << window_bits;
192  struct qtmd_stream *qtm;
193  int i;
194 
195  if (!system) return NULL;
196 
197  /* Quantum supports window sizes of 2^10 (1Kb) through 2^21 (2Mb) */
198  if (window_bits < 10 || window_bits > 21) return NULL;
199 
200  /* round up input buffer size to multiple of two */
201  input_buffer_size = (input_buffer_size + 1) & -2;
202  if (input_buffer_size < 2) return NULL;
203 
204  /* allocate decompression state */
205  if (!(qtm = (struct qtmd_stream *) system->alloc(system, sizeof(struct qtmd_stream)))) {
206  return NULL;
207  }
208 
209  /* allocate decompression window and input buffer */
210  qtm->window = (unsigned char *) system->alloc(system, (size_t) window_size);
211  qtm->inbuf = (unsigned char *) system->alloc(system, (size_t) input_buffer_size);
212  if (!qtm->window || !qtm->inbuf) {
213  system->free(qtm->window);
214  system->free(qtm->inbuf);
215  system->free(qtm);
216  return NULL;
217  }
218 
219  /* initialise decompression state */
220  qtm->sys = system;
221  qtm->input = input;
222  qtm->output = output;
223  qtm->inbuf_size = input_buffer_size;
224  qtm->window_size = window_size;
225  qtm->window_posn = 0;
226  qtm->frame_todo = QTM_FRAME_SIZE;
227  qtm->header_read = 0;
228  qtm->error = MSPACK_ERR_OK;
229 
230  qtm->i_ptr = qtm->i_end = &qtm->inbuf[0];
231  qtm->o_ptr = qtm->o_end = &qtm->window[0];
232  qtm->input_end = 0;
233  qtm->bits_left = 0;
234  qtm->bit_buffer = 0;
235 
236  /* initialise arithmetic coding models
237  * - model 4 depends on window size, ranges from 20 to 24
238  * - model 5 depends on window size, ranges from 20 to 36
239  * - model 6pos depends on window size, ranges from 20 to 42
240  */
241  i = window_bits * 2;
242  qtmd_init_model(&qtm->model0, &qtm->m0sym[0], 0, 64);
243  qtmd_init_model(&qtm->model1, &qtm->m1sym[0], 64, 64);
244  qtmd_init_model(&qtm->model2, &qtm->m2sym[0], 128, 64);
245  qtmd_init_model(&qtm->model3, &qtm->m3sym[0], 192, 64);
246  qtmd_init_model(&qtm->model4, &qtm->m4sym[0], 0, (i > 24) ? 24 : i);
247  qtmd_init_model(&qtm->model5, &qtm->m5sym[0], 0, (i > 36) ? 36 : i);
248  qtmd_init_model(&qtm->model6, &qtm->m6sym[0], 0, i);
249  qtmd_init_model(&qtm->model6len, &qtm->m6lsym[0], 0, 27);
250  qtmd_init_model(&qtm->model7, &qtm->m7sym[0], 0, 7);
251 
252  /* all ok */
253  return qtm;
254 }
static void qtmd_init_model(struct qtmd_model *model, struct qtmd_modelsym *syms, int start, int len)
Definition: qtmd.c:168
#define NULL
Definition: cris-opc.c:27
void *(* alloc)(struct mspack_system *self, size_t bytes)
Definition: mspack.h:421
unsigned char * i_end
Definition: qtm.h:49
struct qtmd_modelsym m1sym[64+1]
Definition: qtm.h:71
struct qtmd_modelsym m2sym[64+1]
Definition: qtm.h:72
struct qtmd_modelsym m6sym[42+1]
Definition: qtm.h:76
struct qtmd_modelsym m7sym[7+1]
Definition: qtm.h:77
struct mspack_file * input
Definition: qtm.h:35
unsigned char * i_ptr
Definition: qtm.h:49
unsigned char input_end
Definition: qtm.h:51
unsigned int bit_buffer
Definition: qtm.h:50
struct qtmd_modelsym m4sym[24+1]
Definition: qtm.h:74
unsigned int inbuf_size
Definition: qtm.h:50
struct qtmd_modelsym m6lsym[27+1]
Definition: qtm.h:76
struct qtmd_modelsym m3sym[64+1]
Definition: qtm.h:73
unsigned char bits_left
Definition: qtm.h:51
struct qtmd_modelsym m5sym[36+1]
Definition: qtm.h:75
struct qtmd_modelsym m0sym[64+1]
Definition: qtm.h:70
static bool input(void *ud, zip_uint8_t *data, zip_uint64_t length)
diff_output_t output
Definition: zipcmp.c:237

References mspack_system::alloc, qtmd_stream::bit_buffer, qtmd_stream::bits_left, qtmd_stream::error, qtmd_stream::frame_todo, mspack_system::free, qtmd_stream::header_read, i, qtmd_stream::i_end, qtmd_stream::i_ptr, qtmd_stream::inbuf, qtmd_stream::inbuf_size, qtmd_stream::input, input(), qtmd_stream::input_end, qtmd_stream::m0sym, qtmd_stream::m1sym, qtmd_stream::m2sym, qtmd_stream::m3sym, qtmd_stream::m4sym, qtmd_stream::m5sym, qtmd_stream::m6lsym, qtmd_stream::m6sym, qtmd_stream::m7sym, qtmd_stream::model3, qtmd_stream::model6len, qtmd_stream::model7, MSPACK_ERR_OK, NULL, qtmd_stream::o_end, qtmd_stream::o_ptr, qtmd_stream::output, output, QTM_FRAME_SIZE, qtmd_init_model(), qtmd_stream::sys, qtmd_stream::window, qtmd_stream::window_posn, and qtmd_stream::window_size.

Referenced by cabd_init_decomp().