Statistics
| Branch: | Revision:

ffmpeg / libavcodec / lzo.c @ 5509bffa

History | View | Annotate | Download (4.81 KB)

1
/*
2
 * LZO 1x decompression
3
 * Copyright (c) 2006 Reimar Doeffinger
4
 *
5
 * This library is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU Lesser General Public
7
 * License as published by the Free Software Foundation; either
8
 * version 2 of the License, or (at your option) any later version.
9
 *
10
 * This library is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
 * Lesser General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU Lesser General Public
16
 * License along with this library; if not, write to the Free Software
17
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
 */
19
#include "common.h"
20
#include "lzo.h"
21

    
22
typedef struct LZOContext {
23
    uint8_t *in, *in_end;
24
    uint8_t *out, *out_end;
25
    int out_size;
26
    int error;
27
} LZOContext;
28

    
29
/**
30
 * \brief read one byte from input buffer, avoiding overrun
31
 * \return byte read
32
 */
33
static inline int get_byte(LZOContext *c) {
34
    if (c->in < c->in_end)
35
        return *c->in++;
36
    c->error |= LZO_INPUT_DEPLETED;
37
    return -1;
38
}
39

    
40
/**
41
 * \brief decode a length value in the coding used by lzo
42
 * \param x previous byte value
43
 * \param mask bits used from x
44
 * \return decoded length value
45
 */
46
static inline int get_len(LZOContext *c, int x, int mask) {
47
    int cnt = x & mask;
48
    if (!cnt) {
49
        while (!(x = get_byte(c))) cnt += 255;
50
        cnt += mask + x;
51
    }
52
    return cnt;
53
}
54

    
55
/**
56
 * \brief copy bytes from input to output buffer with checking
57
 * \param cnt number of bytes to copy, must be > 0
58
 */
59
static inline void copy(LZOContext *c, int cnt) {
60
    if (c->in + cnt > c->in_end) {
61
        cnt = c->in_end - c->in;
62
        c->error |= LZO_INPUT_DEPLETED;
63
    }
64
    if (c->out + cnt > c->out_end) {
65
        cnt = c->out_end - c->out;
66
        c->error |= LZO_OUTPUT_FULL;
67
    }
68
    do {
69
        *c->out++ = *c->in++;
70
    } while (--cnt);
71
}
72

    
73
/**
74
 * \brief copy previously decoded bytes to current position
75
 * \param back how many bytes back we start
76
 * \param cnt number of bytes to copy, must be > 0
77
 *
78
 * cnt > back is valid, this will copy the bytes we just copied.
79
 */
80
static inline void copy_backptr(LZOContext *c, int back, int cnt) {
81
    if (c->out - back < c->out_end - c->out_size) {
82
        c->error |= LZO_INVALID_BACKPTR;
83
        return;
84
    }
85
    if (c->out + cnt > c->out_end) {
86
        cnt = c->out_end - c->out;
87
        c->error |= LZO_OUTPUT_FULL;
88
    }
89
    do {
90
        *c->out++ = c->out[-back];
91
    } while (--cnt);
92
}
93

    
94
/**
95
 * \brief decode LZO 1x compressed data
96
 * \param out output buffer
97
 * \param outlen size of output buffer, number of bytes left are returned here
98
 * \param in input buffer
99
 * \param inlen size of input buffer, number of bytes left are returned here
100
 * \return 0 on success, otherwise error flags, see lzo.h
101
 */
102
int lzo1x_decode(void *out, int *outlen, void *in, int *inlen) {
103
    enum {COPY, BACKPTR} state = COPY;
104
    int x;
105
    LZOContext c;
106
    c.in = in;
107
    c.in_end = in + *inlen;
108
    c.out = out;
109
    c.out_end = out + * outlen;
110
    c.out_size = *outlen;
111
    c.error = 0;
112
    x = get_byte(&c);
113
    if (x > 17) {
114
        copy(&c, x - 17);
115
        x = get_byte(&c);
116
        if (x < 16) c.error |= LZO_ERROR;
117
    }
118
    while (!c.error) {
119
        int cnt, back;
120
        if (x >> 4) {
121
            state = BACKPTR;
122
            if (x >> 6) {
123
                cnt = (x >> 5) - 1;
124
                back = (get_byte(&c) << 3) + ((x >> 2) & 7) + 1;
125
            } else if (x >> 5) {
126
                cnt = get_len(&c, x, 31);
127
                x = get_byte(&c);
128
                back = (get_byte(&c) << 6) + (x >> 2) + 1;
129
            } else {
130
                cnt = get_len(&c, x, 7);
131
                back = (1 << 14) + ((x & 8) << 11);
132
                x = get_byte(&c);
133
                back += (get_byte(&c) << 6) + (x >> 2);
134
                if (back == (1 << 14)) {
135
                    if (cnt != 1)
136
                        c.error |= LZO_ERROR;
137
                    break;
138
                }
139
            }
140
        } else
141
        switch (state) {
142
            case COPY:
143
                cnt = get_len(&c, x, 15);
144
                copy(&c, cnt + 3);
145
                x = get_byte(&c);
146
                if (x >> 4)
147
                    continue;
148
                cnt = 1;
149
                back = (1 << 11) + (get_byte(&c) << 2) + (x >> 2) + 1;
150
                break;
151
            case BACKPTR:
152
                cnt = 0;
153
                back = (get_byte(&c) << 2) + (x >> 2) + 1;
154
                break;
155
        }
156
        copy_backptr(&c, back, cnt + 2);
157
        cnt = x & 3;
158
        if (cnt)
159
            copy(&c, cnt);
160
        else
161
            state = (state == COPY) ? BACKPTR : COPY;
162
        x = get_byte(&c);
163
    }
164
    *inlen = c.in_end - c.in;
165
    *outlen = c.out_end - c.out;
166
    return c.error;
167
}