/// <summary>
        ///    Reads an IFD from file at position <paramref name="offset"/> relative
        ///    to <paramref name="baseOffset"/>.
        /// </summary>
        /// <param name="baseOffset">
        ///    A <see cref="System.Int64"/> with the base offset which every offset
        ///    in IFD is relative to.
        /// </param>
        /// <param name="offset">
        ///    A <see cref="System.UInt32"/> with the offset of the IFD relative to
        ///    <paramref name="baseOffset"/>
        /// </param>
        /// <param name="maxOffset">
        ///    A <see cref="System.UInt32"/> with the maximal offset to consider for
        ///    the IFD.
        /// </param>
        /// <returns>
        ///    A <see cref="System.UInt32"/> with the offset of the next IFD, the
        ///    offset is also relative to <paramref name="baseOffset"/>
        /// </returns>
        uint ReadIFD(long baseOffset, uint offset, uint maxOffset)
        {
            long length = 0;

            try {
                length = file.Length;
            } catch (Exception) {
                // Use a safety-value of 4 gigabyte.
                length = 1073741824L * 4;
            }

            if (baseOffset + offset > length)
            {
                file.MarkAsCorrupt("Invalid IFD offset");
                return(0);
            }

            var directory = new IFDDirectory();

            file.Seek(baseOffset + offset, SeekOrigin.Begin);
            ushort entry_count = ReadUShort();

            if (file.Tell + 12 * entry_count > baseOffset + maxOffset)
            {
                file.MarkAsCorrupt("Size of entries exceeds possible data size");
                return(0);
            }

            ByteVector entry_datas = file.ReadBlock(12 * entry_count);
            uint       next_offset = ReadUInt();

            for (int i = 0; i < entry_count; i++)
            {
                ByteVector entry_data = entry_datas.Mid(i * 12, 12);

                ushort     entry_tag   = entry_data.Mid(0, 2).ToUShort(is_bigendian);
                ushort     type        = entry_data.Mid(2, 2).ToUShort(is_bigendian);
                uint       value_count = entry_data.Mid(4, 4).ToUInt(is_bigendian);
                ByteVector offset_data = entry_data.Mid(8, 4);

                IFDEntry entry = CreateIFDEntry(entry_tag, type, value_count, baseOffset, offset_data, maxOffset);

                if (entry == null)
                {
                    continue;
                }

                if (directory.ContainsKey(entry.Tag))
                {
                    directory.Remove(entry.Tag);
                }

                directory.Add(entry.Tag, entry);
            }

            FixupDirectory(baseOffset, directory);

            structure.directories.Add(directory);
            return(next_offset);
        }
		/// <summary>
		///    Performs some fixups to a read <see cref="IFDDirectory"/>. For some
		///    special cases multiple <see cref="IFDEntry"/> instances contained
		///    in the directory are needed. Therfore, we do the fixups after reading the
		///    whole directory to be sure, all entries are present.
		/// </summary>
		/// <param name="base_offset">
		///    A <see cref="System.Int64"/> value with the base offset, all offsets in the
		///    directory refers to.
		/// </param>
		/// <param name="directory">
		///    A <see cref="IFDDirectory"/> instance which was read and needs fixes.
		/// </param>
		private void FixupDirectory (long base_offset, IFDDirectory directory)
		{
			// The following two entries refer to thumbnail data, where one is  the offset
			// to the data and the other is the length. Unnaturally both are used to describe
			// the data. So it is needed to keep both entries in sync and keep the thumbnail data
			// for writing it back.
			// We determine the position of the data, read it and store it in an ThumbnailDataIFDEntry
			// which replaces the offset-entry to thumbnail data.
			ushort offset_tag = (ushort) IFDEntryTag.JPEGInterchangeFormat;
			ushort length_tag = (ushort) IFDEntryTag.JPEGInterchangeFormatLength;
			if (directory.ContainsKey (offset_tag) && directory.ContainsKey (length_tag)) {

				var offset_entry = directory [offset_tag] as LongIFDEntry;
				var length_entry = directory [length_tag] as LongIFDEntry;

				if (offset_entry != null && length_entry != null) {
					uint offset = offset_entry.Value;
					uint length = length_entry.Value;

					file.Seek (base_offset + offset, SeekOrigin.Begin);
					ByteVector data = file.ReadBlock ((int) length);

					directory.Remove (offset_tag);
					directory.Add (offset_tag, new ThumbnailDataIFDEntry (offset_tag, data));
				}
			}


			// create a StripOffsetIFDEntry if necessary
			ushort strip_offsets_tag = (ushort) IFDEntryTag.StripOffsets;
			ushort strip_byte_counts_tag = (ushort) IFDEntryTag.StripByteCounts;
			if (directory.ContainsKey (strip_offsets_tag) && directory.ContainsKey (strip_byte_counts_tag)) {

				uint [] strip_offsets = null;
				uint [] strip_byte_counts = null;

				var strip_offsets_entry = directory [strip_offsets_tag];
				var strip_byte_counts_entry = directory [strip_byte_counts_tag];

				if (strip_offsets_entry is LongIFDEntry)
					strip_offsets = new uint[] {(strip_offsets_entry as LongIFDEntry).Value};
				else if (strip_offsets_entry is LongArrayIFDEntry)
					strip_offsets = (strip_offsets_entry as LongArrayIFDEntry).Values;

				if (strip_offsets == null)
					return;

				if (strip_byte_counts_entry is LongIFDEntry)
					strip_byte_counts = new uint[] {(strip_byte_counts_entry as LongIFDEntry).Value};
				else if (strip_byte_counts_entry is LongArrayIFDEntry)
					strip_byte_counts = (strip_byte_counts_entry as LongArrayIFDEntry).Values;

				if (strip_byte_counts == null)
					return;

				directory.Remove (strip_offsets_tag);
				directory.Add (strip_offsets_tag, new StripOffsetsIFDEntry (strip_offsets_tag, strip_offsets, strip_byte_counts, file));
			}
		}
		/// <summary>
		///    Reads an IFD from file at position <paramref name="offset"/> relative
		///    to <paramref name="base_offset"/>.
		/// </summary>
		/// <param name="base_offset">
		///    A <see cref="System.Int64"/> with the base offset which every offset
		///    in IFD is relative to.
		/// </param>
		/// <param name="offset">
		///    A <see cref="System.UInt32"/> with the offset of the IFD relative to
		///    <paramref name="base_offset"/>
		/// </param>
		/// <param name="max_offset">
		///    A <see cref="System.UInt32"/> with the maximal offset to consider for
		///    the IFD.
		/// </param>
		/// <returns>
		///    A <see cref="System.UInt32"/> with the offset of the next IFD, the
		///    offset is also relative to <paramref name="base_offset"/>
		/// </returns>
		private uint ReadIFD (long base_offset, uint offset, uint max_offset)
		{
			long length = 0;
			try {
				length = file.Length;
			} catch (Exception) {
				// Use a safety-value of 4 gigabyte.
				length = 1073741824L * 4;
			}

			if (base_offset + offset > length) {
				file.MarkAsCorrupt ("Invalid IFD offset");
				return 0;
			}

			var directory = new IFDDirectory ();

			file.Seek (base_offset + offset, SeekOrigin.Begin);
			ushort entry_count = ReadUShort ();

			if (file.Tell + 12 * entry_count > base_offset + max_offset) {
				file.MarkAsCorrupt ("Size of entries exceeds possible data size");
				return 0;
			}

			ByteVector entry_datas = file.ReadBlock (12 * entry_count);
			uint next_offset = ReadUInt ();

			for (int i = 0; i < entry_count; i++) {
				ByteVector entry_data = entry_datas.Mid (i * 12, 12);

				ushort entry_tag = entry_data.Mid (0, 2).ToUShort (is_bigendian);
				ushort type = entry_data.Mid (2, 2).ToUShort (is_bigendian);
				uint value_count = entry_data.Mid (4, 4).ToUInt (is_bigendian);
				ByteVector offset_data = entry_data.Mid (8, 4);

				IFDEntry entry = CreateIFDEntry (entry_tag, type, value_count, base_offset, offset_data, max_offset);

				if (entry == null)
					continue;

				if (directory.ContainsKey (entry.Tag))
					directory.Remove (entry.Tag);

				directory.Add (entry.Tag, entry);
			}

			FixupDirectory (base_offset, directory);

			structure.directories.Add (directory);
			return next_offset;
		}
        /// <summary>
        ///    Performs some fixups to a read <see cref="IFDDirectory"/>. For some
        ///    special cases multiple <see cref="IFDEntry"/> instances contained
        ///    in the directory are needed. Therfore, we do the fixups after reading the
        ///    whole directory to be sure, all entries are present.
        /// </summary>
        /// <param name="baseOffset">
        ///    A <see cref="System.Int64"/> value with the base offset, all offsets in the
        ///    directory refers to.
        /// </param>
        /// <param name="directory">
        ///    A <see cref="IFDDirectory"/> instance which was read and needs fixes.
        /// </param>
        void FixupDirectory(long baseOffset, IFDDirectory directory)
        {
            // The following two entries refer to thumbnail data, where one is  the offset
            // to the data and the other is the length. Unnaturally both are used to describe
            // the data. So it is needed to keep both entries in sync and keep the thumbnail data
            // for writing it back.
            // We determine the position of the data, read it and store it in an ThumbnailDataIFDEntry
            // which replaces the offset-entry to thumbnail data.
            ushort offset_tag = (ushort)IFDEntryTag.JPEGInterchangeFormat;
            ushort length_tag = (ushort)IFDEntryTag.JPEGInterchangeFormatLength;

            if (directory.ContainsKey(offset_tag) && directory.ContainsKey(length_tag))
            {
                if (directory[offset_tag] is LongIFDEntry offset_entry && directory[length_tag] is LongIFDEntry length_entry)
                {
                    uint offset = offset_entry.Value;
                    uint length = length_entry.Value;

                    file.Seek(baseOffset + offset, SeekOrigin.Begin);
                    var data = file.ReadBlock((int)length);

                    directory.Remove(offset_tag);
                    directory.Add(offset_tag, new ThumbnailDataIFDEntry(offset_tag, data));
                }
            }


            // create a StripOffsetIFDEntry if necessary
            ushort strip_offsets_tag     = (ushort)IFDEntryTag.StripOffsets;
            ushort strip_byte_counts_tag = (ushort)IFDEntryTag.StripByteCounts;

            if (directory.ContainsKey(strip_offsets_tag) && directory.ContainsKey(strip_byte_counts_tag))
            {
                uint[] strip_offsets     = null;
                uint[] strip_byte_counts = null;

                var strip_offsets_entry     = directory[strip_offsets_tag];
                var strip_byte_counts_entry = directory[strip_byte_counts_tag];

                if (strip_offsets_entry is LongIFDEntry)
                {
                    strip_offsets = new[] { (strip_offsets_entry as LongIFDEntry).Value }
                }
                ;
                else if (strip_offsets_entry is LongArrayIFDEntry)
                {
                    strip_offsets = (strip_offsets_entry as LongArrayIFDEntry).Values;
                }

                if (strip_offsets == null)
                {
                    return;
                }

                if (strip_byte_counts_entry is LongIFDEntry)
                {
                    strip_byte_counts = new[] { (strip_byte_counts_entry as LongIFDEntry).Value }
                }
                ;
                else if (strip_byte_counts_entry is LongArrayIFDEntry)
                {
                    strip_byte_counts = (strip_byte_counts_entry as LongArrayIFDEntry).Values;
                }

                if (strip_byte_counts == null)
                {
                    return;
                }

                directory.Remove(strip_offsets_tag);
                directory.Add(strip_offsets_tag, new StripOffsetsIFDEntry(strip_offsets_tag, strip_offsets, strip_byte_counts, file));
            }
        }
