/src/libraw/src/decoders/unpack_thumb.cpp
Line | Count | Source |
1 | | /* -*- C++ -*- |
2 | | * Copyright 2019-2025 LibRaw LLC (info@libraw.org) |
3 | | * |
4 | | LibRaw is free software; you can redistribute it and/or modify |
5 | | it under the terms of the one of two licenses as you choose: |
6 | | |
7 | | 1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 |
8 | | (See file LICENSE.LGPL provided in LibRaw distribution archive for details). |
9 | | |
10 | | 2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 |
11 | | (See file LICENSE.CDDL provided in LibRaw distribution archive for details). |
12 | | |
13 | | */ |
14 | | |
15 | | #include "../../internal/libraw_cxx_defs.h" |
16 | | |
17 | | #ifndef NO_JPEG |
18 | | struct jpegErrorManager |
19 | | { |
20 | | struct jpeg_error_mgr pub; |
21 | | jmp_buf setjmp_buffer; |
22 | | }; |
23 | | |
24 | | static void jpegErrorExit(j_common_ptr cinfo) |
25 | | { |
26 | | jpegErrorManager *myerr = (jpegErrorManager *)cinfo->err; |
27 | | longjmp(myerr->setjmp_buffer, 1); |
28 | | } |
29 | | #endif |
30 | | |
31 | | int LibRaw::unpack_thumb_ex(int idx) |
32 | 0 | { |
33 | 0 | if (idx < 0 || idx >= imgdata.thumbs_list.thumbcount || idx >= LIBRAW_THUMBNAIL_MAXCOUNT) |
34 | 0 | return LIBRAW_REQUEST_FOR_NONEXISTENT_THUMBNAIL; |
35 | | |
36 | | // Set from thumb-list |
37 | 0 | libraw_internal_data.internal_data.toffset = imgdata.thumbs_list.thumblist[idx].toffset; |
38 | 0 | imgdata.thumbnail.tlength = imgdata.thumbs_list.thumblist[idx].tlength; |
39 | 0 | libraw_internal_data.unpacker_data.thumb_format = imgdata.thumbs_list.thumblist[idx].tformat; |
40 | 0 | imgdata.thumbnail.twidth = imgdata.thumbs_list.thumblist[idx].twidth; |
41 | 0 | imgdata.thumbnail.theight = imgdata.thumbs_list.thumblist[idx].theight; |
42 | 0 | libraw_internal_data.unpacker_data.thumb_misc = imgdata.thumbs_list.thumblist[idx].tmisc; |
43 | 0 | int rc = unpack_thumb(); |
44 | 0 | imgdata.progress_flags &= ~LIBRAW_PROGRESS_THUMB_LOAD; |
45 | |
|
46 | 0 | return rc; |
47 | 0 | } |
48 | | |
49 | | |
50 | | int LibRaw::unpack_thumb(void) |
51 | 0 | { |
52 | 0 | CHECK_ORDER_LOW(LIBRAW_PROGRESS_IDENTIFY); |
53 | 0 | CHECK_ORDER_BIT(LIBRAW_PROGRESS_THUMB_LOAD); |
54 | | |
55 | 0 | #define THUMB_SIZE_CHECKT(A) \ |
56 | 0 | do { \ |
57 | 0 | if (INT64(A) > 1024LL * 1024LL * LIBRAW_MAX_THUMBNAIL_MB) return LIBRAW_UNSUPPORTED_THUMBNAIL; \ |
58 | 0 | if (INT64(A) > 0 && INT64(A) < 64LL) return LIBRAW_NO_THUMBNAIL; \ |
59 | 0 | } while (0) |
60 | | |
61 | 0 | #define THUMB_SIZE_CHECKTNZ(A) \ |
62 | 0 | do { \ |
63 | 0 | if (INT64(A) > 1024LL * 1024LL * LIBRAW_MAX_THUMBNAIL_MB) return LIBRAW_UNSUPPORTED_THUMBNAIL; \ |
64 | 0 | if (INT64(A) < 64LL) return LIBRAW_NO_THUMBNAIL; \ |
65 | 0 | } while (0) |
66 | | |
67 | | |
68 | 0 | #define THUMB_SIZE_CHECKWH(W,H) \ |
69 | 0 | do { \ |
70 | 0 | if (INT64(W)*INT64(H) > 1024ULL * 1024ULL * LIBRAW_MAX_THUMBNAIL_MB) return LIBRAW_UNSUPPORTED_THUMBNAIL; \ |
71 | 0 | if (INT64(W)*INT64(H) < 64ULL) return LIBRAW_NO_THUMBNAIL; \ |
72 | 0 | } while (0) |
73 | | |
74 | 0 | #define Tformat libraw_internal_data.unpacker_data.thumb_format |
75 | | |
76 | 0 | try |
77 | 0 | { |
78 | 0 | if (!libraw_internal_data.internal_data.input) |
79 | 0 | return LIBRAW_INPUT_CLOSED; |
80 | | |
81 | 0 | int t_colors = libraw_internal_data.unpacker_data.thumb_misc >> 5 & 7; |
82 | 0 | int t_bytesps = (libraw_internal_data.unpacker_data.thumb_misc & 31) / 8; |
83 | |
|
84 | 0 | if (!ID.toffset && !(imgdata.thumbnail.tlength > 0 && |
85 | 0 | load_raw == &LibRaw::broadcom_load_raw) // RPi |
86 | | #ifdef USE_6BY9RPI |
87 | | && !(imgdata.thumbnail.tlength > 0 && libraw_internal_data.unpacker_data.load_flags & 0x4000 |
88 | | && (load_raw == &LibRaw::rpi_load_raw8 || load_raw == &LibRaw::nokia_load_raw || |
89 | | load_raw == &LibRaw::rpi_load_raw12 || load_raw == &LibRaw::rpi_load_raw14)) |
90 | | #endif |
91 | 0 | ) |
92 | 0 | { |
93 | 0 | return LIBRAW_NO_THUMBNAIL; |
94 | 0 | } |
95 | 0 | else if (Tformat == LIBRAW_INTERNAL_THUMBNAIL_DNG_YCBCR) |
96 | 0 | { |
97 | 0 | try |
98 | 0 | { |
99 | 0 | dng_ycbcr_thumb_loader(); |
100 | 0 | T.tformat = LIBRAW_THUMBNAIL_BITMAP; |
101 | 0 | T.tcolors = 3; |
102 | 0 | SET_PROC_FLAG(LIBRAW_PROGRESS_THUMB_LOAD); |
103 | 0 | } |
104 | 0 | catch (...) |
105 | 0 | { |
106 | 0 | return LIBRAW_NO_THUMBNAIL; |
107 | 0 | } |
108 | 0 | return 0; |
109 | |
|
110 | 0 | } |
111 | 0 | else if ((Tformat >= LIBRAW_INTERNAL_THUMBNAIL_KODAK_THUMB) |
112 | 0 | && ((Tformat <= LIBRAW_INTERNAL_THUMBNAIL_KODAK_RGB))) |
113 | 0 | { |
114 | 0 | try { |
115 | 0 | kodak_thumb_loader(); |
116 | 0 | T.tformat = LIBRAW_THUMBNAIL_BITMAP; |
117 | 0 | SET_PROC_FLAG(LIBRAW_PROGRESS_THUMB_LOAD); |
118 | 0 | } |
119 | 0 | catch (...) |
120 | 0 | { |
121 | 0 | return LIBRAW_NO_THUMBNAIL; |
122 | 0 | } |
123 | 0 | return 0; |
124 | 0 | } |
125 | 0 | else |
126 | 0 | { |
127 | | #ifdef USE_X3FTOOLS |
128 | | if (Tformat == LIBRAW_INTERNAL_THUMBNAIL_X3F) |
129 | | { |
130 | | INT64 tsize = x3f_thumb_size(); |
131 | | if (tsize < 2048 || INT64(ID.toffset) + tsize < 1) |
132 | | return LIBRAW_NO_THUMBNAIL; |
133 | | |
134 | | if (INT64(ID.toffset) + tsize > ID.input->size() + THUMB_READ_BEYOND) |
135 | | return LIBRAW_NO_THUMBNAIL; |
136 | | |
137 | | THUMB_SIZE_CHECKT(tsize); |
138 | | } |
139 | | #else |
140 | 0 | if (0) {} |
141 | 0 | #endif |
142 | 0 | else |
143 | 0 | { |
144 | 0 | if (INT64(ID.toffset) + INT64(T.tlength) < 1) |
145 | 0 | return LIBRAW_NO_THUMBNAIL; |
146 | | |
147 | 0 | if (INT64(ID.toffset) + INT64(T.tlength) > |
148 | 0 | ID.input->size() + THUMB_READ_BEYOND) |
149 | 0 | return LIBRAW_NO_THUMBNAIL; |
150 | 0 | } |
151 | | |
152 | 0 | ID.input->seek(ID.toffset, SEEK_SET); |
153 | 0 | if (Tformat == LIBRAW_INTERNAL_THUMBNAIL_JPEG || Tformat == LIBRAW_INTERNAL_THUMBNAIL_JPEGXL) |
154 | 0 | { |
155 | 0 | THUMB_SIZE_CHECKTNZ(T.tlength); |
156 | 0 | if (T.thumb) |
157 | 0 | free(T.thumb); |
158 | | #ifdef LIBRAW_CALLOC_RAWSTORE |
159 | | T.thumb = (char *)calloc(T.tlength,1); |
160 | | #else |
161 | 0 | T.thumb = (char *)malloc(T.tlength); |
162 | 0 | #endif |
163 | 0 | if(!T.thumb) |
164 | 0 | return LIBRAW_NO_THUMBNAIL; |
165 | 0 | ID.input->read(T.thumb, 1, T.tlength); |
166 | 0 | unsigned char *tthumb = (unsigned char *)T.thumb; |
167 | 0 | if (Tformat == LIBRAW_INTERNAL_THUMBNAIL_JPEGXL) |
168 | 0 | { |
169 | 0 | T.tformat = LIBRAW_THUMBNAIL_JPEGXL; |
170 | 0 | SET_PROC_FLAG(LIBRAW_PROGRESS_THUMB_LOAD); |
171 | 0 | return 0; |
172 | 0 | } |
173 | 0 | if (load_raw == &LibRaw::crxLoadRaw && T.tlength > 0xE0) |
174 | 0 | { |
175 | | // Check if it is canon H.265 preview: CISZ at bytes 4-6, CISZ prefix is 000n |
176 | 0 | if (tthumb[0] == 0 && tthumb[1] == 0 && tthumb[2] == 0 && !memcmp(tthumb + 4, "CISZ", 4)) |
177 | 0 | { |
178 | 0 | T.tformat = LIBRAW_THUMBNAIL_H265; |
179 | 0 | SET_PROC_FLAG(LIBRAW_PROGRESS_THUMB_LOAD); |
180 | 0 | return 0; |
181 | 0 | } |
182 | 0 | } |
183 | 0 | tthumb[0] = 0xff; |
184 | 0 | tthumb[1] = 0xd8; |
185 | 0 | #ifdef NO_JPEG |
186 | 0 | T.tcolors = 3; |
187 | | #else |
188 | | { |
189 | | jpegErrorManager jerr; |
190 | | struct jpeg_decompress_struct cinfo; |
191 | | cinfo.err = jpeg_std_error(&jerr.pub); |
192 | | jerr.pub.error_exit = jpegErrorExit; |
193 | | if (setjmp(jerr.setjmp_buffer)) |
194 | | { |
195 | | err2: |
196 | | // Error in original JPEG thumb, read it again because |
197 | | // original bytes 0-1 was damaged above |
198 | | jpeg_destroy_decompress(&cinfo); |
199 | | T.tcolors = 3; |
200 | | T.tformat = LIBRAW_THUMBNAIL_UNKNOWN; |
201 | | ID.input->seek(ID.toffset, SEEK_SET); |
202 | | ID.input->read(T.thumb, 1, T.tlength); |
203 | | SET_PROC_FLAG(LIBRAW_PROGRESS_THUMB_LOAD); |
204 | | return 0; |
205 | | } |
206 | | jpeg_create_decompress(&cinfo); |
207 | | jpeg_mem_src(&cinfo, (unsigned char *)T.thumb, T.tlength); |
208 | | int rc = jpeg_read_header(&cinfo, TRUE); |
209 | | if (rc != 1) |
210 | | goto err2; |
211 | | T.tcolors = (cinfo.num_components > 0 && cinfo.num_components <= 3) |
212 | | ? cinfo.num_components |
213 | | : 3; |
214 | | jpeg_destroy_decompress(&cinfo); |
215 | | } |
216 | | #endif |
217 | 0 | T.tformat = LIBRAW_THUMBNAIL_JPEG; |
218 | 0 | SET_PROC_FLAG(LIBRAW_PROGRESS_THUMB_LOAD); |
219 | 0 | return 0; |
220 | 0 | } |
221 | 0 | else if (Tformat == LIBRAW_INTERNAL_THUMBNAIL_LAYER) |
222 | 0 | { |
223 | 0 | int colors = libraw_internal_data.unpacker_data.thumb_misc >> 5 & 7; |
224 | 0 | if (colors != 1 && colors != 3) |
225 | 0 | return LIBRAW_UNSUPPORTED_THUMBNAIL; |
226 | | |
227 | 0 | THUMB_SIZE_CHECKWH(T.twidth, T.theight); |
228 | | |
229 | 0 | int tlength = T.twidth * T.theight; |
230 | 0 | if (T.thumb) |
231 | 0 | free(T.thumb); |
232 | 0 | T.thumb = (char *)calloc(colors, tlength); |
233 | 0 | if(!T.thumb) |
234 | 0 | return LIBRAW_NO_THUMBNAIL; |
235 | 0 | unsigned char *tbuf = (unsigned char *)calloc(colors, tlength); |
236 | 0 | if (!tbuf) |
237 | 0 | { |
238 | 0 | free(T.thumb); |
239 | 0 | T.thumb = 0; |
240 | 0 | return LIBRAW_NO_THUMBNAIL; |
241 | 0 | } |
242 | | // Avoid OOB of tbuf, should use tlength |
243 | 0 | ID.input->read(tbuf, colors, tlength); |
244 | 0 | if (libraw_internal_data.unpacker_data.thumb_misc >> 8 && |
245 | 0 | colors == 3) // GRB order |
246 | 0 | for (int i = 0; i < tlength; i++) |
247 | 0 | { |
248 | 0 | T.thumb[i * 3] = tbuf[i + tlength]; |
249 | 0 | T.thumb[i * 3 + 1] = tbuf[i]; |
250 | 0 | T.thumb[i * 3 + 2] = tbuf[i + 2 * tlength]; |
251 | 0 | } |
252 | 0 | else if (colors == 3) // RGB or 1-channel |
253 | 0 | for (int i = 0; i < tlength; i++) |
254 | 0 | { |
255 | 0 | T.thumb[i * 3] = tbuf[i]; |
256 | 0 | T.thumb[i * 3 + 1] = tbuf[i + tlength]; |
257 | 0 | T.thumb[i * 3 + 2] = tbuf[i + 2 * tlength]; |
258 | 0 | } |
259 | 0 | else if (colors == 1) |
260 | 0 | { |
261 | 0 | free(T.thumb); |
262 | 0 | T.thumb = (char *)tbuf; |
263 | 0 | tbuf = 0; |
264 | 0 | } |
265 | 0 | if (tbuf) |
266 | 0 | free(tbuf); |
267 | 0 | T.tcolors = colors; |
268 | 0 | T.tlength = colors * tlength; |
269 | 0 | T.tformat = LIBRAW_THUMBNAIL_BITMAP; |
270 | 0 | SET_PROC_FLAG(LIBRAW_PROGRESS_THUMB_LOAD); |
271 | 0 | return 0; |
272 | 0 | } |
273 | 0 | else if (Tformat == LIBRAW_INTERNAL_THUMBNAIL_ROLLEI) |
274 | 0 | { |
275 | 0 | int i; |
276 | 0 | THUMB_SIZE_CHECKWH(T.twidth, T.theight); |
277 | 0 | int tlength = T.twidth * T.theight; |
278 | 0 | if (T.thumb) |
279 | 0 | free(T.thumb); |
280 | 0 | T.tcolors = 3; |
281 | 0 | T.thumb = (char *)calloc(T.tcolors, tlength); |
282 | 0 | if (!T.thumb) |
283 | 0 | return LIBRAW_NO_THUMBNAIL; |
284 | 0 | unsigned short *tbuf = (unsigned short *)calloc(2, tlength); |
285 | 0 | if (!tbuf) |
286 | 0 | { |
287 | 0 | free(T.thumb); |
288 | 0 | T.thumb = 0; |
289 | 0 | return LIBRAW_NO_THUMBNAIL; |
290 | 0 | } |
291 | 0 | try { |
292 | 0 | read_shorts(tbuf, tlength); |
293 | 0 | for (i = 0; i < tlength; i++) |
294 | 0 | { |
295 | 0 | T.thumb[i * 3] = (tbuf[i] << 3) & 0xff; |
296 | 0 | T.thumb[i * 3 + 1] = (tbuf[i] >> 5 << 2) & 0xff; |
297 | 0 | T.thumb[i * 3 + 2] = (tbuf[i] >> 11 << 3) & 0xff; |
298 | 0 | } |
299 | 0 | free(tbuf); |
300 | 0 | T.tlength = T.tcolors * tlength; |
301 | 0 | T.tformat = LIBRAW_THUMBNAIL_BITMAP; |
302 | 0 | SET_PROC_FLAG(LIBRAW_PROGRESS_THUMB_LOAD); |
303 | 0 | } |
304 | 0 | catch (...) |
305 | 0 | { |
306 | 0 | free(tbuf); |
307 | 0 | return LIBRAW_NO_THUMBNAIL; |
308 | 0 | } |
309 | 0 | return 0; |
310 | 0 | } |
311 | 0 | else if (Tformat == LIBRAW_INTERNAL_THUMBNAIL_PPM) |
312 | 0 | { |
313 | 0 | if (t_bytesps > 1) |
314 | 0 | return LIBRAW_NO_THUMBNAIL; // 8-bit thumb, but parsed for more |
315 | | // bits |
316 | 0 | THUMB_SIZE_CHECKWH(T.twidth, T.theight); |
317 | 0 | int t_length = T.twidth * T.theight * t_colors; |
318 | |
|
319 | 0 | if (T.tlength && |
320 | 0 | (int)T.tlength < t_length) // try to find tiff ifd with needed offset |
321 | 0 | { |
322 | 0 | int pifd = find_ifd_by_offset(libraw_internal_data.internal_data.toffset); |
323 | 0 | if (pifd >= 0 && tiff_ifd[pifd].strip_offsets_count && |
324 | 0 | tiff_ifd[pifd].strip_byte_counts_count) |
325 | 0 | { |
326 | | // We found it, calculate final size |
327 | 0 | INT64 total_size = 0; |
328 | 0 | for (int i = 0; i < tiff_ifd[pifd].strip_byte_counts_count |
329 | 0 | && i < tiff_ifd[pifd].strip_offsets_count; i++) |
330 | 0 | total_size += tiff_ifd[pifd].strip_byte_counts[i]; |
331 | 0 | if (total_size != (unsigned)t_length) // recalculate colors |
332 | 0 | { |
333 | 0 | if (total_size == T.twidth * T.tlength * 3) |
334 | 0 | T.tcolors = 3; |
335 | 0 | else if (total_size == T.twidth * T.tlength) |
336 | 0 | T.tcolors = 1; |
337 | 0 | } |
338 | 0 | T.tlength = unsigned(total_size); |
339 | 0 | THUMB_SIZE_CHECKTNZ(T.tlength); |
340 | 0 | if (T.thumb) |
341 | 0 | free(T.thumb); |
342 | | #ifdef LIBRAW_CALLOC_RAWSTORE |
343 | | T.thumb = (char *)calloc(T.tlength,1); |
344 | | #else |
345 | 0 | T.thumb = (char *)malloc(T.tlength); |
346 | 0 | #endif |
347 | 0 | if (!T.thumb) |
348 | 0 | return LIBRAW_NO_THUMBNAIL; |
349 | | |
350 | 0 | char *dest = T.thumb; |
351 | 0 | INT64 pos = ID.input->tell(); |
352 | 0 | INT64 remain = T.tlength; |
353 | |
|
354 | 0 | for (int i = 0; i < tiff_ifd[pifd].strip_byte_counts_count && |
355 | 0 | i < tiff_ifd[pifd].strip_offsets_count; |
356 | 0 | i++) |
357 | 0 | { |
358 | 0 | int sz = tiff_ifd[pifd].strip_byte_counts[i]; |
359 | 0 | INT64 off = tiff_ifd[pifd].strip_offsets[i]; |
360 | 0 | if (off >= 0 && off + sz <= ID.input->size() && sz > 0 && INT64(sz) <= remain) |
361 | 0 | { |
362 | 0 | ID.input->seek(off, SEEK_SET); |
363 | 0 | ID.input->read(dest, sz, 1); |
364 | 0 | remain -= sz; |
365 | 0 | dest += sz; |
366 | 0 | } |
367 | 0 | } |
368 | 0 | ID.input->seek(pos, SEEK_SET); |
369 | 0 | T.tformat = LIBRAW_THUMBNAIL_BITMAP; |
370 | 0 | SET_PROC_FLAG(LIBRAW_PROGRESS_THUMB_LOAD); |
371 | 0 | return 0; |
372 | 0 | } |
373 | 0 | } |
374 | | |
375 | 0 | if (!T.tlength) |
376 | 0 | T.tlength = t_length; |
377 | 0 | if (T.thumb) |
378 | 0 | free(T.thumb); |
379 | |
|
380 | 0 | THUMB_SIZE_CHECKTNZ(T.tlength); |
381 | | |
382 | | #ifdef LIBRAW_CALLOC_RAWSTORE |
383 | | T.thumb = (char *)calloc(T.tlength,1); |
384 | | #else |
385 | 0 | T.thumb = (char *)malloc(T.tlength); |
386 | 0 | #endif |
387 | 0 | if (!T.thumb) |
388 | 0 | return LIBRAW_NO_THUMBNAIL; |
389 | 0 | if (!T.tcolors) |
390 | 0 | T.tcolors = t_colors; |
391 | |
|
392 | 0 | ID.input->read(T.thumb, 1, T.tlength); |
393 | |
|
394 | 0 | T.tformat = LIBRAW_THUMBNAIL_BITMAP; |
395 | 0 | SET_PROC_FLAG(LIBRAW_PROGRESS_THUMB_LOAD); |
396 | 0 | return 0; |
397 | 0 | } |
398 | 0 | else if (Tformat == LIBRAW_INTERNAL_THUMBNAIL_PPM16) |
399 | 0 | { |
400 | 0 | if (t_bytesps > 2) |
401 | 0 | return LIBRAW_NO_THUMBNAIL; // 16-bit thumb, but parsed for |
402 | | // more bits |
403 | 0 | int o_bps = (imgdata.rawparams.options & LIBRAW_RAWOPTIONS_USE_PPM16_THUMBS) ? 2 : 1; |
404 | 0 | int o_length = T.twidth * T.theight * t_colors * o_bps; |
405 | 0 | int i_length = T.twidth * T.theight * t_colors * 2; |
406 | |
|
407 | 0 | THUMB_SIZE_CHECKTNZ(o_length); |
408 | 0 | THUMB_SIZE_CHECKTNZ(i_length); |
409 | | |
410 | 0 | ushort *t_thumb = (ushort *)calloc(i_length, 1); |
411 | 0 | if (!t_thumb) |
412 | 0 | return LIBRAW_NO_THUMBNAIL;; |
413 | 0 | ID.input->read(t_thumb, 1, i_length); |
414 | 0 | if ((libraw_internal_data.unpacker_data.order == 0x4949) == |
415 | 0 | (ntohs(0x1234) == 0x1234)) |
416 | 0 | libraw_swab(t_thumb, i_length); |
417 | |
|
418 | 0 | if (T.thumb) |
419 | 0 | free(T.thumb); |
420 | 0 | if ((imgdata.rawparams.options & LIBRAW_RAWOPTIONS_USE_PPM16_THUMBS)) |
421 | 0 | { |
422 | 0 | T.thumb = (char *)t_thumb; |
423 | 0 | T.tformat = LIBRAW_THUMBNAIL_BITMAP16; |
424 | 0 | T.tlength = i_length; |
425 | 0 | } |
426 | 0 | else |
427 | 0 | { |
428 | | #ifdef LIBRAW_CALLOC_RAWSTORE |
429 | | T.thumb = (char *)calloc(o_length,1); |
430 | | #else |
431 | 0 | T.thumb = (char *)malloc(o_length); |
432 | 0 | #endif |
433 | 0 | if (!T.thumb) |
434 | 0 | { |
435 | 0 | free(t_thumb); |
436 | 0 | return LIBRAW_NO_THUMBNAIL; |
437 | 0 | } |
438 | 0 | for (int i = 0; i < o_length; i++) |
439 | 0 | T.thumb[i] = t_thumb[i] >> 8; |
440 | 0 | free(t_thumb); |
441 | 0 | T.tformat = LIBRAW_THUMBNAIL_BITMAP; |
442 | 0 | T.tlength = o_length; |
443 | 0 | } |
444 | 0 | SET_PROC_FLAG(LIBRAW_PROGRESS_THUMB_LOAD); |
445 | 0 | return 0; |
446 | 0 | } |
447 | | #ifdef USE_X3FTOOLS |
448 | | else if (Tformat == LIBRAW_INTERNAL_THUMBNAIL_X3F) |
449 | | { |
450 | | x3f_thumb_loader(); // errors already catched in this call |
451 | | SET_PROC_FLAG(LIBRAW_PROGRESS_THUMB_LOAD); |
452 | | return 0; |
453 | | } |
454 | | #endif |
455 | 0 | else |
456 | 0 | { |
457 | 0 | return LIBRAW_UNSUPPORTED_THUMBNAIL; |
458 | 0 | } |
459 | 0 | } |
460 | | // last resort |
461 | 0 | return LIBRAW_UNSUPPORTED_THUMBNAIL; /* warned as unreachable*/ |
462 | 0 | } |
463 | 0 | catch (const LibRaw_exceptions& err) |
464 | 0 | { |
465 | 0 | EXCEPTION_HANDLER(err); |
466 | 0 | } |
467 | 0 | } |