예제 #1
0
 /// <summary>Make sure the x-default item is first.</summary>
 /// <remarks>
 /// Make sure the x-default item is first. Touch up &quot;single value&quot;
 /// arrays that have a default plus one real language. This case should have
 /// the same value for both items. Older Adobe apps were hardwired to only
 /// use the &quot;x-default&quot; item, so we copy that value to the other
 /// item.
 /// </remarks>
 /// <param name="arrayNode">an alt text array node</param>
 internal static void NormalizeLangArray(XmpNode arrayNode)
 {
     if (!arrayNode.Options.IsArrayAltText)
     {
         return;
     }
     // check if node with x-default qual is first place
     for (var i = 2; i <= arrayNode.GetChildrenLength(); i++)
     {
         var child = arrayNode.GetChild(i);
         if (child.HasQualifier && XmpConstants.XDefault.Equals(child.GetQualifier(1).Value))
         {
             // move node to first place
             try
             {
                 arrayNode.RemoveChild(i);
                 arrayNode.AddChild(1, child);
             }
             catch (XmpException)
             {
                 // cannot occur, because same child is removed before
                 Debug.Assert(false);
             }
             if (i == 2)
             {
                 arrayNode.GetChild(2).Value = child.Value;
             }
             break;
         }
     }
 }
예제 #2
0
        /// <summary>
        /// Searches for a field selector in a node:
        /// [fieldName="value] - an element in an array of structs, chosen by a field value.
        /// </summary>
        /// <remarks>
        /// Searches for a field selector in a node:
        /// [fieldName="value] - an element in an array of structs, chosen by a field value.
        /// No implicit nodes are created by field selectors.
        /// </remarks>
        /// <param name="arrayNode"/>
        /// <param name="fieldName"/>
        /// <param name="fieldValue"/>
        /// <returns>Returns the index of the field if found, otherwise -1.</returns>
        /// <exception cref="XmpException"></exception>
        private static int LookupFieldSelector(XmpNode arrayNode, string fieldName, string fieldValue)
        {
            var result = -1;

            for (var index = 1; index <= arrayNode.GetChildrenLength() && result < 0; index++)
            {
                var currItem = arrayNode.GetChild(index);

                if (!currItem.Options.IsStruct)
                {
                    throw new XmpException("Field selector must be used on array of struct", XmpErrorCode.BadXPath);
                }

                for (var f = 1; f <= currItem.GetChildrenLength(); f++)
                {
                    var currField = currItem.GetChild(f);

                    if (currField.Name != fieldName ||
                        currField.Value != fieldValue)
                    {
                        continue;
                    }

                    result = index;
                    break;
                }
            }

            return(result);
        }
예제 #3
0
 /// <summary>
 /// Searches for a qualifier selector in a node:
 /// [?qualName="value"] - an element in an array, chosen by a qualifier value.
 /// </summary>
 /// <remarks>
 /// Searches for a qualifier selector in a node:
 /// [?qualName="value"] - an element in an array, chosen by a qualifier value.
 /// No implicit nodes are created for qualifier selectors,
 /// except for an alias to an x-default item.
 /// </remarks>
 /// <param name="arrayNode">an array node</param>
 /// <param name="qualName">the qualifier name</param>
 /// <param name="qualValue">the qualifier value</param>
 /// <param name="aliasForm">
 /// in case the qual selector results from an alias,
 /// an x-default node is created if there has not been one.
 /// </param>
 /// <returns>Returns the index of th</returns>
 /// <exception cref="XmpException"></exception>
 private static int LookupQualSelector(XmpNode arrayNode, string qualName, string qualValue, int aliasForm)
 {
     if (XmpConstants.XmlLang.Equals(qualName))
     {
         qualValue = Utils.NormalizeLangValue(qualValue);
         var index = LookupLanguageItem(arrayNode, qualValue);
         if (index < 0 && (aliasForm & AliasOptions.PropArrayAltText) > 0)
         {
             var langNode = new XmpNode(XmpConstants.ArrayItemName, null);
             var xdefault = new XmpNode(XmpConstants.XmlLang, XmpConstants.XDefault, null);
             langNode.AddQualifier(xdefault);
             arrayNode.AddChild(1, langNode);
             return(1);
         }
         return(index);
     }
     for (var index = 1; index < arrayNode.GetChildrenLength(); index++)
     {
         var currItem = arrayNode.GetChild(index);
         for (var it = currItem.IterateQualifier(); it.HasNext();)
         {
             var qualifier = (XmpNode)it.Next();
             if (qualName.Equals(qualifier.Name) && qualValue.Equals(qualifier.Value))
             {
                 return(index);
             }
         }
     }
     return(-1);
 }
