]> git.sesse.net Git - ffmpeg/blob - libavcodec/snappy.c
avformat/avio: Add Metacube support
[ffmpeg] / libavcodec / snappy.c
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 static int64_t bytestream2_get_levarint(GetByteContext *gb)
35 {
36     uint64_t val = 0;
37     int shift = 0;
38     int tmp;
39
40     do {
41         tmp = bytestream2_get_byte(gb);
42         if (shift > 31 || ((tmp & 127LL) << shift) > INT_MAX)
43             return AVERROR_INVALIDDATA;
44         val |= (tmp & 127) << shift;
45         shift += 7;
46     } while (tmp & 128);
47
48     return val;
49 }
50
51 static int snappy_literal(GetByteContext *gb, uint8_t *p, int size, int val)
52 {
53     unsigned int len = 1;
54
55     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     case 61:
63         len += bytestream2_get_le16(gb);
64         break;
65     case 60:
66         len += bytestream2_get_byte(gb);
67         break;
68     default: // val < 60
69         len += val;
70     }
71
72     if (size < len)
73         return AVERROR_INVALIDDATA;
74
75     bytestream2_get_buffer(gb, p, len);
76
77     return len;
78 }
79
80 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     if (off > p - start || size < len)
86         return AVERROR_INVALIDDATA;
87
88     q = p - off;
89
90     for (i = 0; i < len; i++)
91         p[i] = q[i];
92
93     return len;
94 }
95
96 static int snappy_copy1(GetByteContext *gb, uint8_t *start, uint8_t *p,
97                         int size, int val)
98 {
99     int len          = 4 + (val & 0x7);
100     unsigned int off = bytestream2_get_byte(gb) | (val & 0x38) << 5;
101
102     return snappy_copy(start, p, size, off, len);
103 }
104
105 static int snappy_copy2(GetByteContext *gb, uint8_t *start, uint8_t *p,
106                         int size, int val)
107 {
108     int len          = 1 + val;
109     unsigned int off = bytestream2_get_le16(gb);
110
111     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 static int64_t decode_len(GetByteContext *gb)
124 {
125     int64_t len = bytestream2_get_levarint(gb);
126
127     if (len < 0 || len > UINT_MAX)
128         return AVERROR_INVALIDDATA;
129
130     return len;
131 }
132
133 int64_t ff_snappy_peek_uncompressed_length(GetByteContext *gb)
134 {
135     int pos = bytestream2_get_bytes_left(gb);
136     int64_t len = decode_len(gb);
137
138     bytestream2_seek(gb, -pos, SEEK_END);
139
140     return len;
141 }
142
143 int ff_snappy_uncompress(GetByteContext *gb, uint8_t *buf, int64_t *size)
144 {
145     int64_t len = decode_len(gb);
146     int ret     = 0;
147     uint8_t *p;
148
149     if (len < 0)
150         return len;
151
152     if (len > *size)
153         return AVERROR_BUFFER_TOO_SMALL;
154
155     *size = len;
156     p     = buf;
157
158     while (bytestream2_get_bytes_left(gb) > 0) {
159         uint8_t s = bytestream2_get_byte(gb);
160         int val   = s >> 2;
161
162         switch (s & 0x03) {
163         case SNAPPY_LITERAL:
164             ret = snappy_literal(gb, p, len, val);
165             break;
166         case SNAPPY_COPY_1:
167             ret = snappy_copy1(gb, buf, p, len, val);
168             break;
169         case SNAPPY_COPY_2:
170             ret = snappy_copy2(gb, buf, p, len, val);
171             break;
172         case SNAPPY_COPY_4:
173             ret = snappy_copy4(gb, buf, p, len, val);
174             break;
175         }
176
177         if (ret < 0)
178             return ret;
179
180         p   += ret;
181         len -= ret;
182     }
183
184     return 0;
185 }