예제 #1
0
        /// <summary>Visit all schemas to do general fixes and handle special cases.</summary>
        /// <param name="xmp">the metadata object implementation</param>
        /// <exception cref="XmpException">Thrown if the normalisation fails.</exception>
        private static void TouchUpDataModel(XmpMeta xmp)
        {
            // make sure the DC schema is existing, because it might be needed within the normalization
            // if not touched it will be removed by removeEmptySchemas
            XmpNodeUtils.FindSchemaNode(xmp.GetRoot(), XmpConstants.NsDC, true);

            // Do the special case fixes within each schema.
            for (var it = xmp.GetRoot().IterateChildren(); it.HasNext();)
            {
                var currSchema = (XmpNode)it.Next();

                switch (currSchema.Name)
                {
                case XmpConstants.NsDC:
                {
                    NormalizeDcArrays(currSchema);
                    break;
                }

                case XmpConstants.NsExif:
                {
                    // Do a special case fix for exif:GPSTimeStamp.
                    FixGpsTimeStamp(currSchema);
                    var arrayNode = XmpNodeUtils.FindChildNode(currSchema, "exif:UserComment", false);
                    if (arrayNode != null)
                    {
                        RepairAltText(arrayNode);
                    }
                    break;
                }

                case XmpConstants.NsDm:
                {
                    // Do a special case migration of xmpDM:copyright to
                    // dc:rights['x-default'].
                    var dmCopyright = XmpNodeUtils.FindChildNode(currSchema, "xmpDM:copyright", false);
                    if (dmCopyright != null)
                    {
                        MigrateAudioCopyright(xmp, dmCopyright);
                    }
                    break;
                }

                case XmpConstants.NsXmpRights:
                {
                    var arrayNode = XmpNodeUtils.FindChildNode(currSchema, "xmpRights:UsageTerms", false);
                    if (arrayNode != null)
                    {
                        RepairAltText(arrayNode);
                    }
                    break;
                }
                }
            }
        }
예제 #2
0
        /// <summary>Constructor with optional initial values.</summary>
        /// <remarks>If <c>propName</c> is provided, <c>schemaNS</c> has also be provided.</remarks>
        /// <param name="xmp">the iterated metadata object.</param>
        /// <param name="schemaNs">the iteration is reduced to this schema (optional)</param>
        /// <param name="propPath">the iteration is reduced to this property within the <c>schemaNS</c></param>
        /// <param name="options">advanced iteration options, see <see cref="IteratorOptions"/></param>
        /// <exception cref="XmpException">If the node defined by the parameters is not existing.</exception>
        public XmpIterator(XmpMeta xmp, string schemaNs, string propPath, IteratorOptions options)
        {
            // make sure that options is defined at least with defaults
            Options = options ?? new IteratorOptions();
            // the start node of the iteration depending on the schema and property filter
            XmpNode startNode    = null;
            string  initialPath  = null;
            var     baseSchema   = !string.IsNullOrEmpty(schemaNs);
            var     baseProperty = !string.IsNullOrEmpty(propPath);

            if (!baseSchema && !baseProperty)
            {
                // complete tree will be iterated
                startNode = xmp.GetRoot();
            }
            else
            {
                if (baseSchema && baseProperty)
                {
                    // Schema and property node provided
                    var path = XmpPathParser.ExpandXPath(schemaNs, propPath);
                    // base path is the prop path without the property leaf
                    var basePath = new XmpPath();
                    for (var i = 0; i < path.Size() - 1; i++)
                    {
                        basePath.Add(path.GetSegment(i));
                    }
                    startNode     = XmpNodeUtils.FindNode(xmp.GetRoot(), path, false, null);
                    BaseNamespace = schemaNs;
                    initialPath   = basePath.ToString();
                }
                else
                {
                    if (baseSchema && !baseProperty)
                    {
                        // Only Schema provided
                        startNode = XmpNodeUtils.FindSchemaNode(xmp.GetRoot(), schemaNs, false);
                    }
                    else
                    {
                        // !baseSchema  &&  baseProperty
                        // No schema but property provided -> error
                        throw new XmpException("Schema namespace URI is required", XmpErrorCode.BadSchema);
                    }
                }
            }
            // create iterator
            _nodeIterator = startNode != null
                ? (IIterator)(!Options.IsJustChildren
                    ? new NodeIterator(this, startNode, initialPath, 1)
                    : new NodeIteratorChildren(this, startNode, initialPath))
                : Enumerable.Empty <object>().Iterator();
        }