예제 #4
0
        /// <summary>
        /// After processing by ExpandXPath, a step can be of these forms:
        /// </summary>
        /// <remarks>
        /// After processing by ExpandXPath, a step can be of these forms:
        /// <list type="bullet">
        /// <item>qualName - A top level property or struct field.</item>
        /// <item>[index] - An element of an array.</item>
        /// <item>[last()] - The last element of an array.</item>
        /// <item>[qualName="value"] - An element in an array of structs, chosen by a field value.</item>
        /// <item>[?qualName="value"] - An element in an array, chosen by a qualifier value.</item>
        /// <item>?qualName - A general qualifier.</item>
        /// </list>
        /// Find the appropriate child node, resolving aliases, and optionally creating nodes.
        /// </remarks>
        /// <param name="parentNode">the node to start to start from</param>
        /// <param name="nextStep">the xpath segment</param>
        /// <param name="createNodes"></param>
        /// <returns>returns the found or created XMPPath node</returns>
        /// <exception cref="XmpException"></exception>
        private static XmpNode FollowXPathStep(XmpNode parentNode, XmpPathSegment nextStep, bool createNodes)
        {
            XmpNode nextNode = null;
            var     stepKind = nextStep.Kind;

            switch (stepKind)
            {
            case XmpPathStepType.StructFieldStep:
                nextNode = FindChildNode(parentNode, nextStep.Name, createNodes);
                break;

            case XmpPathStepType.QualifierStep:
                nextNode = FindQualifierNode(parentNode, nextStep.Name.Substring(1), createNodes);
                break;

            default:
                // This is an array indexing step. First get the index, then get the node.
                if (!parentNode.Options.IsArray)
                {
                    throw new XmpException("Indexing applied to non-array", XmpErrorCode.BadXPath);
                }

                int index;
                switch (stepKind)
                {
                case XmpPathStepType.ArrayIndexStep:
                    index = FindIndexedItem(parentNode, nextStep.Name, createNodes);
                    break;

                case XmpPathStepType.ArrayLastStep:
                    index = parentNode.GetChildrenLength();
                    break;

                case XmpPathStepType.FieldSelectorStep:
                    Utils.SplitNameAndValue(nextStep.Name, out string fieldName, out string fieldValue);
                    index = LookupFieldSelector(parentNode, fieldName, fieldValue);
                    break;

                case XmpPathStepType.QualSelectorStep:
                    Utils.SplitNameAndValue(nextStep.Name, out string qualName, out string qualValue);
                    index = LookupQualSelector(parentNode, qualName, qualValue, nextStep.AliasForm);
                    break;

                default:
                    throw new XmpException("Unknown array indexing step in FollowXPathStep", XmpErrorCode.InternalFailure);
                }

                if (1 <= index && index <= parentNode.GetChildrenLength())
                {
                    nextNode = parentNode.GetChild(index);
                }
                break;
            }

            return(nextNode);
        }
예제 #5
0
 /// <summary>Looks for the appropriate language item in a text alternative array.item</summary>
 /// <param name="arrayNode">an array node</param>
 /// <param name="language">the requested language</param>
 /// <returns>Returns the index if the language has been found, -1 otherwise.</returns>
 /// <exception cref="XmpException"/>
 internal static int LookupLanguageItem(XmpNode arrayNode, string language)
 {
     if (!arrayNode.Options.IsArray)
     {
         throw new XmpException("Language item must be used on array", XmpErrorCode.BadXPath);
     }
     for (var index = 1; index <= arrayNode.GetChildrenLength(); index++)
     {
         var child = arrayNode.GetChild(index);
         if (!child.HasQualifier || !XmpConstants.XmlLang.Equals(child.GetQualifier(1).Name))
         {
             continue;
         }
         if (language.Equals(child.GetQualifier(1).Value))
         {
             return(index);
         }
     }
     return(-1);
 }
