1f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling// ================================================================================================= 2f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling// ADOBE SYSTEMS INCORPORATED 3f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling// Copyright 2006 Adobe Systems Incorporated 4f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling// All Rights Reserved 5f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling// 6f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms 7f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling// of the Adobe license agreement accompanying it. 8f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling// ================================================================================================= 9f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 10f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberlingpackage com.adobe.xmp.impl; 11f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 12f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberlingimport java.util.Calendar; 13f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberlingimport java.util.HashMap; 14f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberlingimport java.util.Iterator; 15f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberlingimport java.util.Map; 16f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 17f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberlingimport com.adobe.xmp.XMPConst; 18f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberlingimport com.adobe.xmp.XMPDateTime; 19f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberlingimport com.adobe.xmp.XMPError; 20f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberlingimport com.adobe.xmp.XMPException; 21f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberlingimport com.adobe.xmp.XMPMeta; 22f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberlingimport com.adobe.xmp.XMPMetaFactory; 23f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberlingimport com.adobe.xmp.XMPUtils; 24f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberlingimport com.adobe.xmp.impl.xpath.XMPPath; 25f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberlingimport com.adobe.xmp.impl.xpath.XMPPathParser; 26f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberlingimport com.adobe.xmp.options.ParseOptions; 27f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberlingimport com.adobe.xmp.options.PropertyOptions; 28f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberlingimport com.adobe.xmp.properties.XMPAliasInfo; 29f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 30f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling/** 31f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @since Aug 18, 2006 32f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling */ 33f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberlingpublic class XMPNormalizer 34f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling{ 35f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling /** caches the correct dc-property array forms */ 36f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling private static Map dcArrayForms; 37f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling /** init char tables */ 38f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling static 39f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 40f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling initDCArrays(); 41f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 42f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 43f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 44f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling /** 45f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * Hidden constructor 46f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling */ 47f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling private XMPNormalizer() 48f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 49f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // EMPTY 50f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 51f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 52f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 53f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling /** 54f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * Normalizes a raw parsed XMPMeta-Object 55f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param xmp the raw metadata object 56f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param options the parsing options 57f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @return Returns the normalized metadata object 58f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @throws XMPException Collects all severe processing errors. 59f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling */ 60f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling static XMPMeta process(XMPMetaImpl xmp, ParseOptions options) throws XMPException 61f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 62f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPNode tree = xmp.getRoot(); 63f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 64f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling touchUpDataModel(xmp); 65f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling moveExplicitAliases(tree, options); 66f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 67f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling tweakOldXMP(tree); 68f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 69f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling deleteEmptySchemas(tree); 70f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 71f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling return xmp; 72f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 73f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 74f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 75f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling /** 76f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * Tweak old XMP: Move an instance ID from rdf:about to the 77f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <em>xmpMM:InstanceID</em> property. An old instance ID usually looks 78f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * like "uuid:bac965c4-9d87-11d9-9a30-000d936b79c4", plus InDesign 79f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * 3.0 wrote them like "bac965c4-9d87-11d9-9a30-000d936b79c4". If 80f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * the name looks like a UUID simply move it to <em>xmpMM:InstanceID</em>, 81f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * don't worry about any existing <em>xmpMM:InstanceID</em>. Both will 82f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * only be present when a newer file with the <em>xmpMM:InstanceID</em> 83f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * property is updated by an old app that uses <em>rdf:about</em>. 84f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * 85f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param tree the root of the metadata tree 86f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @throws XMPException Thrown if tweaking fails. 87f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling */ 88f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling private static void tweakOldXMP(XMPNode tree) throws XMPException 89f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 90f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (tree.getName() != null && tree.getName().length() >= Utils.UUID_LENGTH) 91f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 92f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling String nameStr = tree.getName().toLowerCase(); 93f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (nameStr.startsWith("uuid:")) 94f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 95f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling nameStr = nameStr.substring(5); 96f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 97f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 98f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (Utils.checkUUIDFormat(nameStr)) 99f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 100f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // move UUID to xmpMM:InstanceID and remove it from the root node 101f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPPath path = XMPPathParser.expandXPath(XMPConst.NS_XMP_MM, "InstanceID"); 102f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPNode idNode = XMPNodeUtils.findNode (tree, path, true, null); 103f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (idNode != null) 104f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 105f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling idNode.setOptions(null); // Clobber any existing xmpMM:InstanceID. 106f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling idNode.setValue("uuid:" + nameStr); 107f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling idNode.removeChildren(); 108f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling idNode.removeQualifiers(); 109f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling tree.setName(null); 110f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 111f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else 112f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 113f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling throw new XMPException("Failure creating xmpMM:InstanceID", 114f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPError.INTERNALFAILURE); 115f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 116f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 117f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 118f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 119f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 120f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 121f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling /** 122f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * Visit all schemas to do general fixes and handle special cases. 123f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * 124f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param xmp the metadata object implementation 125f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @throws XMPException Thrown if the normalisation fails. 126f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling */ 127f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling private static void touchUpDataModel(XMPMetaImpl xmp) throws XMPException 128f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 129f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // make sure the DC schema is existing, because it might be needed within the normalization 130f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // if not touched it will be removed by removeEmptySchemas 131f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPNodeUtils.findSchemaNode(xmp.getRoot(), XMPConst.NS_DC, true); 132f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 133f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // Do the special case fixes within each schema. 134f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling for (Iterator it = xmp.getRoot().iterateChildren(); it.hasNext();) 135f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 136f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPNode currSchema = (XMPNode) it.next(); 137f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (XMPConst.NS_DC.equals(currSchema.getName())) 138f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 139f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling normalizeDCArrays(currSchema); 140f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 141f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else if (XMPConst.NS_EXIF.equals(currSchema.getName())) 142f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 143f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // Do a special case fix for exif:GPSTimeStamp. 144f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling fixGPSTimeStamp(currSchema); 145f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPNode arrayNode = XMPNodeUtils.findChildNode(currSchema, "exif:UserComment", 146f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling false); 147f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (arrayNode != null) 148f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 149f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling repairAltText(arrayNode); 150f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 151f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 152f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else if (XMPConst.NS_DM.equals(currSchema.getName())) 153f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 154f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // Do a special case migration of xmpDM:copyright to 155f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // dc:rights['x-default']. 156f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPNode dmCopyright = XMPNodeUtils.findChildNode(currSchema, "xmpDM:copyright", 157f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling false); 158f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (dmCopyright != null) 159f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 160f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling migrateAudioCopyright(xmp, dmCopyright); 161f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 162f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 163f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else if (XMPConst.NS_XMP_RIGHTS.equals(currSchema.getName())) 164f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 165f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPNode arrayNode = XMPNodeUtils.findChildNode(currSchema, "xmpRights:UsageTerms", 166f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling false); 167f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (arrayNode != null) 168f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 169f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling repairAltText(arrayNode); 170f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 171f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 172f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 173f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 174f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 175f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 176f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling /** 177f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * Undo the denormalization performed by the XMP used in Acrobat 5.<br> 178f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * If a Dublin Core array had only one item, it was serialized as a simple 179f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * property. <br> 180f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * The <code>xml:lang</code> attribute was dropped from an 181f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <code>alt-text</code> item if the language was <code>x-default</code>. 182f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * 183f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param dcSchema the DC schema node 184f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @throws XMPException Thrown if normalization fails 185f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling */ 186f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling private static void normalizeDCArrays(XMPNode dcSchema) throws XMPException 187f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 188f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling for (int i = 1; i <= dcSchema.getChildrenLength(); i++) 189f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 190f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPNode currProp = dcSchema.getChild(i); 191f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 192f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling PropertyOptions arrayForm = (PropertyOptions) dcArrayForms.get(currProp.getName()); 193f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (arrayForm == null) 194f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 195f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling continue; 196f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 197f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else if (currProp.getOptions().isSimple()) 198f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 199f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // create a new array and add the current property as child, 200f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // if it was formerly simple 201f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPNode newArray = new XMPNode(currProp.getName(), arrayForm); 202f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling currProp.setName(XMPConst.ARRAY_ITEM_NAME); 203f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling newArray.addChild(currProp); 204f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling dcSchema.replaceChild(i, newArray); 205f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 206f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // fix language alternatives 207f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (arrayForm.isArrayAltText() && !currProp.getOptions().getHasLanguage()) 208f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 209f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPNode newLang = new XMPNode(XMPConst.XML_LANG, XMPConst.X_DEFAULT, null); 210f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling currProp.addQualifier(newLang); 211f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 212f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 213f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else 214f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 215f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // clear array options and add corrected array form if it has been an array before 216f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling currProp.getOptions().setOption( 217f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling PropertyOptions.ARRAY | 218f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling PropertyOptions.ARRAY_ORDERED | 219f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling PropertyOptions.ARRAY_ALTERNATE | 220f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling PropertyOptions.ARRAY_ALT_TEXT, 221f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling false); 222f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling currProp.getOptions().mergeWith(arrayForm); 223f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 224f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (arrayForm.isArrayAltText()) 225f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 226f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // applying for "dc:description", "dc:rights", "dc:title" 227f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling repairAltText(currProp); 228f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 229f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 230f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 231f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 232f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 233f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 234f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 235f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling /** 236f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * Make sure that the array is well-formed AltText. Each item must be simple 237f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * and have an "xml:lang" qualifier. If repairs are needed, keep simple 238f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * non-empty items by adding the "xml:lang" with value "x-repair". 239f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param arrayNode the property node of the array to repair. 240f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @throws XMPException Forwards unexpected exceptions. 241f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling */ 242f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling private static void repairAltText(XMPNode arrayNode) throws XMPException 243f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 244f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (arrayNode == null || 245f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling !arrayNode.getOptions().isArray()) 246f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 247f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // Already OK or not even an array. 248f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling return; 249f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 250f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 251f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // fix options 252f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling arrayNode.getOptions().setArrayOrdered(true).setArrayAlternate(true).setArrayAltText(true); 253f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 254f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling for (Iterator it = arrayNode.iterateChildren(); it.hasNext();) 255f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 256f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPNode currChild = (XMPNode) it.next(); 257f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (currChild.getOptions().isCompositeProperty()) 258f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 259f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // Delete non-simple children. 260f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling it.remove(); 261f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 262f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else if (!currChild.getOptions().getHasLanguage()) 263f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 264f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling String childValue = currChild.getValue(); 265f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (childValue == null || childValue.length() == 0) 266f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 267f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // Delete empty valued children that have no xml:lang. 268f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling it.remove(); 269f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 270f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else 271f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 272f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // Add an xml:lang qualifier with the value "x-repair". 273f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPNode repairLang = new XMPNode(XMPConst.XML_LANG, "x-repair", null); 274f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling currChild.addQualifier(repairLang); 275f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 276f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 277f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 278f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 279f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 280f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 281f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling /** 282f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * Visit all of the top level nodes looking for aliases. If there is 283f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * no base, transplant the alias subtree. If there is a base and strict 284f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * aliasing is on, make sure the alias and base subtrees match. 285f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * 286f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param tree the root of the metadata tree 287f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param options th parsing options 288f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @throws XMPException Forwards XMP errors 289f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling */ 290f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling private static void moveExplicitAliases(XMPNode tree, ParseOptions options) 291f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling throws XMPException 292f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 293f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (!tree.getHasAliases()) 294f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 295f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling return; 296f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 297f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling tree.setHasAliases(false); 298f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 299f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling boolean strictAliasing = options.getStrictAliasing(); 300f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 301f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling for (Iterator schemaIt = tree.getUnmodifiableChildren().iterator(); schemaIt.hasNext();) 302f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 303f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPNode currSchema = (XMPNode) schemaIt.next(); 304f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (!currSchema.getHasAliases()) 305f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 306f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling continue; 307f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 308f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 309f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling for (Iterator propertyIt = currSchema.iterateChildren(); propertyIt.hasNext();) 310f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 311f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPNode currProp = (XMPNode) propertyIt.next(); 312f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 313f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (!currProp.isAlias()) 314f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 315f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling continue; 316f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 317f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 318f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling currProp.setAlias(false); 319f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 320f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // Find the base path, look for the base schema and root node. 321f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPAliasInfo info = XMPMetaFactory.getSchemaRegistry() 322f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling .findAlias(currProp.getName()); 323f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (info != null) 324f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 325f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // find or create schema 326f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPNode baseSchema = XMPNodeUtils.findSchemaNode(tree, info 327f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling .getNamespace(), null, true); 328f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling baseSchema.setImplicit(false); 329f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 330f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPNode baseNode = XMPNodeUtils 331f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling .findChildNode(baseSchema, 332f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling info.getPrefix() + info.getPropName(), false); 333f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (baseNode == null) 334f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 335f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (info.getAliasForm().isSimple()) 336f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 337f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // A top-to-top alias, transplant the property. 338f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // change the alias property name to the base name 339f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling String qname = info.getPrefix() + info.getPropName(); 340f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling currProp.setName(qname); 341f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling baseSchema.addChild(currProp); 342f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // remove the alias property 343f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling propertyIt.remove(); 344f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 345f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else 346f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 347f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // An alias to an array item, 348f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // create the array and transplant the property. 349f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling baseNode = new XMPNode(info.getPrefix() + info.getPropName(), info 350f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling .getAliasForm().toPropertyOptions()); 351f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling baseSchema.addChild(baseNode); 352f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling transplantArrayItemAlias (propertyIt, currProp, baseNode); 353f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 354f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 355f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 356f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else if (info.getAliasForm().isSimple()) 357f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 358f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // The base node does exist and this is a top-to-top alias. 359f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // Check for conflicts if strict aliasing is on. 360f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // Remove and delete the alias subtree. 361f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (strictAliasing) 362f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 363f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling compareAliasedSubtrees (currProp, baseNode, true); 364f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 365f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 366f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling propertyIt.remove(); 367f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 368f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else 369f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 370f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // This is an alias to an array item and the array exists. 371f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // Look for the aliased item. 372f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // Then transplant or check & delete as appropriate. 373f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 374f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPNode itemNode = null; 375f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (info.getAliasForm().isArrayAltText()) 376f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 377f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling int xdIndex = XMPNodeUtils.lookupLanguageItem(baseNode, 378f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPConst.X_DEFAULT); 379f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (xdIndex != -1) 380f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 381f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling itemNode = baseNode.getChild(xdIndex); 382f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 383f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 384f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else if (baseNode.hasChildren()) 385f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 386f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling itemNode = baseNode.getChild(1); 387f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 388f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 389f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (itemNode == null) 390f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 391f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling transplantArrayItemAlias (propertyIt, currProp, baseNode); 392f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 393f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else 394f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 395f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (strictAliasing) 396f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 397f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling compareAliasedSubtrees (currProp, itemNode, true); 398f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 399f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 400f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling propertyIt.remove(); 401f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 402f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 403f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 404f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 405f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling currSchema.setHasAliases(false); 406f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 407f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 408f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 409f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 410f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling /** 411f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * Moves an alias node of array form to another schema into an array 412f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param propertyIt the property iterator of the old schema (used to delete the property) 413f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param childNode the node to be moved 414f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param baseArray the base array for the array item 415f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @throws XMPException Forwards XMP errors 416f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling */ 417f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling private static void transplantArrayItemAlias(Iterator propertyIt, XMPNode childNode, 418f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPNode baseArray) throws XMPException 419f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 420f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (baseArray.getOptions().isArrayAltText()) 421f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 422f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (childNode.getOptions().getHasLanguage()) 423f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 424f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling throw new XMPException("Alias to x-default already has a language qualifier", 425f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPError.BADXMP); 426f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 427f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 428f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPNode langQual = new XMPNode(XMPConst.XML_LANG, XMPConst.X_DEFAULT, null); 429f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling childNode.addQualifier(langQual); 430f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 431f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 432f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling propertyIt.remove(); 433f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling childNode.setName(XMPConst.ARRAY_ITEM_NAME); 434f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling baseArray.addChild(childNode); 435f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 436f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 437f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 438f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling /** 439f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * Fixes the GPS Timestamp in EXIF. 440f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param exifSchema the EXIF schema node 441f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @throws XMPException Thrown if the date conversion fails. 442f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling */ 443f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling private static void fixGPSTimeStamp(XMPNode exifSchema) 444f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling throws XMPException 445f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 446f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // Note: if dates are not found the convert-methods throws an exceptions, 447f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // and this methods returns. 448f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPNode gpsDateTime = XMPNodeUtils.findChildNode(exifSchema, "exif:GPSTimeStamp", false); 449f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (gpsDateTime == null) 450f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 451f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling return; 452f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 453f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 454f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling try 455f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 456f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPDateTime binGPSStamp; 457f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPDateTime binOtherDate; 458f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 459f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling binGPSStamp = XMPUtils.convertToDate(gpsDateTime.getValue()); 460f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (binGPSStamp.getYear() != 0 || 461f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling binGPSStamp.getMonth() != 0 || 462f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling binGPSStamp.getDay() != 0) 463f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 464f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling return; 465f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 466f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 467f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPNode otherDate = XMPNodeUtils.findChildNode(exifSchema, "exif:DateTimeOriginal", 468f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling false); 469f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (otherDate == null) 470f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 471f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling otherDate = XMPNodeUtils.findChildNode(exifSchema, "exif:DateTimeDigitized", false); 472f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 473f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 474f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling binOtherDate = XMPUtils.convertToDate(otherDate.getValue()); 475f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling Calendar cal = binGPSStamp.getCalendar(); 476f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling cal.set(Calendar.YEAR, binOtherDate.getYear()); 477f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling cal.set(Calendar.MONTH, binOtherDate.getMonth()); 478f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling cal.set(Calendar.DAY_OF_MONTH, binOtherDate.getDay()); 479f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling binGPSStamp = new XMPDateTimeImpl(cal); 480f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling gpsDateTime.setValue(XMPUtils.convertFromDate (binGPSStamp)); 481f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 482f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling catch (XMPException e) 483f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 484f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // Don't let a missing or bad date stop other things. 485f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling return; 486f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 487f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 488f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 489f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 490f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 491f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling /** 492f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * Remove all empty schemas from the metadata tree that were generated during the rdf parsing. 493f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param tree the root of the metadata tree 494f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling */ 495f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling private static void deleteEmptySchemas(XMPNode tree) 496f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 497f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // Delete empty schema nodes. Do this last, other cleanup can make empty 498f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // schema. 499f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 500f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling for (Iterator it = tree.iterateChildren(); it.hasNext();) 501f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 502f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPNode schema = (XMPNode) it.next(); 503f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (!schema.hasChildren()) 504f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 505f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling it.remove(); 506f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 507f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 508f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 509f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 510f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 511f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling /** 512f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * The outermost call is special. The names almost certainly differ. The 513f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * qualifiers (and hence options) will differ for an alias to the x-default 514f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * item of a langAlt array. 515f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * 516f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param aliasNode the alias node 517f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param baseNode the base node of the alias 518f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param outerCall marks the outer call of the recursion 519f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @throws XMPException Forwards XMP errors 520f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling */ 521f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling private static void compareAliasedSubtrees(XMPNode aliasNode, XMPNode baseNode, 522f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling boolean outerCall) throws XMPException 523f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 524f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (!aliasNode.getValue().equals(baseNode.getValue()) || 525f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling aliasNode.getChildrenLength() != baseNode.getChildrenLength()) 526f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 527f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling throw new XMPException("Mismatch between alias and base nodes", XMPError.BADXMP); 528f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 529f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 530f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if ( 531f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling !outerCall && 532f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling (!aliasNode.getName().equals(baseNode.getName()) || 533f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling !aliasNode.getOptions().equals(baseNode.getOptions()) || 534f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling aliasNode.getQualifierLength() != baseNode.getQualifierLength()) 535f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling ) 536f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 537f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling throw new XMPException("Mismatch between alias and base nodes", 538f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPError.BADXMP); 539f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 540f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 541f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling for (Iterator an = aliasNode.iterateChildren(), 542f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling bn = baseNode.iterateChildren(); 543f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling an.hasNext() && bn.hasNext();) 544f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 545f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPNode aliasChild = (XMPNode) an.next(); 546f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPNode baseChild = (XMPNode) bn.next(); 547f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling compareAliasedSubtrees (aliasChild, baseChild, false); 548f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 549f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 550f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 551f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling for (Iterator an = aliasNode.iterateQualifier(), 552f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling bn = baseNode.iterateQualifier(); 553f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling an.hasNext() && bn.hasNext();) 554f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 555f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPNode aliasQual = (XMPNode) an.next(); 556f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPNode baseQual = (XMPNode) bn.next(); 557f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling compareAliasedSubtrees (aliasQual, baseQual, false); 558f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 559f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 560f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 561f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 562f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling /** 563f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * The initial support for WAV files mapped a legacy ID3 audio copyright 564f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * into a new xmpDM:copyright property. This is special case code to migrate 565f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * that into dc:rights['x-default']. The rules: 566f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * 567f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * <pre> 568f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * 1. If there is no dc:rights array, or an empty array - 569f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * Create one with dc:rights['x-default'] set from double linefeed and xmpDM:copyright. 570f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * 571f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * 2. If there is a dc:rights array but it has no x-default item - 572f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * Create an x-default item as a copy of the first item then apply rule #3. 573f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * 574f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * 3. If there is a dc:rights array with an x-default item, 575f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * Look for a double linefeed in the value. 576f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * A. If no double linefeed, compare the x-default value to the xmpDM:copyright value. 577f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * A1. If they match then leave the x-default value alone. 578f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * A2. Otherwise, append a double linefeed and 579f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * the xmpDM:copyright value to the x-default value. 580f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * B. If there is a double linefeed, compare the trailing text to the xmpDM:copyright value. 581f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * B1. If they match then leave the x-default value alone. 582f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * B2. Otherwise, replace the trailing x-default text with the xmpDM:copyright value. 583f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * 584f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * 4. In all cases, delete the xmpDM:copyright property. 585f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * </pre> 586f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * 587f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param xmp the metadata object 588f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * @param dmCopyright the "dm:copyright"-property 589f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling */ 590f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling private static void migrateAudioCopyright (XMPMeta xmp, XMPNode dmCopyright) 591f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 592f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling try 593f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 594f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPNode dcSchema = XMPNodeUtils.findSchemaNode( 595f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling ((XMPMetaImpl) xmp).getRoot(), XMPConst.NS_DC, true); 596f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 597f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling String dmValue = dmCopyright.getValue(); 598f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling String doubleLF = "\n\n"; 599f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 600f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPNode dcRightsArray = XMPNodeUtils.findChildNode (dcSchema, "dc:rights", false); 601f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 602f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (dcRightsArray == null || !dcRightsArray.hasChildren()) 603f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 604f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // 1. No dc:rights array, create from double linefeed and xmpDM:copyright. 605f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling dmValue = doubleLF + dmValue; 606f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling xmp.setLocalizedText(XMPConst.NS_DC, "rights", "", XMPConst.X_DEFAULT, dmValue, 607f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling null); 608f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 609f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else 610f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 611f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling int xdIndex = XMPNodeUtils.lookupLanguageItem(dcRightsArray, XMPConst.X_DEFAULT); 612f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 613f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (xdIndex < 0) 614f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 615f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // 2. No x-default item, create from the first item. 616f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling String firstValue = dcRightsArray.getChild(1).getValue(); 617f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling xmp.setLocalizedText (XMPConst.NS_DC, "rights", "", XMPConst.X_DEFAULT, 618f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling firstValue, null); 619f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling xdIndex = XMPNodeUtils.lookupLanguageItem(dcRightsArray, XMPConst.X_DEFAULT); 620f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 621f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 622f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // 3. Look for a double linefeed in the x-default value. 623f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling XMPNode defaultNode = dcRightsArray.getChild(xdIndex); 624f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling String defaultValue = defaultNode.getValue(); 625f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling int lfPos = defaultValue.indexOf(doubleLF); 626f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 627f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (lfPos < 0) 628f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 629f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // 3A. No double LF, compare whole values. 630f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (!dmValue.equals(defaultValue)) 631f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 632f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // 3A2. Append the xmpDM:copyright to the x-default 633f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // item. 634f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling defaultNode.setValue(defaultValue + doubleLF + dmValue); 635f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 636f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 637f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling else 638f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 639f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // 3B. Has double LF, compare the tail. 640f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling if (!defaultValue.substring(lfPos + 2).equals(dmValue)) 641f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 642f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // 3B2. Replace the x-default tail. 643f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling defaultNode.setValue(defaultValue.substring(0, lfPos + 2) + dmValue); 644f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 645f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 646f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 647f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 648f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 649f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // 4. Get rid of the xmpDM:copyright. 650f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling dmCopyright.getParent().removeChild(dmCopyright); 651f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 652f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling catch (XMPException e) 653f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 654f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // Don't let failures (like a bad dc:rights form) stop other 655f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // cleanup. 656f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 657f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 658f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 659f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 660f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling /** 661f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * Initializes the map that contains the known arrays, that are fixed by 662f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling * {@link XMPNormalizer#normalizeDCArrays(XMPNode)}. 663f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling */ 664f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling private static void initDCArrays() 665f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling { 666f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling dcArrayForms = new HashMap(); 667f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 668f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // Properties supposed to be a "Bag". 669f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling PropertyOptions bagForm = new PropertyOptions(); 670f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling bagForm.setArray(true); 671f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling dcArrayForms.put("dc:contributor", bagForm); 672f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling dcArrayForms.put("dc:language", bagForm); 673f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling dcArrayForms.put("dc:publisher", bagForm); 674f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling dcArrayForms.put("dc:relation", bagForm); 675f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling dcArrayForms.put("dc:subject", bagForm); 676f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling dcArrayForms.put("dc:type", bagForm); 677f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 678f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // Properties supposed to be a "Seq". 679f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling PropertyOptions seqForm = new PropertyOptions(); 680f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling seqForm.setArray(true); 681f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling seqForm.setArrayOrdered(true); 682f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling dcArrayForms.put("dc:creator", seqForm); 683f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling dcArrayForms.put("dc:date", seqForm); 684f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling 685f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling // Properties supposed to be an "Alt" in alternative-text form. 686f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling PropertyOptions altTextForm = new PropertyOptions(); 687f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling altTextForm.setArray(true); 688f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling altTextForm.setArrayOrdered(true); 689f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling altTextForm.setArrayAlternate(true); 690f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling altTextForm.setArrayAltText(true); 691f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling dcArrayForms.put("dc:description", altTextForm); 692f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling dcArrayForms.put("dc:rights", altTextForm); 693f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling dcArrayForms.put("dc:title", altTextForm); 694f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling } 695f12f744843a67c910ec325fc6dfa73988f67b97cSascha Haeberling} 696