Diff for /parser3/src/classes/image.C between versions 1.169 and 1.174

version 1.169, 2020/11/30 19:50:47 version 1.174, 2020/12/03 22:48:09
Line 228  public: Line 228  public:
         }          }
 } exif_gps_tag_value2name;  } exif_gps_tag_value2name;
   
   
 ///*********************************************** support functions  ///*********************************************** support functions
   
 class Measure_reader {  class Measure_reader {
 public:  public:
         virtual size_t read(const char* &buf, size_t limit)=0;          virtual size_t read(const char* &buf, size_t limit)=0;
         virtual void seek(long value, int whence)=0;          virtual void seek(uint64_t value)=0;
         virtual long tell()=0;          virtual uint64_t tell()=0;
           virtual uint64_t length()=0;
 };  };
   
 class Measure_file_reader: public Measure_reader {  class Measure_file_reader: public Measure_reader {
Line 257  public: Line 259  public:
                 return read_size;                  return read_size;
         }          }
   
         override void seek(long value, int whence) {          override void seek(uint64_t value) {
                 if(lseek(f, value, whence)<0)                  if(pa_lseek(f, value, SEEK_SET)<0)
                         throw Exception(IMAGE_FORMAT, &file_name, "seek(value=%ld, whence=%d) failed: %s (%d)", value, whence, strerror(errno), errno);                          throw Exception(IMAGE_FORMAT, &file_name, "seek to %.15g failed: %s (%d)", (double)value, strerror(errno), errno);
         }          }
   
         override long tell() { return lseek(f, 0, SEEK_CUR); }          override uint64_t tell() { return pa_lseek(f, 0, SEEK_CUR); }
   
           override uint64_t length() { return pa_lseek(f, 0, SEEK_END); }
   
 };  };
   
Line 285  public: Line 289  public:
                 return to_read;                  return to_read;
         }          }
   
         override void seek(long value, int whence) {          override void seek(uint64_t value) {
                 size_t new_offset;                  if(value>(uint64_t)size)
                 switch(whence) {                          throw Exception(IMAGE_FORMAT, &file_name, "seek to %.15g failed: out of buffer (%.15g)", value, size);
                 case SEEK_CUR: new_offset=offset+value; break;                  offset=(size_t)value;
                 case SEEK_SET: new_offset=(size_t)value; break;  
                 case SEEK_END: new_offset=size; break;  
                 default:   
                         throw Exception(0, 0, "whence #%d not supported", 0, whence);   
                         break; // never  
                 }  
                   
                 if((ssize_t)new_offset<0 || new_offset>size)  
                         throw Exception(IMAGE_FORMAT, &file_name, "seek(value=%l, whence=%d) failed: out of buffer, new_offset>size (%l>%l) or new_offset<0",   
                                         value, whence, new_offset, size);  
                 offset=new_offset;  
         }          }
   
         override long tell() { return offset; }          override uint64_t tell() { return offset; }
   
           override uint64_t length() { return size; }
   
 };  };
   
