1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * Jpeg XL header verification
3cabdff1aSopenharmony_ci * Copyright (c) 2022 Leo Izen <leo.izen@gmail.com>
4cabdff1aSopenharmony_ci *
5cabdff1aSopenharmony_ci * This file is part of FFmpeg.
6cabdff1aSopenharmony_ci *
7cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or
8cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public
9cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either
10cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version.
11cabdff1aSopenharmony_ci *
12cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful,
13cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
14cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15cabdff1aSopenharmony_ci * Lesser General Public License for more details.
16cabdff1aSopenharmony_ci *
17cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public
18cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software
19cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20cabdff1aSopenharmony_ci */
21cabdff1aSopenharmony_ci
22cabdff1aSopenharmony_ci#include "jpegxl_probe.h"
23cabdff1aSopenharmony_ci
24cabdff1aSopenharmony_ci#define UNCHECKED_BITSTREAM_READER 0
25cabdff1aSopenharmony_ci#define BITSTREAM_READER_LE
26cabdff1aSopenharmony_ci#include "libavcodec/get_bits.h"
27cabdff1aSopenharmony_ci
28cabdff1aSopenharmony_cienum JpegXLExtraChannelType {
29cabdff1aSopenharmony_ci    FF_JPEGXL_CT_ALPHA = 0,
30cabdff1aSopenharmony_ci    FF_JPEGXL_CT_DEPTH,
31cabdff1aSopenharmony_ci    FF_JPEGXL_CT_SPOT_COLOR,
32cabdff1aSopenharmony_ci    FF_JPEGXL_CT_SELECTION_MASK,
33cabdff1aSopenharmony_ci    FF_JPEGXL_CT_BLACK,
34cabdff1aSopenharmony_ci    FF_JPEGXL_CT_CFA,
35cabdff1aSopenharmony_ci    FF_JPEGXL_CT_THERMAL,
36cabdff1aSopenharmony_ci    FF_JPEGXL_CT_NON_OPTIONAL = 15,
37cabdff1aSopenharmony_ci    FF_JPEGXL_CT_OPTIONAL
38cabdff1aSopenharmony_ci};
39cabdff1aSopenharmony_ci
40cabdff1aSopenharmony_cienum JpegXLColorSpace {
41cabdff1aSopenharmony_ci    FF_JPEGXL_CS_RGB = 0,
42cabdff1aSopenharmony_ci    FF_JPEGXL_CS_GRAY,
43cabdff1aSopenharmony_ci    FF_JPEGXL_CS_XYB,
44cabdff1aSopenharmony_ci    FF_JPEGXL_CS_UNKNOWN
45cabdff1aSopenharmony_ci};
46cabdff1aSopenharmony_ci
47cabdff1aSopenharmony_cienum JpegXLWhitePoint {
48cabdff1aSopenharmony_ci    FF_JPEGXL_WP_D65 = 1,
49cabdff1aSopenharmony_ci    FF_JPEGXL_WP_CUSTOM,
50cabdff1aSopenharmony_ci    FF_JPEGXL_WP_E = 10,
51cabdff1aSopenharmony_ci    FF_JPEGXL_WP_DCI = 11
52cabdff1aSopenharmony_ci};
53cabdff1aSopenharmony_ci
54cabdff1aSopenharmony_cienum JpegXLPrimaries {
55cabdff1aSopenharmony_ci    FF_JPEGXL_PR_SRGB = 1,
56cabdff1aSopenharmony_ci    FF_JPEGXL_PR_CUSTOM,
57cabdff1aSopenharmony_ci    FF_JPEGXL_PR_2100 = 9,
58cabdff1aSopenharmony_ci    FF_JPEGXL_PR_P3 = 11,
59cabdff1aSopenharmony_ci};
60cabdff1aSopenharmony_ci
61cabdff1aSopenharmony_ci/* read a U32(c_i + u(u_i)) */
62cabdff1aSopenharmony_cistatic av_always_inline uint32_t jxl_u32(GetBitContext *gb,
63cabdff1aSopenharmony_ci                        uint32_t c0, uint32_t c1, uint32_t c2, uint32_t c3,
64cabdff1aSopenharmony_ci                        uint32_t u0, uint32_t u1, uint32_t u2, uint32_t u3)
65cabdff1aSopenharmony_ci{
66cabdff1aSopenharmony_ci    const uint32_t constants[4] = {c0, c1, c2, c3};
67cabdff1aSopenharmony_ci    const uint32_t ubits    [4] = {u0, u1, u2, u3};
68cabdff1aSopenharmony_ci    uint32_t ret, choice = get_bits(gb, 2);
69cabdff1aSopenharmony_ci
70cabdff1aSopenharmony_ci    ret = constants[choice];
71cabdff1aSopenharmony_ci    if (ubits[choice])
72cabdff1aSopenharmony_ci        ret += get_bits_long(gb, ubits[choice]);
73cabdff1aSopenharmony_ci
74cabdff1aSopenharmony_ci    return ret;
75cabdff1aSopenharmony_ci}
76cabdff1aSopenharmony_ci
77cabdff1aSopenharmony_cistatic av_always_inline uint32_t jxl_enum(GetBitContext *gb)
78cabdff1aSopenharmony_ci{
79cabdff1aSopenharmony_ci    return jxl_u32(gb, 0, 1, 2, 18, 0, 0, 4, 6);
80cabdff1aSopenharmony_ci}
81cabdff1aSopenharmony_ci
82cabdff1aSopenharmony_ci/* read a U64() */
83cabdff1aSopenharmony_cistatic uint64_t jpegxl_u64(GetBitContext *gb)
84cabdff1aSopenharmony_ci{
85cabdff1aSopenharmony_ci    uint64_t shift = 12, ret;
86cabdff1aSopenharmony_ci
87cabdff1aSopenharmony_ci    switch (get_bits(gb, 2)) {
88cabdff1aSopenharmony_ci    case 0:
89cabdff1aSopenharmony_ci        ret = 0;
90cabdff1aSopenharmony_ci        break;
91cabdff1aSopenharmony_ci    case 1:
92cabdff1aSopenharmony_ci        ret = 1 + get_bits(gb, 4);
93cabdff1aSopenharmony_ci        break;
94cabdff1aSopenharmony_ci    case 2:
95cabdff1aSopenharmony_ci        ret = 17 + get_bits(gb, 8);
96cabdff1aSopenharmony_ci        break;
97cabdff1aSopenharmony_ci    case 3:
98cabdff1aSopenharmony_ci        ret = get_bits(gb, 12);
99cabdff1aSopenharmony_ci        while (get_bits1(gb)) {
100cabdff1aSopenharmony_ci            if (shift < 60) {
101cabdff1aSopenharmony_ci                ret |= (uint64_t)get_bits(gb, 8) << shift;
102cabdff1aSopenharmony_ci                shift += 8;
103cabdff1aSopenharmony_ci            } else {
104cabdff1aSopenharmony_ci                ret |= (uint64_t)get_bits(gb, 4) << shift;
105cabdff1aSopenharmony_ci                break;
106cabdff1aSopenharmony_ci            }
107cabdff1aSopenharmony_ci        }
108cabdff1aSopenharmony_ci        break;
109cabdff1aSopenharmony_ci    }
110cabdff1aSopenharmony_ci
111cabdff1aSopenharmony_ci    return ret;
112cabdff1aSopenharmony_ci}
113cabdff1aSopenharmony_ci
114cabdff1aSopenharmony_cistatic uint32_t jpegxl_width_from_ratio(uint32_t height, int ratio)
115cabdff1aSopenharmony_ci{
116cabdff1aSopenharmony_ci    uint64_t height64 = height; /* avoid integer overflow */
117cabdff1aSopenharmony_ci    switch (ratio) {
118cabdff1aSopenharmony_ci    case 1:
119cabdff1aSopenharmony_ci        return height;
120cabdff1aSopenharmony_ci    case 2:
121cabdff1aSopenharmony_ci        return (uint32_t)((height64 * 12) / 10);
122cabdff1aSopenharmony_ci    case 3:
123cabdff1aSopenharmony_ci        return (uint32_t)((height64 * 4) / 3);
124cabdff1aSopenharmony_ci    case 4:
125cabdff1aSopenharmony_ci        return (uint32_t)((height64 * 3) / 2);
126cabdff1aSopenharmony_ci    case 5:
127cabdff1aSopenharmony_ci        return (uint32_t)((height64 * 16) / 9);
128cabdff1aSopenharmony_ci    case 6:
129cabdff1aSopenharmony_ci        return (uint32_t)((height64 * 5) / 4);
130cabdff1aSopenharmony_ci    case 7:
131cabdff1aSopenharmony_ci        return (uint32_t)(height64 * 2);
132cabdff1aSopenharmony_ci    default:
133cabdff1aSopenharmony_ci        break;
134cabdff1aSopenharmony_ci    }
135cabdff1aSopenharmony_ci
136cabdff1aSopenharmony_ci    return 0; /* manual width */
137cabdff1aSopenharmony_ci}
138cabdff1aSopenharmony_ci
139cabdff1aSopenharmony_ci/**
140cabdff1aSopenharmony_ci * validate a Jpeg XL Size Header
141cabdff1aSopenharmony_ci * @return >= 0 upon valid size, < 0 upon invalid size found
142cabdff1aSopenharmony_ci */
143cabdff1aSopenharmony_cistatic int jpegxl_read_size_header(GetBitContext *gb)
144cabdff1aSopenharmony_ci{
145cabdff1aSopenharmony_ci    uint32_t width, height;
146cabdff1aSopenharmony_ci
147cabdff1aSopenharmony_ci    if (get_bits1(gb)) {
148cabdff1aSopenharmony_ci        /* small size header */
149cabdff1aSopenharmony_ci        height = (get_bits(gb, 5) + 1) << 3;
150cabdff1aSopenharmony_ci        width = jpegxl_width_from_ratio(height, get_bits(gb, 3));
151cabdff1aSopenharmony_ci        if (!width)
152cabdff1aSopenharmony_ci            width = (get_bits(gb, 5) + 1) << 3;
153cabdff1aSopenharmony_ci    } else {
154cabdff1aSopenharmony_ci        /* large size header */
155cabdff1aSopenharmony_ci        height = 1 + jxl_u32(gb, 0, 0, 0, 0, 9, 13, 18, 30);
156cabdff1aSopenharmony_ci        width = jpegxl_width_from_ratio(height, get_bits(gb, 3));
157cabdff1aSopenharmony_ci        if (!width)
158cabdff1aSopenharmony_ci            width = 1 + jxl_u32(gb, 0, 0, 0, 0, 9, 13, 18, 30);
159cabdff1aSopenharmony_ci    }
160cabdff1aSopenharmony_ci    if (width > (1 << 18) || height > (1 << 18)
161cabdff1aSopenharmony_ci        || (width >> 4) * (height >> 4) > (1 << 20))
162cabdff1aSopenharmony_ci        return -1;
163cabdff1aSopenharmony_ci
164cabdff1aSopenharmony_ci    return 0;
165cabdff1aSopenharmony_ci}
166cabdff1aSopenharmony_ci
167cabdff1aSopenharmony_ci/**
168cabdff1aSopenharmony_ci * validate a Jpeg XL Preview Header
169cabdff1aSopenharmony_ci * @return >= 0 upon valid size, < 0 upon invalid size found
170cabdff1aSopenharmony_ci */
171cabdff1aSopenharmony_cistatic int jpegxl_read_preview_header(GetBitContext *gb)
172cabdff1aSopenharmony_ci{
173cabdff1aSopenharmony_ci    uint32_t width, height;
174cabdff1aSopenharmony_ci
175cabdff1aSopenharmony_ci    if (get_bits1(gb)) {
176cabdff1aSopenharmony_ci        /* coded height and width divided by eight */
177cabdff1aSopenharmony_ci        height = jxl_u32(gb, 16, 32, 1, 33, 0, 0, 5, 9) << 3;
178cabdff1aSopenharmony_ci        width = jpegxl_width_from_ratio(height, get_bits(gb, 3));
179cabdff1aSopenharmony_ci        if (!width)
180cabdff1aSopenharmony_ci            width = jxl_u32(gb, 16, 32, 1, 33, 0, 0, 5, 9) << 3;
181cabdff1aSopenharmony_ci    } else {
182cabdff1aSopenharmony_ci        /* full height and width coded */
183cabdff1aSopenharmony_ci        height = jxl_u32(gb, 1, 65, 321, 1345, 6, 8, 10, 12);
184cabdff1aSopenharmony_ci        width = jpegxl_width_from_ratio(height, get_bits(gb, 3));
185cabdff1aSopenharmony_ci        if (!width)
186cabdff1aSopenharmony_ci            width = jxl_u32(gb, 1, 65, 321, 1345, 6, 8, 10, 12);
187cabdff1aSopenharmony_ci    }
188cabdff1aSopenharmony_ci    if (width > 4096 || height > 4096)
189cabdff1aSopenharmony_ci        return -1;
190cabdff1aSopenharmony_ci
191cabdff1aSopenharmony_ci    return 0;
192cabdff1aSopenharmony_ci}
193cabdff1aSopenharmony_ci
194cabdff1aSopenharmony_ci/**
195cabdff1aSopenharmony_ci * skip a Jpeg XL BitDepth Header. These cannot be invalid.
196cabdff1aSopenharmony_ci */
197cabdff1aSopenharmony_cistatic void jpegxl_skip_bit_depth(GetBitContext *gb)
198cabdff1aSopenharmony_ci{
199cabdff1aSopenharmony_ci    if (get_bits1(gb)) {
200cabdff1aSopenharmony_ci        /* float samples */
201cabdff1aSopenharmony_ci        jxl_u32(gb, 32, 16, 24, 1, 0, 0, 0, 6); /* mantissa */
202cabdff1aSopenharmony_ci        skip_bits_long(gb, 4); /* exponent */
203cabdff1aSopenharmony_ci    } else {
204cabdff1aSopenharmony_ci        /* integer samples */
205cabdff1aSopenharmony_ci        jxl_u32(gb, 8, 10, 12, 1, 0, 0, 0, 6);
206cabdff1aSopenharmony_ci    }
207cabdff1aSopenharmony_ci}
208cabdff1aSopenharmony_ci
209cabdff1aSopenharmony_ci/**
210cabdff1aSopenharmony_ci * validate a Jpeg XL Extra Channel Info bundle
211cabdff1aSopenharmony_ci * @return >= 0 upon valid, < 0 upon invalid
212cabdff1aSopenharmony_ci */
213cabdff1aSopenharmony_cistatic int jpegxl_read_extra_channel_info(GetBitContext *gb)
214cabdff1aSopenharmony_ci{
215cabdff1aSopenharmony_ci    int all_default = get_bits1(gb);
216cabdff1aSopenharmony_ci    uint32_t type, name_len = 0;
217cabdff1aSopenharmony_ci
218cabdff1aSopenharmony_ci    if (!all_default) {
219cabdff1aSopenharmony_ci        type = jxl_enum(gb);
220cabdff1aSopenharmony_ci        if (type > 63)
221cabdff1aSopenharmony_ci            return -1; /* enum types cannot be 64+ */
222cabdff1aSopenharmony_ci        if (type == FF_JPEGXL_CT_BLACK)
223cabdff1aSopenharmony_ci            return -1;
224cabdff1aSopenharmony_ci        jpegxl_skip_bit_depth(gb);
225cabdff1aSopenharmony_ci        jxl_u32(gb, 0, 3, 4, 1, 0, 0, 0, 3); /* dim-shift */
226cabdff1aSopenharmony_ci        /* max of name_len is 1071 = 48 + 2^10 - 1 */
227cabdff1aSopenharmony_ci        name_len = jxl_u32(gb, 0, 0, 16, 48, 0, 4, 5, 10);
228cabdff1aSopenharmony_ci    } else {
229cabdff1aSopenharmony_ci        type = FF_JPEGXL_CT_ALPHA;
230cabdff1aSopenharmony_ci    }
231cabdff1aSopenharmony_ci
232cabdff1aSopenharmony_ci    /* skip over the name */
233cabdff1aSopenharmony_ci    skip_bits_long(gb, 8 * name_len);
234cabdff1aSopenharmony_ci
235cabdff1aSopenharmony_ci    if (!all_default && type == FF_JPEGXL_CT_ALPHA)
236cabdff1aSopenharmony_ci        skip_bits1(gb);
237cabdff1aSopenharmony_ci
238cabdff1aSopenharmony_ci    if (type == FF_JPEGXL_CT_SPOT_COLOR)
239cabdff1aSopenharmony_ci        skip_bits_long(gb, 16 * 4);
240cabdff1aSopenharmony_ci
241cabdff1aSopenharmony_ci    if (type == FF_JPEGXL_CT_CFA)
242cabdff1aSopenharmony_ci        jxl_u32(gb, 1, 0, 3, 19, 0, 2, 4, 8);
243cabdff1aSopenharmony_ci
244cabdff1aSopenharmony_ci    return 0;
245cabdff1aSopenharmony_ci}
246cabdff1aSopenharmony_ci
247cabdff1aSopenharmony_ci/* verify that a codestream header is valid */
248cabdff1aSopenharmony_ciint ff_jpegxl_verify_codestream_header(const uint8_t *buf, int buflen)
249cabdff1aSopenharmony_ci{
250cabdff1aSopenharmony_ci    GetBitContext gbi, *gb = &gbi;
251cabdff1aSopenharmony_ci    int all_default, extra_fields = 0;
252cabdff1aSopenharmony_ci    int xyb_encoded = 1, have_icc_profile = 0;
253cabdff1aSopenharmony_ci    uint32_t num_extra_channels;
254cabdff1aSopenharmony_ci    uint64_t extensions;
255cabdff1aSopenharmony_ci    int ret;
256cabdff1aSopenharmony_ci
257cabdff1aSopenharmony_ci    ret = init_get_bits8(gb, buf, buflen);
258cabdff1aSopenharmony_ci    if (ret < 0)
259cabdff1aSopenharmony_ci        return ret;
260cabdff1aSopenharmony_ci
261cabdff1aSopenharmony_ci    if (get_bits_long(gb, 16) != FF_JPEGXL_CODESTREAM_SIGNATURE_LE)
262cabdff1aSopenharmony_ci        return -1;
263cabdff1aSopenharmony_ci
264cabdff1aSopenharmony_ci    if ((ret = jpegxl_read_size_header(gb)) < 0)
265cabdff1aSopenharmony_ci        return ret;
266cabdff1aSopenharmony_ci
267cabdff1aSopenharmony_ci    all_default = get_bits1(gb);
268cabdff1aSopenharmony_ci    if (!all_default)
269cabdff1aSopenharmony_ci        extra_fields = get_bits1(gb);
270cabdff1aSopenharmony_ci
271cabdff1aSopenharmony_ci    if (extra_fields) {
272cabdff1aSopenharmony_ci        skip_bits_long(gb, 3); /* orientation */
273cabdff1aSopenharmony_ci
274cabdff1aSopenharmony_ci        /*
275cabdff1aSopenharmony_ci         * intrinstic size
276cabdff1aSopenharmony_ci         * any size header here is valid, but as it
277cabdff1aSopenharmony_ci         * is variable length we have to read it
278cabdff1aSopenharmony_ci         */
279cabdff1aSopenharmony_ci        if (get_bits1(gb))
280cabdff1aSopenharmony_ci            jpegxl_read_size_header(gb);
281cabdff1aSopenharmony_ci
282cabdff1aSopenharmony_ci        /* preview header */
283cabdff1aSopenharmony_ci        if (get_bits1(gb)) {
284cabdff1aSopenharmony_ci            ret = jpegxl_read_preview_header(gb);
285cabdff1aSopenharmony_ci            if (ret < 0)
286cabdff1aSopenharmony_ci                return ret;
287cabdff1aSopenharmony_ci        }
288cabdff1aSopenharmony_ci
289cabdff1aSopenharmony_ci        /* animation header */
290cabdff1aSopenharmony_ci        if (get_bits1(gb)) {
291cabdff1aSopenharmony_ci            jxl_u32(gb, 100, 1000, 1, 1, 0, 0, 10, 30);
292cabdff1aSopenharmony_ci            jxl_u32(gb, 1, 1001, 1, 1, 0, 0, 8, 10);
293cabdff1aSopenharmony_ci            jxl_u32(gb, 0, 0, 0, 0, 0, 3, 16, 32);
294cabdff1aSopenharmony_ci            skip_bits_long(gb, 1);
295cabdff1aSopenharmony_ci        }
296cabdff1aSopenharmony_ci    }
297cabdff1aSopenharmony_ci    if (get_bits_left(gb) < 1)
298cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
299cabdff1aSopenharmony_ci
300cabdff1aSopenharmony_ci    if (!all_default) {
301cabdff1aSopenharmony_ci        jpegxl_skip_bit_depth(gb);
302cabdff1aSopenharmony_ci
303cabdff1aSopenharmony_ci        /* modular_16bit_buffers must equal 1 */
304cabdff1aSopenharmony_ci        if (!get_bits1(gb))
305cabdff1aSopenharmony_ci            return -1;
306cabdff1aSopenharmony_ci
307cabdff1aSopenharmony_ci        num_extra_channels = jxl_u32(gb, 0, 1, 2, 1, 0, 0, 4, 12);
308cabdff1aSopenharmony_ci        if (num_extra_channels > 4)
309cabdff1aSopenharmony_ci            return -1;
310cabdff1aSopenharmony_ci        for (uint32_t i = 0; i < num_extra_channels; i++) {
311cabdff1aSopenharmony_ci            ret = jpegxl_read_extra_channel_info(gb);
312cabdff1aSopenharmony_ci            if (ret < 0)
313cabdff1aSopenharmony_ci                return ret;
314cabdff1aSopenharmony_ci            if (get_bits_left(gb) < 1)
315cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
316cabdff1aSopenharmony_ci        }
317cabdff1aSopenharmony_ci
318cabdff1aSopenharmony_ci        xyb_encoded = get_bits1(gb);
319cabdff1aSopenharmony_ci
320cabdff1aSopenharmony_ci        /* color encoding bundle */
321cabdff1aSopenharmony_ci        if (!get_bits1(gb)) {
322cabdff1aSopenharmony_ci            uint32_t color_space;
323cabdff1aSopenharmony_ci            have_icc_profile = get_bits1(gb);
324cabdff1aSopenharmony_ci            color_space = jxl_enum(gb);
325cabdff1aSopenharmony_ci            if (color_space > 63)
326cabdff1aSopenharmony_ci                return -1;
327cabdff1aSopenharmony_ci
328cabdff1aSopenharmony_ci            if (!have_icc_profile) {
329cabdff1aSopenharmony_ci                if (color_space != FF_JPEGXL_CS_XYB) {
330cabdff1aSopenharmony_ci                    uint32_t white_point = jxl_enum(gb);
331cabdff1aSopenharmony_ci                    if (white_point > 63)
332cabdff1aSopenharmony_ci                        return -1;
333cabdff1aSopenharmony_ci                    if (white_point == FF_JPEGXL_WP_CUSTOM) {
334cabdff1aSopenharmony_ci                        /* ux and uy values */
335cabdff1aSopenharmony_ci                        jxl_u32(gb, 0, 524288, 1048576, 2097152, 19, 19, 20, 21);
336cabdff1aSopenharmony_ci                        jxl_u32(gb, 0, 524288, 1048576, 2097152, 19, 19, 20, 21);
337cabdff1aSopenharmony_ci                    }
338cabdff1aSopenharmony_ci                    if (color_space != FF_JPEGXL_CS_GRAY) {
339cabdff1aSopenharmony_ci                        /* primaries */
340cabdff1aSopenharmony_ci                        uint32_t primaries = jxl_enum(gb);
341cabdff1aSopenharmony_ci                        if (primaries > 63)
342cabdff1aSopenharmony_ci                            return -1;
343cabdff1aSopenharmony_ci                        if (primaries == FF_JPEGXL_PR_CUSTOM) {
344cabdff1aSopenharmony_ci                            /* ux/uy values for r,g,b */
345cabdff1aSopenharmony_ci                            for (int i = 0; i < 6; i++) {
346cabdff1aSopenharmony_ci                                jxl_u32(gb, 0, 524288, 1048576, 2097152, 19, 19, 20, 21);
347cabdff1aSopenharmony_ci                                if (get_bits_left(gb) < 1)
348cabdff1aSopenharmony_ci                                    return AVERROR_INVALIDDATA;
349cabdff1aSopenharmony_ci                            }
350cabdff1aSopenharmony_ci                        }
351cabdff1aSopenharmony_ci                    }
352cabdff1aSopenharmony_ci                }
353cabdff1aSopenharmony_ci
354cabdff1aSopenharmony_ci                /* transfer characteristics */
355cabdff1aSopenharmony_ci                if (get_bits1(gb)) {
356cabdff1aSopenharmony_ci                    /* gamma */
357cabdff1aSopenharmony_ci                    skip_bits_long(gb, 24);
358cabdff1aSopenharmony_ci                } else {
359cabdff1aSopenharmony_ci                    /* transfer function */
360cabdff1aSopenharmony_ci                    if (jxl_enum(gb) > 63)
361cabdff1aSopenharmony_ci                        return -1;
362cabdff1aSopenharmony_ci                }
363cabdff1aSopenharmony_ci
364cabdff1aSopenharmony_ci                /* rendering intent */
365cabdff1aSopenharmony_ci                if (jxl_enum(gb) > 63)
366cabdff1aSopenharmony_ci                    return -1;
367cabdff1aSopenharmony_ci            }
368cabdff1aSopenharmony_ci        }
369cabdff1aSopenharmony_ci
370cabdff1aSopenharmony_ci        /* tone mapping bundle */
371cabdff1aSopenharmony_ci        if (extra_fields && !get_bits1(gb))
372cabdff1aSopenharmony_ci            skip_bits_long(gb, 16 + 16 + 1 + 16);
373cabdff1aSopenharmony_ci
374cabdff1aSopenharmony_ci        extensions = jpegxl_u64(gb);
375cabdff1aSopenharmony_ci        if (get_bits_left(gb) < 1)
376cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
377cabdff1aSopenharmony_ci        if (extensions) {
378cabdff1aSopenharmony_ci            for (int i = 0; i < 64; i++) {
379cabdff1aSopenharmony_ci                if (extensions & (UINT64_C(1) << i))
380cabdff1aSopenharmony_ci                    jpegxl_u64(gb);
381cabdff1aSopenharmony_ci                if (get_bits_left(gb) < 1)
382cabdff1aSopenharmony_ci                    return AVERROR_INVALIDDATA;
383cabdff1aSopenharmony_ci            }
384cabdff1aSopenharmony_ci        }
385cabdff1aSopenharmony_ci    }
386cabdff1aSopenharmony_ci
387cabdff1aSopenharmony_ci    /* default transform */
388cabdff1aSopenharmony_ci    if (!get_bits1(gb)) {
389cabdff1aSopenharmony_ci        /* opsin inverse matrix */
390cabdff1aSopenharmony_ci        if (xyb_encoded && !get_bits1(gb))
391cabdff1aSopenharmony_ci            skip_bits_long(gb, 16 * 16);
392cabdff1aSopenharmony_ci        /* cw_mask and default weights */
393cabdff1aSopenharmony_ci        if (get_bits1(gb))
394cabdff1aSopenharmony_ci            skip_bits_long(gb, 16 * 15);
395cabdff1aSopenharmony_ci        if (get_bits1(gb))
396cabdff1aSopenharmony_ci            skip_bits_long(gb, 16 * 55);
397cabdff1aSopenharmony_ci        if (get_bits1(gb))
398cabdff1aSopenharmony_ci            skip_bits_long(gb, 16 * 210);
399cabdff1aSopenharmony_ci    }
400cabdff1aSopenharmony_ci
401cabdff1aSopenharmony_ci    if (!have_icc_profile) {
402cabdff1aSopenharmony_ci        int bits_remaining = 7 - (get_bits_count(gb) - 1) % 8;
403cabdff1aSopenharmony_ci        if (bits_remaining && get_bits(gb, bits_remaining))
404cabdff1aSopenharmony_ci            return -1;
405cabdff1aSopenharmony_ci    }
406cabdff1aSopenharmony_ci
407cabdff1aSopenharmony_ci    if (get_bits_left(gb) < 0)
408cabdff1aSopenharmony_ci        return -1;
409cabdff1aSopenharmony_ci
410cabdff1aSopenharmony_ci    return 0;
411cabdff1aSopenharmony_ci}
412