Exemple #5
0
        /// <summary>
        ///    Reads an IFD from file at position <paramref name="offset"/> relative
        ///    to <paramref name="base_offset"/>.
        /// </summary>
        /// <param name="base_offset">
        ///    A <see cref="System.Int64"/> with the base offset which every offset
        ///    in IFD is relative to.
        /// </param>
        /// <param name="offset">
        ///    A <see cref="System.UInt32"/> with the offset of the IFD relative to
        ///    <paramref name="base_offset"/>
        /// </param>
        /// <param name="max_offset">
        ///    A <see cref="System.UInt32"/> with the maximal offset to consider for
        ///    the IFD.
        /// </param>
        /// <returns>
        ///    A <see cref="System.UInt32"/> with the offset of the next IFD, the
        ///    offset is also relative to <paramref name="base_offset"/>
        /// </returns>
        private uint ReadIFD(long base_offset, uint offset, uint max_offset)
        {
            long length = 0;

            try {
                length = file.Length;
            } catch (Exception) {
                // Use a safety-value of 4 gigabyte.
                length = 1073741824L * 4;
            }

            if (base_offset + offset > length)
            {
                file.MarkAsCorrupt("Invalid IFD offset");
                return(0);
            }

            var directory = new IFDDirectory();

            file.Seek(base_offset + offset, SeekOrigin.Begin);
            ushort entry_count = ReadUShort();

            if (file.Tell + 12 * entry_count > base_offset + max_offset)
            {
                file.MarkAsCorrupt("Size of entries exceeds possible data size");
                return(0);
            }

            ByteVector entry_datas = file.ReadBlock(12 * entry_count);
            uint       next_offset = ReadUInt();

            for (int i = 0; i < entry_count; i++)
            {
                ByteVector entry_data = entry_datas.Mid(i * 12, 12);

                ushort     entry_tag   = entry_data.Mid(0, 2).ToUShort(is_bigendian);
                ushort     type        = entry_data.Mid(2, 2).ToUShort(is_bigendian);
                uint       value_count = entry_data.Mid(4, 4).ToUInt(is_bigendian);
                ByteVector offset_data = entry_data.Mid(8, 4);

                // Even if the value count represents a single bytes it's impossible
                // for the count plus the base offset to be bigger than the entire file,
                // ignore this entry and keep going
                if (value_count + base_offset > max_offset)
                {
                    file.MarkAsCorrupt("Value count + base offset is greater than the maximum possible offset");
                    continue;
                }

                IFDEntry entry = CreateIFDEntry(entry_tag, type, value_count, base_offset, offset_data, max_offset);

                if (entry == null)
                {
                    continue;
                }

                if (directory.ContainsKey(entry.Tag))
                {
                    directory.Remove(entry.Tag);
                }

                directory.Add(entry.Tag, entry);
            }

            FixupDirectory(base_offset, directory);

            structure.directories.Add(directory);
            return(next_offset);
        }
