File indexing completed on 2025-01-05 03:56:54
0001 /* -*- C++ -*- 0002 * Copyright 2019-2021 LibRaw LLC (info@libraw.org) 0003 * 0004 LibRaw is free software; you can redistribute it and/or modify 0005 it under the terms of the one of two licenses as you choose: 0006 0007 1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 0008 (See file LICENSE.LGPL provided in LibRaw distribution archive for details). 0009 0010 2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 0011 (See file LICENSE.CDDL provided in LibRaw distribution archive for details). 0012 0013 */ 0014 0015 #include "../../internal/libraw_cxx_defs.h" 0016 0017 #ifndef NO_JPEG 0018 struct jpegErrorManager 0019 { 0020 struct jpeg_error_mgr pub; 0021 jmp_buf setjmp_buffer; 0022 }; 0023 0024 static void jpegErrorExit(j_common_ptr cinfo) 0025 { 0026 jpegErrorManager *myerr = (jpegErrorManager *)cinfo->err; 0027 longjmp(myerr->setjmp_buffer, 1); 0028 } 0029 #endif 0030 0031 int LibRaw::unpack_thumb_ex(int idx) 0032 { 0033 if (idx < 0 || idx >= imgdata.thumbs_list.thumbcount || idx >= LIBRAW_THUMBNAIL_MAXCOUNT) 0034 return LIBRAW_REQUEST_FOR_NONEXISTENT_THUMBNAIL; 0035 0036 // Set from thumb-list 0037 libraw_internal_data.internal_data.toffset = imgdata.thumbs_list.thumblist[idx].toffset; 0038 imgdata.thumbnail.tlength = imgdata.thumbs_list.thumblist[idx].tlength; 0039 libraw_internal_data.unpacker_data.thumb_format = imgdata.thumbs_list.thumblist[idx].tformat; 0040 imgdata.thumbnail.twidth = imgdata.thumbs_list.thumblist[idx].twidth; 0041 imgdata.thumbnail.theight = imgdata.thumbs_list.thumblist[idx].theight; 0042 libraw_internal_data.unpacker_data.thumb_misc = imgdata.thumbs_list.thumblist[idx].tmisc; 0043 int rc = unpack_thumb(); 0044 imgdata.progress_flags &= ~LIBRAW_PROGRESS_THUMB_LOAD; 0045 0046 return rc; 0047 } 0048 0049 0050 int LibRaw::unpack_thumb(void) 0051 { 0052 CHECK_ORDER_LOW(LIBRAW_PROGRESS_IDENTIFY); 0053 CHECK_ORDER_BIT(LIBRAW_PROGRESS_THUMB_LOAD); 0054 0055 #define THUMB_SIZE_CHECKT(A) \ 0056 do { \ 0057 if (INT64(A) > 1024LL * 1024LL * LIBRAW_MAX_THUMBNAIL_MB) return LIBRAW_UNSUPPORTED_THUMBNAIL; \ 0058 if (INT64(A) > 0 && INT64(A) < 64LL) return LIBRAW_NO_THUMBNAIL; \ 0059 } while (0) 0060 0061 #define THUMB_SIZE_CHECKTNZ(A) \ 0062 do { \ 0063 if (INT64(A) > 1024LL * 1024LL * LIBRAW_MAX_THUMBNAIL_MB) return LIBRAW_UNSUPPORTED_THUMBNAIL; \ 0064 if (INT64(A) < 64LL) return LIBRAW_NO_THUMBNAIL; \ 0065 } while (0) 0066 0067 0068 #define THUMB_SIZE_CHECKWH(W,H) \ 0069 do { \ 0070 if (INT64(W)*INT64(H) > 1024ULL * 1024ULL * LIBRAW_MAX_THUMBNAIL_MB) return LIBRAW_UNSUPPORTED_THUMBNAIL; \ 0071 if (INT64(W)*INT64(H) < 64ULL) return LIBRAW_NO_THUMBNAIL; \ 0072 } while (0) 0073 0074 #define Tformat libraw_internal_data.unpacker_data.thumb_format 0075 0076 try 0077 { 0078 if (!libraw_internal_data.internal_data.input) 0079 return LIBRAW_INPUT_CLOSED; 0080 0081 int t_colors = libraw_internal_data.unpacker_data.thumb_misc >> 5 & 7; 0082 int t_bytesps = (libraw_internal_data.unpacker_data.thumb_misc & 31) / 8; 0083 0084 if (!ID.toffset && !(imgdata.thumbnail.tlength > 0 && 0085 load_raw == &LibRaw::broadcom_load_raw) // RPi 0086 #ifdef USE_6BY9RPI 0087 && !(imgdata.thumbnail.tlength > 0 && libraw_internal_data.unpacker_data.load_flags & 0x4000 0088 && (load_raw == &LibRaw::rpi_load_raw8 || load_raw == &LibRaw::nokia_load_raw || 0089 load_raw == &LibRaw::rpi_load_raw12 || load_raw == &LibRaw::rpi_load_raw14)) 0090 #endif 0091 ) 0092 { 0093 return LIBRAW_NO_THUMBNAIL; 0094 } 0095 else if ((Tformat >= LIBRAW_INTERNAL_THUMBNAIL_KODAK_THUMB) 0096 && ((Tformat <= LIBRAW_INTERNAL_THUMBNAIL_KODAK_RGB))) 0097 { 0098 kodak_thumb_loader(); 0099 T.tformat = LIBRAW_THUMBNAIL_BITMAP; 0100 SET_PROC_FLAG(LIBRAW_PROGRESS_THUMB_LOAD); 0101 return 0; 0102 } 0103 else 0104 { 0105 #ifdef USE_X3FTOOLS 0106 if (Tformat == LIBRAW_INTERNAL_THUMBNAIL_X3F) 0107 { 0108 INT64 tsize = x3f_thumb_size(); 0109 if (tsize < 2048 || INT64(ID.toffset) + tsize < 1) 0110 throw LIBRAW_EXCEPTION_IO_CORRUPT; 0111 0112 if (INT64(ID.toffset) + tsize > ID.input->size() + THUMB_READ_BEYOND) 0113 throw LIBRAW_EXCEPTION_IO_EOF; 0114 THUMB_SIZE_CHECKT(tsize); 0115 } 0116 #else 0117 if (0) {} 0118 #endif 0119 else 0120 { 0121 if (INT64(ID.toffset) + INT64(T.tlength) < 1) 0122 throw LIBRAW_EXCEPTION_IO_CORRUPT; 0123 0124 if (INT64(ID.toffset) + INT64(T.tlength) > 0125 ID.input->size() + THUMB_READ_BEYOND) 0126 throw LIBRAW_EXCEPTION_IO_EOF; 0127 } 0128 0129 ID.input->seek(ID.toffset, SEEK_SET); 0130 if (Tformat == LIBRAW_INTERNAL_THUMBNAIL_JPEG) 0131 { 0132 THUMB_SIZE_CHECKTNZ(T.tlength); 0133 if (T.thumb) 0134 free(T.thumb); 0135 T.thumb = (char *)malloc(T.tlength); 0136 ID.input->read(T.thumb, 1, T.tlength); 0137 unsigned char *tthumb = (unsigned char *)T.thumb; 0138 if (load_raw == &LibRaw::crxLoadRaw && T.tlength > 0xE0) 0139 { 0140 // Check if it is canon H.265 preview: CISZ at bytes 4-6, CISZ prefix is 000n 0141 if (tthumb[0] == 0 && tthumb[1] == 0 && tthumb[2] == 0 && !memcmp(tthumb + 4, "CISZ", 4)) 0142 { 0143 T.tformat = LIBRAW_THUMBNAIL_H265; 0144 SET_PROC_FLAG(LIBRAW_PROGRESS_THUMB_LOAD); 0145 return 0; 0146 } 0147 } 0148 tthumb[0] = 0xff; 0149 tthumb[1] = 0xd8; 0150 #ifdef NO_JPEG 0151 T.tcolors = 3; 0152 #else 0153 { 0154 jpegErrorManager jerr; 0155 struct jpeg_decompress_struct cinfo; 0156 cinfo.err = jpeg_std_error(&jerr.pub); 0157 jerr.pub.error_exit = jpegErrorExit; 0158 if (setjmp(jerr.setjmp_buffer)) 0159 { 0160 err2: 0161 // Error in original JPEG thumb, read it again because 0162 // original bytes 0-1 was damaged above 0163 jpeg_destroy_decompress(&cinfo); 0164 T.tcolors = 3; 0165 T.tformat = LIBRAW_THUMBNAIL_UNKNOWN; 0166 ID.input->seek(ID.toffset, SEEK_SET); 0167 ID.input->read(T.thumb, 1, T.tlength); 0168 SET_PROC_FLAG(LIBRAW_PROGRESS_THUMB_LOAD); 0169 return 0; 0170 } 0171 jpeg_create_decompress(&cinfo); 0172 jpeg_mem_src(&cinfo, (unsigned char *)T.thumb, T.tlength); 0173 int rc = jpeg_read_header(&cinfo, TRUE); 0174 if (rc != 1) 0175 goto err2; 0176 T.tcolors = (cinfo.num_components > 0 && cinfo.num_components <= 3) 0177 ? cinfo.num_components 0178 : 3; 0179 jpeg_destroy_decompress(&cinfo); 0180 } 0181 #endif 0182 T.tformat = LIBRAW_THUMBNAIL_JPEG; 0183 SET_PROC_FLAG(LIBRAW_PROGRESS_THUMB_LOAD); 0184 return 0; 0185 } 0186 else if (Tformat == LIBRAW_INTERNAL_THUMBNAIL_LAYER) 0187 { 0188 int colors = libraw_internal_data.unpacker_data.thumb_misc >> 5 & 7; 0189 if (colors != 1 && colors != 3) 0190 return LIBRAW_UNSUPPORTED_THUMBNAIL; 0191 0192 THUMB_SIZE_CHECKWH(T.twidth, T.theight); 0193 0194 int tlength = T.twidth * T.theight; 0195 if (T.thumb) 0196 free(T.thumb); 0197 T.thumb = (char *)calloc(colors, tlength); 0198 unsigned char *tbuf = (unsigned char *)calloc(colors, tlength); 0199 // Avoid OOB of tbuf, should use tlength 0200 ID.input->read(tbuf, colors, tlength); 0201 if (libraw_internal_data.unpacker_data.thumb_misc >> 8 && 0202 colors == 3) // GRB order 0203 for (int i = 0; i < tlength; i++) 0204 { 0205 T.thumb[i * 3] = tbuf[i + tlength]; 0206 T.thumb[i * 3 + 1] = tbuf[i]; 0207 T.thumb[i * 3 + 2] = tbuf[i + 2 * tlength]; 0208 } 0209 else if (colors == 3) // RGB or 1-channel 0210 for (int i = 0; i < tlength; i++) 0211 { 0212 T.thumb[i * 3] = tbuf[i]; 0213 T.thumb[i * 3 + 1] = tbuf[i + tlength]; 0214 T.thumb[i * 3 + 2] = tbuf[i + 2 * tlength]; 0215 } 0216 else if (colors == 1) 0217 { 0218 free(T.thumb); 0219 T.thumb = (char *)tbuf; 0220 tbuf = 0; 0221 } 0222 if (tbuf) 0223 free(tbuf); 0224 T.tcolors = colors; 0225 T.tlength = colors * tlength; 0226 T.tformat = LIBRAW_THUMBNAIL_BITMAP; 0227 SET_PROC_FLAG(LIBRAW_PROGRESS_THUMB_LOAD); 0228 return 0; 0229 } 0230 else if (Tformat == LIBRAW_INTERNAL_THUMBNAIL_ROLLEI) 0231 { 0232 int i; 0233 THUMB_SIZE_CHECKWH(T.twidth, T.theight); 0234 int tlength = T.twidth * T.theight; 0235 if (T.thumb) 0236 free(T.thumb); 0237 T.tcolors = 3; 0238 T.thumb = (char *)calloc(T.tcolors, tlength); 0239 unsigned short *tbuf = (unsigned short *)calloc(2, tlength); 0240 read_shorts(tbuf, tlength); 0241 for (i = 0; i < tlength; i++) 0242 { 0243 T.thumb[i * 3] = (tbuf[i] << 3) & 0xff; 0244 T.thumb[i * 3 + 1] = (tbuf[i] >> 5 << 2) & 0xff; 0245 T.thumb[i * 3 + 2] = (tbuf[i] >> 11 << 3) & 0xff; 0246 } 0247 free(tbuf); 0248 T.tlength = T.tcolors * tlength; 0249 T.tformat = LIBRAW_THUMBNAIL_BITMAP; 0250 SET_PROC_FLAG(LIBRAW_PROGRESS_THUMB_LOAD); 0251 return 0; 0252 } 0253 else if (Tformat == LIBRAW_INTERNAL_THUMBNAIL_PPM) 0254 { 0255 if (t_bytesps > 1) 0256 throw LIBRAW_EXCEPTION_IO_CORRUPT; // 8-bit thumb, but parsed for more 0257 // bits 0258 THUMB_SIZE_CHECKWH(T.twidth, T.theight); 0259 int t_length = T.twidth * T.theight * t_colors; 0260 0261 if (T.tlength && 0262 (int)T.tlength < t_length) // try to find tiff ifd with needed offset 0263 { 0264 int pifd = find_ifd_by_offset(libraw_internal_data.internal_data.toffset); 0265 if (pifd >= 0 && tiff_ifd[pifd].strip_offsets_count && 0266 tiff_ifd[pifd].strip_byte_counts_count) 0267 { 0268 // We found it, calculate final size 0269 INT64 total_size = 0; 0270 for (int i = 0; i < tiff_ifd[pifd].strip_byte_counts_count 0271 && i < tiff_ifd[pifd].strip_offsets_count; i++) 0272 total_size += tiff_ifd[pifd].strip_byte_counts[i]; 0273 if (total_size != (unsigned)t_length) // recalculate colors 0274 { 0275 if (total_size == T.twidth * T.tlength * 3) 0276 T.tcolors = 3; 0277 else if (total_size == T.twidth * T.tlength) 0278 T.tcolors = 1; 0279 } 0280 T.tlength = total_size; 0281 THUMB_SIZE_CHECKTNZ(T.tlength); 0282 if (T.thumb) 0283 free(T.thumb); 0284 T.thumb = (char *)malloc(T.tlength); 0285 0286 char *dest = T.thumb; 0287 INT64 pos = ID.input->tell(); 0288 INT64 remain = T.tlength; 0289 0290 for (int i = 0; i < tiff_ifd[pifd].strip_byte_counts_count && 0291 i < tiff_ifd[pifd].strip_offsets_count; 0292 i++) 0293 { 0294 int sz = tiff_ifd[pifd].strip_byte_counts[i]; 0295 INT64 off = tiff_ifd[pifd].strip_offsets[i]; 0296 if (off >= 0 && off + sz <= ID.input->size() && sz > 0 && INT64(sz) <= remain) 0297 { 0298 ID.input->seek(off, SEEK_SET); 0299 ID.input->read(dest, sz, 1); 0300 remain -= sz; 0301 dest += sz; 0302 } 0303 } 0304 ID.input->seek(pos, SEEK_SET); 0305 T.tformat = LIBRAW_THUMBNAIL_BITMAP; 0306 SET_PROC_FLAG(LIBRAW_PROGRESS_THUMB_LOAD); 0307 return 0; 0308 } 0309 } 0310 0311 if (!T.tlength) 0312 T.tlength = t_length; 0313 if (T.thumb) 0314 free(T.thumb); 0315 0316 THUMB_SIZE_CHECKTNZ(T.tlength); 0317 0318 T.thumb = (char *)malloc(T.tlength); 0319 if (!T.tcolors) 0320 T.tcolors = t_colors; 0321 0322 ID.input->read(T.thumb, 1, T.tlength); 0323 0324 T.tformat = LIBRAW_THUMBNAIL_BITMAP; 0325 SET_PROC_FLAG(LIBRAW_PROGRESS_THUMB_LOAD); 0326 return 0; 0327 } 0328 else if (Tformat == LIBRAW_INTERNAL_THUMBNAIL_PPM16) 0329 { 0330 if (t_bytesps > 2) 0331 throw LIBRAW_EXCEPTION_IO_CORRUPT; // 16-bit thumb, but parsed for 0332 // more bits 0333 int o_bps = (imgdata.rawparams.options & LIBRAW_RAWOPTIONS_USE_PPM16_THUMBS) ? 2 : 1; 0334 int o_length = T.twidth * T.theight * t_colors * o_bps; 0335 int i_length = T.twidth * T.theight * t_colors * 2; 0336 0337 THUMB_SIZE_CHECKTNZ(o_length); 0338 THUMB_SIZE_CHECKTNZ(i_length); 0339 0340 ushort *t_thumb = (ushort *)calloc(i_length, 1); 0341 if (!t_thumb) 0342 throw LIBRAW_EXCEPTION_ALLOC; 0343 ID.input->read(t_thumb, 1, i_length); 0344 if ((libraw_internal_data.unpacker_data.order == 0x4949) == 0345 (ntohs(0x1234) == 0x1234)) 0346 libraw_swab(t_thumb, i_length); 0347 0348 if (T.thumb) 0349 free(T.thumb); 0350 if ((imgdata.rawparams.options & LIBRAW_RAWOPTIONS_USE_PPM16_THUMBS)) 0351 { 0352 T.thumb = (char *)t_thumb; 0353 T.tformat = LIBRAW_THUMBNAIL_BITMAP16; 0354 T.tlength = i_length; 0355 } 0356 else 0357 { 0358 T.thumb = (char *)malloc(o_length); 0359 if (!T.thumb) 0360 throw LIBRAW_EXCEPTION_ALLOC; 0361 for (int i = 0; i < o_length; i++) 0362 T.thumb[i] = t_thumb[i] >> 8; 0363 free(t_thumb); 0364 T.tformat = LIBRAW_THUMBNAIL_BITMAP; 0365 T.tlength = o_length; 0366 } 0367 SET_PROC_FLAG(LIBRAW_PROGRESS_THUMB_LOAD); 0368 return 0; 0369 } 0370 #ifdef USE_X3FTOOLS 0371 else if (Tformat == LIBRAW_INTERNAL_THUMBNAIL_X3F) 0372 { 0373 x3f_thumb_loader(); 0374 SET_PROC_FLAG(LIBRAW_PROGRESS_THUMB_LOAD); 0375 return 0; 0376 } 0377 #endif 0378 else 0379 { 0380 return LIBRAW_UNSUPPORTED_THUMBNAIL; 0381 } 0382 } 0383 // last resort 0384 return LIBRAW_UNSUPPORTED_THUMBNAIL; /* warned as unreachable*/ 0385 } 0386 catch (const LibRaw_exceptions& err) 0387 { 0388 EXCEPTION_HANDLER(err); 0389 } 0390 }