예제 #3
0
 /// <summary>Constructor with optional initial values.</summary>
 /// <remarks>If <c>propName</c> is provided, <c>schemaNS</c> has also be provided.</remarks>
 /// <param name="xmp">the iterated metadata object.</param>
 /// <param name="schemaNs">the iteration is reduced to this schema (optional)</param>
 /// <param name="propPath">the iteration is reduced to this property within the <c>schemaNS</c></param>
 /// <param name="options">advanced iteration options, see <see cref="IteratorOptions"/></param>
 /// <exception cref="XmpException">If the node defined by the parameters is not existing.</exception>
 public XmpIterator(XmpMeta xmp, string schemaNs, string propPath, IteratorOptions options)
 {
     // make sure that options is defined at least with defaults
     Options = options ?? new IteratorOptions();
     // the start node of the iteration depending on the schema and property filter
     XmpNode startNode = null;
     string initialPath = null;
     var baseSchema = !string.IsNullOrEmpty(schemaNs);
     var baseProperty = !string.IsNullOrEmpty(propPath);
     if (!baseSchema && !baseProperty)
     {
         // complete tree will be iterated
         startNode = xmp.GetRoot();
     }
     else
     {
         if (baseSchema && baseProperty)
         {
             // Schema and property node provided
             var path = XmpPathParser.ExpandXPath(schemaNs, propPath);
             // base path is the prop path without the property leaf
             var basePath = new XmpPath();
             for (var i = 0; i < path.Size() - 1; i++)
             {
                 basePath.Add(path.GetSegment(i));
             }
             startNode = XmpNodeUtils.FindNode(xmp.GetRoot(), path, false, null);
             BaseNamespace = schemaNs;
             initialPath = basePath.ToString();
         }
         else
         {
             if (baseSchema && !baseProperty)
             {
                 // Only Schema provided
                 startNode = XmpNodeUtils.FindSchemaNode(xmp.GetRoot(), schemaNs, false);
             }
             else
             {
                 // !baseSchema  &&  baseProperty
                 // No schema but property provided -> error
                 throw new XmpException("Schema namespace URI is required", XmpErrorCode.BadSchema);
             }
         }
     }
     // create iterator
     _nodeIterator = startNode != null
         ? (IIterator)(!Options.IsJustChildren
             ? new NodeIterator(this, startNode, initialPath, 1)
             : new NodeIteratorChildren(this, startNode, initialPath))
         : Enumerable.Empty<object>().Iterator();
 }
예제 #4
0
 /// <summary>Normalizes a raw parsed XMPMeta-Object</summary>
 /// <param name="xmp">the raw metadata object</param>
 /// <param name="options">the parsing options</param>
 /// <returns>Returns the normalized metadata object</returns>
 /// <exception cref="XmpException">Collects all severe processing errors.</exception>
 internal static IXmpMeta Process(XmpMeta xmp, ParseOptions options)
 {
     var tree = xmp.GetRoot();
     TouchUpDataModel(xmp);
     MoveExplicitAliases(tree, options);
     TweakOldXmp(tree);
     DeleteEmptySchemas(tree);
     return xmp;
 }