Exemple #6
0
		/// <summary>
		///    Performs some fixups to a read <see cref="IFDDirectory"/>. For some
		///    special cases multiple <see cref="IFDEntry"/> instances contained
		///    in the directory are needed. Therfore, we do the fixups after reading the
		///    whole directory to be sure, all entries are present.
		/// </summary>
		/// <param name="base_offset">
		///    A <see cref="System.Int64"/> value with the base offset, all offsets in the
		///    directory refers to.
		/// </param>
		/// <param name="directory">
		///    A <see cref="IFDDirectory"/> instance which was read and needs fixes.
		/// </param>
		private void FixupDirectory (long base_offset, IFDDirectory directory)
		{
			// The following two entries refer to thumbnail data, where one is  the offset
			// to the data and the other is the length. Unnaturally both are used to describe
			// the data. So it is needed to keep both entries in sync and keep the thumbnail data
			// for writing it back.
			// We determine the position of the data, read it and store it in an ThumbnailDataIFDEntry
			// which replaces the offset-entry to thumbnail data.
			ushort offset_tag = (ushort) IFDEntryTag.JPEGInterchangeFormat;
			ushort length_tag = (ushort) IFDEntryTag.JPEGInterchangeFormatLength;
			if (directory.ContainsKey (offset_tag) && directory.ContainsKey (length_tag)) {
				
				var offset_entry = directory [offset_tag] as LongIFDEntry;
				var length_entry = directory [length_tag] as LongIFDEntry;
				
				if (offset_entry != null && length_entry != null) {
					uint offset = offset_entry.Value;
					uint length = length_entry.Value;
					
					file.Seek (base_offset + offset, SeekOrigin.Begin);
					ByteVector data = file.ReadBlock ((int) length);
					
					directory.Remove (offset_tag);
					directory.Add (offset_tag, new ThumbnailDataIFDEntry (offset_tag, data));
				}
			}
		}
