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 }