e33156039ee40f65c6e184e12eafa8117551cea0
[firmware_extractor.git] / lzw_decode.c
1 /*
2  * LZW decoder
3  * Copyright (c) 2003 Fabrice Bellard.
4  * Copyright (c) 2006 Konstantin Shishkov.
5  *
6  * This file is part of FFmpeg.
7  *
8  * FFmpeg is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * FFmpeg is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with FFmpeg; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22
23
24 #ifdef COMPRESSED_CONFIG_FILE
25
26 #include "cms_lzw.h"
27
28
29
30 static const uint16_t mask[17] =
31 {
32     0x0000, 0x0001, 0x0003, 0x0007,
33     0x000F, 0x001F, 0x003F, 0x007F,
34     0x00FF, 0x01FF, 0x03FF, 0x07FF,
35     0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF
36 };
37
38
39 enum FF_LZW_MODES{
40     FF_LZW_GIF,
41     FF_LZW_TIFF
42 };
43
44
45 /* get one code from stream */
46 static int lzw_get_code(LZWDecoderState *s)
47 {
48     int c;
49
50     /* always use TIFF mode */
51
52     while (s->bbits < s->cursize) {
53         s->bbuf = (s->bbuf << 8) | (*s->pbuf++);
54         s->bbits += 8;
55     }
56     //    printf("TIFF: bbuf=0x%08x bbits=%d cursize=%d\n", s->bbuf, s->bbits, s->cursize);
57     c = s->bbuf >> (s->bbits - s->cursize);
58
59     s->bbits -= s->cursize;
60
61     //    printf("bbits=%d c=0x%08x curmask=0x%08x\n", s->bbits, c, s->curmask);
62     return c & s->curmask;
63 }
64
65
66 void ff_lzw_decode_tail(LZWDecoderState *s)
67 {
68     /* always use TIFF mode */
69     s->pbuf= s->ebuf;
70 }
71
72
73 CmsRet cmsLzw_initDecoder(LZWDecoderState **p, UINT8 *inbuf, UINT32 inbuf_size)
74 {
75     LZWDecoderState *s;
76     int mode = FF_LZW_TIFF;  /* always use TIFF mode */
77     int csize = 8;  /* the encoder side has this hardcoded, so hardcode here too */
78
79     *p = (LZWDecoderState *) cmsMem_alloc(sizeof(LZWDecoderState), ALLOC_ZEROIZE);
80     if (*p == NULL)
81     {
82        cmsLog_error("could not allocate %d bytes for decoder state", sizeof(LZWDecoderState));
83        return CMSRET_RESOURCE_EXCEEDED;
84     }
85     else
86     {
87        cmsLog_debug("%d bytes allocated for decoder state", sizeof(LZWDecoderState));
88     }
89
90     s = *p;
91
92     /* read buffer */
93     s->pbuf = inbuf;
94     s->ebuf = s->pbuf + inbuf_size;
95     s->bbuf = 0;
96     s->bbits = 0;
97     s->bs = 0;
98
99     /* decoder */
100     s->codesize = csize;
101     s->cursize = s->codesize + 1;
102     s->curmask = mask[s->cursize];
103     s->top_slot = 1 << s->cursize;
104     s->clear_code = 1 << s->codesize;
105     s->end_code = s->clear_code + 1;
106     s->slot = s->newcodes = s->clear_code + 2;
107     s->oc = s->fc = -1;
108     s->sp = s->stack;
109
110     s->mode = mode;
111     s->extra_slot = (s->mode == FF_LZW_TIFF);
112
113     return CMSRET_SUCCESS;
114 }
115
116
117 SINT32 cmsLzw_decode(LZWDecoderState *s, UINT8 *outbuf, UINT32 outlen)
118 {
119     UINT32 l;
120     int c, code, oc, fc;
121     uint8_t *sp;
122
123     if (s->end_code < 0)
124         return -1;
125
126     l = outlen;
127     sp = s->sp;
128     oc = s->oc;
129     fc = s->fc;
130
131     for (;;) {
132
133         while (sp > s->stack) {
134            //           printf("transfer stack to buf, sp=0x%02x buf=%p\n", *sp, outbuf);
135             *outbuf++ = *(--sp);
136             if ((--l) == 0)
137                 goto the_end;
138         }
139
140         c = lzw_get_code(s);
141         if (c == s->end_code) {
142             cmsLog_debug("got end code %d", c);
143             break;
144         } else if (c == s->clear_code) {
145             cmsLog_debug("got clear code %d", c);
146             s->cursize = s->codesize + 1;
147             s->curmask = mask[s->cursize];
148             s->slot = s->newcodes;
149             s->top_slot = 1 << s->cursize;
150             fc= oc= -1;
151         } else {
152             code = c;
153             //            printf("got valid code %d (0x%02x)\n", c, c);
154
155             if (code == s->slot && fc>=0) {
156                 *sp++ = fc;
157                 code = oc;
158             }else if(code >= s->slot) {
159                 cmsLog_error("code %d greater than slot %d", code, s->slot);
160                 break;
161             }
162
163             while (code >= s->newcodes) {
164                //               printf("transfer suffix to to sp \n");
165                 *sp++ = s->suffix[code];
166                 code = s->prefix[code];
167             }
168
169             //            printf("sp=%p gets code %d\n", sp, code);
170             *sp++ = code;
171
172
173             if (s->slot < s->top_slot && oc>=0) {
174                //                printf("suffix[%d]=%d prefix[%d]=%d\n", s->slot, code, s->slot, oc);
175                 s->suffix[s->slot] = code;
176                 s->prefix[s->slot++] = oc;
177             }
178             fc = code;
179             oc = c;
180
181             if (s->slot >= s->top_slot - s->extra_slot) {
182                 if (s->cursize < LZW_MAXBITS) {
183                     s->top_slot <<= 1;
184                     s->curmask = mask[++s->cursize];
185                     //                    printf("new top_slot=0x%x curmask=0x%x\n", s->top_slot, s->curmask);
186                 }
187             }
188         }
189     }  // end of for loop
190
191
192     s->end_code = -1;
193   the_end:
194     s->sp = sp;
195     s->oc = oc;
196     s->fc = fc;
197
198     cmsLog_debug("about to return, outlen=%d l=%d\n", outlen, l);
199     return outlen - l;
200 }
201
202
203
204 void cmsLzw_cleanupDecoder(LZWDecoderState **s)
205 {
206    cmsMem_free(*s);
207    *s = NULL;
208 }
209
210
211
212 #endif /* COMPRESSED_CONFIG_FILE */