예제 #5
0
        /// <summary>Normalizes a raw parsed XMPMeta-Object</summary>
        /// <param name="xmp">the raw metadata object</param>
        /// <param name="options">the parsing options</param>
        /// <returns>Returns the normalized metadata object</returns>
        /// <exception cref="XmpException">Collects all severe processing errors.</exception>
        internal static IXmpMeta Process(XmpMeta xmp, ParseOptions options)
        {
            var tree = xmp.GetRoot();

            TouchUpDataModel(xmp);
            MoveExplicitAliases(tree, options);
            TweakOldXmp(tree);
            DeleteEmptySchemas(tree);
            return(xmp);
        }
예제 #6
0
        /// <summary>Utility to find or create the array used by <c>separateArrayItems()</c>.</summary>
        /// <param name="schemaNs">a the namespace fo the array</param>
        /// <param name="arrayName">the name of the array</param>
        /// <param name="arrayOptions">the options for the array if newly created</param>
        /// <param name="xmp">the xmp object</param>
        /// <returns>Returns the array node.</returns>
        /// <exception cref="XmpException">Forwards exceptions</exception>
        private static XmpNode SeparateFindCreateArray(string schemaNs, string arrayName, PropertyOptions arrayOptions, XmpMeta xmp)
        {
            arrayOptions = XmpNodeUtils.VerifySetOptions(arrayOptions, null);

            if (!arrayOptions.IsOnlyArrayOptions)
            {
                throw new XmpException("Options can only provide array form", XmpErrorCode.BadOptions);
            }

            // Find the array node, make sure it is OK. Move the current children
            // aside, to be readded later if kept.
            var arrayPath = XmpPathParser.ExpandXPath(schemaNs, arrayName);
            var arrayNode = XmpNodeUtils.FindNode(xmp.GetRoot(), arrayPath, false, null);

            if (arrayNode != null)
            {
                // The array exists, make sure the form is compatible. Zero
                // arrayForm means take what exists.
                var arrayForm = arrayNode.Options;

                if (!arrayForm.IsArray || arrayForm.IsArrayAlternate)
                {
                    throw new XmpException("Named property must be non-alternate array", XmpErrorCode.BadXPath);
                }
                if (arrayOptions.EqualArrayTypes(arrayForm))
                {
                    throw new XmpException("Mismatch of specified and existing array form", XmpErrorCode.BadXPath);
                }
            }
            else
            {
                // *** Right error?
                // The array does not exist, try to create it.
                // don't modify the options handed into the method
                arrayOptions.IsArray = true;
                arrayNode            = XmpNodeUtils.FindNode(xmp.GetRoot(), arrayPath, true, arrayOptions);
                if (arrayNode == null)
                {
                    throw new XmpException("Failed to create named array", XmpErrorCode.BadXPath);
                }
            }
            return(arrayNode);
        }
예제 #7
0
        /// <summary>Normalizes a raw parsed XMPMeta-Object</summary>
        /// <param name="xmp">the raw metadata object</param>
        /// <param name="options">the parsing options</param>
        /// <returns>Returns the normalized metadata object</returns>
        /// <exception cref="XmpException">Collects all severe processing errors.</exception>
        internal static IXmpMeta Process(XmpMeta xmp, ParseOptions options)
        {
            var tree = xmp.GetRoot();

            TouchUpDataModel(xmp);

            // FfF: collect the aliases to prevent browsing the tree again

            MoveExplicitAliases(tree, options);
            TweakOldXmp(tree);
            DeleteEmptySchemas(tree);
            return(xmp);
        }
예제 #8
0
 /// <summary>Serializes the metadata in pretty-printed manner.</summary>
 /// <param name="level">indent level</param>
 /// <exception cref="System.IO.IOException">Forwarded writer exceptions</exception>
 /// <exception cref="XmpException"></exception>
 private void SerializeCanonicalRdfSchemas(int level)
 {
     if (_xmp.GetRoot().GetChildrenLength() > 0)
     {
         StartOuterRdfDescription(_xmp.GetRoot(), level);
         for (var it = _xmp.GetRoot().IterateChildren(); it.HasNext();)
         {
             var currSchema = (XmpNode)it.Next();
             SerializeCanonicalRdfSchema(currSchema, level);
         }
         EndOuterRdfDescription(level);
     }
     else
     {
         WriteIndent(level + 1);
         Write(RdfSchemaStart);
         // Special case an empty XMP object.
         WriteTreeName();
         Write("/>");
         WriteNewline();
     }
 }
