Beispiel #1
0
        /// <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);
        }
Beispiel #2
0
        /// <summary>
        ///    Renders a complete entry together with the data. The entry itself
        ///    is stored in <paramref name="entry_data"/> and the data of the
        ///    entry is stored in <paramref name="offset_data"/> if it cannot be
        ///    stored in the offset. This method is called for every <see
        ///    cref="IFDEntry"/> of this IFD and can be overwritten in subclasses
        ///    to provide special behavior.
        /// </summary>
        /// <param name="entry">
        ///    A <see cref="IFDEntry"/> with the entry to render.
        /// </param>
        /// <param name="entry_data">
        ///    A <see cref="ByteVector"/> to add the entry to.
        /// </param>
        /// <param name="offset_data">
        ///    A <see cref="ByteVector"/> to add the entry data to if it cannot be
        ///    stored in the offset field.
        /// </param>
        /// <param name="data_offset">
        ///    A <see cref="System.UInt32"/> with the offset, were the data of the
        ///    entries starts. It is needed to adjust the offsets of the entries
        ///    itself.
        /// </param>
        protected virtual void RenderEntryData(IFDEntry entry, ByteVector entry_data, ByteVector offset_data, uint data_offset)
        {
            ushort tag    = (ushort)entry.Tag;
            uint   offset = (uint)(data_offset + offset_data.Count);

            ushort     type;
            uint       count;
            ByteVector data = entry.Render(is_bigendian, offset, out type, out count);

            // store data in offset, if it is smaller than 4 byte
            if (data.Count <= 4)
            {
                while (data.Count < 4)
                {
                    data.Add("\0");
                }

                offset = data.ToUInt(is_bigendian);
                data   = null;
            }

            // preserve word boundary of offsets
            if (data != null && data.Count % 2 != 0)
            {
                data.Add("\0");
            }

            RenderEntry(entry_data, tag, type, count, offset);
            offset_data.Add(data);
        }
        /// <summary>
        ///    Adds an <see cref="IFDEntry"/> to the IFD, if it is not already
        ///    contained in, it fails otherwise.
        /// </summary>
        /// <param name="directory">
        ///    A <see cref="System.Int32"/> value with the directory index that
        ///    should contain the tag that will be added.
        /// </param>
        /// <param name="entry">
        ///    A <see cref="IFDEntry"/> to add to the IFD.
        /// </param>
        public void AddEntry(int directory, IFDEntry entry)
        {
            while (directory >= directories.Count)
                directories.Add (new IFDDirectory ());

            directories [directory].Add (entry.Tag, entry);
        }
Beispiel #4
0
 public void SetEntry(int directory, IFDEntry entry)
 {
     if (ContainsTag(directory, entry.Tag))
     {
         RemoveTag(directory, entry.Tag);
     }
     AddEntry(directory, entry);
 }
Beispiel #5
0
 public void AddEntry(int directory, IFDEntry entry)
 {
     while (directory >= directories.Count)
     {
         directories.Add(new IFDDirectory());
     }
     directories[directory].Add(entry.Tag, entry);
 }
Beispiel #6
0
        protected virtual void RenderEntryData(IFDEntry entry, ByteVector entry_data, ByteVector offset_data, uint data_offset)
        {
            ushort     tag    = (ushort)entry.Tag;
            uint       offset = (uint)(data_offset + offset_data.Count);
            ushort     type;
            uint       count;
            ByteVector data = entry.Render(is_bigendian, offset, out type, out count);

            if (data.Count <= 4)
            {
                while (data.Count < 4)
                {
                    data.Add("\0");
                }
                offset = data.ToUInt(is_bigendian);
                data   = null;
            }
            if (data != null && data.Count % 2 != 0)
            {
                data.Add("\0");
            }
            RenderEntry(entry_data, tag, type, count, offset);
            offset_data.Add(data);
        }
        /// <summary>
        ///    Renders a complete entry together with the data. The entry itself
        ///    is stored in <paramref name="entry_data"/> and the data of the
        ///    entry is stored in <paramref name="offset_data"/> if it cannot be
        ///    stored in the offset. This method is called for every <see
        ///    cref="IFDEntry"/> of this IFD and can be overwritten in subclasses
        ///    to provide special behavior.
        /// </summary>
        /// <param name="entry">
        ///    A <see cref="IFDEntry"/> with the entry to render.
        /// </param>
        /// <param name="entry_data">
        ///    A <see cref="ByteVector"/> to add the entry to.
        /// </param>
        /// <param name="offset_data">
        ///    A <see cref="ByteVector"/> to add the entry data to if it cannot be
        ///    stored in the offset field.
        /// </param>
        /// <param name="data_offset">
        ///    A <see cref="System.UInt32"/> with the offset, were the data of the
        ///    entries starts. It is needed to adjust the offsets of the entries
        ///    itself.
        /// </param>
        protected virtual void RenderEntryData(IFDEntry entry, ByteVector entry_data, ByteVector offset_data, uint data_offset)
        {
            ushort tag = (ushort) entry.Tag;
            uint offset = (uint) (data_offset + offset_data.Count);

            ushort type;
            uint count;
            ByteVector data = entry.Render (is_bigendian, offset, out type, out count);

            // store data in offset, if it is smaller than 4 byte
            if (data.Count <= 4) {

                while (data.Count < 4)
                    data.Add ("\0");

                offset = data.ToUInt (is_bigendian);
                data = null;
            }

            // preserve word boundary of offsets
            if (data != null && data.Count % 2 != 0)
                data.Add ("\0");

            RenderEntry (entry_data, tag, type, count, offset);
            offset_data.Add (data);
        }
        /// <summary>
        ///    Adds an <see cref="IFDEntry"/> to the IFD. If it is already contained
        ///    in the IFD, it is overwritten.
        /// </summary>
        /// <param name="directory">
        ///    A <see cref="System.Int32"/> value with the directory index that
        ///    contains the tag that will be set.
        /// </param>
        /// <param name="entry">
        ///    A <see cref="IFDEntry"/> to add to the IFD.
        /// </param>
        public void SetEntry(int directory, IFDEntry entry)
        {
            if (ContainsTag (directory, entry.Tag))
                RemoveTag (directory, entry.Tag);

            AddEntry (directory, entry);
        }
