GCC Code Coverage Report
Directory: ../../../ffmpeg/ Exec Total Coverage
File: src/libavcodec/snappy.c Lines: 70 90 77.8 %
Date: 2020-10-23 17:01:47 Branches: 22 36 61.1 %

Line Branch Exec Source
1
/*
2
 * Snappy decompression algorithm
3
 * Copyright (c) 2015 Luca Barbato
4
 *
5
 * This file is part of FFmpeg.
6
 *
7
 * FFmpeg is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU Lesser General Public
9
 * License as published by the Free Software Foundation; either
10
 * version 2.1 of the License, or (at your option) any later version.
11
 *
12
 * FFmpeg is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 * Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with FFmpeg; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
 */
21
22
#include "libavutil/mem.h"
23
24
#include "bytestream.h"
25
#include "snappy.h"
26
27
enum {
28
    SNAPPY_LITERAL,
29
    SNAPPY_COPY_1,
30
    SNAPPY_COPY_2,
31
    SNAPPY_COPY_4,
32
};
33
34
100
static int64_t bytestream2_get_levarint(GetByteContext *gb)
35
{
36
100
    uint64_t val = 0;
37
100
    int shift = 0;
38
    int tmp;
39
40
    do {
41
206
        tmp = bytestream2_get_byte(gb);
42

206
        if (shift > 31 || ((tmp & 127LL) << shift) > INT_MAX)
43
            return AVERROR_INVALIDDATA;
44
206
        val |= (tmp & 127) << shift;
45
206
        shift += 7;
46
206
    } while (tmp & 128);
47
48
100
    return val;
49
}
50
51
26644
static int snappy_literal(GetByteContext *gb, uint8_t *p, int size, int val)
52
{
53
26644
    unsigned int len = 1;
54
55

26644
    switch (val) {
56
    case 63:
57
        len += bytestream2_get_le32(gb);
58
        break;
59
    case 62:
60
        len += bytestream2_get_le24(gb);
61
        break;
62
65
    case 61:
63
65
        len += bytestream2_get_le16(gb);
64
65
        break;
65
669
    case 60:
66
669
        len += bytestream2_get_byte(gb);
67
669
        break;
68
25910
    default: // val < 60
69
25910
        len += val;
70
    }
71
72
26644
    if (size < len)
73
        return AVERROR_INVALIDDATA;
74
75
26644
    bytestream2_get_buffer(gb, p, len);
76
77
26644
    return len;
78
}
79
80
33740
static int snappy_copy(uint8_t *start, uint8_t *p, int size,
81
                       unsigned int off, int len)
82
{
83
    uint8_t *q;
84
    int i;
85

33740
    if (off > p - start || size < len)
86
        return AVERROR_INVALIDDATA;
87
88
33740
    q = p - off;
89
90
466071
    for (i = 0; i < len; i++)
91
432331
        p[i] = q[i];
92
93
33740
    return len;
94
}
95
96
16119
static int snappy_copy1(GetByteContext *gb, uint8_t *start, uint8_t *p,
97
                        int size, int val)
98
{
99
16119
    int len          = 4 + (val & 0x7);
100
16119
    unsigned int off = bytestream2_get_byte(gb) | (val & 0x38) << 5;
101
102
16119
    return snappy_copy(start, p, size, off, len);
103
}
104
105
17621
static int snappy_copy2(GetByteContext *gb, uint8_t *start, uint8_t *p,
106
                        int size, int val)
107
{
108
17621
    int len          = 1 + val;
109
17621
    unsigned int off = bytestream2_get_le16(gb);
110
111
17621
    return snappy_copy(start, p, size, off, len);
112
}
113
114
static int snappy_copy4(GetByteContext *gb, uint8_t *start, uint8_t *p,
115
                        int size, int val)
116
{
117
    int len          = 1 + val;
118
    unsigned int off = bytestream2_get_le32(gb);
119
120
    return snappy_copy(start, p, size, off, len);
121
}
122
123
100
static int64_t decode_len(GetByteContext *gb)
124
{
125
100
    int64_t len = bytestream2_get_levarint(gb);
126
127

100
    if (len < 0 || len > UINT_MAX)
128
        return AVERROR_INVALIDDATA;
129
130
100
    return len;
131
}
132
133
50
int64_t ff_snappy_peek_uncompressed_length(GetByteContext *gb)
134
{
135
50
    int pos = bytestream2_get_bytes_left(gb);
136
50
    int64_t len = decode_len(gb);
137
138
50
    bytestream2_seek(gb, -pos, SEEK_END);
139
140
50
    return len;
141
}
142
143
50
int ff_snappy_uncompress(GetByteContext *gb, uint8_t *buf, int64_t *size)
144
{
145
50
    int64_t len = decode_len(gb);
146
50
    int ret     = 0;
147
    uint8_t *p;
148
149
50
    if (len < 0)
150
        return len;
151
152
50
    if (len > *size)
153
        return AVERROR_BUFFER_TOO_SMALL;
154
155
50
    *size = len;
156
50
    p     = buf;
157
158
60434
    while (bytestream2_get_bytes_left(gb) > 0) {
159
60384
        uint8_t s = bytestream2_get_byte(gb);
160
60384
        int val   = s >> 2;
161
162

60384
        switch (s & 0x03) {
163
26644
        case SNAPPY_LITERAL:
164
26644
            ret = snappy_literal(gb, p, len, val);
165
26644
            break;
166
16119
        case SNAPPY_COPY_1:
167
16119
            ret = snappy_copy1(gb, buf, p, len, val);
168
16119
            break;
169
17621
        case SNAPPY_COPY_2:
170
17621
            ret = snappy_copy2(gb, buf, p, len, val);
171
17621
            break;
172
        case SNAPPY_COPY_4:
173
            ret = snappy_copy4(gb, buf, p, len, val);
174
            break;
175
        }
176
177
60384
        if (ret < 0)
178
            return ret;
179
180
60384
        p   += ret;
181
60384
        len -= ret;
182
    }
183
184
50
    return 0;
185
}