Exemple #7
0
		/// <summary>
		///    Reads an IFD from file at position <paramref name="offset"/> relative
		///    to <paramref name="base_offset"/>.
		/// </summary>
		/// <param name="base_offset">
		///    A <see cref="System.Int64"/> with the base offset which every offset
		///    in IFD is relative to.
		/// </param>
		/// <param name="offset">
		///    A <see cref="System.UInt32"/> with the offset of the IFD relative to
		///    <paramref name="base_offset"/>
		/// </param>
		/// <param name="max_offset">
		///    A <see cref="System.UInt32"/> with the maximal offset to consider for
		///    the IFD.
		/// </param>
		/// <returns>
		///    A <see cref="System.UInt32"/> with the offset of the next IFD, the
		///    offset is also relative to <paramref name="base_offset"/>
		/// </returns>
		private uint ReadIFD (long base_offset, uint offset, uint max_offset)
		{
			if (base_offset + offset > file.Length)
				throw new Exception (String.Format ("Invalid IFD offset {0}, length: {1}", offset, file.Length));

			var directory = new IFDDirectory ();

			file.Seek (base_offset + offset, SeekOrigin.Begin);
			ushort entry_count = ReadUShort ();

			if (file.Tell + 12 * entry_count > base_offset + max_offset)
				throw new Exception (String.Format ("Size of entries exceeds possible data size"));
			
			ByteVector entry_datas = file.ReadBlock (12 * entry_count);
			uint next_offset = ReadUInt ();
			
			for (int i = 0; i < entry_count; i++) {
				ByteVector entry_data = entry_datas.Mid (i * 12, 12);
				
				ushort entry_tag = entry_data.Mid (0, 2).ToUShort (is_bigendian);
				ushort type = entry_data.Mid (2, 2).ToUShort (is_bigendian);
				uint value_count = entry_data.Mid (4, 4).ToUInt (is_bigendian);
				ByteVector offset_data = entry_data.Mid (8, 4);

				IFDEntry entry = CreateIFDEntry (entry_tag, type, value_count, base_offset, offset_data, max_offset);
				
				if (entry == null)
					continue;
				
				if (directory.ContainsKey (entry.Tag))
					directory.Remove (entry.Tag);
				
				directory.Add (entry.Tag, entry);
			}

			FixupDirectory (base_offset, directory);
			
			structure.directories.Add (directory);
			return next_offset;
		}
