public XmpDirectory Extract([NotNull] byte[] xmpBytes, int offset, int length)
        {
            if (offset < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(offset), "Must be zero or greater.");
            }
            if (length < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(length), "Must be zero or greater.");
            }
            if (xmpBytes.Length < offset + length)
            {
                throw new ArgumentException("Extends beyond length of byte array.", nameof(length));
            }

            // Trim any trailing null bytes
            // https://github.com/drewnoakes/metadata-extractor-dotnet/issues/154
            while (xmpBytes[offset + length - 1] == 0)
            {
                length--;
            }

            var directory = new XmpDirectory();

            try
            {
                var xmpMeta = XmpMetaFactory.ParseFromBuffer(xmpBytes, offset, length);
                directory.SetXmpMeta(xmpMeta);
            }
            catch (XmpException e)
            {
                directory.AddError("Error processing XMP data: " + e.Message);
            }
            return(directory);
        }
        public XmpDirectory Extract([NotNull] byte[] xmpBytes, int offset, int length)
        {
            var directory = new XmpDirectory();

            try
            {
                var xmpMeta = XmpMetaFactory.ParseFromBuffer(xmpBytes, offset, length);
                directory.SetXmpMeta(xmpMeta);
            }
            catch (XmpException e)
            {
                directory.AddError("Error processing XMP data: " + e.Message);
            }
            return(directory);
        }
        /// <summary>
        /// Performs the XMP data extraction.
        /// <para />
        /// The extraction is done with Adobe's XMPCore library.
        /// </summary>
        public XmpDirectory Extract([NotNull] byte[] xmpBytes)
        {
            var directory = new XmpDirectory();

            try
            {
                var xmpMeta = XmpMetaFactory.ParseFromBuffer(xmpBytes);
                ProcessXmpTags(directory, xmpMeta);
            }
            catch (XmpException e)
            {
                directory.AddError("Error processing XMP data: " + e.Message);
            }
            return(directory);
        }
        public XmpDirectory Extract([NotNull] byte[] xmpBytes, int offset, int length)
        {
            if (offset < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(offset), "Must be zero or greater.");
            }
            if (length < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(length), "Must be zero or greater.");
            }
            if (xmpBytes.Length < offset + length)
            {
                throw new ArgumentException("Extends beyond length of byte array.", nameof(length));
            }

            // Trim any trailing null bytes
            // https://github.com/drewnoakes/metadata-extractor-dotnet/issues/154
            while (xmpBytes[offset + length - 1] == 0)
            {
                length--;
            }

            var directory = new XmpDirectory();

            try
            {
                // Limit photoshop:DocumentAncestors node as it can reach over 100000 items and make parsing extremely slow.
                // This is not a typical value but it may happen https://forums.adobe.com/thread/2081839
                var parseOptions = new ParseOptions();
                parseOptions.SetXMPNodesToLimit(new Dictionary <string, int>()
                {
                    { "photoshop:DocumentAncestors", 1000 }
                });

                var xmpMeta = XmpMetaFactory.ParseFromBuffer(xmpBytes, offset, length, parseOptions);
                directory.SetXmpMeta(xmpMeta);
            }
            catch (XmpException e)
            {
                directory.AddError("Error processing XMP data: " + e.Message);
            }
            return(directory);
        }
        private static void ProcessXmpTag([NotNull] IXmpMeta meta, [NotNull] XmpDirectory directory, int tagType, FormatType formatCode)
        {
            string schemaNs;
            string propName;

            if (!XmpDirectory.TagSchemaMap.TryGetValue(tagType, out schemaNs) || !XmpDirectory.TagPropNameMap.TryGetValue(tagType, out propName))
            {
                return;
            }

            var property = meta.GetPropertyString(schemaNs, propName);

            if (property == null)
            {
                return;
            }

            switch (formatCode)
            {
            case FormatType.Rational:
            {
                // TODO introduce Rational.TryParse
                var rationalParts = property.Split('/').Take(2).ToArray();
                if (rationalParts.Length == 2)
                {
                    // TODO should this really be parsed as float?
                    float numerator;
                    float denominator;
                    if (float.TryParse(rationalParts[0], out numerator) && float.TryParse(rationalParts[1], out denominator))
                    {
                        directory.Set(tagType, new Rational((long)numerator, (long)denominator));
                    }
                    else
                    {
                        directory.AddError($"Unable to parse XMP property {propName} as a Rational.");
                    }
                }
                else
                {
                    directory.AddError($"Error in rational format for tag {tagType}");
                }
                break;
            }

            case FormatType.Int:
            {
                int value;
                if (int.TryParse(property, out value))
                {
                    directory.Set(tagType, value);
                }
                else
                {
                    directory.AddError($"Unable to parse XMP property {propName} as an int.");
                }
                break;
            }

            case FormatType.Double:
            {
                double value;
                if (double.TryParse(property, out value))
                {
                    directory.Set(tagType, value);
                }
                else
                {
                    directory.AddError($"Unable to parse XMP property {propName} as a double.");
                }
                break;
            }

            case FormatType.String:
            {
                directory.Set(tagType, property);
                break;
            }

            case FormatType.StringArray:
            {
                // XMP iterators are 1-based
                var count = meta.CountArrayItems(schemaNs, propName);
                var array = new string[count];
                for (var i = 1; i <= count; i++)
                {
                    array[i - 1] = meta.GetArrayItem(schemaNs, propName, i).Value;
                }
                directory.Set(tagType, array);
                break;
            }

            default:
            {
                directory.AddError($"Unknown format code {formatCode} for tag {tagType}");
                break;
            }
            }
        }
 /// <summary>
 /// Performs the XMP data extraction.
 /// </summary>
 /// <remarks>
 /// The extraction is done with Adobe's XMPCore library.
 /// </remarks>
 public XmpDirectory Extract([NotNull] byte[] xmpBytes)
 {
     var directory = new XmpDirectory();
     try
     {
         var xmpMeta = XmpMetaFactory.ParseFromBuffer(xmpBytes);
         ProcessXmpTags(directory, xmpMeta);
     }
     catch (XmpException e)
     {
         directory.AddError("Error processing XMP data: " + e.Message);
     }
     return directory;
 }
        /// <summary>Reads an property value with given namespace URI and property name.</summary>
        /// <remarks>Reads an property value with given namespace URI and property name. Add property value to directory if exists</remarks>
        /// <exception cref="XmpException"/>
        private static void ProcessXmpTag([NotNull] IXmpMeta meta, [NotNull] XmpDirectory directory, int tagType, FormatType formatCode)
        {
            string schemaNs;
            string propName;

            if (!XmpDirectory.TagSchemaMap.TryGetValue(tagType, out schemaNs) || !XmpDirectory.TagPropNameMap.TryGetValue(tagType, out propName))
            {
                return;
            }

            var property = meta.GetPropertyString(schemaNs, propName);

            if (property == null)
            {
                return;
            }

            switch (formatCode)
            {
            case FormatType.Rational:
            {
                var rationalParts = property.Split(new[] { '/' }, 2);
                if (rationalParts.Length == 2)
                {
                    try
                    {
                        var rational = new Rational((long)float.Parse(rationalParts[0]), (long)float.Parse(rationalParts[1]));
                        directory.Set(tagType, rational);
                    }
                    catch (FormatException)
                    {
                        directory.AddError($"Unable to parse XMP property {propName} as a Rational.");
                    }
                }
                else
                {
                    directory.AddError("Error in rational format for tag " + tagType);
                }
                break;
            }

            case FormatType.Int:
            {
                try
                {
                    directory.Set(tagType, int.Parse(property));
                }
                catch (FormatException)
                {
                    directory.AddError($"Unable to parse XMP property {propName} as an int.");
                }
                break;
            }

            case FormatType.Double:
            {
                try
                {
                    directory.Set(tagType, double.Parse(property));
                }
                catch (FormatException)
                {
                    directory.AddError($"Unable to parse XMP property {propName} as an double.");
                }
                break;
            }

            case FormatType.String:
            {
                directory.Set(tagType, property);
                break;
            }

            case FormatType.StringArray:
            {
                //XMP iterators are 1-based
                var count = meta.CountArrayItems(schemaNs, propName);
                var array = new string[count];
                for (var i = 1; i <= count; ++i)
                {
                    array[i - 1] = meta.GetArrayItem(schemaNs, propName, i).Value;
                }
                directory.Set(tagType, array);
                break;
            }

            default:
            {
                directory.AddError($"Unknown format code {formatCode} for tag {tagType}");
                break;
            }
            }
        }