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 23av_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 40av_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 55static 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 66static 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 119static 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 128int 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