예제 #6
0
 /// <summary>
 /// Undo the denormalization performed by the XMP used in Acrobat 5.<br />
 /// If a Dublin Core array had only one item, it was serialized as a simple
 /// property.
 /// </summary>
 /// <remarks>
 /// Undo the denormalization performed by the XMP used in Acrobat 5.<br />
 /// If a Dublin Core array had only one item, it was serialized as a simple
 /// property. <br />
 /// The <c>xml:lang</c> attribute was dropped from an
 /// <c>alt-text</c> item if the language was <c>x-default</c>.
 /// </remarks>
 /// <param name="dcSchema">the DC schema node</param>
 /// <exception cref="XmpException">Thrown if normalization fails</exception>
 private static void NormalizeDcArrays(XmpNode dcSchema)
 {
     for (var i = 1; i <= dcSchema.GetChildrenLength(); i++)
     {
         var currProp  = dcSchema.GetChild(i);
         var arrayForm = (PropertyOptions)_dcArrayForms[currProp.Name];
         if (arrayForm == null)
         {
             continue;
         }
         if (currProp.Options.IsSimple)
         {
             // create a new array and add the current property as child,
             // if it was formerly simple
             var newArray = new XmpNode(currProp.Name, arrayForm);
             currProp.Name = XmpConstants.ArrayItemName;
             newArray.AddChild(currProp);
             dcSchema.ReplaceChild(i, newArray);
             // fix language alternatives
             if (arrayForm.IsArrayAltText && !currProp.Options.HasLanguage)
             {
                 var newLang = new XmpNode(XmpConstants.XmlLang, XmpConstants.XDefault, null);
                 currProp.AddQualifier(newLang);
             }
         }
         else
         {
             // clear array options and add corrected array form if it has been an array before
             currProp.Options.SetOption(PropertyOptions.ArrayFlag | PropertyOptions.ArrayOrderedFlag | PropertyOptions.ArrayAlternateFlag | PropertyOptions.ArrayAltTextFlag, false);
             currProp.Options.MergeWith(arrayForm);
             if (arrayForm.IsArrayAltText)
             {
                 // applying for "dc:description", "dc:rights", "dc:title"
                 RepairAltText(currProp);
             }
         }
     }
 }
예제 #7
0
        /// <summary>
        /// </summary>
        /// <remarks>
        /// <list>
        /// <item>Look for an exact match with the specific language.</item>
        /// <item>If a generic language is given, look for partial matches.</item>
        /// <item>Look for an "x-default"-item.</item>
        /// <item>Choose the first item.</item>
        /// </list>
        /// </remarks>
        /// <param name="arrayNode">the alt text array node</param>
        /// <param name="genericLang">the generic language</param>
        /// <param name="specificLang">the specific language</param>
        /// <returns>
        /// Returns the kind of match as an Integer and the found node in an
        /// array.
        /// </returns>
        /// <exception cref="XmpException"/>
        internal static object[] ChooseLocalizedText(XmpNode arrayNode, string genericLang, string specificLang)
        {
            // See if the array has the right form. Allow empty alt arrays,
            // that is what parsing returns.
            if (!arrayNode.Options.IsArrayAltText)
            {
                throw new XmpException("Localized text array is not alt-text", XmpErrorCode.BadXPath);
            }

            if (!arrayNode.HasChildren)
            {
                return new object[] { CltNoValues, null }
            }
            ;

            var     foundGenericMatches = 0;
            XmpNode resultNode          = null;
            XmpNode xDefault            = null;

            // Look for the first partial match with the generic language.
            for (var it = arrayNode.IterateChildren(); it.HasNext();)
            {
                var currItem = (XmpNode)it.Next();

                // perform some checks on the current item
                if (currItem.Options.IsCompositeProperty)
                {
                    throw new XmpException("Alt-text array item is not simple", XmpErrorCode.BadXPath);
                }

                if (!currItem.HasQualifier || currItem.GetQualifier(1).Name != XmpConstants.XmlLang)
                {
                    throw new XmpException("Alt-text array item has no language qualifier", XmpErrorCode.BadXPath);
                }

                var currLang = currItem.GetQualifier(1).Value;

                // Look for an exact match with the specific language.
                if (currLang == specificLang)
                {
                    return new object[] { CltSpecificMatch, currItem }
                }
                ;

                if (genericLang != null && currLang.StartsWith(genericLang))
                {
                    if (resultNode == null)
                    {
                        resultNode = currItem;
                    }

                    // ! Don't return/break, need to look for other matches.
                    foundGenericMatches++;
                }
                else if (currLang == XmpConstants.XDefault)
                {
                    xDefault = currItem;
                }
            }

            // evaluate loop
            if (foundGenericMatches == 1)
            {
                return new object[] { CltSingleGeneric, resultNode }
            }
            ;

            if (foundGenericMatches > 1)
            {
                return new object[] { CltMultipleGeneric, resultNode }
            }
            ;

            if (xDefault != null)
            {
                return new object[] { CltXDefault, xDefault }
            }
            ;

            // Everything failed, choose the first item.
            return(new object[] { CltFirstItem, arrayNode.GetChild(1) });
        }
