This class resembles the structure of a TIFF file. It can either be a top-level IFD, or a nested IFD (in the case of Exif).
Esempio n. 1
0
        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);
            }
        }
Esempio n. 2
0
 /// <summary>
 ///    Constructor. Reads an IFD from given file, using the given endianness.
 /// </summary>
 /// <param name="file">
 ///    A <see cref="File"/> to read from.
 /// </param>
 /// <param name="is_bigendian">
 ///     A <see cref="System.Boolean"/>, it must be true, if the data of the IFD should be
 ///     read as bigendian, otherwise false.
 /// </param>
 /// <param name="structure">
 ///    A <see cref="IFDStructure"/> that will be populated.
 /// </param>
 /// <param name="base_offset">
 ///     A <see cref="System.Int64"/> value describing the base were the IFD offsets
 ///     refer to. E.g. in Jpegs the IFD are located in an Segment and the offsets
 ///     inside the IFD refer from the beginning of this segment. So <paramref
 ///     name="base_offset"/> must contain the beginning of the segment.
 /// </param>
 /// <param name="ifd_offset">
 ///     A <see cref="System.UInt32"/> value with the beginning of the IFD relative to
 ///     <paramref name="base_offset"/>.
 /// </param>
 /// <param name="max_offset">
 ///     A <see cref="System.UInt32"/> value with maximal possible offset. This is to limit
 ///     the size of the possible data;
 /// </param>
 public IFDReader(File file, bool is_bigendian, IFDStructure structure, long base_offset, uint ifd_offset, uint max_offset)
 {
     this.file         = file;
     this.is_bigendian = is_bigendian;
     this.structure    = structure;
     this.base_offset  = base_offset;
     this.ifd_offset   = ifd_offset;
     this.max_offset   = max_offset;
 }
Esempio n. 3
0
		/// <summary>
		///    Constructor. Reads an IFD from given file, using the given endianness.
		/// </summary>
		/// <param name="file">
		///    A <see cref="File"/> to read from.
		/// </param>
		/// <param name="is_bigendian">
		///     A <see cref="System.Boolean"/>, it must be true, if the data of the IFD should be
		///     read as bigendian, otherwise false.
		/// </param>
		/// <param name="structure">
		///    A <see cref="IFDStructure"/> that will be populated.
		/// </param>
		/// <param name="base_offset">
		///     A <see cref="System.Int64"/> value describing the base were the IFD offsets
		///     refer to. E.g. in Jpegs the IFD are located in an Segment and the offsets
		///     inside the IFD refer from the beginning of this segment. So <paramref
		///     name="base_offset"/> must contain the beginning of the segment.
		/// </param>
		/// <param name="ifd_offset">
		///     A <see cref="System.UInt32"/> value with the beginning of the IFD relative to
		///     <paramref name="base_offset"/>.
		/// </param>
		/// <param name="max_offset">
		/// 	A <see cref="System.UInt32"/> value with maximal possible offset. This is to limit
		///     the size of the possible data;
		/// </param>
		public IFDReader (File file, bool is_bigendian, IFDStructure structure, long base_offset, uint ifd_offset, uint max_offset)
		{
			this.file = file;
			this.is_bigendian = is_bigendian;
			this.structure = structure;
			this.base_offset = base_offset;
			this.ifd_offset = ifd_offset;
			this.max_offset = max_offset;
		}