예제 #9
0
 /// <summary>Visit all schemas to do general fixes and handle special cases.</summary>
 /// <param name="xmp">the metadata object implementation</param>
 /// <exception cref="XmpException">Thrown if the normalisation fails.</exception>
 private static void TouchUpDataModel(XmpMeta xmp)
 {
     // make sure the DC schema is existing, because it might be needed within the normalization
     // if not touched it will be removed by removeEmptySchemas
     XmpNodeUtils.FindSchemaNode(xmp.GetRoot(), XmpConstants.NsDC, true);
     // Do the special case fixes within each schema.
     for (var it = xmp.GetRoot().IterateChildren(); it.HasNext(); )
     {
         var currSchema = (XmpNode)it.Next();
         if (XmpConstants.NsDC.Equals(currSchema.Name))
         {
             NormalizeDcArrays(currSchema);
         }
         else
         {
             if (XmpConstants.NsExif.Equals(currSchema.Name))
             {
                 // Do a special case fix for exif:GPSTimeStamp.
                 FixGpsTimeStamp(currSchema);
                 var arrayNode = XmpNodeUtils.FindChildNode(currSchema, "exif:UserComment", false);
                 if (arrayNode != null)
                 {
                     RepairAltText(arrayNode);
                 }
             }
             else
             {
                 if (XmpConstants.NsDm.Equals(currSchema.Name))
                 {
                     // Do a special case migration of xmpDM:copyright to
                     // dc:rights['x-default'].
                     var dmCopyright = XmpNodeUtils.FindChildNode(currSchema, "xmpDM:copyright", false);
                     if (dmCopyright != null)
                     {
                         MigrateAudioCopyright(xmp, dmCopyright);
                     }
                 }
                 else
                 {
                     if (XmpConstants.NsXmpRights.Equals(currSchema.Name))
                     {
                         var arrayNode = XmpNodeUtils.FindChildNode(currSchema, "xmpRights:UsageTerms", false);
                         if (arrayNode != null)
                         {
                             RepairAltText(arrayNode);
                         }
                     }
                 }
             }
         }
     }
 }
