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