/// <summary> /// The initial support for WAV files mapped a legacy ID3 audio copyright /// into a new xmpDM:copyright property. /// </summary> /// <remarks> /// The initial support for WAV files mapped a legacy ID3 audio copyright /// into a new xmpDM:copyright property. This is special case code to migrate /// that into dc:rights['x-default']. The rules: /// <pre> /// 1. If there is no dc:rights array, or an empty array - /// Create one with dc:rights['x-default'] set from double linefeed and xmpDM:copyright. /// 2. If there is a dc:rights array but it has no x-default item - /// Create an x-default item as a copy of the first item then apply rule #3. /// 3. If there is a dc:rights array with an x-default item, /// Look for a double linefeed in the value. /// A. If no double linefeed, compare the x-default value to the xmpDM:copyright value. /// A1. If they match then leave the x-default value alone. /// A2. Otherwise, append a double linefeed and /// the xmpDM:copyright value to the x-default value. /// B. If there is a double linefeed, compare the trailing text to the xmpDM:copyright value. /// B1. If they match then leave the x-default value alone. /// B2. Otherwise, replace the trailing x-default text with the xmpDM:copyright value. /// 4. In all cases, delete the xmpDM:copyright property. /// </pre> /// </remarks> /// <param name="xmp">the metadata object</param> /// <param name="dmCopyright">the "dm:copyright"-property</param> private static void MigrateAudioCopyright(XMPMeta xmp, XMPNode dmCopyright) { try { XMPNode dcSchema = XMPNodeUtils.FindSchemaNode(((XMPMetaImpl)xmp).GetRoot(), XMPConst .NS_DC, true); String dmValue = dmCopyright.GetValue(); String doubleLF = "\n\n"; XMPNode dcRightsArray = XMPNodeUtils.FindChildNode(dcSchema, "dc:rights", false); if (dcRightsArray == null || !dcRightsArray.HasChildren()) { // 1. No dc:rights array, create from double linefeed and xmpDM:copyright. dmValue = doubleLF + dmValue; xmp.SetLocalizedText(XMPConst.NS_DC, "rights", "", XMPConst.X_DEFAULT, dmValue, null ); } else { int xdIndex = XMPNodeUtils.LookupLanguageItem(dcRightsArray, XMPConst.X_DEFAULT); if (xdIndex < 0) { // 2. No x-default item, create from the first item. String firstValue = dcRightsArray.GetChild(1).GetValue(); xmp.SetLocalizedText(XMPConst.NS_DC, "rights", "", XMPConst.X_DEFAULT, firstValue , null); xdIndex = XMPNodeUtils.LookupLanguageItem(dcRightsArray, XMPConst.X_DEFAULT); } // 3. Look for a double linefeed in the x-default value. XMPNode defaultNode = dcRightsArray.GetChild(xdIndex); String defaultValue = defaultNode.GetValue(); int lfPos = defaultValue.IndexOf(doubleLF); if (lfPos < 0) { // 3A. No double LF, compare whole values. if (!dmValue.Equals(defaultValue)) { // 3A2. Append the xmpDM:copyright to the x-default // item. defaultNode.SetValue(defaultValue + doubleLF + dmValue); } } else { // 3B. Has double LF, compare the tail. if (!defaultValue.Substring(lfPos + 2).Equals(dmValue)) { // 3B2. Replace the x-default tail. defaultNode.SetValue(defaultValue.JSubstring(0, lfPos + 2) + dmValue); } } } // 4. Get rid of the xmpDM:copyright. dmCopyright.GetParent().RemoveChild(dmCopyright); } catch (XMPException) { } }
/// <summary>Constructor with optionsl initial values.</summary> /// <remarks> /// Constructor with optionsl initial values. If <code>propName</code> is provided, /// <code>schemaNS</code> 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 redurce to this property within the <code>schemaNS</code> /// </param> /// <param name="options"> /// advanced iteration options, see /// <see cref="iText.Kernel.XMP.Options.IteratorOptions"/> /// </param> /// <exception cref="iText.Kernel.XMP.XMPException">If the node defined by the paramters is not existing. /// </exception> public XMPIteratorImpl(XMPMetaImpl xmp, String schemaNS, String propPath, IteratorOptions options) { // make sure that options is defined at least with defaults this.options = options ?? new IteratorOptions(); // the start node of the iteration depending on the schema and property filter XMPNode startNode; string initialPath = null; bool baseSchema = !String.IsNullOrEmpty(schemaNS); bool baseProperty = !String.IsNullOrEmpty(propPath); if (!baseSchema && !baseProperty) { // complete tree will be iterated startNode = xmp.GetRoot(); } else if (baseSchema && baseProperty) { // Schema and property node provided XMPPath path = XMPPathParser.ExpandXPath(schemaNS, propPath); // base path is the prop path without the property leaf XMPPath basePath = new XMPPath(); for (int i = 0; i < path.Size() - 1; i++) { basePath.Add(path.GetSegment(i)); } startNode = XMPNodeUtils.FindNode(xmp.GetRoot(), path, false, null); this.baseNS = 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", XMPError.BADSCHEMA); } // create iterator if (startNode != null) { this.nodeIterator = (!this.options.IsJustChildren()) ? new NodeIterator(this, startNode, initialPath, 1) : new NodeIteratorChildren(this, startNode, initialPath); } else { // create null iterator this.nodeIterator = EmptyList.GetEnumerator(); } }
/// <summary>Visit all schemas to do general fixes and handle special cases.</summary> /// <param name="xmp">the metadata object implementation</param> /// <exception cref="iText.Kernel.XMP.XMPException">Thrown if the normalisation fails. /// </exception> private static void TouchUpDataModel(XMPMetaImpl 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(), XMPConst.NS_DC, true); // Do the special case fixes within each schema. for (IEnumerator it = xmp.GetRoot().IterateChildren(); it.MoveNext();) { XMPNode currSchema = (XMPNode)it.Current; if (XMPConst.NS_DC.Equals(currSchema.GetName())) { NormalizeDCArrays(currSchema); } else { if (XMPConst.NS_EXIF.Equals(currSchema.GetName())) { // Do a special case fix for exif:GPSTimeStamp. FixGPSTimeStamp(currSchema); XMPNode arrayNode = XMPNodeUtils.FindChildNode(currSchema, "exif:UserComment", false ); if (arrayNode != null) { RepairAltText(arrayNode); } } else { if (XMPConst.NS_DM.Equals(currSchema.GetName())) { // Do a special case migration of xmpDM:copyright to // dc:rights['x-default']. XMPNode dmCopyright = XMPNodeUtils.FindChildNode(currSchema, "xmpDM:copyright", false ); if (dmCopyright != null) { MigrateAudioCopyright(xmp, dmCopyright); } } else { if (XMPConst.NS_XMP_RIGHTS.Equals(currSchema.GetName())) { XMPNode arrayNode = XMPNodeUtils.FindChildNode(currSchema, "xmpRights:UsageTerms" , false); if (arrayNode != null) { RepairAltText(arrayNode); } } } } } } }
/// <summary>Visit all of the top level nodes looking for aliases.</summary> /// <remarks> /// Visit all of the top level nodes looking for aliases. If there is /// no base, transplant the alias subtree. If there is a base and strict /// aliasing is on, make sure the alias and base subtrees match. /// </remarks> /// <param name="tree">the root of the metadata tree</param> /// <param name="options">th parsing options</param> /// <exception cref="iText.Kernel.XMP.XMPException">Forwards XMP errors</exception> private static void MoveExplicitAliases(XMPNode tree, ParseOptions options) { if (!tree.GetHasAliases()) { return; } tree.SetHasAliases(false); bool strictAliasing = options.GetStrictAliasing(); IEnumerator schemaIt = tree.GetUnmodifiableChildren().GetEnumerator(); while (schemaIt.MoveNext()) { XMPNode currSchema = (XMPNode)schemaIt.Current; if (currSchema == null) { continue; } if (!currSchema.GetHasAliases()) { continue; } List <XMPNode> currPropsToRemove = new List <XMPNode>(); IEnumerator propertyIt = currSchema.IterateChildren(); while (propertyIt.MoveNext()) { XMPNode currProp = (XMPNode)propertyIt.Current; if (currProp == null) { continue; } if (!currProp.IsAlias()) { continue; } currProp.SetAlias(false); // Find the base path, look for the base schema and root node. XMPAliasInfo info = XMPMetaFactory.GetSchemaRegistry().FindAlias(currProp.GetName()); if (info != null) { // find or create schema XMPNode baseSchema = XMPNodeUtils.FindSchemaNode(tree, info.GetNamespace(), null, true); baseSchema.SetImplicit(false); XMPNode baseNode = XMPNodeUtils.FindChildNode(baseSchema, info.GetPrefix() + info.GetPropName(), false); if (baseNode == null) { if (info.GetAliasForm().IsSimple()) { // A top-to-top alias, transplant the property. // change the alias property name to the base name string qname = info.GetPrefix() + info.GetPropName(); currProp.SetName(qname); baseSchema.AddChild(currProp); } else { // An alias to an array item, // create the array and transplant the property. baseNode = new XMPNode(info.GetPrefix() + info.GetPropName(), info.GetAliasForm().ToPropertyOptions()); baseSchema.AddChild(baseNode); TransplantArrayItemAlias(currProp, baseNode); } currPropsToRemove.Add(currProp); } else if (info.GetAliasForm().IsSimple()) { // The base node does exist and this is a top-to-top alias. // Check for conflicts if strict aliasing is on. // Remove and delete the alias subtree. if (strictAliasing) { CompareAliasedSubtrees(currProp, baseNode, true); } currPropsToRemove.Add(currProp); } else { // This is an alias to an array item and the array exists. // Look for the aliased item. // Then transplant or check & delete as appropriate. XMPNode itemNode = null; if (info.GetAliasForm().IsArrayAltText()) { int xdIndex = XMPNodeUtils.LookupLanguageItem(baseNode, XMPConst.X_DEFAULT); if (xdIndex != -1) { itemNode = baseNode.GetChild(xdIndex); } } else if (baseNode.HasChildren()) { itemNode = baseNode.GetChild(1); } if (itemNode == null) { TransplantArrayItemAlias(currProp, baseNode); } else { if (strictAliasing) { CompareAliasedSubtrees(currProp, itemNode, true); } } currPropsToRemove.Add(currProp); } } } foreach (XMPNode o in currPropsToRemove) { currSchema.RemoveChild(o); } currPropsToRemove.Clear(); currSchema.SetHasAliases(false); } }