Skip to content

Commit ba9e8b8

Browse files
committed
Fix HTJ2K chunk header length error
Group common HTJ2K functions
1 parent 9dd63df commit ba9e8b8

File tree

3 files changed

+153
-138
lines changed

3 files changed

+153
-138
lines changed

src/lib/OpenEXRCore/internal_ht.cpp

Lines changed: 2 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -18,137 +18,6 @@
1818
#include "openexr_encode.h"
1919
#include "internal_ht_common.h"
2020

21-
/***********************************
22-
23-
Structure of the HTJ2K chunk
24-
- MAGIC = 0x4854: magic number
25-
- PLEN: length of header payload (big endian uint32_t)
26-
- header payload
27-
- NCH: number of channels in channel map (big endian uint16_t)
28-
- for(i = 0; i < NCH; i++)
29-
- CS_TO_F[i]: OpenEXR channel index corresponding to J2K component index i (big endian uint16_t)
30-
- any number of opaque bytes
31-
- CS: JPEG 2000 Codestream
32-
33-
***********************************/
34-
35-
class MemoryReader
36-
{
37-
public:
38-
MemoryReader (uint8_t* buffer, size_t max_sz)
39-
: buffer (buffer), cur (buffer), end (buffer + max_sz){};
40-
41-
uint32_t pull_uint32 ()
42-
{
43-
if (this->end - this->cur < 4)
44-
throw std::out_of_range ("Insufficient data to pull uint32_t");
45-
46-
uint32_t v = *this->cur++;
47-
v = (v << 8) + *this->cur++;
48-
v = (v << 8) + *this->cur++;
49-
return (v << 8) + *cur++;
50-
}
51-
52-
uint16_t pull_uint16 ()
53-
{
54-
if (this->end - this->cur < 2)
55-
throw std::out_of_range ("Insufficient data to pull uint16_t");
56-
57-
uint32_t v = *cur++;
58-
return (v << 8) + *cur++;
59-
}
60-
61-
protected:
62-
uint8_t* buffer;
63-
uint8_t* cur;
64-
uint8_t* end;
65-
};
66-
67-
class MemoryWriter
68-
{
69-
public:
70-
MemoryWriter (uint8_t* buffer, size_t max_sz)
71-
: buffer (buffer), cur (buffer), end (buffer + max_sz){};
72-
73-
void push_uint32 (uint32_t value)
74-
{
75-
if (this->end - this->cur < 4)
76-
throw std::range_error ("Insufficient data to push uint32_t");
77-
78-
*this->cur++ = (value >> 24) & 0xFF;
79-
*this->cur++ = (value >> 16) & 0xFF;
80-
*this->cur++ = (value >> 8) & 0xFF;
81-
*this->cur++ = value & 0xFF;
82-
}
83-
84-
void push_uint16 (uint16_t value)
85-
{
86-
if (this->end - this->cur < 2)
87-
throw std::range_error ("Insufficient data to push uint32_t");
88-
89-
*this->cur++ = (value >> 8) & 0xFF;
90-
*this->cur++ = value & 0xFF;
91-
}
92-
93-
size_t get_size () { return this->cur - this->buffer; }
94-
95-
uint8_t* get_buffer () { return this->buffer; }
96-
97-
uint8_t* get_cur () { return this->cur; }
98-
99-
protected:
100-
uint8_t* buffer;
101-
uint8_t* cur;
102-
uint8_t* end;
103-
};
104-
105-
constexpr uint16_t HEADER_MARKER = 'H' * 256 + 'T';
106-
107-
size_t
108-
write_header (
109-
uint8_t* buffer,
110-
size_t max_sz,
111-
const std::vector<CodestreamChannelInfo>& map)
112-
{
113-
constexpr uint16_t HEADER_SZ = 6;
114-
MemoryWriter payload (buffer + HEADER_SZ, max_sz - HEADER_SZ);
115-
payload.push_uint16 (map.size ());
116-
for (size_t i = 0; i < map.size (); i++)
117-
{
118-
payload.push_uint16 (map.at (i).file_index);
119-
}
120-
121-
MemoryWriter header (buffer, max_sz);
122-
header.push_uint16 (HEADER_MARKER);
123-
header.push_uint32 (payload.get_size ());
124-
125-
return header.get_size () + payload.get_size ();
126-
}
127-
128-
void
129-
read_header (
130-
void* buffer,
131-
size_t max_sz,
132-
size_t& length,
133-
std::vector<CodestreamChannelInfo>& map)
134-
{
135-
MemoryReader header ((uint8_t*) buffer, max_sz);
136-
if (header.pull_uint16 () != HEADER_MARKER)
137-
throw std::runtime_error (
138-
"HTJ2K chunk header missing does not start with magic number.");
139-
140-
length = header.pull_uint32 ();
141-
142-
if (length < 2)
143-
throw std::runtime_error ("Error while reading the channel map");
144-
145-
map.resize (header.pull_uint16 ());
146-
for (size_t i = 0; i < map.size (); i++)
147-
{
148-
map.at (i).file_index = header.pull_uint16 ();
149-
}
150-
}
151-
15221
/**
15322
* OpenJPH output file that is backed by a fixed-size memory buffer
15423
*/
@@ -303,8 +172,8 @@ internal_exr_undo_ht (
303172
/* read the channel map */
304173

305174
size_t header_sz;
306-
read_header (
307-
(uint8_t*) compressed_data, comp_buf_size, header_sz, cs_to_file_ch);
175+
header_sz = read_header (
176+
(uint8_t*) compressed_data, comp_buf_size, cs_to_file_ch);
308177
if (decode->channel_count != cs_to_file_ch.size ())
309178
throw std::runtime_error ("Unexpected number of channels");
310179

src/lib/OpenEXRCore/internal_ht_common.cpp

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,3 +177,137 @@ make_channel_map (
177177

178178
return isRGB;
179179
}
180+
181+
/***********************************
182+
183+
Structure of the HTJ2K chunk
184+
- MAGIC = 0x4854: magic number
185+
- PLEN: length of header payload (big endian uint32_t)
186+
- header payload
187+
- NCH: number of channels in channel map (big endian uint16_t)
188+
- for(i = 0; i < NCH; i++)
189+
- CS_TO_F[i]: OpenEXR channel index corresponding to J2K component index i (big endian uint16_t)
190+
- any number of opaque bytes
191+
- CS: JPEG 2000 Codestream
192+
193+
***********************************/
194+
195+
class MemoryReader
196+
{
197+
public:
198+
MemoryReader (uint8_t* buffer, size_t max_sz)
199+
: buffer (buffer), cur (buffer), end (buffer + max_sz){};
200+
201+
uint32_t pull_uint32 ()
202+
{
203+
if (this->end - this->cur < 4)
204+
throw std::out_of_range ("Insufficient data to pull uint32_t");
205+
206+
uint32_t v = *this->cur++;
207+
v = (v << 8) + *this->cur++;
208+
v = (v << 8) + *this->cur++;
209+
return (v << 8) + *cur++;
210+
}
211+
212+
uint16_t pull_uint16 ()
213+
{
214+
if (this->end - this->cur < 2)
215+
throw std::out_of_range ("Insufficient data to pull uint16_t");
216+
217+
uint32_t v = *cur++;
218+
return (v << 8) + *cur++;
219+
}
220+
221+
protected:
222+
uint8_t* buffer;
223+
uint8_t* cur;
224+
uint8_t* end;
225+
};
226+
227+
class MemoryWriter
228+
{
229+
public:
230+
MemoryWriter (uint8_t* buffer, size_t max_sz)
231+
: buffer (buffer), cur (buffer), end (buffer + max_sz){};
232+
233+
void push_uint32 (uint32_t value)
234+
{
235+
if (this->end - this->cur < 4)
236+
throw std::range_error ("Insufficient data to push uint32_t");
237+
238+
*this->cur++ = (value >> 24) & 0xFF;
239+
*this->cur++ = (value >> 16) & 0xFF;
240+
*this->cur++ = (value >> 8) & 0xFF;
241+
*this->cur++ = value & 0xFF;
242+
}
243+
244+
void push_uint16 (uint16_t value)
245+
{
246+
if (this->end - this->cur < 2)
247+
throw std::range_error ("Insufficient data to push uint32_t");
248+
249+
*this->cur++ = (value >> 8) & 0xFF;
250+
*this->cur++ = value & 0xFF;
251+
}
252+
253+
size_t get_size () { return this->cur - this->buffer; }
254+
255+
uint8_t* get_buffer () { return this->buffer; }
256+
257+
uint8_t* get_cur () { return this->cur; }
258+
259+
protected:
260+
uint8_t* buffer;
261+
uint8_t* cur;
262+
uint8_t* end;
263+
};
264+
265+
constexpr uint16_t HEADER_MARKER = 'H' * 256 + 'T';
266+
constexpr uint16_t HEADER_SZ = 6;
267+
268+
size_t
269+
write_header (
270+
uint8_t* buffer,
271+
size_t max_sz,
272+
const std::vector<CodestreamChannelInfo>& map)
273+
{
274+
MemoryWriter payload (buffer + HEADER_SZ, max_sz - HEADER_SZ);
275+
payload.push_uint16 (map.size ());
276+
for (size_t i = 0; i < map.size (); i++)
277+
{
278+
payload.push_uint16 (map.at (i).file_index);
279+
}
280+
281+
MemoryWriter header (buffer, max_sz);
282+
header.push_uint16 (HEADER_MARKER);
283+
header.push_uint32 (payload.get_size ());
284+
285+
return header.get_size () + payload.get_size ();
286+
}
287+
288+
size_t
289+
read_header (
290+
void* buffer,
291+
size_t max_sz,
292+
std::vector<CodestreamChannelInfo>& map)
293+
{
294+
MemoryReader header ((uint8_t*) buffer, max_sz);
295+
if (header.pull_uint16 () != HEADER_MARKER)
296+
throw std::runtime_error (
297+
"HTJ2K chunk header missing does not start with magic number.");
298+
299+
size_t length = header.pull_uint32 ();
300+
301+
if (length < 2)
302+
throw std::runtime_error ("Error while reading the channel map");
303+
304+
length += HEADER_SZ;
305+
306+
map.resize (header.pull_uint16 ());
307+
for (size_t i = 0; i < map.size (); i++)
308+
{
309+
map.at (i).file_index = header.pull_uint16 ();
310+
}
311+
312+
return length;
313+
}

src/lib/OpenEXRCore/internal_ht_common.h

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,25 @@
1010
#include <stdlib.h>
1111
#include "openexr_coding.h"
1212

13-
struct CodestreamChannelInfo {
14-
int file_index;
13+
struct CodestreamChannelInfo
14+
{
15+
int file_index;
1516
size_t raster_line_offset;
1617
};
1718

18-
bool
19-
make_channel_map (
20-
int channel_count, exr_coding_channel_info_t* channels, std::vector<CodestreamChannelInfo>& cs_to_file_ch);
19+
bool make_channel_map (
20+
int channel_count,
21+
exr_coding_channel_info_t* channels,
22+
std::vector<CodestreamChannelInfo>& cs_to_file_ch);
23+
24+
size_t write_header (
25+
uint8_t* buffer,
26+
size_t max_sz,
27+
const std::vector<CodestreamChannelInfo>& map);
28+
29+
size_t read_header (
30+
void* buffer,
31+
size_t max_sz,
32+
std::vector<CodestreamChannelInfo>& map);
2133

2234
#endif /* OPENEXR_PRIVATE_HT_COMMON_H */

0 commit comments

Comments
 (0)