Beispiel #9
0
 internal static void WriteTaglibTiffDirEntry(ushort key, IFDEntry entry, string indent)
 {
     if (entry is TagLib.IFD.Entries.ShortIFDEntry ifdShort)
     {
         Console.WriteLine("{0}TIFF entry = [{1}] = {2}", indent, ifdShort.Tag, ifdShort.Value);
     }
     else if (entry is TagLib.IFD.Entries.LongIFDEntry ifdLong)
     {
         Console.WriteLine("{0}TIFF entry = [{1}] = {2}", indent, ifdLong.Tag, ifdLong.Value);
     }
     else if (entry is TagLib.IFD.Entries.StringIFDEntry ifdString)
     {
         Console.WriteLine("{0}TIFF entry = [{1}] = \"{2}\"", indent, ifdString.Tag, ifdString.Value);
     }
     else if (entry is TagLib.IFD.Entries.UserCommentIFDEntry ifdUserComment)
     {
         Console.WriteLine("{0}TIFF entry = [{1}] = \"{2}\"", indent, ifdUserComment.Tag, ifdUserComment.Value);
     }
     else if (entry is TagLib.IFD.Entries.RationalIFDEntry ifdRational)
     {
         Console.WriteLine("{0}TIFF entry = [{1}] = {2}/{3}", indent, ifdRational.Tag, ifdRational.Value.Numerator, ifdRational.Value.Denominator);
     }
     else if (entry is TagLib.IFD.Entries.SRationalIFDEntry ifdSRational)
     {
         Console.WriteLine("{0}TIFF entry = [{1}] = {2}/{3}", indent, ifdSRational.Tag, ifdSRational.Value.Numerator, ifdSRational.Value.Denominator);
     }
     else if (entry is TagLib.IFD.Entries.ShortArrayIFDEntry ifdShortArray)
     {
         Console.Write("{0}TIFF entry = [{1}] =", indent, ifdShortArray.Tag);
         foreach (var x in ifdShortArray.Values)
         {
             Console.Write("  {0}", x);
         }
         Console.WriteLine();
     }
     else if (entry is TagLib.IFD.Entries.RationalArrayIFDEntry ifdRationalArray)
     {
         Console.Write("{0}TIFF entry = [{1}] =", indent, ifdRationalArray.Tag);
         foreach (var x in ifdRationalArray.Values)
         {
             Console.Write("  {0}/{1}", x.Numerator, x.Denominator);
         }
         Console.WriteLine();
     }
     else if (entry is TagLib.IFD.Entries.ThumbnailDataIFDEntry ifdThumbnailData)
     {
         Console.WriteLine("{0}TIFF entry = [{1}] has {2} bytes of thumbnail data", indent, ifdThumbnailData.Tag, ifdThumbnailData.Data?.Count);
     }
     else if (entry is TagLib.IFD.Entries.ByteVectorIFDEntry ifdByteVector)
     {
         Console.WriteLine("{0}TIFF entry = [{1}] has {2} bytes of byte vector data", indent, ifdByteVector.Tag, ifdByteVector.Data?.Count);
     }
     else if (entry is TagLib.IFD.Entries.SubIFDEntry ifdSubEntry)
     {
         Console.WriteLine("{0}TIFF entry = [{1}] has {2} subentries in {3} directories", indent, ifdSubEntry.Tag, ifdSubEntry.ChildCount, ifdSubEntry.Count);
         foreach (var dir in ifdSubEntry.Structure.Directories)
         {
             foreach (var subentry in dir)
             {
                 WriteTaglibTiffDirEntry(subentry.Key, subentry.Value, indent + "    ");
             }
         }
     }
     else if (entry is TagLib.IFD.Entries.UndefinedIFDEntry ifdUndefined)
     {
         Console.WriteLine("{0}TIFF entry = [{1}] has {2} bytes of undefined data", indent, ifdUndefined.Tag, ifdUndefined.Data?.Count);
     }
     else
     {
         Console.WriteLine("{0}TIFF entry = [{1}] is {2}", indent, entry.Tag, entry.GetType());
     }
 }
Beispiel #10
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);
        }