예제 #10
0
        /// <summary>Visit all schemas to do general fixes and handle special cases.</summary>
        /// <param name="xmp">the metadata object implementation</param>
        /// <exception cref="XmpException">Thrown if the normalisation fails.</exception>
        private static void TouchUpDataModel(XmpMeta xmp)
        {
            // make sure the DC schema is existing, because it might be needed within the normalization
            // if not touched it will be removed by removeEmptySchemas
            XmpNodeUtils.FindSchemaNode(xmp.GetRoot(), XmpConstants.NsDC, true);

            // Do the special case fixes within each schema.
            for (var it = xmp.GetRoot().IterateChildren(); it.HasNext();)
            {
                var currSchema = (XmpNode)it.Next();

                switch (currSchema.Name)
                {
                case XmpConstants.NsDC:
                {
                    NormalizeDcArrays(currSchema);
                    break;
                }

                case XmpConstants.NsExif:
                {
                    // Do a special case fix for exif:GPSTimeStamp.
                    FixGpsTimeStamp(currSchema);

                    /*var arrayNode = XmpNodeUtils.FindChildNode(currSchema, "exif:UserComment", false);
                     * if (arrayNode != null)
                     * {
                     *  RepairAltText(arrayNode);
                     * }*/
                    var userComment = XmpNodeUtils.FindChildNode(currSchema, "exif:UserComment", false);
                    if (userComment != null)
                    {
                        if (userComment.Options.IsSimple)
                        {
                            XmpNode newNode = new XmpNode(XmpConstants.ArrayItemName, userComment.Value, userComment.Options);
                            newNode.Parent = userComment;

                            int QualNo = userComment.GetQualifierLength();
                            while (QualNo > 0)
                            {
                                newNode.AddQualifier(userComment.GetQualifier(userComment.GetQualifierLength() - QualNo));
                                --QualNo;
                            }

                            userComment.RemoveQualifiers();
                            if (!newNode.Options.HasLanguage)
                            {
                                var po = new PropertyOptions();
                                po.SetOption(PropertyOptions.HasQualifiersFlag, true);
                                XmpNode langQual = new XmpNode("xml:lang", "x-default", po);
                                newNode.AddQualifier(langQual);
                                newNode.Options.SetOption(PropertyOptions.HasQualifiersFlag, true);
                                newNode.Options.SetOption(PropertyOptions.HasLanguageFlag, true);
                            }
                            userComment.AddChild(newNode);
                            userComment.Options = new PropertyOptions(PropertyOptions.ArrayFlag | PropertyOptions.ArrayOrderedFlag
                                                                      | PropertyOptions.ArrayAltTextFlag | PropertyOptions.ArrayAlternateFlag);
                            userComment.Value = "";
                        }
                        RepairAltText(userComment);
                    }

                    break;
                }

                case XmpConstants.NsDm:
                {
                    // Do a special case migration of xmpDM:copyright to
                    // dc:rights['x-default'].
                    var dmCopyright = XmpNodeUtils.FindChildNode(currSchema, "xmpDM:copyright", false);
                    if (dmCopyright != null)
                    {
                        MigrateAudioCopyright(xmp, dmCopyright);
                    }
                    break;
                }

                case XmpConstants.NsXmpRights:
                {
                    var arrayNode = XmpNodeUtils.FindChildNode(currSchema, "xmpRights:UsageTerms", false);
                    if (arrayNode != null)
                    {
                        RepairAltText(arrayNode);
                    }
                    break;
                }
                }
            }
        }
예제 #11
0
        /// <summary>Utility to find or create the array used by <c>separateArrayItems()</c>.</summary>
        /// <param name="schemaNs">a the namespace fo the array</param>
        /// <param name="arrayName">the name of the array</param>
        /// <param name="arrayOptions">the options for the array if newly created</param>
        /// <param name="xmp">the xmp object</param>
        /// <returns>Returns the array node.</returns>
        /// <exception cref="XmpException">Forwards exceptions</exception>
        private static XmpNode SeparateFindCreateArray(string schemaNs, string arrayName, PropertyOptions arrayOptions, XmpMeta xmp)
        {
            arrayOptions = XmpNodeUtils.VerifySetOptions(arrayOptions, null);

            if (!arrayOptions.IsOnlyArrayOptions)
                throw new XmpException("Options can only provide array form", XmpErrorCode.BadOptions);

            // Find the array node, make sure it is OK. Move the current children
            // aside, to be readded later if kept.
            var arrayPath = XmpPathParser.ExpandXPath(schemaNs, arrayName);
            var arrayNode = XmpNodeUtils.FindNode(xmp.GetRoot(), arrayPath, false, null);
            if (arrayNode != null)
            {
                // The array exists, make sure the form is compatible. Zero
                // arrayForm means take what exists.
                var arrayForm = arrayNode.Options;

                if (!arrayForm.IsArray || arrayForm.IsArrayAlternate)
                    throw new XmpException("Named property must be non-alternate array", XmpErrorCode.BadXPath);
                if (arrayOptions.EqualArrayTypes(arrayForm))
                    throw new XmpException("Mismatch of specified and existing array form", XmpErrorCode.BadXPath);
            }
            else
            {
                // *** Right error?
                // The array does not exist, try to create it.
                // don't modify the options handed into the method
                arrayOptions.IsArray = true;
                arrayNode = XmpNodeUtils.FindNode(xmp.GetRoot(), arrayPath, true, arrayOptions);
                if (arrayNode == null)
                    throw new XmpException("Failed to create named array", XmpErrorCode.BadXPath);
            }
            return arrayNode;
        }
