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 "mlz.h"
22
ff_mlz_init_dict(void * context,MLZ * mlz)23 av_cold int ff_mlz_init_dict(void *context, MLZ *mlz)
24 {
25 mlz->dict = av_mallocz(TABLE_SIZE * sizeof(*mlz->dict));
26 if (!mlz->dict)
27 return AVERROR(ENOMEM);
28
29 mlz->flush_code = FLUSH_CODE;
30 mlz->current_dic_index_max = DIC_INDEX_INIT;
31 mlz->dic_code_bit = CODE_BIT_INIT;
32 mlz->bump_code = (DIC_INDEX_INIT - 1);
33 mlz->next_code = FIRST_CODE;
34 mlz->freeze_flag = 0;
35 mlz->context = context;
36
37 return 0;
38 }
39
ff_mlz_flush_dict(MLZ * mlz)40 av_cold void ff_mlz_flush_dict(MLZ *mlz) {
41 MLZDict *dict = mlz->dict;
42 int i;
43 for ( i = 0; i < TABLE_SIZE; i++ ) {
44 dict[i].string_code = CODE_UNSET;
45 dict[i].parent_code = CODE_UNSET;
46 dict[i].match_len = 0;
47 }
48 mlz->current_dic_index_max = DIC_INDEX_INIT;
49 mlz->dic_code_bit = CODE_BIT_INIT; // DicCodeBitInit;
50 mlz->bump_code = mlz->current_dic_index_max - 1;
51 mlz->next_code = FIRST_CODE;
52 mlz->freeze_flag = 0;
53 }
54
set_new_entry_dict(MLZDict * dict,int string_code,int parent_code,int char_code)55 static void set_new_entry_dict(MLZDict* dict, int string_code, int parent_code, int char_code) {
56 dict[string_code].parent_code = parent_code;
57 dict[string_code].string_code = string_code;
58 dict[string_code].char_code = char_code;
59 if (parent_code < FIRST_CODE) {
60 dict[string_code].match_len = 2;
61 } else {
62 dict[string_code].match_len = (dict[parent_code].match_len) + 1;
63 }
64 }
65
decode_string(MLZ * mlz,unsigned char * buff,int string_code,int * first_char_code,unsigned long bufsize)66 static int decode_string(MLZ* mlz, unsigned char *buff, int string_code, int *first_char_code, unsigned long bufsize) {
67 MLZDict* dict = mlz->dict;
68 unsigned long count, offset;
69 int current_code, parent_code, tmp_code;
70
71 count = 0;
72 current_code = string_code;
73 *first_char_code = CODE_UNSET;
74
75 while (count < bufsize) {
76 switch (current_code) {
77 case CODE_UNSET:
78 return count;
79 break;
80 default:
81 if (current_code < FIRST_CODE) {
82 *first_char_code = current_code;
83 buff[0] = current_code;
84 count++;
85 return count;
86 } else {
87 offset = dict[current_code].match_len - 1;
88 tmp_code = dict[current_code].char_code;
89 if (offset >= bufsize) {
90 av_log(mlz->context, AV_LOG_ERROR, "MLZ offset error.\n");
91 return count;
92 }
93 buff[offset] = tmp_code;
94 count++;
95 }
96 current_code = dict[current_code].parent_code;
97 if ((current_code < 0) || (current_code > (DIC_INDEX_MAX - 1))) {
98 av_log(mlz->context, AV_LOG_ERROR, "MLZ dic index error.\n");
99 return count;
100 }
101 if (current_code > FIRST_CODE) {
102 parent_code = dict[current_code].parent_code;
103 offset = (dict[current_code].match_len) - 1;
104 if (parent_code < 0 || parent_code > DIC_INDEX_MAX-1) {
105 av_log(mlz->context, AV_LOG_ERROR, "MLZ dic index error.\n");
106 return count;
107 }
108 if (( offset > (DIC_INDEX_MAX - 1))) {
109 av_log(mlz->context, AV_LOG_ERROR, "MLZ dic offset error.\n");
110 return count;
111 }
112 }
113 break;
114 }
115 }
116 return count;
117 }
118
input_code(GetBitContext * gb,int len)119 static int input_code(GetBitContext* gb, int len) {
120 int tmp_code = 0;
121 int i;
122 for (i = 0; i < len; ++i) {
123 tmp_code |= get_bits1(gb) << i;
124 }
125 return tmp_code;
126 }
127
ff_mlz_decompression(MLZ * mlz,GetBitContext * gb,int size,unsigned char * buff)128 int ff_mlz_decompression(MLZ* mlz, GetBitContext* gb, int size, unsigned char *buff) {
129 MLZDict *dict = mlz->dict;
130 unsigned long output_chars;
131 int string_code, last_string_code, char_code;
132
133 string_code = 0;
134 char_code = -1;
135 last_string_code = -1;
136 output_chars = 0;
137
138 while (output_chars < size) {
139 string_code = input_code(gb, mlz->dic_code_bit);
140 switch (string_code) {
141 case FLUSH_CODE:
142 case MAX_CODE:
143 ff_mlz_flush_dict(mlz);
144 char_code = -1;
145 last_string_code = -1;
146 break;
147 case FREEZE_CODE:
148 mlz->freeze_flag = 1;
149 break;
150 default:
151 if (string_code > mlz->current_dic_index_max) {
152 av_log(mlz->context, AV_LOG_ERROR, "String code %d exceeds maximum value of %d.\n", string_code, mlz->current_dic_index_max);
153 return output_chars;
154 }
155 if (string_code == (int) mlz->bump_code) {
156 ++mlz->dic_code_bit;
157 mlz->current_dic_index_max *= 2;
158 mlz->bump_code = mlz->current_dic_index_max - 1;
159 } else {
160 if (string_code >= mlz->next_code) {
161 int ret = decode_string(mlz, &buff[output_chars], last_string_code, &char_code, size - output_chars);
162 if (ret < 0 || ret > size - output_chars) {
163 av_log(mlz->context, AV_LOG_ERROR, "output chars overflow\n");
164 return output_chars;
165 }
166 output_chars += ret;
167 ret = decode_string(mlz, &buff[output_chars], char_code, &char_code, size - output_chars);
168 if (ret < 0 || ret > size - output_chars) {
169 av_log(mlz->context, AV_LOG_ERROR, "output chars overflow\n");
170 return output_chars;
171 }
172 output_chars += ret;
173 set_new_entry_dict(dict, mlz->next_code, last_string_code, char_code);
174 if (mlz->next_code >= TABLE_SIZE - 1) {
175 av_log(mlz->context, AV_LOG_ERROR, "Too many MLZ codes\n");
176 return output_chars;
177 }
178 mlz->next_code++;
179 } else {
180 int ret = decode_string(mlz, &buff[output_chars], string_code, &char_code, size - output_chars);
181 if (ret < 0 || ret > size - output_chars) {
182 av_log(mlz->context, AV_LOG_ERROR, "output chars overflow\n");
183 return output_chars;
184 }
185 output_chars += ret;
186 if (output_chars <= size && !mlz->freeze_flag) {
187 if (last_string_code != -1) {
188 set_new_entry_dict(dict, mlz->next_code, last_string_code, char_code);
189 if (mlz->next_code >= TABLE_SIZE - 1) {
190 av_log(mlz->context, AV_LOG_ERROR, "Too many MLZ codes\n");
191 return output_chars;
192 }
193 mlz->next_code++;
194 }
195 } else {
196 break;
197 }
198 }
199 last_string_code = string_code;
200 }
201 break;
202 }
203 }
204 return output_chars;
205 }
206