protected virtual IFDEntry ParseIFDEntry(ushort tag, ushort type, uint count, long base_offset, uint offset) { if (tag == (ushort)ExifEntryTag.MakerNote && parse_makernote) { return(ParseMakernote(tag, type, count, base_offset, offset)); } if (tag == (ushort)IFDEntryTag.SubIFDs) { var entries = new List <IFDStructure>(); uint[] data; if (count >= 2) { if (base_offset + offset > file.Length) { file.MarkAsCorrupt("Length of SubIFD is too long"); return(null); } file.Seek(base_offset + offset, SeekOrigin.Begin); data = ReadUIntArray(count); } else { data = new uint[] { offset }; } foreach (var sub_offset in data) { var sub_structure = new IFDStructure(); var sub_reader = CreateSubIFDReader(file, is_bigendian, sub_structure, base_offset, sub_offset, max_offset); sub_reader.Read(); entries.Add(sub_structure); } return(new SubIFDArrayEntry(tag, entries)); } IFDStructure ifd_structure = new IFDStructure(); IFDReader reader = CreateSubIFDReader(file, is_bigendian, ifd_structure, base_offset, offset, max_offset); if (type == (ushort)IFDEntryType.IFD) { reader.Read(); return(new SubIFDEntry(tag, type, (uint)ifd_structure.Directories.Length, ifd_structure)); } switch (tag) { case (ushort) IFDEntryTag.ExifIFD: case (ushort) IFDEntryTag.InteroperabilityIFD: case (ushort) IFDEntryTag.GPSIFD: reader.Read(); return(new SubIFDEntry(tag, (ushort)IFDEntryType.Long, 1, ifd_structure)); default: return(null); } }
private IFDEntry ParseMakernote (ushort tag, ushort type, uint count, long base_offset, uint offset) { long makernote_offset = base_offset + offset; IFDStructure ifd_structure = new IFDStructure (); // This is the minimum size a makernote should have // The shortest header is PENTAX_HEADER (4) // + IFD entry count (2) // + at least one IFD etry (12) // + next IFD pointer (4) // = 22 .... // we use this number to read a header which is big used // to identify the makernote types int header_size = 18; long length = 0; try { length = file.Length; } catch (Exception) { // Use a safety-value of 4 gigabyte. length = 1073741824L * 4; } if (makernote_offset > length) { file.MarkAsCorrupt ("offset to makernote is beyond file size"); return null; } if (makernote_offset + header_size > length) { file.MarkAsCorrupt ("data is to short to contain a maker note ifd"); return null; } // read header file.Seek (makernote_offset, SeekOrigin.Begin); ByteVector header = file.ReadBlock (header_size); if (header.StartsWith (PANASONIC_HEADER)) { IFDReader reader = new IFDReader (file, is_bigendian, ifd_structure, base_offset, offset + 12, max_offset); reader.ReadIFD (base_offset, offset + 12, max_offset); return new MakernoteIFDEntry (tag, ifd_structure, MakernoteType.Panasonic, PANASONIC_HEADER, 12, true, null); } if (header.StartsWith (PENTAX_HEADER)) { IFDReader reader = new IFDReader (file, is_bigendian, ifd_structure, base_offset, offset + 6, max_offset); reader.ReadIFD (base_offset, offset + 6, max_offset); return new MakernoteIFDEntry (tag, ifd_structure, MakernoteType.Pentax, header.Mid (0, 6), 6, true, null); } if (header.StartsWith (OLYMPUS1_HEADER)) { IFDReader reader = new IFDReader (file, is_bigendian, ifd_structure, base_offset, offset + 8, max_offset); reader.Read (); return new MakernoteIFDEntry (tag, ifd_structure, MakernoteType.Olympus1, header.Mid (0, 8), 8, true, null); } if (header.StartsWith (OLYMPUS2_HEADER)) { IFDReader reader = new IFDReader (file, is_bigendian, ifd_structure, makernote_offset, 12, count); reader.Read (); return new MakernoteIFDEntry (tag, ifd_structure, MakernoteType.Olympus2, header.Mid (0, 12), 12, false, null); } if (header.StartsWith (SONY_HEADER)) { IFDReader reader = new IFDReader (file, is_bigendian, ifd_structure, base_offset, offset + 12, max_offset); reader.ReadIFD (base_offset, offset + 12, max_offset); return new MakernoteIFDEntry (tag, ifd_structure, MakernoteType.Sony, SONY_HEADER, 12, true, null); } if (header.StartsWith (NIKON_HEADER)) { ByteVector endian_bytes = header.Mid (10, 2); if (endian_bytes.ToString () == "II" || endian_bytes.ToString () == "MM") { bool makernote_endian = endian_bytes.ToString ().Equals ("MM"); ushort magic = header.Mid (12, 2).ToUShort (is_bigendian); if (magic == 42) { // TODO: the max_offset value is not correct here. However, some nikon files have offsets to a sub-ifd // (preview image) which are not stored with the other makernote data. Therfore, we keep the max_offset // for now. (It is just an upper bound for some checks. So if it is too big, it doesn't matter) var reader = new Nikon3MakernoteReader (file, makernote_endian, ifd_structure, makernote_offset + 10, 8, max_offset - offset - 10); reader.Read (); return new MakernoteIFDEntry (tag, ifd_structure, MakernoteType.Nikon3, header.Mid (0, 18), 8, false, makernote_endian); } } } if (header.StartsWith (LEICA_HEADER)) { IFDReader reader = new IFDReader (file, is_bigendian, ifd_structure, makernote_offset, 8, count); reader.Read (); return new MakernoteIFDEntry (tag, ifd_structure, MakernoteType.Leica, header.Mid (0, 8), 10, false, null); } try { IFDReader reader = new IFDReader (file, is_bigendian, ifd_structure, base_offset, offset, max_offset); reader.Read (); return new MakernoteIFDEntry (tag, ifd_structure, MakernoteType.Canon); } catch { return null; } }
IFDEntry ParseMakernote(ushort tag, ushort type, uint count, long baseOffset, uint offset) { long makernote_offset = baseOffset + offset; var ifd_structure = new IFDStructure(); // This is the minimum size a makernote should have // The shortest header is PENTAX_HEADER (4) // + IFD entry count (2) // + at least one IFD etry (12) // + next IFD pointer (4) // = 22 .... // we use this number to read a header which is big used // to identify the makernote types int header_size = 18; long length = 0; try { length = file.Length; } catch (Exception) { // Use a safety-value of 4 gigabyte. length = 1073741824L * 4; } if (makernote_offset > length) { file.MarkAsCorrupt("offset to makernote is beyond file size"); return(null); } if (makernote_offset + header_size > length) { file.MarkAsCorrupt("data is to short to contain a maker note ifd"); return(null); } // read header file.Seek(makernote_offset, SeekOrigin.Begin); ByteVector header = file.ReadBlock(header_size); if (header.StartsWith(PANASONIC_HEADER)) { var reader = new IFDReader(file, is_bigendian, ifd_structure, baseOffset, offset + 12, max_offset); reader.ReadIFD(baseOffset, offset + 12, max_offset); return(new MakernoteIFDEntry(tag, ifd_structure, MakernoteType.Panasonic, PANASONIC_HEADER, 12, true, null)); } if (header.StartsWith(PENTAX_HEADER)) { var reader = new IFDReader(file, is_bigendian, ifd_structure, baseOffset, offset + 6, max_offset); reader.ReadIFD(baseOffset, offset + 6, max_offset); return(new MakernoteIFDEntry(tag, ifd_structure, MakernoteType.Pentax, header.Mid(0, 6), 6, true, null)); } if (header.StartsWith(OLYMPUS1_HEADER)) { var reader = new IFDReader(file, is_bigendian, ifd_structure, baseOffset, offset + 8, max_offset); reader.Read(); return(new MakernoteIFDEntry(tag, ifd_structure, MakernoteType.Olympus1, header.Mid(0, 8), 8, true, null)); } if (header.StartsWith(OLYMPUS2_HEADER)) { var reader = new IFDReader(file, is_bigendian, ifd_structure, makernote_offset, 12, count); reader.Read(); return(new MakernoteIFDEntry(tag, ifd_structure, MakernoteType.Olympus2, header.Mid(0, 12), 12, false, null)); } if (header.StartsWith(SONY_HEADER)) { var reader = new IFDReader(file, is_bigendian, ifd_structure, baseOffset, offset + 12, max_offset); reader.ReadIFD(baseOffset, offset + 12, max_offset); return(new MakernoteIFDEntry(tag, ifd_structure, MakernoteType.Sony, SONY_HEADER, 12, true, null)); } if (header.StartsWith(NIKON_HEADER)) { ByteVector endian_bytes = header.Mid(10, 2); if (endian_bytes.ToString() == "II" || endian_bytes.ToString() == "MM") { bool makernote_endian = endian_bytes.ToString().Equals("MM"); ushort magic = header.Mid(12, 2).ToUShort(is_bigendian); if (magic == 42) { var reader = new Nikon3MakernoteReader(file, makernote_endian, ifd_structure, makernote_offset + 10, 8, max_offset - offset - 10); reader.Read(); return(new MakernoteIFDEntry(tag, ifd_structure, MakernoteType.Nikon3, header.Mid(0, 18), 8, false, makernote_endian)); } } } if (header.StartsWith(LEICA_HEADER)) { var reader = new IFDReader(file, is_bigendian, ifd_structure, makernote_offset, 8, count); reader.Read(); return(new MakernoteIFDEntry(tag, ifd_structure, MakernoteType.Leica, header.Mid(0, 8), 10, false, null)); } try { var reader = new IFDReader(file, is_bigendian, ifd_structure, baseOffset, offset, max_offset); reader.Read(); return(new MakernoteIFDEntry(tag, ifd_structure, MakernoteType.Canon)); } catch { return(null); } }
/// <summary> /// Reads the file with a specified read style. /// </summary> /// <param name="propertiesStyle"> /// A <see cref="ReadStyle" /> value specifying at what level /// of accuracy to read the media properties, or <see /// cref="ReadStyle.None" /> to ignore the properties. /// </param> private void Read (ReadStyle propertiesStyle) { Mode = AccessMode.Read; try { uint offset = ReadFirstIFDOffset (); var ifd_tag = new IFDTag (); var reader = new IFDReader (this, is_bigendian, ifd_tag.Structure, 0, offset, (uint) Length); reader.Read (); ImageTag.AddTag (ifd_tag); // Find XMP data var xmp_entry = ifd_tag.Structure.GetEntry (0, (ushort) IFDEntryTag.XMP) as ByteVectorIFDEntry; if (xmp_entry != null) { ImageTag.AddTag (new XmpTag (xmp_entry.Data.ToString ())); } if (propertiesStyle == ReadStyle.None) return; properties = ExtractProperties (); } finally { Mode = AccessMode.Closed; } }
/// <summary> /// Reads an APP1 segment to find EXIF or XMP metadata. /// </summary> /// <param name="length"> /// The length of the segment that will be read. /// </param> private void ReadAPP1Segment (ushort length) { long position = Tell; ByteVector data = null; // for an Exif segment, the data block consists of 14 bytes of: // * 6 bytes Exif identifier string // * 2 bytes bigendian indication MM (or II) // * 2 bytes Tiff magic number (42) // * 4 bytes offset of the first IFD in this segment // // the last two points are alreay encoded according to // big- or littleendian int exif_header_length = 14; // could be an Exif segment if ((ImageTag.TagTypes & TagLib.TagTypes.TiffIFD) == 0x00 && length >= exif_header_length) { data = ReadBlock (exif_header_length); if (data.Count == exif_header_length && data.Mid (0, 6).ToString ().Equals (EXIF_IDENTIFIER)) { bool is_bigendian = data.Mid (6, 2).ToString ().Equals ("MM"); ushort magic = data.Mid (8, 2).ToUShort (is_bigendian); if (magic != 42) throw new Exception (String.Format ("Invalid TIFF magic: {0}", magic)); uint ifd_offset = data.Mid (10, 4).ToUInt (is_bigendian); var exif = new IFDTag (); var reader = new IFDReader (this, is_bigendian, exif.Structure, position + 6, ifd_offset, (uint) (length - 6)); reader.Read (); ImageTag.AddTag (exif); AddMetadataBlock (position - 4, length + 4); return; } } int xmp_header_length = XmpTag.XAP_NS.Length + 1; // could be an Xmp segment if ((ImageTag.TagTypes & TagLib.TagTypes.XMP) == 0x00 && length >= xmp_header_length) { // if already data is read for determining the Exif segment, // just read the remaining bytes. // NOTE: that (exif_header_length < xmp_header_length) holds if (data == null) data = ReadBlock (xmp_header_length); else data.Add (ReadBlock (xmp_header_length - exif_header_length)); if (data.ToString ().Equals (XmpTag.XAP_NS + "\0")) { ByteVector xmp_data = ReadBlock (length - xmp_header_length); ImageTag.AddTag (new XmpTag (xmp_data.ToString (), this)); AddMetadataBlock (position - 4, length + 4); } } }
private IFDEntry ParseMakernote(ushort tag, ushort type, uint count, long base_offset, uint offset) { long makernote_offset = base_offset + offset; IFDStructure ifd_structure = new IFDStructure(); int header_size = 18; long length = 0; try { length = file.Length; } catch (Exception) { length = 1073741824L * 4; } if (makernote_offset > length) { file.MarkAsCorrupt("offset to makernote is beyond file size"); return(null); } if (makernote_offset + header_size > length) { file.MarkAsCorrupt("data is to short to contain a maker note ifd"); return(null); } file.Seek(makernote_offset, SeekOrigin.Begin); ByteVector header = file.ReadBlock(header_size); if (header.StartsWith(PANASONIC_HEADER)) { IFDReader reader = new IFDReader(file, is_bigendian, ifd_structure, base_offset, offset + 12, max_offset); reader.ReadIFD(base_offset, offset + 12, max_offset); return(new MakernoteIFDEntry(tag, ifd_structure, MakernoteType.Panasonic, PANASONIC_HEADER, 12, true, null)); } if (header.StartsWith(PENTAX_HEADER)) { IFDReader reader = new IFDReader(file, is_bigendian, ifd_structure, base_offset, offset + 6, max_offset); reader.ReadIFD(base_offset, offset + 6, max_offset); return(new MakernoteIFDEntry(tag, ifd_structure, MakernoteType.Pentax, header.Mid(0, 6), 6, true, null)); } if (header.StartsWith(OLYMPUS1_HEADER)) { IFDReader reader = new IFDReader(file, is_bigendian, ifd_structure, base_offset, offset + 8, max_offset); reader.Read(); return(new MakernoteIFDEntry(tag, ifd_structure, MakernoteType.Olympus1, header.Mid(0, 8), 8, true, null)); } if (header.StartsWith(OLYMPUS2_HEADER)) { IFDReader reader = new IFDReader(file, is_bigendian, ifd_structure, makernote_offset, 12, count); reader.Read(); return(new MakernoteIFDEntry(tag, ifd_structure, MakernoteType.Olympus2, header.Mid(0, 12), 12, false, null)); } if (header.StartsWith(SONY_HEADER)) { IFDReader reader = new IFDReader(file, is_bigendian, ifd_structure, base_offset, offset + 12, max_offset); reader.ReadIFD(base_offset, offset + 12, max_offset); return(new MakernoteIFDEntry(tag, ifd_structure, MakernoteType.Sony, SONY_HEADER, 12, true, null)); } if (header.StartsWith(NIKON_HEADER)) { ByteVector endian_bytes = header.Mid(10, 2); if (endian_bytes.ToString() == "II" || endian_bytes.ToString() == "MM") { bool makernote_endian = endian_bytes.ToString().Equals("MM"); ushort magic = header.Mid(12, 2).ToUShort(is_bigendian); if (magic == 42) { var reader = new Nikon3MakernoteReader(file, makernote_endian, ifd_structure, makernote_offset + 10, 8, max_offset - offset - 10); reader.Read(); return(new MakernoteIFDEntry(tag, ifd_structure, MakernoteType.Nikon3, header.Mid(0, 18), 8, false, makernote_endian)); } } } if (header.StartsWith(LEICA_HEADER)) { IFDReader reader = new IFDReader(file, is_bigendian, ifd_structure, makernote_offset, 8, count); reader.Read(); return(new MakernoteIFDEntry(tag, ifd_structure, MakernoteType.Leica, header.Mid(0, 8), 10, false, null)); } try { IFDReader reader = new IFDReader(file, is_bigendian, ifd_structure, base_offset, offset, max_offset); reader.Read(); return(new MakernoteIFDEntry(tag, ifd_structure, MakernoteType.Canon)); } catch { return(null); } }