Esempio n. 4
0
		/// <summary>
		///    Create a reader for Sub IFD entries.
		/// </summary>
		/// <param name="file">
		///    A <see cref="File"/> to read from.
		/// </param>
		/// <param name="is_bigendian">
		///     A <see cref="System.Boolean"/>, it must be true, if the data of the IFD should be
		///     read as bigendian, otherwise false.
		/// </param>
		/// <param name="structure">
		///    A <see cref="IFDStructure"/> that will be populated.
		/// </param>
		/// <param name="base_offset">
		///    A <see cref="System.Int64"/> with the base offset which every offsets in the
		///    IFD are relative to.
		/// </param>
		/// <param name="offset">
		///    A <see cref="System.UInt32"/> with the offset of the entry.
		/// </param>
		/// <param name="max_offset">
		///    A <see cref="System.UInt32"/> with the maximal offset to consider for
		///    the IFD.
		/// </param>
		/// <returns>
		///    A <see cref="IFDReader"/> which can be used to read the specified sub IFD.
		/// </returns>
		protected virtual IFDReader CreateSubIFDReader (File file, bool is_bigendian, IFDStructure structure, long base_offset, uint offset, uint max_offset)
		{
			return new IFDReader (file, is_bigendian, structure, base_offset, offset, max_offset);
		}
Esempio n. 5
0
        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);
            }
        }
Esempio n. 6
0
 /// <summary>
 ///    Create a reader for Sub IFD entries.
 /// </summary>
 /// <param name="file">
 ///    A <see cref="File"/> to read from.
 /// </param>
 /// <param name="isBigendian">
 ///     A <see cref="System.Boolean"/>, it must be true, if the data of the IFD should be
 ///     read as bigendian, otherwise false.
 /// </param>
 /// <param name="structure">
 ///    A <see cref="IFDStructure"/> that will be populated.
 /// </param>
 /// <param name="baseOffset">
 ///    A <see cref="System.Int64"/> with the base offset which every offsets in the
 ///    IFD are relative to.
 /// </param>
 /// <param name="offset">
 ///    A <see cref="System.UInt32"/> with the offset of the entry.
 /// </param>
 /// <param name="maxOffset">
 ///    A <see cref="System.UInt32"/> with the maximal offset to consider for
 ///    the IFD.
 /// </param>
 /// <returns>
 ///    A <see cref="IFDReader"/> which can be used to read the specified sub IFD.
 /// </returns>
 protected virtual IFDReader CreateSubIFDReader(File file, bool isBigendian, IFDStructure structure, long baseOffset, uint offset, uint maxOffset)
 {
     return(new IFDReader(file, isBigendian, structure, baseOffset, offset, maxOffset));
 }
Esempio n. 7
0
 public IFDTag()
 {
     Structure = new IFDStructure();
 }
Esempio n. 8
0
		/// <summary>
		///    Constructor. Creates an empty IFD tag. Can be populated manually, or via
		///    <see cref="IFDReader"/>.
		/// </summary>
		public IFDTag ()
		{
			Structure = new IFDStructure ();
		}
 /// <summary>
 ///    Constructs a new IFD Renderer used to render a <see cref="SubIFDEntry"/>.
 /// </summary>
 /// <param name="is_bigendian">
 ///    If IFD should be encoded in BigEndian or not.
 /// </param>
 /// <param name="structure">
 ///    The IFD structure that will be rendered.
 /// </param>
 /// <param name="ifd_offset">
 ///    A <see cref="System.UInt32"/> value with the offset of the
 ///    current IFD. All offsets inside the IFD must be adjusted
 ///    according to this given offset.
 /// </param>
 protected virtual IFDRenderer CreateSubRenderer(bool is_bigendian, IFDStructure structure, uint ifd_offset)
 {
     return new IFDRenderer (is_bigendian, structure, ifd_offset);
 }
