yading@10: /* yading@10: * LZW decoder yading@10: * Copyright (c) 2003 Fabrice Bellard yading@10: * Copyright (c) 2006 Konstantin Shishkov yading@10: * yading@10: * This file is part of FFmpeg. yading@10: * yading@10: * FFmpeg is free software; you can redistribute it and/or yading@10: * modify it under the terms of the GNU Lesser General Public yading@10: * License as published by the Free Software Foundation; either yading@10: * version 2.1 of the License, or (at your option) any later version. yading@10: * yading@10: * FFmpeg is distributed in the hope that it will be useful, yading@10: * but WITHOUT ANY WARRANTY; without even the implied warranty of yading@10: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU yading@10: * Lesser General Public License for more details. yading@10: * yading@10: * You should have received a copy of the GNU Lesser General Public yading@10: * License along with FFmpeg; if not, write to the Free Software yading@10: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA yading@10: */ yading@10: yading@10: /** yading@10: * @file yading@10: * @brief LZW decoding routines yading@10: * @author Fabrice Bellard yading@10: * @author modified for use in TIFF by Konstantin Shishkov yading@10: */ yading@10: yading@10: #include "avcodec.h" yading@10: #include "lzw.h" yading@10: #include "libavutil/mem.h" yading@10: yading@10: #define LZW_MAXBITS 12 yading@10: #define LZW_SIZTABLE (1<mode == FF_LZW_GIF) { yading@10: while (s->bbits < s->cursize) { yading@10: if (!s->bs) { yading@10: s->bs = *s->pbuf++; yading@10: } yading@10: s->bbuf |= (*s->pbuf++) << s->bbits; yading@10: s->bbits += 8; yading@10: s->bs--; yading@10: } yading@10: c = s->bbuf; yading@10: s->bbuf >>= s->cursize; yading@10: } else { // TIFF yading@10: while (s->bbits < s->cursize) { yading@10: s->bbuf = (s->bbuf << 8) | (*s->pbuf++); yading@10: s->bbits += 8; yading@10: } yading@10: c = s->bbuf >> (s->bbits - s->cursize); yading@10: } yading@10: s->bbits -= s->cursize; yading@10: return c & s->curmask; yading@10: } yading@10: yading@10: void ff_lzw_decode_tail(LZWState *p) yading@10: { yading@10: struct LZWState *s = (struct LZWState *)p; yading@10: yading@10: if(s->mode == FF_LZW_GIF) { yading@10: while (s->bs > 0) { yading@10: if (s->bs >= s->ebuf - s->pbuf) { yading@10: s->pbuf = s->ebuf; yading@10: break; yading@10: } else { yading@10: s->pbuf += s->bs; yading@10: s->bs = *s->pbuf++; yading@10: } yading@10: } yading@10: }else yading@10: s->pbuf= s->ebuf; yading@10: } yading@10: yading@10: av_cold void ff_lzw_decode_open(LZWState **p) yading@10: { yading@10: *p = av_mallocz(sizeof(struct LZWState)); yading@10: } yading@10: yading@10: av_cold void ff_lzw_decode_close(LZWState **p) yading@10: { yading@10: av_freep(p); yading@10: } yading@10: yading@10: /** yading@10: * Initialize LZW decoder yading@10: * @param p LZW context yading@10: * @param csize initial code size in bits yading@10: * @param buf input data yading@10: * @param buf_size input data size yading@10: * @param mode decoder working mode - either GIF or TIFF yading@10: */ yading@10: int ff_lzw_decode_init(LZWState *p, int csize, const uint8_t *buf, int buf_size, int mode) yading@10: { yading@10: struct LZWState *s = (struct LZWState *)p; yading@10: yading@10: if(csize < 1 || csize >= LZW_MAXBITS) yading@10: return -1; yading@10: /* read buffer */ yading@10: s->pbuf = buf; yading@10: s->ebuf = s->pbuf + buf_size; yading@10: s->bbuf = 0; yading@10: s->bbits = 0; yading@10: s->bs = 0; yading@10: yading@10: /* decoder */ yading@10: s->codesize = csize; yading@10: s->cursize = s->codesize + 1; yading@10: s->curmask = mask[s->cursize]; yading@10: s->top_slot = 1 << s->cursize; yading@10: s->clear_code = 1 << s->codesize; yading@10: s->end_code = s->clear_code + 1; yading@10: s->slot = s->newcodes = s->clear_code + 2; yading@10: s->oc = s->fc = -1; yading@10: s->sp = s->stack; yading@10: yading@10: s->mode = mode; yading@10: s->extra_slot = s->mode == FF_LZW_TIFF; yading@10: return 0; yading@10: } yading@10: yading@10: /** yading@10: * Decode given number of bytes yading@10: * NOTE: the algorithm here is inspired from the LZW GIF decoder yading@10: * written by Steven A. Bennett in 1987. yading@10: * yading@10: * @param p LZW context yading@10: * @param buf output buffer yading@10: * @param len number of bytes to decode yading@10: * @return number of bytes decoded yading@10: */ yading@10: int ff_lzw_decode(LZWState *p, uint8_t *buf, int len){ yading@10: int l, c, code, oc, fc; yading@10: uint8_t *sp; yading@10: struct LZWState *s = (struct LZWState *)p; yading@10: yading@10: if (s->end_code < 0) yading@10: return 0; yading@10: yading@10: l = len; yading@10: sp = s->sp; yading@10: oc = s->oc; yading@10: fc = s->fc; yading@10: yading@10: for (;;) { yading@10: while (sp > s->stack) { yading@10: *buf++ = *(--sp); yading@10: if ((--l) == 0) yading@10: goto the_end; yading@10: } yading@10: if (s->ebuf < s->pbuf) { yading@10: av_log(NULL, AV_LOG_ERROR, "lzw overread\n"); yading@10: goto the_end; yading@10: } yading@10: c = lzw_get_code(s); yading@10: if (c == s->end_code) { yading@10: break; yading@10: } else if (c == s->clear_code) { yading@10: s->cursize = s->codesize + 1; yading@10: s->curmask = mask[s->cursize]; yading@10: s->slot = s->newcodes; yading@10: s->top_slot = 1 << s->cursize; yading@10: fc= oc= -1; yading@10: } else { yading@10: code = c; yading@10: if (code == s->slot && fc>=0) { yading@10: *sp++ = fc; yading@10: code = oc; yading@10: }else if(code >= s->slot) yading@10: break; yading@10: while (code >= s->newcodes) { yading@10: *sp++ = s->suffix[code]; yading@10: code = s->prefix[code]; yading@10: } yading@10: *sp++ = code; yading@10: if (s->slot < s->top_slot && oc>=0) { yading@10: s->suffix[s->slot] = code; yading@10: s->prefix[s->slot++] = oc; yading@10: } yading@10: fc = code; yading@10: oc = c; yading@10: if (s->slot >= s->top_slot - s->extra_slot) { yading@10: if (s->cursize < LZW_MAXBITS) { yading@10: s->top_slot <<= 1; yading@10: s->curmask = mask[++s->cursize]; yading@10: } yading@10: } yading@10: } yading@10: } yading@10: s->end_code = -1; yading@10: the_end: yading@10: s->sp = sp; yading@10: s->oc = oc; yading@10: s->fc = fc; yading@10: return len - l; yading@10: }