Coverage Report

Created: 2025-11-16 07:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}