--- parser3/src/classes/image.C 2020/12/01 18:53:01 1.172 +++ parser3/src/classes/image.C 2020/12/07 23:18:40 1.178 @@ -26,7 +26,7 @@ #include "pa_table.h" #include "pa_charsets.h" -volatile const char * IDENT_IMAGE_C="$Id: image.C,v 1.172 2020/12/01 18:53:01 moko Exp $"; +volatile const char * IDENT_IMAGE_C="$Id: image.C,v 1.178 2020/12/07 23:18:40 moko Exp $"; // defines @@ -234,8 +234,9 @@ public: class Measure_reader { public: virtual size_t read(const char* &buf, size_t limit)=0; - virtual void seek(off_t value, int whence)=0; - virtual off_t tell()=0; + virtual void seek(uint64_t value)=0; + virtual uint64_t tell()=0; + virtual uint64_t length()=0; }; class Measure_file_reader: public Measure_reader { @@ -258,12 +259,14 @@ public: return read_size; } - override void seek(off_t value, int whence) { - if(lseek(f, value, whence)<0) - throw Exception(IMAGE_FORMAT, &file_name, "seek(value=%ld, whence=%d) failed: %s (%d)", value, whence, strerror(errno), errno); + override void seek(uint64_t value) { + if(pa_lseek(f, value, SEEK_SET)<0) + throw Exception(IMAGE_FORMAT, &file_name, "seek to %.15g failed: %s (%d)", (double)value, strerror(errno), errno); } - override off_t 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); } }; @@ -286,24 +289,15 @@ public: return to_read; } - override void seek(off_t value, int whence) { - size_t new_offset; - switch(whence) { - case SEEK_CUR: new_offset=offset+value; break; - 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 void seek(uint64_t value) { + if(value>(uint64_t)size) + throw Exception(IMAGE_FORMAT, &file_name, "seek to %.15g failed: out of buffer (%.15g)", value, size); + offset=(size_t)value; } - override off_t tell() { return offset; } + override uint64_t tell() { return offset; } + + override uint64_t length() { return size; } }; @@ -453,7 +447,7 @@ static Value* parse_IFD_entry_formatted_ return result; } -static Value* parse_IFD_entry_value(bool is_big, Measure_reader& reader, long tiff_base, JPG_Exif_IFD_entry& entry) { +static Value* parse_IFD_entry_value(bool is_big, Measure_reader& reader, uint64_t tiff_base, JPG_Exif_IFD_entry& entry) { size_t format2component_size[]={ 0, // undefined 1, // unsigned byte @@ -490,32 +484,32 @@ static Value* parse_IFD_entry_value(bool if(value_size<=4) result=parse_IFD_entry_formatted_value(is_big, format, component_size, components_count, entry.value_or_offset_to_it); else { - off_t 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; if(reader.read(value, value_size)byte_align_identifier[0]=='M'; // [M]otorola vs [I]ntel 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; @@ -592,7 +586,7 @@ static void measure_jpeg(const String& o throw Exception(IMAGE_FORMAT, &origin_string, "not JPEG file - wrong signature"); while(true) { - uint segment_base=reader.tell()+2/*marker,code*/; + uint64_t segment_base=reader.tell()+2/*marker,code*/; if(reader.read(buf, sizeof(JPG_Segment_head))components_count) != 1) return false; uint value = (entry_format == 3) ? endian_to_ushort(is_big, entry->value_or_offset_to_it) : endian_to_uint(is_big, entry->value_or_offset_to_it); - (entry_tag == 256) ? info.width=value : info.height=value; + (entry_tag == 256) ? info.width=(short)value : info.height=(short)value; if(info.width && info.height) return true; } @@ -699,7 +693,7 @@ static void measure_tiff(const String& o if(endian_to_ushort(is_big, head->signature) != 42) 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)) throw Exception(IMAGE_FORMAT, &origin_string, "broken TIFF file - size field entry not found"); } @@ -785,8 +779,7 @@ static void measure_bmp(const String& or if(strncmp(head->signature, "BM", 2)!=0) throw Exception(IMAGE_FORMAT, &origin_string, "not BMP file - wrong signature"); - reader.seek(0, SEEK_END); - if((uint)reader.tell() != endian_to_uint(false, head->file_size)) + if((uint)reader.length() != endian_to_uint(false, head->file_size)) throw Exception(IMAGE_FORMAT, &origin_string, "not BMP file - length header and file size do not match"); width=endian_to_ushort(false, head->width); @@ -875,32 +868,47 @@ struct MP4_Header { char signature[4]; // 'ftyp' in first chunk }; -static bool measure_mp4(const String& origin_string, Measure_reader& reader, ushort& width, ushort& height, off_t anext, const char* lastTkhd=NULL) { +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; - const size_t head_size=sizeof(MP4_Header); - if(reader.read(buf, head_size)size); - off_t next=reader.tell() + size - head_size; + uint64_t size=endian_to_uint(true, head->size); -// printf("%d processing chunk size %d signature '%c%c%c%c %p'\n", anext, size, head->signature[0], head->signature[1], head->signature[2], head->signature[3], lastTkhd); + if(size==1){ + if(reader.read(buf, sizeof(MP4_ExtSize))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; - reader.seek(0, SEEK_END); - anext=reader.tell(); // to avoid reading beyond EOF + 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, SEEK_SET); - if(reader.read(lastTkhd, 8)<8) + reader.seek(next-8); + if(reader.read(lastTkhd, sizeof(MP4_Tkhd))signature, "hdlr", 4)==0) { @@ -908,19 +916,17 @@ static bool measure_mp4(const String& or const char* hdlr; if(reader.read(hdlr, 12)<12) throw Exception(IMAGE_FORMAT, &origin_string, "broken MP4 file - bad hdlr chunk"); -// if(strncmp(hdlr+8, "vide", 4)==0) -// printf("vide found\n"); - if( lastTkhd && strncmp(hdlr+8, "vide", 4)==0) { - width=endian_to_ushort(true, (const unsigned char*)(lastTkhd)); - height=endian_to_ushort(true, (const unsigned char*)(lastTkhd+4)); -// printf("wh %d %d\n",width, height); + 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, SEEK_SET); + reader.seek(next); } return false; }