Line 332  inline uint endian_to_uint(bool is_big, Line 327  inline uint endian_to_uint(bool is_big,
         return is_big ? x_endian_to_uint(b[3], b[2], b[1], b[0]) : x_endian_to_uint(b[0], b[1], b[2], b[3]);          return is_big ? x_endian_to_uint(b[3], b[2], b[1], b[0]) : x_endian_to_uint(b[0], b[1], b[2], b[3]);
 }  }
   
   
 ///*********************************************** JPEG  ///*********************************************** JPEG
   
 struct JPG_Segment_head {  struct JPG_Segment_head {
         uchar marker;          uchar marker;
         uchar code;          uchar code;
Line 487  static Value* parse_IFD_entry_value(bool Line 484  static Value* parse_IFD_entry_value(bool
         if(value_size<=4)          if(value_size<=4)
                 result=parse_IFD_entry_formatted_value(is_big, format, component_size, components_count, entry.value_or_offset_to_it);                  result=parse_IFD_entry_formatted_value(is_big, format, component_size, components_count, entry.value_or_offset_to_it);
         else {          else {
                 long remembered=reader.tell();                  uint64_t remembered=reader.tell();
                 {                  {
                         reader.seek(tiff_base+endian_to_uint(is_big, entry.value_or_offset_to_it), SEEK_SET);                          reader.seek(tiff_base+endian_to_uint(is_big, entry.value_or_offset_to_it));
                         const char* value;                          const char* value;
                         if(reader.read(value, value_size)<value_size)                          if(reader.read(value, value_size)<value_size)
                                 return 0;                                  return 0;
                         result=parse_IFD_entry_formatted_value(is_big, format, component_size, components_count, (const uchar*)value);                          result=parse_IFD_entry_formatted_value(is_big, format, component_size, components_count, (const uchar*)value);
                 }                  }
                 reader.seek(remembered, SEEK_SET);                  reader.seek(remembered);
         }          }
   
         return result;          return result;
Line 507  static void parse_IFD_entry(HashStringVa Line 504  static void parse_IFD_entry(HashStringVa
         ushort tag=endian_to_ushort(is_big, entry.tag);          ushort tag=endian_to_ushort(is_big, entry.tag);
   
         if(tag==JPG_IFD_TAG_EXIF_OFFSET || tag==JPG_IFD_TAG_EXIF_GPS_OFFSET){          if(tag==JPG_IFD_TAG_EXIF_OFFSET || tag==JPG_IFD_TAG_EXIF_GPS_OFFSET){
                 long remembered=reader.tell();                  uint64_t remembered=reader.tell();
                 {                  {
                         reader.seek(tiff_base+endian_to_uint(is_big, entry.value_or_offset_to_it), SEEK_SET);                          reader.seek(tiff_base+endian_to_uint(is_big, entry.value_or_offset_to_it));
                         parse_IFD(hash, is_big, reader, tiff_base, (tag==JPG_IFD_TAG_EXIF_GPS_OFFSET)?true:gps);                          parse_IFD(hash, is_big, reader, tiff_base, (tag==JPG_IFD_TAG_EXIF_GPS_OFFSET)?true:gps);
                 }                  }
                 reader.seek(remembered, SEEK_SET);                  reader.seek(remembered);
                 return;                  return;
         }          }
   
Line 551  static Value* parse_exif(Measure_reader& Line 548  static Value* parse_exif(Measure_reader&
         bool is_big=head->byte_align_identifier[0]=='M'; // [M]otorola vs [I]ntel          bool is_big=head->byte_align_identifier[0]=='M'; // [M]otorola vs [I]ntel
   
         uint first_IFD_offset=endian_to_uint(is_big, head->first_IFD_offset);          uint first_IFD_offset=endian_to_uint(is_big, head->first_IFD_offset);
         reader.seek(tiff_base+first_IFD_offset, SEEK_SET);          reader.seek(tiff_base+first_IFD_offset);
   
         VHash* vhash=new VHash;          VHash* vhash=new VHash;
   
Line 643  static void measure_jpeg(const String& o Line 640  static void measure_jpeg(const String& o
                         return;                          return;
                 };                  };
   
                 reader.seek(segment_base + segment_length, SEEK_SET);                  reader.seek(segment_base + segment_length);
         }          }
   
         throw Exception(IMAGE_FORMAT, &origin_string, "broken JPEG file - size frame not found");          throw Exception(IMAGE_FORMAT, &origin_string, "broken JPEG file - size frame not found");
Line 696  static void measure_tiff(const String& o Line 693  static void measure_tiff(const String& o
         if(endian_to_ushort(is_big, head->signature) != 42)          if(endian_to_ushort(is_big, head->signature) != 42)
                 throw Exception(IMAGE_FORMAT, &origin_string, "not TIFF file - wrong signature");                  throw Exception(IMAGE_FORMAT, &origin_string, "not TIFF file - wrong signature");
   
         reader.seek(endian_to_uint(is_big, head->first_IFD_offset), SEEK_SET);          reader.seek(endian_to_uint(is_big, head->first_IFD_offset));
         if(!parse_tiff_IFD(is_big, reader, info))          if(!parse_tiff_IFD(is_big, reader, info))
                 throw Exception(IMAGE_FORMAT, &origin_string, "broken TIFF file - size field entry not found");                  throw Exception(IMAGE_FORMAT, &origin_string, "broken TIFF file - size field entry not found");
 }  }
Line 782  static void measure_bmp(const String& or Line 779  static void measure_bmp(const String& or
         if(strncmp(head->signature, "BM", 2)!=0)          if(strncmp(head->signature, "BM", 2)!=0)
                 throw Exception(IMAGE_FORMAT, &origin_string, "not BMP file - wrong signature");                  throw Exception(IMAGE_FORMAT, &origin_string, "not BMP file - wrong signature");
   
         reader.seek(0, SEEK_END);          if((uint)reader.length() != endian_to_uint(false, head->file_size))
         if((uint)reader.tell() != endian_to_uint(false, head->file_size))  
                 throw Exception(IMAGE_FORMAT, &origin_string, "not BMP file - length header and file size do not match");                  throw Exception(IMAGE_FORMAT, &origin_string, "not BMP file - length header and file size do not match");
   
         width=endian_to_ushort(false, head->width);          width=endian_to_ushort(false, head->width);
Line 864  static void measure_webp(const String& o Line 860  static void measure_webp(const String& o
         } else throw Exception(IMAGE_FORMAT, &origin_string, "broken WEBP file - invalid chunk signature");          } else throw Exception(IMAGE_FORMAT, &origin_string, "broken WEBP file - invalid chunk signature");
 }  }
   
   
   ///*********************************************** MP4
   
   struct MP4_Header {
           uchar size[4];
           char signature[4];   // 'ftyp' in first chunk
   };
   
   struct MP4_ExtSize {
           uchar high[4];
           uchar low[4];
   };
   
   struct MP4_Tkhd {
           uchar width[4];
           uchar height[4];
   };
   
   static bool measure_mp4(const String& origin_string, Measure_reader& reader, ushort& width, ushort& height, uint64_t anext, const char* lastTkhd=NULL) {
           for(bool first=anext==0;;){
                   const char* buf;
                   uint64_t next=reader.tell();
   
                   if(reader.read(buf, sizeof(MP4_Header))<sizeof(MP4_Header))
                           throw Exception(IMAGE_FORMAT, &origin_string, first ? "not MP4 file - too small" : "broken MP4 file - truncated chunk header");
   
                   MP4_Header *head=(MP4_Header *)buf;
                   uint64_t size=endian_to_uint(true, head->size);
   
                   if(size==1){
                           if(reader.read(buf, sizeof(MP4_ExtSize))<sizeof(MP4_ExtSize))
                                   throw Exception(IMAGE_FORMAT, &origin_string, "broken MP4 file - truncated chunk extended size header");
                           MP4_ExtSize *ext_size=(MP4_ExtSize *)buf;
                           size=((uint64_t)endian_to_uint(true, ext_size->high) << 32) + endian_to_uint(true, ext_size->low);
                   }
                   next+=size;
   
                   if(first){
                           if(strncmp(head->signature, "ftyp", 4)!=0)
                                   throw Exception(IMAGE_FORMAT, &origin_string, "not MP4 file - wrong signature");
                           first=false;
                           anext=reader.length(); // to avoid reading beyond EOF
                   } else if(strncmp(head->signature, "moov", 4)==0 || strncmp(head->signature, "mdia", 4)==0 || strncmp(head->signature, "trak", 4)==0) {
                           if(measure_mp4(origin_string, reader, width, height, next, lastTkhd))
                                   return true;
                   } else if(strncmp(head->signature, "tkhd", 4)==0) {
                           if(size>8){
                                   reader.seek(next-8);
                                   if(reader.read(lastTkhd, sizeof(MP4_Tkhd))<sizeof(MP4_Tkhd))
                                           throw Exception(IMAGE_FORMAT, &origin_string, "broken MP4 file - bad tkhd chunk");
                           }
                   } else if (strncmp(head->signature, "hdlr", 4)==0) {
                           if(size>12){
                                   const char* hdlr;
                                   if(reader.read(hdlr, 12)<12)
                                           throw Exception(IMAGE_FORMAT, &origin_string, "broken MP4 file - bad hdlr chunk");
                                   if(lastTkhd && strncmp(hdlr+8, "vide", 4)==0) {
                                           MP4_Tkhd *tkhd=(MP4_Tkhd *)lastTkhd;
                                           width=endian_to_ushort(true, tkhd->width);
                                           height=endian_to_ushort(true, tkhd->height);
                                           return true;
                                   }
                           }
                   }
                   if(anext && next>=anext)
                           break;
                   reader.seek(next);
           }
           return false;
   }
   
   static void measure_mp4(const String& origin_string, Measure_reader& reader, ushort& width, ushort& height) {
           if(!measure_mp4(origin_string, reader, width, height, 0))
                   throw Exception(IMAGE_FORMAT, &origin_string, "unsupported MP4 file - size not found");
   }
   
 ///*********************************************** measure center  ///*********************************************** measure center
   
 static void measure(const String& file_name, Measure_reader& reader, Measure_info &info) {  static void measure(const String& file_name, Measure_reader& reader, Measure_info &info) {
Line 882  static void measure(const String& file_n Line 954  static void measure(const String& file_n
                         measure_webp(file_name, reader, info.width, info.height);                          measure_webp(file_name, reader, info.width, info.height);
                 else if(strcasecmp(cext, "TIF")==0 || strcasecmp(cext, "TIFF")==0)                  else if(strcasecmp(cext, "TIF")==0 || strcasecmp(cext, "TIFF")==0)
                         measure_tiff(file_name, reader, info);                          measure_tiff(file_name, reader, info);
                   else if(strcasecmp(cext, "MP4")==0 || strcasecmp(cext, "MOV")==0)
                           measure_mp4(file_name, reader, info.width, info.height);
                 else                  else
                         throw Exception(IMAGE_FORMAT, &file_name, "unhandled image file name extension '%s'", cext);                          throw Exception(IMAGE_FORMAT, &file_name, "unhandled image file name extension '%s'", cext);
         } else          } else

Removed from v.1.169  
changed lines
  Added in v.1.174


E-mail: