/src/ffmpeg/libavcodec/mlz.c
Line | Count | Source |
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 | 1.02k | { |
26 | 1.02k | mlz->dict = av_mallocz(TABLE_SIZE * sizeof(*mlz->dict)); |
27 | 1.02k | if (!mlz->dict) |
28 | 0 | return AVERROR(ENOMEM); |
29 | | |
30 | 1.02k | mlz->flush_code = FLUSH_CODE; |
31 | 1.02k | mlz->current_dic_index_max = DIC_INDEX_INIT; |
32 | 1.02k | mlz->dic_code_bit = CODE_BIT_INIT; |
33 | 1.02k | mlz->bump_code = (DIC_INDEX_INIT - 1); |
34 | 1.02k | mlz->next_code = FIRST_CODE; |
35 | 1.02k | mlz->freeze_flag = 0; |
36 | 1.02k | mlz->context = context; |
37 | | |
38 | 1.02k | return 0; |
39 | 1.02k | } |
40 | | |
41 | 232k | av_cold void ff_mlz_flush_dict(MLZ *mlz) { |
42 | 232k | MLZDict *dict = mlz->dict; |
43 | 232k | int i; |
44 | 8.14G | for ( i = 0; i < TABLE_SIZE; i++ ) { |
45 | 8.14G | dict[i].string_code = CODE_UNSET; |
46 | 8.14G | dict[i].parent_code = CODE_UNSET; |
47 | 8.14G | dict[i].match_len = 0; |
48 | 8.14G | } |
49 | 232k | mlz->current_dic_index_max = DIC_INDEX_INIT; |
50 | 232k | mlz->dic_code_bit = CODE_BIT_INIT; // DicCodeBitInit; |
51 | 232k | mlz->bump_code = mlz->current_dic_index_max - 1; |
52 | 232k | mlz->next_code = FIRST_CODE; |
53 | 232k | mlz->freeze_flag = 0; |
54 | 232k | } |
55 | | |
56 | 91.4M | static void set_new_entry_dict(MLZDict* dict, int string_code, int parent_code, int char_code) { |
57 | 91.4M | dict[string_code].parent_code = parent_code; |
58 | 91.4M | dict[string_code].string_code = string_code; |
59 | 91.4M | dict[string_code].char_code = char_code; |
60 | 91.4M | if (parent_code < FIRST_CODE) { |
61 | 90.4M | dict[string_code].match_len = 2; |
62 | 90.4M | } else { |
63 | 984k | dict[string_code].match_len = (dict[parent_code].match_len) + 1; |
64 | 984k | } |
65 | 91.4M | } |
66 | | |
67 | 102M | static int decode_string(MLZ* mlz, unsigned char *buff, int string_code, int *first_char_code, unsigned long bufsize) { |
68 | 102M | MLZDict* dict = mlz->dict; |
69 | 102M | unsigned long count, offset; |
70 | 102M | int current_code, parent_code, tmp_code; |
71 | | |
72 | 102M | count = 0; |
73 | 102M | current_code = string_code; |
74 | 102M | *first_char_code = CODE_UNSET; |
75 | | |
76 | 110M | while (count < bufsize) { |
77 | 110M | switch (current_code) { |
78 | 848k | case CODE_UNSET: |
79 | 848k | return count; |
80 | 0 | break; |
81 | 109M | default: |
82 | 109M | if (current_code < FIRST_CODE) { |
83 | 100M | *first_char_code = current_code; |
84 | 100M | buff[0] = current_code; |
85 | 100M | count++; |
86 | 100M | return count; |
87 | 100M | } else { |
88 | 9.17M | offset = dict[current_code].match_len - 1; |
89 | 9.17M | tmp_code = dict[current_code].char_code; |
90 | 9.17M | if (offset >= bufsize) { |
91 | 736k | av_log(mlz->context, AV_LOG_ERROR, "MLZ offset error.\n"); |
92 | 736k | return count; |
93 | 736k | } |
94 | 8.43M | buff[offset] = tmp_code; |
95 | 8.43M | count++; |
96 | 8.43M | } |
97 | 8.43M | current_code = dict[current_code].parent_code; |
98 | 8.43M | if ((current_code < 0) || (current_code > (DIC_INDEX_MAX - 1))) { |
99 | 20.7k | av_log(mlz->context, AV_LOG_ERROR, "MLZ dic index error.\n"); |
100 | 20.7k | return count; |
101 | 20.7k | } |
102 | 8.41M | if (current_code > FIRST_CODE) { |
103 | 8.32M | parent_code = dict[current_code].parent_code; |
104 | 8.32M | offset = (dict[current_code].match_len) - 1; |
105 | 8.32M | if (parent_code < 0 || parent_code > DIC_INDEX_MAX-1) { |
106 | 107k | av_log(mlz->context, AV_LOG_ERROR, "MLZ dic index error.\n"); |
107 | 107k | return count; |
108 | 107k | } |
109 | 8.21M | 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 | 8.21M | } |
114 | 8.30M | break; |
115 | 110M | } |
116 | 110M | } |
117 | 96.3k | return count; |
118 | 102M | } |
119 | | |
120 | 102M | static int input_code(GetBitContext* gb, int len) { |
121 | 102M | int tmp_code = 0; |
122 | 102M | int i; |
123 | 1.11G | for (i = 0; i < len; ++i) { |
124 | 1.01G | tmp_code |= get_bits1(gb) << i; |
125 | 1.01G | } |
126 | 102M | return tmp_code; |
127 | 102M | } |
128 | | |
129 | 281k | int ff_mlz_decompression(MLZ* mlz, GetBitContext* gb, int size, unsigned char *buff) { |
130 | 281k | MLZDict *dict = mlz->dict; |
131 | 281k | unsigned long output_chars; |
132 | 281k | int string_code, last_string_code, char_code; |
133 | | |
134 | 281k | string_code = 0; |
135 | 281k | char_code = -1; |
136 | 281k | last_string_code = -1; |
137 | 281k | output_chars = 0; |
138 | | |
139 | 102M | while (output_chars < size) { |
140 | 102M | string_code = input_code(gb, mlz->dic_code_bit); |
141 | 102M | switch (string_code) { |
142 | 5.07k | case FLUSH_CODE: |
143 | 222k | case MAX_CODE: |
144 | 222k | ff_mlz_flush_dict(mlz); |
145 | 222k | char_code = -1; |
146 | 222k | last_string_code = -1; |
147 | 222k | break; |
148 | 2.69k | case FREEZE_CODE: |
149 | 2.69k | mlz->freeze_flag = 1; |
150 | 2.69k | break; |
151 | 102M | default: |
152 | 102M | 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 | 102M | if (string_code == (int) mlz->bump_code) { |
157 | 1.31M | ++mlz->dic_code_bit; |
158 | 1.31M | mlz->current_dic_index_max *= 2; |
159 | 1.31M | mlz->bump_code = mlz->current_dic_index_max - 1; |
160 | 101M | } else { |
161 | 101M | if (string_code >= mlz->next_code) { |
162 | 874k | int ret = decode_string(mlz, &buff[output_chars], last_string_code, &char_code, size - output_chars); |
163 | 874k | 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 | 874k | output_chars += ret; |
168 | 874k | ret = decode_string(mlz, &buff[output_chars], char_code, &char_code, size - output_chars); |
169 | 874k | 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 | 874k | output_chars += ret; |
174 | 874k | set_new_entry_dict(dict, mlz->next_code, last_string_code, char_code); |
175 | 874k | 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 | 874k | mlz->next_code++; |
180 | 100M | } else { |
181 | 100M | int ret = decode_string(mlz, &buff[output_chars], string_code, &char_code, size - output_chars); |
182 | 100M | 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 | 100M | output_chars += ret; |
187 | 100M | if (output_chars <= size && !mlz->freeze_flag) { |
188 | 90.7M | if (last_string_code != -1) { |
189 | 90.6M | set_new_entry_dict(dict, mlz->next_code, last_string_code, char_code); |
190 | 90.6M | if (mlz->next_code >= TABLE_SIZE - 1) { |
191 | 3.50k | av_log(mlz->context, AV_LOG_ERROR, "Too many MLZ codes\n"); |
192 | 3.50k | return output_chars; |
193 | 3.50k | } |
194 | 90.6M | mlz->next_code++; |
195 | 90.6M | } |
196 | 90.7M | } else { |
197 | 9.52M | break; |
198 | 9.52M | } |
199 | 100M | } |
200 | 91.6M | last_string_code = string_code; |
201 | 91.6M | } |
202 | 92.9M | break; |
203 | 102M | } |
204 | 102M | } |
205 | 278k | return output_chars; |
206 | 281k | } |