예제 #8
0
        /// <summary>
        /// After processing by ExpandXPath, a step can be of these forms:
        /// </summary>
        /// <remarks>
        /// After processing by ExpandXPath, a step can be of these forms:
        /// <list type="bullet">
        /// <item>qualName - A top level property or struct field.</item>
        /// <item>[index] - An element of an array.</item>
        /// <item>[last()] - The last element of an array.</item>
        /// <item>[qualName="value"] - An element in an array of structs, chosen by a field value.</item>
        /// <item>[?qualName="value"] - An element in an array, chosen by a qualifier value.</item>
        /// <item>?qualName - A general qualifier.</item>
        /// </list>
        /// Find the appropriate child node, resolving aliases, and optionally creating nodes.
        /// </remarks>
        /// <param name="parentNode">the node to start to start from</param>
        /// <param name="nextStep">the xpath segment</param>
        /// <param name="createNodes"></param>
        /// <returns>returns the found or created XMPPath node</returns>
        /// <exception cref="XmpException"></exception>
        private static XmpNode FollowXPathStep(XmpNode parentNode, XmpPathSegment nextStep, bool createNodes)
        {
            XmpNode nextNode = null;
            var     stepKind = nextStep.Kind;

            if (stepKind == XmpPath.StructFieldStep)
            {
                nextNode = FindChildNode(parentNode, nextStep.Name, createNodes);
            }
            else
            {
                if (stepKind == XmpPath.QualifierStep)
                {
                    nextNode = FindQualifierNode(parentNode, nextStep.Name.Substring(1), createNodes);
                }
                else
                {
                    // This is an array indexing step. First get the index, then get the node.
                    if (!parentNode.Options.IsArray)
                    {
                        throw new XmpException("Indexing applied to non-array", XmpErrorCode.BadXPath);
                    }
                    var index = 0;
                    if (stepKind == XmpPath.ArrayIndexStep)
                    {
                        index = FindIndexedItem(parentNode, nextStep.Name, createNodes);
                    }
                    else
                    {
                        if (stepKind == XmpPath.ArrayLastStep)
                        {
                            index = parentNode.GetChildrenLength();
                        }
                        else
                        {
                            if (stepKind == XmpPath.FieldSelectorStep)
                            {
                                var result     = Utils.SplitNameAndValue(nextStep.Name);
                                var fieldName  = result[0];
                                var fieldValue = result[1];
                                index = LookupFieldSelector(parentNode, fieldName, fieldValue);
                            }
                            else
                            {
                                if (stepKind == XmpPath.QualSelectorStep)
                                {
                                    var result    = Utils.SplitNameAndValue(nextStep.Name);
                                    var qualName  = result[0];
                                    var qualValue = result[1];
                                    index = LookupQualSelector(parentNode, qualName, qualValue, nextStep.AliasForm);
                                }
                                else
                                {
                                    throw new XmpException("Unknown array indexing step in FollowXPathStep", XmpErrorCode.InternalFailure);
                                }
                            }
                        }
                    }
                    if (1 <= index && index <= parentNode.GetChildrenLength())
                    {
                        nextNode = parentNode.GetChild(index);
                    }
                }
            }
            return(nextNode);
        }