예제 #12
0
 /// <summary>
 /// Each of these parsing methods is responsible for recognizing an RDF
 /// syntax production and adding the appropriate structure to the XMP tree.
 /// </summary>
 /// <remarks>
 /// Each of these parsing methods is responsible for recognizing an RDF
 /// syntax production and adding the appropriate structure to the XMP tree.
 /// They simply return for success, failures will throw an exception.
 /// </remarks>
 /// <param name="xmp">the xmp metadata object that is generated</param>
 /// <param name="rdfRdfNode">the top-level xml node</param>
 /// <exception cref="XmpException">thrown on parsing errors</exception>
 internal static void Rdf_RDF(XmpMeta xmp, XElement rdfRdfNode)
 {
     if (rdfRdfNode.Attributes().Count() > 0)
     {
         Rdf_NodeElementList(xmp, xmp.GetRoot(), rdfRdfNode);
     }
     else
     {
         throw new XmpException("Invalid attributes of rdf:RDF element", XmpErrorCode.BadRdf);
     }
 }
예제 #13
0
 private static XmpNode AddChildNode(XmpMeta xmp, XmpNode xmpParent, XName nodeName, string nodeNamespacePrefix, string value, bool isTopLevel)
 {
     var registry = XmpMetaFactory.SchemaRegistry;
     var ns = nodeName.NamespaceName;
     string childName;
     if (ns != string.Empty)
     {
         if (XmpConstants.NsDcDeprecated.Equals(ns))
         {
             // Fix a legacy DC namespace
             ns = XmpConstants.NsDC;
         }
         var prefix = registry.GetNamespacePrefix(ns);
         if (prefix == null)
         {
             prefix = nodeNamespacePrefix ?? DefaultPrefix;
             prefix = registry.RegisterNamespace(ns, prefix);
         }
         childName = prefix + nodeName.LocalName;
     }
     else
     {
         throw new XmpException("XML namespace required for all elements and attributes", XmpErrorCode.BadRdf);
     }
     // create schema node if not already there
     var childOptions = new PropertyOptions();
     var isAlias = false;
     if (isTopLevel)
     {
         // Lookup the schema node, adjust the XMP parent pointer.
         // Incoming parent must be the tree root.
         var schemaNode = XmpNodeUtils.FindSchemaNode(xmp.GetRoot(), ns, DefaultPrefix, true);
         schemaNode.IsImplicit = false;
         // Clear the implicit node bit.
         // need runtime check for proper 32 bit code.
         xmpParent = schemaNode;
         // If this is an alias set the alias flag in the node
         // and the hasAliases flag in the tree.
         if (registry.FindAlias(childName) != null)
         {
             isAlias = true;
             xmp.GetRoot().HasAliases = true;
             schemaNode.HasAliases = true;
         }
     }
     // Make sure that this is not a duplicate of a named node.
     var isArrayItem = "rdf:li".Equals(childName);
     var isValueNode = "rdf:value".Equals(childName);
     // Create XMP node and so some checks
     var newChild = new XmpNode(childName, value, childOptions) { IsAlias = isAlias };
     // Add the new child to the XMP parent node, a value node first.
     if (!isValueNode)
     {
         xmpParent.AddChild(newChild);
     }
     else
     {
         xmpParent.AddChild(1, newChild);
     }
     if (isValueNode)
     {
         if (isTopLevel || !xmpParent.Options.IsStruct)
         {
             throw new XmpException("Misplaced rdf:value element", XmpErrorCode.BadRdf);
         }
         xmpParent.HasValueChild = true;
     }
     if (isArrayItem)
     {
         if (!xmpParent.Options.IsArray)
         {
             throw new XmpException("Misplaced rdf:li element", XmpErrorCode.BadRdf);
         }
         newChild.Name = XmpConstants.ArrayItemName;
     }
     return newChild;
 }