FreeBASIC  0.91.0
gfx_lzw.c
Go to the documentation of this file.
1 /* tiny LZW codec
2  * Based on code by Mark Nelson, Dr. Dobb's Journal October, 1989
3  */
4 
5 #include "fb_gfx.h"
6 #include "fb_gfx_lzw.h"
7 
9 
10 static unsigned char *decode_string(unsigned char *buffer, int code)
11 {
12  int index = 0;
13 
14  while (code > 255) {
15  *buffer++ = fb_lzw_entry[code].value;
16  code = fb_lzw_entry[code].prefix;
17  if (index++ >= MAX_CODE - 1)
18  return NULL;
19  }
20  *buffer = code;
21  return buffer;
22 }
23 
25  (
26  const unsigned char *in_buffer,
27  ssize_t in_size,
28  unsigned char *out_buffer,
29  ssize_t *out_size
30  )
31 {
32  unsigned short new_code, old_code, next_code = 256;
33  unsigned char *limit, decode_stack[MAX_CODE], *string, byte, bit = 0;
34 
35  INPUT_CODE(old_code);
36  byte = old_code;
37  *out_buffer++ = old_code;
38  limit = out_buffer + *out_size;
39  *out_size = 1;
40  while (in_size > 0) {
41  INPUT_CODE(new_code);
42  if (new_code == MAX_CODE)
43  return 0;
44  if (new_code >= next_code) {
45  *decode_stack = byte;
46  string = decode_string(decode_stack + 1, old_code);
47  }
48  else
49  string = decode_string(decode_stack, new_code);
50  if (!string)
51  return -1;
52  byte = *string;
53  while (string >= decode_stack) {
54  if (out_buffer >= limit)
55  return -1;
56  *out_buffer++ = *string--;
57  (*out_size)++;
58  }
59  if (next_code < MAX_CODE) {
60  fb_lzw_entry[next_code].prefix = old_code;
61  fb_lzw_entry[next_code].value = byte;
62  next_code++;
63  }
64  old_code = new_code;
65  }
66  return -1;
67 }