Exemple #8
0
        private void FixupDirectory(long base_offset, IFDDirectory directory)
        {
            ushort offset_tag = (ushort)IFDEntryTag.JPEGInterchangeFormat;
            ushort length_tag = (ushort)IFDEntryTag.JPEGInterchangeFormatLength;

            if (directory.ContainsKey(offset_tag) && directory.ContainsKey(length_tag))
            {
                var offset_entry = directory[offset_tag] as LongIFDEntry;
                var length_entry = directory[length_tag] as LongIFDEntry;
                if (offset_entry != null && length_entry != null)
                {
                    uint offset = offset_entry.Value;
                    uint length = length_entry.Value;
                    file.Seek(base_offset + offset, SeekOrigin.Begin);
                    ByteVector data = file.ReadBlock((int)length);
                    directory.Remove(offset_tag);
                    directory.Add(offset_tag, new ThumbnailDataIFDEntry(offset_tag, data));
                }
            }
            ushort strip_offsets_tag     = (ushort)IFDEntryTag.StripOffsets;
            ushort strip_byte_counts_tag = (ushort)IFDEntryTag.StripByteCounts;

            if (directory.ContainsKey(strip_offsets_tag) && directory.ContainsKey(strip_byte_counts_tag))
            {
                uint[] strip_offsets           = null;
                uint[] strip_byte_counts       = null;
                var    strip_offsets_entry     = directory[strip_offsets_tag];
                var    strip_byte_counts_entry = directory[strip_byte_counts_tag];
                if (strip_offsets_entry is LongIFDEntry)
                {
                    strip_offsets = new uint[]
                    {
                        (strip_offsets_entry as LongIFDEntry).Value
                    };
                }
                else if (strip_offsets_entry is LongArrayIFDEntry)
                {
                    strip_offsets = (strip_offsets_entry as LongArrayIFDEntry).Values;
                }
                if (strip_offsets == null)
                {
                    return;
                }
                if (strip_byte_counts_entry is LongIFDEntry)
                {
                    strip_byte_counts = new uint[]
                    {
                        (strip_byte_counts_entry as LongIFDEntry).Value
                    };
                }
                else if (strip_byte_counts_entry is LongArrayIFDEntry)
                {
                    strip_byte_counts = (strip_byte_counts_entry as LongArrayIFDEntry).Values;
                }
                if (strip_byte_counts == null)
                {
                    return;
                }
                directory.Remove(strip_offsets_tag);
                directory.Add(strip_offsets_tag, new StripOffsetsIFDEntry(strip_offsets_tag, strip_offsets, strip_byte_counts, file));
            }
        }