/src/ffmpeg/libavcodec/mlz.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2016 Umair Khan <omerjerk@gmail.com> |
3 | | * |
4 | | * This file is part of FFmpeg. |
5 | | * |
6 | | * FFmpeg is free software; you can redistribute it and/or |
7 | | * modify it under the terms of the GNU Lesser General Public |
8 | | * License as published by the Free Software Foundation; either |
9 | | * version 2.1 of the License, or (at your option) any later version. |
10 | | * |
11 | | * FFmpeg is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | | * Lesser General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU Lesser General Public |
17 | | * License along with FFmpeg; if not, write to the Free Software |
18 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
19 | | */ |
20 | | |
21 | | #include "libavutil/mem.h" |
22 | | #include "mlz.h" |
23 | | |
24 | | av_cold int ff_mlz_init_dict(void *context, MLZ *mlz) |
25 | 883 | { |
26 | 883 | mlz->dict = av_mallocz(TABLE_SIZE * sizeof(*mlz->dict)); |
27 | 883 | if (!mlz->dict) |
28 | 0 | return AVERROR(ENOMEM); |
29 | | |
30 | 883 | mlz->flush_code = FLUSH_CODE; |
31 | 883 | mlz->current_dic_index_max = DIC_INDEX_INIT; |
32 | 883 | mlz->dic_code_bit = CODE_BIT_INIT; |
33 | 883 | mlz->bump_code = (DIC_INDEX_INIT - 1); |
34 | 883 | mlz->next_code = FIRST_CODE; |
35 | 883 | mlz->freeze_flag = 0; |
36 | 883 | mlz->context = context; |
37 | | |
38 | 883 | return 0; |
39 | 883 | } |
40 | | |
41 | 227k | av_cold void ff_mlz_flush_dict(MLZ *mlz) { |
42 | 227k | MLZDict *dict = mlz->dict; |
43 | 227k | int i; |
44 | 7.97G | for ( i = 0; i < TABLE_SIZE; i++ ) { |
45 | 7.97G | dict[i].string_code = CODE_UNSET; |
46 | 7.97G | dict[i].parent_code = CODE_UNSET; |
47 | 7.97G | dict[i].match_len = 0; |
48 | 7.97G | } |
49 | 227k | mlz->current_dic_index_max = DIC_INDEX_INIT; |
50 | 227k | mlz->dic_code_bit = CODE_BIT_INIT; // DicCodeBitInit; |
51 | 227k | mlz->bump_code = mlz->current_dic_index_max - 1; |
52 | 227k | mlz->next_code = FIRST_CODE; |
53 | 227k | mlz->freeze_flag = 0; |
54 | 227k | } |
55 | | |
56 | 86.0M | static void set_new_entry_dict(MLZDict* dict, int string_code, int parent_code, int char_code) { |
57 | 86.0M | dict[string_code].parent_code = parent_code; |
58 | 86.0M | dict[string_code].string_code = string_code; |
59 | 86.0M | dict[string_code].char_code = char_code; |
60 | 86.0M | if (parent_code < FIRST_CODE) { |
61 | 85.1M | dict[string_code].match_len = 2; |
62 | 85.1M | } else { |
63 | 917k | dict[string_code].match_len = (dict[parent_code].match_len) + 1; |
64 | 917k | } |
65 | 86.0M | } |
66 | | |
67 | 96.7M | static int decode_string(MLZ* mlz, unsigned char *buff, int string_code, int *first_char_code, unsigned long bufsize) { |
68 | 96.7M | MLZDict* dict = mlz->dict; |
69 | 96.7M | unsigned long count, offset; |
70 | 96.7M | int current_code, parent_code, tmp_code; |
71 | | |
72 | 96.7M | count = 0; |
73 | 96.7M | current_code = string_code; |
74 | 96.7M | *first_char_code = CODE_UNSET; |
75 | | |
76 | 147M | while (count < bufsize) { |
77 | 147M | switch (current_code) { |
78 | 627k | case CODE_UNSET: |
79 | 627k | return count; |
80 | 0 | break; |
81 | 146M | default: |
82 | 146M | if (current_code < FIRST_CODE) { |
83 | 95.4M | *first_char_code = current_code; |
84 | 95.4M | buff[0] = current_code; |
85 | 95.4M | count++; |
86 | 95.4M | return count; |
87 | 95.4M | } else { |
88 | 51.1M | offset = dict[current_code].match_len - 1; |
89 | 51.1M | tmp_code = dict[current_code].char_code; |
90 | 51.1M | if (offset >= bufsize) { |
91 | 559k | av_log(mlz->context, AV_LOG_ERROR, "MLZ offset error.\n"); |
92 | 559k | return count; |
93 | 559k | } |
94 | 50.5M | buff[offset] = tmp_code; |
95 | 50.5M | count++; |
96 | 50.5M | } |
97 | 50.5M | current_code = dict[current_code].parent_code; |
98 | 50.5M | if ((current_code < 0) || (current_code > (DIC_INDEX_MAX - 1))) { |
99 | 12.9k | av_log(mlz->context, AV_LOG_ERROR, "MLZ dic index error.\n"); |
100 | 12.9k | return count; |
101 | 12.9k | } |
102 | 50.5M | if (current_code > FIRST_CODE) { |
103 | 50.4M | parent_code = dict[current_code].parent_code; |
104 | 50.4M | offset = (dict[current_code].match_len) - 1; |
105 | 50.4M | if (parent_code < 0 || parent_code > DIC_INDEX_MAX-1) { |
106 | 126k | av_log(mlz->context, AV_LOG_ERROR, "MLZ dic index error.\n"); |
107 | 126k | return count; |
108 | 126k | } |
109 | 50.2M | if (( offset > (DIC_INDEX_MAX - 1))) { |
110 | 0 | av_log(mlz->context, AV_LOG_ERROR, "MLZ dic offset error.\n"); |
111 | 0 | return count; |
112 | 0 | } |
113 | 50.2M | } |
114 | 50.4M | break; |
115 | 147M | } |
116 | 147M | } |
117 | 53.0k | return count; |
118 | 96.7M | } |
119 | | |
120 | 97.3M | static int input_code(GetBitContext* gb, int len) { |
121 | 97.3M | int tmp_code = 0; |
122 | 97.3M | int i; |
123 | 1.06G | for (i = 0; i < len; ++i) { |
124 | 963M | tmp_code |= get_bits1(gb) << i; |
125 | 963M | } |
126 | 97.3M | return tmp_code; |
127 | 97.3M | } |
128 | | |
129 | 149k | int ff_mlz_decompression(MLZ* mlz, GetBitContext* gb, int size, unsigned char *buff) { |
130 | 149k | MLZDict *dict = mlz->dict; |
131 | 149k | unsigned long output_chars; |
132 | 149k | int string_code, last_string_code, char_code; |
133 | | |
134 | 149k | string_code = 0; |
135 | 149k | char_code = -1; |
136 | 149k | last_string_code = -1; |
137 | 149k | output_chars = 0; |
138 | | |
139 | 97.5M | while (output_chars < size) { |
140 | 97.3M | string_code = input_code(gb, mlz->dic_code_bit); |
141 | 97.3M | switch (string_code) { |
142 | 5.42k | case FLUSH_CODE: |
143 | 185k | case MAX_CODE: |
144 | 185k | ff_mlz_flush_dict(mlz); |
145 | 185k | char_code = -1; |
146 | 185k | last_string_code = -1; |
147 | 185k | break; |
148 | 2.85k | case FREEZE_CODE: |
149 | 2.85k | mlz->freeze_flag = 1; |
150 | 2.85k | break; |
151 | 97.1M | default: |
152 | 97.1M | if (string_code > mlz->current_dic_index_max) { |
153 | 0 | av_log(mlz->context, AV_LOG_ERROR, "String code %d exceeds maximum value of %d.\n", string_code, mlz->current_dic_index_max); |
154 | 0 | return output_chars; |
155 | 0 | } |
156 | 97.1M | if (string_code == (int) mlz->bump_code) { |
157 | 1.08M | ++mlz->dic_code_bit; |
158 | 1.08M | mlz->current_dic_index_max *= 2; |
159 | 1.08M | mlz->bump_code = mlz->current_dic_index_max - 1; |
160 | 96.1M | } else { |
161 | 96.1M | if (string_code >= mlz->next_code) { |
162 | 680k | int ret = decode_string(mlz, &buff[output_chars], last_string_code, &char_code, size - output_chars); |
163 | 680k | if (ret < 0 || ret > size - output_chars) { |
164 | 0 | av_log(mlz->context, AV_LOG_ERROR, "output chars overflow\n"); |
165 | 0 | return output_chars; |
166 | 0 | } |
167 | 680k | output_chars += ret; |
168 | 680k | ret = decode_string(mlz, &buff[output_chars], char_code, &char_code, size - output_chars); |
169 | 680k | if (ret < 0 || ret > size - output_chars) { |
170 | 0 | av_log(mlz->context, AV_LOG_ERROR, "output chars overflow\n"); |
171 | 0 | return output_chars; |
172 | 0 | } |
173 | 680k | output_chars += ret; |
174 | 680k | set_new_entry_dict(dict, mlz->next_code, last_string_code, char_code); |
175 | 680k | if (mlz->next_code >= TABLE_SIZE - 1) { |
176 | 0 | av_log(mlz->context, AV_LOG_ERROR, "Too many MLZ codes\n"); |
177 | 0 | return output_chars; |
178 | 0 | } |
179 | 680k | mlz->next_code++; |
180 | 95.4M | } else { |
181 | 95.4M | int ret = decode_string(mlz, &buff[output_chars], string_code, &char_code, size - output_chars); |
182 | 95.4M | if (ret < 0 || ret > size - output_chars) { |
183 | 0 | av_log(mlz->context, AV_LOG_ERROR, "output chars overflow\n"); |
184 | 0 | return output_chars; |
185 | 0 | } |
186 | 95.4M | output_chars += ret; |
187 | 95.4M | if (output_chars <= size && !mlz->freeze_flag) { |
188 | 85.4M | if (last_string_code != -1) { |
189 | 85.3M | set_new_entry_dict(dict, mlz->next_code, last_string_code, char_code); |
190 | 85.3M | if (mlz->next_code >= TABLE_SIZE - 1) { |
191 | 2.84k | av_log(mlz->context, AV_LOG_ERROR, "Too many MLZ codes\n"); |
192 | 2.84k | return output_chars; |
193 | 2.84k | } |
194 | 85.3M | mlz->next_code++; |
195 | 85.3M | } |
196 | 85.4M | } else { |
197 | 9.94M | break; |
198 | 9.94M | } |
199 | 95.4M | } |
200 | 86.1M | last_string_code = string_code; |
201 | 86.1M | } |
202 | 87.2M | break; |
203 | 97.3M | } |
204 | 97.3M | } |
205 | 147k | return output_chars; |
206 | 149k | } |