Esempio n. 10
0
 /// <summary>
 ///    Creates an IFD reader to parse the file.
 /// </summary>
 /// <param name="file">
 ///    A <see cref="File"/> to read from.
 /// </param>
 /// <param name="is_bigendian">
 ///     A <see cref="System.Boolean"/>, it must be true, if the data of the IFD should be
 ///     read as bigendian, otherwise false.
 /// </param>
 /// <param name="structure">
 ///    A <see cref="IFDStructure"/> that will be populated.
 /// </param>
 /// <param name="base_offset">
 ///     A <see cref="System.Int64"/> value describing the base were the IFD offsets
 ///     refer to. E.g. in Jpegs the IFD are located in an Segment and the offsets
 ///     inside the IFD refer from the beginning of this segment. So <paramref
 ///     name="base_offset"/> must contain the beginning of the segment.
 /// </param>
 /// <param name="ifd_offset">
 ///     A <see cref="System.UInt32"/> value with the beginning of the IFD relative to
 ///     <paramref name="base_offset"/>.
 /// </param>
 /// <param name="max_offset">
 /// 	A <see cref="System.UInt32"/> value with maximal possible offset. This is to limit
 ///     the size of the possible data;
 /// </param>
 protected override TagLib.IFD.IFDReader CreateIFDReader(BaseTiffFile file, bool is_bigendian, IFDStructure structure, long base_offset, uint ifd_offset, uint max_offset)
 {
     return new IFDReader (file, is_bigendian, structure, base_offset, ifd_offset, max_offset);
 }
Esempio n. 11
0
		/// <summary>
		///    Constructor. Reads an IFD from given file, using the given endianness.
		/// </summary>
		/// <param name="file">
		///    A <see cref="File"/> to read from.
		/// </param>
		/// <param name="is_bigendian">
		///     A <see cref="System.Boolean"/>, it must be true, if the data of the IFD should be
		///     read as bigendian, otherwise false.
		/// </param>
		/// <param name="structure">
		///    A <see cref="IFDStructure"/> that will be populated.
		/// </param>
		/// <param name="base_offset">
		///     A <see cref="System.Int64"/> value describing the base were the IFD offsets
		///     refer to. E.g. in Jpegs the IFD are located in an Segment and the offsets
		///     inside the IFD refer from the beginning of this segment. So <paramref
		///     name="base_offset"/> must contain the beginning of the segment.
		/// </param>
		/// <param name="ifd_offset">
		///     A <see cref="System.UInt32"/> value with the beginning of the IFD relative to
		///     <paramref name="base_offset"/>.
		/// </param>
		/// <param name="max_offset">
		/// 	A <see cref="System.UInt32"/> value with maximal possible offset. This is to limit
		///     the size of the possible data;
		/// </param>
		public IFDReader (BaseTiffFile file, bool is_bigendian, IFDStructure structure, long base_offset, uint ifd_offset, uint max_offset) :
			base (file, is_bigendian, structure, base_offset, ifd_offset, max_offset)
		{
		}
Esempio n. 12
0
		/// <summary>
		///    Try to parse the given IFD entry, used to discover format-specific entries.
		/// </summary>
		/// <param name="tag">
		///    A <see cref="System.UInt16"/> with the tag of the entry.
		/// </param>
		/// <param name="type">
		///    A <see cref="System.UInt16"/> with the type of the entry.
		/// </param>
		/// <param name="count">
		///    A <see cref="System.UInt32"/> with the data count of the entry.
		/// </param>
		/// <param name="base_offset">
		///    A <see cref="System.Int64"/> with the base offset which every offsets in the
		///    IFD are relative to.
		/// </param>
		/// <param name="offset">
		///    A <see cref="System.UInt32"/> with the offset of the entry.
		/// </param>
		/// <returns>
		///    A <see cref="IFDEntry"/> with the given parameters, or null if none was parsed, after
		///    which the normal TIFF parsing is used.
		/// </returns>
		protected virtual IFDEntry ParseIFDEntry (ushort tag, ushort type, uint count, long base_offset, uint offset)
		{
			if (tag == (ushort) ExifEntryTag.MakerNote)
				return ParseMakernote (tag, type, count, base_offset, offset);
			
			IFDStructure ifd_structure = new IFDStructure ();
			IFDReader reader = CreateSubIFDReader (file, is_bigendian, ifd_structure, base_offset, offset, max_offset);
			
			// Sub IFDs are either identified by the IFD-type ...
			if (type == (ushort) IFDEntryType.IFD) {
				reader.Read ();
				return new SubIFDEntry (tag, type, (uint) ifd_structure.Directories.Length, ifd_structure);
			}
			
			// ... or by one of the following tags
			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;
			}
		}
Esempio n. 13
0
 /// <summary>
 ///    Constructor. Will render the given IFD structure.
 /// </summary>
 /// <param name="is_bigendian">
 ///    If IFD should be encoded in BigEndian or not.
 /// </param>
 /// <param name="structure">
 ///    The IFD structure that will be rendered.
 /// </param>
 /// <param name="ifd_offset">
 ///    A <see cref="System.UInt32"/> value with the offset of the
 ///    current IFD. All offsets inside the IFD must be adjusted
 ///    according to this given offset.
 /// </param>
 public IFDRenderer(bool is_bigendian, IFDStructure structure, uint ifd_offset)
 {
     this.is_bigendian = is_bigendian;
     this.structure    = structure;
     this.ifd_offset   = ifd_offset;
 }
Esempio n. 14
0
 /// <summary>
 ///    Constructs a new IFD Renderer used to render a <see cref="SubIFDEntry"/>.
 /// </summary>
 /// <param name="is_bigendian">
 ///    If IFD should be encoded in BigEndian or not.
 /// </param>
 /// <param name="structure">
 ///    The IFD structure that will be rendered.
 /// </param>
 /// <param name="ifd_offset">
 ///    A <see cref="System.UInt32"/> value with the offset of the
 ///    current IFD. All offsets inside the IFD must be adjusted
 ///    according to this given offset.
 /// </param>
 protected virtual IFDRenderer CreateSubRenderer(bool is_bigendian, IFDStructure structure, uint ifd_offset)
 {
     return(new IFDRenderer(is_bigendian, structure, ifd_offset));
 }
Esempio n. 15
0
		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;
			}
		}
 /// <summary>
 ///    Constructor. Will render the given IFD structure.
 /// </summary>
 /// <param name="is_bigendian">
 ///    If IFD should be encoded in BigEndian or not.
 /// </param>
 /// <param name="structure">
 ///    The IFD structure that will be rendered.
 /// </param>
 /// <param name="ifd_offset">
 ///    A <see cref="System.UInt32"/> value with the offset of the
 ///    current IFD. All offsets inside the IFD must be adjusted
 ///    according to this given offset.
 /// </param>
 public IFDRenderer(bool is_bigendian, IFDStructure structure, uint ifd_offset)
 {
     this.is_bigendian = is_bigendian;
     this.structure = structure;
     this.ifd_offset = ifd_offset;
 }
Esempio n. 17
0
		/// <summary>
		///    Try to parse the given IFD entry, used to discover format-specific entries.
		/// </summary>
		/// <param name="tag">
		///    A <see cref="System.UInt16"/> with the tag of the entry.
		/// </param>
		/// <param name="type">
		///    A <see cref="System.UInt16"/> with the type of the entry.
		/// </param>
		/// <param name="count">
		///    A <see cref="System.UInt32"/> with the data count of the entry.
		/// </param>
		/// <param name="base_offset">
		///    A <see cref="System.Int64"/> with the base offset which every offsets in the
		///    IFD are relative to.
		/// </param>
		/// <param name="offset">
		///    A <see cref="System.UInt32"/> with the offset of the entry.
		/// </param>
		/// <returns>
		///    A <see cref="IFDEntry"/> with the given parameters, or null if none was parsed, after
		///    which the normal TIFF parsing is used.
		/// </returns>
		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) {

					// This is impossible right?
					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);

			// Sub IFDs are either identified by the IFD-type ...
			if (type == (ushort) IFDEntryType.IFD) {
				reader.Read ();
				return new SubIFDEntry (tag, type, (uint) ifd_structure.Directories.Length, ifd_structure);
			}

			// ... or by one of the following tags
			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;
			}
		}
Esempio n. 18
0
        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);
            }
        }