summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build/XMP_BuildInfo.h36
-rw-r--r--build/gcc/XMPCore.mak213
-rw-r--r--build/gcc/i80386linux/expat_config.h95
-rw-r--r--build/gcc/sparcsolaris/expat_config.h95
-rw-r--r--build/vsnet/XMPCore.vcproj278
-rw-r--r--build/vsnet/XMPFiles.vcproj322
-rw-r--r--build/vsnet/XMPToolkit.sln25
-rw-r--r--build/vsnet/expat_config.h95
-rw-r--r--build/xcode/XMPToolkit-Common.xcconfig63
-rw-r--r--build/xcode/XMPToolkit-Debug.xcconfig12
-rw-r--r--build/xcode/XMPToolkit-Release.xcconfig12
-rw-r--r--build/xcode/XMPToolkit.xcodeproj/project.pbxproj790
-rw-r--r--build/xcode/expat_config.h107
-rw-r--r--docs/BSD-License.txt25
-rw-r--r--docs/XMP-SDK-Overview.pdfbin0 -> 56191 bytes
-rw-r--r--docs/XMP-Specification.pdfbin0 -> 931213 bytes
-rw-r--r--docs/XMPToolkit/TXMPFiles_8hpp-source.html162
-rw-r--r--docs/XMPToolkit/TXMPFiles_8hpp.html34
-rw-r--r--docs/XMPToolkit/TXMPFiles_8incl__cpp.html32
-rw-r--r--docs/XMPToolkit/TXMPFiles_8incl__cpp__incl.pngbin0 -> 1604 bytes
-rw-r--r--docs/XMPToolkit/TXMPIterator_8hpp-source.html104
-rw-r--r--docs/XMPToolkit/TXMPIterator_8hpp.html37
-rw-r--r--docs/XMPToolkit/TXMPIterator_8hpp__incl.pngbin0 -> 1125 bytes
-rw-r--r--docs/XMPToolkit/TXMPIterator_8incl__cpp.html33
-rw-r--r--docs/XMPToolkit/TXMPIterator_8incl__cpp__incl.pngbin0 -> 2105 bytes
-rw-r--r--docs/XMPToolkit/TXMPMeta_8hpp-source.html617
-rw-r--r--docs/XMPToolkit/TXMPMeta_8hpp.html33
-rw-r--r--docs/XMPToolkit/TXMPMeta_8incl__cpp.html33
-rw-r--r--docs/XMPToolkit/TXMPMeta_8incl__cpp__incl.pngbin0 -> 2068 bytes
-rw-r--r--docs/XMPToolkit/TXMPUtils_8hpp-source.html360
-rw-r--r--docs/XMPToolkit/TXMPUtils_8hpp.html33
-rw-r--r--docs/XMPToolkit/TXMPUtils_8incl__cpp.html33
-rw-r--r--docs/XMPToolkit/TXMPUtils_8incl__cpp__incl.pngbin0 -> 2101 bytes
-rw-r--r--docs/XMPToolkit/XMP_8incl__cpp.html35
-rw-r--r--docs/XMPToolkit/XMP_8incl__cpp__incl.pngbin0 -> 691 bytes
-rw-r--r--docs/XMPToolkit/XMP__Const_8h-source.html661
-rw-r--r--docs/XMPToolkit/XMP__Const_8h.html190
-rw-r--r--docs/XMPToolkit/XMP__Const_8h__incl.pngbin0 -> 1243 bytes
-rw-r--r--docs/XMPToolkit/annotated.html31
-rw-r--r--docs/XMPToolkit/classTXMPFiles-members.html40
-rw-r--r--docs/XMPToolkit/classTXMPFiles.html527
-rw-r--r--docs/XMPToolkit/classTXMPIterator-members.html32
-rw-r--r--docs/XMPToolkit/classTXMPIterator.html328
-rw-r--r--docs/XMPToolkit/classTXMPMeta-members.html93
-rw-r--r--docs/XMPToolkit/classTXMPMeta.html2781
-rw-r--r--docs/XMPToolkit/classTXMPUtils-members.html63
-rw-r--r--docs/XMPToolkit/classTXMPUtils.html1540
-rw-r--r--docs/XMPToolkit/doxygen.css358
-rw-r--r--docs/XMPToolkit/doxygen.pngbin0 -> 1281 bytes
-rw-r--r--docs/XMPToolkit/files.html31
-rw-r--r--docs/XMPToolkit/functions.html281
-rw-r--r--docs/XMPToolkit/functions_func.html281
-rw-r--r--docs/XMPToolkit/graph_legend.dot22
-rw-r--r--docs/XMPToolkit/graph_legend.html81
-rw-r--r--docs/XMPToolkit/graph_legend.pngbin0 -> 4256 bytes
-rw-r--r--docs/XMPToolkit/group__Transition.html259
-rw-r--r--docs/XMPToolkit/index.html112
-rw-r--r--docs/XMPToolkit/modules.html22
-rw-r--r--docs/XMPToolkit/structXMP__DateTime-members.html25
-rw-r--r--docs/XMPToolkit/structXMP__DateTime.html59
-rw-r--r--docs/XMPToolkit/tab_b.gifbin0 -> 35 bytes
-rw-r--r--docs/XMPToolkit/tab_l.gifbin0 -> 706 bytes
-rw-r--r--docs/XMPToolkit/tab_r.gifbin0 -> 2585 bytes
-rw-r--r--docs/XMPToolkit/tabs.css102
-rw-r--r--java/XMPCore/.classpath6
-rw-r--r--java/XMPCore/.project17
-rw-r--r--java/XMPCore/build.xml176
-rw-r--r--java/XMPCore/docs/allclasses-frame.html70
-rw-r--r--java/XMPCore/docs/allclasses-noframe.html70
-rw-r--r--java/XMPCore/docs/com/adobe/xmp/XMPConst.html1227
-rw-r--r--java/XMPCore/docs/com/adobe/xmp/XMPDateTime.html624
-rw-r--r--java/XMPCore/docs/com/adobe/xmp/XMPDateTimeFactory.html381
-rw-r--r--java/XMPCore/docs/com/adobe/xmp/XMPError.html423
-rw-r--r--java/XMPCore/docs/com/adobe/xmp/XMPException.html300
-rw-r--r--java/XMPCore/docs/com/adobe/xmp/XMPIterator.html304
-rw-r--r--java/XMPCore/docs/com/adobe/xmp/XMPMeta.html2301
-rw-r--r--java/XMPCore/docs/com/adobe/xmp/XMPMetaFactory.html571
-rw-r--r--java/XMPCore/docs/com/adobe/xmp/XMPPathFactory.html427
-rw-r--r--java/XMPCore/docs/com/adobe/xmp/XMPSchemaRegistry.html547
-rw-r--r--java/XMPCore/docs/com/adobe/xmp/XMPUtils.html770
-rw-r--r--java/XMPCore/docs/com/adobe/xmp/XMPVersionInfo.html316
-rw-r--r--java/XMPCore/docs/com/adobe/xmp/class-use/XMPConst.html140
-rw-r--r--java/XMPCore/docs/com/adobe/xmp/class-use/XMPDateTime.html311
-rw-r--r--java/XMPCore/docs/com/adobe/xmp/class-use/XMPDateTimeFactory.html140
-rw-r--r--java/XMPCore/docs/com/adobe/xmp/class-use/XMPError.html140
-rw-r--r--java/XMPCore/docs/com/adobe/xmp/class-use/XMPException.html989
-rw-r--r--java/XMPCore/docs/com/adobe/xmp/class-use/XMPIterator.html194
-rw-r--r--java/XMPCore/docs/com/adobe/xmp/class-use/XMPMeta.html335
-rw-r--r--java/XMPCore/docs/com/adobe/xmp/class-use/XMPMetaFactory.html140
-rw-r--r--java/XMPCore/docs/com/adobe/xmp/class-use/XMPPathFactory.html140
-rw-r--r--java/XMPCore/docs/com/adobe/xmp/class-use/XMPSchemaRegistry.html176
-rw-r--r--java/XMPCore/docs/com/adobe/xmp/class-use/XMPUtils.html140
-rw-r--r--java/XMPCore/docs/com/adobe/xmp/class-use/XMPVersionInfo.html176
-rw-r--r--java/XMPCore/docs/com/adobe/xmp/options/AliasOptions.html591
-rw-r--r--java/XMPCore/docs/com/adobe/xmp/options/IteratorOptions.html534
-rw-r--r--java/XMPCore/docs/com/adobe/xmp/options/Options.html502
-rw-r--r--java/XMPCore/docs/com/adobe/xmp/options/ParseOptions.html508
-rw-r--r--java/XMPCore/docs/com/adobe/xmp/options/PropertyOptions.html1171
-rw-r--r--java/XMPCore/docs/com/adobe/xmp/options/SerializeOptions.html1080
-rw-r--r--java/XMPCore/docs/com/adobe/xmp/options/class-use/AliasOptions.html262
-rw-r--r--java/XMPCore/docs/com/adobe/xmp/options/class-use/IteratorOptions.html239
-rw-r--r--java/XMPCore/docs/com/adobe/xmp/options/class-use/Options.html210
-rw-r--r--java/XMPCore/docs/com/adobe/xmp/options/class-use/ParseOptions.html249
-rw-r--r--java/XMPCore/docs/com/adobe/xmp/options/class-use/PropertyOptions.html534
-rw-r--r--java/XMPCore/docs/com/adobe/xmp/options/class-use/SerializeOptions.html321
-rw-r--r--java/XMPCore/docs/com/adobe/xmp/options/package-frame.html42
-rw-r--r--java/XMPCore/docs/com/adobe/xmp/options/package-summary.html200
-rw-r--r--java/XMPCore/docs/com/adobe/xmp/options/package-tree.html151
-rw-r--r--java/XMPCore/docs/com/adobe/xmp/options/package-use.html270
-rw-r--r--java/XMPCore/docs/com/adobe/xmp/package-frame.html72
-rw-r--r--java/XMPCore/docs/com/adobe/xmp/package-summary.html240
-rw-r--r--java/XMPCore/docs/com/adobe/xmp/package-tree.html165
-rw-r--r--java/XMPCore/docs/com/adobe/xmp/package-use.html221
-rw-r--r--java/XMPCore/docs/com/adobe/xmp/properties/XMPAliasInfo.html276
-rw-r--r--java/XMPCore/docs/com/adobe/xmp/properties/XMPProperty.html257
-rw-r--r--java/XMPCore/docs/com/adobe/xmp/properties/XMPPropertyInfo.html297
-rw-r--r--java/XMPCore/docs/com/adobe/xmp/properties/class-use/XMPAliasInfo.html193
-rw-r--r--java/XMPCore/docs/com/adobe/xmp/properties/class-use/XMPProperty.html252
-rw-r--r--java/XMPCore/docs/com/adobe/xmp/properties/class-use/XMPPropertyInfo.html140
-rw-r--r--java/XMPCore/docs/com/adobe/xmp/properties/package-frame.html36
-rw-r--r--java/XMPCore/docs/com/adobe/xmp/properties/package-summary.html179
-rw-r--r--java/XMPCore/docs/com/adobe/xmp/properties/package-tree.html149
-rw-r--r--java/XMPCore/docs/com/adobe/xmp/properties/package-use.html191
-rw-r--r--java/XMPCore/docs/constant-values.html866
-rw-r--r--java/XMPCore/docs/deprecated-list.html157
-rw-r--r--java/XMPCore/docs/help-doc.html219
-rw-r--r--java/XMPCore/docs/index-files/index-1.html182
-rw-r--r--java/XMPCore/docs/index-files/index-10.html147
-rw-r--r--java/XMPCore/docs/index-files/index-11.html141
-rw-r--r--java/XMPCore/docs/index-files/index-12.html246
-rw-r--r--java/XMPCore/docs/index-files/index-13.html150
-rw-r--r--java/XMPCore/docs/index-files/index-14.html182
-rw-r--r--java/XMPCore/docs/index-files/index-15.html141
-rw-r--r--java/XMPCore/docs/index-files/index-16.html162
-rw-r--r--java/XMPCore/docs/index-files/index-17.html409
-rw-r--r--java/XMPCore/docs/index-files/index-18.html183
-rw-r--r--java/XMPCore/docs/index-files/index-19.html147
-rw-r--r--java/XMPCore/docs/index-files/index-2.html171
-rw-r--r--java/XMPCore/docs/index-files/index-20.html141
-rw-r--r--java/XMPCore/docs/index-files/index-21.html157
-rw-r--r--java/XMPCore/docs/index-files/index-3.html225
-rw-r--r--java/XMPCore/docs/index-files/index-4.html177
-rw-r--r--java/XMPCore/docs/index-files/index-5.html159
-rw-r--r--java/XMPCore/docs/index-files/index-6.html150
-rw-r--r--java/XMPCore/docs/index-files/index-7.html362
-rw-r--r--java/XMPCore/docs/index-files/index-8.html150
-rw-r--r--java/XMPCore/docs/index-files/index-9.html234
-rw-r--r--java/XMPCore/docs/index.html37
-rw-r--r--java/XMPCore/docs/overview-frame.html46
-rw-r--r--java/XMPCore/docs/overview-summary.html161
-rw-r--r--java/XMPCore/docs/overview-tree.html168
-rw-r--r--java/XMPCore/docs/package-list3
-rw-r--r--java/XMPCore/docs/resources/inherit.gifbin0 -> 57 bytes
-rw-r--r--java/XMPCore/docs/serialized-form.html177
-rw-r--r--java/XMPCore/docs/stylesheet.css29
-rw-r--r--java/XMPCore/src/com/adobe/xmp/XMPConst.java159
-rw-r--r--java/XMPCore/src/com/adobe/xmp/XMPDateTime.java98
-rw-r--r--java/XMPCore/src/com/adobe/xmp/XMPDateTimeFactory.java142
-rw-r--r--java/XMPCore/src/com/adobe/xmp/XMPError.java44
-rw-r--r--java/XMPCore/src/com/adobe/xmp/XMPException.java55
-rw-r--r--java/XMPCore/src/com/adobe/xmp/XMPIterator.java82
-rw-r--r--java/XMPCore/src/com/adobe/xmp/XMPMeta.java1152
-rw-r--r--java/XMPCore/src/com/adobe/xmp/XMPMetaFactory.java327
-rw-r--r--java/XMPCore/src/com/adobe/xmp/XMPPathFactory.java286
-rw-r--r--java/XMPCore/src/com/adobe/xmp/XMPSchemaRegistry.java235
-rw-r--r--java/XMPCore/src/com/adobe/xmp/XMPUtils.java506
-rw-r--r--java/XMPCore/src/com/adobe/xmp/XMPVersionInfo.java45
-rw-r--r--java/XMPCore/src/com/adobe/xmp/impl/Base64.java251
-rw-r--r--java/XMPCore/src/com/adobe/xmp/impl/ByteBuffer.java326
-rw-r--r--java/XMPCore/src/com/adobe/xmp/impl/CountOutputStream.java79
-rw-r--r--java/XMPCore/src/com/adobe/xmp/impl/FixASCIIControlsReader.java214
-rw-r--r--java/XMPCore/src/com/adobe/xmp/impl/ISO8601Converter.java503
-rw-r--r--java/XMPCore/src/com/adobe/xmp/impl/Latin1Converter.java197
-rw-r--r--java/XMPCore/src/com/adobe/xmp/impl/ParameterAsserts.java153
-rw-r--r--java/XMPCore/src/com/adobe/xmp/impl/ParseRDF.java1349
-rw-r--r--java/XMPCore/src/com/adobe/xmp/impl/QName.java80
-rw-r--r--java/XMPCore/src/com/adobe/xmp/impl/Utils.java511
-rw-r--r--java/XMPCore/src/com/adobe/xmp/impl/XMPDateTimeImpl.java303
-rw-r--r--java/XMPCore/src/com/adobe/xmp/impl/XMPIteratorImpl.java598
-rw-r--r--java/XMPCore/src/com/adobe/xmp/impl/XMPMetaImpl.java1389
-rw-r--r--java/XMPCore/src/com/adobe/xmp/impl/XMPMetaParser.java361
-rw-r--r--java/XMPCore/src/com/adobe/xmp/impl/XMPNode.java921
-rw-r--r--java/XMPCore/src/com/adobe/xmp/impl/XMPNodeUtils.java930
-rw-r--r--java/XMPCore/src/com/adobe/xmp/impl/XMPNormalizer.java696
-rw-r--r--java/XMPCore/src/com/adobe/xmp/impl/XMPSchemaRegistryImpl.java467
-rw-r--r--java/XMPCore/src/com/adobe/xmp/impl/XMPSerializerHelper.java102
-rw-r--r--java/XMPCore/src/com/adobe/xmp/impl/XMPSerializerRDF.java1295
-rw-r--r--java/XMPCore/src/com/adobe/xmp/impl/XMPUtilsImpl.java1167
-rw-r--r--java/XMPCore/src/com/adobe/xmp/impl/package.html11
-rw-r--r--java/XMPCore/src/com/adobe/xmp/impl/xpath/XMPPath.java106
-rw-r--r--java/XMPCore/src/com/adobe/xmp/impl/xpath/XMPPathParser.java529
-rw-r--r--java/XMPCore/src/com/adobe/xmp/impl/xpath/XMPPathSegment.java147
-rw-r--r--java/XMPCore/src/com/adobe/xmp/impl/xpath/package.html12
-rw-r--r--java/XMPCore/src/com/adobe/xmp/options/AliasOptions.java186
-rw-r--r--java/XMPCore/src/com/adobe/xmp/options/IteratorOptions.java148
-rw-r--r--java/XMPCore/src/com/adobe/xmp/options/Options.java290
-rw-r--r--java/XMPCore/src/com/adobe/xmp/options/ParseOptions.java150
-rw-r--r--java/XMPCore/src/com/adobe/xmp/options/PropertyOptions.java453
-rw-r--r--java/XMPCore/src/com/adobe/xmp/options/SerializeOptions.java461
-rw-r--r--java/XMPCore/src/com/adobe/xmp/options/package.html20
-rw-r--r--java/XMPCore/src/com/adobe/xmp/package.html11
-rw-r--r--java/XMPCore/src/com/adobe/xmp/properties/XMPAliasInfo.java39
-rw-r--r--java/XMPCore/src/com/adobe/xmp/properties/XMPProperty.java40
-rw-r--r--java/XMPCore/src/com/adobe/xmp/properties/XMPPropertyInfo.java45
-rw-r--r--java/XMPCore/src/com/adobe/xmp/properties/package.html13
-rw-r--r--java/XMPCore/src/com/adobe/xmp/version.properties15
-rw-r--r--java/XMPCoreCoverage/.classpath7
-rw-r--r--java/XMPCoreCoverage/.project17
-rw-r--r--java/XMPCoreCoverage/src/samples/XMPCoreCoverage.java1073
-rw-r--r--java/XMPCoreCoverage/src/samples/XMPCoreCoverageConst.java280
-rw-r--r--java/readme.txt39
-rw-r--r--public/include/TXMPFiles.hpp418
-rw-r--r--public/include/TXMPIterator.hpp205
-rw-r--r--public/include/TXMPMeta.hpp1599
-rw-r--r--public/include/TXMPUtils.hpp845
-rw-r--r--public/include/XMP.hpp98
-rw-r--r--public/include/XMP.incl_cpp69
-rw-r--r--public/include/XMP_Const.h913
-rw-r--r--public/include/XMP_Environment.h121
-rw-r--r--public/include/XMP_Version.h45
-rw-r--r--public/include/client-glue/TXMPFiles.incl_cpp347
-rw-r--r--public/include/client-glue/TXMPIterator.incl_cpp226
-rw-r--r--public/include/client-glue/TXMPMeta.incl_cpp927
-rw-r--r--public/include/client-glue/TXMPUtils.incl_cpp491
-rw-r--r--public/include/client-glue/WXMPFiles.hpp155
-rw-r--r--public/include/client-glue/WXMPIterator.hpp83
-rw-r--r--public/include/client-glue/WXMPMeta.hpp610
-rw-r--r--public/include/client-glue/WXMPUtils.hpp322
-rw-r--r--public/include/client-glue/WXMP_Common.hpp110
-rw-r--r--samples/BlueSquares/BlueSquare.aibin0 -> 1186535 bytes
-rw-r--r--samples/BlueSquares/BlueSquare.avibin0 -> 132262 bytes
-rw-r--r--samples/BlueSquares/BlueSquare.eps87
-rw-r--r--samples/BlueSquares/BlueSquare.inddbin0 -> 757760 bytes
-rw-r--r--samples/BlueSquares/BlueSquare.jpgbin0 -> 24205 bytes
-rw-r--r--samples/BlueSquares/BlueSquare.movbin0 -> 47641 bytes
-rw-r--r--samples/BlueSquares/BlueSquare.mp3bin0 -> 130244 bytes
-rw-r--r--samples/BlueSquares/BlueSquare.pdfbin0 -> 10806 bytes
-rwxr-xr-xsamples/BlueSquares/BlueSquare.pngbin0 -> 5998 bytes
-rw-r--r--samples/BlueSquares/BlueSquare.psdbin0 -> 36014 bytes
-rw-r--r--samples/BlueSquares/BlueSquare.tifbin0 -> 259384 bytes
-rw-r--r--samples/BlueSquares/BlueSquare.wavbin0 -> 683118 bytes
-rw-r--r--samples/build/gcc/XMPSamples.mak178
-rw-r--r--samples/build/vsnet/DumpMainXMP.vcproj309
-rw-r--r--samples/build/vsnet/DumpScannedXMP.vcproj230
-rw-r--r--samples/build/vsnet/XMPCoreCoverage.vcproj226
-rw-r--r--samples/build/vsnet/XMPFilesCoverage.vcproj319
-rw-r--r--samples/build/vsnet/XMPSamples.sln37
-rw-r--r--samples/build/xcode/XMPSamples-Common.xcconfig39
-rw-r--r--samples/build/xcode/XMPSamples-Debug.xcconfig15
-rw-r--r--samples/build/xcode/XMPSamples-Release.xcconfig15
-rw-r--r--samples/build/xcode/XMPSamples.xcodeproj/project.pbxproj705
-rw-r--r--samples/source/DumpMainXMP.cpp158
-rw-r--r--samples/source/DumpScannedXMP.cpp188
-rw-r--r--samples/source/XMPCoreCoverage.cpp1955
-rw-r--r--samples/source/XMPFilesCoverage.cpp322
-rw-r--r--samples/source/XMPScanner.cpp1470
-rw-r--r--samples/source/XMPScanner.hpp332
-rw-r--r--source/XMPCore/ExpatAdapter.cpp465
-rw-r--r--source/XMPCore/ExpatAdapter.hpp38
-rw-r--r--source/XMPCore/ParseRDF.cpp1344
-rw-r--r--source/XMPCore/WXMPIterator.cpp186
-rw-r--r--source/XMPCore/WXMPMeta.cpp1285
-rw-r--r--source/XMPCore/WXMPUtils.cpp624
-rw-r--r--source/XMPCore/XMLParserAdapter.hpp53
-rw-r--r--source/XMPCore/XMPCore_Impl.cpp1507
-rw-r--r--source/XMPCore/XMPCore_Impl.hpp631
-rw-r--r--source/XMPCore/XMPIterator.cpp735
-rw-r--r--source/XMPCore/XMPIterator.hpp148
-rw-r--r--source/XMPCore/XMPMeta-GetSet.cpp1209
-rw-r--r--source/XMPCore/XMPMeta-Parse.cpp1290
-rw-r--r--source/XMPCore/XMPMeta-Serialize.cpp1352
-rw-r--r--source/XMPCore/XMPMeta.cpp1471
-rw-r--r--source/XMPCore/XMPMeta.hpp414
-rw-r--r--source/XMPCore/XMPUtils-FileInfo.cpp1257
-rw-r--r--source/XMPCore/XMPUtils.cpp2123
-rw-r--r--source/XMPCore/XMPUtils.hpp220
-rw-r--r--source/XMPFiles/FileHandlers/AVI_Handler.cpp432
-rw-r--r--source/XMPFiles/FileHandlers/AVI_Handler.hpp53
-rw-r--r--source/XMPFiles/FileHandlers/Basic_Handler.cpp247
-rw-r--r--source/XMPFiles/FileHandlers/Basic_Handler.hpp103
-rw-r--r--source/XMPFiles/FileHandlers/InDesign_Handler.cpp423
-rw-r--r--source/XMPFiles/FileHandlers/InDesign_Handler.hpp60
-rw-r--r--source/XMPFiles/FileHandlers/JPEG_Handler.cpp997
-rw-r--r--source/XMPFiles/FileHandlers/JPEG_Handler.hpp95
-rw-r--r--source/XMPFiles/FileHandlers/MOV_Handler.cpp312
-rw-r--r--source/XMPFiles/FileHandlers/MOV_Handler.hpp76
-rw-r--r--source/XMPFiles/FileHandlers/MP3_Handler.cpp339
-rw-r--r--source/XMPFiles/FileHandlers/MP3_Handler.hpp56
-rw-r--r--source/XMPFiles/FileHandlers/MPEG_Handler.cpp234
-rw-r--r--source/XMPFiles/FileHandlers/MPEG_Handler.hpp57
-rw-r--r--source/XMPFiles/FileHandlers/PNG_Handler.cpp281
-rw-r--r--source/XMPFiles/FileHandlers/PNG_Handler.hpp60
-rw-r--r--source/XMPFiles/FileHandlers/PSD_Handler.cpp457
-rw-r--r--source/XMPFiles/FileHandlers/PSD_Handler.hpp74
-rw-r--r--source/XMPFiles/FileHandlers/PostScript_Handler.cpp578
-rw-r--r--source/XMPFiles/FileHandlers/PostScript_Handler.hpp63
-rw-r--r--source/XMPFiles/FileHandlers/Scanner_Handler.cpp338
-rw-r--r--source/XMPFiles/FileHandlers/Scanner_Handler.hpp42
-rw-r--r--source/XMPFiles/FileHandlers/TIFF_Handler.cpp379
-rw-r--r--source/XMPFiles/FileHandlers/TIFF_Handler.hpp70
-rw-r--r--source/XMPFiles/FileHandlers/Trivial_Handler.cpp66
-rw-r--r--source/XMPFiles/FileHandlers/Trivial_Handler.hpp47
-rw-r--r--source/XMPFiles/FileHandlers/WAV_Handler.cpp648
-rw-r--r--source/XMPFiles/FileHandlers/WAV_Handler.hpp71
-rw-r--r--source/XMPFiles/FormatSupport/EndianUtils.hpp422
-rw-r--r--source/XMPFiles/FormatSupport/ID3_Support.cpp1137
-rw-r--r--source/XMPFiles/FormatSupport/ID3_Support.hpp39
-rw-r--r--source/XMPFiles/FormatSupport/IPTC_Support.cpp703
-rw-r--r--source/XMPFiles/FormatSupport/IPTC_Support.hpp302
-rw-r--r--source/XMPFiles/FormatSupport/PNG_Support.cpp335
-rw-r--r--source/XMPFiles/FormatSupport/PNG_Support.hpp74
-rw-r--r--source/XMPFiles/FormatSupport/PSIR_FileWriter.cpp572
-rw-r--r--source/XMPFiles/FormatSupport/PSIR_MemoryReader.cpp95
-rw-r--r--source/XMPFiles/FormatSupport/PSIR_Support.hpp289
-rw-r--r--source/XMPFiles/FormatSupport/QuickTime_Support.cpp79
-rw-r--r--source/XMPFiles/FormatSupport/QuickTime_Support.hpp27
-rw-r--r--source/XMPFiles/FormatSupport/RIFF_Support.cpp491
-rw-r--r--source/XMPFiles/FormatSupport/RIFF_Support.hpp172
-rw-r--r--source/XMPFiles/FormatSupport/ReconcileIPTC.cpp829
-rw-r--r--source/XMPFiles/FormatSupport/ReconcileLegacy.cpp191
-rw-r--r--source/XMPFiles/FormatSupport/ReconcileLegacy.hpp298
-rw-r--r--source/XMPFiles/FormatSupport/ReconcileTIFF.cpp2416
-rw-r--r--source/XMPFiles/FormatSupport/Reconcile_Impl.cpp395
-rw-r--r--source/XMPFiles/FormatSupport/Reconcile_Impl.hpp63
-rw-r--r--source/XMPFiles/FormatSupport/TIFF_FileWriter.cpp1966
-rw-r--r--source/XMPFiles/FormatSupport/TIFF_MemoryReader.cpp610
-rw-r--r--source/XMPFiles/FormatSupport/TIFF_Support.cpp626
-rw-r--r--source/XMPFiles/FormatSupport/TIFF_Support.hpp887
-rw-r--r--source/XMPFiles/FormatSupport/XMPScanner.cpp1478
-rw-r--r--source/XMPFiles/FormatSupport/XMPScanner.hpp330
-rw-r--r--source/XMPFiles/WXMPFiles.cpp320
-rw-r--r--source/XMPFiles/XMPFiles.cpp1005
-rw-r--r--source/XMPFiles/XMPFiles.hpp224
-rw-r--r--source/XMPFiles/XMPFiles_Impl.cpp1210
-rw-r--r--source/XMPFiles/XMPFiles_Impl.hpp517
-rw-r--r--source/common/UnicodeConversions.cpp1665
-rw-r--r--source/common/UnicodeConversions.hpp121
-rw-r--r--source/common/UnicodeInlines.incl_cpp129
-rw-r--r--third-party/MD5/MD5.cpp325
-rw-r--r--third-party/MD5/MD5.h46
-rw-r--r--third-party/QTDevWin/ReadMe.txt12
-rw-r--r--third-party/expat/ReadMe.txt38
342 files changed, 115327 insertions, 0 deletions
diff --git a/build/XMP_BuildInfo.h b/build/XMP_BuildInfo.h
new file mode 100644
index 0000000..6261f3c
--- /dev/null
+++ b/build/XMP_BuildInfo.h
@@ -0,0 +1,36 @@
+#ifndef __XMP_BuildInfo_h__
+#define __XMP_BuildInfo_h__ 1
+
+/* --------------------------------------------------------------------------------------------- */
+/* ** IMPORTANT ** This file must be usable by strict ANSI C compilers. No "//" comments, etc. */
+/* --------------------------------------------------------------------------------------------- */
+
+/*
+// =================================================================================================
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+*/
+
+
+/*
+// =================================================================================================
+// This file provides build numbers that are set automatically by the external build system. This is
+// in contrast to the manual version numbers of XMP_ChangeLog.h.
+//
+// The value of kXMP_BuildDate is set to the date of the build, in some reasonable format. It would
+// be nice if the month used a name instead of a number and if the year has 4 digits. But it isn't
+// worth going to great lengths for this, a numeric date is OK.
+
+// The value of kXMP_BuildNumber is set to some number that is meaningful to the build system, such
+// as a Perforce changelist number.
+// =================================================================================================
+*/
+
+#define kXMP_Copyright Copyright (c) 2002-2007, Adobe Systems Incorporated
+#define kXMP_CopyrightStr "Copyright (c) 2002-2007, Adobe Systems Incorporated"
+
+#endif /* __XMP_BuildInfo_h__ */
diff --git a/build/gcc/XMPCore.mak b/build/gcc/XMPCore.mak
new file mode 100644
index 0000000..cd37bae
--- /dev/null
+++ b/build/gcc/XMPCore.mak
@@ -0,0 +1,213 @@
+# ==================================================================================================
+# Copyright 2002-2004 Adobe Systems Incorporated
+# All Rights Reserved.
+#
+# NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+# of the Adobe license agreement accompanying it.
+# ==================================================================================================
+
+# ==================================================================================================
+
+# Define internal use variables.
+
+Error =
+TargetOS = ${OS}
+
+ifeq "${TargetOS}" ""
+ TargetOS = ${os}
+endif
+
+ifeq "${TargetOS}" ""
+ TargetOS = ${MACHTYPE}${OSTYPE}
+endif
+
+ifeq "${TargetOS}" "i386linux" # Linux ${MACHTYPE}${OSTYPE} is i386linux.
+ TargetOS = i80386linux
+endif
+
+ifeq "${TargetOS}" "linux"
+ TargetOS = i80386linux
+endif
+
+ifeq "${TargetOS}" "solaris"
+ TargetOS = sparcsolaris
+endif
+
+ifneq "${TargetOS}" "i80386linux"
+ ifneq "${TargetOS}" "sparcsolaris"
+ Error += Invalid target OS "${TargetOS}"
+ endif
+endif
+
+TargetStage = ${STAGE}
+
+ifeq "${TargetStage}" ""
+ TargetStage = ${stage}
+endif
+
+ifeq "${TargetStage}" ""
+ TargetStage = debug
+endif
+
+ifneq "${TargetStage}" "debug"
+ ifneq "${TargetStage}" "release"
+ Error += Invalid target stage "${TargetStage}"
+ endif
+endif
+
+ifeq "${TargetStage}" "debug"
+ LibSuffix = StaticDebug
+endif
+
+ifeq "${TargetStage}" "release"
+ LibSuffix = StaticRelease
+endif
+
+BuildRoot = ../..
+TargetRoot = ${BuildRoot}/public/libraries/${TargetOS}/${TargetStage}
+TempRoot = ${BuildRoot}/intermediate/${TargetOS}/${TargetStage}
+
+HeaderRoot = ${BuildRoot}/public/include
+SourceRoot = ${BuildRoot}/source
+ExpatRoot = ${BuildRoot}/third-party/expat
+MD5Root = ${BuildRoot}/third-party/MD5
+
+LibName = ${TargetRoot}/libXMPCore${LibSuffix}.a
+
+# ==================================================================================================
+
+CC = gcc
+CPP = gcc -x c++
+AR = ar -rs
+
+CPPFLAGS = -Wno-multichar -Wno-implicit -Wno-ctor-dtor-privacy -funsigned-char -fexceptions
+CPPFLAGS += -DUNIX_ENV=1 -DXMP_IMPL=1 -DXMP_ClientBuild=0 -D_FILE_OFFSET_BITS=64 -DHAVE_EXPAT_CONFIG_H=1 -DXML_STATIC=1
+
+ifeq "${TargetOS}" "i80386linux"
+ CPPFLAGS += -mtune=i686
+endif
+
+ifeq "${TargetOS}" "sparcsolaris"
+ CPPFLAGS += -mtune=ultrasparc
+endif
+
+ifeq "$(TargetStage)" "debug"
+ CPPFLAGS += -DDEBUG=1 -D_DEBUG=1 -g -O0
+endif
+
+ifeq "$(TargetStage)" "release"
+ CPPFLAGS += -DNDEBUG=1 -O2 -Os
+endif
+
+# ==================================================================================================
+
+CPPObjs = $(foreach objs,${CPPSources:.cpp=.o},${TempRoot}/$(objs))
+CCObjs = $(foreach objs,${CCSources:.c=.o},${TempRoot}/$(objs))
+
+vpath %.incl_cpp \
+ ${HeaderRoot}: \
+ ${HeaderRoot}/client-glue:
+
+vpath %.cpp \
+ ${SourceRoot}/XMPCore: \
+ ${SourceRoot}/common: \
+ ${HeaderRoot}: \
+ ${HeaderRoot}/client-glue: \
+ ${ExpatRoot}/lib: \
+ ${MD5Root}:
+
+vpath %.c \
+ ${SourceRoot}/XMPCore: \
+ ${HeaderRoot}: \
+ ${HeaderRoot}/client-glue: \
+ ${ExpatRoot}/lib:
+
+CPPSources = \
+ XMPMeta.cpp \
+ XMPMeta-GetSet.cpp \
+ XMPMeta-Parse.cpp \
+ XMPMeta-Serialize.cpp \
+ XMPIterator.cpp \
+ XMPUtils.cpp \
+ XMPUtils-FileInfo.cpp \
+ XMPCore_Impl.cpp \
+ ExpatAdapter.cpp \
+ ParseRDF.cpp \
+ UnicodeConversions.cpp \
+ MD5.cpp \
+ WXMPMeta.cpp \
+ WXMPIterator.cpp \
+ WXMPUtils.cpp
+
+CCSources = \
+ xmlparse.c \
+ xmlrole.c \
+ xmltok.c
+
+Includes = \
+ -I${HeaderRoot} \
+ -I${SourceRoot}/XMPCore \
+ -I${SourceRoot}/common \
+ -I${BuildRoot}/build \
+ -I${BuildRoot}/build/gcc/${TargetOS} \
+ -I${ExpatRoot}/lib \
+ -I${MD5Root}
+
+.SUFFIXES: # Delete the default suffixes
+.SUFFIXES: .o .c .cpp # Define our suffix list
+
+# ==================================================================================================
+
+${TempRoot}/%.o : %.c
+ @echo ""
+ @echo "Compiling $<"
+ ${CC} ${CPPFLAGS} ${Includes} -c $< -o $@
+
+${TempRoot}/%.o : %.cpp
+ @echo ""
+ @echo "Compiling $<"
+ ${CPP} ${CPPFLAGS} ${Includes} -c $< -o $@
+
+# ==================================================================================================
+
+.PHONY: all msg create_dirs
+
+all : msg create_dirs ${LibName}
+
+msg :
+ifeq "${Error}" ""
+ @echo ""
+ @echo Building XMP toolkit for ${TargetOS} ${TargetStage}
+else
+ @echo ""
+ @echo "Error: ${Error}"
+ @echo ""
+ @echo "# To build the XMP Toolkit :"
+ @echo "# make -f XMPCore.mak [OS=<os>] [STAGE=<stage>]"
+ @echo "# where"
+ @echo "# OS = i80386linux | sparcsolaris"
+ @echo "# STAGE = debug | release"
+ @echo "#"
+ @echo "# The OS and STAGE symbols can also be lowercase, os and stage."
+ @echo "# This makefile is only for Linux and Solaris, AIX and HPUX do"
+ @echo "# not use gcc, their makefiles are in other build folders. If"
+ @echo "# the OS is omitted it will try to default from the OSTYPE and"
+ @echo "# MACHTYPE environment variables. If the stage is omitted it"
+ @echo "# defaults to debug."
+ @echo ""
+ exit 1
+endif
+
+create_dirs :
+ mkdir -p ${TempRoot}
+ mkdir -p ${TargetRoot}
+
+${LibName} : ${CCObjs} ${CPPObjs}
+ @echo ""
+ @echo "Linking $@"
+ rm -f $@
+ ${AR} $@ $?
+ @echo ""
+
+clean : msg
+ rm -f ${TempRoot}/* ${TargetRoot}/*
diff --git a/build/gcc/i80386linux/expat_config.h b/build/gcc/i80386linux/expat_config.h
new file mode 100644
index 0000000..18fe7bc
--- /dev/null
+++ b/build/gcc/i80386linux/expat_config.h
@@ -0,0 +1,95 @@
+/* expat_config.h. Generated by configure. */
+/* expat_config.h.in. Generated from configure.in by autoheader. */
+
+/* *** Tweaked by hand for 32 bit x86 Linux builds */
+
+/* 1234 = LIL_ENDIAN, 4321 = BIGENDIAN */
+#define BYTEORDER 1234
+
+/* Define to 1 if you have the `bcopy' function. */
+#define HAVE_BCOPY 1
+
+/* Define to 1 if you have the <check.h> header file. */
+/* #undef HAVE_CHECK_H */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have the `getpagesize' function. */
+#define HAVE_GETPAGESIZE 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `memmove' function. */
+#define HAVE_MEMMOVE 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have a working `mmap' system call. */
+#define HAVE_MMAP 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "expat-bugs@mail.libexpat.org"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "expat"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "expat 1.95.8"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "expat"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "1.95.8"
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* whether byteorder is bigendian */
+/* #undef WORDS_BIGENDIAN */
+
+/* Define to specify how much context to retain around the current parse
+ point. */
+#define XML_CONTEXT_BYTES 1024
+
+/* Define to make parameter entity parsing functionality available. */
+/* #define XML_DTD 1 */
+
+/* Define to make XML Namespaces functionality available. */
+#define XML_NS 1
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to `long' if <sys/types.h> does not define. */
+/* #undef off_t */
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+/* #undef size_t */
diff --git a/build/gcc/sparcsolaris/expat_config.h b/build/gcc/sparcsolaris/expat_config.h
new file mode 100644
index 0000000..48bdd2e
--- /dev/null
+++ b/build/gcc/sparcsolaris/expat_config.h
@@ -0,0 +1,95 @@
+/* expat_config.h. Generated by configure. */
+/* expat_config.h.in. Generated from configure.in by autoheader. */
+
+/* *** Tweaked by hand for 32 bit Sparc Solaris builds */
+
+/* 1234 = LIL_ENDIAN, 4321 = BIGENDIAN */
+#define BYTEORDER 4321
+
+/* Define to 1 if you have the `bcopy' function. */
+#define HAVE_BCOPY 1
+
+/* Define to 1 if you have the <check.h> header file. */
+/* #undef HAVE_CHECK_H */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have the `getpagesize' function. */
+#define HAVE_GETPAGESIZE 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `memmove' function. */
+#define HAVE_MEMMOVE 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have a working `mmap' system call. */
+#define HAVE_MMAP 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+/* #undef HAVE_STDINT_H */
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "expat-bugs@mail.libexpat.org"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "expat"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "expat 1.95.8"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "expat"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "1.95.8"
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* whether byteorder is bigendian */
+#define WORDS_BIGENDIAN 1
+
+/* Define to specify how much context to retain around the current parse
+ point. */
+#define XML_CONTEXT_BYTES 1024
+
+/* Define to make parameter entity parsing functionality available. */
+/* #define XML_DTD 1 */
+
+/* Define to make XML Namespaces functionality available. */
+#define XML_NS 1
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to `long' if <sys/types.h> does not define. */
+/* #undef off_t */
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+/* #undef size_t */
diff --git a/build/vsnet/XMPCore.vcproj b/build/vsnet/XMPCore.vcproj
new file mode 100644
index 0000000..6b76f57
--- /dev/null
+++ b/build/vsnet/XMPCore.vcproj
@@ -0,0 +1,278 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8,00"
+ Name="XMPCore"
+ ProjectGUID="{C5BB1536-3776-4474-861D-B5923C610FE4}"
+ RootNamespace="XMPCore"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="../../public/libraries/windows/debug/"
+ IntermediateDirectory="../../intermediate/windows/debug/"
+ ConfigurationType="4"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ InlineFunctionExpansion="0"
+ FavorSizeOrSpeed="0"
+ WholeProgramOptimization="false"
+ AdditionalIncludeDirectories="./;../;../../public/include/;../../source/common/;../../source/XMPCore/;&quot;../../third-party/expat/lib/&quot;;&quot;../../third-party/MD5/&quot;"
+ PreprocessorDefinitions="WIN32=1;_WINDOWS=1;WIN_ENV=1;XMP_ClientBuild=0;HAVE_EXPAT_CONFIG_H=1;XML_STATIC=1;DEBUG=1;_DEBUG=1"
+ StringPooling="true"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ SmallerTypeCheck="false"
+ RuntimeLibrary="1"
+ DefaultCharIsUnsigned="true"
+ ForceConformanceInForLoopScope="true"
+ UsePrecompiledHeader="0"
+ ObjectFile="..\..\intermediate\windows\debug\"
+ ProgramDataBaseFileName="..\..\intermediate\windows\debug\vc80.pdb"
+ BrowseInformation="0"
+ WarningLevel="3"
+ WarnAsError="false"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ CompileAs="2"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="$(OutDir)/XMPCoreStaticDebug.lib"
+ IgnoreAllDefaultLibraries="true"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="../../public/libraries/windows/release/"
+ IntermediateDirectory="../../intermediate/windows/release/"
+ ConfigurationType="4"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ InlineFunctionExpansion="2"
+ FavorSizeOrSpeed="2"
+ WholeProgramOptimization="true"
+ AdditionalIncludeDirectories="./;../;../../public/include/;../../source/common/;../../source/XMPCore/;&quot;../../third-party/expat/lib/&quot;;&quot;../../third-party/MD5/&quot;"
+ PreprocessorDefinitions="WIN32=1;_WINDOWS=1;WIN_ENV=1;XMP_ClientBuild=0;HAVE_EXPAT_CONFIG_H=1;XML_STATIC=1;NDEBUG=1;"
+ StringPooling="true"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="0"
+ SmallerTypeCheck="false"
+ RuntimeLibrary="0"
+ BufferSecurityCheck="false"
+ DefaultCharIsUnsigned="true"
+ ForceConformanceInForLoopScope="true"
+ UsePrecompiledHeader="0"
+ ObjectFile="..\..\intermediate\windows\release\"
+ ProgramDataBaseFileName="..\..\intermediate\windows\release\vc80pdb"
+ BrowseInformation="0"
+ WarningLevel="3"
+ WarnAsError="false"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="0"
+ CompileAs="2"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="$(OutDir)/XMPCoreStaticRelease.lib"
+ IgnoreAllDefaultLibraries="true"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath=".\XMPCore.def"
+ >
+ </File>
+ <Filter
+ Name="Toolkit Core"
+ >
+ <File
+ RelativePath="..\..\source\XMPCore\XMPCore_Impl.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\source\XMPCore\XMPIterator.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\source\XMPCore\XMPMeta-GetSet.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\source\XMPCore\XMPMeta-Parse.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\source\XMPCore\XMPMeta-Serialize.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\source\XMPCore\XMPMeta.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\source\XMPCore\XMPUtils-FileInfo.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\source\XMPCore\XMPUtils.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Utilities"
+ >
+ <File
+ RelativePath="..\..\source\XMPCore\ExpatAdapter.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\third-party\MD5\MD5.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\source\XMPCore\ParseRDF.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\source\common\UnicodeConversions.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="XML Parser"
+ >
+ <File
+ RelativePath="..\..\third-party\expat\lib\xmlparse.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\third-party\expat\lib\xmlrole.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\third-party\expat\lib\xmltok.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="ABI Wrappers"
+ >
+ <File
+ RelativePath="..\..\source\XMPCore\WXMPIterator.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\source\XMPCore\WXMPMeta.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\source\XMPCore\WXMPUtils.cpp"
+ >
+ </File>
+ </Filter>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/build/vsnet/XMPFiles.vcproj b/build/vsnet/XMPFiles.vcproj
new file mode 100644
index 0000000..4c72e2a
--- /dev/null
+++ b/build/vsnet/XMPFiles.vcproj
@@ -0,0 +1,322 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8,00"
+ Name="XMPFiles"
+ ProjectGUID="{B9A2E1F1-4E5C-49AC-B052-604CAE21F56E}"
+ RootNamespace="XMPFilesStatic"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="..\..\public\libraries\windows\debug"
+ IntermediateDirectory="..\..\intermediate\windows\debug"
+ ConfigurationType="4"
+ CharacterSet="1"
+ WholeProgramOptimization="0"
+ BuildLogFile="$(IntDir)\BuildLog.htm"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ UseUnicodeResponseFiles="true"
+ Optimization="0"
+ AdditionalIncludeDirectories=".\;..\;..\..\public\include\;..\..\source\XMPFiles\;..\..\source\XMPFiles\FormatSupport\;..\..\source\common\;&quot;..\..\third-party\MD5\&quot;;&quot;..\..\third-party\QTDevWin\CIncludes&quot;"
+ PreprocessorDefinitions="WIN32=1;_WINDOWS=1;WIN_ENV=1;XMP_StaticBuild=1;XMP_PRESERVE_BIB_CLIENT=0;DEBUG=1;_DEBUG=1"
+ StringPooling="true"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ DefaultCharIsUnsigned="true"
+ UsePrecompiledHeader="0"
+ ObjectFile="../../intermediate/windows/debug/"
+ ProgramDataBaseFileName="../../intermediate/windows/debug/vc80.pdb"
+ XMLDocumentationFileName="$(IntDir)\"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ AdditionalDependencies="..\..\third-party\QTDevWin\Libraries\qtmlClient.lib Advapi32.lib User32.lib $(NOINHERIT)"
+ OutputFile="$(OutDir)/XMPFilesStaticDebug.lib"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ CommandLine=""
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="..\..\public\libraries\windows\release"
+ IntermediateDirectory="..\..\intermediate\windows\release"
+ ConfigurationType="4"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ BuildLogFile="$(IntDir)\BuildLog.htm"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ InlineFunctionExpansion="2"
+ FavorSizeOrSpeed="2"
+ WholeProgramOptimization="true"
+ AdditionalIncludeDirectories="./;../;../../public/include/;../../source/XMPFiles/;../../source/XMPFiles/FormatSupport/;../../source/common/;&quot;../../third-party/MD5/&quot;;&quot;../../third-party/QTDevWin/CIncludes&quot;"
+ PreprocessorDefinitions="WIN32=1;_WINDOWS=1;WIN_ENV=1;XMP_StaticBuild=1;XMP_PRESERVE_BIB_CLIENT=0;NDEBUG=1"
+ StringPooling="true"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="0"
+ RuntimeLibrary="0"
+ BufferSecurityCheck="false"
+ DefaultCharIsUnsigned="true"
+ UsePrecompiledHeader="0"
+ ObjectFile="$(IntDir)\"
+ ProgramDataBaseFileName="$(IntDir)\vc80.pdb"
+ XMLDocumentationFileName="$(IntDir)\"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="0"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ AdditionalDependencies="..\..\third-party\QTDevWin\Libraries\qtmlClient.lib Advapi32.lib User32.lib $(NOINHERIT)"
+ OutputFile="$(OutDir)/XMPFilesStaticRelease.lib"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ CommandLine=""
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <Filter
+ Name="Common Code"
+ >
+ <File
+ RelativePath="..\..\source\XMPFiles\WXMPFiles.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\source\XMPFiles\XMPFiles.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\source\XMPFiles\XMPFiles_Impl.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="File Handlers"
+ >
+ <File
+ RelativePath="..\..\source\XMPFiles\FileHandlers\AVI_Handler.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\source\XMPFiles\FileHandlers\Basic_Handler.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\source\XMPFiles\FileHandlers\InDesign_Handler.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\source\XMPFiles\FileHandlers\JPEG_Handler.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\source\XMPFiles\FileHandlers\MOV_Handler.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\source\XMPFiles\FileHandlers\MP3_Handler.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\source\XMPFiles\FileHandlers\MPEG_Handler.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\source\XMPFiles\FileHandlers\PNG_Handler.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\source\XMPFiles\FileHandlers\PostScript_Handler.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\source\XMPFiles\FileHandlers\PSD_Handler.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\source\XMPFiles\FileHandlers\Scanner_Handler.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\source\XMPFiles\FileHandlers\TIFF_Handler.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\source\XMPFiles\FileHandlers\Trivial_Handler.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\source\XMPFiles\FileHandlers\WAV_Handler.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Format Support"
+ >
+ <File
+ RelativePath="..\..\source\XMPFiles\FormatSupport\ID3_Support.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\source\XMPFiles\FormatSupport\IPTC_Support.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\source\XMPFiles\FormatSupport\PNG_Support.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\source\XMPFiles\FormatSupport\PSIR_FileWriter.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\source\XMPFiles\FormatSupport\PSIR_MemoryReader.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\source\XMPFiles\FormatSupport\QuickTime_Support.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\source\XMPFiles\FormatSupport\Reconcile_Impl.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\source\XMPFiles\FormatSupport\ReconcileIPTC.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\source\XMPFiles\FormatSupport\ReconcileLegacy.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\source\XMPFiles\FormatSupport\ReconcileTIFF.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\source\XMPFiles\FormatSupport\RIFF_Support.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\source\XMPFiles\FormatSupport\TIFF_FileWriter.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\source\XMPFiles\FormatSupport\TIFF_MemoryReader.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\source\XMPFiles\FormatSupport\TIFF_Support.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\source\XMPFiles\FormatSupport\XMPScanner.cpp"
+ >
+ </File>
+ </Filter>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/build/vsnet/XMPToolkit.sln b/build/vsnet/XMPToolkit.sln
new file mode 100644
index 0000000..44aac01
--- /dev/null
+++ b/build/vsnet/XMPToolkit.sln
@@ -0,0 +1,25 @@
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual Studio 2005
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "XMPCore", "XMPCore.vcproj", "{C5BB1536-3776-4474-861D-B5923C610FE4}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "XMPFiles Static", "XMPFiles.vcproj", "{B9A2E1F1-4E5C-49AC-B052-604CAE21F56E}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {C5BB1536-3776-4474-861D-B5923C610FE4}.Debug|Win32.ActiveCfg = Debug|Win32
+ {C5BB1536-3776-4474-861D-B5923C610FE4}.Debug|Win32.Build.0 = Debug|Win32
+ {C5BB1536-3776-4474-861D-B5923C610FE4}.Release|Win32.ActiveCfg = Release|Win32
+ {C5BB1536-3776-4474-861D-B5923C610FE4}.Release|Win32.Build.0 = Release|Win32
+ {B9A2E1F1-4E5C-49AC-B052-604CAE21F56E}.Debug|Win32.ActiveCfg = Debug|Win32
+ {B9A2E1F1-4E5C-49AC-B052-604CAE21F56E}.Debug|Win32.Build.0 = Debug|Win32
+ {B9A2E1F1-4E5C-49AC-B052-604CAE21F56E}.Release|Win32.ActiveCfg = Release|Win32
+ {B9A2E1F1-4E5C-49AC-B052-604CAE21F56E}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/build/vsnet/expat_config.h b/build/vsnet/expat_config.h
new file mode 100644
index 0000000..945d0bd
--- /dev/null
+++ b/build/vsnet/expat_config.h
@@ -0,0 +1,95 @@
+/* expat_config.h. Generated by configure. */
+/* expat_config.h.in. Generated from configure.in by autoheader. */
+
+/* *** Tweaked by hand for 32 bit Windows builds */
+
+/* 1234 = LIL_ENDIAN, 4321 = BIGENDIAN */
+#define BYTEORDER 1234
+
+/* Define to 1 if you have the `bcopy' function. */
+/* #define HAVE_BCOPY 1 */
+
+/* Define to 1 if you have the <check.h> header file. */
+/* #undef HAVE_CHECK_H */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+/* #define HAVE_DLFCN_H 1 */
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+/* #define HAVE_FCNTL_H 1 */
+
+/* Define to 1 if you have the `getpagesize' function. */
+/* #define HAVE_GETPAGESIZE 1 */
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+/* #define HAVE_INTTYPES_H 1 */
+
+/* Define to 1 if you have the `memmove' function. */
+#define HAVE_MEMMOVE 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have a working `mmap' system call. */
+/* #define HAVE_MMAP 1 */
+
+/* Define to 1 if you have the <stdint.h> header file. */
+/* #define HAVE_STDINT_H 1 */
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+/* #define HAVE_STRINGS_H 1 */
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+/* #define HAVE_SYS_STAT_H 1 */
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+/* #define HAVE_SYS_TYPES_H 1 */
+
+/* Define to 1 if you have the <unistd.h> header file. */
+/* #define HAVE_UNISTD_H 1 */
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "expat-bugs@mail.libexpat.org"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "expat"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "expat 1.95.8"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "expat"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "1.95.8"
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* whether byteorder is bigendian */
+/* #define WORDS_BIGENDIAN 1 */
+
+/* Define to specify how much context to retain around the current parse
+ point. */
+#define XML_CONTEXT_BYTES 1024
+
+/* Define to make parameter entity parsing functionality available. */
+/* #define XML_DTD 1 */
+
+/* Define to make XML Namespaces functionality available. */
+#define XML_NS 1
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to `long' if <sys/types.h> does not define. */
+/* #undef off_t */
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+/* #undef size_t */
diff --git a/build/xcode/XMPToolkit-Common.xcconfig b/build/xcode/XMPToolkit-Common.xcconfig
new file mode 100644
index 0000000..4637c75
--- /dev/null
+++ b/build/xcode/XMPToolkit-Common.xcconfig
@@ -0,0 +1,63 @@
+PRODUCT_ROOT = ${PROJECT_DIR}/../..
+
+SOURCE_ROOT = ${PRODUCT_ROOT}/source
+PUBLIC_ROOT = ${PRODUCT_ROOT}/public
+
+EXPAT_ROOT = ${PRODUCT_ROOT}/third-party/expat
+
+SRCROOT = ${SOURCE_ROOT}
+
+DSTROOT =
+INSTALL_PATH =
+
+EXECUTABLE_PREFIX = lib
+EXECUTABLE_EXTENSION = a
+WRAPPER_EXTENSION =
+
+INSTALL_PATH =
+EXPORTED_SYMBOLS_FILE =
+LIBRARY_STYLE = STATIC
+ZERO_LINK = NO
+OTHER_LDFLAGS =
+
+INFOPLIST_FILE =
+INFOPLIST_PREPROCESS =
+INFOPLIST_PREFIX_HEADER =
+
+ARCHS = ppc i386
+MACOSX_DEPLOYMENT_TARGET = 10.3
+SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk
+
+SHARED_PRECOMPS_DIR =
+PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR = NO
+GCC_PRECOMPILE_PREFIX_HEADER = NO
+
+HEADER_SEARCH_PATHS = ${PROJECT_DIR} ${PUBLIC_ROOT}/include ${SOURCE_ROOT}/XMPCore ${SOURCE_ROOT}/XMPFiles ${SOURCE_ROOT}/common ${EXPAT_ROOT}/lib /Developer/Headers/FlatCarbon
+
+COMMON_DEFINES = MAC_ENV=1 HAVE_EXPAT_CONFIG_H=1 XML_STATIC=1
+
+GCC_CHAR_IS_UNSIGNED_CHAR = YES
+GCC_ENABLE_PASCAL_STRINGS = NO
+GCC_SHORT_ENUMS = YES
+GCC_ONE_BYTE_BOOL = YES
+GCC_NO_COMMON_BLOCKS = YES
+GCC_FAST_MATH = YES
+
+GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES
+GCC_WARN_ABOUT_RETURN_TYPE = YES
+GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES
+GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES
+GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES
+GCC_WARN_MISSING_PARENTHESES = YES
+GCC_WARN_CHECK_SWITCH_STATEMENTS = YES
+GCC_WARN_UNKNOWN_PRAGMAS = YES
+GCC_WARN_SIGN_COMPARE = YES
+GCC_WARN_ABOUT_MISSING_NEWLINE = YES
+
+Comment_1 = "It would be nice to set these, but they cause a huge number of warnings, many from Expat."
+GCC_WARN_EFFECTIVE_CPLUSPLUS_VIOLATIONS = NO
+GCC_WARN_UNINITIALIZED_AUTOS = NO
+GCC_WARN_UNUSED_PARAMETER = NO
+GCC_WARN_UNUSED_VARIABLE = NO
+GCC_WARN_UNUSED_VALUE = NO
+GCC_WARN_SHADOW = NO
diff --git a/build/xcode/XMPToolkit-Debug.xcconfig b/build/xcode/XMPToolkit-Debug.xcconfig
new file mode 100644
index 0000000..7297bf4
--- /dev/null
+++ b/build/xcode/XMPToolkit-Debug.xcconfig
@@ -0,0 +1,12 @@
+BUILD_MODE = debug
+
+OBJROOT = ${PRODUCT_ROOT}/intermediate/macintosh/${BUILD_MODE}
+SYMROOT = ${PUBLIC_ROOT}/libraries/macintosh/${BUILD_MODE}
+
+CONFIGURATION_BUILD_DIR = ${SYMROOT}
+
+GCC_PREPROCESSOR_DEFINITIONS = ${COMMON_DEFINES} DEBUG=1 _DEBUG=1
+
+GCC_GENERATE_DEBUGGING_SYMBOLS = YES
+GCC_DEBUGGING_SYMBOLS = full
+GCC_OPTIMIZATION_LEVEL = 0
diff --git a/build/xcode/XMPToolkit-Release.xcconfig b/build/xcode/XMPToolkit-Release.xcconfig
new file mode 100644
index 0000000..f60710a
--- /dev/null
+++ b/build/xcode/XMPToolkit-Release.xcconfig
@@ -0,0 +1,12 @@
+BUILD_MODE = release
+
+OBJROOT = ${PRODUCT_ROOT}/intermediate/macintosh/${BUILD_MODE}
+SYMROOT = ${PUBLIC_ROOT}/libraries/macintosh/${BUILD_MODE}
+
+CONFIGURATION_BUILD_DIR = ${SYMROOT}
+
+GCC_PREPROCESSOR_DEFINITIONS = ${COMMON_DEFINES} NDEBUG=1
+
+GCC_GENERATE_DEBUGGING_SYMBOLS = NO
+GCC_DEBUGGING_SYMBOLS = used
+GCC_OPTIMIZATION_LEVEL = s
diff --git a/build/xcode/XMPToolkit.xcodeproj/project.pbxproj b/build/xcode/XMPToolkit.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..a07e410
--- /dev/null
+++ b/build/xcode/XMPToolkit.xcodeproj/project.pbxproj
@@ -0,0 +1,790 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 42;
+ objects = {
+
+/* Begin PBXAggregateTarget section */
+ DCF912BC09A3E6970055523F /* Build All */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = DCF912C109A3E6C60055523F /* Build configuration list for PBXAggregateTarget "Build All" */;
+ buildPhases = (
+ );
+ dependencies = (
+ DCF912BE09A3E6A40055523F /* PBXTargetDependency */,
+ DCF912C009A3E6A70055523F /* PBXTargetDependency */,
+ 01FC6D920B7B7858008559A1 /* PBXTargetDependency */,
+ 01FC6D900B7B7858008559A1 /* PBXTargetDependency */,
+ );
+ name = "Build All";
+ productName = "Build All";
+ };
+/* End PBXAggregateTarget section */
+
+/* Begin PBXBuildFile section */
+ 0102D1C70B7B8471001AF6F7 /* MD5.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 014A2AA10B78FF1400A80B2A /* MD5.cpp */; };
+ 0102D1C80B7B8472001AF6F7 /* MD5.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 014A2AA10B78FF1400A80B2A /* MD5.cpp */; };
+ 014796520B776899007CF8F4 /* XMPCore_Impl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 014796510B776899007CF8F4 /* XMPCore_Impl.cpp */; };
+ 014796530B776899007CF8F4 /* XMPCore_Impl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 014796510B776899007CF8F4 /* XMPCore_Impl.cpp */; };
+ 014A2AA20B78FF2C00A80B2A /* MD5.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 014A2AA10B78FF1400A80B2A /* MD5.cpp */; };
+ 014A2AA30B78FF2C00A80B2A /* MD5.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 014A2AA10B78FF1400A80B2A /* MD5.cpp */; };
+ 01FC6CE80B7B6D65008559A1 /* WXMPFiles.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 014A2AAD0B78FFD200A80B2A /* WXMPFiles.cpp */; };
+ 01FC6D060B7B7514008559A1 /* WXMPFiles.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 014A2AAD0B78FFD200A80B2A /* WXMPFiles.cpp */; };
+ 01FC6D3D0B7B7789008559A1 /* ID3_Support.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D2C0B7B7773008559A1 /* ID3_Support.cpp */; };
+ 01FC6D3E0B7B7789008559A1 /* IPTC_Support.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D2D0B7B7773008559A1 /* IPTC_Support.cpp */; };
+ 01FC6D3F0B7B7789008559A1 /* PNG_Support.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D2E0B7B7773008559A1 /* PNG_Support.cpp */; };
+ 01FC6D400B7B7789008559A1 /* PSIR_FileWriter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D2F0B7B7773008559A1 /* PSIR_FileWriter.cpp */; };
+ 01FC6D410B7B7789008559A1 /* PSIR_MemoryReader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D300B7B7773008559A1 /* PSIR_MemoryReader.cpp */; };
+ 01FC6D420B7B7789008559A1 /* QuickTime_Support.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D310B7B7773008559A1 /* QuickTime_Support.cpp */; };
+ 01FC6D430B7B7789008559A1 /* Reconcile_Impl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D320B7B7773008559A1 /* Reconcile_Impl.cpp */; };
+ 01FC6D440B7B7789008559A1 /* ReconcileIPTC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D330B7B7773008559A1 /* ReconcileIPTC.cpp */; };
+ 01FC6D450B7B7789008559A1 /* ReconcileLegacy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D340B7B7773008559A1 /* ReconcileLegacy.cpp */; };
+ 01FC6D460B7B7789008559A1 /* ReconcileTIFF.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D350B7B7773008559A1 /* ReconcileTIFF.cpp */; };
+ 01FC6D470B7B7789008559A1 /* RIFF_Support.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D360B7B7773008559A1 /* RIFF_Support.cpp */; };
+ 01FC6D490B7B7789008559A1 /* TIFF_FileWriter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D380B7B7773008559A1 /* TIFF_FileWriter.cpp */; };
+ 01FC6D4A0B7B7789008559A1 /* TIFF_MemoryReader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D390B7B7773008559A1 /* TIFF_MemoryReader.cpp */; };
+ 01FC6D4B0B7B7789008559A1 /* TIFF_Support.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D3A0B7B7773008559A1 /* TIFF_Support.cpp */; };
+ 01FC6D4C0B7B7789008559A1 /* XMPScanner.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D3B0B7B7773008559A1 /* XMPScanner.cpp */; };
+ 01FC6D4E0B7B778A008559A1 /* ID3_Support.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D2C0B7B7773008559A1 /* ID3_Support.cpp */; };
+ 01FC6D4F0B7B778A008559A1 /* IPTC_Support.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D2D0B7B7773008559A1 /* IPTC_Support.cpp */; };
+ 01FC6D500B7B778A008559A1 /* PNG_Support.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D2E0B7B7773008559A1 /* PNG_Support.cpp */; };
+ 01FC6D510B7B778A008559A1 /* PSIR_FileWriter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D2F0B7B7773008559A1 /* PSIR_FileWriter.cpp */; };
+ 01FC6D520B7B778A008559A1 /* PSIR_MemoryReader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D300B7B7773008559A1 /* PSIR_MemoryReader.cpp */; };
+ 01FC6D530B7B778A008559A1 /* QuickTime_Support.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D310B7B7773008559A1 /* QuickTime_Support.cpp */; };
+ 01FC6D540B7B778A008559A1 /* Reconcile_Impl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D320B7B7773008559A1 /* Reconcile_Impl.cpp */; };
+ 01FC6D550B7B778A008559A1 /* ReconcileIPTC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D330B7B7773008559A1 /* ReconcileIPTC.cpp */; };
+ 01FC6D560B7B778A008559A1 /* ReconcileLegacy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D340B7B7773008559A1 /* ReconcileLegacy.cpp */; };
+ 01FC6D570B7B778A008559A1 /* ReconcileTIFF.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D350B7B7773008559A1 /* ReconcileTIFF.cpp */; };
+ 01FC6D580B7B778A008559A1 /* RIFF_Support.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D360B7B7773008559A1 /* RIFF_Support.cpp */; };
+ 01FC6D5A0B7B778A008559A1 /* TIFF_FileWriter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D380B7B7773008559A1 /* TIFF_FileWriter.cpp */; };
+ 01FC6D5B0B7B778A008559A1 /* TIFF_MemoryReader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D390B7B7773008559A1 /* TIFF_MemoryReader.cpp */; };
+ 01FC6D5C0B7B778A008559A1 /* TIFF_Support.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D3A0B7B7773008559A1 /* TIFF_Support.cpp */; };
+ 01FC6D5D0B7B778A008559A1 /* XMPScanner.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D3B0B7B7773008559A1 /* XMPScanner.cpp */; };
+ 01FC6D5F0B7B7799008559A1 /* AVI_Handler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D160B7B75F9008559A1 /* AVI_Handler.cpp */; };
+ 01FC6D600B7B7799008559A1 /* Basic_Handler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D170B7B75F9008559A1 /* Basic_Handler.cpp */; };
+ 01FC6D610B7B7799008559A1 /* InDesign_Handler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D180B7B75F9008559A1 /* InDesign_Handler.cpp */; };
+ 01FC6D620B7B7799008559A1 /* JPEG_Handler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D190B7B75F9008559A1 /* JPEG_Handler.cpp */; };
+ 01FC6D640B7B7799008559A1 /* MOV_Handler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D1B0B7B75F9008559A1 /* MOV_Handler.cpp */; };
+ 01FC6D650B7B7799008559A1 /* MP3_Handler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D1C0B7B75F9008559A1 /* MP3_Handler.cpp */; };
+ 01FC6D670B7B7799008559A1 /* MPEG_Handler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D1E0B7B75F9008559A1 /* MPEG_Handler.cpp */; };
+ 01FC6D680B7B7799008559A1 /* PNG_Handler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D1F0B7B75F9008559A1 /* PNG_Handler.cpp */; };
+ 01FC6D690B7B7799008559A1 /* PostScript_Handler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D200B7B75F9008559A1 /* PostScript_Handler.cpp */; };
+ 01FC6D6A0B7B7799008559A1 /* PSD_Handler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D210B7B75F9008559A1 /* PSD_Handler.cpp */; };
+ 01FC6D6B0B7B7799008559A1 /* Scanner_Handler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D220B7B75F9008559A1 /* Scanner_Handler.cpp */; };
+ 01FC6D6D0B7B7799008559A1 /* TIFF_Handler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D240B7B75F9008559A1 /* TIFF_Handler.cpp */; };
+ 01FC6D6E0B7B7799008559A1 /* Trivial_Handler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D250B7B75F9008559A1 /* Trivial_Handler.cpp */; };
+ 01FC6D6F0B7B7799008559A1 /* WAV_Handler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D260B7B75F9008559A1 /* WAV_Handler.cpp */; };
+ 01FC6D710B7B779A008559A1 /* AVI_Handler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D160B7B75F9008559A1 /* AVI_Handler.cpp */; };
+ 01FC6D720B7B779A008559A1 /* Basic_Handler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D170B7B75F9008559A1 /* Basic_Handler.cpp */; };
+ 01FC6D730B7B779A008559A1 /* InDesign_Handler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D180B7B75F9008559A1 /* InDesign_Handler.cpp */; };
+ 01FC6D740B7B779A008559A1 /* JPEG_Handler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D190B7B75F9008559A1 /* JPEG_Handler.cpp */; };
+ 01FC6D760B7B779A008559A1 /* MOV_Handler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D1B0B7B75F9008559A1 /* MOV_Handler.cpp */; };
+ 01FC6D770B7B779A008559A1 /* MP3_Handler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D1C0B7B75F9008559A1 /* MP3_Handler.cpp */; };
+ 01FC6D790B7B779A008559A1 /* MPEG_Handler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D1E0B7B75F9008559A1 /* MPEG_Handler.cpp */; };
+ 01FC6D7A0B7B779A008559A1 /* PNG_Handler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D1F0B7B75F9008559A1 /* PNG_Handler.cpp */; };
+ 01FC6D7B0B7B779A008559A1 /* PostScript_Handler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D200B7B75F9008559A1 /* PostScript_Handler.cpp */; };
+ 01FC6D7C0B7B779A008559A1 /* PSD_Handler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D210B7B75F9008559A1 /* PSD_Handler.cpp */; };
+ 01FC6D7D0B7B779A008559A1 /* Scanner_Handler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D220B7B75F9008559A1 /* Scanner_Handler.cpp */; };
+ 01FC6D7F0B7B779A008559A1 /* TIFF_Handler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D240B7B75F9008559A1 /* TIFF_Handler.cpp */; };
+ 01FC6D800B7B779A008559A1 /* Trivial_Handler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D250B7B75F9008559A1 /* Trivial_Handler.cpp */; };
+ 01FC6D810B7B779A008559A1 /* WAV_Handler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D260B7B75F9008559A1 /* WAV_Handler.cpp */; };
+ 01FC6D870B7B77D9008559A1 /* WXMPFiles.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D840B7B77C1008559A1 /* WXMPFiles.cpp */; };
+ 01FC6D880B7B77D9008559A1 /* XMPFiles.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D850B7B77C1008559A1 /* XMPFiles.cpp */; };
+ 01FC6D890B7B77D9008559A1 /* XMPFiles_Impl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D860B7B77C1008559A1 /* XMPFiles_Impl.cpp */; };
+ 01FC6D8A0B7B77DA008559A1 /* WXMPFiles.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D840B7B77C1008559A1 /* WXMPFiles.cpp */; };
+ 01FC6D8B0B7B77DA008559A1 /* XMPFiles.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D850B7B77C1008559A1 /* XMPFiles.cpp */; };
+ 01FC6D8C0B7B77DA008559A1 /* XMPFiles_Impl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 01FC6D860B7B77C1008559A1 /* XMPFiles_Impl.cpp */; };
+ DC493270089A94CE003ADAAF /* XMPIterator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07601E46085F950A003FEB33 /* XMPIterator.cpp */; };
+ DC493271089A94CE003ADAAF /* XMPMeta.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07601E47085F950A003FEB33 /* XMPMeta.cpp */; };
+ DC493272089A94CE003ADAAF /* XMPMeta-GetSet.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DC87E517089960DB000A7ADF /* XMPMeta-GetSet.cpp */; };
+ DC493273089A94CE003ADAAF /* XMPMeta-Parse.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DC87E518089960DB000A7ADF /* XMPMeta-Parse.cpp */; };
+ DC493274089A94CE003ADAAF /* XMPMeta-Serialize.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DC87E519089960DB000A7ADF /* XMPMeta-Serialize.cpp */; };
+ DC493275089A94CE003ADAAF /* XMPUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07601E48085F950A003FEB33 /* XMPUtils.cpp */; };
+ DC49327B089A94E6003ADAAF /* ExpatAdapter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07601E73085F9791003FEB33 /* ExpatAdapter.cpp */; };
+ DC49327D089A94E6003ADAAF /* ParseRDF.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07601E75085F9791003FEB33 /* ParseRDF.cpp */; };
+ DC49327E089A94E6003ADAAF /* UnicodeConversions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07601E76085F9791003FEB33 /* UnicodeConversions.cpp */; };
+ DC49327F089A94FF003ADAAF /* xmlparse.c in Sources */ = {isa = PBXBuildFile; fileRef = DC14FDD2089A8591004D5310 /* xmlparse.c */; };
+ DC493280089A94FF003ADAAF /* xmlrole.c in Sources */ = {isa = PBXBuildFile; fileRef = DC14FDD3089A8591004D5310 /* xmlrole.c */; };
+ DC493281089A94FF003ADAAF /* xmltok.c in Sources */ = {isa = PBXBuildFile; fileRef = DC14FDD4089A8591004D5310 /* xmltok.c */; };
+ DC493282089A950C003ADAAF /* WXMPIterator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07601E89085F9A39003FEB33 /* WXMPIterator.cpp */; };
+ DC493283089A950C003ADAAF /* WXMPMeta.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07601E8A085F9A39003FEB33 /* WXMPMeta.cpp */; };
+ DC493284089A950C003ADAAF /* WXMPUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07601E8B085F9A39003FEB33 /* WXMPUtils.cpp */; };
+ DC493297089A9726003ADAAF /* XMPIterator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07601E46085F950A003FEB33 /* XMPIterator.cpp */; };
+ DC493298089A9726003ADAAF /* XMPMeta.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07601E47085F950A003FEB33 /* XMPMeta.cpp */; };
+ DC493299089A9726003ADAAF /* XMPMeta-GetSet.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DC87E517089960DB000A7ADF /* XMPMeta-GetSet.cpp */; };
+ DC49329A089A9726003ADAAF /* XMPMeta-Parse.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DC87E518089960DB000A7ADF /* XMPMeta-Parse.cpp */; };
+ DC49329B089A9726003ADAAF /* XMPMeta-Serialize.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DC87E519089960DB000A7ADF /* XMPMeta-Serialize.cpp */; };
+ DC49329C089A9726003ADAAF /* XMPUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07601E48085F950A003FEB33 /* XMPUtils.cpp */; };
+ DC4932A2089A9726003ADAAF /* ExpatAdapter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07601E73085F9791003FEB33 /* ExpatAdapter.cpp */; };
+ DC4932A4089A9726003ADAAF /* ParseRDF.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07601E75085F9791003FEB33 /* ParseRDF.cpp */; };
+ DC4932A5089A9726003ADAAF /* UnicodeConversions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07601E76085F9791003FEB33 /* UnicodeConversions.cpp */; };
+ DC4932A6089A9726003ADAAF /* xmlparse.c in Sources */ = {isa = PBXBuildFile; fileRef = DC14FDD2089A8591004D5310 /* xmlparse.c */; };
+ DC4932A7089A9726003ADAAF /* xmlrole.c in Sources */ = {isa = PBXBuildFile; fileRef = DC14FDD3089A8591004D5310 /* xmlrole.c */; };
+ DC4932A8089A9726003ADAAF /* xmltok.c in Sources */ = {isa = PBXBuildFile; fileRef = DC14FDD4089A8591004D5310 /* xmltok.c */; };
+ DC4932A9089A9726003ADAAF /* WXMPIterator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07601E89085F9A39003FEB33 /* WXMPIterator.cpp */; };
+ DC4932AA089A9726003ADAAF /* WXMPMeta.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07601E8A085F9A39003FEB33 /* WXMPMeta.cpp */; };
+ DC4932AB089A9726003ADAAF /* WXMPUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07601E8B085F9A39003FEB33 /* WXMPUtils.cpp */; };
+ DCEDFE2509ACBECF00D86460 /* XMPUtils-FileInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCEDFE2409ACBECF00D86460 /* XMPUtils-FileInfo.cpp */; };
+ DCEDFE2609ACBECF00D86460 /* XMPUtils-FileInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCEDFE2409ACBECF00D86460 /* XMPUtils-FileInfo.cpp */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ 01FC6D8F0B7B7858008559A1 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 01FC6CF20B7B7514008559A1;
+ remoteInfo = "XMPFiles Release";
+ };
+ 01FC6D910B7B7858008559A1 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 01FC6CD40B7B6D65008559A1;
+ remoteInfo = "XMPFiles Debug";
+ };
+ DCF912BD09A3E6A40055523F /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = DC49326B089A9441003ADAAF;
+ remoteInfo = "XMPCore Debug";
+ };
+ DCF912BF09A3E6A70055523F /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = DC493293089A9726003ADAAF;
+ remoteInfo = "XMPCore Release";
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXFileReference section */
+ 0147964D0B776823007CF8F4 /* XMPCore_Impl.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = XMPCore_Impl.hpp; sourceTree = "<group>"; };
+ 014796510B776899007CF8F4 /* XMPCore_Impl.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = XMPCore_Impl.cpp; sourceTree = "<group>"; };
+ 014A29EF0B78E2C300A80B2A /* UnicodeConversions.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = UnicodeConversions.hpp; path = ../common/UnicodeConversions.hpp; sourceTree = "<group>"; };
+ 014A29F40B78E2F300A80B2A /* UnicodeInlines.incl_cpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = UnicodeInlines.incl_cpp; path = ../common/UnicodeInlines.incl_cpp; sourceTree = "<group>"; };
+ 014A2A040B78E5C500A80B2A /* XMP_BuildInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = XMP_BuildInfo.h; path = ../../build/XMP_BuildInfo.h; sourceTree = "<group>"; };
+ 014A2AA10B78FF1400A80B2A /* MD5.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = MD5.cpp; path = "../../third-party/MD5/MD5.cpp"; sourceTree = "<group>"; };
+ 014A2AAD0B78FFD200A80B2A /* WXMPFiles.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = WXMPFiles.cpp; path = ../XMPFiles/WXMPFiles.cpp; sourceTree = "<group>"; };
+ 01FC6CEC0B7B6D65008559A1 /* libXMPFilesStaticDebug.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libXMPFilesStaticDebug.a; sourceTree = BUILT_PRODUCTS_DIR; };
+ 01FC6D0A0B7B7514008559A1 /* libXMPFilesStaticRelease.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libXMPFilesStaticRelease.a; sourceTree = BUILT_PRODUCTS_DIR; };
+ 01FC6D160B7B75F9008559A1 /* AVI_Handler.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = AVI_Handler.cpp; path = ../../source/XMPFiles/FileHandlers/AVI_Handler.cpp; sourceTree = "<group>"; };
+ 01FC6D170B7B75F9008559A1 /* Basic_Handler.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Basic_Handler.cpp; path = ../../source/XMPFiles/FileHandlers/Basic_Handler.cpp; sourceTree = "<group>"; };
+ 01FC6D180B7B75F9008559A1 /* InDesign_Handler.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = InDesign_Handler.cpp; path = ../../source/XMPFiles/FileHandlers/InDesign_Handler.cpp; sourceTree = "<group>"; };
+ 01FC6D190B7B75F9008559A1 /* JPEG_Handler.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = JPEG_Handler.cpp; path = ../../source/XMPFiles/FileHandlers/JPEG_Handler.cpp; sourceTree = "<group>"; };
+ 01FC6D1B0B7B75F9008559A1 /* MOV_Handler.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = MOV_Handler.cpp; path = ../../source/XMPFiles/FileHandlers/MOV_Handler.cpp; sourceTree = "<group>"; };
+ 01FC6D1C0B7B75F9008559A1 /* MP3_Handler.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = MP3_Handler.cpp; path = ../../source/XMPFiles/FileHandlers/MP3_Handler.cpp; sourceTree = "<group>"; };
+ 01FC6D1E0B7B75F9008559A1 /* MPEG_Handler.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = MPEG_Handler.cpp; path = ../../source/XMPFiles/FileHandlers/MPEG_Handler.cpp; sourceTree = "<group>"; };
+ 01FC6D1F0B7B75F9008559A1 /* PNG_Handler.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = PNG_Handler.cpp; path = ../../source/XMPFiles/FileHandlers/PNG_Handler.cpp; sourceTree = "<group>"; };
+ 01FC6D200B7B75F9008559A1 /* PostScript_Handler.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = PostScript_Handler.cpp; path = ../../source/XMPFiles/FileHandlers/PostScript_Handler.cpp; sourceTree = "<group>"; };
+ 01FC6D210B7B75F9008559A1 /* PSD_Handler.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = PSD_Handler.cpp; path = ../../source/XMPFiles/FileHandlers/PSD_Handler.cpp; sourceTree = "<group>"; };
+ 01FC6D220B7B75F9008559A1 /* Scanner_Handler.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Scanner_Handler.cpp; path = ../../source/XMPFiles/FileHandlers/Scanner_Handler.cpp; sourceTree = "<group>"; };
+ 01FC6D240B7B75F9008559A1 /* TIFF_Handler.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = TIFF_Handler.cpp; path = ../../source/XMPFiles/FileHandlers/TIFF_Handler.cpp; sourceTree = "<group>"; };
+ 01FC6D250B7B75F9008559A1 /* Trivial_Handler.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Trivial_Handler.cpp; path = ../../source/XMPFiles/FileHandlers/Trivial_Handler.cpp; sourceTree = "<group>"; };
+ 01FC6D260B7B75F9008559A1 /* WAV_Handler.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = WAV_Handler.cpp; path = ../../source/XMPFiles/FileHandlers/WAV_Handler.cpp; sourceTree = "<group>"; };
+ 01FC6D2C0B7B7773008559A1 /* ID3_Support.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ID3_Support.cpp; path = ../../source/XMPFiles/FormatSupport/ID3_Support.cpp; sourceTree = "<group>"; };
+ 01FC6D2D0B7B7773008559A1 /* IPTC_Support.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = IPTC_Support.cpp; path = ../../source/XMPFiles/FormatSupport/IPTC_Support.cpp; sourceTree = "<group>"; };
+ 01FC6D2E0B7B7773008559A1 /* PNG_Support.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = PNG_Support.cpp; path = ../../source/XMPFiles/FormatSupport/PNG_Support.cpp; sourceTree = "<group>"; };
+ 01FC6D2F0B7B7773008559A1 /* PSIR_FileWriter.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = PSIR_FileWriter.cpp; path = ../../source/XMPFiles/FormatSupport/PSIR_FileWriter.cpp; sourceTree = "<group>"; };
+ 01FC6D300B7B7773008559A1 /* PSIR_MemoryReader.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = PSIR_MemoryReader.cpp; path = ../../source/XMPFiles/FormatSupport/PSIR_MemoryReader.cpp; sourceTree = "<group>"; };
+ 01FC6D310B7B7773008559A1 /* QuickTime_Support.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = QuickTime_Support.cpp; path = ../../source/XMPFiles/FormatSupport/QuickTime_Support.cpp; sourceTree = "<group>"; };
+ 01FC6D320B7B7773008559A1 /* Reconcile_Impl.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Reconcile_Impl.cpp; path = ../../source/XMPFiles/FormatSupport/Reconcile_Impl.cpp; sourceTree = "<group>"; };
+ 01FC6D330B7B7773008559A1 /* ReconcileIPTC.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ReconcileIPTC.cpp; path = ../../source/XMPFiles/FormatSupport/ReconcileIPTC.cpp; sourceTree = "<group>"; };
+ 01FC6D340B7B7773008559A1 /* ReconcileLegacy.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ReconcileLegacy.cpp; path = ../../source/XMPFiles/FormatSupport/ReconcileLegacy.cpp; sourceTree = "<group>"; };
+ 01FC6D350B7B7773008559A1 /* ReconcileTIFF.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ReconcileTIFF.cpp; path = ../../source/XMPFiles/FormatSupport/ReconcileTIFF.cpp; sourceTree = "<group>"; };
+ 01FC6D360B7B7773008559A1 /* RIFF_Support.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = RIFF_Support.cpp; path = ../../source/XMPFiles/FormatSupport/RIFF_Support.cpp; sourceTree = "<group>"; };
+ 01FC6D380B7B7773008559A1 /* TIFF_FileWriter.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = TIFF_FileWriter.cpp; path = ../../source/XMPFiles/FormatSupport/TIFF_FileWriter.cpp; sourceTree = "<group>"; };
+ 01FC6D390B7B7773008559A1 /* TIFF_MemoryReader.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = TIFF_MemoryReader.cpp; path = ../../source/XMPFiles/FormatSupport/TIFF_MemoryReader.cpp; sourceTree = "<group>"; };
+ 01FC6D3A0B7B7773008559A1 /* TIFF_Support.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = TIFF_Support.cpp; path = ../../source/XMPFiles/FormatSupport/TIFF_Support.cpp; sourceTree = "<group>"; };
+ 01FC6D3B0B7B7773008559A1 /* XMPScanner.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = XMPScanner.cpp; path = ../../source/XMPFiles/FormatSupport/XMPScanner.cpp; sourceTree = "<group>"; };
+ 01FC6D840B7B77C1008559A1 /* WXMPFiles.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = WXMPFiles.cpp; path = ../../source/XMPFiles/WXMPFiles.cpp; sourceTree = "<group>"; };
+ 01FC6D850B7B77C1008559A1 /* XMPFiles.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = XMPFiles.cpp; path = ../../source/XMPFiles/XMPFiles.cpp; sourceTree = "<group>"; };
+ 01FC6D860B7B77C1008559A1 /* XMPFiles_Impl.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = XMPFiles_Impl.cpp; path = ../../source/XMPFiles/XMPFiles_Impl.cpp; sourceTree = "<group>"; };
+ 07601E46085F950A003FEB33 /* XMPIterator.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = XMPIterator.cpp; sourceTree = "<group>"; };
+ 07601E47085F950A003FEB33 /* XMPMeta.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = XMPMeta.cpp; sourceTree = "<group>"; };
+ 07601E48085F950A003FEB33 /* XMPUtils.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = XMPUtils.cpp; sourceTree = "<group>"; };
+ 07601E73085F9791003FEB33 /* ExpatAdapter.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = ExpatAdapter.cpp; sourceTree = "<group>"; };
+ 07601E75085F9791003FEB33 /* ParseRDF.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = ParseRDF.cpp; sourceTree = "<group>"; };
+ 07601E76085F9791003FEB33 /* UnicodeConversions.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = UnicodeConversions.cpp; path = ../common/UnicodeConversions.cpp; sourceTree = "<group>"; };
+ 07601E89085F9A39003FEB33 /* WXMPIterator.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = WXMPIterator.cpp; sourceTree = "<group>"; };
+ 07601E8A085F9A39003FEB33 /* WXMPMeta.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = WXMPMeta.cpp; sourceTree = "<group>"; };
+ 07601E8B085F9A39003FEB33 /* WXMPUtils.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = WXMPUtils.cpp; sourceTree = "<group>"; };
+ 07601E92085F9A72003FEB33 /* XMPIterator.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = XMPIterator.hpp; sourceTree = "<group>"; };
+ 07601E93085F9A72003FEB33 /* XMPMeta.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = XMPMeta.hpp; sourceTree = "<group>"; };
+ 07601E94085F9A72003FEB33 /* XMPUtils.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = XMPUtils.hpp; sourceTree = "<group>"; };
+ 07601E95085F9A88003FEB33 /* XMP_Const.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = XMP_Const.h; sourceTree = "<group>"; };
+ 07601E97085F9AB8003FEB33 /* TXMPMeta.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = TXMPMeta.hpp; sourceTree = "<group>"; };
+ 07601E98085F9AB8003FEB33 /* TXMPUtils.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = TXMPUtils.hpp; sourceTree = "<group>"; };
+ 07601E99085F9AB8003FEB33 /* XMP_Environment.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = XMP_Environment.h; sourceTree = "<group>"; };
+ 07601E9A085F9AB8003FEB33 /* XMP_Version.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = XMP_Version.h; sourceTree = "<group>"; };
+ 07601E9B085F9AB8003FEB33 /* XMP.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = XMP.hpp; sourceTree = "<group>"; };
+ DC14FDD2089A8591004D5310 /* xmlparse.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = xmlparse.c; sourceTree = "<group>"; };
+ DC14FDD3089A8591004D5310 /* xmlrole.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = xmlrole.c; sourceTree = "<group>"; };
+ DC14FDD4089A8591004D5310 /* xmltok.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = xmltok.c; sourceTree = "<group>"; };
+ DC49326C089A9441003ADAAF /* libXMPCoreStaticDebug.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libXMPCoreStaticDebug.a; sourceTree = BUILT_PRODUCTS_DIR; };
+ DC4932B0089A9726003ADAAF /* libXMPCoreStaticRelease.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libXMPCoreStaticRelease.a; sourceTree = BUILT_PRODUCTS_DIR; };
+ DC87E517089960DB000A7ADF /* XMPMeta-GetSet.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = "XMPMeta-GetSet.cpp"; sourceTree = "<group>"; };
+ DC87E518089960DB000A7ADF /* XMPMeta-Parse.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = "XMPMeta-Parse.cpp"; sourceTree = "<group>"; };
+ DC87E519089960DB000A7ADF /* XMPMeta-Serialize.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = "XMPMeta-Serialize.cpp"; sourceTree = "<group>"; };
+ DCE400F60951DA740040D71F /* TXMPIterator.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = TXMPIterator.hpp; sourceTree = "<group>"; };
+ DCE400F70951DAA90040D71F /* XMPToolkit-Common.xcconfig */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.xcconfig; path = "XMPToolkit-Common.xcconfig"; sourceTree = "<group>"; };
+ DCE400F80951DAA90040D71F /* XMPToolkit-Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.xcconfig; path = "XMPToolkit-Debug.xcconfig"; sourceTree = "<group>"; };
+ DCE400F90951DAA90040D71F /* XMPToolkit-Release.xcconfig */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.xcconfig; path = "XMPToolkit-Release.xcconfig"; sourceTree = "<group>"; };
+ DCEDFE2409ACBECF00D86460 /* XMPUtils-FileInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = "XMPUtils-FileInfo.cpp"; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 01FC6CE90B7B6D65008559A1 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 01FC6D070B7B7514008559A1 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ DC49326A089A9441003ADAAF /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ DC4932AC089A9726003ADAAF /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 014A2AB10B79001E00A80B2A /* Toolkit Files */ = {
+ isa = PBXGroup;
+ children = (
+ 01FC6D840B7B77C1008559A1 /* WXMPFiles.cpp */,
+ 01FC6D850B7B77C1008559A1 /* XMPFiles.cpp */,
+ 01FC6D860B7B77C1008559A1 /* XMPFiles_Impl.cpp */,
+ 01FC6CEE0B7B7462008559A1 /* Format Support */,
+ 01FC6CED0B7B7458008559A1 /* File Handlers */,
+ );
+ name = "Toolkit Files";
+ sourceTree = "<group>";
+ };
+ 01FC6CED0B7B7458008559A1 /* File Handlers */ = {
+ isa = PBXGroup;
+ children = (
+ 01FC6D160B7B75F9008559A1 /* AVI_Handler.cpp */,
+ 01FC6D170B7B75F9008559A1 /* Basic_Handler.cpp */,
+ 01FC6D180B7B75F9008559A1 /* InDesign_Handler.cpp */,
+ 01FC6D190B7B75F9008559A1 /* JPEG_Handler.cpp */,
+ 01FC6D1B0B7B75F9008559A1 /* MOV_Handler.cpp */,
+ 01FC6D1C0B7B75F9008559A1 /* MP3_Handler.cpp */,
+ 01FC6D1E0B7B75F9008559A1 /* MPEG_Handler.cpp */,
+ 01FC6D1F0B7B75F9008559A1 /* PNG_Handler.cpp */,
+ 01FC6D200B7B75F9008559A1 /* PostScript_Handler.cpp */,
+ 01FC6D210B7B75F9008559A1 /* PSD_Handler.cpp */,
+ 01FC6D220B7B75F9008559A1 /* Scanner_Handler.cpp */,
+ 01FC6D240B7B75F9008559A1 /* TIFF_Handler.cpp */,
+ 01FC6D250B7B75F9008559A1 /* Trivial_Handler.cpp */,
+ 01FC6D260B7B75F9008559A1 /* WAV_Handler.cpp */,
+ );
+ name = "File Handlers";
+ sourceTree = "<group>";
+ };
+ 01FC6CEE0B7B7462008559A1 /* Format Support */ = {
+ isa = PBXGroup;
+ children = (
+ 01FC6D2C0B7B7773008559A1 /* ID3_Support.cpp */,
+ 01FC6D2D0B7B7773008559A1 /* IPTC_Support.cpp */,
+ 01FC6D2E0B7B7773008559A1 /* PNG_Support.cpp */,
+ 01FC6D2F0B7B7773008559A1 /* PSIR_FileWriter.cpp */,
+ 01FC6D300B7B7773008559A1 /* PSIR_MemoryReader.cpp */,
+ 01FC6D310B7B7773008559A1 /* QuickTime_Support.cpp */,
+ 01FC6D320B7B7773008559A1 /* Reconcile_Impl.cpp */,
+ 01FC6D330B7B7773008559A1 /* ReconcileIPTC.cpp */,
+ 01FC6D340B7B7773008559A1 /* ReconcileLegacy.cpp */,
+ 01FC6D350B7B7773008559A1 /* ReconcileTIFF.cpp */,
+ 01FC6D360B7B7773008559A1 /* RIFF_Support.cpp */,
+ 01FC6D380B7B7773008559A1 /* TIFF_FileWriter.cpp */,
+ 01FC6D390B7B7773008559A1 /* TIFF_MemoryReader.cpp */,
+ 01FC6D3A0B7B7773008559A1 /* TIFF_Support.cpp */,
+ 01FC6D3B0B7B7773008559A1 /* XMPScanner.cpp */,
+ );
+ name = "Format Support";
+ sourceTree = "<group>";
+ };
+ 07601E35085F945B003FEB33 /* Build Extras */ = {
+ isa = PBXGroup;
+ children = (
+ DCE400F70951DAA90040D71F /* XMPToolkit-Common.xcconfig */,
+ DCE400F80951DAA90040D71F /* XMPToolkit-Debug.xcconfig */,
+ DCE400F90951DAA90040D71F /* XMPToolkit-Release.xcconfig */,
+ );
+ name = "Build Extras";
+ sourceTree = "<group>";
+ };
+ 07601E38085F9469003FEB33 /* Public Headers and Glue */ = {
+ isa = PBXGroup;
+ children = (
+ 07601E95085F9A88003FEB33 /* XMP_Const.h */,
+ DCE400F60951DA740040D71F /* TXMPIterator.hpp */,
+ 07601E97085F9AB8003FEB33 /* TXMPMeta.hpp */,
+ 07601E98085F9AB8003FEB33 /* TXMPUtils.hpp */,
+ 07601E99085F9AB8003FEB33 /* XMP_Environment.h */,
+ 07601E9A085F9AB8003FEB33 /* XMP_Version.h */,
+ 07601E9B085F9AB8003FEB33 /* XMP.hpp */,
+ );
+ name = "Public Headers and Glue";
+ path = ../../public/include;
+ sourceTree = "<group>";
+ };
+ 07601E3A085F947B003FEB33 /* Internal Headers */ = {
+ isa = PBXGroup;
+ children = (
+ 014A2A040B78E5C500A80B2A /* XMP_BuildInfo.h */,
+ 0147964D0B776823007CF8F4 /* XMPCore_Impl.hpp */,
+ 07601E92085F9A72003FEB33 /* XMPIterator.hpp */,
+ 07601E93085F9A72003FEB33 /* XMPMeta.hpp */,
+ 07601E94085F9A72003FEB33 /* XMPUtils.hpp */,
+ 014A29EF0B78E2C300A80B2A /* UnicodeConversions.hpp */,
+ 014A29F40B78E2F300A80B2A /* UnicodeInlines.incl_cpp */,
+ );
+ name = "Internal Headers";
+ path = ../../source/XMPCore;
+ sourceTree = "<group>";
+ };
+ 07601E3C085F9484003FEB33 /* ABI Wrappers */ = {
+ isa = PBXGroup;
+ children = (
+ 07601E89085F9A39003FEB33 /* WXMPIterator.cpp */,
+ 07601E8A085F9A39003FEB33 /* WXMPMeta.cpp */,
+ 07601E8B085F9A39003FEB33 /* WXMPUtils.cpp */,
+ 014A2AAD0B78FFD200A80B2A /* WXMPFiles.cpp */,
+ );
+ name = "ABI Wrappers";
+ path = ../../source/XMPCore;
+ sourceTree = "<group>";
+ };
+ 07601E40085F949B003FEB33 /* Utilities */ = {
+ isa = PBXGroup;
+ children = (
+ 07601E73085F9791003FEB33 /* ExpatAdapter.cpp */,
+ 07601E75085F9791003FEB33 /* ParseRDF.cpp */,
+ 07601E76085F9791003FEB33 /* UnicodeConversions.cpp */,
+ 014A2AA10B78FF1400A80B2A /* MD5.cpp */,
+ );
+ name = Utilities;
+ path = ../../source/XMPCore;
+ sourceTree = "<group>";
+ };
+ 07601E42085F94A2003FEB33 /* Toolkit Core */ = {
+ isa = PBXGroup;
+ children = (
+ 014796510B776899007CF8F4 /* XMPCore_Impl.cpp */,
+ 07601E46085F950A003FEB33 /* XMPIterator.cpp */,
+ 07601E47085F950A003FEB33 /* XMPMeta.cpp */,
+ DC87E517089960DB000A7ADF /* XMPMeta-GetSet.cpp */,
+ DC87E518089960DB000A7ADF /* XMPMeta-Parse.cpp */,
+ DC87E519089960DB000A7ADF /* XMPMeta-Serialize.cpp */,
+ 07601E48085F950A003FEB33 /* XMPUtils.cpp */,
+ DCEDFE2409ACBECF00D86460 /* XMPUtils-FileInfo.cpp */,
+ );
+ name = "Toolkit Core";
+ path = ../../source/XMPCore;
+ sourceTree = "<group>";
+ };
+ 0867D691FE84028FC02AAC07 /* AdobeXMP */ = {
+ isa = PBXGroup;
+ children = (
+ 07601E42085F94A2003FEB33 /* Toolkit Core */,
+ 014A2AB10B79001E00A80B2A /* Toolkit Files */,
+ 07601E40085F949B003FEB33 /* Utilities */,
+ DC14FDC2089A84F0004D5310 /* XML Parser */,
+ 07601E3C085F9484003FEB33 /* ABI Wrappers */,
+ 07601E3A085F947B003FEB33 /* Internal Headers */,
+ 07601E38085F9469003FEB33 /* Public Headers and Glue */,
+ 07601E35085F945B003FEB33 /* Build Extras */,
+ DC3CC41908A4342900F44C7B /* Products */,
+ );
+ name = AdobeXMP;
+ sourceTree = "<group>";
+ };
+ DC14FDC2089A84F0004D5310 /* XML Parser */ = {
+ isa = PBXGroup;
+ children = (
+ DC14FDD2089A8591004D5310 /* xmlparse.c */,
+ DC14FDD3089A8591004D5310 /* xmlrole.c */,
+ DC14FDD4089A8591004D5310 /* xmltok.c */,
+ );
+ name = "XML Parser";
+ path = "../../third-party/expat/lib";
+ sourceTree = "<group>";
+ };
+ DC3CC41908A4342900F44C7B /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ DC49326C089A9441003ADAAF /* libXMPCoreStaticDebug.a */,
+ DC4932B0089A9726003ADAAF /* libXMPCoreStaticRelease.a */,
+ 01FC6CEC0B7B6D65008559A1 /* libXMPFilesStaticDebug.a */,
+ 01FC6D0A0B7B7514008559A1 /* libXMPFilesStaticRelease.a */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 01FC6CD40B7B6D65008559A1 /* XMPFiles Debug */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 01FC6CEA0B7B6D65008559A1 /* Build configuration list for PBXNativeTarget "XMPFiles Debug" */;
+ buildPhases = (
+ 01FC6CD50B7B6D65008559A1 /* Sources */,
+ 01FC6CE90B7B6D65008559A1 /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = "XMPFiles Debug";
+ productName = "Debug-static";
+ productReference = 01FC6CEC0B7B6D65008559A1 /* libXMPFilesStaticDebug.a */;
+ productType = "com.apple.product-type.library.static";
+ };
+ 01FC6CF20B7B7514008559A1 /* XMPFiles Release */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 01FC6D080B7B7514008559A1 /* Build configuration list for PBXNativeTarget "XMPFiles Release" */;
+ buildPhases = (
+ 01FC6CF30B7B7514008559A1 /* Sources */,
+ 01FC6D070B7B7514008559A1 /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = "XMPFiles Release";
+ productName = "Debug-static";
+ productReference = 01FC6D0A0B7B7514008559A1 /* libXMPFilesStaticRelease.a */;
+ productType = "com.apple.product-type.library.static";
+ };
+ DC49326B089A9441003ADAAF /* XMPCore Debug */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = DC49326D089A9460003ADAAF /* Build configuration list for PBXNativeTarget "XMPCore Debug" */;
+ buildPhases = (
+ DC493269089A9441003ADAAF /* Sources */,
+ DC49326A089A9441003ADAAF /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = "XMPCore Debug";
+ productName = "Debug-static";
+ productReference = DC49326C089A9441003ADAAF /* libXMPCoreStaticDebug.a */;
+ productType = "com.apple.product-type.library.static";
+ };
+ DC493293089A9726003ADAAF /* XMPCore Release */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = DC4932AD089A9726003ADAAF /* Build configuration list for PBXNativeTarget "XMPCore Release" */;
+ buildPhases = (
+ DC493295089A9726003ADAAF /* Sources */,
+ DC4932AC089A9726003ADAAF /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = "XMPCore Release";
+ productName = "Debug-static";
+ productReference = DC4932B0089A9726003ADAAF /* libXMPCoreStaticRelease.a */;
+ productType = "com.apple.product-type.library.static";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 0867D690FE84028FC02AAC07 /* Project object */ = {
+ isa = PBXProject;
+ buildConfigurationList = 07601E2C085F9443003FEB33 /* Build configuration list for PBXProject "XMPToolkit" */;
+ hasScannedForEncodings = 1;
+ mainGroup = 0867D691FE84028FC02AAC07 /* AdobeXMP */;
+ productRefGroup = 0867D691FE84028FC02AAC07 /* AdobeXMP */;
+ projectDirPath = "";
+ targets = (
+ DCF912BC09A3E6970055523F /* Build All */,
+ DC49326B089A9441003ADAAF /* XMPCore Debug */,
+ DC493293089A9726003ADAAF /* XMPCore Release */,
+ 01FC6CD40B7B6D65008559A1 /* XMPFiles Debug */,
+ 01FC6CF20B7B7514008559A1 /* XMPFiles Release */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 01FC6CD50B7B6D65008559A1 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 01FC6CE80B7B6D65008559A1 /* WXMPFiles.cpp in Sources */,
+ 01FC6D3D0B7B7789008559A1 /* ID3_Support.cpp in Sources */,
+ 01FC6D3E0B7B7789008559A1 /* IPTC_Support.cpp in Sources */,
+ 01FC6D3F0B7B7789008559A1 /* PNG_Support.cpp in Sources */,
+ 01FC6D400B7B7789008559A1 /* PSIR_FileWriter.cpp in Sources */,
+ 01FC6D410B7B7789008559A1 /* PSIR_MemoryReader.cpp in Sources */,
+ 01FC6D420B7B7789008559A1 /* QuickTime_Support.cpp in Sources */,
+ 01FC6D430B7B7789008559A1 /* Reconcile_Impl.cpp in Sources */,
+ 01FC6D440B7B7789008559A1 /* ReconcileIPTC.cpp in Sources */,
+ 01FC6D450B7B7789008559A1 /* ReconcileLegacy.cpp in Sources */,
+ 01FC6D460B7B7789008559A1 /* ReconcileTIFF.cpp in Sources */,
+ 01FC6D470B7B7789008559A1 /* RIFF_Support.cpp in Sources */,
+ 01FC6D490B7B7789008559A1 /* TIFF_FileWriter.cpp in Sources */,
+ 01FC6D4A0B7B7789008559A1 /* TIFF_MemoryReader.cpp in Sources */,
+ 01FC6D4B0B7B7789008559A1 /* TIFF_Support.cpp in Sources */,
+ 01FC6D4C0B7B7789008559A1 /* XMPScanner.cpp in Sources */,
+ 01FC6D5F0B7B7799008559A1 /* AVI_Handler.cpp in Sources */,
+ 01FC6D600B7B7799008559A1 /* Basic_Handler.cpp in Sources */,
+ 01FC6D610B7B7799008559A1 /* InDesign_Handler.cpp in Sources */,
+ 01FC6D620B7B7799008559A1 /* JPEG_Handler.cpp in Sources */,
+ 01FC6D640B7B7799008559A1 /* MOV_Handler.cpp in Sources */,
+ 01FC6D650B7B7799008559A1 /* MP3_Handler.cpp in Sources */,
+ 01FC6D670B7B7799008559A1 /* MPEG_Handler.cpp in Sources */,
+ 01FC6D680B7B7799008559A1 /* PNG_Handler.cpp in Sources */,
+ 01FC6D690B7B7799008559A1 /* PostScript_Handler.cpp in Sources */,
+ 01FC6D6A0B7B7799008559A1 /* PSD_Handler.cpp in Sources */,
+ 01FC6D6B0B7B7799008559A1 /* Scanner_Handler.cpp in Sources */,
+ 01FC6D6D0B7B7799008559A1 /* TIFF_Handler.cpp in Sources */,
+ 01FC6D6E0B7B7799008559A1 /* Trivial_Handler.cpp in Sources */,
+ 01FC6D6F0B7B7799008559A1 /* WAV_Handler.cpp in Sources */,
+ 01FC6D870B7B77D9008559A1 /* WXMPFiles.cpp in Sources */,
+ 01FC6D880B7B77D9008559A1 /* XMPFiles.cpp in Sources */,
+ 01FC6D890B7B77D9008559A1 /* XMPFiles_Impl.cpp in Sources */,
+ 0102D1C70B7B8471001AF6F7 /* MD5.cpp in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 01FC6CF30B7B7514008559A1 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 01FC6D060B7B7514008559A1 /* WXMPFiles.cpp in Sources */,
+ 01FC6D4E0B7B778A008559A1 /* ID3_Support.cpp in Sources */,
+ 01FC6D4F0B7B778A008559A1 /* IPTC_Support.cpp in Sources */,
+ 01FC6D500B7B778A008559A1 /* PNG_Support.cpp in Sources */,
+ 01FC6D510B7B778A008559A1 /* PSIR_FileWriter.cpp in Sources */,
+ 01FC6D520B7B778A008559A1 /* PSIR_MemoryReader.cpp in Sources */,
+ 01FC6D530B7B778A008559A1 /* QuickTime_Support.cpp in Sources */,
+ 01FC6D540B7B778A008559A1 /* Reconcile_Impl.cpp in Sources */,
+ 01FC6D550B7B778A008559A1 /* ReconcileIPTC.cpp in Sources */,
+ 01FC6D560B7B778A008559A1 /* ReconcileLegacy.cpp in Sources */,
+ 01FC6D570B7B778A008559A1 /* ReconcileTIFF.cpp in Sources */,
+ 01FC6D580B7B778A008559A1 /* RIFF_Support.cpp in Sources */,
+ 01FC6D5A0B7B778A008559A1 /* TIFF_FileWriter.cpp in Sources */,
+ 01FC6D5B0B7B778A008559A1 /* TIFF_MemoryReader.cpp in Sources */,
+ 01FC6D5C0B7B778A008559A1 /* TIFF_Support.cpp in Sources */,
+ 01FC6D5D0B7B778A008559A1 /* XMPScanner.cpp in Sources */,
+ 01FC6D710B7B779A008559A1 /* AVI_Handler.cpp in Sources */,
+ 01FC6D720B7B779A008559A1 /* Basic_Handler.cpp in Sources */,
+ 01FC6D730B7B779A008559A1 /* InDesign_Handler.cpp in Sources */,
+ 01FC6D740B7B779A008559A1 /* JPEG_Handler.cpp in Sources */,
+ 01FC6D760B7B779A008559A1 /* MOV_Handler.cpp in Sources */,
+ 01FC6D770B7B779A008559A1 /* MP3_Handler.cpp in Sources */,
+ 01FC6D790B7B779A008559A1 /* MPEG_Handler.cpp in Sources */,
+ 01FC6D7A0B7B779A008559A1 /* PNG_Handler.cpp in Sources */,
+ 01FC6D7B0B7B779A008559A1 /* PostScript_Handler.cpp in Sources */,
+ 01FC6D7C0B7B779A008559A1 /* PSD_Handler.cpp in Sources */,
+ 01FC6D7D0B7B779A008559A1 /* Scanner_Handler.cpp in Sources */,
+ 01FC6D7F0B7B779A008559A1 /* TIFF_Handler.cpp in Sources */,
+ 01FC6D800B7B779A008559A1 /* Trivial_Handler.cpp in Sources */,
+ 01FC6D810B7B779A008559A1 /* WAV_Handler.cpp in Sources */,
+ 01FC6D8A0B7B77DA008559A1 /* WXMPFiles.cpp in Sources */,
+ 01FC6D8B0B7B77DA008559A1 /* XMPFiles.cpp in Sources */,
+ 01FC6D8C0B7B77DA008559A1 /* XMPFiles_Impl.cpp in Sources */,
+ 0102D1C80B7B8472001AF6F7 /* MD5.cpp in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ DC493269089A9441003ADAAF /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ DC493270089A94CE003ADAAF /* XMPIterator.cpp in Sources */,
+ DC493271089A94CE003ADAAF /* XMPMeta.cpp in Sources */,
+ DC493272089A94CE003ADAAF /* XMPMeta-GetSet.cpp in Sources */,
+ DC493273089A94CE003ADAAF /* XMPMeta-Parse.cpp in Sources */,
+ DC493274089A94CE003ADAAF /* XMPMeta-Serialize.cpp in Sources */,
+ DC493275089A94CE003ADAAF /* XMPUtils.cpp in Sources */,
+ DC49327B089A94E6003ADAAF /* ExpatAdapter.cpp in Sources */,
+ DC49327D089A94E6003ADAAF /* ParseRDF.cpp in Sources */,
+ DC49327E089A94E6003ADAAF /* UnicodeConversions.cpp in Sources */,
+ DC49327F089A94FF003ADAAF /* xmlparse.c in Sources */,
+ DC493280089A94FF003ADAAF /* xmlrole.c in Sources */,
+ DC493281089A94FF003ADAAF /* xmltok.c in Sources */,
+ DC493282089A950C003ADAAF /* WXMPIterator.cpp in Sources */,
+ DC493283089A950C003ADAAF /* WXMPMeta.cpp in Sources */,
+ DC493284089A950C003ADAAF /* WXMPUtils.cpp in Sources */,
+ DCEDFE2509ACBECF00D86460 /* XMPUtils-FileInfo.cpp in Sources */,
+ 014796520B776899007CF8F4 /* XMPCore_Impl.cpp in Sources */,
+ 014A2AA20B78FF2C00A80B2A /* MD5.cpp in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ DC493295089A9726003ADAAF /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ DC493297089A9726003ADAAF /* XMPIterator.cpp in Sources */,
+ DC493298089A9726003ADAAF /* XMPMeta.cpp in Sources */,
+ DC493299089A9726003ADAAF /* XMPMeta-GetSet.cpp in Sources */,
+ DC49329A089A9726003ADAAF /* XMPMeta-Parse.cpp in Sources */,
+ DC49329B089A9726003ADAAF /* XMPMeta-Serialize.cpp in Sources */,
+ DC49329C089A9726003ADAAF /* XMPUtils.cpp in Sources */,
+ DC4932A2089A9726003ADAAF /* ExpatAdapter.cpp in Sources */,
+ DC4932A4089A9726003ADAAF /* ParseRDF.cpp in Sources */,
+ DC4932A5089A9726003ADAAF /* UnicodeConversions.cpp in Sources */,
+ DC4932A6089A9726003ADAAF /* xmlparse.c in Sources */,
+ DC4932A7089A9726003ADAAF /* xmlrole.c in Sources */,
+ DC4932A8089A9726003ADAAF /* xmltok.c in Sources */,
+ DC4932A9089A9726003ADAAF /* WXMPIterator.cpp in Sources */,
+ DC4932AA089A9726003ADAAF /* WXMPMeta.cpp in Sources */,
+ DC4932AB089A9726003ADAAF /* WXMPUtils.cpp in Sources */,
+ DCEDFE2609ACBECF00D86460 /* XMPUtils-FileInfo.cpp in Sources */,
+ 014796530B776899007CF8F4 /* XMPCore_Impl.cpp in Sources */,
+ 014A2AA30B78FF2C00A80B2A /* MD5.cpp in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ 01FC6D900B7B7858008559A1 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 01FC6CF20B7B7514008559A1 /* XMPFiles Release */;
+ targetProxy = 01FC6D8F0B7B7858008559A1 /* PBXContainerItemProxy */;
+ };
+ 01FC6D920B7B7858008559A1 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 01FC6CD40B7B6D65008559A1 /* XMPFiles Debug */;
+ targetProxy = 01FC6D910B7B7858008559A1 /* PBXContainerItemProxy */;
+ };
+ DCF912BE09A3E6A40055523F /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = DC49326B089A9441003ADAAF /* XMPCore Debug */;
+ targetProxy = DCF912BD09A3E6A40055523F /* PBXContainerItemProxy */;
+ };
+ DCF912C009A3E6A70055523F /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = DC493293089A9726003ADAAF /* XMPCore Release */;
+ targetProxy = DCF912BF09A3E6A70055523F /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin XCBuildConfiguration section */
+ 01FC6CEB0B7B6D65008559A1 /* Default */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = DCE400F80951DAA90040D71F /* XMPToolkit-Debug.xcconfig */;
+ buildSettings = {
+ PRODUCT_NAME = XMPFilesStaticDebug;
+ };
+ name = Default;
+ };
+ 01FC6D090B7B7514008559A1 /* Default */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = DCE400F90951DAA90040D71F /* XMPToolkit-Release.xcconfig */;
+ buildSettings = {
+ PRODUCT_NAME = XMPFilesStaticRelease;
+ };
+ name = Default;
+ };
+ 07A256240868DD5F00CA045D /* Default */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = DCE400F70951DAA90040D71F /* XMPToolkit-Common.xcconfig */;
+ buildSettings = {
+ };
+ name = Default;
+ };
+ DC49326E089A9460003ADAAF /* Default */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = DCE400F80951DAA90040D71F /* XMPToolkit-Debug.xcconfig */;
+ buildSettings = {
+ PRODUCT_NAME = XMPCoreStaticDebug;
+ };
+ name = Default;
+ };
+ DC4932AE089A9726003ADAAF /* Default */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = DCE400F90951DAA90040D71F /* XMPToolkit-Release.xcconfig */;
+ buildSettings = {
+ PRODUCT_NAME = XMPCoreStaticRelease;
+ };
+ name = Default;
+ };
+ DCF912C209A3E6C60055523F /* Default */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "Build All";
+ };
+ name = Default;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 01FC6CEA0B7B6D65008559A1 /* Build configuration list for PBXNativeTarget "XMPFiles Debug" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 01FC6CEB0B7B6D65008559A1 /* Default */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Default;
+ };
+ 01FC6D080B7B7514008559A1 /* Build configuration list for PBXNativeTarget "XMPFiles Release" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 01FC6D090B7B7514008559A1 /* Default */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Default;
+ };
+ 07601E2C085F9443003FEB33 /* Build configuration list for PBXProject "XMPToolkit" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 07A256240868DD5F00CA045D /* Default */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Default;
+ };
+ DC49326D089A9460003ADAAF /* Build configuration list for PBXNativeTarget "XMPCore Debug" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ DC49326E089A9460003ADAAF /* Default */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Default;
+ };
+ DC4932AD089A9726003ADAAF /* Build configuration list for PBXNativeTarget "XMPCore Release" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ DC4932AE089A9726003ADAAF /* Default */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Default;
+ };
+ DCF912C109A3E6C60055523F /* Build configuration list for PBXAggregateTarget "Build All" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ DCF912C209A3E6C60055523F /* Default */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Default;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 0867D690FE84028FC02AAC07 /* Project object */;
+}
diff --git a/build/xcode/expat_config.h b/build/xcode/expat_config.h
new file mode 100644
index 0000000..a21de6e
--- /dev/null
+++ b/build/xcode/expat_config.h
@@ -0,0 +1,107 @@
+/* expat_config.h. Generated by configure. */
+/* expat_config.h.in. Generated from configure.in by autoheader. */
+
+/* *** Tweaked by hand for 32 bit Xcode builds on PowerPC and x86 */
+
+#if __BIG_ENDIAN__
+
+ /* 1234 = LIL_ENDIAN, 4321 = BIGENDIAN */
+ #define BYTEORDER 4321
+
+ /* whether byteorder is bigendian */
+ #define WORDS_BIGENDIAN 1
+
+#else
+
+ /* 1234 = LIL_ENDIAN, 4321 = BIGENDIAN */
+ #define BYTEORDER 1234
+
+ /* whether byteorder is bigendian */
+ /* #define WORDS_BIGENDIAN 1 */
+
+#endif
+
+/* Define to 1 if you have the `bcopy' function. */
+#define HAVE_BCOPY 1
+
+/* Define to 1 if you have the <check.h> header file. */
+/* #undef HAVE_CHECK_H */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have the `getpagesize' function. */
+#define HAVE_GETPAGESIZE 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `memmove' function. */
+#define HAVE_MEMMOVE 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have a working `mmap' system call. */
+#define HAVE_MMAP 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "expat-bugs@mail.libexpat.org"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "expat"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "expat 1.95.8"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "expat"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "1.95.8"
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to specify how much context to retain around the current parse
+ point. */
+#define XML_CONTEXT_BYTES 1024
+
+/* Define to make parameter entity parsing functionality available. */
+/* #define XML_DTD 1 */
+
+/* Define to make XML Namespaces functionality available. */
+#define XML_NS 1
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to `long' if <sys/types.h> does not define. */
+/* #undef off_t */
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+/* #undef size_t */
diff --git a/docs/BSD-License.txt b/docs/BSD-License.txt
new file mode 100644
index 0000000..e413f87
--- /dev/null
+++ b/docs/BSD-License.txt
@@ -0,0 +1,25 @@
+The BSD License
+
+Copyright (c) 1999 - 2007, Adobe Systems Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+* Neither the name of Adobe Systems Incorporated, nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
diff --git a/docs/XMP-SDK-Overview.pdf b/docs/XMP-SDK-Overview.pdf
new file mode 100644
index 0000000..9ad8b6d
--- /dev/null
+++ b/docs/XMP-SDK-Overview.pdf
Binary files differ
diff --git a/docs/XMP-Specification.pdf b/docs/XMP-Specification.pdf
new file mode 100644
index 0000000..c66f122
--- /dev/null
+++ b/docs/XMP-Specification.pdf
Binary files differ
diff --git a/docs/XMPToolkit/TXMPFiles_8hpp-source.html b/docs/XMPToolkit/TXMPFiles_8hpp-source.html
new file mode 100644
index 0000000..aa8571e
--- /dev/null
+++ b/docs/XMPToolkit/TXMPFiles_8hpp-source.html
@@ -0,0 +1,162 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
+<title>Adobe XMP Toolkit: TXMPFiles.hpp Source File</title>
+<link href="doxygen.css" rel="stylesheet" type="text/css">
+<link href="tabs.css" rel="stylesheet" type="text/css">
+</head><body>
+<!-- Generated by Doxygen 1.5.1 -->
+<div class="tabs">
+ <ul>
+ <li><a href="index.html"><span>Main&nbsp;Page</span></a></li>
+ <li><a href="modules.html"><span>Modules</span></a></li>
+ <li><a href="annotated.html"><span>Classes</span></a></li>
+ <li id="current"><a href="files.html"><span>Files</span></a></li>
+ </ul></div>
+<h1>TXMPFiles.hpp</h1><a href="TXMPFiles_8hpp.html">Go to the documentation of this file.</a><div class="fragment"><pre class="fragment"><a name="l00001"></a>00001 <span class="preprocessor">#ifndef __TXMPFiles_hpp__</span>
+<a name="l00002"></a>00002 <span class="preprocessor"></span><span class="preprocessor">#define __TXMPFiles_hpp__ 1</span>
+<a name="l00003"></a>00003 <span class="preprocessor"></span>
+<a name="l00004"></a>00004 <span class="preprocessor">#if ( ! __XMP_hpp__ )</span>
+<a name="l00005"></a>00005 <span class="preprocessor"></span><span class="preprocessor"> #error "Do not directly include, use XMP.hpp"</span>
+<a name="l00006"></a>00006 <span class="preprocessor"></span><span class="preprocessor">#endif</span>
+<a name="l00007"></a>00007 <span class="preprocessor"></span>
+<a name="l00008"></a>00008 <span class="comment">// =================================================================================================</span>
+<a name="l00009"></a>00009 <span class="comment">// ADOBE SYSTEMS INCORPORATED</span>
+<a name="l00010"></a>00010 <span class="comment">// Copyright 2002-2007 Adobe Systems Incorporated</span>
+<a name="l00011"></a>00011 <span class="comment">// All Rights Reserved</span>
+<a name="l00012"></a>00012 <span class="comment">//</span>
+<a name="l00013"></a>00013 <span class="comment">// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms</span>
+<a name="l00014"></a>00014 <span class="comment">// of the Adobe license agreement accompanying it.</span>
+<a name="l00015"></a>00015 <span class="comment">// =================================================================================================</span>
+<a name="l00016"></a>00016
+<a name="l00017"></a>00017 <span class="comment">// ================================================================================================</span>
+<a name="l00033"></a>00033 <span class="comment"></span><span class="comment">// ================================================================================================</span>
+<a name="l00034"></a>00034
+<a name="l00035"></a>00035 <span class="comment">// ================================================================================================</span>
+<a name="l00060"></a>00060 <span class="comment"></span><span class="comment">// ================================================================================================</span>
+<a name="l00061"></a>00061
+<a name="l00062"></a>00062 <span class="keyword">template</span> &lt;<span class="keyword">class</span> tStringObj&gt;
+<a name="l00063"></a><a class="code" href="classTXMPFiles.html">00063</a> <span class="keyword">class </span><a class="code" href="classTXMPFiles.html">TXMPFiles</a> {
+<a name="l00064"></a>00064
+<a name="l00065"></a>00065 <span class="keyword">public</span>:
+<a name="l00066"></a>00066
+<a name="l00067"></a>00067 <span class="comment">// ============================================================================================</span>
+<a name="l00071"></a>00071 <span class="comment"></span>
+<a name="l00072"></a>00072 <span class="keyword">static</span> <span class="keywordtype">void</span> GetVersionInfo ( XMP_VersionInfo * versionInfo );
+<a name="l00073"></a>00073
+<a name="l00076"></a>00076
+<a name="l00077"></a>00077 <span class="keyword">static</span> <span class="keywordtype">bool</span> <a class="code" href="classTXMPFiles.html#0874bbbf41c9490abfb613bfe297327d">Initialize</a>();
+<a name="l00078"></a>00078 <span class="keyword">static</span> <span class="keywordtype">bool</span> <a class="code" href="classTXMPFiles.html#0874bbbf41c9490abfb613bfe297327d">Initialize</a> ( <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options );
+<a name="l00079"></a>00079
+<a name="l00082"></a>00082
+<a name="l00083"></a>00083 <span class="keyword">static</span> <span class="keywordtype">void</span> <a class="code" href="classTXMPFiles.html#1e8de80c252b60b332dc4bc524139fd8">Terminate</a>();
+<a name="l00084"></a>00084
+<a name="l00086"></a>00086
+<a name="l00087"></a>00087 <span class="comment">// ============================================================================================</span>
+<a name="l00092"></a>00092 <span class="comment"></span>
+<a name="l00094"></a>00094
+<a name="l00095"></a>00095 <a class="code" href="classTXMPFiles.html#14f01e38454178578fd25fff6024fd54">TXMPFiles</a>();
+<a name="l00096"></a>00096 <span class="keyword">virtual</span> ~<a class="code" href="classTXMPFiles.html">TXMPFiles</a>() <span class="keywordflow">throw</span>();
+<a name="l00097"></a>00097
+<a name="l00100"></a>00100
+<a name="l00101"></a>00101 <a class="code" href="classTXMPFiles.html#14f01e38454178578fd25fff6024fd54">TXMPFiles</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> filePath,
+<a name="l00102"></a>00102 XMP_FileFormat format = kXMP_UnknownFile,
+<a name="l00103"></a>00103 <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> openFlags = 0 );
+<a name="l00104"></a>00104
+<a name="l00105"></a>00105 <a class="code" href="classTXMPFiles.html#14f01e38454178578fd25fff6024fd54">TXMPFiles</a> ( <span class="keyword">const</span> tStringObj &amp; filePath,
+<a name="l00106"></a>00106 XMP_FileFormat format = kXMP_UnknownFile,
+<a name="l00107"></a>00107 <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> openFlags = 0 );
+<a name="l00108"></a>00108
+<a name="l00111"></a>00111
+<a name="l00112"></a>00112 <a class="code" href="classTXMPFiles.html#14f01e38454178578fd25fff6024fd54">TXMPFiles</a> ( <span class="keyword">const</span> <a class="code" href="classTXMPFiles.html">TXMPFiles&lt;tStringObj&gt;</a> &amp; original );
+<a name="l00113"></a>00113
+<a name="l00114"></a>00114 <span class="keywordtype">void</span> operator= ( <span class="keyword">const</span> <a class="code" href="classTXMPFiles.html">TXMPFiles&lt;tStringObj&gt;</a> &amp; rhs );
+<a name="l00115"></a>00115
+<a name="l00119"></a>00119
+<a name="l00120"></a>00120 <a class="code" href="classTXMPFiles.html#14f01e38454178578fd25fff6024fd54">TXMPFiles</a> ( XMPFilesRef xmpFilesObj );
+<a name="l00121"></a>00121
+<a name="l00122"></a>00122 XMPFilesRef GetInternalRef();
+<a name="l00123"></a>00123
+<a name="l00125"></a>00125
+<a name="l00126"></a>00126 <span class="comment">// ============================================================================================</span>
+<a name="l00129"></a>00129 <span class="comment"></span>
+<a name="l00130"></a>00130 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00158"></a>00158 <span class="comment"></span>
+<a name="l00159"></a>00159 <span class="keyword">static</span> <span class="keywordtype">bool</span> <a class="code" href="classTXMPFiles.html#6ac78e3c7286ca8dcb41eaa007aa00e8">GetFormatInfo</a> ( XMP_FileFormat format,
+<a name="l00160"></a>00160 <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> * handlerFlags = 0 );
+<a name="l00161"></a>00161
+<a name="l00163"></a>00163
+<a name="l00164"></a>00164 <span class="comment">// ============================================================================================</span>
+<a name="l00167"></a>00167 <span class="comment"></span>
+<a name="l00168"></a>00168 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00223"></a>00223 <span class="comment"></span>
+<a name="l00224"></a>00224 <span class="keywordtype">bool</span> <a class="code" href="classTXMPFiles.html#fcd21cfe5d6f13c648c5541e161919cb">OpenFile</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> filePath,
+<a name="l00225"></a>00225 XMP_FileFormat format = kXMP_UnknownFile,
+<a name="l00226"></a>00226 <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> openFlags = 0 );
+<a name="l00227"></a>00227
+<a name="l00228"></a>00228 <span class="keywordtype">bool</span> <a class="code" href="classTXMPFiles.html#fcd21cfe5d6f13c648c5541e161919cb">OpenFile</a> ( <span class="keyword">const</span> tStringObj &amp; filePath,
+<a name="l00229"></a>00229 XMP_FileFormat format = kXMP_UnknownFile,
+<a name="l00230"></a>00230 <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> openFlags = 0 );
+<a name="l00231"></a>00231
+<a name="l00232"></a>00232 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00243"></a>00243 <span class="comment"></span>
+<a name="l00244"></a>00244 <span class="keywordtype">void</span> <a class="code" href="classTXMPFiles.html#eca89170c7aa3e2d56e30bff04dd7927">CloseFile</a> ( <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> closeFlags = 0 );
+<a name="l00245"></a>00245
+<a name="l00246"></a>00246 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00260"></a>00260 <span class="comment"></span>
+<a name="l00261"></a>00261 <span class="keywordtype">bool</span> <a class="code" href="classTXMPFiles.html#f9931d081cb19f98c81e41786030765b">GetFileInfo</a> ( tStringObj * filePath = 0,
+<a name="l00262"></a>00262 <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> * openFlags = 0,
+<a name="l00263"></a>00263 XMP_FileFormat * format = 0,
+<a name="l00264"></a>00264 <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> * handlerFlags = 0 );
+<a name="l00265"></a>00265
+<a name="l00266"></a>00266 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00274"></a>00274 <span class="comment"></span>
+<a name="l00275"></a>00275 <span class="keywordtype">void</span> <a class="code" href="classTXMPFiles.html#7b86c130fdbd54b5ac158ec3fee93777">SetAbortProc</a> ( XMP_AbortProc abortProc,
+<a name="l00276"></a>00276 <span class="keywordtype">void</span> * abortArg );
+<a name="l00277"></a>00277
+<a name="l00279"></a>00279
+<a name="l00280"></a>00280 <span class="comment">// ============================================================================================</span>
+<a name="l00283"></a>00283 <span class="comment"></span>
+<a name="l00284"></a>00284 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00313"></a>00313 <span class="comment"></span>
+<a name="l00314"></a>00314 <span class="keywordtype">bool</span> <a class="code" href="classTXMPFiles.html#42ca0bbc5ac66a8de1710e03a7ff17b3">GetXMP</a> ( SXMPMeta * xmpObj = 0,
+<a name="l00315"></a>00315 tStringObj * xmpPacket = 0,
+<a name="l00316"></a>00316 XMP_PacketInfo * packetInfo = 0 );
+<a name="l00317"></a>00317
+<a name="l00318"></a>00318 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00347"></a>00347 <span class="comment"></span>
+<a name="l00348"></a>00348 <span class="keywordtype">bool</span> <a class="code" href="classTXMPFiles.html#4ea1eda39f803322e10b2a554ef8ab06">GetThumbnail</a> ( XMP_ThumbnailInfo * tnailInfo );
+<a name="l00349"></a>00349
+<a name="l00350"></a>00350 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00357"></a>00357 <span class="comment"></span>
+<a name="l00358"></a>00358 <span class="keywordtype">void</span> <a class="code" href="classTXMPFiles.html#d3f7babdc07c7de0d0cd9a3362b4710a">PutXMP</a> ( <span class="keyword">const</span> SXMPMeta &amp; xmpObj );
+<a name="l00359"></a>00359
+<a name="l00360"></a>00360 <span class="keywordtype">void</span> <a class="code" href="classTXMPFiles.html#d3f7babdc07c7de0d0cd9a3362b4710a">PutXMP</a> ( <span class="keyword">const</span> tStringObj &amp; xmpPacket );
+<a name="l00361"></a>00361
+<a name="l00362"></a>00362 <span class="keywordtype">void</span> <a class="code" href="classTXMPFiles.html#d3f7babdc07c7de0d0cd9a3362b4710a">PutXMP</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> xmpPacket,
+<a name="l00363"></a>00363 <a class="code" href="XMP__Const_8h.html#9f7dcc184f901c713274edfdac5bcc9a">XMP_StringLen</a> xmpLength = kXMP_UseNullTermination );
+<a name="l00364"></a>00364
+<a name="l00365"></a>00365 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00399"></a>00399 <span class="comment"></span>
+<a name="l00400"></a>00400 <span class="keywordtype">bool</span> <a class="code" href="classTXMPFiles.html#29a11a1539d6300da3fb4c7e9ea02bb6">CanPutXMP</a> ( <span class="keyword">const</span> SXMPMeta &amp; xmpObj );
+<a name="l00401"></a>00401
+<a name="l00402"></a>00402 <span class="keywordtype">bool</span> <a class="code" href="classTXMPFiles.html#29a11a1539d6300da3fb4c7e9ea02bb6">CanPutXMP</a> ( <span class="keyword">const</span> tStringObj &amp; xmpPacket );
+<a name="l00403"></a>00403
+<a name="l00404"></a>00404 <span class="keywordtype">bool</span> <a class="code" href="classTXMPFiles.html#29a11a1539d6300da3fb4c7e9ea02bb6">CanPutXMP</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> xmpPacket,
+<a name="l00405"></a>00405 <a class="code" href="XMP__Const_8h.html#9f7dcc184f901c713274edfdac5bcc9a">XMP_StringLen</a> xmpLength = kXMP_UseNullTermination );
+<a name="l00406"></a>00406
+<a name="l00408"></a>00408
+<a name="l00409"></a>00409 <span class="comment">// =============================================================================================</span>
+<a name="l00410"></a>00410
+<a name="l00411"></a>00411 <span class="keyword">private</span>:
+<a name="l00412"></a>00412 XMPFilesRef xmpFilesRef;
+<a name="l00413"></a>00413
+<a name="l00414"></a>00414 }; <span class="comment">// class TXMPFiles</span>
+<a name="l00415"></a>00415
+<a name="l00416"></a>00416 <span class="comment">// =================================================================================================</span>
+<a name="l00417"></a>00417
+<a name="l00418"></a>00418 <span class="preprocessor">#endif // __TXMPFiles_hpp__</span>
+</pre></div><hr size="1"><address style="align: right;"><small>Generated on Thu May 3 14:54:57 2007 for Adobe XMP Toolkit by&nbsp;
+<a href="http://www.doxygen.org/index.html">
+<img src="doxygen.png" alt="doxygen" align="middle" border="0"></a> 1.5.1 </small></address>
+</body>
+</html>
diff --git a/docs/XMPToolkit/TXMPFiles_8hpp.html b/docs/XMPToolkit/TXMPFiles_8hpp.html
new file mode 100644
index 0000000..48e78dc
--- /dev/null
+++ b/docs/XMPToolkit/TXMPFiles_8hpp.html
@@ -0,0 +1,34 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
+<title>Adobe XMP Toolkit: TXMPFiles.hpp File Reference</title>
+<link href="doxygen.css" rel="stylesheet" type="text/css">
+<link href="tabs.css" rel="stylesheet" type="text/css">
+</head><body>
+<!-- Generated by Doxygen 1.5.1 -->
+<div class="tabs">
+ <ul>
+ <li><a href="index.html"><span>Main&nbsp;Page</span></a></li>
+ <li><a href="modules.html"><span>Modules</span></a></li>
+ <li><a href="annotated.html"><span>Classes</span></a></li>
+ <li id="current"><a href="files.html"><span>Files</span></a></li>
+ </ul></div>
+<h1>TXMPFiles.hpp File Reference</h1>API for access to the "main" metadata in a file. <a href="#_details">More...</a>
+<p>
+
+<p>
+<a href="TXMPFiles_8hpp-source.html">Go to the source code of this file.</a><table border="0" cellpadding="0" cellspacing="0">
+<tr><td></td></tr>
+<tr><td colspan="2"><br><h2>Classes</h2></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">class &nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPFiles.html">TXMPFiles&lt; tStringObj &gt;</a></td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">API for access to the "main" metadata in a file. <a href="classTXMPFiles.html#_details">More...</a><br></td></tr>
+</table>
+<hr><a name="_details"></a><h2>Detailed Description</h2>
+API for access to the "main" metadata in a file.
+<p>
+<code><a class="el" href="classTXMPFiles.html">TXMPFiles</a></code> provides the API for the Adobe XMP Toolkit's File Handler component. This provides convenient access to the main, or document level, XMP for a file. The File Handler supports file I/O, the XMP Toolkit Core supports manipulation of the XMP properties. The File Handler is intended to eventually have smart, efficient support for all file formats for which the means to embed XMP is defined in the XMP Specification. Where possible this support will allow injection of XMP where none currently exists, expansion of XMP without regard to existing padding, and reconciliation of the XMP and other legacy forms of metadata.<p>
+<code><a class="el" href="classTXMPFiles.html">TXMPFiles</a></code> is designed for use by clients interested in the metadata and not in the primary file content. The Adobe Bridge application is a typical example. <code><a class="el" href="classTXMPFiles.html">TXMPFiles</a></code> is not intended to be particulary appropriate for files authored by an application. I.e. those files for which the application has explicit knowledge of the file format. <hr size="1"><address style="align: right;"><small>Generated on Thu May 3 14:54:57 2007 for Adobe XMP Toolkit by&nbsp;
+<a href="http://www.doxygen.org/index.html">
+<img src="doxygen.png" alt="doxygen" align="middle" border="0"></a> 1.5.1 </small></address>
+</body>
+</html>
diff --git a/docs/XMPToolkit/TXMPFiles_8incl__cpp.html b/docs/XMPToolkit/TXMPFiles_8incl__cpp.html
new file mode 100644
index 0000000..146d09b
--- /dev/null
+++ b/docs/XMPToolkit/TXMPFiles_8incl__cpp.html
@@ -0,0 +1,32 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
+<title>Adobe XMP Toolkit: TXMPFiles.incl_cpp File Reference</title>
+<link href="doxygen.css" rel="stylesheet" type="text/css">
+<link href="tabs.css" rel="stylesheet" type="text/css">
+</head><body>
+<!-- Generated by Doxygen 1.5.1 -->
+<div class="tabs">
+ <ul>
+ <li><a href="index.html"><span>Main&nbsp;Page</span></a></li>
+ <li><a href="modules.html"><span>Modules</span></a></li>
+ <li><a href="annotated.html"><span>Classes</span></a></li>
+ <li id="current"><a href="files.html"><span>Files</span></a></li>
+ </ul></div>
+<h1>TXMPFiles.incl_cpp File Reference</h1>The implementation of the <a class="el" href="classTXMPFiles.html">TXMPFiles</a> template class. <a href="#_details">More...</a>
+<p>
+<code>#include &quot;client-glue/WXMP_Common.hpp&quot;</code><br>
+<code>#include &quot;client-glue/WXMPFiles.hpp&quot;</code><br>
+
+<p>
+Include dependency graph for TXMPFiles.incl_cpp:<p><center><img src="TXMPFiles_8incl__cpp__incl.png" border="0" usemap="#TXMPFiles.incl_cpp_map" alt=""></center>
+<table border="0" cellpadding="0" cellspacing="0">
+<tr><td></td></tr>
+</table>
+<hr><a name="_details"></a><h2>Detailed Description</h2>
+The implementation of the <a class="el" href="classTXMPFiles.html">TXMPFiles</a> template class.
+<p>
+<hr size="1"><address style="align: right;"><small>Generated on Thu May 3 14:54:57 2007 for Adobe XMP Toolkit by&nbsp;
+<a href="http://www.doxygen.org/index.html">
+<img src="doxygen.png" alt="doxygen" align="middle" border="0"></a> 1.5.1 </small></address>
+</body>
+</html>
diff --git a/docs/XMPToolkit/TXMPFiles_8incl__cpp__incl.png b/docs/XMPToolkit/TXMPFiles_8incl__cpp__incl.png
new file mode 100644
index 0000000..704bd4f
--- /dev/null
+++ b/docs/XMPToolkit/TXMPFiles_8incl__cpp__incl.png
Binary files differ
diff --git a/docs/XMPToolkit/TXMPIterator_8hpp-source.html b/docs/XMPToolkit/TXMPIterator_8hpp-source.html
new file mode 100644
index 0000000..8ef6239
--- /dev/null
+++ b/docs/XMPToolkit/TXMPIterator_8hpp-source.html
@@ -0,0 +1,104 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
+<title>Adobe XMP Toolkit: TXMPIterator.hpp Source File</title>
+<link href="doxygen.css" rel="stylesheet" type="text/css">
+<link href="tabs.css" rel="stylesheet" type="text/css">
+</head><body>
+<!-- Generated by Doxygen 1.5.1 -->
+<div class="tabs">
+ <ul>
+ <li><a href="index.html"><span>Main&nbsp;Page</span></a></li>
+ <li><a href="modules.html"><span>Modules</span></a></li>
+ <li><a href="annotated.html"><span>Classes</span></a></li>
+ <li id="current"><a href="files.html"><span>Files</span></a></li>
+ </ul></div>
+<h1>TXMPIterator.hpp</h1><a href="TXMPIterator_8hpp.html">Go to the documentation of this file.</a><div class="fragment"><pre class="fragment"><a name="l00001"></a>00001 <span class="preprocessor">#ifndef __TXMPIterator_hpp__</span>
+<a name="l00002"></a>00002 <span class="preprocessor"></span><span class="preprocessor">#define __TXMPIterator_hpp__ 1</span>
+<a name="l00003"></a>00003 <span class="preprocessor"></span>
+<a name="l00004"></a>00004 <span class="preprocessor">#if ( ! __XMP_hpp__ )</span>
+<a name="l00005"></a>00005 <span class="preprocessor"></span><span class="preprocessor"> #error "Do not directly include, use XMP.hpp"</span>
+<a name="l00006"></a>00006 <span class="preprocessor"></span><span class="preprocessor">#endif</span>
+<a name="l00007"></a>00007 <span class="preprocessor"></span>
+<a name="l00008"></a>00008 <span class="comment">// =================================================================================================</span>
+<a name="l00009"></a>00009 <span class="comment">// ADOBE SYSTEMS INCORPORATED</span>
+<a name="l00010"></a>00010 <span class="comment">// Copyright 2002-2007 Adobe Systems Incorporated</span>
+<a name="l00011"></a>00011 <span class="comment">// All Rights Reserved</span>
+<a name="l00012"></a>00012 <span class="comment">//</span>
+<a name="l00013"></a>00013 <span class="comment">// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms</span>
+<a name="l00014"></a>00014 <span class="comment">// of the Adobe license agreement accompanying it.</span>
+<a name="l00015"></a>00015 <span class="comment">// =================================================================================================</span>
+<a name="l00016"></a>00016
+<a name="l00017"></a>00017 <span class="comment">// ================================================================================================</span>
+<a name="l00024"></a>00024 <span class="comment"></span><span class="comment">// ================================================================================================</span>
+<a name="l00025"></a>00025
+<a name="l00026"></a>00026 <span class="comment">// ================================================================================================</span>
+<a name="l00084"></a>00084 <span class="comment"></span><span class="comment">// ================================================================================================</span>
+<a name="l00085"></a>00085
+<a name="l00086"></a>00086 <span class="preprocessor">#include "client-glue/WXMPIterator.hpp"</span>
+<a name="l00087"></a>00087
+<a name="l00088"></a>00088 <span class="keyword">template</span> &lt;<span class="keyword">class</span> tStringObj&gt;
+<a name="l00089"></a><a class="code" href="classTXMPIterator.html">00089</a> <span class="keyword">class </span><a class="code" href="classTXMPIterator.html">TXMPIterator</a> {
+<a name="l00090"></a>00090
+<a name="l00091"></a>00091 <span class="keyword">public</span>:
+<a name="l00092"></a>00092
+<a name="l00093"></a>00093 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00098"></a>00098 <span class="comment"></span>
+<a name="l00099"></a>00099 <span class="keywordtype">void</span> <a class="code" href="classTXMPIterator.html#d767d731320d3f4c997c6ce9f7f8fa63">operator= </a>( <span class="keyword">const</span> <a class="code" href="classTXMPIterator.html">TXMPIterator&lt;tStringObj&gt;</a> &amp; rhs );
+<a name="l00100"></a>00100
+<a name="l00101"></a>00101 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00105"></a>00105 <span class="comment"></span>
+<a name="l00106"></a>00106 <a class="code" href="classTXMPIterator.html">TXMPIterator</a> ( <span class="keyword">const</span> <a class="code" href="classTXMPIterator.html">TXMPIterator&lt;tStringObj&gt;</a> &amp; original );
+<a name="l00107"></a>00107
+<a name="l00108"></a>00108 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00132"></a>00132 <span class="comment"></span>
+<a name="l00133"></a>00133 <a class="code" href="classTXMPIterator.html">TXMPIterator</a> ( <span class="keyword">const</span> <a class="code" href="classTXMPMeta.html">TXMPMeta&lt;tStringObj&gt;</a> &amp; xmpObj,
+<a name="l00134"></a>00134 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS,
+<a name="l00135"></a>00135 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> propName,
+<a name="l00136"></a>00136 <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options = 0 );
+<a name="l00137"></a>00137
+<a name="l00138"></a>00138 <a class="code" href="classTXMPIterator.html">TXMPIterator</a> ( <span class="keyword">const</span> <a class="code" href="classTXMPMeta.html">TXMPMeta&lt;tStringObj&gt;</a> &amp; xmpObj,
+<a name="l00139"></a>00139 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS,
+<a name="l00140"></a>00140 <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options = 0 );
+<a name="l00141"></a>00141
+<a name="l00142"></a>00142 <a class="code" href="classTXMPIterator.html">TXMPIterator</a> ( <span class="keyword">const</span> <a class="code" href="classTXMPMeta.html">TXMPMeta&lt;tStringObj&gt;</a> &amp; xmpObj,
+<a name="l00143"></a>00143 <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options = 0 );
+<a name="l00144"></a>00144
+<a name="l00145"></a>00145 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00149"></a>00149 <span class="comment"></span>
+<a name="l00150"></a>00150 <a class="code" href="classTXMPIterator.html">TXMPIterator</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS,
+<a name="l00151"></a>00151 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> propName,
+<a name="l00152"></a>00152 <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options );
+<a name="l00153"></a>00153
+<a name="l00154"></a>00154 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00156"></a>00156 <span class="comment"></span>
+<a name="l00157"></a>00157 <span class="keyword">virtual</span> <a class="code" href="classTXMPIterator.html#911554533e8a3f09ab8870bd54462196">~TXMPIterator</a>() <span class="keywordflow">throw</span>();
+<a name="l00158"></a>00158
+<a name="l00159"></a>00159 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00175"></a>00175 <span class="comment"></span>
+<a name="l00176"></a>00176 <span class="keywordtype">bool</span>
+<a name="l00177"></a>00177 <a class="code" href="classTXMPIterator.html#124a1dd1ab3ff0d236e4d4b967dafcd9">Next</a> ( tStringObj * schemaNS = 0,
+<a name="l00178"></a>00178 tStringObj * propPath = 0,
+<a name="l00179"></a>00179 tStringObj * propValue = 0,
+<a name="l00180"></a>00180 <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> * options = 0 );
+<a name="l00181"></a>00181
+<a name="l00182"></a>00182 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00191"></a>00191 <span class="comment"></span>
+<a name="l00192"></a>00192 <span class="keywordtype">void</span>
+<a name="l00193"></a>00193 <a class="code" href="classTXMPIterator.html#30b4d78974b347e4fcd275f1f65a61b2">Skip</a> ( <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options );
+<a name="l00194"></a>00194
+<a name="l00195"></a>00195 <span class="keyword">private</span>:
+<a name="l00196"></a>00196
+<a name="l00197"></a>00197 XMPIteratorRef iterRef;
+<a name="l00198"></a>00198
+<a name="l00199"></a>00199 <a class="code" href="classTXMPIterator.html">TXMPIterator</a>(); <span class="comment">// ! Hidden, must choose property or table iteration.</span>
+<a name="l00200"></a>00200
+<a name="l00201"></a>00201 }; <span class="comment">// class TXMPIterator</span>
+<a name="l00202"></a>00202
+<a name="l00203"></a>00203 <span class="comment">// =================================================================================================</span>
+<a name="l00204"></a>00204
+<a name="l00205"></a>00205 <span class="preprocessor">#endif // __TXMPIterator_hpp__</span>
+</pre></div><hr size="1"><address style="align: right;"><small>Generated on Thu May 3 14:54:57 2007 for Adobe XMP Toolkit by&nbsp;
+<a href="http://www.doxygen.org/index.html">
+<img src="doxygen.png" alt="doxygen" align="middle" border="0"></a> 1.5.1 </small></address>
+</body>
+</html>
diff --git a/docs/XMPToolkit/TXMPIterator_8hpp.html b/docs/XMPToolkit/TXMPIterator_8hpp.html
new file mode 100644
index 0000000..4bca589
--- /dev/null
+++ b/docs/XMPToolkit/TXMPIterator_8hpp.html
@@ -0,0 +1,37 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
+<title>Adobe XMP Toolkit: TXMPIterator.hpp File Reference</title>
+<link href="doxygen.css" rel="stylesheet" type="text/css">
+<link href="tabs.css" rel="stylesheet" type="text/css">
+</head><body>
+<!-- Generated by Doxygen 1.5.1 -->
+<div class="tabs">
+ <ul>
+ <li><a href="index.html"><span>Main&nbsp;Page</span></a></li>
+ <li><a href="modules.html"><span>Modules</span></a></li>
+ <li><a href="annotated.html"><span>Classes</span></a></li>
+ <li id="current"><a href="files.html"><span>Files</span></a></li>
+ </ul></div>
+<h1>TXMPIterator.hpp File Reference</h1>Template class for the XMP Toolkit iteration services. <a href="#_details">More...</a>
+<p>
+<code>#include &quot;client-glue/WXMPIterator.hpp&quot;</code><br>
+
+<p>
+Include dependency graph for TXMPIterator.hpp:<p><center><img src="TXMPIterator_8hpp__incl.png" border="0" usemap="#TXMPIterator.hpp_map" alt=""></center>
+
+<p>
+<a href="TXMPIterator_8hpp-source.html">Go to the source code of this file.</a><table border="0" cellpadding="0" cellspacing="0">
+<tr><td></td></tr>
+<tr><td colspan="2"><br><h2>Classes</h2></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">class &nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPIterator.html">TXMPIterator&lt; tStringObj &gt;</a></td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Template class for the XMP Toolkit iteration services. <a href="classTXMPIterator.html#_details">More...</a><br></td></tr>
+</table>
+<hr><a name="_details"></a><h2>Detailed Description</h2>
+Template class for the XMP Toolkit iteration services.
+<p>
+This template class provides iteration services for the XMP Toolkit. It should be instantiated with a string class such as <code>std::string</code>. Please read the general usage notes for information on the overall architecture of the XMP API. <hr size="1"><address style="align: right;"><small>Generated on Thu May 3 14:54:57 2007 for Adobe XMP Toolkit by&nbsp;
+<a href="http://www.doxygen.org/index.html">
+<img src="doxygen.png" alt="doxygen" align="middle" border="0"></a> 1.5.1 </small></address>
+</body>
+</html>
diff --git a/docs/XMPToolkit/TXMPIterator_8hpp__incl.png b/docs/XMPToolkit/TXMPIterator_8hpp__incl.png
new file mode 100644
index 0000000..b3e627b
--- /dev/null
+++ b/docs/XMPToolkit/TXMPIterator_8hpp__incl.png
Binary files differ
diff --git a/docs/XMPToolkit/TXMPIterator_8incl__cpp.html b/docs/XMPToolkit/TXMPIterator_8incl__cpp.html
new file mode 100644
index 0000000..ee6f9d8
--- /dev/null
+++ b/docs/XMPToolkit/TXMPIterator_8incl__cpp.html
@@ -0,0 +1,33 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
+<title>Adobe XMP Toolkit: TXMPIterator.incl_cpp File Reference</title>
+<link href="doxygen.css" rel="stylesheet" type="text/css">
+<link href="tabs.css" rel="stylesheet" type="text/css">
+</head><body>
+<!-- Generated by Doxygen 1.5.1 -->
+<div class="tabs">
+ <ul>
+ <li><a href="index.html"><span>Main&nbsp;Page</span></a></li>
+ <li><a href="modules.html"><span>Modules</span></a></li>
+ <li><a href="annotated.html"><span>Classes</span></a></li>
+ <li id="current"><a href="files.html"><span>Files</span></a></li>
+ </ul></div>
+<h1>TXMPIterator.incl_cpp File Reference</h1>The implementation of the <a class="el" href="classTXMPIterator.html">TXMPIterator</a> template class. <a href="#_details">More...</a>
+<p>
+<code>#include &quot;XMP.hpp&quot;</code><br>
+<code>#include &quot;client-glue/WXMP_Common.hpp&quot;</code><br>
+<code>#include &quot;client-glue/WXMPIterator.hpp&quot;</code><br>
+
+<p>
+Include dependency graph for TXMPIterator.incl_cpp:<p><center><img src="TXMPIterator_8incl__cpp__incl.png" border="0" usemap="#TXMPIterator.incl_cpp_map" alt=""></center>
+<table border="0" cellpadding="0" cellspacing="0">
+<tr><td></td></tr>
+</table>
+<hr><a name="_details"></a><h2>Detailed Description</h2>
+The implementation of the <a class="el" href="classTXMPIterator.html">TXMPIterator</a> template class.
+<p>
+<hr size="1"><address style="align: right;"><small>Generated on Thu May 3 14:54:58 2007 for Adobe XMP Toolkit by&nbsp;
+<a href="http://www.doxygen.org/index.html">
+<img src="doxygen.png" alt="doxygen" align="middle" border="0"></a> 1.5.1 </small></address>
+</body>
+</html>
diff --git a/docs/XMPToolkit/TXMPIterator_8incl__cpp__incl.png b/docs/XMPToolkit/TXMPIterator_8incl__cpp__incl.png
new file mode 100644
index 0000000..e2c9422
--- /dev/null
+++ b/docs/XMPToolkit/TXMPIterator_8incl__cpp__incl.png
Binary files differ
diff --git a/docs/XMPToolkit/TXMPMeta_8hpp-source.html b/docs/XMPToolkit/TXMPMeta_8hpp-source.html
new file mode 100644
index 0000000..1aa7688
--- /dev/null
+++ b/docs/XMPToolkit/TXMPMeta_8hpp-source.html
@@ -0,0 +1,617 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
+<title>Adobe XMP Toolkit: TXMPMeta.hpp Source File</title>
+<link href="doxygen.css" rel="stylesheet" type="text/css">
+<link href="tabs.css" rel="stylesheet" type="text/css">
+</head><body>
+<!-- Generated by Doxygen 1.5.1 -->
+<div class="tabs">
+ <ul>
+ <li><a href="index.html"><span>Main&nbsp;Page</span></a></li>
+ <li><a href="modules.html"><span>Modules</span></a></li>
+ <li><a href="annotated.html"><span>Classes</span></a></li>
+ <li id="current"><a href="files.html"><span>Files</span></a></li>
+ </ul></div>
+<h1>TXMPMeta.hpp</h1><a href="TXMPMeta_8hpp.html">Go to the documentation of this file.</a><div class="fragment"><pre class="fragment"><a name="l00001"></a>00001 <span class="preprocessor">#ifndef __TXMPMeta_hpp__</span>
+<a name="l00002"></a>00002 <span class="preprocessor"></span><span class="preprocessor">#define __TXMPMeta_hpp__ 1</span>
+<a name="l00003"></a>00003 <span class="preprocessor"></span>
+<a name="l00004"></a>00004 <span class="preprocessor">#if ( ! __XMP_hpp__ )</span>
+<a name="l00005"></a>00005 <span class="preprocessor"></span><span class="preprocessor"> #error "Do not directly include, use XMP.hpp"</span>
+<a name="l00006"></a>00006 <span class="preprocessor"></span><span class="preprocessor">#endif</span>
+<a name="l00007"></a>00007 <span class="preprocessor"></span>
+<a name="l00008"></a>00008 <span class="comment">// =================================================================================================</span>
+<a name="l00009"></a>00009 <span class="comment">// ADOBE SYSTEMS INCORPORATED</span>
+<a name="l00010"></a>00010 <span class="comment">// Copyright 2002-2007 Adobe Systems Incorporated</span>
+<a name="l00011"></a>00011 <span class="comment">// All Rights Reserved</span>
+<a name="l00012"></a>00012 <span class="comment">//</span>
+<a name="l00013"></a>00013 <span class="comment">// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms</span>
+<a name="l00014"></a>00014 <span class="comment">// of the Adobe license agreement accompanying it.</span>
+<a name="l00015"></a>00015 <span class="comment">// =================================================================================================</span>
+<a name="l00016"></a>00016
+<a name="l00017"></a>00017 <span class="comment">// ================================================================================================</span>
+<a name="l00024"></a>00024 <span class="comment"></span><span class="comment">// ================================================================================================</span>
+<a name="l00025"></a>00025
+<a name="l00026"></a>00026 <span class="comment">// ================================================================================================</span>
+<a name="l00063"></a>00063 <span class="comment"></span><span class="comment">// ================================================================================================</span>
+<a name="l00064"></a>00064
+<a name="l00065"></a>00065 <span class="keyword">template</span> &lt;<span class="keyword">class</span> tStringObj&gt; <span class="keyword">class </span><a class="code" href="classTXMPIterator.html">TXMPIterator</a>;
+<a name="l00066"></a>00066 <span class="keyword">template</span> &lt;<span class="keyword">class</span> tStringObj&gt; <span class="keyword">class </span><a class="code" href="classTXMPUtils.html">TXMPUtils</a>;
+<a name="l00067"></a>00067
+<a name="l00068"></a>00068 <span class="comment">// -------------------------------------------------------------------------------------------------</span>
+<a name="l00069"></a>00069
+<a name="l00070"></a>00070 <span class="keyword">template</span> &lt;<span class="keyword">class</span> tStringObj&gt;
+<a name="l00071"></a><a class="code" href="classTXMPMeta.html">00071</a> <span class="keyword">class </span><a class="code" href="classTXMPMeta.html">TXMPMeta</a> {
+<a name="l00072"></a>00072
+<a name="l00073"></a>00073 <span class="keyword">public</span>:
+<a name="l00074"></a>00074
+<a name="l00075"></a>00075 <span class="comment">// =============================================================================================</span>
+<a name="l00076"></a>00076 <span class="comment">// Initialization and termination</span>
+<a name="l00077"></a>00077 <span class="comment">// ==============================</span>
+<a name="l00078"></a>00078
+<a name="l00079"></a>00079 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00082"></a>00082 <span class="comment"></span>
+<a name="l00083"></a>00083 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00085"></a>00085 <span class="comment"></span>
+<a name="l00086"></a>00086 <span class="keyword">static</span> <span class="keywordtype">void</span>
+<a name="l00087"></a>00087 <a class="code" href="classTXMPMeta.html#5415cfc01a9cb8786939246571a23a9d">GetVersionInfo</a> ( XMP_VersionInfo * info );
+<a name="l00088"></a>00088
+<a name="l00089"></a>00089 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00094"></a>00094 <span class="comment"></span>
+<a name="l00095"></a>00095 <span class="keyword">static</span> <span class="keywordtype">bool</span>
+<a name="l00096"></a>00096 <a class="code" href="classTXMPMeta.html#bfddf1df0e01ab33d5636a80edc973ca">Initialize</a>();
+<a name="l00097"></a>00097 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00099"></a>00099 <span class="comment"></span>
+<a name="l00100"></a>00100 <span class="keyword">static</span> <span class="keywordtype">void</span>
+<a name="l00101"></a>00101 <a class="code" href="classTXMPMeta.html#6c30fae26173167958b6f0da95a53865">Terminate</a>();
+<a name="l00102"></a>00102
+<a name="l00104"></a>00104
+<a name="l00105"></a>00105 <span class="comment">// =============================================================================================</span>
+<a name="l00106"></a>00106 <span class="comment">// Constuctors and destructor</span>
+<a name="l00107"></a>00107 <span class="comment">// =========================</span>
+<a name="l00108"></a>00108
+<a name="l00109"></a>00109 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00112"></a>00112 <span class="comment"></span>
+<a name="l00113"></a>00113 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00117"></a>00117 <span class="comment"></span>
+<a name="l00118"></a>00118 <a class="code" href="classTXMPMeta.html#7729cbce91956632289b88d85fdc65ae">TXMPMeta</a>();
+<a name="l00119"></a>00119
+<a name="l00120"></a>00120 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00124"></a>00124 <span class="comment"></span>
+<a name="l00125"></a>00125 <a class="code" href="classTXMPMeta.html#7729cbce91956632289b88d85fdc65ae">TXMPMeta</a> ( <span class="keyword">const</span> <a class="code" href="classTXMPMeta.html">TXMPMeta&lt;tStringObj&gt;</a> &amp; original );
+<a name="l00126"></a>00126
+<a name="l00127"></a>00127 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00132"></a>00132 <span class="comment"></span>
+<a name="l00133"></a>00133 <span class="keywordtype">void</span> <a class="code" href="classTXMPMeta.html#4d5a601c9b77f6f6ab5f14e658de58ef">operator= </a>( <span class="keyword">const</span> <a class="code" href="classTXMPMeta.html">TXMPMeta&lt;tStringObj&gt;</a> &amp; rhs );
+<a name="l00134"></a>00134
+<a name="l00135"></a>00135 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00141"></a>00141 <span class="comment"></span>
+<a name="l00142"></a>00142 <a class="code" href="classTXMPMeta.html#7729cbce91956632289b88d85fdc65ae">TXMPMeta</a> ( <a class="code" href="XMP__Const_8h.html#5912613564f80e17eb10acef9236f70a">XMPMetaRef</a> xmpRef );
+<a name="l00143"></a>00143
+<a name="l00144"></a>00144 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00157"></a>00157 <span class="comment"></span>
+<a name="l00158"></a>00158 <a class="code" href="classTXMPMeta.html#7729cbce91956632289b88d85fdc65ae">TXMPMeta</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> buffer,
+<a name="l00159"></a>00159 <a class="code" href="XMP__Const_8h.html#9f7dcc184f901c713274edfdac5bcc9a">XMP_StringLen</a> xmpSize );
+<a name="l00160"></a>00160
+<a name="l00161"></a>00161 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00163"></a>00163 <span class="comment"></span>
+<a name="l00164"></a>00164 <span class="keyword">virtual</span> <a class="code" href="classTXMPMeta.html#bab5013870cd47eb0d9d701653735a02">~TXMPMeta</a>() <span class="keywordflow">throw</span>();
+<a name="l00165"></a>00165
+<a name="l00167"></a>00167
+<a name="l00168"></a>00168 <span class="comment">// =============================================================================================</span>
+<a name="l00169"></a>00169 <span class="comment">// Global state functions</span>
+<a name="l00170"></a>00170 <span class="comment">// ======================</span>
+<a name="l00171"></a>00171
+<a name="l00172"></a>00172 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00177"></a>00177 <span class="comment"></span>
+<a name="l00179"></a>00179
+<a name="l00180"></a>00180 <span class="keyword">static</span> <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a>
+<a name="l00181"></a>00181 <a class="code" href="classTXMPMeta.html#12b2435ba039c62a164951948c016eb4">GetGlobalOptions</a>();
+<a name="l00182"></a>00182
+<a name="l00188"></a>00188
+<a name="l00189"></a>00189 <span class="keyword">static</span> <span class="keywordtype">void</span>
+<a name="l00190"></a>00190 <a class="code" href="classTXMPMeta.html#e7bb38d9b3857b08106630a386b47332">SetGlobalOptions</a> ( <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options );
+<a name="l00191"></a>00191
+<a name="l00193"></a>00193
+<a name="l00194"></a>00194 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00199"></a>00199 <span class="comment"></span>
+<a name="l00201"></a>00201
+<a name="l00202"></a>00202 <span class="keyword">static</span> <a class="code" href="XMP__Const_8h.html#91efdc0a7fbe6e1d42ca34e6ce589b98">XMP_Status</a>
+<a name="l00203"></a>00203 <a class="code" href="classTXMPMeta.html#44250140a710c0b7c5cc0881e387d004">DumpNamespaces</a> ( <a class="code" href="XMP__Const_8h.html#36eab570ab85ff8fb5789661692d13c2">XMP_TextOutputProc</a> outProc,
+<a name="l00204"></a>00204 <span class="keywordtype">void</span> * refCon );
+<a name="l00205"></a>00205
+<a name="l00207"></a>00207
+<a name="l00208"></a>00208 <span class="keyword">static</span> <a class="code" href="XMP__Const_8h.html#91efdc0a7fbe6e1d42ca34e6ce589b98">XMP_Status</a>
+<a name="l00209"></a>00209 <a class="code" href="classTXMPMeta.html#afb027f200b85467298d237a0c23949b">DumpAliases</a> ( <a class="code" href="XMP__Const_8h.html#36eab570ab85ff8fb5789661692d13c2">XMP_TextOutputProc</a> outProc,
+<a name="l00210"></a>00210 <span class="keywordtype">void</span> * refCon );
+<a name="l00211"></a>00211
+<a name="l00213"></a>00213
+<a name="l00214"></a>00214 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00224"></a>00224 <span class="comment"></span>
+<a name="l00225"></a>00225 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00243"></a>00243 <span class="comment"></span>
+<a name="l00244"></a>00244 <span class="keyword">static</span> <span class="keywordtype">bool</span>
+<a name="l00245"></a>00245 <a class="code" href="classTXMPMeta.html#4c69d31a37ff24c85679229c479aa1ac">RegisterNamespace</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> namespaceURI,
+<a name="l00246"></a>00246 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> suggestedPrefix,
+<a name="l00247"></a>00247 tStringObj * registeredPrefix );
+<a name="l00248"></a>00248
+<a name="l00249"></a>00249 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00260"></a>00260 <span class="comment"></span>
+<a name="l00261"></a>00261 <span class="keyword">static</span> <span class="keywordtype">bool</span>
+<a name="l00262"></a>00262 <a class="code" href="classTXMPMeta.html#f28589472d8c0397db6cef868f2b8c97">GetNamespacePrefix</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> namespaceURI,
+<a name="l00263"></a>00263 tStringObj * namespacePrefix );
+<a name="l00264"></a>00264
+<a name="l00265"></a>00265 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00276"></a>00276 <span class="comment"></span>
+<a name="l00277"></a>00277 <span class="keyword">static</span> <span class="keywordtype">bool</span>
+<a name="l00278"></a>00278 <a class="code" href="classTXMPMeta.html#a20c84e7549d0a3252fa29a1e83a757a">GetNamespaceURI</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> namespacePrefix,
+<a name="l00279"></a>00279 tStringObj * namespaceURI );
+<a name="l00280"></a>00280
+<a name="l00281"></a>00281 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00290"></a>00290 <span class="comment"></span>
+<a name="l00291"></a>00291 <span class="keyword">static</span> <span class="keywordtype">void</span>
+<a name="l00292"></a>00292 <a class="code" href="classTXMPMeta.html#3f989597e95db929676273cacd4ea09a">DeleteNamespace</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> namespaceURI );
+<a name="l00293"></a>00293
+<a name="l00295"></a>00295
+<a name="l00296"></a>00296 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00311"></a>00311 <span class="comment"></span>
+<a name="l00312"></a>00312 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00348"></a>00348 <span class="comment"></span>
+<a name="l00349"></a>00349 <span class="keyword">static</span> <span class="keywordtype">void</span>
+<a name="l00350"></a>00350 <a class="code" href="classTXMPMeta.html#b9463c7459125ca0038db2e586c5e4df">RegisterAlias</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> aliasNS,
+<a name="l00351"></a>00351 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> aliasProp,
+<a name="l00352"></a>00352 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> actualNS,
+<a name="l00353"></a>00353 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> actualProp,
+<a name="l00354"></a>00354 <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> arrayForm = kXMP_NoOptions );
+<a name="l00355"></a>00355
+<a name="l00356"></a>00356 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00382"></a>00382 <span class="comment"></span>
+<a name="l00383"></a>00383 <span class="keyword">static</span> <span class="keywordtype">bool</span>
+<a name="l00384"></a>00384 <a class="code" href="classTXMPMeta.html#c4b9c75202f2b961ad92f10a9e504e9a">ResolveAlias</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> aliasNS,
+<a name="l00385"></a>00385 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> aliasProp,
+<a name="l00386"></a>00386 tStringObj * actualNS,
+<a name="l00387"></a>00387 tStringObj * actualProp,
+<a name="l00388"></a>00388 <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> * arrayForm );
+<a name="l00389"></a>00389
+<a name="l00390"></a>00390 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00401"></a>00401 <span class="comment"></span>
+<a name="l00402"></a>00402 <span class="keyword">static</span> <span class="keywordtype">void</span>
+<a name="l00403"></a>00403 <a class="code" href="classTXMPMeta.html#af64964e983235247ef65c86a42a4675">DeleteAlias</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> aliasNS,
+<a name="l00404"></a>00404 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> aliasProp );
+<a name="l00405"></a>00405
+<a name="l00406"></a>00406 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00413"></a>00413 <span class="comment"></span>
+<a name="l00414"></a>00414 <span class="keyword">static</span> <span class="keywordtype">void</span>
+<a name="l00415"></a>00415 <a class="code" href="classTXMPMeta.html#b77cf73fa0cc63d845f113b3d1c83602">RegisterStandardAliases</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS );
+<a name="l00416"></a>00416
+<a name="l00418"></a>00418
+<a name="l00419"></a>00419 <span class="comment">// =============================================================================================</span>
+<a name="l00420"></a>00420 <span class="comment">// Basic property manipulation functions</span>
+<a name="l00421"></a>00421 <span class="comment">// =====================================</span>
+<a name="l00422"></a>00422
+<a name="l00423"></a>00423 <span class="comment">// *** Should add discussion of schemaNS and propName prefix usage.</span>
+<a name="l00424"></a>00424
+<a name="l00425"></a>00425 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00484"></a>00484 <span class="comment"></span>
+<a name="l00485"></a>00485 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00507"></a>00507 <span class="comment"></span>
+<a name="l00508"></a>00508 <span class="keywordtype">bool</span>
+<a name="l00509"></a>00509 <a class="code" href="classTXMPMeta.html#06a3241c7fa5df87f61dff02fca23a0c">GetProperty</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS,
+<a name="l00510"></a>00510 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> propName,
+<a name="l00511"></a>00511 tStringObj * propValue,
+<a name="l00512"></a>00512 <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> * options ) <span class="keyword">const</span>;
+<a name="l00513"></a>00513
+<a name="l00514"></a>00514 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00535"></a>00535 <span class="comment"></span>
+<a name="l00536"></a>00536 <span class="keywordtype">bool</span>
+<a name="l00537"></a>00537 <a class="code" href="classTXMPMeta.html#c64a4251d157937f69b73f2ffac4f7cc">GetArrayItem</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS,
+<a name="l00538"></a>00538 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> arrayName,
+<a name="l00539"></a>00539 <a class="code" href="XMP__Const_8h.html#00e9d9a76c144421105a4c2742203315">XMP_Index</a> itemIndex,
+<a name="l00540"></a>00540 tStringObj * itemValue,
+<a name="l00541"></a>00541 <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> * options ) <span class="keyword">const</span>;
+<a name="l00542"></a>00542
+<a name="l00543"></a>00543 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00571"></a>00571 <span class="comment"></span>
+<a name="l00572"></a>00572 <span class="keywordtype">bool</span>
+<a name="l00573"></a>00573 <a class="code" href="classTXMPMeta.html#e99d2bc414d5cd68851147aef6710d4a">GetStructField</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS,
+<a name="l00574"></a>00574 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> structName,
+<a name="l00575"></a>00575 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> fieldNS,
+<a name="l00576"></a>00576 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> fieldName,
+<a name="l00577"></a>00577 tStringObj * fieldValue,
+<a name="l00578"></a>00578 <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> * options ) <span class="keyword">const</span>;
+<a name="l00579"></a>00579
+<a name="l00580"></a>00580 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00613"></a>00613 <span class="comment"></span>
+<a name="l00614"></a>00614 <span class="keywordtype">bool</span>
+<a name="l00615"></a>00615 <a class="code" href="classTXMPMeta.html#2cc58d8316043b035643e7c21633bc13">GetQualifier</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS,
+<a name="l00616"></a>00616 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> propName,
+<a name="l00617"></a>00617 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> qualNS,
+<a name="l00618"></a>00618 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> qualName,
+<a name="l00619"></a>00619 tStringObj * qualValue,
+<a name="l00620"></a>00620 <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> * options ) <span class="keyword">const</span>;
+<a name="l00621"></a>00621
+<a name="l00623"></a>00623
+<a name="l00624"></a>00624 <span class="comment">// =============================================================================================</span>
+<a name="l00625"></a>00625
+<a name="l00626"></a>00626 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00670"></a>00670 <span class="comment"></span>
+<a name="l00671"></a>00671 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00684"></a>00684 <span class="comment"></span>
+<a name="l00685"></a>00685 <span class="keywordtype">void</span>
+<a name="l00686"></a>00686 <a class="code" href="classTXMPMeta.html#1dfd6a08ebfd1a6364b3a7b6584bcc28">SetProperty</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS,
+<a name="l00687"></a>00687 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> propName,
+<a name="l00688"></a>00688 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> propValue,
+<a name="l00689"></a>00689 <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options = 0 );
+<a name="l00690"></a>00690
+<a name="l00691"></a>00691 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00694"></a>00694 <span class="comment"></span>
+<a name="l00695"></a>00695 <span class="keywordtype">void</span>
+<a name="l00696"></a>00696 <a class="code" href="classTXMPMeta.html#1dfd6a08ebfd1a6364b3a7b6584bcc28">SetProperty</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS,
+<a name="l00697"></a>00697 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> propName,
+<a name="l00698"></a>00698 <span class="keyword">const</span> tStringObj &amp; propValue,
+<a name="l00699"></a>00699 <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options = 0 );
+<a name="l00700"></a>00700
+<a name="l00701"></a>00701 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00726"></a>00726 <span class="comment"></span>
+<a name="l00727"></a>00727 <span class="keywordtype">void</span>
+<a name="l00728"></a>00728 <a class="code" href="classTXMPMeta.html#1570eb89d613b4a94ca572e4644168cc">SetArrayItem</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS,
+<a name="l00729"></a>00729 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> arrayName,
+<a name="l00730"></a>00730 <a class="code" href="XMP__Const_8h.html#00e9d9a76c144421105a4c2742203315">XMP_Index</a> itemIndex,
+<a name="l00731"></a>00731 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> itemValue,
+<a name="l00732"></a>00732 <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options = 0 );
+<a name="l00733"></a>00733
+<a name="l00734"></a>00734 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00737"></a>00737 <span class="comment"></span>
+<a name="l00738"></a>00738 <span class="keywordtype">void</span>
+<a name="l00739"></a>00739 <a class="code" href="classTXMPMeta.html#1570eb89d613b4a94ca572e4644168cc">SetArrayItem</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS,
+<a name="l00740"></a>00740 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> arrayName,
+<a name="l00741"></a>00741 <a class="code" href="XMP__Const_8h.html#00e9d9a76c144421105a4c2742203315">XMP_Index</a> itemIndex,
+<a name="l00742"></a>00742 <span class="keyword">const</span> tStringObj &amp; itemValue,
+<a name="l00743"></a>00743 <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options = 0 );
+<a name="l00744"></a>00744
+<a name="l00745"></a>00745 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00767"></a>00767 <span class="comment"></span>
+<a name="l00768"></a>00768 <span class="keywordtype">void</span>
+<a name="l00769"></a>00769 <a class="code" href="classTXMPMeta.html#00d7314dc970ad390499ce9db27d314a">AppendArrayItem</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS,
+<a name="l00770"></a>00770 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> arrayName,
+<a name="l00771"></a>00771 <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> arrayOptions,
+<a name="l00772"></a>00772 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> itemValue,
+<a name="l00773"></a>00773 <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> itemOptions = 0 );
+<a name="l00774"></a>00774
+<a name="l00775"></a>00775 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00778"></a>00778 <span class="comment"></span>
+<a name="l00779"></a>00779 <span class="keywordtype">void</span>
+<a name="l00780"></a>00780 <a class="code" href="classTXMPMeta.html#00d7314dc970ad390499ce9db27d314a">AppendArrayItem</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS,
+<a name="l00781"></a>00781 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> arrayName,
+<a name="l00782"></a>00782 <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> arrayOptions,
+<a name="l00783"></a>00783 <span class="keyword">const</span> tStringObj &amp; itemValue,
+<a name="l00784"></a>00784 <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> itemOptions = 0 );
+<a name="l00785"></a>00785
+<a name="l00786"></a>00786 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00811"></a>00811 <span class="comment"></span>
+<a name="l00812"></a>00812 <span class="keywordtype">void</span>
+<a name="l00813"></a>00813 <a class="code" href="classTXMPMeta.html#0e44c30e7527064909e5f7035d53c4f5">SetStructField</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS,
+<a name="l00814"></a>00814 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> structName,
+<a name="l00815"></a>00815 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> fieldNS,
+<a name="l00816"></a>00816 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> fieldName,
+<a name="l00817"></a>00817 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> fieldValue,
+<a name="l00818"></a>00818 <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options = 0 );
+<a name="l00819"></a>00819
+<a name="l00820"></a>00820 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00823"></a>00823 <span class="comment"></span>
+<a name="l00824"></a>00824 <span class="keywordtype">void</span>
+<a name="l00825"></a>00825 <a class="code" href="classTXMPMeta.html#0e44c30e7527064909e5f7035d53c4f5">SetStructField</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS,
+<a name="l00826"></a>00826 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> structName,
+<a name="l00827"></a>00827 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> fieldNS,
+<a name="l00828"></a>00828 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> fieldName,
+<a name="l00829"></a>00829 <span class="keyword">const</span> tStringObj &amp; fieldValue,
+<a name="l00830"></a>00830 <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options = 0 );
+<a name="l00831"></a>00831
+<a name="l00832"></a>00832 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00859"></a>00859 <span class="comment"></span>
+<a name="l00860"></a>00860 <span class="keywordtype">void</span>
+<a name="l00861"></a>00861 <a class="code" href="classTXMPMeta.html#c2e798da5f9d94e486382a41e73fcea3">SetQualifier</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS,
+<a name="l00862"></a>00862 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> propName,
+<a name="l00863"></a>00863 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> qualNS,
+<a name="l00864"></a>00864 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> qualName,
+<a name="l00865"></a>00865 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> qualValue,
+<a name="l00866"></a>00866 <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options = 0 );
+<a name="l00867"></a>00867
+<a name="l00868"></a>00868 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00871"></a>00871 <span class="comment"></span>
+<a name="l00872"></a>00872 <span class="keywordtype">void</span>
+<a name="l00873"></a>00873 <a class="code" href="classTXMPMeta.html#c2e798da5f9d94e486382a41e73fcea3">SetQualifier</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS,
+<a name="l00874"></a>00874 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> propName,
+<a name="l00875"></a>00875 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> qualNS,
+<a name="l00876"></a>00876 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> qualName,
+<a name="l00877"></a>00877 <span class="keyword">const</span> tStringObj &amp; qualValue,
+<a name="l00878"></a>00878 <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options = 0 );
+<a name="l00879"></a>00879
+<a name="l00881"></a>00881
+<a name="l00882"></a>00882 <span class="comment">// =============================================================================================</span>
+<a name="l00883"></a>00883
+<a name="l00884"></a>00884 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00888"></a>00888 <span class="comment"></span>
+<a name="l00889"></a>00889 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00896"></a>00896 <span class="comment"></span>
+<a name="l00897"></a>00897 <span class="keywordtype">void</span>
+<a name="l00898"></a>00898 <a class="code" href="classTXMPMeta.html#c8b555ba99904fa49bb4851a60cc3844">DeleteProperty</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS,
+<a name="l00899"></a>00899 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> propName );
+<a name="l00900"></a>00900
+<a name="l00901"></a>00901 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00912"></a>00912 <span class="comment"></span>
+<a name="l00913"></a>00913 <span class="keywordtype">void</span>
+<a name="l00914"></a>00914 <a class="code" href="classTXMPMeta.html#bc1211f47225b5973a170ff952743264">DeleteArrayItem</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS,
+<a name="l00915"></a>00915 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> arrayName,
+<a name="l00916"></a>00916 <a class="code" href="XMP__Const_8h.html#00e9d9a76c144421105a4c2742203315">XMP_Index</a> itemIndex );
+<a name="l00917"></a>00917
+<a name="l00918"></a>00918 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00932"></a>00932 <span class="comment"></span>
+<a name="l00933"></a>00933 <span class="keywordtype">void</span>
+<a name="l00934"></a>00934 <a class="code" href="classTXMPMeta.html#bc258e027780a15be65a88fcfd4e1fd4">DeleteStructField</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS,
+<a name="l00935"></a>00935 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> structName,
+<a name="l00936"></a>00936 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> fieldNS,
+<a name="l00937"></a>00937 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> fieldName );
+<a name="l00938"></a>00938
+<a name="l00939"></a>00939 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00953"></a>00953 <span class="comment"></span>
+<a name="l00954"></a>00954 <span class="keywordtype">void</span>
+<a name="l00955"></a>00955 <a class="code" href="classTXMPMeta.html#8ce15f7de7fd3b258f07158ab5fa88be">DeleteQualifier</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS,
+<a name="l00956"></a>00956 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> propName,
+<a name="l00957"></a>00957 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> qualNS,
+<a name="l00958"></a>00958 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> qualName );
+<a name="l00959"></a>00959
+<a name="l00960"></a>00960 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00968"></a>00968 <span class="comment"></span>
+<a name="l00969"></a>00969 <span class="keywordtype">bool</span>
+<a name="l00970"></a>00970 <a class="code" href="classTXMPMeta.html#f22b116d71ecbbebea016ec5337e7066">DoesPropertyExist</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS,
+<a name="l00971"></a>00971 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> propName ) <span class="keyword">const</span>;
+<a name="l00972"></a>00972
+<a name="l00973"></a>00973 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00985"></a>00985 <span class="comment"></span>
+<a name="l00986"></a>00986 <span class="keywordtype">bool</span>
+<a name="l00987"></a>00987 <a class="code" href="classTXMPMeta.html#492465c588d6d4cb8e30f94790e66f58">DoesArrayItemExist</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS,
+<a name="l00988"></a>00988 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> arrayName,
+<a name="l00989"></a>00989 <a class="code" href="XMP__Const_8h.html#00e9d9a76c144421105a4c2742203315">XMP_Index</a> itemIndex ) <span class="keyword">const</span>;
+<a name="l00990"></a>00990
+<a name="l00991"></a>00991 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l01006"></a>01006 <span class="comment"></span>
+<a name="l01007"></a>01007 <span class="keywordtype">bool</span>
+<a name="l01008"></a>01008 <a class="code" href="classTXMPMeta.html#9261b80d62e77a10ff1a89843bfa10a5">DoesStructFieldExist</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS,
+<a name="l01009"></a>01009 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> structName,
+<a name="l01010"></a>01010 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> fieldNS,
+<a name="l01011"></a>01011 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> fieldName ) <span class="keyword">const</span>;
+<a name="l01012"></a>01012
+<a name="l01013"></a>01013 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l01028"></a>01028 <span class="comment"></span>
+<a name="l01029"></a>01029 <span class="keywordtype">bool</span>
+<a name="l01030"></a>01030 <a class="code" href="classTXMPMeta.html#81347a92becd387a14f4d47c582f129a">DoesQualifierExist</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS,
+<a name="l01031"></a>01031 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> propName,
+<a name="l01032"></a>01032 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> qualNS,
+<a name="l01033"></a>01033 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> qualName ) <span class="keyword">const</span>;
+<a name="l01034"></a>01034
+<a name="l01036"></a>01036
+<a name="l01037"></a>01037 <span class="comment">// =============================================================================================</span>
+<a name="l01038"></a>01038 <span class="comment">// Specialized Get and Set functions</span>
+<a name="l01039"></a>01039 <span class="comment">// =================================</span>
+<a name="l01040"></a>01040
+<a name="l01041"></a>01041 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l01094"></a>01094 <span class="comment"></span>
+<a name="l01095"></a>01095 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l01123"></a>01123 <span class="comment"></span>
+<a name="l01124"></a>01124 <span class="keywordtype">bool</span>
+<a name="l01125"></a>01125 <a class="code" href="classTXMPMeta.html#eefe49bbf669770d769f4fe0ea566bd0">GetLocalizedText</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS,
+<a name="l01126"></a>01126 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> altTextName,
+<a name="l01127"></a>01127 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> genericLang,
+<a name="l01128"></a>01128 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> specificLang,
+<a name="l01129"></a>01129 tStringObj * actualLang,
+<a name="l01130"></a>01130 tStringObj * itemValue,
+<a name="l01131"></a>01131 <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> * options ) <span class="keyword">const</span>;
+<a name="l01132"></a>01132
+<a name="l01133"></a>01133 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l01174"></a>01174 <span class="comment"></span>
+<a name="l01175"></a>01175 <span class="keywordtype">void</span>
+<a name="l01176"></a>01176 <a class="code" href="classTXMPMeta.html#f9531b949a462f5663b1f3fd99464c19">SetLocalizedText</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS,
+<a name="l01177"></a>01177 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> altTextName,
+<a name="l01178"></a>01178 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> genericLang,
+<a name="l01179"></a>01179 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> specificLang,
+<a name="l01180"></a>01180 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> itemValue,
+<a name="l01181"></a>01181 <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options = 0 );
+<a name="l01182"></a>01182
+<a name="l01183"></a>01183 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l01186"></a>01186 <span class="comment"></span>
+<a name="l01187"></a>01187 <span class="keywordtype">void</span>
+<a name="l01188"></a>01188 <a class="code" href="classTXMPMeta.html#f9531b949a462f5663b1f3fd99464c19">SetLocalizedText</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS,
+<a name="l01189"></a>01189 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> altTextName,
+<a name="l01190"></a>01190 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> genericLang,
+<a name="l01191"></a>01191 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> specificLang,
+<a name="l01192"></a>01192 <span class="keyword">const</span> tStringObj &amp; itemValue,
+<a name="l01193"></a>01193 <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options = 0 );
+<a name="l01194"></a>01194
+<a name="l01196"></a>01196
+<a name="l01197"></a>01197 <span class="comment">// =============================================================================================</span>
+<a name="l01198"></a>01198
+<a name="l01199"></a>01199 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l01207"></a>01207 <span class="comment"></span>
+<a name="l01208"></a>01208 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l01222"></a>01222 <span class="comment"></span>
+<a name="l01223"></a>01223 <span class="keywordtype">bool</span>
+<a name="l01224"></a>01224 <a class="code" href="classTXMPMeta.html#dcf8a1959a8bd42641a42cbd4d64a5b7">GetProperty_Bool</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS,
+<a name="l01225"></a>01225 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> propName,
+<a name="l01226"></a>01226 <span class="keywordtype">bool</span> * propValue,
+<a name="l01227"></a>01227 <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> * options ) <span class="keyword">const</span>;
+<a name="l01228"></a>01228
+<a name="l01229"></a>01229 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l01243"></a>01243 <span class="comment"></span>
+<a name="l01244"></a>01244 <span class="keywordtype">bool</span>
+<a name="l01245"></a>01245 <a class="code" href="classTXMPMeta.html#3b6ba486c02607b544917091c43b05cc">GetProperty_Int</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS,
+<a name="l01246"></a>01246 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> propName,
+<a name="l01247"></a>01247 <span class="keywordtype">long</span> * propValue,
+<a name="l01248"></a>01248 <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> * options ) <span class="keyword">const</span>;
+<a name="l01249"></a>01249
+<a name="l01250"></a>01250 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l01264"></a>01264 <span class="comment"></span>
+<a name="l01265"></a>01265 <span class="keywordtype">bool</span>
+<a name="l01266"></a>01266 <a class="code" href="classTXMPMeta.html#d1a6629b0466981b67d31c9dc3840ea7">GetProperty_Int64</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS,
+<a name="l01267"></a>01267 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> propName,
+<a name="l01268"></a>01268 <span class="keywordtype">long</span> <span class="keywordtype">long</span> * propValue,
+<a name="l01269"></a>01269 <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> * options ) <span class="keyword">const</span>;
+<a name="l01270"></a>01270
+<a name="l01271"></a>01271 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l01285"></a>01285 <span class="comment"></span>
+<a name="l01286"></a>01286 <span class="keywordtype">bool</span>
+<a name="l01287"></a>01287 <a class="code" href="classTXMPMeta.html#7708c31c9af3e740b27a4893dcd9aa47">GetProperty_Float</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS,
+<a name="l01288"></a>01288 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> propName,
+<a name="l01289"></a>01289 <span class="keywordtype">double</span> * propValue,
+<a name="l01290"></a>01290 <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> * options ) <span class="keyword">const</span>;
+<a name="l01291"></a>01291
+<a name="l01292"></a>01292 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l01306"></a>01306 <span class="comment"></span>
+<a name="l01307"></a>01307 <span class="keywordtype">bool</span>
+<a name="l01308"></a>01308 <a class="code" href="classTXMPMeta.html#2f561295e73047ee90765558d29bd650">GetProperty_Date</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS,
+<a name="l01309"></a>01309 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> propName,
+<a name="l01310"></a>01310 <a class="code" href="structXMP__DateTime.html">XMP_DateTime</a> * propValue,
+<a name="l01311"></a>01311 <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> * options ) <span class="keyword">const</span>;
+<a name="l01312"></a>01312
+<a name="l01313"></a>01313 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l01324"></a>01324 <span class="comment"></span>
+<a name="l01325"></a>01325 <span class="keywordtype">void</span>
+<a name="l01326"></a>01326 <a class="code" href="classTXMPMeta.html#9521e3838272ec501ffdb60ff3eb482f">SetProperty_Bool</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS,
+<a name="l01327"></a>01327 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> propName,
+<a name="l01328"></a>01328 <span class="keywordtype">bool</span> propValue,
+<a name="l01329"></a>01329 <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options = 0 );
+<a name="l01330"></a>01330
+<a name="l01331"></a>01331 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l01341"></a>01341 <span class="comment"></span>
+<a name="l01342"></a>01342 <span class="keywordtype">void</span>
+<a name="l01343"></a>01343 <a class="code" href="classTXMPMeta.html#b8ae94130d9a05c1b9a3ee25588b6421">SetProperty_Int</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS,
+<a name="l01344"></a>01344 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> propName,
+<a name="l01345"></a>01345 <span class="keywordtype">long</span> propValue,
+<a name="l01346"></a>01346 <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options = 0 );
+<a name="l01347"></a>01347
+<a name="l01348"></a>01348 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l01358"></a>01358 <span class="comment"></span>
+<a name="l01359"></a>01359 <span class="keywordtype">void</span>
+<a name="l01360"></a>01360 <a class="code" href="classTXMPMeta.html#df919aff205e934e4c8250a067f7b377">SetProperty_Int64</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS,
+<a name="l01361"></a>01361 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> propName,
+<a name="l01362"></a>01362 <span class="keywordtype">long</span> <span class="keywordtype">long</span> propValue,
+<a name="l01363"></a>01363 <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options = 0 );
+<a name="l01364"></a>01364
+<a name="l01365"></a>01365 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l01375"></a>01375 <span class="comment"></span>
+<a name="l01376"></a>01376 <span class="keywordtype">void</span>
+<a name="l01377"></a>01377 <a class="code" href="classTXMPMeta.html#3b0f2f6bae57931ea96775f03608c0ed">SetProperty_Float</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS,
+<a name="l01378"></a>01378 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> propName,
+<a name="l01379"></a>01379 <span class="keywordtype">double</span> propValue,
+<a name="l01380"></a>01380 <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options = 0 );
+<a name="l01381"></a>01381
+<a name="l01382"></a>01382 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l01392"></a>01392 <span class="comment"></span>
+<a name="l01393"></a>01393 <span class="keywordtype">void</span>
+<a name="l01394"></a>01394 <a class="code" href="classTXMPMeta.html#eee10669445f77139d5634199ff01079">SetProperty_Date</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS,
+<a name="l01395"></a>01395 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> propName,
+<a name="l01396"></a>01396 <span class="keyword">const</span> <a class="code" href="structXMP__DateTime.html">XMP_DateTime</a> &amp; propValue,
+<a name="l01397"></a>01397 <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options = 0 );
+<a name="l01398"></a>01398
+<a name="l01400"></a>01400
+<a name="l01401"></a>01401 <span class="comment">// =============================================================================================</span>
+<a name="l01402"></a>01402 <span class="comment">// Miscellaneous Member Functions</span>
+<a name="l01403"></a>01403 <span class="comment">// ==============================</span>
+<a name="l01404"></a>01404
+<a name="l01405"></a>01405 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l01408"></a>01408 <span class="comment"></span>
+<a name="l01409"></a>01409 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l01412"></a>01412 <span class="comment"></span>
+<a name="l01413"></a>01413 <a class="code" href="XMP__Const_8h.html#5912613564f80e17eb10acef9236f70a">XMPMetaRef</a>
+<a name="l01414"></a>01414 <a class="code" href="classTXMPMeta.html#4d35b44f1f017a27772ee902a3dacf04">GetInternalRef</a>() <span class="keyword">const</span>;
+<a name="l01415"></a>01415
+<a name="l01416"></a>01416 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l01418"></a>01418 <span class="comment"></span>
+<a name="l01419"></a>01419 <span class="keywordtype">void</span>
+<a name="l01420"></a>01420 <a class="code" href="classTXMPMeta.html#b0d179ed95487d4fd4f2680c1fbe0d40">GetObjectName</a> ( tStringObj * name ) <span class="keyword">const</span>;
+<a name="l01421"></a>01421
+<a name="l01422"></a>01422 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l01424"></a>01424 <span class="comment"></span>
+<a name="l01425"></a>01425 <span class="keywordtype">void</span>
+<a name="l01426"></a>01426 <a class="code" href="classTXMPMeta.html#cf1935be8e4849976dfc02325424960a">SetObjectName</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> name );
+<a name="l01427"></a>01427
+<a name="l01428"></a>01428 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l01430"></a>01430 <span class="comment"></span>
+<a name="l01431"></a>01431 <span class="keywordtype">void</span>
+<a name="l01432"></a>01432 <a class="code" href="classTXMPMeta.html#cf1935be8e4849976dfc02325424960a">SetObjectName</a> ( tStringObj name );
+<a name="l01433"></a>01433
+<a name="l01434"></a>01434 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l01436"></a>01436 <span class="comment"></span>
+<a name="l01437"></a>01437 <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a>
+<a name="l01438"></a>01438 <a class="code" href="classTXMPMeta.html#39aeaf9eb83cfc1c5455807b95f055f9">GetObjectOptions</a>() <span class="keyword">const</span>;
+<a name="l01439"></a>01439
+<a name="l01440"></a>01440 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l01444"></a>01444 <span class="comment"></span>
+<a name="l01445"></a>01445 <span class="keywordtype">void</span>
+<a name="l01446"></a>01446 <a class="code" href="classTXMPMeta.html#92055b3ae18dfd5e5491108f59318f17">SetObjectOptions</a> ( <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options );
+<a name="l01447"></a>01447
+<a name="l01448"></a>01448 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l01469"></a>01469 <span class="comment"></span>
+<a name="l01470"></a>01470 <a class="code" href="classTXMPMeta.html">TXMPMeta</a>
+<a name="l01471"></a>01471 <a class="code" href="classTXMPMeta.html#6ca653436995bbb76315efe7934afd4c">Clone</a> ( <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options = 0 ) <span class="keyword">const</span>;
+<a name="l01472"></a>01472
+<a name="l01473"></a>01473 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l01475"></a>01475 <span class="comment"></span>
+<a name="l01476"></a>01476 <a class="code" href="XMP__Const_8h.html#00e9d9a76c144421105a4c2742203315">XMP_Index</a>
+<a name="l01477"></a>01477 <a class="code" href="classTXMPMeta.html#b79aae864b3ce190d0699252f48e0acc">CountArrayItems</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS,
+<a name="l01478"></a>01478 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> arrayName ) <span class="keyword">const</span>;
+<a name="l01479"></a>01479
+<a name="l01480"></a>01480 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l01482"></a>01482 <span class="comment"></span>
+<a name="l01483"></a>01483 <a class="code" href="XMP__Const_8h.html#91efdc0a7fbe6e1d42ca34e6ce589b98">XMP_Status</a>
+<a name="l01484"></a>01484 <a class="code" href="classTXMPMeta.html#976c1eb889f44080f76628805712b618">DumpObject</a> ( <a class="code" href="XMP__Const_8h.html#36eab570ab85ff8fb5789661692d13c2">XMP_TextOutputProc</a> outProc,
+<a name="l01485"></a>01485 <span class="keywordtype">void</span> * refCon ) <span class="keyword">const</span>;
+<a name="l01486"></a>01486
+<a name="l01488"></a>01488
+<a name="l01489"></a>01489 <span class="comment">// =============================================================================================</span>
+<a name="l01490"></a>01490
+<a name="l01491"></a>01491 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l01497"></a>01497 <span class="comment"></span>
+<a name="l01498"></a>01498 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l01517"></a>01517 <span class="comment"></span>
+<a name="l01518"></a>01518 <span class="keywordtype">void</span>
+<a name="l01519"></a>01519 <a class="code" href="classTXMPMeta.html#7b383f5b357fff040cdbde82f4f43f26">ParseFromBuffer</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> buffer,
+<a name="l01520"></a>01520 <a class="code" href="XMP__Const_8h.html#9f7dcc184f901c713274edfdac5bcc9a">XMP_StringLen</a> bufferSize,
+<a name="l01521"></a>01521 <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options = 0 );
+<a name="l01522"></a>01522
+<a name="l01523"></a>01523 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l01565"></a>01565 <span class="comment"></span>
+<a name="l01566"></a>01566 <span class="keywordtype">void</span>
+<a name="l01567"></a>01567 <a class="code" href="classTXMPMeta.html#2774a6f15ae22f0002201b58c46bfb49">SerializeToBuffer</a> ( tStringObj * rdfString,
+<a name="l01568"></a>01568 <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options,
+<a name="l01569"></a>01569 <a class="code" href="XMP__Const_8h.html#9f7dcc184f901c713274edfdac5bcc9a">XMP_StringLen</a> padding,
+<a name="l01570"></a>01570 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> newline,
+<a name="l01571"></a>01571 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> indent = <span class="stringliteral">""</span>,
+<a name="l01572"></a>01572 <a class="code" href="XMP__Const_8h.html#00e9d9a76c144421105a4c2742203315">XMP_Index</a> baseIndent = 0 ) <span class="keyword">const</span>;
+<a name="l01573"></a>01573
+<a name="l01574"></a>01574 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l01578"></a>01578 <span class="comment"></span>
+<a name="l01579"></a>01579 <span class="keywordtype">void</span>
+<a name="l01580"></a>01580 <a class="code" href="classTXMPMeta.html#2774a6f15ae22f0002201b58c46bfb49">SerializeToBuffer</a> ( tStringObj * rdfString,
+<a name="l01581"></a>01581 <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options = 0,
+<a name="l01582"></a>01582 <a class="code" href="XMP__Const_8h.html#9f7dcc184f901c713274edfdac5bcc9a">XMP_StringLen</a> padding = 0 ) <span class="keyword">const</span>;
+<a name="l01583"></a>01583
+<a name="l01585"></a>01585
+<a name="l01586"></a>01586 <span class="comment">// =============================================================================================</span>
+<a name="l01587"></a>01587
+<a name="l01588"></a>01588 <a class="code" href="XMP__Const_8h.html#5912613564f80e17eb10acef9236f70a">XMPMetaRef</a> xmpRef; <span class="comment">// *** Should be private, see below.</span>
+<a name="l01589"></a>01589
+<a name="l01590"></a>01590 <span class="keyword">private</span>:
+<a name="l01591"></a>01591
+<a name="l01592"></a>01592 <span class="preprocessor">#if 0 // *** VS.Net and gcc seem to not handle the friend declarations properly.</span>
+<a name="l01593"></a>01593 <span class="preprocessor"></span> <span class="keyword">friend</span> <span class="keyword">class </span><a class="code" href="classTXMPIterator.html">TXMPIterator</a> &lt;class tStringObj&gt;;
+<a name="l01594"></a>01594 <span class="keyword">friend</span> <span class="keyword">class </span><a class="code" href="classTXMPUtils.html">TXMPUtils</a> &lt;class tStringObj&gt;;
+<a name="l01595"></a>01595 <span class="preprocessor">#endif</span>
+<a name="l01596"></a>01596 <span class="preprocessor"></span>
+<a name="l01597"></a>01597 }; <span class="comment">// class TXMPMeta</span>
+<a name="l01598"></a>01598
+<a name="l01599"></a>01599 <span class="preprocessor">#endif // __TXMPMeta_hpp__</span>
+</pre></div><hr size="1"><address style="align: right;"><small>Generated on Thu May 3 14:54:57 2007 for Adobe XMP Toolkit by&nbsp;
+<a href="http://www.doxygen.org/index.html">
+<img src="doxygen.png" alt="doxygen" align="middle" border="0"></a> 1.5.1 </small></address>
+</body>
+</html>
diff --git a/docs/XMPToolkit/TXMPMeta_8hpp.html b/docs/XMPToolkit/TXMPMeta_8hpp.html
new file mode 100644
index 0000000..162e5eb
--- /dev/null
+++ b/docs/XMPToolkit/TXMPMeta_8hpp.html
@@ -0,0 +1,33 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
+<title>Adobe XMP Toolkit: TXMPMeta.hpp File Reference</title>
+<link href="doxygen.css" rel="stylesheet" type="text/css">
+<link href="tabs.css" rel="stylesheet" type="text/css">
+</head><body>
+<!-- Generated by Doxygen 1.5.1 -->
+<div class="tabs">
+ <ul>
+ <li><a href="index.html"><span>Main&nbsp;Page</span></a></li>
+ <li><a href="modules.html"><span>Modules</span></a></li>
+ <li><a href="annotated.html"><span>Classes</span></a></li>
+ <li id="current"><a href="files.html"><span>Files</span></a></li>
+ </ul></div>
+<h1>TXMPMeta.hpp File Reference</h1>Template class for the XMP Toolkit core services. <a href="#_details">More...</a>
+<p>
+
+<p>
+<a href="TXMPMeta_8hpp-source.html">Go to the source code of this file.</a><table border="0" cellpadding="0" cellspacing="0">
+<tr><td></td></tr>
+<tr><td colspan="2"><br><h2>Classes</h2></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">class &nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Template class for the XMP Toolkit core services. <a href="classTXMPMeta.html#_details">More...</a><br></td></tr>
+</table>
+<hr><a name="_details"></a><h2>Detailed Description</h2>
+Template class for the XMP Toolkit core services.
+<p>
+<a class="el" href="classTXMPMeta.html">TXMPMeta</a> is the template class providing the core services of the XMP Toolkit. It should be instantiated with a string class such as <code>std::string</code>. Please read the general toolkit usage notes for information about the overall architecture of the XMP API. <hr size="1"><address style="align: right;"><small>Generated on Thu May 3 14:54:58 2007 for Adobe XMP Toolkit by&nbsp;
+<a href="http://www.doxygen.org/index.html">
+<img src="doxygen.png" alt="doxygen" align="middle" border="0"></a> 1.5.1 </small></address>
+</body>
+</html>
diff --git a/docs/XMPToolkit/TXMPMeta_8incl__cpp.html b/docs/XMPToolkit/TXMPMeta_8incl__cpp.html
new file mode 100644
index 0000000..c0b862b
--- /dev/null
+++ b/docs/XMPToolkit/TXMPMeta_8incl__cpp.html
@@ -0,0 +1,33 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
+<title>Adobe XMP Toolkit: TXMPMeta.incl_cpp File Reference</title>
+<link href="doxygen.css" rel="stylesheet" type="text/css">
+<link href="tabs.css" rel="stylesheet" type="text/css">
+</head><body>
+<!-- Generated by Doxygen 1.5.1 -->
+<div class="tabs">
+ <ul>
+ <li><a href="index.html"><span>Main&nbsp;Page</span></a></li>
+ <li><a href="modules.html"><span>Modules</span></a></li>
+ <li><a href="annotated.html"><span>Classes</span></a></li>
+ <li id="current"><a href="files.html"><span>Files</span></a></li>
+ </ul></div>
+<h1>TXMPMeta.incl_cpp File Reference</h1>The implementation of the <a class="el" href="classTXMPMeta.html">TXMPMeta</a> template class. <a href="#_details">More...</a>
+<p>
+<code>#include &quot;XMP.hpp&quot;</code><br>
+<code>#include &quot;client-glue/WXMP_Common.hpp&quot;</code><br>
+<code>#include &quot;client-glue/WXMPMeta.hpp&quot;</code><br>
+
+<p>
+Include dependency graph for TXMPMeta.incl_cpp:<p><center><img src="TXMPMeta_8incl__cpp__incl.png" border="0" usemap="#TXMPMeta.incl_cpp_map" alt=""></center>
+<table border="0" cellpadding="0" cellspacing="0">
+<tr><td></td></tr>
+</table>
+<hr><a name="_details"></a><h2>Detailed Description</h2>
+The implementation of the <a class="el" href="classTXMPMeta.html">TXMPMeta</a> template class.
+<p>
+<hr size="1"><address style="align: right;"><small>Generated on Thu May 3 14:54:58 2007 for Adobe XMP Toolkit by&nbsp;
+<a href="http://www.doxygen.org/index.html">
+<img src="doxygen.png" alt="doxygen" align="middle" border="0"></a> 1.5.1 </small></address>
+</body>
+</html>
diff --git a/docs/XMPToolkit/TXMPMeta_8incl__cpp__incl.png b/docs/XMPToolkit/TXMPMeta_8incl__cpp__incl.png
new file mode 100644
index 0000000..f453f8c
--- /dev/null
+++ b/docs/XMPToolkit/TXMPMeta_8incl__cpp__incl.png
Binary files differ
diff --git a/docs/XMPToolkit/TXMPUtils_8hpp-source.html b/docs/XMPToolkit/TXMPUtils_8hpp-source.html
new file mode 100644
index 0000000..5b4777c
--- /dev/null
+++ b/docs/XMPToolkit/TXMPUtils_8hpp-source.html
@@ -0,0 +1,360 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
+<title>Adobe XMP Toolkit: TXMPUtils.hpp Source File</title>
+<link href="doxygen.css" rel="stylesheet" type="text/css">
+<link href="tabs.css" rel="stylesheet" type="text/css">
+</head><body>
+<!-- Generated by Doxygen 1.5.1 -->
+<div class="tabs">
+ <ul>
+ <li><a href="index.html"><span>Main&nbsp;Page</span></a></li>
+ <li><a href="modules.html"><span>Modules</span></a></li>
+ <li><a href="annotated.html"><span>Classes</span></a></li>
+ <li id="current"><a href="files.html"><span>Files</span></a></li>
+ </ul></div>
+<h1>TXMPUtils.hpp</h1><a href="TXMPUtils_8hpp.html">Go to the documentation of this file.</a><div class="fragment"><pre class="fragment"><a name="l00001"></a>00001 <span class="preprocessor">#ifndef __TXMPUtils_hpp__</span>
+<a name="l00002"></a>00002 <span class="preprocessor"></span><span class="preprocessor">#define __TXMPUtils_hpp__ 1</span>
+<a name="l00003"></a>00003 <span class="preprocessor"></span>
+<a name="l00004"></a>00004 <span class="preprocessor">#if ( ! __XMP_hpp__ )</span>
+<a name="l00005"></a>00005 <span class="preprocessor"></span><span class="preprocessor"> #error "Do not directly include, use XMP.hpp"</span>
+<a name="l00006"></a>00006 <span class="preprocessor"></span><span class="preprocessor">#endif</span>
+<a name="l00007"></a>00007 <span class="preprocessor"></span>
+<a name="l00008"></a>00008 <span class="comment">// =================================================================================================</span>
+<a name="l00009"></a>00009 <span class="comment">// ADOBE SYSTEMS INCORPORATED</span>
+<a name="l00010"></a>00010 <span class="comment">// Copyright 2002-2007 Adobe Systems Incorporated</span>
+<a name="l00011"></a>00011 <span class="comment">// All Rights Reserved</span>
+<a name="l00012"></a>00012 <span class="comment">//</span>
+<a name="l00013"></a>00013 <span class="comment">// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms</span>
+<a name="l00014"></a>00014 <span class="comment">// of the Adobe license agreement accompanying it.</span>
+<a name="l00015"></a>00015 <span class="comment">// =================================================================================================</span>
+<a name="l00016"></a>00016
+<a name="l00017"></a>00017 <span class="comment">// ================================================================================================</span>
+<a name="l00024"></a>00024 <span class="comment"></span><span class="comment">// ================================================================================================</span>
+<a name="l00025"></a>00025
+<a name="l00026"></a>00026 <span class="comment">// ================================================================================================</span>
+<a name="l00041"></a>00041 <span class="comment"></span><span class="comment">// ================================================================================================</span>
+<a name="l00042"></a>00042
+<a name="l00043"></a>00043 <span class="keyword">template</span> &lt;<span class="keyword">class</span> tStringObj&gt;
+<a name="l00044"></a><a class="code" href="classTXMPUtils.html">00044</a> <span class="keyword">class </span><a class="code" href="classTXMPUtils.html">TXMPUtils</a> {
+<a name="l00045"></a>00045
+<a name="l00046"></a>00046 <span class="keyword">public</span>:
+<a name="l00047"></a>00047
+<a name="l00048"></a>00048 <span class="comment">// =============================================================================================</span>
+<a name="l00049"></a>00049 <span class="comment">// No constructors or destructor declared or needed</span>
+<a name="l00050"></a>00050 <span class="comment">// ================================================</span>
+<a name="l00051"></a>00051
+<a name="l00052"></a>00052 <span class="comment">// =============================================================================================</span>
+<a name="l00053"></a>00053 <span class="comment">// =============================================================================================</span>
+<a name="l00054"></a>00054
+<a name="l00055"></a>00055 <span class="comment">// ============================================================================================</span>
+<a name="l00087"></a>00087 <span class="comment"></span>
+<a name="l00088"></a>00088 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00103"></a>00103 <span class="comment"></span>
+<a name="l00104"></a>00104 <span class="keyword">static</span> <span class="keywordtype">void</span>
+<a name="l00105"></a>00105 <a class="code" href="classTXMPUtils.html#47fa195aa2e1457aa1f74f7e1ed06da6">ComposeArrayItemPath</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS,
+<a name="l00106"></a>00106 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> arrayName,
+<a name="l00107"></a>00107 <a class="code" href="XMP__Const_8h.html#00e9d9a76c144421105a4c2742203315">XMP_Index</a> itemIndex,
+<a name="l00108"></a>00108 tStringObj * fullPath );
+<a name="l00109"></a>00109
+<a name="l00110"></a>00110 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00126"></a>00126 <span class="comment"></span>
+<a name="l00127"></a>00127 <span class="keyword">static</span> <span class="keywordtype">void</span>
+<a name="l00128"></a>00128 <a class="code" href="classTXMPUtils.html#706eb85b8401b8682a01348f7e25ee3d">ComposeStructFieldPath</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS,
+<a name="l00129"></a>00129 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> structName,
+<a name="l00130"></a>00130 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> fieldNS,
+<a name="l00131"></a>00131 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> fieldName,
+<a name="l00132"></a>00132 tStringObj * fullPath );
+<a name="l00133"></a>00133
+<a name="l00134"></a>00134 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00152"></a>00152 <span class="comment"></span>
+<a name="l00153"></a>00153 <span class="keyword">static</span> <span class="keywordtype">void</span>
+<a name="l00154"></a>00154 <a class="code" href="classTXMPUtils.html#40ae0ce2065fcb71725e37137884e172">ComposeQualifierPath</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS,
+<a name="l00155"></a>00155 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> propName,
+<a name="l00156"></a>00156 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> qualNS,
+<a name="l00157"></a>00157 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> qualName,
+<a name="l00158"></a>00158 tStringObj * fullPath );
+<a name="l00159"></a>00159
+<a name="l00160"></a>00160 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00184"></a>00184 <span class="comment"></span>
+<a name="l00185"></a>00185 <span class="keyword">static</span> <span class="keywordtype">void</span>
+<a name="l00186"></a>00186 <a class="code" href="classTXMPUtils.html#e4989e5c199a2a4287ee3ae89b872e69">ComposeLangSelector</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS,
+<a name="l00187"></a>00187 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> arrayName,
+<a name="l00188"></a>00188 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> langName,
+<a name="l00189"></a>00189 tStringObj * fullPath );
+<a name="l00190"></a>00190
+<a name="l00191"></a>00191 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00194"></a>00194 <span class="comment"></span>
+<a name="l00195"></a>00195 <span class="keyword">static</span> <span class="keywordtype">void</span>
+<a name="l00196"></a>00196 <a class="code" href="classTXMPUtils.html#e4989e5c199a2a4287ee3ae89b872e69">ComposeLangSelector</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS,
+<a name="l00197"></a>00197 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> arrayName,
+<a name="l00198"></a>00198 <span class="keyword">const</span> tStringObj &amp; langName,
+<a name="l00199"></a>00199 tStringObj * fullPath );
+<a name="l00200"></a>00200
+<a name="l00201"></a>00201 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00235"></a>00235 <span class="comment"></span>
+<a name="l00236"></a>00236 <span class="keyword">static</span> <span class="keywordtype">void</span>
+<a name="l00237"></a>00237 <a class="code" href="classTXMPUtils.html#458f8e8729e2334fe54ca8f691a9db23">ComposeFieldSelector</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS,
+<a name="l00238"></a>00238 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> arrayName,
+<a name="l00239"></a>00239 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> fieldNS,
+<a name="l00240"></a>00240 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> fieldName,
+<a name="l00241"></a>00241 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> fieldValue,
+<a name="l00242"></a>00242 tStringObj * fullPath );
+<a name="l00243"></a>00243
+<a name="l00244"></a>00244 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00247"></a>00247 <span class="comment"></span>
+<a name="l00248"></a>00248 <span class="keyword">static</span> <span class="keywordtype">void</span>
+<a name="l00249"></a>00249 <a class="code" href="classTXMPUtils.html#458f8e8729e2334fe54ca8f691a9db23">ComposeFieldSelector</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS,
+<a name="l00250"></a>00250 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> arrayName,
+<a name="l00251"></a>00251 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> fieldNS,
+<a name="l00252"></a>00252 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> fieldName,
+<a name="l00253"></a>00253 <span class="keyword">const</span> tStringObj &amp; fieldValue,
+<a name="l00254"></a>00254 tStringObj * fullPath );
+<a name="l00255"></a>00255
+<a name="l00257"></a>00257
+<a name="l00258"></a>00258 <span class="comment">// =============================================================================================</span>
+<a name="l00259"></a>00259 <span class="comment">// =============================================================================================</span>
+<a name="l00260"></a>00260
+<a name="l00261"></a>00261 <span class="comment">// ============================================================================================</span>
+<a name="l00264"></a>00264 <span class="comment"></span>
+<a name="l00265"></a>00265 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00272"></a>00272 <span class="comment"></span>
+<a name="l00273"></a>00273 <span class="keyword">static</span> <span class="keywordtype">void</span>
+<a name="l00274"></a>00274 <a class="code" href="classTXMPUtils.html#509691eb270988de6a770c9c8304ab6b">ConvertFromBool</a> ( <span class="keywordtype">bool</span> binValue,
+<a name="l00275"></a>00275 tStringObj * strValue );
+<a name="l00276"></a>00276
+<a name="l00277"></a>00277 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00285"></a>00285 <span class="comment"></span>
+<a name="l00286"></a>00286 <span class="keyword">static</span> <span class="keywordtype">void</span>
+<a name="l00287"></a>00287 <a class="code" href="classTXMPUtils.html#eec45b4d1a26717290105c9f4e8b4235">ConvertFromInt</a> ( <span class="keywordtype">long</span> binValue,
+<a name="l00288"></a>00288 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> format,
+<a name="l00289"></a>00289 tStringObj * strValue );
+<a name="l00290"></a>00290
+<a name="l00291"></a>00291 <span class="keyword">static</span> <span class="keywordtype">void</span>
+<a name="l00292"></a>00292 ConvertFromInt64 ( <span class="keywordtype">long</span> <span class="keywordtype">long</span> binValue,
+<a name="l00293"></a>00293 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> format,
+<a name="l00294"></a>00294 tStringObj * strValue );
+<a name="l00295"></a>00295
+<a name="l00296"></a>00296 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00304"></a>00304 <span class="comment"></span>
+<a name="l00305"></a>00305 <span class="keyword">static</span> <span class="keywordtype">void</span>
+<a name="l00306"></a>00306 <a class="code" href="classTXMPUtils.html#e67ef3931836432b7e574832f0610ed0">ConvertFromFloat</a> ( <span class="keywordtype">double</span> binValue,
+<a name="l00307"></a>00307 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> format,
+<a name="l00308"></a>00308 tStringObj * strValue );
+<a name="l00309"></a>00309
+<a name="l00310"></a>00310 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00339"></a>00339 <span class="comment"></span>
+<a name="l00340"></a>00340 <span class="keyword">static</span> <span class="keywordtype">void</span>
+<a name="l00341"></a>00341 <a class="code" href="classTXMPUtils.html#6146a522a3974b4088d6e8241e9cd223">ConvertFromDate</a> ( <span class="keyword">const</span> <a class="code" href="structXMP__DateTime.html">XMP_DateTime</a> &amp; binValue,
+<a name="l00342"></a>00342 tStringObj * strValue );
+<a name="l00343"></a>00343
+<a name="l00344"></a>00344 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00352"></a>00352 <span class="comment"></span>
+<a name="l00353"></a>00353 <span class="keyword">static</span> <span class="keywordtype">bool</span>
+<a name="l00354"></a>00354 <a class="code" href="classTXMPUtils.html#aaaaadb23f4089daa795f50cba4f405c">ConvertToBool</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> strValue );
+<a name="l00355"></a>00355
+<a name="l00356"></a>00356 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00359"></a>00359 <span class="comment"></span>
+<a name="l00360"></a>00360 <span class="keyword">static</span> <span class="keywordtype">bool</span>
+<a name="l00361"></a>00361 <a class="code" href="classTXMPUtils.html#aaaaadb23f4089daa795f50cba4f405c">ConvertToBool</a> ( <span class="keyword">const</span> tStringObj &amp; strValue );
+<a name="l00362"></a>00362
+<a name="l00363"></a>00363 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00369"></a>00369 <span class="comment"></span>
+<a name="l00370"></a>00370 <span class="keyword">static</span> <span class="keywordtype">long</span>
+<a name="l00371"></a>00371 <a class="code" href="classTXMPUtils.html#dfd9d1c522377d5db4ad667a7973ba00">ConvertToInt</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> strValue );
+<a name="l00372"></a>00372
+<a name="l00373"></a>00373 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00376"></a>00376 <span class="comment"></span>
+<a name="l00377"></a>00377 <span class="keyword">static</span> <span class="keywordtype">long</span>
+<a name="l00378"></a>00378 <a class="code" href="classTXMPUtils.html#dfd9d1c522377d5db4ad667a7973ba00">ConvertToInt</a> ( <span class="keyword">const</span> tStringObj &amp; strValue );
+<a name="l00379"></a>00379
+<a name="l00380"></a>00380 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00386"></a>00386 <span class="comment"></span>
+<a name="l00387"></a>00387 <span class="keyword">static</span> <span class="keywordtype">long</span> <span class="keywordtype">long</span>
+<a name="l00388"></a>00388 <a class="code" href="classTXMPUtils.html#be5d2dcc03c5442202203bba5ca7b172">ConvertToInt64</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> strValue );
+<a name="l00389"></a>00389
+<a name="l00390"></a>00390 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00393"></a>00393 <span class="comment"></span>
+<a name="l00394"></a>00394 <span class="keyword">static</span> <span class="keywordtype">long</span> <span class="keywordtype">long</span>
+<a name="l00395"></a>00395 <a class="code" href="classTXMPUtils.html#be5d2dcc03c5442202203bba5ca7b172">ConvertToInt64</a> ( <span class="keyword">const</span> tStringObj &amp; strValue );
+<a name="l00396"></a>00396
+<a name="l00397"></a>00397 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00403"></a>00403 <span class="comment"></span>
+<a name="l00404"></a>00404 <span class="keyword">static</span> <span class="keywordtype">double</span>
+<a name="l00405"></a>00405 <a class="code" href="classTXMPUtils.html#8a507b006286460814e0486c622d828c">ConvertToFloat</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> strValue );
+<a name="l00406"></a>00406
+<a name="l00407"></a>00407 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00410"></a>00410 <span class="comment"></span>
+<a name="l00411"></a>00411 <span class="keyword">static</span> <span class="keywordtype">double</span>
+<a name="l00412"></a>00412 <a class="code" href="classTXMPUtils.html#8a507b006286460814e0486c622d828c">ConvertToFloat</a> ( <span class="keyword">const</span> tStringObj &amp; strValue );
+<a name="l00413"></a>00413
+<a name="l00414"></a>00414 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00444"></a>00444 <span class="comment"></span>
+<a name="l00445"></a>00445 <span class="keyword">static</span> <span class="keywordtype">void</span>
+<a name="l00446"></a>00446 <a class="code" href="classTXMPUtils.html#60d33e6ce30286028acca47b2b6e7a0b">ConvertToDate</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> strValue,
+<a name="l00447"></a>00447 <a class="code" href="structXMP__DateTime.html">XMP_DateTime</a> * binValue );
+<a name="l00448"></a>00448
+<a name="l00449"></a>00449 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00452"></a>00452 <span class="comment"></span>
+<a name="l00453"></a>00453 <span class="keyword">static</span> <span class="keywordtype">void</span>
+<a name="l00454"></a>00454 <a class="code" href="classTXMPUtils.html#60d33e6ce30286028acca47b2b6e7a0b">ConvertToDate</a> ( <span class="keyword">const</span> tStringObj &amp; strValue,
+<a name="l00455"></a>00455 <a class="code" href="structXMP__DateTime.html">XMP_DateTime</a> * binValue );
+<a name="l00456"></a>00456
+<a name="l00458"></a>00458
+<a name="l00459"></a>00459 <span class="comment">// =============================================================================================</span>
+<a name="l00460"></a>00460 <span class="comment">// =============================================================================================</span>
+<a name="l00461"></a>00461
+<a name="l00462"></a>00462 <span class="comment">// ============================================================================================</span>
+<a name="l00465"></a>00465 <span class="comment"></span>
+<a name="l00466"></a>00466 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00472"></a>00472 <span class="comment"></span>
+<a name="l00473"></a>00473 <span class="keyword">static</span> <span class="keywordtype">void</span>
+<a name="l00474"></a>00474 <a class="code" href="classTXMPUtils.html#c83f0b963ea64d7eee0b481e15a8439c">CurrentDateTime</a> ( <a class="code" href="structXMP__DateTime.html">XMP_DateTime</a> * time );
+<a name="l00475"></a>00475
+<a name="l00476"></a>00476 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00481"></a>00481 <span class="comment"></span>
+<a name="l00482"></a>00482 <span class="keyword">static</span> <span class="keywordtype">void</span>
+<a name="l00483"></a>00483 <a class="code" href="classTXMPUtils.html#96bcc45febac55f6c49951815b7de2ef">SetTimeZone</a> ( <a class="code" href="structXMP__DateTime.html">XMP_DateTime</a> * time );
+<a name="l00484"></a>00484
+<a name="l00485"></a>00485 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00490"></a>00490 <span class="comment"></span>
+<a name="l00491"></a>00491 <span class="keyword">static</span> <span class="keywordtype">void</span>
+<a name="l00492"></a>00492 <a class="code" href="classTXMPUtils.html#bbd4d691c83287ea2fc6b1e33e5858b8">ConvertToUTCTime</a> ( <a class="code" href="structXMP__DateTime.html">XMP_DateTime</a> * time );
+<a name="l00493"></a>00493
+<a name="l00494"></a>00494 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00499"></a>00499 <span class="comment"></span>
+<a name="l00500"></a>00500 <span class="keyword">static</span> <span class="keywordtype">void</span>
+<a name="l00501"></a>00501 <a class="code" href="classTXMPUtils.html#61852aaba494c8fbad5a6c0c4caf21f5">ConvertToLocalTime</a> ( <a class="code" href="structXMP__DateTime.html">XMP_DateTime</a> * time );
+<a name="l00502"></a>00502
+<a name="l00503"></a>00503 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00514"></a>00514 <span class="comment"></span>
+<a name="l00515"></a>00515 <span class="keyword">static</span> <span class="keywordtype">int</span>
+<a name="l00516"></a>00516 <a class="code" href="classTXMPUtils.html#9fc7f1771032f59f9020aeda4f91991d">CompareDateTime</a> ( <span class="keyword">const</span> <a class="code" href="structXMP__DateTime.html">XMP_DateTime</a> &amp; left,
+<a name="l00517"></a>00517 <span class="keyword">const</span> <a class="code" href="structXMP__DateTime.html">XMP_DateTime</a> &amp; right );
+<a name="l00518"></a>00518
+<a name="l00520"></a>00520
+<a name="l00521"></a>00521 <span class="comment">// =============================================================================================</span>
+<a name="l00522"></a>00522 <span class="comment">// =============================================================================================</span>
+<a name="l00523"></a>00523
+<a name="l00524"></a>00524 <span class="comment">// ============================================================================================</span>
+<a name="l00527"></a>00527 <span class="comment"></span>
+<a name="l00528"></a>00528 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00536"></a>00536 <span class="comment"></span>
+<a name="l00537"></a>00537 <span class="keyword">static</span> <span class="keywordtype">void</span>
+<a name="l00538"></a>00538 <a class="code" href="classTXMPUtils.html#ef3b23bbc152480f699e269620ecad4a">EncodeToBase64</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> rawStr,
+<a name="l00539"></a>00539 <a class="code" href="XMP__Const_8h.html#9f7dcc184f901c713274edfdac5bcc9a">XMP_StringLen</a> rawLen,
+<a name="l00540"></a>00540 tStringObj * encodedStr );
+<a name="l00541"></a>00541
+<a name="l00542"></a>00542 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00545"></a>00545 <span class="comment"></span>
+<a name="l00546"></a>00546 <span class="keyword">static</span> <span class="keywordtype">void</span>
+<a name="l00547"></a>00547 <a class="code" href="classTXMPUtils.html#ef3b23bbc152480f699e269620ecad4a">EncodeToBase64</a> ( <span class="keyword">const</span> tStringObj &amp; rawStr,
+<a name="l00548"></a>00548 tStringObj * encodedStr );
+<a name="l00549"></a>00549
+<a name="l00550"></a>00550 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00558"></a>00558 <span class="comment"></span>
+<a name="l00559"></a>00559 <span class="keyword">static</span> <span class="keywordtype">void</span>
+<a name="l00560"></a>00560 <a class="code" href="classTXMPUtils.html#e5bdd91c0c3ee9262dc0a8b9f591b921">DecodeFromBase64</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> encodedStr,
+<a name="l00561"></a>00561 <a class="code" href="XMP__Const_8h.html#9f7dcc184f901c713274edfdac5bcc9a">XMP_StringLen</a> encodedLen,
+<a name="l00562"></a>00562 tStringObj * rawStr );
+<a name="l00563"></a>00563
+<a name="l00564"></a>00564 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00567"></a>00567 <span class="comment"></span>
+<a name="l00568"></a>00568 <span class="keyword">static</span> <span class="keywordtype">void</span>
+<a name="l00569"></a>00569 <a class="code" href="classTXMPUtils.html#e5bdd91c0c3ee9262dc0a8b9f591b921">DecodeFromBase64</a> ( <span class="keyword">const</span> tStringObj &amp; encodedStr,
+<a name="l00570"></a>00570 tStringObj * rawStr );
+<a name="l00571"></a>00571
+<a name="l00573"></a>00573
+<a name="l00574"></a>00574 <span class="comment">// =============================================================================================</span>
+<a name="l00575"></a>00575 <span class="comment">// =============================================================================================</span>
+<a name="l00576"></a>00576
+<a name="l00577"></a>00577 <span class="comment">// ============================================================================================</span>
+<a name="l00582"></a>00582 <span class="comment"></span>
+<a name="l00583"></a>00583 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00595"></a>00595 <span class="comment"></span>
+<a name="l00596"></a>00596 <span class="keyword">static</span> <span class="keywordtype">void</span>
+<a name="l00597"></a>00597 <a class="code" href="classTXMPUtils.html#6001b4ff54c60fdf0c40e6b78a5c457a">PackageForJPEG</a> ( <span class="keyword">const</span> <a class="code" href="classTXMPMeta.html">TXMPMeta&lt;tStringObj&gt;</a> &amp; xmpObj,
+<a name="l00598"></a>00598 tStringObj * standardXMP,
+<a name="l00599"></a>00599 tStringObj * extendedXMP,
+<a name="l00600"></a>00600 tStringObj * extendedDigest );
+<a name="l00601"></a>00601
+<a name="l00602"></a>00602 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00608"></a>00608 <span class="comment"></span>
+<a name="l00609"></a>00609 <span class="keyword">static</span> <span class="keywordtype">void</span>
+<a name="l00610"></a>00610 <a class="code" href="classTXMPUtils.html#6187cd5fef0eccecac6805d4114dcd2e">MergeFromJPEG</a> ( <a class="code" href="classTXMPMeta.html">TXMPMeta&lt;tStringObj&gt;</a> * fullXMP,
+<a name="l00611"></a>00611 <span class="keyword">const</span> <a class="code" href="classTXMPMeta.html">TXMPMeta&lt;tStringObj&gt;</a> &amp; extendedXMP );
+<a name="l00612"></a>00612
+<a name="l00614"></a>00614
+<a name="l00615"></a>00615 <span class="comment">// =============================================================================================</span>
+<a name="l00616"></a>00616 <span class="comment">// =============================================================================================</span>
+<a name="l00617"></a>00617
+<a name="l00618"></a>00618 <span class="comment">// ============================================================================================</span>
+<a name="l00622"></a>00622 <span class="comment"></span>
+<a name="l00623"></a>00623 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00644"></a>00644 <span class="comment"></span>
+<a name="l00645"></a>00645 <span class="keyword">static</span> <span class="keywordtype">void</span>
+<a name="l00646"></a>00646 <a class="code" href="classTXMPUtils.html#d7e1aa7928252fb88a24fb5c3aef22ba">CatenateArrayItems</a> ( <span class="keyword">const</span> <a class="code" href="classTXMPMeta.html">TXMPMeta&lt;tStringObj&gt;</a> &amp; xmpObj,
+<a name="l00647"></a>00647 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS,
+<a name="l00648"></a>00648 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> arrayName,
+<a name="l00649"></a>00649 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> separator,
+<a name="l00650"></a>00650 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> quotes,
+<a name="l00651"></a>00651 <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options,
+<a name="l00652"></a>00652 tStringObj * catedStr );
+<a name="l00653"></a>00653
+<a name="l00654"></a>00654 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00669"></a>00669 <span class="comment"></span>
+<a name="l00670"></a>00670 <span class="keyword">static</span> <span class="keywordtype">void</span>
+<a name="l00671"></a>00671 <a class="code" href="classTXMPUtils.html#66c5ddee47aa36ed906353f94ca18d2e">SeparateArrayItems</a> ( <a class="code" href="classTXMPMeta.html">TXMPMeta&lt;tStringObj&gt;</a> * xmpObj,
+<a name="l00672"></a>00672 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS,
+<a name="l00673"></a>00673 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> arrayName,
+<a name="l00674"></a>00674 <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options,
+<a name="l00675"></a>00675 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> catedStr );
+<a name="l00676"></a>00676
+<a name="l00677"></a>00677 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00680"></a>00680 <span class="comment"></span>
+<a name="l00681"></a>00681 <span class="keyword">static</span> <span class="keywordtype">void</span>
+<a name="l00682"></a>00682 <a class="code" href="classTXMPUtils.html#66c5ddee47aa36ed906353f94ca18d2e">SeparateArrayItems</a> ( <a class="code" href="classTXMPMeta.html">TXMPMeta&lt;tStringObj&gt;</a> * xmpObj,
+<a name="l00683"></a>00683 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS,
+<a name="l00684"></a>00684 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> arrayName,
+<a name="l00685"></a>00685 <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options,
+<a name="l00686"></a>00686 <span class="keyword">const</span> tStringObj &amp; catedStr );
+<a name="l00687"></a>00687
+<a name="l00688"></a>00688 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00719"></a>00719 <span class="comment"></span>
+<a name="l00720"></a>00720 <span class="keyword">static</span> <span class="keywordtype">void</span>
+<a name="l00721"></a>00721 <a class="code" href="classTXMPUtils.html#40c645803530662e08d042b4b7c6190d">RemoveProperties</a> ( <a class="code" href="classTXMPMeta.html">TXMPMeta&lt;tStringObj&gt;</a> * xmpObj,
+<a name="l00722"></a>00722 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS = 0,
+<a name="l00723"></a>00723 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> propName = 0,
+<a name="l00724"></a>00724 <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options = 0 );
+<a name="l00725"></a>00725
+<a name="l00726"></a>00726 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00800"></a>00800 <span class="comment"></span>
+<a name="l00801"></a>00801 <span class="keyword">static</span> <span class="keywordtype">void</span>
+<a name="l00802"></a>00802 <a class="code" href="classTXMPUtils.html#4795244ffcbda927800f789b0e40c262">AppendProperties</a> ( <span class="keyword">const</span> <a class="code" href="classTXMPMeta.html">TXMPMeta&lt;tStringObj&gt;</a> &amp; source,
+<a name="l00803"></a>00803 <a class="code" href="classTXMPMeta.html">TXMPMeta&lt;tStringObj&gt;</a> * dest,
+<a name="l00804"></a>00804 <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options = 0 );
+<a name="l00805"></a>00805
+<a name="l00806"></a>00806 <span class="comment">// --------------------------------------------------------------------------------------------</span>
+<a name="l00826"></a>00826 <span class="comment"></span>
+<a name="l00827"></a>00827 <span class="keyword">static</span> <span class="keywordtype">void</span>
+<a name="l00828"></a>00828 <a class="code" href="classTXMPUtils.html#a17838f062e5414bc0929f67ac94a3aa">DuplicateSubtree</a> ( <span class="keyword">const</span> <a class="code" href="classTXMPMeta.html">TXMPMeta&lt;tStringObj&gt;</a> &amp; source,
+<a name="l00829"></a>00829 <a class="code" href="classTXMPMeta.html">TXMPMeta&lt;tStringObj&gt;</a> * dest,
+<a name="l00830"></a>00830 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> sourceNS,
+<a name="l00831"></a>00831 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> sourceRoot,
+<a name="l00832"></a>00832 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> destNS = 0,
+<a name="l00833"></a>00833 <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> destRoot = 0,
+<a name="l00834"></a>00834 <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options = 0 );
+<a name="l00835"></a>00835
+<a name="l00836"></a>00836
+<a name="l00838"></a>00838
+<a name="l00839"></a>00839 <span class="comment">// =============================================================================================</span>
+<a name="l00840"></a>00840
+<a name="l00841"></a>00841 }; <span class="comment">// class TXMPUtils</span>
+<a name="l00842"></a>00842
+<a name="l00843"></a>00843 <span class="comment">// =================================================================================================</span>
+<a name="l00844"></a>00844
+<a name="l00845"></a>00845 <span class="preprocessor">#endif // __TXMPUtils_hpp__</span>
+</pre></div><hr size="1"><address style="align: right;"><small>Generated on Thu May 3 14:54:57 2007 for Adobe XMP Toolkit by&nbsp;
+<a href="http://www.doxygen.org/index.html">
+<img src="doxygen.png" alt="doxygen" align="middle" border="0"></a> 1.5.1 </small></address>
+</body>
+</html>
diff --git a/docs/XMPToolkit/TXMPUtils_8hpp.html b/docs/XMPToolkit/TXMPUtils_8hpp.html
new file mode 100644
index 0000000..d0f1cea
--- /dev/null
+++ b/docs/XMPToolkit/TXMPUtils_8hpp.html
@@ -0,0 +1,33 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
+<title>Adobe XMP Toolkit: TXMPUtils.hpp File Reference</title>
+<link href="doxygen.css" rel="stylesheet" type="text/css">
+<link href="tabs.css" rel="stylesheet" type="text/css">
+</head><body>
+<!-- Generated by Doxygen 1.5.1 -->
+<div class="tabs">
+ <ul>
+ <li><a href="index.html"><span>Main&nbsp;Page</span></a></li>
+ <li><a href="modules.html"><span>Modules</span></a></li>
+ <li><a href="annotated.html"><span>Classes</span></a></li>
+ <li id="current"><a href="files.html"><span>Files</span></a></li>
+ </ul></div>
+<h1>TXMPUtils.hpp File Reference</h1>Template class for the XMP Toolkit utility services. <a href="#_details">More...</a>
+<p>
+
+<p>
+<a href="TXMPUtils_8hpp-source.html">Go to the source code of this file.</a><table border="0" cellpadding="0" cellspacing="0">
+<tr><td></td></tr>
+<tr><td colspan="2"><br><h2>Classes</h2></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">class &nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPUtils.html">TXMPUtils&lt; tStringObj &gt;</a></td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Template class for the XMP Toolkit utility services. <a href="classTXMPUtils.html#_details">More...</a><br></td></tr>
+</table>
+<hr><a name="_details"></a><h2>Detailed Description</h2>
+Template class for the XMP Toolkit utility services.
+<p>
+<code><a class="el" href="classTXMPUtils.html">TXMPUtils</a></code> is the template class providing utility services for the XMP Toolkit. It should be instantiated with a string class such as <code>std::string</code>. Please read the general toolkit usage notes for information about the overall architecture of the XMP API. <hr size="1"><address style="align: right;"><small>Generated on Thu May 3 14:54:58 2007 for Adobe XMP Toolkit by&nbsp;
+<a href="http://www.doxygen.org/index.html">
+<img src="doxygen.png" alt="doxygen" align="middle" border="0"></a> 1.5.1 </small></address>
+</body>
+</html>
diff --git a/docs/XMPToolkit/TXMPUtils_8incl__cpp.html b/docs/XMPToolkit/TXMPUtils_8incl__cpp.html
new file mode 100644
index 0000000..40480d0
--- /dev/null
+++ b/docs/XMPToolkit/TXMPUtils_8incl__cpp.html
@@ -0,0 +1,33 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
+<title>Adobe XMP Toolkit: TXMPUtils.incl_cpp File Reference</title>
+<link href="doxygen.css" rel="stylesheet" type="text/css">
+<link href="tabs.css" rel="stylesheet" type="text/css">
+</head><body>
+<!-- Generated by Doxygen 1.5.1 -->
+<div class="tabs">
+ <ul>
+ <li><a href="index.html"><span>Main&nbsp;Page</span></a></li>
+ <li><a href="modules.html"><span>Modules</span></a></li>
+ <li><a href="annotated.html"><span>Classes</span></a></li>
+ <li id="current"><a href="files.html"><span>Files</span></a></li>
+ </ul></div>
+<h1>TXMPUtils.incl_cpp File Reference</h1>The implementation of the <a class="el" href="classTXMPUtils.html">TXMPUtils</a> template class. <a href="#_details">More...</a>
+<p>
+<code>#include &quot;XMP.hpp&quot;</code><br>
+<code>#include &quot;client-glue/WXMP_Common.hpp&quot;</code><br>
+<code>#include &quot;client-glue/WXMPUtils.hpp&quot;</code><br>
+
+<p>
+Include dependency graph for TXMPUtils.incl_cpp:<p><center><img src="TXMPUtils_8incl__cpp__incl.png" border="0" usemap="#TXMPUtils.incl_cpp_map" alt=""></center>
+<table border="0" cellpadding="0" cellspacing="0">
+<tr><td></td></tr>
+</table>
+<hr><a name="_details"></a><h2>Detailed Description</h2>
+The implementation of the <a class="el" href="classTXMPUtils.html">TXMPUtils</a> template class.
+<p>
+<hr size="1"><address style="align: right;"><small>Generated on Thu May 3 14:54:58 2007 for Adobe XMP Toolkit by&nbsp;
+<a href="http://www.doxygen.org/index.html">
+<img src="doxygen.png" alt="doxygen" align="middle" border="0"></a> 1.5.1 </small></address>
+</body>
+</html>
diff --git a/docs/XMPToolkit/TXMPUtils_8incl__cpp__incl.png b/docs/XMPToolkit/TXMPUtils_8incl__cpp__incl.png
new file mode 100644
index 0000000..fc3f99c
--- /dev/null
+++ b/docs/XMPToolkit/TXMPUtils_8incl__cpp__incl.png
Binary files differ
diff --git a/docs/XMPToolkit/XMP_8incl__cpp.html b/docs/XMPToolkit/XMP_8incl__cpp.html
new file mode 100644
index 0000000..767a855
--- /dev/null
+++ b/docs/XMPToolkit/XMP_8incl__cpp.html
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
+<title>Adobe XMP Toolkit: XMP.incl_cpp File Reference</title>
+<link href="doxygen.css" rel="stylesheet" type="text/css">
+<link href="tabs.css" rel="stylesheet" type="text/css">
+</head><body>
+<!-- Generated by Doxygen 1.5.1 -->
+<div class="tabs">
+ <ul>
+ <li><a href="index.html"><span>Main&nbsp;Page</span></a></li>
+ <li><a href="modules.html"><span>Modules</span></a></li>
+ <li><a href="annotated.html"><span>Classes</span></a></li>
+ <li id="current"><a href="files.html"><span>Files</span></a></li>
+ </ul></div>
+<h1>XMP.incl_cpp File Reference</h1>Overall client glue file for the XMP toolkit. <a href="#_details">More...</a>
+<p>
+<code>#include &quot;XMP.hpp&quot;</code><br>
+
+<p>
+Include dependency graph for XMP.incl_cpp:<p><center><img src="XMP_8incl__cpp__incl.png" border="0" usemap="#XMP.incl_cpp_map" alt=""></center>
+<table border="0" cellpadding="0" cellspacing="0">
+<tr><td></td></tr>
+</table>
+<hr><a name="_details"></a><h2>Detailed Description</h2>
+Overall client glue file for the XMP toolkit.
+<p>
+This is an overall client source file of XMP toolkit glue, the only XMP-specific one that clients should build in projects. This ensures that all of the client-side glue code for the XMP toolkit gets compiled.<p>
+You cannot compile this file directly, because the template's string type must be declared and only the client can do that. Instead, include this in some other source file. For example, to use <code>std::string</code> you only need these two lines:<p>
+<div class="fragment"><pre class="fragment"><span class="preprocessor"> #include &lt;string&gt;</span>
+<span class="preprocessor"> #include "<a class="code" href="XMP_8incl__cpp.html">XMP.incl_cpp</a>"</span>
+</pre></div> <hr size="1"><address style="align: right;"><small>Generated on Thu May 3 14:54:58 2007 for Adobe XMP Toolkit by&nbsp;
+<a href="http://www.doxygen.org/index.html">
+<img src="doxygen.png" alt="doxygen" align="middle" border="0"></a> 1.5.1 </small></address>
+</body>
+</html>
diff --git a/docs/XMPToolkit/XMP_8incl__cpp__incl.png b/docs/XMPToolkit/XMP_8incl__cpp__incl.png
new file mode 100644
index 0000000..26f5616
--- /dev/null
+++ b/docs/XMPToolkit/XMP_8incl__cpp__incl.png
Binary files differ
diff --git a/docs/XMPToolkit/XMP__Const_8h-source.html b/docs/XMPToolkit/XMP__Const_8h-source.html
new file mode 100644
index 0000000..be0823f
--- /dev/null
+++ b/docs/XMPToolkit/XMP__Const_8h-source.html
@@ -0,0 +1,661 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
+<title>Adobe XMP Toolkit: XMP_Const.h Source File</title>
+<link href="doxygen.css" rel="stylesheet" type="text/css">
+<link href="tabs.css" rel="stylesheet" type="text/css">
+</head><body>
+<!-- Generated by Doxygen 1.5.1 -->
+<div class="tabs">
+ <ul>
+ <li><a href="index.html"><span>Main&nbsp;Page</span></a></li>
+ <li><a href="modules.html"><span>Modules</span></a></li>
+ <li><a href="annotated.html"><span>Classes</span></a></li>
+ <li id="current"><a href="files.html"><span>Files</span></a></li>
+ </ul></div>
+<h1>XMP_Const.h</h1><a href="XMP__Const_8h.html">Go to the documentation of this file.</a><div class="fragment"><pre class="fragment"><a name="l00001"></a>00001 <span class="preprocessor">#ifndef __XMP_Const_h__</span>
+<a name="l00002"></a>00002 <span class="preprocessor"></span><span class="preprocessor">#define __XMP_Const_h__ 1</span>
+<a name="l00003"></a>00003 <span class="preprocessor"></span>
+<a name="l00004"></a>00004 <span class="comment">/* --------------------------------------------------------------------------------------------- */</span>
+<a name="l00005"></a>00005 <span class="comment">/* ** IMPORTANT ** This file must be usable by strict ANSI C compilers. No "//" comments, etc. */</span>
+<a name="l00006"></a>00006 <span class="comment">/* --------------------------------------------------------------------------------------------- */</span>
+<a name="l00007"></a>00007
+<a name="l00008"></a>00008 <span class="comment">/*</span>
+<a name="l00009"></a>00009 <span class="comment">// =================================================================================================</span>
+<a name="l00010"></a>00010 <span class="comment">// Copyright 2002-2007 Adobe Systems Incorporated</span>
+<a name="l00011"></a>00011 <span class="comment">// All Rights Reserved.</span>
+<a name="l00012"></a>00012 <span class="comment">//</span>
+<a name="l00013"></a>00013 <span class="comment">// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms</span>
+<a name="l00014"></a>00014 <span class="comment">// of the Adobe license agreement accompanying it.</span>
+<a name="l00015"></a>00015 <span class="comment">// =================================================================================================</span>
+<a name="l00016"></a>00016 <span class="comment">*/</span>
+<a name="l00017"></a>00017
+<a name="l00018"></a>00018 <span class="preprocessor">#include "XMP_Environment.h"</span>
+<a name="l00019"></a>00019
+<a name="l00020"></a>00020 <span class="preprocessor"> #include &lt;stddef.h&gt;</span>
+<a name="l00021"></a>00021
+<a name="l00022"></a>00022 <span class="preprocessor">#if XMP_MacBuild </span><span class="comment">/* ! No stdint.h on Windows and some UNIXes. */</span>
+<a name="l00023"></a>00023 <span class="preprocessor"> #include &lt;stdint.h&gt;</span>
+<a name="l00024"></a>00024 <span class="preprocessor">#endif</span>
+<a name="l00025"></a>00025 <span class="preprocessor"></span>
+<a name="l00026"></a>00026 <span class="preprocessor">#if __cplusplus</span>
+<a name="l00027"></a>00027 <span class="preprocessor"></span><span class="keyword">extern</span> <span class="stringliteral">"C"</span> {
+<a name="l00028"></a>00028 <span class="preprocessor">#endif</span>
+<a name="l00029"></a>00029 <span class="preprocessor"></span>
+<a name="l00030"></a>00030
+<a name="l00037"></a>00037 <span class="comment">/* ============================================================================================== */</span>
+<a name="l00038"></a>00038 <span class="comment">/* Basic types and constants */</span>
+<a name="l00039"></a>00039 <span class="comment">/* ========================= */</span>
+<a name="l00040"></a>00040
+<a name="l00041"></a>00041 <span class="comment">/* The XMP_... types are used on the off chance that the ..._t types present a problem. In that */</span>
+<a name="l00042"></a>00042 <span class="comment">/* case only the declarations of the XMP_... types needs to change, not all of the uses. These */</span>
+<a name="l00043"></a>00043 <span class="comment">/* types are used where fixed sizes are required in order to have a known ABI for a DLL build. */</span>
+<a name="l00044"></a>00044
+<a name="l00045"></a>00045 <span class="preprocessor">#if XMP_MacBuild</span>
+<a name="l00046"></a>00046 <span class="preprocessor"></span>
+<a name="l00047"></a>00047 <span class="keyword">typedef</span> int8_t XMP_Int8;
+<a name="l00048"></a>00048 <span class="keyword">typedef</span> int16_t XMP_Int16;
+<a name="l00049"></a>00049 <span class="keyword">typedef</span> int32_t XMP_Int32;
+<a name="l00050"></a>00050 <span class="keyword">typedef</span> int64_t XMP_Int64;
+<a name="l00051"></a>00051
+<a name="l00052"></a>00052 <span class="keyword">typedef</span> uint8_t XMP_Uns8;
+<a name="l00053"></a>00053 <span class="keyword">typedef</span> uint16_t XMP_Uns16;
+<a name="l00054"></a>00054 <span class="keyword">typedef</span> uint32_t XMP_Uns32;
+<a name="l00055"></a>00055 <span class="keyword">typedef</span> uint64_t XMP_Uns64;
+<a name="l00056"></a>00056
+<a name="l00057"></a>00057 <span class="preprocessor">#else</span>
+<a name="l00058"></a>00058 <span class="preprocessor"></span>
+<a name="l00059"></a>00059 <span class="keyword">typedef</span> <span class="keywordtype">signed</span> <span class="keywordtype">char</span> XMP_Int8;
+<a name="l00060"></a>00060 <span class="keyword">typedef</span> <span class="keywordtype">signed</span> <span class="keywordtype">short</span> XMP_Int16;
+<a name="l00061"></a>00061 <span class="keyword">typedef</span> <span class="keywordtype">signed</span> <span class="keywordtype">long</span> XMP_Int32;
+<a name="l00062"></a>00062 <span class="keyword">typedef</span> <span class="keywordtype">signed</span> <span class="keywordtype">long</span> <span class="keywordtype">long</span> XMP_Int64;
+<a name="l00063"></a>00063
+<a name="l00064"></a>00064 <span class="keyword">typedef</span> <span class="keywordtype">unsigned</span> <span class="keywordtype">char</span> XMP_Uns8;
+<a name="l00065"></a>00065 <span class="keyword">typedef</span> <span class="keywordtype">unsigned</span> <span class="keywordtype">short</span> XMP_Uns16;
+<a name="l00066"></a>00066 <span class="keyword">typedef</span> <span class="keywordtype">unsigned</span> <span class="keywordtype">long</span> XMP_Uns32;
+<a name="l00067"></a>00067 <span class="keyword">typedef</span> <span class="keywordtype">unsigned</span> <span class="keywordtype">long</span> <span class="keywordtype">long</span> XMP_Uns64;
+<a name="l00068"></a>00068
+<a name="l00069"></a>00069 <span class="preprocessor">#endif</span>
+<a name="l00070"></a>00070 <span class="preprocessor"></span>
+<a name="l00071"></a>00071 <span class="keyword">typedef</span> XMP_Uns8 XMP_Bool;
+<a name="l00072"></a>00072
+<a name="l00073"></a>00073 <span class="comment">/* Typedefs to preserve old, unfortunate spellings: */</span>
+<a name="l00074"></a>00074
+<a name="l00075"></a>00075 <span class="preprocessor">#if 0 </span><span class="comment">/* *** Enable after internal compiles work. */</span>
+<a name="l00076"></a>00076 <span class="keyword">typedef</span> XMP_Int8 XMPInt8;
+<a name="l00077"></a>00077 <span class="keyword">typedef</span> XMP_Int16 XMPInt16;
+<a name="l00078"></a>00078 <span class="keyword">typedef</span> XMP_Int32 XMPInt32;
+<a name="l00079"></a>00079 <span class="keyword">typedef</span> XMP_Int64 XMPInt64;
+<a name="l00080"></a>00080 <span class="keyword">typedef</span> XMP_Uns8 XMPUns8;
+<a name="l00081"></a>00081 <span class="keyword">typedef</span> XMP_Uns16 XMPUns16;
+<a name="l00082"></a>00082 <span class="keyword">typedef</span> XMP_Uns32 XMPUns32;
+<a name="l00083"></a>00083 <span class="keyword">typedef</span> XMP_Uns64 XMPUns64;
+<a name="l00084"></a>00084 <span class="keyword">typedef</span> XMP_Bool XMPBool;
+<a name="l00085"></a>00085 <span class="preprocessor">#endif</span>
+<a name="l00086"></a>00086 <span class="preprocessor"></span>
+<a name="l00095"></a><a class="code" href="XMP__Const_8h.html#5912613564f80e17eb10acef9236f70a">00095</a> <span class="keyword">typedef</span> <span class="keyword">struct </span>__XMPMeta__ * <a class="code" href="XMP__Const_8h.html#5912613564f80e17eb10acef9236f70a">XMPMetaRef</a>;
+<a name="l00096"></a>00096 <span class="keyword">typedef</span> <span class="keyword">struct </span>__XMPIterator__ * XMPIteratorRef;
+<a name="l00097"></a>00097 <span class="keyword">typedef</span> <span class="keyword">struct </span>__XMPFiles__ * XMPFilesRef;
+<a name="l00098"></a>00098
+<a name="l00099"></a>00099 <span class="comment">/* ============================================================================================== */</span>
+<a name="l00100"></a>00100
+<a name="l00132"></a><a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">00132</a> <span class="keyword">typedef</span> <span class="keyword">const</span> <span class="keywordtype">char</span> * <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>; <span class="comment">/* Points to a null terminated UTF-8 string. */</span>
+<a name="l00133"></a><a class="code" href="XMP__Const_8h.html#9f7dcc184f901c713274edfdac5bcc9a">00133</a> <span class="keyword">typedef</span> XMP_Uns32 <a class="code" href="XMP__Const_8h.html#9f7dcc184f901c713274edfdac5bcc9a">XMP_StringLen</a>;
+<a name="l00134"></a><a class="code" href="XMP__Const_8h.html#00e9d9a76c144421105a4c2742203315">00134</a> <span class="keyword">typedef</span> XMP_Int32 <a class="code" href="XMP__Const_8h.html#00e9d9a76c144421105a4c2742203315">XMP_Index</a>; <span class="comment">/* Signed, sometimes -1 is handy. */</span>
+<a name="l00135"></a><a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">00135</a> <span class="keyword">typedef</span> XMP_Uns32 <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a>; <span class="comment">/* Used as 32 individual bits. */</span>
+<a name="l00136"></a>00136
+<a name="l00149"></a><a class="code" href="XMP__Const_8h.html#4c39e0131b0e3d7db66e1cfa82b67141">00149</a> <span class="preprocessor">#define kXMP_TrueStr "True" </span><span class="comment">/* Serialized XMP spellings, not for the type bool. */</span>
+<a name="l00150"></a><a class="code" href="XMP__Const_8h.html#2dc55b533ed63ed7ff0c3be16a97e278">00150</a> <span class="preprocessor">#define kXMP_FalseStr "False"</span>
+<a name="l00151"></a>00151 <span class="preprocessor"></span>
+<a name="l00156"></a>00156 <span class="comment">/* ============================================================================================== */</span>
+<a name="l00157"></a>00157
+<a name="l00190"></a><a class="code" href="structXMP__DateTime.html">00190</a> <span class="keyword">struct </span><a class="code" href="structXMP__DateTime.html">XMP_DateTime</a> {
+<a name="l00191"></a>00191 XMP_Int32 year;
+<a name="l00192"></a>00192 XMP_Int32 month; <span class="comment">/* 1..12 */</span>
+<a name="l00193"></a>00193 XMP_Int32 day; <span class="comment">/* 1..31 */</span>
+<a name="l00194"></a>00194 XMP_Int32 hour; <span class="comment">/* 0..23 */</span>
+<a name="l00195"></a>00195 XMP_Int32 minute; <span class="comment">/* 0..59 */</span>
+<a name="l00196"></a>00196 XMP_Int32 second; <span class="comment">/* 0..59 */</span>
+<a name="l00197"></a>00197 XMP_Int32 tzSign; <span class="comment">/* -1..+1, 0 means UTC, -1 is west, +1 is east. */</span>
+<a name="l00198"></a>00198 XMP_Int32 tzHour; <span class="comment">/* 0..23 */</span>
+<a name="l00199"></a>00199 XMP_Int32 tzMinute; <span class="comment">/* 0..59 */</span>
+<a name="l00200"></a>00200 XMP_Int32 nanoSecond;
+<a name="l00201"></a>00201 };
+<a name="l00202"></a>00202
+<a name="l00203"></a>00203 <span class="keyword">enum</span> { <span class="comment">/* Values used for tzSign field. */</span>
+<a name="l00204"></a>00204 kXMP_TimeWestOfUTC = -1,
+<a name="l00205"></a>00205 kXMP_TimeIsUTC = 0,
+<a name="l00206"></a>00206 kXMP_TimeEastOfUTC = +1
+<a name="l00207"></a>00207 };
+<a name="l00208"></a>00208
+<a name="l00209"></a>00209
+<a name="l00210"></a>00210 <span class="comment">/* ============================================================================================== */</span>
+<a name="l00211"></a>00211 <span class="comment">/* Standard namespace URI constants */</span>
+<a name="l00212"></a>00212 <span class="comment">/* ================================ */</span>
+<a name="l00213"></a>00213
+<a name="l00273"></a><a class="code" href="XMP__Const_8h.html#030875c9dc0861c9251a3374ca14a376">00273</a> <span class="preprocessor">#define kXMP_NS_XMP "http://ns.adobe.com/xap/1.0/"</span>
+<a name="l00274"></a>00274 <span class="preprocessor"></span>
+<a name="l00275"></a><a class="code" href="XMP__Const_8h.html#e52d761e5a4fc8c8499215d2f3d82b90">00275</a> <span class="preprocessor">#define kXMP_NS_XMP_Rights "http://ns.adobe.com/xap/1.0/rights/"</span>
+<a name="l00276"></a><a class="code" href="XMP__Const_8h.html#c67379a9ffa425d0d7976a51c4f2f754">00276</a> <span class="preprocessor"></span><span class="preprocessor">#define kXMP_NS_XMP_MM "http://ns.adobe.com/xap/1.0/mm/"</span>
+<a name="l00277"></a><a class="code" href="XMP__Const_8h.html#308e156c325618acb2172e550929ebee">00277</a> <span class="preprocessor"></span><span class="preprocessor">#define kXMP_NS_XMP_BJ "http://ns.adobe.com/xap/1.0/bj/"</span>
+<a name="l00278"></a>00278 <span class="preprocessor"></span>
+<a name="l00279"></a><a class="code" href="XMP__Const_8h.html#0bcb67d0dd0922504e3da7ca5c40c82a">00279</a> <span class="preprocessor">#define kXMP_NS_PDF "http://ns.adobe.com/pdf/1.3/"</span>
+<a name="l00280"></a><a class="code" href="XMP__Const_8h.html#a1a6f38ebfcdb281c5bf2809859167c7">00280</a> <span class="preprocessor"></span><span class="preprocessor">#define kXMP_NS_Photoshop "http://ns.adobe.com/photoshop/1.0/"</span>
+<a name="l00281"></a>00281 <span class="preprocessor"></span><span class="preprocessor">#define kXMP_NS_PSAlbum "http://ns.adobe.com/album/1.0/"</span>
+<a name="l00282"></a><a class="code" href="XMP__Const_8h.html#d12182e1df1652f56b5eec60c1fcdd8f">00282</a> <span class="preprocessor"></span><span class="preprocessor">#define kXMP_NS_EXIF "http://ns.adobe.com/exif/1.0/"</span>
+<a name="l00283"></a>00283 <span class="preprocessor"></span><span class="preprocessor">#define kXMP_NS_EXIF_Aux "http://ns.adobe.com/exif/1.0/aux/"</span>
+<a name="l00284"></a><a class="code" href="XMP__Const_8h.html#673355818b7b9224e8fec0fbc60ba00c">00284</a> <span class="preprocessor"></span><span class="preprocessor">#define kXMP_NS_TIFF "http://ns.adobe.com/tiff/1.0/"</span>
+<a name="l00285"></a>00285 <span class="preprocessor"></span><span class="preprocessor">#define kXMP_NS_PNG "http://ns.adobe.com/png/1.0/"</span>
+<a name="l00286"></a>00286 <span class="preprocessor"></span><span class="preprocessor">#define kXMP_NS_SWF "http://ns.adobe.com/swf/1.0/"</span>
+<a name="l00287"></a>00287 <span class="preprocessor"></span><span class="preprocessor">#define kXMP_NS_JPEG "http://ns.adobe.com/jpeg/1.0/"</span>
+<a name="l00288"></a>00288 <span class="preprocessor"></span><span class="preprocessor">#define kXMP_NS_JP2K "http://ns.adobe.com/jp2k/1.0/"</span>
+<a name="l00289"></a>00289 <span class="preprocessor"></span><span class="preprocessor">#define kXMP_NS_CameraRaw "http://ns.adobe.com/camera-raw-settings/1.0/"</span>
+<a name="l00290"></a>00290 <span class="preprocessor"></span><span class="preprocessor">#define kXMP_NS_DM "http://ns.adobe.com/xmp/1.0/DynamicMedia/"</span>
+<a name="l00291"></a>00291 <span class="preprocessor"></span><span class="preprocessor">#define kXMP_NS_ASF "http://ns.adobe.com/asf/1.0/"</span>
+<a name="l00292"></a>00292 <span class="preprocessor"></span><span class="preprocessor">#define kXMP_NS_WAV "http://ns.adobe.com/xmp/wav/1.0/"</span>
+<a name="l00293"></a>00293 <span class="preprocessor"></span>
+<a name="l00294"></a>00294 <span class="preprocessor">#define kXMP_NS_XMP_Note "http://ns.adobe.com/xmp/note/"</span>
+<a name="l00295"></a>00295 <span class="preprocessor"></span>
+<a name="l00296"></a>00296 <span class="preprocessor">#define kXMP_NS_AdobeStockPhoto "http://ns.adobe.com/StockPhoto/1.0/"</span>
+<a name="l00297"></a>00297 <span class="preprocessor"></span>
+<a name="l00342"></a><a class="code" href="XMP__Const_8h.html#b466db52a4b85cecfa04710682c1e671">00342</a> <span class="preprocessor">#define kXMP_NS_XMP_IdentifierQual "http://ns.adobe.com/xmp/Identifier/qual/1.0/"</span>
+<a name="l00343"></a><a class="code" href="XMP__Const_8h.html#9618e013619aa92ebc808b62243d2ba8">00343</a> <span class="preprocessor"></span><span class="preprocessor">#define kXMP_NS_XMP_Dimensions "http://ns.adobe.com/xap/1.0/sType/Dimensions#"</span>
+<a name="l00344"></a>00344 <span class="preprocessor"></span><span class="preprocessor">#define kXMP_NS_XMP_Text "http://ns.adobe.com/xap/1.0/t/"</span>
+<a name="l00345"></a>00345 <span class="preprocessor"></span><span class="preprocessor">#define kXMP_NS_XMP_PagedFile "http://ns.adobe.com/xap/1.0/t/pg/"</span>
+<a name="l00346"></a>00346 <span class="preprocessor"></span><span class="preprocessor">#define kXMP_NS_XMP_Graphics "http://ns.adobe.com/xap/1.0/g/"</span>
+<a name="l00347"></a><a class="code" href="XMP__Const_8h.html#935641acc7d01e782ad7a457a7ff338b">00347</a> <span class="preprocessor"></span><span class="preprocessor">#define kXMP_NS_XMP_Image "http://ns.adobe.com/xap/1.0/g/img/"</span>
+<a name="l00348"></a>00348 <span class="preprocessor"></span><span class="preprocessor">#define kXMP_NS_XMP_Font "http://ns.adobe.com/xap/1.0/sType/Font#"</span>
+<a name="l00349"></a><a class="code" href="XMP__Const_8h.html#861613273127156050b456eee11f6b0a">00349</a> <span class="preprocessor"></span><span class="preprocessor">#define kXMP_NS_XMP_ResourceEvent "http://ns.adobe.com/xap/1.0/sType/ResourceEvent#"</span>
+<a name="l00350"></a><a class="code" href="XMP__Const_8h.html#9bf51f2653400645f7b5087e8c4e1c77">00350</a> <span class="preprocessor"></span><span class="preprocessor">#define kXMP_NS_XMP_ResourceRef "http://ns.adobe.com/xap/1.0/sType/ResourceRef#"</span>
+<a name="l00351"></a><a class="code" href="XMP__Const_8h.html#b4923bed71ab29c6aa88debe8816c0a2">00351</a> <span class="preprocessor"></span><span class="preprocessor">#define kXMP_NS_XMP_ST_Version "http://ns.adobe.com/xap/1.0/sType/Version#"</span>
+<a name="l00352"></a><a class="code" href="XMP__Const_8h.html#c7dc4d65bcbba2862e410cc8cfdff6f6">00352</a> <span class="preprocessor"></span><span class="preprocessor">#define kXMP_NS_XMP_ST_Job "http://ns.adobe.com/xap/1.0/sType/Job#"</span>
+<a name="l00353"></a>00353 <span class="preprocessor"></span><span class="preprocessor">#define kXMP_NS_XMP_ManifestItem "http://ns.adobe.com/xap/1.0/sType/ManifestItem#"</span>
+<a name="l00354"></a>00354 <span class="preprocessor"></span>
+<a name="l00355"></a>00355 <span class="comment">/* Deprecated constant names */</span>
+<a name="l00356"></a><a class="code" href="XMP__Const_8h.html#0a2d9c5f7beb27553214a7ad1df4f27e">00356</a> <span class="preprocessor">#define kXMP_NS_XMP_T "http://ns.adobe.com/xap/1.0/t/"</span>
+<a name="l00357"></a><a class="code" href="XMP__Const_8h.html#39afb495ffb24bb3082493c6811e65d0">00357</a> <span class="preprocessor"></span><span class="preprocessor">#define kXMP_NS_XMP_T_PG "http://ns.adobe.com/xap/1.0/t/pg/"</span>
+<a name="l00358"></a>00358 <span class="preprocessor"></span><span class="preprocessor">#define kXMP_NS_XMP_G_IMG "http://ns.adobe.com/xap/1.0/g/img/"</span>
+<a name="l00359"></a>00359 <span class="preprocessor"></span>
+<a name="l00389"></a><a class="code" href="XMP__Const_8h.html#44453f0d0a1dd295d41722c2387b36fa">00389</a> <span class="preprocessor">#define kXMP_NS_DC "http://purl.org/dc/elements/1.1/"</span>
+<a name="l00390"></a>00390 <span class="preprocessor"></span>
+<a name="l00391"></a><a class="code" href="XMP__Const_8h.html#b794d3d798daf75a963398347dcbb79b">00391</a> <span class="preprocessor">#define kXMP_NS_IPTCCore "http://iptc.org/std/Iptc4xmpCore/1.0/xmlns/"</span>
+<a name="l00392"></a>00392 <span class="preprocessor"></span>
+<a name="l00393"></a>00393 <span class="preprocessor">#define kXMP_NS_PDFA_Schema "http://www.aiim.org/pdfa/ns/schema#"</span>
+<a name="l00394"></a>00394 <span class="preprocessor"></span><span class="preprocessor">#define kXMP_NS_PDFA_Property "http://www.aiim.org/pdfa/ns/property#"</span>
+<a name="l00395"></a>00395 <span class="preprocessor"></span><span class="preprocessor">#define kXMP_NS_PDFA_Type "http://www.aiim.org/pdfa/ns/type#"</span>
+<a name="l00396"></a>00396 <span class="preprocessor"></span><span class="preprocessor">#define kXMP_NS_PDFA_Field "http://www.aiim.org/pdfa/ns/field#"</span>
+<a name="l00397"></a>00397 <span class="preprocessor"></span><span class="preprocessor">#define kXMP_NS_PDFA_ID "http://www.aiim.org/pdfa/ns/id/"</span>
+<a name="l00398"></a>00398 <span class="preprocessor"></span><span class="preprocessor">#define kXMP_NS_PDFA_Extension "http://www.aiim.org/pdfa/ns/extension/"</span>
+<a name="l00399"></a>00399 <span class="preprocessor"></span>
+<a name="l00400"></a>00400 <span class="preprocessor">#define kXMP_NS_PDFX "http://ns.adobe.com/pdfx/1.3/"</span>
+<a name="l00401"></a>00401 <span class="preprocessor"></span><span class="preprocessor">#define kXMP_NS_PDFX_ID "http://www.npes.org/pdfx/ns/id/"</span>
+<a name="l00402"></a>00402 <span class="preprocessor"></span>
+<a name="l00403"></a><a class="code" href="XMP__Const_8h.html#276fac0f70893607afa3f09030ad84c7">00403</a> <span class="preprocessor">#define kXMP_NS_RDF "http://www.w3.org/1999/02/22-rdf-syntax-ns#"</span>
+<a name="l00404"></a><a class="code" href="XMP__Const_8h.html#97564c70460d1f235c8a41b8ac40cfe9">00404</a> <span class="preprocessor"></span><span class="preprocessor">#define kXMP_NS_XML "http://www.w3.org/XML/1998/namespace"</span>
+<a name="l00405"></a>00405 <span class="preprocessor"></span>
+<a name="l00406"></a>00406
+<a name="l00407"></a>00407 <span class="comment">/* ============================================================================================== */</span>
+<a name="l00408"></a>00408 <span class="comment">/* Enums and macros used for option bits */</span>
+<a name="l00409"></a>00409 <span class="comment">/* ===================================== */</span>
+<a name="l00410"></a>00410
+<a name="l00411"></a>00411 <span class="preprocessor">#define kXMP_ArrayLastItem ((XMP_Index)(-1L))</span>
+<a name="l00412"></a>00412 <span class="preprocessor"></span><span class="preprocessor">#define kXMP_UseNullTermination ((XMP_StringLen)(~0UL))</span>
+<a name="l00413"></a>00413 <span class="preprocessor"></span>
+<a name="l00414"></a>00414 <span class="preprocessor">#define kXMP_NoOptions ((XMP_OptionBits)0UL)</span>
+<a name="l00415"></a>00415 <span class="preprocessor"></span>
+<a name="l00416"></a>00416 <span class="preprocessor">#define XMP_SetOption(var,opt) var |= (opt)</span>
+<a name="l00417"></a>00417 <span class="preprocessor"></span><span class="preprocessor">#define XMP_ClearOption(var,opt) var &amp;= ~(opt)</span>
+<a name="l00418"></a>00418 <span class="preprocessor"></span><span class="preprocessor">#define XMP_TestOption(var,opt) (((var) &amp; (opt)) != 0)</span>
+<a name="l00419"></a>00419 <span class="preprocessor"></span><span class="preprocessor">#define XMP_OptionIsSet(var,opt) (((var) &amp; (opt)) != 0)</span>
+<a name="l00420"></a>00420 <span class="preprocessor"></span><span class="preprocessor">#define XMP_OptionIsClear(var,opt) (((var) &amp; (opt)) == 0)</span>
+<a name="l00421"></a>00421 <span class="preprocessor"></span>
+<a name="l00422"></a>00422 <span class="preprocessor">#define XMP_PropIsSimple(opt) (((opt) &amp; kXMP_PropCompositeMask) == 0)</span>
+<a name="l00423"></a>00423 <span class="preprocessor"></span><span class="preprocessor">#define XMP_PropIsStruct(opt) (((opt) &amp; kXMP_PropValueIsStruct) != 0)</span>
+<a name="l00424"></a>00424 <span class="preprocessor"></span><span class="preprocessor">#define XMP_PropIsArray(opt) (((opt) &amp; kXMP_PropValueIsArray) != 0)</span>
+<a name="l00425"></a>00425 <span class="preprocessor"></span><span class="preprocessor">#define XMP_ArrayIsUnordered(opt) (((opt) &amp; kXMP_PropArrayIsOrdered) == 0)</span>
+<a name="l00426"></a>00426 <span class="preprocessor"></span><span class="preprocessor">#define XMP_ArrayIsOrdered(opt) (((opt) &amp; kXMP_PropArrayIsOrdered) != 0)</span>
+<a name="l00427"></a>00427 <span class="preprocessor"></span><span class="preprocessor">#define XMP_ArrayIsAlternate(opt) (((opt) &amp; kXMP_PropArrayIsAlternate) != 0)</span>
+<a name="l00428"></a>00428 <span class="preprocessor"></span><span class="preprocessor">#define XMP_ArrayIsAltText(opt) (((opt) &amp; kXMP_PropArrayIsAltText) != 0)</span>
+<a name="l00429"></a>00429 <span class="preprocessor"></span>
+<a name="l00430"></a>00430 <span class="preprocessor">#define XMP_PropHasQualifiers(opt) (((opt) &amp; kXMP_PropHasQualifiers) != 0)</span>
+<a name="l00431"></a>00431 <span class="preprocessor"></span><span class="preprocessor">#define XMP_PropIsQualifier(opt) (((opt) &amp; kXMP_PropIsQualifier) != 0)</span>
+<a name="l00432"></a>00432 <span class="preprocessor"></span><span class="preprocessor">#define XMP_PropHasLang(opt) (((opt) &amp; kXMP_PropHasLang) != 0)</span>
+<a name="l00433"></a>00433 <span class="preprocessor"></span>
+<a name="l00434"></a>00434 <span class="preprocessor">#define XMP_NodeIsSchema(opt) (((opt) &amp; kXMP_SchemaNode) != 0)</span>
+<a name="l00435"></a>00435 <span class="preprocessor"></span><span class="preprocessor">#define XMP_PropIsAlias(opt) (((opt) &amp; kXMP_PropIsAlias) != 0)</span>
+<a name="l00436"></a>00436 <span class="preprocessor"></span>
+<a name="l00437"></a>00437 <span class="comment">/* ---------------------------------------------------------------------------------------------- */</span>
+<a name="l00438"></a>00438
+<a name="l00439"></a>00439 <span class="keyword">enum</span> { <span class="comment">/* Option bits returned from the TXMPMeta::GetXyz functions. */</span>
+<a name="l00440"></a>00440
+<a name="l00441"></a>00441 <span class="comment">/* Options relating to the XML string form of the property value. */</span>
+<a name="l00442"></a>00442 kXMP_PropValueIsURI = 0x00000002UL, <span class="comment">/* The value is a URI, use rdf:resource attribute. DISCOURAGED */</span>
+<a name="l00443"></a>00443
+<a name="l00444"></a>00444 <span class="comment">/* Options relating to qualifiers attached to a property. */</span>
+<a name="l00445"></a>00445 kXMP_PropHasQualifiers = 0x00000010UL, <span class="comment">/* The property has qualifiers, includes rdf:type and xml:lang. */</span>
+<a name="l00446"></a>00446 kXMP_PropIsQualifier = 0x00000020UL, <span class="comment">/* This is a qualifier, includes rdf:type and xml:lang. */</span>
+<a name="l00447"></a>00447 kXMP_PropHasLang = 0x00000040UL, <span class="comment">/* Implies kXMP_PropHasQualifiers, property has xml:lang. */</span>
+<a name="l00448"></a>00448 kXMP_PropHasType = 0x00000080UL, <span class="comment">/* Implies kXMP_PropHasQualifiers, property has rdf:type. */</span>
+<a name="l00449"></a>00449
+<a name="l00450"></a>00450 <span class="comment">/* Options relating to the data structure form. */</span>
+<a name="l00451"></a>00451 kXMP_PropValueIsStruct = 0x00000100UL, <span class="comment">/* The value is a structure with nested fields. */</span>
+<a name="l00452"></a>00452 kXMP_PropValueIsArray = 0x00000200UL, <span class="comment">/* The value is an array (RDF alt/bag/seq). */</span>
+<a name="l00453"></a>00453 kXMP_PropArrayIsUnordered = kXMP_PropValueIsArray, <span class="comment">/* The item order does not matter. */</span>
+<a name="l00454"></a>00454 kXMP_PropArrayIsOrdered = 0x00000400UL, <span class="comment">/* Implies kXMP_PropValueIsArray, item order matters. */</span>
+<a name="l00455"></a>00455 kXMP_PropArrayIsAlternate = 0x00000800UL, <span class="comment">/* Implies kXMP_PropArrayIsOrdered, items are alternates. */</span>
+<a name="l00456"></a>00456
+<a name="l00457"></a>00457 <span class="comment">/* Additional struct and array options. */</span>
+<a name="l00458"></a>00458 kXMP_PropArrayIsAltText = 0x00001000UL, <span class="comment">/* Implies kXMP_PropArrayIsAlternate, items are localized text. */</span>
+<a name="l00459"></a>00459 <span class="comment">/* kXMP_InsertBeforeItem = 0x00004000UL, ! Used by SetXyz functions. */</span>
+<a name="l00460"></a>00460 <span class="comment">/* kXMP_InsertAfterItem = 0x00008000UL, ! Used by SetXyz functions. */</span>
+<a name="l00461"></a>00461
+<a name="l00462"></a>00462 <span class="comment">/* Other miscellaneous options. */</span>
+<a name="l00463"></a>00463 kXMP_PropIsAlias = 0x00010000UL, <span class="comment">/* This property is an alias name for another property. */</span>
+<a name="l00464"></a>00464 kXMP_PropHasAliases = 0x00020000UL, <span class="comment">/* This property is the base value for a set of aliases. */</span>
+<a name="l00465"></a>00465 kXMP_PropIsInternal = 0x00040000UL, <span class="comment">/* This property is an "internal" property, owned by applications. */</span>
+<a name="l00466"></a>00466 kXMP_PropIsStable = 0x00100000UL, <span class="comment">/* This property is not derived from the document content. */</span>
+<a name="l00467"></a>00467 kXMP_PropIsDerived = 0x00200000UL, <span class="comment">/* This property is derived from the document content. */</span>
+<a name="l00468"></a>00468 <span class="comment">/* kXMPUtil_AllowCommas = 0x10000000UL, ! Used by TXMPUtils::CatenateArrayItems and ::SeparateArrayItems. */</span>
+<a name="l00469"></a>00469 <span class="comment">/* kXMP_DeleteExisting = 0x20000000UL, ! Used by TXMPMeta::SetXyz functions to delete any pre-existing property. */</span>
+<a name="l00470"></a>00470 <span class="comment">/* kXMP_SchemaNode = 0x80000000UL, ! Returned by iterators - #define to avoid warnings */</span>
+<a name="l00471"></a>00471
+<a name="l00472"></a>00472 <span class="comment">/* Masks that are multiple flags. */</span>
+<a name="l00473"></a>00473 kXMP_PropArrayFormMask = kXMP_PropValueIsArray | kXMP_PropArrayIsOrdered | kXMP_PropArrayIsAlternate | kXMP_PropArrayIsAltText,
+<a name="l00474"></a>00474 kXMP_PropCompositeMask = kXMP_PropValueIsStruct | kXMP_PropArrayFormMask, <span class="comment">/* Is it simple or composite (array or struct)? */</span>
+<a name="l00475"></a>00475 kXMP_ImplReservedMask = 0x70000000L <span class="comment">/* Reserved for transient use by the implementation. */</span>
+<a name="l00476"></a>00476 };
+<a name="l00477"></a>00477
+<a name="l00478"></a>00478 <span class="preprocessor">#define kXMP_SchemaNode ((XMP_OptionBits)0x80000000UL)</span>
+<a name="l00479"></a>00479 <span class="preprocessor"></span>
+<a name="l00480"></a>00480 <span class="keyword">enum</span> { <span class="comment">/* Option bits for the TXMPMeta::SetXyz functions. */</span>
+<a name="l00481"></a>00481
+<a name="l00482"></a>00482 <span class="comment">/* Options shared with GetXyz functions. */</span>
+<a name="l00483"></a>00483 <span class="comment">/*</span>
+<a name="l00484"></a>00484 <span class="comment"> kXMP_PropValueIsURI = 0x00000002UL, DISCOURAGED</span>
+<a name="l00485"></a>00485 <span class="comment"> kXMP_PropValueIsStruct = 0x00000100UL,</span>
+<a name="l00486"></a>00486 <span class="comment"> kXMP_PropValueIsArray = 0x00000200UL,</span>
+<a name="l00487"></a>00487 <span class="comment"> kXMP_PropArrayIsOrdered = 0x00000400UL,</span>
+<a name="l00488"></a>00488 <span class="comment"> kXMP_PropArrayIsAlternate = 0x00000800UL,</span>
+<a name="l00489"></a>00489 <span class="comment"> kXMP_PropArrayIsAltText = 0x00001000UL,</span>
+<a name="l00490"></a>00490 <span class="comment"> kXMP_PropValueIsCompact = 0x00002000UL, RESERVED</span>
+<a name="l00491"></a>00491 <span class="comment"> */</span>
+<a name="l00492"></a>00492
+<a name="l00493"></a>00493 <span class="comment">/* Options for array item location. */</span>
+<a name="l00494"></a>00494 kXMP_InsertBeforeItem = 0x00004000UL, <span class="comment">/* Insert a new item before the given index. */</span>
+<a name="l00495"></a>00495 kXMP_InsertAfterItem = 0x00008000UL, <span class="comment">/* Insert a new item after the given index. */</span>
+<a name="l00496"></a>00496
+<a name="l00497"></a>00497 <span class="comment">/* Miscellaneous options */</span>
+<a name="l00498"></a>00498 kXMP_DeleteExisting = 0x20000000UL, <span class="comment">/* Delete any pre-existing property. */</span>
+<a name="l00499"></a>00499
+<a name="l00500"></a>00500 <span class="comment">/* Masks that are multiple flags. */</span>
+<a name="l00501"></a>00501 kXMP_PropValueOptionsMask = kXMP_PropValueIsURI,
+<a name="l00502"></a>00502 kXMP_PropArrayLocationMask = kXMP_InsertBeforeItem | kXMP_InsertAfterItem
+<a name="l00503"></a>00503
+<a name="l00504"></a>00504 };
+<a name="l00505"></a>00505
+<a name="l00506"></a>00506 <span class="comment">/* ---------------------------------------------------------------------------------------------- */</span>
+<a name="l00507"></a>00507
+<a name="l00508"></a>00508 <span class="keyword">enum</span> { <span class="comment">/* Options for TXMPMeta::ParseFromBuffer. */</span>
+<a name="l00509"></a>00509 kXMP_RequireXMPMeta = 0x0001UL, <span class="comment">/* Require a surrounding x:xmpmeta element. */</span>
+<a name="l00510"></a>00510 kXMP_ParseMoreBuffers = 0x0002UL, <span class="comment">/* This is the not last input buffer for this parse stream. */</span>
+<a name="l00511"></a>00511 kXMP_StrictAliasing = 0x0004UL <span class="comment">/* Do not reconcile alias differences, throw an exception. */</span>
+<a name="l00512"></a>00512 };
+<a name="l00513"></a>00513
+<a name="l00514"></a>00514 <span class="keyword">enum</span> { <span class="comment">/* Options for TXMPMeta::SerializeToBuffer. */</span>
+<a name="l00515"></a>00515
+<a name="l00516"></a>00516 <span class="comment">/* *** Option to remove empty struct/array, or leaf with empty value? */</span>
+<a name="l00517"></a>00517
+<a name="l00518"></a>00518 kXMP_OmitPacketWrapper = 0x0010UL, <span class="comment">/* Omit the XML packet wrapper. */</span>
+<a name="l00519"></a>00519 kXMP_ReadOnlyPacket = 0x0020UL, <span class="comment">/* Default is a writeable packet. */</span>
+<a name="l00520"></a>00520 kXMP_UseCompactFormat = 0x0040UL, <span class="comment">/* Use a compact form of RDF. */</span>
+<a name="l00521"></a>00521
+<a name="l00522"></a>00522 kXMP_IncludeThumbnailPad = 0x0100UL, <span class="comment">/* Include a padding allowance for a thumbnail image. */</span>
+<a name="l00523"></a>00523 kXMP_ExactPacketLength = 0x0200UL, <span class="comment">/* The padding parameter is the overall packet length. */</span>
+<a name="l00524"></a>00524 kXMP_WriteAliasComments = 0x0400UL, <span class="comment">/* Show aliases as XML comments. */</span>
+<a name="l00525"></a>00525 kXMP_OmitAllFormatting = 0x0800UL, <span class="comment">/* Omit all formatting whitespace. */</span>
+<a name="l00526"></a>00526
+<a name="l00527"></a>00527 _XMP_LittleEndian_Bit = 0x0001UL, <span class="comment">/* ! Don't use directly, see the combined values below! */</span>
+<a name="l00528"></a>00528 _XMP_UTF16_Bit = 0x0002UL,
+<a name="l00529"></a>00529 _XMP_UTF32_Bit = 0x0004UL,
+<a name="l00530"></a>00530
+<a name="l00531"></a>00531 kXMP_EncodingMask = 0x0007UL,
+<a name="l00532"></a>00532 kXMP_EncodeUTF8 = 0UL,
+<a name="l00533"></a>00533 kXMP_EncodeUTF16Big = _XMP_UTF16_Bit,
+<a name="l00534"></a>00534 kXMP_EncodeUTF16Little = _XMP_UTF16_Bit | _XMP_LittleEndian_Bit,
+<a name="l00535"></a>00535 kXMP_EncodeUTF32Big = _XMP_UTF32_Bit,
+<a name="l00536"></a>00536 kXMP_EncodeUTF32Little = _XMP_UTF32_Bit | _XMP_LittleEndian_Bit
+<a name="l00537"></a>00537
+<a name="l00538"></a>00538 };
+<a name="l00539"></a>00539
+<a name="l00540"></a>00540 <span class="comment">/* ---------------------------------------------------------------------------------------------- */</span>
+<a name="l00541"></a>00541
+<a name="l00542"></a>00542 <span class="keyword">enum</span> { <span class="comment">/* Options for TXMPIterator construction. */</span>
+<a name="l00543"></a>00543
+<a name="l00544"></a>00544 kXMP_IterClassMask = 0x00FFUL, <span class="comment">/* The low 8 bits are an enum of what data structure to iterate. */</span>
+<a name="l00545"></a>00545 kXMP_IterProperties = 0x0000UL, <span class="comment">/* Iterate the property tree of a TXMPMeta object. */</span>
+<a name="l00546"></a>00546 kXMP_IterAliases = 0x0001UL, <span class="comment">/* Iterate the global alias table. */</span>
+<a name="l00547"></a>00547 kXMP_IterNamespaces = 0x0002UL, <span class="comment">/* Iterate the global namespace table. */</span>
+<a name="l00548"></a>00548 kXMP_IterJustChildren = 0x0100UL, <span class="comment">/* Just do the immediate children of the root, default is subtree. */</span>
+<a name="l00549"></a>00549 kXMP_IterJustLeafNodes = 0x0200UL, <span class="comment">/* Just do the leaf nodes, default is all nodes in the subtree. */</span>
+<a name="l00550"></a>00550 kXMP_IterJustLeafName = 0x0400UL, <span class="comment">/* Return just the leaf part of the path, default is the full path. */</span>
+<a name="l00551"></a>00551 kXMP_IterIncludeAliases = 0x0800UL, <span class="comment">/* Include aliases, default is just actual properties. */</span>
+<a name="l00552"></a>00552
+<a name="l00553"></a>00553 kXMP_IterOmitQualifiers = 0x1000UL <span class="comment">/* Omit all qualifiers. */</span>
+<a name="l00554"></a>00554
+<a name="l00555"></a>00555 };
+<a name="l00556"></a>00556
+<a name="l00557"></a>00557 <span class="keyword">enum</span> { <span class="comment">/* Options for TXMPIterator::Skip. */</span>
+<a name="l00558"></a>00558 kXMP_IterSkipSubtree = 0x0001UL, <span class="comment">/* Skip the subtree below the current node. */</span>
+<a name="l00559"></a>00559 kXMP_IterSkipSiblings = 0x0002UL <span class="comment">/* Skip the subtree below and remaining siblings of the current node. */</span>
+<a name="l00560"></a>00560 };
+<a name="l00561"></a>00561
+<a name="l00562"></a>00562 <span class="comment">/* ---------------------------------------------------------------------------------------------- */</span>
+<a name="l00563"></a>00563
+<a name="l00564"></a>00564 <span class="keyword">enum</span> { <span class="comment">/* Options for TXMPUtils::CatenateArrayItems and TXMPUtils::SeparateArrayItems. */</span>
+<a name="l00565"></a>00565
+<a name="l00566"></a>00566 <span class="comment">/* Options shared with GetXyz functions. */</span>
+<a name="l00567"></a>00567 <span class="comment">/*</span>
+<a name="l00568"></a>00568 <span class="comment"> kXMP_PropValueIsArray = 0x00000200UL,</span>
+<a name="l00569"></a>00569 <span class="comment"> kXMP_PropArrayIsOrdered = 0x00000400UL,</span>
+<a name="l00570"></a>00570 <span class="comment"> kXMP_PropArrayIsAlternate = 0x00000800UL,</span>
+<a name="l00571"></a>00571 <span class="comment"> kXMP_PropArrayIsAltText = 0x00001000UL,</span>
+<a name="l00572"></a>00572 <span class="comment"> */</span>
+<a name="l00573"></a>00573
+<a name="l00574"></a>00574 kXMPUtil_AllowCommas = 0x10000000UL <span class="comment">/* Allow commas in item values, default is separator. */</span>
+<a name="l00575"></a>00575
+<a name="l00576"></a>00576 };
+<a name="l00577"></a>00577
+<a name="l00578"></a>00578 <span class="keyword">enum</span> { <span class="comment">/* Options for TXMPUtils::RemoveProperties and TXMPUtils::AppendProperties. */</span>
+<a name="l00579"></a>00579 kXMPUtil_DoAllProperties = 0x0001UL, <span class="comment">/* Do all properties, default is just external properties. */</span>
+<a name="l00580"></a>00580 kXMPUtil_ReplaceOldValues = 0x0002UL, <span class="comment">/* Replace existing values, default is to leave them. */</span>
+<a name="l00581"></a>00581 kXMPUtil_DeleteEmptyValues = 0x0004UL, <span class="comment">/* Delete properties if the new value is empty. */</span>
+<a name="l00582"></a>00582 kXMPUtil_IncludeAliases = 0x0800UL <span class="comment">/* == kXMP_IterIncludeAliases */</span>
+<a name="l00583"></a>00583 };
+<a name="l00584"></a>00584
+<a name="l00585"></a>00585 <span class="comment">/* ============================================================================================== */</span>
+<a name="l00586"></a>00586 <span class="comment">/* Types and Constants for XMP File Handler */</span>
+<a name="l00587"></a>00587 <span class="comment">/* ======================================== */</span>
+<a name="l00588"></a>00588
+<a name="l00589"></a>00589 <span class="keyword">enum</span> {
+<a name="l00590"></a>00590
+<a name="l00591"></a>00591 <span class="comment">/* Public file formats. Hex used to avoid gcc warnings. */</span>
+<a name="l00592"></a>00592 <span class="comment">/* ! Leave them as big endian. There seems to be no decent way on UNIX to determine the target */</span>
+<a name="l00593"></a>00593 <span class="comment">/* ! endianness at compile time. Forcing it on the client isn't acceptable. */</span>
+<a name="l00594"></a>00594
+<a name="l00595"></a>00595 kXMP_PDFFile = 0x50444620UL, <span class="comment">/* 'PDF ' */</span>
+<a name="l00596"></a>00596 kXMP_PostScriptFile = 0x50532020UL, <span class="comment">/* 'PS ', general PostScript following DSC conventions. */</span>
+<a name="l00597"></a>00597 kXMP_EPSFile = 0x45505320UL, <span class="comment">/* 'EPS ', encapsulated PostScript. */</span>
+<a name="l00598"></a>00598
+<a name="l00599"></a>00599 kXMP_JPEGFile = 0x4A504547UL, <span class="comment">/* 'JPEG' */</span>
+<a name="l00600"></a>00600 kXMP_JPEG2KFile = 0x4A505820UL, <span class="comment">/* 'JPX ', ISO 15444-1 */</span>
+<a name="l00601"></a>00601 kXMP_TIFFFile = 0x54494646UL, <span class="comment">/* 'TIFF' */</span>
+<a name="l00602"></a>00602 kXMP_GIFFile = 0x47494620UL, <span class="comment">/* 'GIF ' */</span>
+<a name="l00603"></a>00603 kXMP_PNGFile = 0x504E4720UL, <span class="comment">/* 'PNG ' */</span>
+<a name="l00604"></a>00604
+<a name="l00605"></a>00605 kXMP_SWFFile = 0x53574620UL, <span class="comment">/* 'SWF ' */</span>
+<a name="l00606"></a>00606 kXMP_FLAFile = 0x464C4120UL, <span class="comment">/* 'FLA ' */</span>
+<a name="l00607"></a>00607 kXMP_FLVFile = 0x464C5620UL, <span class="comment">/* 'FLV ' */</span>
+<a name="l00608"></a>00608
+<a name="l00609"></a>00609 kXMP_MOVFile = 0x4D4F5620UL, <span class="comment">/* 'MOV ', Quicktime */</span>
+<a name="l00610"></a>00610 kXMP_AVIFile = 0x41564920UL, <span class="comment">/* 'AVI ' */</span>
+<a name="l00611"></a>00611 kXMP_CINFile = 0x43494E20UL, <span class="comment">/* 'CIN ', Cineon */</span>
+<a name="l00612"></a>00612 kXMP_WAVFile = 0x57415620UL, <span class="comment">/* 'WAV ' */</span>
+<a name="l00613"></a>00613 kXMP_MP3File = 0x4D503320UL, <span class="comment">/* 'MP3 ' */</span>
+<a name="l00614"></a>00614 kXMP_SESFile = 0x53455320UL, <span class="comment">/* 'SES ', Audition session */</span>
+<a name="l00615"></a>00615 kXMP_CELFile = 0x43454C20UL, <span class="comment">/* 'CEL ', Audition loop */</span>
+<a name="l00616"></a>00616 kXMP_MPEGFile = 0x4D504547UL, <span class="comment">/* 'MPEG' */</span>
+<a name="l00617"></a>00617 kXMP_MPEG2File = 0x4D503220UL, <span class="comment">/* 'MP2 ' */</span>
+<a name="l00618"></a>00618 kXMP_MPEG4File = 0x4D503420UL, <span class="comment">/* 'MP4 ', ISO 14494-12 and -14 */</span>
+<a name="l00619"></a>00619 kXMP_WMAVFile = 0x574D4156UL, <span class="comment">/* 'WMAV', Windows Media Audio and Video */</span>
+<a name="l00620"></a>00620 kXMP_AIFFFile = 0x41494646UL, <span class="comment">/* 'AIFF' */</span>
+<a name="l00621"></a>00621
+<a name="l00622"></a>00622 kXMP_HTMLFile = 0x48544D4CUL, <span class="comment">/* 'HTML' */</span>
+<a name="l00623"></a>00623 kXMP_XMLFile = 0x584D4C20UL, <span class="comment">/* 'XML ' */</span>
+<a name="l00624"></a>00624 kXMP_TextFile = 0x74657874UL, <span class="comment">/* 'text' */</span>
+<a name="l00625"></a>00625
+<a name="l00626"></a>00626 <span class="comment">/* Adobe application file formats. */</span>
+<a name="l00627"></a>00627
+<a name="l00628"></a>00628 kXMP_PhotoshopFile = 0x50534420UL, <span class="comment">/* 'PSD ' */</span>
+<a name="l00629"></a>00629 kXMP_IllustratorFile = 0x41492020UL, <span class="comment">/* 'AI ' */</span>
+<a name="l00630"></a>00630 kXMP_InDesignFile = 0x494E4444UL, <span class="comment">/* 'INDD' */</span>
+<a name="l00631"></a>00631 kXMP_AEProjectFile = 0x41455020UL, <span class="comment">/* 'AEP ' */</span>
+<a name="l00632"></a>00632 kXMP_AEProjTemplateFile = 0x41455420UL, <span class="comment">/* 'AET ', After Effects Project Template */</span>
+<a name="l00633"></a>00633 kXMP_AEFilterPresetFile = 0x46465820UL, <span class="comment">/* 'FFX ' */</span>
+<a name="l00634"></a>00634 kXMP_EncoreProjectFile = 0x4E434F52UL, <span class="comment">/* 'NCOR' */</span>
+<a name="l00635"></a>00635 kXMP_PremiereProjectFile = 0x5052504AUL, <span class="comment">/* 'PRPJ' */</span>
+<a name="l00636"></a>00636 kXMP_PremiereTitleFile = 0x5052544CUL, <span class="comment">/* 'PRTL' */</span>
+<a name="l00637"></a>00637
+<a name="l00638"></a>00638 <span class="comment">/* Catch all. */</span>
+<a name="l00639"></a>00639
+<a name="l00640"></a>00640 kXMP_UnknownFile = 0x20202020UL <span class="comment">/* ' ' */</span>
+<a name="l00641"></a>00641
+<a name="l00642"></a>00642 };
+<a name="l00643"></a>00643 <span class="keyword">typedef</span> XMP_Uns32 XMP_FileFormat;
+<a name="l00644"></a>00644
+<a name="l00645"></a>00645 <span class="comment">/* ---------------------------------------------------------------------------------------------- */</span>
+<a name="l00646"></a>00646
+<a name="l00647"></a>00647 <span class="keyword">enum</span> {
+<a name="l00648"></a>00648 kXMP_CharLittleEndianMask = 1,
+<a name="l00649"></a>00649 kXMP_Char16BitMask = 2, <span class="comment">/* Don't use these directly. */</span>
+<a name="l00650"></a>00650 kXMP_Char32BitMask = 4
+<a name="l00651"></a>00651 };
+<a name="l00652"></a>00652
+<a name="l00653"></a>00653 <span class="keyword">enum</span> { <span class="comment">/* The values allow easy testing for 16/32 bit and big/little endian. */</span>
+<a name="l00654"></a>00654 kXMP_Char8Bit = 0,
+<a name="l00655"></a>00655 kXMP_Char16BitBig = kXMP_Char16BitMask,
+<a name="l00656"></a>00656 kXMP_Char16BitLittle = kXMP_Char16BitMask | kXMP_CharLittleEndianMask,
+<a name="l00657"></a>00657 kXMP_Char32BitBig = kXMP_Char32BitMask,
+<a name="l00658"></a>00658 kXMP_Char32BitLittle = kXMP_Char32BitMask | kXMP_CharLittleEndianMask,
+<a name="l00659"></a>00659 kXMP_CharUnknown = 1 <span class="comment">/* ! A bit of a hack, for variable or not-yet-known cases. */</span>
+<a name="l00660"></a>00660 };
+<a name="l00661"></a>00661
+<a name="l00662"></a>00662 <span class="preprocessor">#define XMP_CharFormIs16Bit(f) ( ((int)(f) &amp; kXMP_Char16BitMask) != 0 )</span>
+<a name="l00663"></a>00663 <span class="preprocessor"></span><span class="preprocessor">#define XMP_CharFormIs32Bit(f) ( ((int)(f) &amp; kXMP_Char32BitMask) != 0 )</span>
+<a name="l00664"></a>00664 <span class="preprocessor"></span>
+<a name="l00665"></a>00665 <span class="preprocessor">#define XMP_CharFormIsBigEndian(f) ( ((int)(f) &amp; kXMP_CharLittleEndianMask) == 0 )</span>
+<a name="l00666"></a>00666 <span class="preprocessor"></span><span class="preprocessor">#define XMP_CharFormIsLittleEndian(f) ( ((int)(f) &amp; kXMP_CharLittleEndianMask) != 0 )</span>
+<a name="l00667"></a>00667 <span class="preprocessor"></span>
+<a name="l00668"></a>00668 <span class="preprocessor">#define XMP_GetCharSize(f) ( ((int)(f)&amp;6) == 0 ? 1 : (int)(f)&amp;6 )</span>
+<a name="l00669"></a>00669 <span class="preprocessor"></span>
+<a name="l00670"></a>00670 <span class="preprocessor">#define XMP_CharToSerializeForm(cf) ( (XMP_OptionBits)(cf) )</span>
+<a name="l00671"></a>00671 <span class="preprocessor"></span><span class="preprocessor">#define XMP_CharFromSerializeForm(sf) ( (XMP_Uns8)(sf) )</span>
+<a name="l00672"></a>00672 <span class="preprocessor"></span>
+<a name="l00673"></a>00673 <span class="keyword">struct </span>XMP_PacketInfo {
+<a name="l00674"></a>00674 XMP_Int64 offset;
+<a name="l00675"></a>00675 XMP_Int32 length;
+<a name="l00676"></a>00676 XMP_Int32 padSize; <span class="comment">/* Zero if unknown. */</span>
+<a name="l00677"></a>00677 XMP_Uns8 charForm;
+<a name="l00678"></a>00678 XMP_Bool writeable;
+<a name="l00679"></a>00679 XMP_Uns8 pad1, pad2;
+<a name="l00680"></a>00680 <span class="preprocessor"> #if __cplusplus</span>
+<a name="l00681"></a>00681 <span class="preprocessor"></span> XMP_PacketInfo() : offset(0), length(0), padSize(0), charForm(0), writeable(0), pad1(0), pad2(0) {};
+<a name="l00682"></a>00682 <span class="preprocessor"> #endif</span>
+<a name="l00683"></a>00683 <span class="preprocessor"></span>};
+<a name="l00684"></a>00684 <span class="preprocessor">#if ! __cplusplus</span>
+<a name="l00685"></a>00685 <span class="preprocessor"></span> <span class="keyword">typedef</span> <span class="keyword">struct </span>XMP_PacketInfo XMP_PacketInfo;
+<a name="l00686"></a>00686 <span class="preprocessor">#endif</span>
+<a name="l00687"></a>00687 <span class="preprocessor"></span><span class="keyword">enum</span> { kXMP_PacketInfoVersion = 3 };
+<a name="l00688"></a>00688
+<a name="l00689"></a>00689 <span class="comment">/* ---------------------------------------------------------------------------------------------- */</span>
+<a name="l00690"></a>00690
+<a name="l00691"></a>00691 <span class="keyword">enum</span> { <span class="comment">/* Values for XMP_ThumbnailInfo.tnailFormat. */</span>
+<a name="l00692"></a>00692 kXMP_UnknownTNail = 0, <span class="comment">/* The thumbnail data has an unknown format. */</span>
+<a name="l00693"></a>00693 kXMP_JPEGTNail = 1, <span class="comment">/* The thumbnail data is a JPEG stream, presumably compressed. */</span>
+<a name="l00694"></a>00694 kXMP_TIFFTNail = 2, <span class="comment">/* The thumbnail data is a TIFF stream, presumably uncompressed. */</span>
+<a name="l00695"></a>00695 kXMP_PShopTNail = 3 <span class="comment">/* The thumbnail data is in the format of Photoshop Image Resource 1036. */</span>
+<a name="l00696"></a>00696 };
+<a name="l00697"></a>00697
+<a name="l00698"></a>00698 <span class="keyword">struct </span>XMP_ThumbnailInfo {
+<a name="l00699"></a>00699 XMP_FileFormat fileFormat; <span class="comment">/* The format of the containing file. */</span>
+<a name="l00700"></a>00700 XMP_Uns32 fullWidth, fullHeight; <span class="comment">/* Full image size in pixels. */</span>
+<a name="l00701"></a>00701 XMP_Uns32 tnailWidth, tnailHeight; <span class="comment">/* Thumbnail image size in pixels. */</span>
+<a name="l00702"></a>00702 XMP_Uns16 fullOrientation, tnailOrientation; <span class="comment">/* Orientation of full image and thumbnail, as defined by Exif for tag 274. */</span>
+<a name="l00703"></a>00703 <span class="keyword">const</span> XMP_Uns8 * tnailImage; <span class="comment">/* Raw data from the host file, valid for life of the owning XMPFiles object. Do not modify! */</span>
+<a name="l00704"></a>00704 XMP_Uns32 tnailSize; <span class="comment">/* The size in bytes of the tnailImage data. */</span>
+<a name="l00705"></a>00705 XMP_Uns8 tnailFormat; <span class="comment">/* The format of the tnailImage data. */</span>
+<a name="l00706"></a>00706 XMP_Uns8 pad1, pad2, pad3;
+<a name="l00707"></a>00707 <span class="preprocessor"> #if __cplusplus</span>
+<a name="l00708"></a>00708 <span class="preprocessor"></span> XMP_ThumbnailInfo() : fileFormat(kXMP_UnknownFile), fullWidth(0), fullHeight(0),
+<a name="l00709"></a>00709 tnailWidth(0), tnailHeight(0), fullOrientation(0), tnailOrientation(0),
+<a name="l00710"></a>00710 tnailImage(0), tnailSize(0), tnailFormat(kXMP_UnknownTNail) {};
+<a name="l00711"></a>00711 <span class="preprocessor"> #endif</span>
+<a name="l00712"></a>00712 <span class="preprocessor"></span>};
+<a name="l00713"></a>00713 <span class="preprocessor">#if ! __cplusplus</span>
+<a name="l00714"></a>00714 <span class="preprocessor"></span> <span class="keyword">typedef</span> <span class="keyword">struct </span>XMP_ThumbnailInfo XMP_ThumbnailInfo;
+<a name="l00715"></a>00715 <span class="preprocessor">#endif</span>
+<a name="l00716"></a>00716 <span class="preprocessor"></span><span class="keyword">enum</span> { kXMP_ThumbnailInfoVersion = 1 };
+<a name="l00717"></a>00717
+<a name="l00718"></a>00718 <span class="comment">/* ---------------------------------------------------------------------------------------------- */</span>
+<a name="l00719"></a>00719
+<a name="l00720"></a>00720 <span class="preprocessor">#define kXMPFiles_UnknownOffset ((XMP_Int64)-1)</span>
+<a name="l00721"></a>00721 <span class="preprocessor"></span><span class="preprocessor">#define kXMPFiles_UnknownLength ((XMP_Int32)-1)</span>
+<a name="l00722"></a>00722 <span class="preprocessor"></span>
+<a name="l00723"></a>00723 <span class="keyword">enum</span> { <span class="comment">/* Options for Initialize. */</span>
+<a name="l00724"></a>00724 kXMPFiles_NoQuickTimeInit = 0x0001 <span class="comment">/* Don't initialize QuickTime, the client will. */</span>
+<a name="l00725"></a>00725 };
+<a name="l00726"></a>00726
+<a name="l00727"></a>00727 <span class="keyword">enum</span> { <span class="comment">/* Options for GetFormatInfo. */</span>
+<a name="l00728"></a>00728 kXMPFiles_CanInjectXMP = 0x00000001, <span class="comment">/* Can inject first-time XMP into an existing file. */</span>
+<a name="l00729"></a>00729 kXMPFiles_CanExpand = 0x00000002, <span class="comment">/* Can expand XMP or other metadata in an existing file. */</span>
+<a name="l00730"></a>00730 kXMPFiles_CanRewrite = 0x00000004, <span class="comment">/* Can copy one file to another, writing new metadata. */</span>
+<a name="l00731"></a>00731 kXMPFiles_PrefersInPlace = 0x00000008, <span class="comment">/* Can expand, but prefers in-place update. */</span>
+<a name="l00732"></a>00732 kXMPFiles_CanReconcile = 0x00000010, <span class="comment">/* Supports reconciliation between XMP and other forms. */</span>
+<a name="l00733"></a>00733 kXMPFiles_AllowsOnlyXMP = 0x00000020, <span class="comment">/* Allows access to just the XMP, ignoring other forms. */</span>
+<a name="l00734"></a>00734 kXMPFiles_ReturnsRawPacket = 0x00000040, <span class="comment">/* File handler returns raw XMP packet information. */</span>
+<a name="l00735"></a>00735 kXMPFiles_ReturnsTNail = 0x00000080, <span class="comment">/* File handler returns native thumbnail. */</span>
+<a name="l00736"></a>00736 kXMPFiles_HandlerOwnsFile = 0x00000100, <span class="comment">/* The file handler does the file open and close. */</span>
+<a name="l00737"></a>00737 kXMPFiles_AllowsSafeUpdate = 0x00000200, <span class="comment">/* The file handler allows crash-safe file updates. */</span>
+<a name="l00738"></a>00738 kXMPFiles_NeedsReadOnlyPacket = 0x00000400, <span class="comment">/* The file format needs the XMP packet to be read-only. */</span>
+<a name="l00739"></a>00739 kXMPFiles_UsesSidecarXMP = 0x00000800 <span class="comment">/* The file handler uses a "sidecar" file for the XMP. */</span>
+<a name="l00740"></a>00740 };
+<a name="l00741"></a>00741
+<a name="l00742"></a>00742 <span class="keyword">enum</span> { <span class="comment">/* Options for OpenFile. */</span>
+<a name="l00743"></a>00743 kXMPFiles_OpenForRead = 0x00000001, <span class="comment">/* Open for read-only access. */</span>
+<a name="l00744"></a>00744 kXMPFiles_OpenForUpdate = 0x00000002, <span class="comment">/* Open for reading and writing. */</span>
+<a name="l00745"></a>00745 kXMPFiles_OpenOnlyXMP = 0x00000004, <span class="comment">/* Only the XMP is wanted, allows space/time optimizations. */</span>
+<a name="l00746"></a>00746 kXMPFiles_OpenCacheTNail = 0x00000008, <span class="comment">/* Cache thumbnail if possible, GetThumbnail will be called. */</span>
+<a name="l00747"></a>00747 kXMPFiles_OpenStrictly = 0x00000010, <span class="comment">/* Be strict about locating XMP and reconciling with other forms. */</span>
+<a name="l00748"></a>00748 kXMPFiles_OpenUseSmartHandler = 0x00000020, <span class="comment">/* Require the use of a smart handler. */</span>
+<a name="l00749"></a>00749 kXMPFiles_OpenUsePacketScanning = 0x00000040, <span class="comment">/* Force packet scanning, don't use a smart handler. */</span>
+<a name="l00750"></a>00750 kXMPFiles_OpenLimitedScanning = 0x00000080, <span class="comment">/* Only packet scan files "known" to need scanning. */</span>
+<a name="l00751"></a>00751 kXMPFiles_OpenInBackground = 0x10000000 <span class="comment">/* Set if calling from background thread. */</span>
+<a name="l00752"></a>00752 };
+<a name="l00753"></a>00753
+<a name="l00754"></a>00754 <span class="comment">/* A note about kXMPFiles_OpenInBackground. The XMPFiles handler for .mov files currently uses */</span>
+<a name="l00755"></a>00755 <span class="comment">/* QuickTime. On Macintosh, calls to Enter/ExitMovies versus Enter/ExitMoviesOnThread must be made. */</span>
+<a name="l00756"></a>00756 <span class="comment">/* This option is used to signal background use so that the .mov handler can behave appropriately. */</span>
+<a name="l00757"></a>00757
+<a name="l00758"></a>00758 <span class="keyword">enum</span> { <span class="comment">/* Options for CloseFile. */</span>
+<a name="l00759"></a>00759 kXMPFiles_UpdateSafely = 0x0001 <span class="comment">/* Write into a temporary file and swap for crash safety. */</span>
+<a name="l00760"></a>00760 };
+<a name="l00761"></a>00761
+<a name="l00762"></a>00762 <span class="comment">/* ============================================================================================== */</span>
+<a name="l00763"></a>00763 <span class="comment">/* Exception codes */</span>
+<a name="l00764"></a>00764 <span class="comment">/* =============== */</span>
+<a name="l00765"></a>00765
+<a name="l00779"></a>00779 <span class="preprocessor">#if ! __cplusplus</span>
+<a name="l00780"></a>00780 <span class="preprocessor"></span>
+<a name="l00781"></a>00781 <span class="keyword">typedef</span> <span class="keyword">struct </span>XMP_Error {
+<a name="l00782"></a>00782 XMP_Int32 id;
+<a name="l00783"></a>00783 XMP_StringPtr errMsg;
+<a name="l00784"></a>00784 } XMP_Error;
+<a name="l00785"></a>00785
+<a name="l00786"></a>00786 <span class="preprocessor">#else</span>
+<a name="l00787"></a>00787 <span class="preprocessor"></span>
+<a name="l00788"></a>00788 <span class="keyword">class </span>XMP_Error {
+<a name="l00789"></a>00789 <span class="keyword">public</span>:
+<a name="l00790"></a>00790 XMP_Error ( XMP_Int32 _id, XMP_StringPtr _errMsg ) : id(_id), errMsg(_errMsg) {};
+<a name="l00791"></a>00791 <span class="keyword">inline</span> XMP_Int32 GetID()<span class="keyword"> const </span>{ <span class="keywordflow">return</span> id; };
+<a name="l00792"></a>00792 <span class="keyword">inline</span> XMP_StringPtr GetErrMsg()<span class="keyword"> const </span>{ <span class="keywordflow">return</span> errMsg; };
+<a name="l00793"></a>00793 <span class="keyword">private</span>:
+<a name="l00794"></a>00794 XMP_Int32 id;
+<a name="l00795"></a>00795 XMP_StringPtr errMsg;
+<a name="l00796"></a>00796 };
+<a name="l00797"></a>00797
+<a name="l00798"></a>00798 <span class="preprocessor">#endif</span>
+<a name="l00799"></a>00799 <span class="preprocessor"></span>
+<a name="l00800"></a>00800 <span class="keyword">enum</span> {
+<a name="l00801"></a>00801
+<a name="l00802"></a>00802 <span class="comment">/* More or less generic error codes. */</span>
+<a name="l00803"></a>00803 kXMPErr_Unknown = 0,
+<a name="l00804"></a>00804 kXMPErr_TBD = 1,
+<a name="l00805"></a>00805 kXMPErr_Unavailable = 2,
+<a name="l00806"></a>00806 kXMPErr_BadObject = 3,
+<a name="l00807"></a>00807 kXMPErr_BadParam = 4,
+<a name="l00808"></a>00808 kXMPErr_BadValue = 5,
+<a name="l00809"></a>00809 kXMPErr_AssertFailure = 6,
+<a name="l00810"></a>00810 kXMPErr_EnforceFailure = 7,
+<a name="l00811"></a>00811 kXMPErr_Unimplemented = 8,
+<a name="l00812"></a>00812 kXMPErr_InternalFailure = 9,
+<a name="l00813"></a>00813 kXMPErr_Deprecated = 10,
+<a name="l00814"></a>00814 kXMPErr_ExternalFailure = 11,
+<a name="l00815"></a>00815 kXMPErr_UserAbort = 12,
+<a name="l00816"></a>00816 kXMPErr_StdException = 13,
+<a name="l00817"></a>00817 kXMPErr_UnknownException = 14,
+<a name="l00818"></a>00818 kXMPErr_NoMemory = 15,
+<a name="l00819"></a>00819
+<a name="l00820"></a>00820 <span class="comment">/* More specific parameter error codes. */</span>
+<a name="l00821"></a>00821 kXMPErr_BadSchema = 101,
+<a name="l00822"></a>00822 kXMPErr_BadXPath = 102,
+<a name="l00823"></a>00823 kXMPErr_BadOptions = 103,
+<a name="l00824"></a>00824 kXMPErr_BadIndex = 104,
+<a name="l00825"></a>00825 kXMPErr_BadIterPosition = 105,
+<a name="l00826"></a>00826 kXMPErr_BadParse = 106,
+<a name="l00827"></a>00827 kXMPErr_BadSerialize = 107,
+<a name="l00828"></a>00828 kXMPErr_BadFileFormat = 108,
+<a name="l00829"></a>00829 kXMPErr_NoFileHandler = 109,
+<a name="l00830"></a>00830 kXMPErr_TooLargeForJPEG = 110,
+<a name="l00831"></a>00831
+<a name="l00832"></a>00832 <span class="comment">/* File format and internal structure error codes. */</span>
+<a name="l00833"></a>00833 kXMPErr_BadXML = 201,
+<a name="l00834"></a>00834 kXMPErr_BadRDF = 202,
+<a name="l00835"></a>00835 kXMPErr_BadXMP = 203,
+<a name="l00836"></a>00836 kXMPErr_EmptyIterator = 204,
+<a name="l00837"></a>00837 kXMPErr_BadUnicode = 205,
+<a name="l00838"></a>00838 kXMPErr_BadTIFF = 206,
+<a name="l00839"></a>00839 kXMPErr_BadJPEG = 207,
+<a name="l00840"></a>00840 kXMPErr_BadPSD = 208,
+<a name="l00841"></a>00841 kXMPErr_BadPSIR = 209,
+<a name="l00842"></a>00842 kXMPErr_BadIPTC = 210,
+<a name="l00843"></a>00843 kXMPErr_BadMPEG = 211
+<a name="l00844"></a>00844
+<a name="l00845"></a>00845 };
+<a name="l00846"></a>00846
+<a name="l00852"></a>00852 <span class="comment">/* ============================================================================================== */</span>
+<a name="l00853"></a>00853 <span class="comment">/* Client callbacks */</span>
+<a name="l00854"></a>00854 <span class="comment">/* ================ */</span>
+<a name="l00855"></a>00855
+<a name="l00856"></a>00856
+<a name="l00880"></a><a class="code" href="XMP__Const_8h.html#91efdc0a7fbe6e1d42ca34e6ce589b98">00880</a> <span class="keyword">typedef</span> XMP_Int32 <a class="code" href="XMP__Const_8h.html#91efdc0a7fbe6e1d42ca34e6ce589b98">XMP_Status</a>;
+<a name="l00881"></a>00881
+<a name="l00882"></a><a class="code" href="XMP__Const_8h.html#36eab570ab85ff8fb5789661692d13c2">00882</a> <span class="keyword">typedef</span> <a class="code" href="XMP__Const_8h.html#91efdc0a7fbe6e1d42ca34e6ce589b98">XMP_Status</a> (* <a class="code" href="XMP__Const_8h.html#36eab570ab85ff8fb5789661692d13c2">XMP_TextOutputProc</a>) ( <span class="keywordtype">void</span> * refCon,
+<a name="l00883"></a>00883 XMP_StringPtr buffer,
+<a name="l00884"></a>00884 XMP_StringLen bufferSize );
+<a name="l00885"></a>00885
+<a name="l00891"></a>00891 <span class="comment">/* ============================================================================================== */</span>
+<a name="l00892"></a>00892 <span class="comment">/* Stuff with no better place to be */</span>
+<a name="l00893"></a>00893 <span class="comment">/* ================================ */</span>
+<a name="l00894"></a>00894
+<a name="l00895"></a>00895 <span class="keyword">typedef</span> <span class="keyword">struct </span>XMP_VersionInfo {
+<a name="l00896"></a>00896 XMP_Uns8 major; <span class="comment">/* The primary release number, the "1" in version "1.2.3". */</span>
+<a name="l00897"></a>00897 XMP_Uns8 minor; <span class="comment">/* The secondary release number, the "2" in version "1.2.3". */</span>
+<a name="l00898"></a>00898 XMP_Uns8 micro; <span class="comment">/* The tertiary release number, the "3" in version "1.2.3". */</span>
+<a name="l00899"></a>00899 XMP_Bool isDebug; <span class="comment">/* Really a 0/1 bool value. True if this is a debug build. */</span>
+<a name="l00900"></a>00900 XMP_Uns32 build; <span class="comment">/* A rolling build number, monotonically increasing in a release. */</span>
+<a name="l00901"></a>00901 XMP_Uns32 flags; <span class="comment">/* Individual feature implementation flags. */</span>
+<a name="l00902"></a>00902 XMP_StringPtr message; <span class="comment">/* A comprehensive version information string. */</span>
+<a name="l00903"></a>00903 } XMP_VersionInfo;
+<a name="l00904"></a>00904
+<a name="l00905"></a>00905 <span class="keyword">typedef</span> bool (* XMP_AbortProc) ( <span class="keywordtype">void</span> * arg ); <span class="comment">/* Used by SXMPFiles::SetAbortProc. */</span>
+<a name="l00906"></a>00906
+<a name="l00907"></a>00907 <span class="comment">/* ============================================================================================== */</span>
+<a name="l00908"></a>00908
+<a name="l00909"></a>00909 <span class="preprocessor">#if __cplusplus</span>
+<a name="l00910"></a>00910 <span class="preprocessor"></span>} <span class="comment">/* extern "C" */</span>
+<a name="l00911"></a>00911 <span class="preprocessor">#endif</span>
+<a name="l00912"></a>00912 <span class="preprocessor"></span>
+<a name="l00913"></a>00913 <span class="preprocessor">#endif </span><span class="comment">/* __XMP_Const_h__ */</span>
+</pre></div><hr size="1"><address style="align: right;"><small>Generated on Thu May 3 14:54:57 2007 for Adobe XMP Toolkit by&nbsp;
+<a href="http://www.doxygen.org/index.html">
+<img src="doxygen.png" alt="doxygen" align="middle" border="0"></a> 1.5.1 </small></address>
+</body>
+</html>
diff --git a/docs/XMPToolkit/XMP__Const_8h.html b/docs/XMPToolkit/XMP__Const_8h.html
new file mode 100644
index 0000000..d991c56
--- /dev/null
+++ b/docs/XMPToolkit/XMP__Const_8h.html
@@ -0,0 +1,190 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
+<title>Adobe XMP Toolkit: XMP_Const.h File Reference</title>
+<link href="doxygen.css" rel="stylesheet" type="text/css">
+<link href="tabs.css" rel="stylesheet" type="text/css">
+</head><body>
+<!-- Generated by Doxygen 1.5.1 -->
+<div class="tabs">
+ <ul>
+ <li><a href="index.html"><span>Main&nbsp;Page</span></a></li>
+ <li><a href="modules.html"><span>Modules</span></a></li>
+ <li><a href="annotated.html"><span>Classes</span></a></li>
+ <li id="current"><a href="files.html"><span>Files</span></a></li>
+ </ul></div>
+<h1>XMP_Const.h File Reference</h1>Common C/C++ types and constants for the XMP toolkit. <a href="#_details">More...</a>
+<p>
+<code>#include &quot;XMP_Environment.h&quot;</code><br>
+<code>#include &lt;stddef.h&gt;</code><br>
+
+<p>
+Include dependency graph for XMP_Const.h:<p><center><img src="XMP__Const_8h__incl.png" border="0" usemap="#XMP_Const.h_map" alt=""></center>
+
+<p>
+<a href="XMP__Const_8h-source.html">Go to the source code of this file.</a><table border="0" cellpadding="0" cellspacing="0">
+<tr><td></td></tr>
+<tr><td colspan="2"><br><h2>Classes</h2></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">struct &nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="structXMP__DateTime.html">XMP_DateTime</a></td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">The expanded type for a date and time. Dates and time in the serialized XMP are ISO 8601 strings. The <code><a class="el" href="structXMP__DateTime.html">XMP_DateTime</a></code> struct allows easy conversion with other formats. <a href="structXMP__DateTime.html#_details">More...</a><br></td></tr>
+<tr><td colspan="2"><br><h2>General scalar types and constants</h2></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="4c39e0131b0e3d7db66e1cfa82b67141"></a><!-- doxytag: member="XMP_Const.h::kXMP_TrueStr" ref="4c39e0131b0e3d7db66e1cfa82b67141" args="" -->
+#define&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="XMP__Const_8h.html#4c39e0131b0e3d7db66e1cfa82b67141">kXMP_TrueStr</a>&nbsp;&nbsp;&nbsp;&quot;True&quot;</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">The canonical true string value for Booleans in serialized XMP. Code that converts from the string to a bool should be case insensitive, and even allow "1". <br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="2dc55b533ed63ed7ff0c3be16a97e278"></a><!-- doxytag: member="XMP_Const.h::kXMP_FalseStr" ref="2dc55b533ed63ed7ff0c3be16a97e278" args="" -->
+#define&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="XMP__Const_8h.html#2dc55b533ed63ed7ff0c3be16a97e278">kXMP_FalseStr</a>&nbsp;&nbsp;&nbsp;&quot;False&quot;</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">The canonical false string value for Booleans in serialized XMP. Code that converts from the string to a bool should be case insensitive, and even allow "0". <br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="d439e3ceeb4590d310f6125aa12c6df6"></a><!-- doxytag: member="XMP_Const.h::XMP_StringPtr" ref="d439e3ceeb4590d310f6125aa12c6df6" args="" -->
+typedef const char *&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a></td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">The type for input string parameters. A <code>const char *</code>, a null-terminated UTF-8 string. <br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="9f7dcc184f901c713274edfdac5bcc9a"></a><!-- doxytag: member="XMP_Const.h::XMP_StringLen" ref="9f7dcc184f901c713274edfdac5bcc9a" args="" -->
+typedef XMP_Uns32&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="XMP__Const_8h.html#9f7dcc184f901c713274edfdac5bcc9a">XMP_StringLen</a></td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">The type for string length parameters. A 32-bit unsigned integer, as big as will be practically needed. <br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="00e9d9a76c144421105a4c2742203315"></a><!-- doxytag: member="XMP_Const.h::XMP_Index" ref="00e9d9a76c144421105a4c2742203315" args="" -->
+typedef XMP_Int32&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="XMP__Const_8h.html#00e9d9a76c144421105a4c2742203315">XMP_Index</a></td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">The type for offsets and indices. A 32-bit signed integer. It is signed because that often makes loop termination tests safer. <br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="eb865118433be92d88e5f49ed11487c8"></a><!-- doxytag: member="XMP_Const.h::XMP_OptionBits" ref="eb865118433be92d88e5f49ed11487c8" args="" -->
+typedef XMP_Uns32&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a></td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">The type for a collection of 32 flag bits. Individual flags are defined as enum value bit masks. A number of macros provide common set or set operations, e.g. <code>XMP_PropIsSimple</code>. For other tests use an expression like "options &amp; kXMP_&lt;theOption&gt;". When passing multiple option flags use the bitwise-or operator. '|', not the arithmatic plus, '+'. <br></td></tr>
+<tr><td colspan="2"><br><h2>Defines</h2></td></tr>
+<tr><td colspan="2"><div class="groupHeader">XML namespace constants for standard XMP schema.</div></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="030875c9dc0861c9251a3374ca14a376"></a><!-- doxytag: member="XMP_Const.h::kXMP_NS_XMP" ref="030875c9dc0861c9251a3374ca14a376" args="" -->
+#define&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="XMP__Const_8h.html#030875c9dc0861c9251a3374ca14a376">kXMP_NS_XMP</a>&nbsp;&nbsp;&nbsp;&quot;http://ns.adobe.com/xap/1.0/&quot;</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">The XML namespace for the XMP "basic" schema. <br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="e52d761e5a4fc8c8499215d2f3d82b90"></a><!-- doxytag: member="XMP_Const.h::kXMP_NS_XMP_Rights" ref="e52d761e5a4fc8c8499215d2f3d82b90" args="" -->
+#define&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="XMP__Const_8h.html#e52d761e5a4fc8c8499215d2f3d82b90">kXMP_NS_XMP_Rights</a>&nbsp;&nbsp;&nbsp;&quot;http://ns.adobe.com/xap/1.0/rights/&quot;</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">The XML namespace for the XMP copyright schema. <br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="c67379a9ffa425d0d7976a51c4f2f754"></a><!-- doxytag: member="XMP_Const.h::kXMP_NS_XMP_MM" ref="c67379a9ffa425d0d7976a51c4f2f754" args="" -->
+#define&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="XMP__Const_8h.html#c67379a9ffa425d0d7976a51c4f2f754">kXMP_NS_XMP_MM</a>&nbsp;&nbsp;&nbsp;&quot;http://ns.adobe.com/xap/1.0/mm/&quot;</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">The XML namespace for the XMP digital asset management schema. <br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="308e156c325618acb2172e550929ebee"></a><!-- doxytag: member="XMP_Const.h::kXMP_NS_XMP_BJ" ref="308e156c325618acb2172e550929ebee" args="" -->
+#define&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="XMP__Const_8h.html#308e156c325618acb2172e550929ebee">kXMP_NS_XMP_BJ</a>&nbsp;&nbsp;&nbsp;&quot;http://ns.adobe.com/xap/1.0/bj/&quot;</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">The XML namespace for the job management schema. <br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="0bcb67d0dd0922504e3da7ca5c40c82a"></a><!-- doxytag: member="XMP_Const.h::kXMP_NS_PDF" ref="0bcb67d0dd0922504e3da7ca5c40c82a" args="" -->
+#define&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="XMP__Const_8h.html#0bcb67d0dd0922504e3da7ca5c40c82a">kXMP_NS_PDF</a>&nbsp;&nbsp;&nbsp;&quot;http://ns.adobe.com/pdf/1.3/&quot;</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">The XML namespace for the PDF schema. <br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="a1a6f38ebfcdb281c5bf2809859167c7"></a><!-- doxytag: member="XMP_Const.h::kXMP_NS_Photoshop" ref="a1a6f38ebfcdb281c5bf2809859167c7" args="" -->
+#define&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="XMP__Const_8h.html#a1a6f38ebfcdb281c5bf2809859167c7">kXMP_NS_Photoshop</a>&nbsp;&nbsp;&nbsp;&quot;http://ns.adobe.com/photoshop/1.0/&quot;</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">The XML namespace for the Photoshop custom schema. <br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="d12182e1df1652f56b5eec60c1fcdd8f"></a><!-- doxytag: member="XMP_Const.h::kXMP_NS_EXIF" ref="d12182e1df1652f56b5eec60c1fcdd8f" args="" -->
+#define&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="XMP__Const_8h.html#d12182e1df1652f56b5eec60c1fcdd8f">kXMP_NS_EXIF</a>&nbsp;&nbsp;&nbsp;&quot;http://ns.adobe.com/exif/1.0/&quot;</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">The XML namespace for Adobe's EXIF schema. <br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="673355818b7b9224e8fec0fbc60ba00c"></a><!-- doxytag: member="XMP_Const.h::kXMP_NS_TIFF" ref="673355818b7b9224e8fec0fbc60ba00c" args="" -->
+#define&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="XMP__Const_8h.html#673355818b7b9224e8fec0fbc60ba00c">kXMP_NS_TIFF</a>&nbsp;&nbsp;&nbsp;&quot;http://ns.adobe.com/tiff/1.0/&quot;</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">The XML namespace for Adobe's TIFF schema. <br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="0a2d9c5f7beb27553214a7ad1df4f27e"></a><!-- doxytag: member="XMP_Const.h::kXMP_NS_XMP_T" ref="0a2d9c5f7beb27553214a7ad1df4f27e" args="" -->
+#define&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="XMP__Const_8h.html#0a2d9c5f7beb27553214a7ad1df4f27e">kXMP_NS_XMP_T</a>&nbsp;&nbsp;&nbsp;&quot;http://ns.adobe.com/xap/1.0/t/&quot;</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">The XML namespace for the XMP text document schema. <br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="39afb495ffb24bb3082493c6811e65d0"></a><!-- doxytag: member="XMP_Const.h::kXMP_NS_XMP_T_PG" ref="39afb495ffb24bb3082493c6811e65d0" args="" -->
+#define&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="XMP__Const_8h.html#39afb495ffb24bb3082493c6811e65d0">kXMP_NS_XMP_T_PG</a>&nbsp;&nbsp;&nbsp;&quot;http://ns.adobe.com/xap/1.0/t/pg/&quot;</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">The XML namespace for the XMP paged document schema. <br></td></tr>
+<tr><td colspan="2"><div class="groupHeader">XML namespace constants for qualifiers and structured property fields.</div></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="b466db52a4b85cecfa04710682c1e671"></a><!-- doxytag: member="XMP_Const.h::kXMP_NS_XMP_IdentifierQual" ref="b466db52a4b85cecfa04710682c1e671" args="" -->
+#define&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="XMP__Const_8h.html#b466db52a4b85cecfa04710682c1e671">kXMP_NS_XMP_IdentifierQual</a>&nbsp;&nbsp;&nbsp;&quot;http://ns.adobe.com/xmp/Identifier/qual/1.0/&quot;</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">The XML namespace for qualifiers of the xmp:Identifier property. <br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="9618e013619aa92ebc808b62243d2ba8"></a><!-- doxytag: member="XMP_Const.h::kXMP_NS_XMP_Dimensions" ref="9618e013619aa92ebc808b62243d2ba8" args="" -->
+#define&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="XMP__Const_8h.html#9618e013619aa92ebc808b62243d2ba8">kXMP_NS_XMP_Dimensions</a>&nbsp;&nbsp;&nbsp;&quot;http://ns.adobe.com/xap/1.0/sType/Dimensions#&quot;</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">The XML namespace for fields of the Dimensions type. <br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="935641acc7d01e782ad7a457a7ff338b"></a><!-- doxytag: member="XMP_Const.h::kXMP_NS_XMP_Image" ref="935641acc7d01e782ad7a457a7ff338b" args="" -->
+#define&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="XMP__Const_8h.html#935641acc7d01e782ad7a457a7ff338b">kXMP_NS_XMP_Image</a>&nbsp;&nbsp;&nbsp;&quot;http://ns.adobe.com/xap/1.0/g/img/&quot;</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">The XML namespace for fields of a graphical image. Used for the Thumbnail type. <br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="861613273127156050b456eee11f6b0a"></a><!-- doxytag: member="XMP_Const.h::kXMP_NS_XMP_ResourceEvent" ref="861613273127156050b456eee11f6b0a" args="" -->
+#define&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="XMP__Const_8h.html#861613273127156050b456eee11f6b0a">kXMP_NS_XMP_ResourceEvent</a>&nbsp;&nbsp;&nbsp;&quot;http://ns.adobe.com/xap/1.0/sType/ResourceEvent#&quot;</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">The XML namespace for fields of the ResourceEvent type. <br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="9bf51f2653400645f7b5087e8c4e1c77"></a><!-- doxytag: member="XMP_Const.h::kXMP_NS_XMP_ResourceRef" ref="9bf51f2653400645f7b5087e8c4e1c77" args="" -->
+#define&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="XMP__Const_8h.html#9bf51f2653400645f7b5087e8c4e1c77">kXMP_NS_XMP_ResourceRef</a>&nbsp;&nbsp;&nbsp;&quot;http://ns.adobe.com/xap/1.0/sType/ResourceRef#&quot;</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">The XML namespace for fields of the ResourceRef type. <br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="b4923bed71ab29c6aa88debe8816c0a2"></a><!-- doxytag: member="XMP_Const.h::kXMP_NS_XMP_ST_Version" ref="b4923bed71ab29c6aa88debe8816c0a2" args="" -->
+#define&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="XMP__Const_8h.html#b4923bed71ab29c6aa88debe8816c0a2">kXMP_NS_XMP_ST_Version</a>&nbsp;&nbsp;&nbsp;&quot;http://ns.adobe.com/xap/1.0/sType/Version#&quot;</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">The XML namespace for fields of the Version type. <br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="c7dc4d65bcbba2862e410cc8cfdff6f6"></a><!-- doxytag: member="XMP_Const.h::kXMP_NS_XMP_ST_Job" ref="c7dc4d65bcbba2862e410cc8cfdff6f6" args="" -->
+#define&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="XMP__Const_8h.html#c7dc4d65bcbba2862e410cc8cfdff6f6">kXMP_NS_XMP_ST_Job</a>&nbsp;&nbsp;&nbsp;&quot;http://ns.adobe.com/xap/1.0/sType/Job#&quot;</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">The XML namespace for fields of the JobRef type. <br></td></tr>
+<tr><td colspan="2"><div class="groupHeader">XML namespace constants from outside Adobe.</div></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="44453f0d0a1dd295d41722c2387b36fa"></a><!-- doxytag: member="XMP_Const.h::kXMP_NS_DC" ref="44453f0d0a1dd295d41722c2387b36fa" args="" -->
+#define&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="XMP__Const_8h.html#44453f0d0a1dd295d41722c2387b36fa">kXMP_NS_DC</a>&nbsp;&nbsp;&nbsp;&quot;http://purl.org/dc/elements/1.1/&quot;</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">The XML namespace for the Dublin Core schema. <br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="b794d3d798daf75a963398347dcbb79b"></a><!-- doxytag: member="XMP_Const.h::kXMP_NS_IPTCCore" ref="b794d3d798daf75a963398347dcbb79b" args="" -->
+#define&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="XMP__Const_8h.html#b794d3d798daf75a963398347dcbb79b">kXMP_NS_IPTCCore</a>&nbsp;&nbsp;&nbsp;&quot;http://iptc.org/std/Iptc4xmpCore/1.0/xmlns/&quot;</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">The XML namespace for the IPTC Core schema. <br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="276fac0f70893607afa3f09030ad84c7"></a><!-- doxytag: member="XMP_Const.h::kXMP_NS_RDF" ref="276fac0f70893607afa3f09030ad84c7" args="" -->
+#define&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="XMP__Const_8h.html#276fac0f70893607afa3f09030ad84c7">kXMP_NS_RDF</a>&nbsp;&nbsp;&nbsp;&quot;http://www.w3.org/1999/02/22-rdf-syntax-ns#&quot;</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">The XML namespace for RDF. <br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="97564c70460d1f235c8a41b8ac40cfe9"></a><!-- doxytag: member="XMP_Const.h::kXMP_NS_XML" ref="97564c70460d1f235c8a41b8ac40cfe9" args="" -->
+#define&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="XMP__Const_8h.html#97564c70460d1f235c8a41b8ac40cfe9">kXMP_NS_XML</a>&nbsp;&nbsp;&nbsp;&quot;http://www.w3.org/XML/1998/namespace&quot;</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">The XML namespace for XML. <br></td></tr>
+<tr><td colspan="2"><br><h2>Typedefs</h2></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">typedef __XMPMeta__ *&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="XMP__Const_8h.html#5912613564f80e17eb10acef9236f70a">XMPMetaRef</a></td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">An "ABI safe" pointer to the internal part of an XMP object. <a href="#5912613564f80e17eb10acef9236f70a"></a><br></td></tr>
+<tr><td colspan="2"><div class="groupHeader">Special purpose callback functions</div></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="91efdc0a7fbe6e1d42ca34e6ce589b98"></a><!-- doxytag: member="XMP_Const.h::XMP_Status" ref="91efdc0a7fbe6e1d42ca34e6ce589b98" args="" -->
+typedef XMP_Int32&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="XMP__Const_8h.html#91efdc0a7fbe6e1d42ca34e6ce589b98">XMP_Status</a></td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">A signed 32 bit integer used as a status result for the output callback routine. Zero means no error, all other values except -1 are private to the callback. The callback is wrapped to prevent exceptions being thrown across DLL boundaries. Any exceptions thrown out of the callback cause a return status of -1. <br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="36eab570ab85ff8fb5789661692d13c2"></a><!-- doxytag: member="XMP_Const.h::XMP_TextOutputProc" ref="36eab570ab85ff8fb5789661692d13c2" args="(void *refCon, XMP_StringPtr buffer, XMP_StringLen bufferSize)" -->
+typedef <a class="el" href="XMP__Const_8h.html#91efdc0a7fbe6e1d42ca34e6ce589b98">XMP_Status</a>(*)&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="XMP__Const_8h.html#36eab570ab85ff8fb5789661692d13c2">XMP_TextOutputProc</a> (void *refCon, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> buffer, <a class="el" href="XMP__Const_8h.html#9f7dcc184f901c713274edfdac5bcc9a">XMP_StringLen</a> bufferSize)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Direct text output from the XMP toolkit, such as debugging dumps, is done using client supplied callbacks. The callback is invoked one or more times for each line of output. The end of a line is signaled by a '<br>
+' character at the end of the buffer. Formatting newlines are never present in the middle of a buffer, but values of properties might contain any UTF-8 characters. A success/fail status is returned by the callback. Any failure result aborts the output. <br></td></tr>
+<tr><td colspan="2"><br><h2>Enumerations</h2></td></tr>
+<tr><td colspan="2"><div class="groupHeader">Exception codes.</div></td></tr>
+<tr><td colspan="2"><div class="groupText">XMP tookit errors result in throwing an <code>XMP_Error</code> exception. Any exception thrown within the XMP toolkit is caught in the toolkit and rethrown as an <code>XMP_Error</code>. The <code>XMP_Error</code> struct contains a numeric code and an English explanation. New numeric codes may be added at any time. There are typically many possible explanations for each numeric code. The explanations try to be precise about the specific circumstances causing the error.<p>
+<dl class="note" compact><dt><b>Note:</b></dt><dd>The explanation string is for debugging use only. It must not be shown to users in a final product. It is written for developers not users, and never localized. </dd></dl>
+<br><br></div></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">enum &nbsp;</td><td class="memItemRight" valign="bottom"></td></tr>
+
+</table>
+<hr><a name="_details"></a><h2>Detailed Description</h2>
+Common C/C++ types and constants for the XMP toolkit.
+<p>
+================================================================================================ <hr><h2>Typedef Documentation</h2>
+<a class="anchor" name="5912613564f80e17eb10acef9236f70a"></a><!-- doxytag: member="XMP_Const.h::XMPMetaRef" ref="5912613564f80e17eb10acef9236f70a" args="" -->
+<div class="memitem">
+<div class="memproto">
+ <table class="memname">
+ <tr>
+ <td class="memname"><a class="el" href="XMP__Const_8h.html#5912613564f80e17eb10acef9236f70a">XMPMetaRef</a> </td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+An "ABI safe" pointer to the internal part of an XMP object.
+<p>
+<code>XMPMetaRef</code> is an "ABI safe" pointer to the internal part of an XMP object. It should be used for passing an XMP object across client DLL boundaries. See the discussion in <code><a class="el" href="TXMPMeta_8hpp.html">TXMPMeta.hpp</a></code>.
+</div>
+</div><p>
+<hr size="1"><address style="align: right;"><small>Generated on Thu May 3 14:54:58 2007 for Adobe XMP Toolkit by&nbsp;
+<a href="http://www.doxygen.org/index.html">
+<img src="doxygen.png" alt="doxygen" align="middle" border="0"></a> 1.5.1 </small></address>
+</body>
+</html>
diff --git a/docs/XMPToolkit/XMP__Const_8h__incl.png b/docs/XMPToolkit/XMP__Const_8h__incl.png
new file mode 100644
index 0000000..c1bdbeb
--- /dev/null
+++ b/docs/XMPToolkit/XMP__Const_8h__incl.png
Binary files differ
diff --git a/docs/XMPToolkit/annotated.html b/docs/XMPToolkit/annotated.html
new file mode 100644
index 0000000..d3cb5e2
--- /dev/null
+++ b/docs/XMPToolkit/annotated.html
@@ -0,0 +1,31 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
+<title>Adobe XMP Toolkit: Class List</title>
+<link href="doxygen.css" rel="stylesheet" type="text/css">
+<link href="tabs.css" rel="stylesheet" type="text/css">
+</head><body>
+<!-- Generated by Doxygen 1.5.1 -->
+<div class="tabs">
+ <ul>
+ <li><a href="index.html"><span>Main&nbsp;Page</span></a></li>
+ <li><a href="modules.html"><span>Modules</span></a></li>
+ <li id="current"><a href="annotated.html"><span>Classes</span></a></li>
+ <li><a href="files.html"><span>Files</span></a></li>
+ </ul></div>
+<div class="tabs">
+ <ul>
+ <li id="current"><a href="annotated.html"><span>Class&nbsp;List</span></a></li>
+ <li><a href="functions.html"><span>Class&nbsp;Members</span></a></li>
+ </ul></div>
+<h1>Adobe XMP Toolkit Class List</h1>Here are the classes, structs, unions and interfaces with brief descriptions:<table>
+ <tr><td class="indexkey"><a class="el" href="classTXMPFiles.html">TXMPFiles&lt; tStringObj &gt;</a></td><td class="indexvalue">API for access to the "main" metadata in a file </td></tr>
+ <tr><td class="indexkey"><a class="el" href="classTXMPIterator.html">TXMPIterator&lt; tStringObj &gt;</a></td><td class="indexvalue">Template class for the XMP Toolkit iteration services </td></tr>
+ <tr><td class="indexkey"><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td class="indexvalue">Template class for the XMP Toolkit core services </td></tr>
+ <tr><td class="indexkey"><a class="el" href="classTXMPUtils.html">TXMPUtils&lt; tStringObj &gt;</a></td><td class="indexvalue">Template class for the XMP Toolkit utility services </td></tr>
+ <tr><td class="indexkey"><a class="el" href="structXMP__DateTime.html">XMP_DateTime</a></td><td class="indexvalue">The expanded type for a date and time. Dates and time in the serialized XMP are ISO 8601 strings. The <code><a class="el" href="structXMP__DateTime.html">XMP_DateTime</a></code> struct allows easy conversion with other formats </td></tr>
+</table>
+<hr size="1"><address style="align: right;"><small>Generated on Thu May 3 14:54:58 2007 for Adobe XMP Toolkit by&nbsp;
+<a href="http://www.doxygen.org/index.html">
+<img src="doxygen.png" alt="doxygen" align="middle" border="0"></a> 1.5.1 </small></address>
+</body>
+</html>
diff --git a/docs/XMPToolkit/classTXMPFiles-members.html b/docs/XMPToolkit/classTXMPFiles-members.html
new file mode 100644
index 0000000..b5deac5
--- /dev/null
+++ b/docs/XMPToolkit/classTXMPFiles-members.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
+<title>Adobe XMP Toolkit: Member List</title>
+<link href="doxygen.css" rel="stylesheet" type="text/css">
+<link href="tabs.css" rel="stylesheet" type="text/css">
+</head><body>
+<!-- Generated by Doxygen 1.5.1 -->
+<div class="tabs">
+ <ul>
+ <li><a href="index.html"><span>Main&nbsp;Page</span></a></li>
+ <li><a href="modules.html"><span>Modules</span></a></li>
+ <li id="current"><a href="annotated.html"><span>Classes</span></a></li>
+ <li><a href="files.html"><span>Files</span></a></li>
+ </ul></div>
+<div class="tabs">
+ <ul>
+ <li><a href="annotated.html"><span>Class&nbsp;List</span></a></li>
+ <li><a href="functions.html"><span>Class&nbsp;Members</span></a></li>
+ </ul></div>
+<h1>TXMPFiles&lt; tStringObj &gt; Member List</h1>This is the complete list of members for <a class="el" href="classTXMPFiles.html">TXMPFiles&lt; tStringObj &gt;</a>, including all inherited members.<p><table>
+ <tr class="memlist"><td><a class="el" href="classTXMPFiles.html#29a11a1539d6300da3fb4c7e9ea02bb6">CanPutXMP</a>(const SXMPMeta &amp;xmpObj)</td><td><a class="el" href="classTXMPFiles.html">TXMPFiles&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPFiles.html#eca89170c7aa3e2d56e30bff04dd7927">CloseFile</a>(XMP_OptionBits closeFlags=0)</td><td><a class="el" href="classTXMPFiles.html">TXMPFiles&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPFiles.html#f9931d081cb19f98c81e41786030765b">GetFileInfo</a>(tStringObj *filePath=0, XMP_OptionBits *openFlags=0, XMP_FileFormat *format=0, XMP_OptionBits *handlerFlags=0)</td><td><a class="el" href="classTXMPFiles.html">TXMPFiles&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPFiles.html#6ac78e3c7286ca8dcb41eaa007aa00e8">GetFormatInfo</a>(XMP_FileFormat format, XMP_OptionBits *handlerFlags=0)</td><td><a class="el" href="classTXMPFiles.html">TXMPFiles&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPFiles.html#4ea1eda39f803322e10b2a554ef8ab06">GetThumbnail</a>(XMP_ThumbnailInfo *tnailInfo)</td><td><a class="el" href="classTXMPFiles.html">TXMPFiles&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPFiles.html#42ca0bbc5ac66a8de1710e03a7ff17b3">GetXMP</a>(SXMPMeta *xmpObj=0, tStringObj *xmpPacket=0, XMP_PacketInfo *packetInfo=0)</td><td><a class="el" href="classTXMPFiles.html">TXMPFiles&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPFiles.html#0874bbbf41c9490abfb613bfe297327d">Initialize</a>()</td><td><a class="el" href="classTXMPFiles.html">TXMPFiles&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPFiles.html#fcd21cfe5d6f13c648c5541e161919cb">OpenFile</a>(XMP_StringPtr filePath, XMP_FileFormat format=kXMP_UnknownFile, XMP_OptionBits openFlags=0)</td><td><a class="el" href="classTXMPFiles.html">TXMPFiles&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPFiles.html#d3f7babdc07c7de0d0cd9a3362b4710a">PutXMP</a>(const SXMPMeta &amp;xmpObj)</td><td><a class="el" href="classTXMPFiles.html">TXMPFiles&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPFiles.html#7b86c130fdbd54b5ac158ec3fee93777">SetAbortProc</a>(XMP_AbortProc abortProc, void *abortArg)</td><td><a class="el" href="classTXMPFiles.html">TXMPFiles&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPFiles.html#1e8de80c252b60b332dc4bc524139fd8">Terminate</a>()</td><td><a class="el" href="classTXMPFiles.html">TXMPFiles&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPFiles.html#14f01e38454178578fd25fff6024fd54">TXMPFiles</a>()</td><td><a class="el" href="classTXMPFiles.html">TXMPFiles&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPFiles.html#36abe01988d4ca3939138e871c7b75e7">TXMPFiles</a>(XMP_StringPtr filePath, XMP_FileFormat format=kXMP_UnknownFile, XMP_OptionBits openFlags=0)</td><td><a class="el" href="classTXMPFiles.html">TXMPFiles&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPFiles.html#cf343fb6771b482ca72d467233a6f920">TXMPFiles</a>(const TXMPFiles&lt; tStringObj &gt; &amp;original)</td><td><a class="el" href="classTXMPFiles.html">TXMPFiles&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPFiles.html#d986c7b2e2d82eaef6cf6a33e9d09b65">TXMPFiles</a>(XMPFilesRef xmpFilesObj)</td><td><a class="el" href="classTXMPFiles.html">TXMPFiles&lt; tStringObj &gt;</a></td><td></td></tr>
+</table><hr size="1"><address style="align: right;"><small>Generated on Thu May 3 14:54:58 2007 for Adobe XMP Toolkit by&nbsp;
+<a href="http://www.doxygen.org/index.html">
+<img src="doxygen.png" alt="doxygen" align="middle" border="0"></a> 1.5.1 </small></address>
+</body>
+</html>
diff --git a/docs/XMPToolkit/classTXMPFiles.html b/docs/XMPToolkit/classTXMPFiles.html
new file mode 100644
index 0000000..689af11
--- /dev/null
+++ b/docs/XMPToolkit/classTXMPFiles.html
@@ -0,0 +1,527 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
+<title>Adobe XMP Toolkit: TXMPFiles&lt; tStringObj &gt; Class Template Reference</title>
+<link href="doxygen.css" rel="stylesheet" type="text/css">
+<link href="tabs.css" rel="stylesheet" type="text/css">
+</head><body>
+<!-- Generated by Doxygen 1.5.1 -->
+<div class="tabs">
+ <ul>
+ <li><a href="index.html"><span>Main&nbsp;Page</span></a></li>
+ <li><a href="modules.html"><span>Modules</span></a></li>
+ <li id="current"><a href="annotated.html"><span>Classes</span></a></li>
+ <li><a href="files.html"><span>Files</span></a></li>
+ </ul></div>
+<div class="tabs">
+ <ul>
+ <li><a href="annotated.html"><span>Class&nbsp;List</span></a></li>
+ <li><a href="functions.html"><span>Class&nbsp;Members</span></a></li>
+ </ul></div>
+<h1>TXMPFiles&lt; tStringObj &gt; Class Template Reference</h1><!-- doxytag: class="TXMPFiles" -->API for access to the "main" metadata in a file.
+<a href="#_details">More...</a>
+<p>
+<code>#include &lt;<a class="el" href="TXMPFiles_8hpp-source.html">TXMPFiles.hpp</a>&gt;</code>
+<p>
+<a href="classTXMPFiles-members.html">List of all members.</a><table border="0" cellpadding="0" cellspacing="0">
+<tr><td></td></tr>
+<tr><td colspan="2"><br><h2>Constructors and destructor</h2></td></tr>
+<tr><td colspan="2">The default constructor initializes an object that is associated with no file. The alternate constructors call OpenFile. The destructor automatically calls CloseFile if necessary. <br><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="14f01e38454178578fd25fff6024fd54"></a><!-- doxytag: member="TXMPFiles::TXMPFiles" ref="14f01e38454178578fd25fff6024fd54" args="()" -->
+&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPFiles.html#14f01e38454178578fd25fff6024fd54">TXMPFiles</a> ()</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">The default constructor initializes an object that is associated with no file. <br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="5eaa92724cc82d933a32eff9c4636739"></a><!-- doxytag: member="TXMPFiles::~TXMPFiles" ref="5eaa92724cc82d933a32eff9c4636739" args="()" -->
+virtual&nbsp;</td><td class="memItemRight" valign="bottom"><b>~TXMPFiles</b> () throw ()</td></tr>
+
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="36abe01988d4ca3939138e871c7b75e7"></a><!-- doxytag: member="TXMPFiles::TXMPFiles" ref="36abe01988d4ca3939138e871c7b75e7" args="(XMP_StringPtr filePath, XMP_FileFormat format=kXMP_UnknownFile, XMP_OptionBits openFlags=0)" -->
+&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPFiles.html#36abe01988d4ca3939138e871c7b75e7">TXMPFiles</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> filePath, XMP_FileFormat format=kXMP_UnknownFile, <a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> openFlags=0)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">These alternate constructors call <code>OpenFile</code>. The second form is a trivial overload that calls the first form passing <code>filePath.c_str()</code>. <br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="f540b3ea689a6d7381dca4f52132a4ac"></a><!-- doxytag: member="TXMPFiles::TXMPFiles" ref="f540b3ea689a6d7381dca4f52132a4ac" args="(const tStringObj &amp;filePath, XMP_FileFormat format=kXMP_UnknownFile, XMP_OptionBits openFlags=0)" -->
+&nbsp;</td><td class="memItemRight" valign="bottom"><b>TXMPFiles</b> (const tStringObj &amp;filePath, XMP_FileFormat format=kXMP_UnknownFile, <a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> openFlags=0)</td></tr>
+
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="cf343fb6771b482ca72d467233a6f920"></a><!-- doxytag: member="TXMPFiles::TXMPFiles" ref="cf343fb6771b482ca72d467233a6f920" args="(const TXMPFiles&lt; tStringObj &gt; &amp;original)" -->
+&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPFiles.html#cf343fb6771b482ca72d467233a6f920">TXMPFiles</a> (const <a class="el" href="classTXMPFiles.html">TXMPFiles</a>&lt; tStringObj &gt; &amp;original)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">The copy constructor and assignment operator increment an internal reference count, they do not perform a deep copy. <br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="3f1483fcc92860460d3772216dfaef81"></a><!-- doxytag: member="TXMPFiles::operator=" ref="3f1483fcc92860460d3772216dfaef81" args="(const TXMPFiles&lt; tStringObj &gt; &amp;rhs)" -->
+void&nbsp;</td><td class="memItemRight" valign="bottom"><b>operator=</b> (const <a class="el" href="classTXMPFiles.html">TXMPFiles</a>&lt; tStringObj &gt; &amp;rhs)</td></tr>
+
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="d986c7b2e2d82eaef6cf6a33e9d09b65"></a><!-- doxytag: member="TXMPFiles::TXMPFiles" ref="d986c7b2e2d82eaef6cf6a33e9d09b65" args="(XMPFilesRef xmpFilesObj)" -->
+&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPFiles.html#d986c7b2e2d82eaef6cf6a33e9d09b65">TXMPFiles</a> (XMPFilesRef xmpFilesObj)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">The "ref" constructor and <code>GetInternalRef</code> serve the same purpose as their analogs in SXMPMeta, safely passing <code>SXMPFiles</code> references across DLL boundaries where the clients might have used different string types when instantiating <code><a class="el" href="classTXMPFiles.html">TXMPFiles</a></code>. <br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="311fc36fdf7270fe05b1c531cdbbd009"></a><!-- doxytag: member="TXMPFiles::GetInternalRef" ref="311fc36fdf7270fe05b1c531cdbbd009" args="()" -->
+XMPFilesRef&nbsp;</td><td class="memItemRight" valign="bottom"><b>GetInternalRef</b> ()</td></tr>
+
+<tr><td colspan="2"><br><h2>Public Member Functions</h2></td></tr>
+<tr><td colspan="2"><div class="groupHeader">OpenFile, CloseFile, and related file-oriented operations</div></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">bool&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPFiles.html#fcd21cfe5d6f13c648c5541e161919cb">OpenFile</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> filePath, XMP_FileFormat format=kXMP_UnknownFile, <a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> openFlags=0)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Open a file for metadata access. <a href="#fcd21cfe5d6f13c648c5541e161919cb"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPFiles.html#eca89170c7aa3e2d56e30bff04dd7927">CloseFile</a> (<a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> closeFlags=0)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Close an opened file. <a href="#eca89170c7aa3e2d56e30bff04dd7927"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">bool&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPFiles.html#f9931d081cb19f98c81e41786030765b">GetFileInfo</a> (tStringObj *filePath=0, <a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> *openFlags=0, XMP_FileFormat *format=0, <a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> *handlerFlags=0)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Get basic information about an opened file. <a href="#f9931d081cb19f98c81e41786030765b"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPFiles.html#7b86c130fdbd54b5ac158ec3fee93777">SetAbortProc</a> (XMP_AbortProc abortProc, void *abortArg)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Set the callback function used to check for a user signaled abort. <a href="#7b86c130fdbd54b5ac158ec3fee93777"></a><br></td></tr>
+<tr><td colspan="2"><div class="groupHeader">Metadata Access Functions</div></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">bool&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPFiles.html#42ca0bbc5ac66a8de1710e03a7ff17b3">GetXMP</a> (SXMPMeta *xmpObj=0, tStringObj *xmpPacket=0, XMP_PacketInfo *packetInfo=0)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Obtain the XMP. <a href="#42ca0bbc5ac66a8de1710e03a7ff17b3"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">bool&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPFiles.html#4ea1eda39f803322e10b2a554ef8ab06">GetThumbnail</a> (XMP_ThumbnailInfo *tnailInfo)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Obtain the native thumbnail. <a href="#4ea1eda39f803322e10b2a554ef8ab06"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPFiles.html#d3f7babdc07c7de0d0cd9a3362b4710a">PutXMP</a> (const SXMPMeta &amp;xmpObj)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Update the XMP. <a href="#d3f7babdc07c7de0d0cd9a3362b4710a"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">bool&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPFiles.html#29a11a1539d6300da3fb4c7e9ea02bb6">CanPutXMP</a> (const SXMPMeta &amp;xmpObj)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Determine if the XMP can be updated. <a href="#29a11a1539d6300da3fb4c7e9ea02bb6"></a><br></td></tr>
+<tr><td colspan="2"><br><h2>Static Public Member Functions</h2></td></tr>
+<tr><td colspan="2"><div class="groupHeader">Initialization and termination</div></td></tr>
+<tr><td colspan="2"><div class="groupText"><code>SXMPFiles</code> must be initialized before use and may be terminated when done. <br><br></div></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="6e521c034728b59ab55213a9d8203d1e"></a><!-- doxytag: member="TXMPFiles::GetVersionInfo" ref="6e521c034728b59ab55213a9d8203d1e" args="(XMP_VersionInfo *versionInfo)" -->
+static void&nbsp;</td><td class="memItemRight" valign="bottom"><b>GetVersionInfo</b> (XMP_VersionInfo *versionInfo)</td></tr>
+
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="0874bbbf41c9490abfb613bfe297327d"></a><!-- doxytag: member="TXMPFiles::Initialize" ref="0874bbbf41c9490abfb613bfe297327d" args="()" -->
+static bool&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPFiles.html#0874bbbf41c9490abfb613bfe297327d">Initialize</a> ()</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight"><code>Initialize</code> must be called before using <code>SXMPFiles</code>. It returns a Boolean success/failure value. <br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="794e1830a84a6328eaa1995ba5aa6874"></a><!-- doxytag: member="TXMPFiles::Initialize" ref="794e1830a84a6328eaa1995ba5aa6874" args="(XMP_OptionBits options)" -->
+static bool&nbsp;</td><td class="memItemRight" valign="bottom"><b>Initialize</b> (<a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options)</td></tr>
+
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="1e8de80c252b60b332dc4bc524139fd8"></a><!-- doxytag: member="TXMPFiles::Terminate" ref="1e8de80c252b60b332dc4bc524139fd8" args="()" -->
+static void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPFiles.html#1e8de80c252b60b332dc4bc524139fd8">Terminate</a> ()</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight"><code>Terminate</code> may be called when done using <code>SXMPFiles</code>. It deallocates global data structures created by <code>Initialize</code>. <br></td></tr>
+<tr><td colspan="2"><div class="groupHeader">Static Functions</div></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">static bool&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPFiles.html#6ac78e3c7286ca8dcb41eaa007aa00e8">GetFormatInfo</a> (XMP_FileFormat format, <a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> *handlerFlags=0)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Determine the supported features for a given file format. <a href="#6ac78e3c7286ca8dcb41eaa007aa00e8"></a><br></td></tr>
+</table>
+<hr><a name="_details"></a><h2>Detailed Description</h2>
+<h3>template&lt;class tStringObj&gt;<br>
+ class TXMPFiles&lt; tStringObj &gt;</h3>
+
+API for access to the "main" metadata in a file.
+<p>
+<code><a class="el" href="classTXMPFiles.html">TXMPFiles</a></code> provides the API for the Adobe XMP Toolkit's File Handler component. This provides convenient access to the main, or document level, XMP for a file. The general model is to open a file, read and write the metadata, then close the file. While open, portions of the file might be maintained in RAM data structures. Memory usage can vary considerably depending on file format and access options. The file may be opened for read-only or read-write access, with typical exclusion for both modes.<p>
+Errors result in the throw of an <code>XMPError</code> exception.<p>
+The template is instantiated with a string object class. This allows a clean implementation that provides two major benefits: output string storage is fully owned by the client and access is fully thread safe. The template parameter, class <code>tStringObj</code>, is described in the XMP.hpp umbrella header.<p>
+To use <a class="el" href="classTXMPFiles.html">TXMPFiles</a> define TXMP_STRING_TYPE and XMP_INCLUDE_XMPFILES, then include the XMP.hpp umbrella header: <div class="fragment"><pre class="fragment"><span class="preprocessor"> #define TXMP_STRING_TYPE std::string</span>
+<span class="preprocessor"></span><span class="preprocessor"> #define XMP_INCLUDE_XMPFILES 1</span>
+<span class="preprocessor"> #include "XMP.hpp"</span>
+</pre></div>
+<p>
+<hr><h2>Member Function Documentation</h2>
+<a class="anchor" name="6ac78e3c7286ca8dcb41eaa007aa00e8"></a><!-- doxytag: member="TXMPFiles::GetFormatInfo" ref="6ac78e3c7286ca8dcb41eaa007aa00e8" args="(XMP_FileFormat format, XMP_OptionBits *handlerFlags=0)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">static bool <a class="el" href="classTXMPFiles.html">TXMPFiles</a>&lt; tStringObj &gt;::GetFormatInfo </td>
+ <td>(</td>
+ <td class="paramtype">XMP_FileFormat&nbsp;</td>
+ <td class="paramname"> <em>format</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> *&nbsp;</td>
+ <td class="paramname"> <em>handlerFlags</em> = <code>0</code></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"><code> [static]</code></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Determine the supported features for a given file format.
+<p>
+The supported features can vary quite a bit among file formats, depending on both the general capabilities of the format and the implementation of the handler for that format.<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>format</em>&nbsp;</td><td>The format whose support flags are desired.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>handlerFlags</em>&nbsp;</td><td>A set of option bits showing the support for this format:</td></tr>
+ </table>
+</dl>
+<ul>
+<li>kXMPFiles_CanInjectXMP - Can inject first-time XMP into an existing file. </li>
+<li>kXMPFiles_CanExpand - Can expand XMP or other metadata in an existing file. </li>
+<li>kXMPFiles_CanRewrite - Can copy one file to another, writing new metadata. </li>
+<li>kXMPFiles_CanReconcile - Supports reconciliation between XMP and other forms. </li>
+<li>kXMPFiles_AllowsOnlyXMP - Allows access to just the XMP, ignoring other forms. </li>
+<li>kXMPFiles_ReturnsRawPacket - File handler returns raw XMP packet information and string. </li>
+<li>kXMPFiles_ReturnsTNail - File handler returns native thumbnail information.</li>
+</ul>
+The kXMPFiles_AllowsOnlyXMP flag is only meaningful if kXMPFiles_CanReconcile is set.<p>
+If kXMPFiles_ReturnsRawPacket is set, the returned packet information might have an offset of -1 to indicate an unknown offset. While all file handlers should be able to return the raw packet, some might not know the offset of the packet within the file. This is typical in cases where external libraries are used. These cases might not even allow return of the raw packet.<p>
+<dl class="return" compact><dt><b>Returns:</b></dt><dd>Returns true if the format has explicit "smart" support. Returns false if the format is handled by the default packet scanning plus heuristics. </dd></dl>
+
+</div>
+</div><p>
+<a class="anchor" name="fcd21cfe5d6f13c648c5541e161919cb"></a><!-- doxytag: member="TXMPFiles::OpenFile" ref="fcd21cfe5d6f13c648c5541e161919cb" args="(XMP_StringPtr filePath, XMP_FileFormat format=kXMP_UnknownFile, XMP_OptionBits openFlags=0)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">bool <a class="el" href="classTXMPFiles.html">TXMPFiles</a>&lt; tStringObj &gt;::OpenFile </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>filePath</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">XMP_FileFormat&nbsp;</td>
+ <td class="paramname"> <em>format</em> = <code>kXMP_UnknownFile</code>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a>&nbsp;</td>
+ <td class="paramname"> <em>openFlags</em> = <code>0</code></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Open a file for metadata access.
+<p>
+Opens a file for the requested forms of metadata access. Opening the file at a minimum causes the raw XMP packet to be read from the file. If the file handler supports legacy metadata reconciliation then legacy metadata will also be read, unless kXMPFiles_OpenOnlyXMP is passed. If the file handler supports native thumbnails and kXMPFiles_OpenCacheTNail is passed then the native thumbnail will also be cached.<p>
+If the file is opened for read-only access (passing kXMPFiles_OpenForRead), then the disk file itself will be closed after reading the data from it. The XMPFiles object will not be "closed" though, it is still necessary to call CloseFile when finished using it. Other methods (GetXMP, etc.) can only be used between the OpenFile and CloseFile calls. The XMPFiles destructor will not call CloseFile, any pending updates will be lost.<p>
+If the file is opened for update (passing kXMPFiles_OpenForUpdate), then the disk file remains open until CloseFile is called. The disk file is only updated once, when Close file is called, no matter how many calls are made to PutXMP.<p>
+Ideally the XMP is not parsed and legacy reconciliation is not performed until GetXMP is called. This is not guaranteed though, specific file handlers might do earlier parsing of the XMP. This delayed parsing and the early disk file close for read-only access are optimizations to help clients implementing file browsers. They can access the file briefly and possibly display a thumbnail, then postpone more expensive XMP processing until later.<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>filePath</em>&nbsp;</td><td>The UTF-8 path for the file, appropriate for the local OS. Overloads are declared to pass the path as either a "const char *" or a string object.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>format</em>&nbsp;</td><td>The format of the file. If the format is unknown pass <code>kXMP_UnknownFile</code> and the format will be determined from the file content. The first handler to check will be guessed from the file's extension. Passing any other format value is generally just a hint about what file handler to try first (instead of the one based on the extension). If the kXMPFiles_OpenStrictly is set, then any format other than kXMP_UnknownFile requires that the file actually be that format, an exception is thrown if not.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>openFlags</em>&nbsp;</td><td>A set of option bits describing the desired access. By default (zero) the file is opened for read-only access and the format handler decides on the level of reconciliation that will be performed. By default a best effort will be made to locate the correct XMP and to reconcile XMP with other forms (if reconciliation is done). The option <code>kXMPFiles_OpenStrictly</code> may be used to force more strict rules, resulting is exceptions for errors. The definition of strictness is specific to each handler, there may be no difference.</td></tr>
+ </table>
+</dl>
+The defined openFlag bits are:<p>
+<ul>
+<li>kXMPFiles_OpenForRead - Open for read-only access. </li>
+<li>kXMPFiles_OpenForUpdate - Open for reading and writing. </li>
+<li>kXMPFiles_OpenOnlyXMP - Only the XMP is wanted, no reconciliation. </li>
+<li>kXMPFiles_OpenCacheTNail - Cache thumbnail if possible, GetThumbnail will be called. </li>
+<li>kXMPFiles_OpenStrictly - Be strict about locating XMP and reconciling with other forms. </li>
+<li>kXMPFiles_OpenUseSmartHandler - Require the use of a smart handler. </li>
+<li>kXMPFiles_OpenUsePacketScanning - Force packet scanning, don't use a smart handler.</li>
+</ul>
+<dl class="return" compact><dt><b>Returns:</b></dt><dd>Returns true if the file is succesfully opened and attached to a file handler. Returns false for "anticipated" problems, e.g. passing kXMPFiles_OpenUseSmartHandler but not having an appropriate smart handler. Throws an exception for serious problems. </dd></dl>
+
+</div>
+</div><p>
+<a class="anchor" name="eca89170c7aa3e2d56e30bff04dd7927"></a><!-- doxytag: member="TXMPFiles::CloseFile" ref="eca89170c7aa3e2d56e30bff04dd7927" args="(XMP_OptionBits closeFlags=0)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">void <a class="el" href="classTXMPFiles.html">TXMPFiles</a>&lt; tStringObj &gt;::CloseFile </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a>&nbsp;</td>
+ <td class="paramname"> <em>closeFlags</em> = <code>0</code> </td>
+ <td>&nbsp;)&nbsp;</td>
+ <td width="100%"></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Close an opened file.
+<p>
+Performs any necessary output to the file and closes it. Files that are opened for update are written to only when closing.<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>closeFlags</em>&nbsp;</td><td>A set of bit flags for optional closing actions.</td></tr>
+ </table>
+</dl>
+The defined closeFlags bits are:<p>
+<ul>
+<li>kXMPFiles_UpdateSafely - Write into a temporary file then swap for crash safety. </li>
+</ul>
+
+</div>
+</div><p>
+<a class="anchor" name="f9931d081cb19f98c81e41786030765b"></a><!-- doxytag: member="TXMPFiles::GetFileInfo" ref="f9931d081cb19f98c81e41786030765b" args="(tStringObj *filePath=0, XMP_OptionBits *openFlags=0, XMP_FileFormat *format=0, XMP_OptionBits *handlerFlags=0)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">bool <a class="el" href="classTXMPFiles.html">TXMPFiles</a>&lt; tStringObj &gt;::GetFileInfo </td>
+ <td>(</td>
+ <td class="paramtype">tStringObj *&nbsp;</td>
+ <td class="paramname"> <em>filePath</em> = <code>0</code>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> *&nbsp;</td>
+ <td class="paramname"> <em>openFlags</em> = <code>0</code>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">XMP_FileFormat *&nbsp;</td>
+ <td class="paramname"> <em>format</em> = <code>0</code>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> *&nbsp;</td>
+ <td class="paramname"> <em>handlerFlags</em> = <code>0</code></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Get basic information about an opened file.
+<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>filePath</em>&nbsp;</td><td>If not null, returns the path passed to OpenFile.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>openFlags</em>&nbsp;</td><td>If not null, returns the flags passed to OpenFile.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>format</em>&nbsp;</td><td>If not null, returns the format of the file.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>handlerFlags</em>&nbsp;</td><td>If not null, returns the handler's capability flags.</td></tr>
+ </table>
+</dl>
+<dl class="return" compact><dt><b>Returns:</b></dt><dd>Returns true if a file is opened, false otherwise. This notion of "open" really means that OpenFile has been called but CloseFile has not. The actual disk file might be closed in the host file system sense, as explained for OpenFile. </dd></dl>
+
+</div>
+</div><p>
+<a class="anchor" name="7b86c130fdbd54b5ac158ec3fee93777"></a><!-- doxytag: member="TXMPFiles::SetAbortProc" ref="7b86c130fdbd54b5ac158ec3fee93777" args="(XMP_AbortProc abortProc, void *abortArg)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">void <a class="el" href="classTXMPFiles.html">TXMPFiles</a>&lt; tStringObj &gt;::SetAbortProc </td>
+ <td>(</td>
+ <td class="paramtype">XMP_AbortProc&nbsp;</td>
+ <td class="paramname"> <em>abortProc</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">void *&nbsp;</td>
+ <td class="paramname"> <em>abortArg</em></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Set the callback function used to check for a user signaled abort.
+<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>abortProc</em>&nbsp;</td><td>The callback function used to check for a user signaled abort. It will be called periodically to allow an abort of time consuming operations. The abort results in an exception being thrown. The callback function should return true to signal an abort.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>abortArg</em>&nbsp;</td><td>An argument passed to the callback function. </td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<a class="anchor" name="42ca0bbc5ac66a8de1710e03a7ff17b3"></a><!-- doxytag: member="TXMPFiles::GetXMP" ref="42ca0bbc5ac66a8de1710e03a7ff17b3" args="(SXMPMeta *xmpObj=0, tStringObj *xmpPacket=0, XMP_PacketInfo *packetInfo=0)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">bool <a class="el" href="classTXMPFiles.html">TXMPFiles</a>&lt; tStringObj &gt;::GetXMP </td>
+ <td>(</td>
+ <td class="paramtype">SXMPMeta *&nbsp;</td>
+ <td class="paramname"> <em>xmpObj</em> = <code>0</code>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">tStringObj *&nbsp;</td>
+ <td class="paramname"> <em>xmpPacket</em> = <code>0</code>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">XMP_PacketInfo *&nbsp;</td>
+ <td class="paramname"> <em>packetInfo</em> = <code>0</code></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Obtain the XMP.
+<p>
+<code>GetXMP</code> is used to obtain the parsed XMP, and/or the raw XMP packet, and/or information about the raw XMP packet. If all parameters are null it simply tells if XMP is present or not. The options provided when the file was opened determine if reconciliation is done with other forms of metadata.<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>xmpObj</em>&nbsp;</td><td>If not null, returns the parsed XMP.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>xmpPacket</em>&nbsp;</td><td>If not null, returns the raw XMP packet as stored in the file. The encoding of the packet is given in the packetInfo. The string will be empty if the low level file handler does not provide the raw packet.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>packetInfo</em>&nbsp;</td><td>If not null, returns the location and form of the raw XMP in the file. The charForm and writeable flag reflect the raw XMP in the file. The parsed XMP property values are always UTF-8. The writeable flag is taken from the packet trailer, it is only relevant for "format ignorant" writing.</td></tr>
+ </table>
+</dl>
+<dl class="note" compact><dt><b>Note:</b></dt><dd>The packetInfo struct always reflects the state of the XMP in the file. The offset, length, and character form will not change as a result of calling <code>PutXMP</code> unless the file is also written.<p>
+Some file handlers might not return location or contents of the raw packet string. Check the <code>kXMPFiles_ReturnsRawPacket</code> bit returned by GetFormatInfo if you depend on this. If the low level file handler does not provide the raw packet location then the offset and length will both be 0, the charForm will be UTF-8, and the writeable flag will be false.</dd></dl>
+<dl class="return" compact><dt><b>Returns:</b></dt><dd>Returns true if the file has XMP, false otherwise. </dd></dl>
+
+</div>
+</div><p>
+<a class="anchor" name="4ea1eda39f803322e10b2a554ef8ab06"></a><!-- doxytag: member="TXMPFiles::GetThumbnail" ref="4ea1eda39f803322e10b2a554ef8ab06" args="(XMP_ThumbnailInfo *tnailInfo)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">bool <a class="el" href="classTXMPFiles.html">TXMPFiles</a>&lt; tStringObj &gt;::GetThumbnail </td>
+ <td>(</td>
+ <td class="paramtype">XMP_ThumbnailInfo *&nbsp;</td>
+ <td class="paramname"> <em>tnailInfo</em> </td>
+ <td>&nbsp;)&nbsp;</td>
+ <td width="100%"></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Obtain the native thumbnail.
+<p>
+<code>GetThumbnail</code> is used to obtain native thumbnail information, if the associated file handler supports that and the thumbnail was cached by OpenFile. This requires that kXMPFiles_OpenCacheTNail be passed to OpenFile. The tnailInfo output pointer can be null, in which case GetThumbnail will simply tell if a recognized native thumbnail is present.<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>tnailInfo</em>&nbsp;</td><td>If not null, returns information about a recognized native thumbnail, and some related information about the primary image if appropriate.</td></tr>
+ </table>
+</dl>
+<dl class="note" compact><dt><b>Note:</b></dt><dd>The returned thumbnail information can be incomplete. What gets returned can depend on the file format, the file handler's capabilities, and the specific file content.</dd></dl>
+<ul>
+<li>The fullHeight, fullWIdth, and fullOrientation fields are only meaningful for image files. They are not meaningful for multi-page files such as PDF or InDesign, for dynamic audio or video files, etc. The fields will be zero if not meaningful or not determined.</li>
+</ul>
+<ul>
+<li>The tnailImage and tnailSize fields might be zero even if a "recognized" thumbnail is present. Being recognized means only that the handler has determined that the file does contain a native thumbnail. The thumbnail data might be of a format that the file handler cannot (or does not) return a single contiguous block of thumbnail data. A possible case of this is a TIFF uncompressed thumbnail, the handler might not have logic to gather the various disjoint pieces of the thumbnail from the overall TIFF stream.</li>
+</ul>
+<dl class="return" compact><dt><b>Returns:</b></dt><dd>Returns true if a recognized native thumbnail is presentand the thumbnail was cached by OpenFile. This requires that kXMPFiles_OpenCacheTNail be passed to OpenFile. Note that GetThumbnail can return true but still not return an actual thumbnail image, see the above note. </dd></dl>
+
+</div>
+</div><p>
+<a class="anchor" name="d3f7babdc07c7de0d0cd9a3362b4710a"></a><!-- doxytag: member="TXMPFiles::PutXMP" ref="d3f7babdc07c7de0d0cd9a3362b4710a" args="(const SXMPMeta &amp;xmpObj)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">void <a class="el" href="classTXMPFiles.html">TXMPFiles</a>&lt; tStringObj &gt;::PutXMP </td>
+ <td>(</td>
+ <td class="paramtype">const SXMPMeta &amp;&nbsp;</td>
+ <td class="paramname"> <em>xmpObj</em> </td>
+ <td>&nbsp;)&nbsp;</td>
+ <td width="100%"></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Update the XMP.
+<p>
+<code>PutXMP</code> supplies new XMP for the file. However, the file is not actully written until closed. The options provided when the file was opened determine if reconciliation is done with other forms of metadata. Overloads are provided to pass the XMP as an XMP object, a string object, or a "const char *" plus length.
+</div>
+</div><p>
+<a class="anchor" name="29a11a1539d6300da3fb4c7e9ea02bb6"></a><!-- doxytag: member="TXMPFiles::CanPutXMP" ref="29a11a1539d6300da3fb4c7e9ea02bb6" args="(const SXMPMeta &amp;xmpObj)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">bool <a class="el" href="classTXMPFiles.html">TXMPFiles</a>&lt; tStringObj &gt;::CanPutXMP </td>
+ <td>(</td>
+ <td class="paramtype">const SXMPMeta &amp;&nbsp;</td>
+ <td class="paramname"> <em>xmpObj</em> </td>
+ <td>&nbsp;)&nbsp;</td>
+ <td width="100%"></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Determine if the XMP can be updated.
+<p>
+<code>CanPutXMP</code> determines if the XMP can (probably) be updated. The provided XMP is only used to obtain the length of the serialized packet. The new XMP is not kept, calling this will not cause the file to be written when closed. Overloads are provided to pass the XMP as an XMP object, a string object, or a "const char *" plus length. This is implemented roughly as:<p>
+<div class="fragment"><pre class="fragment"> <span class="keywordtype">bool</span> <a class="code" href="classTXMPFiles.html#29a11a1539d6300da3fb4c7e9ea02bb6">CanPutXMP</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> xmpPacket )
+ {
+ XMP_FileFormat format;
+ this-&gt;<a class="code" href="classTXMPFiles.html#f9931d081cb19f98c81e41786030765b">GetFileInfo</a> ( 0, &amp;format, 0 );
+
+ <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> formatFlags;
+ <a class="code" href="classTXMPFiles.html#6ac78e3c7286ca8dcb41eaa007aa00e8">GetFormatInfo</a> ( format, &amp;formatFlags );
+
+ <span class="keywordflow">if</span> ( (formatFlags &amp; kXMPFiles_CanInjectXMP) &amp;&amp; (formatFlags &amp; kXMPFiles_CanExpand) ) <span class="keywordflow">return</span> <span class="keyword">true</span>;
+
+ XMP_PacketInfo packetInfo;
+ <span class="keywordtype">bool</span> hasXMP = this-&gt;<a class="code" href="classTXMPFiles.html#42ca0bbc5ac66a8de1710e03a7ff17b3">GetXMP</a> ( 0, 0, &amp;packetInfo );
+
+ <span class="keywordflow">if</span> ( ! hasXMP ) {
+ <span class="keywordflow">if</span> ( formatFlags &amp; kXMPFiles_CanInjectXMP ) <span class="keywordflow">return</span> <span class="keyword">true</span>;
+ } <span class="keywordflow">else</span> {
+ <span class="keywordflow">if</span> ( (formatFlags &amp; kXMPFiles_CanExpand) ||
+ (packetInfo.length &gt;= strlen(xmpPacket)) ) <span class="keywordflow">return</span> <span class="keyword">true</span>;
+ }
+
+ <span class="keywordflow">return</span> <span class="keyword">false</span>;
+
+ }
+</pre></div>
+</div>
+</div><p>
+<hr>The documentation for this class was generated from the following file:<ul>
+<li><a class="el" href="TXMPFiles_8hpp-source.html">TXMPFiles.hpp</a></ul>
+<hr size="1"><address style="align: right;"><small>Generated on Thu May 3 14:54:58 2007 for Adobe XMP Toolkit by&nbsp;
+<a href="http://www.doxygen.org/index.html">
+<img src="doxygen.png" alt="doxygen" align="middle" border="0"></a> 1.5.1 </small></address>
+</body>
+</html>
diff --git a/docs/XMPToolkit/classTXMPIterator-members.html b/docs/XMPToolkit/classTXMPIterator-members.html
new file mode 100644
index 0000000..6f822f8
--- /dev/null
+++ b/docs/XMPToolkit/classTXMPIterator-members.html
@@ -0,0 +1,32 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
+<title>Adobe XMP Toolkit: Member List</title>
+<link href="doxygen.css" rel="stylesheet" type="text/css">
+<link href="tabs.css" rel="stylesheet" type="text/css">
+</head><body>
+<!-- Generated by Doxygen 1.5.1 -->
+<div class="tabs">
+ <ul>
+ <li><a href="index.html"><span>Main&nbsp;Page</span></a></li>
+ <li><a href="modules.html"><span>Modules</span></a></li>
+ <li id="current"><a href="annotated.html"><span>Classes</span></a></li>
+ <li><a href="files.html"><span>Files</span></a></li>
+ </ul></div>
+<div class="tabs">
+ <ul>
+ <li><a href="annotated.html"><span>Class&nbsp;List</span></a></li>
+ <li><a href="functions.html"><span>Class&nbsp;Members</span></a></li>
+ </ul></div>
+<h1>TXMPIterator&lt; tStringObj &gt; Member List</h1>This is the complete list of members for <a class="el" href="classTXMPIterator.html">TXMPIterator&lt; tStringObj &gt;</a>, including all inherited members.<p><table>
+ <tr class="memlist"><td><a class="el" href="classTXMPIterator.html#124a1dd1ab3ff0d236e4d4b967dafcd9">Next</a>(tStringObj *schemaNS=0, tStringObj *propPath=0, tStringObj *propValue=0, XMP_OptionBits *options=0)</td><td><a class="el" href="classTXMPIterator.html">TXMPIterator&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPIterator.html#d767d731320d3f4c997c6ce9f7f8fa63">operator=</a>(const TXMPIterator&lt; tStringObj &gt; &amp;rhs)</td><td><a class="el" href="classTXMPIterator.html">TXMPIterator&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPIterator.html#30b4d78974b347e4fcd275f1f65a61b2">Skip</a>(XMP_OptionBits options)</td><td><a class="el" href="classTXMPIterator.html">TXMPIterator&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPIterator.html#88e855c18b2b15f7b8a5ccf3b9398352">TXMPIterator</a>(const TXMPIterator&lt; tStringObj &gt; &amp;original)</td><td><a class="el" href="classTXMPIterator.html">TXMPIterator&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPIterator.html#5c1bd03e776a91cbb6fd02991fe08e1b">TXMPIterator</a>(const TXMPMeta&lt; tStringObj &gt; &amp;xmpObj, XMP_StringPtr schemaNS, XMP_StringPtr propName, XMP_OptionBits options=0)</td><td><a class="el" href="classTXMPIterator.html">TXMPIterator&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPIterator.html#6b2b7a3d6359aec216adf32bdf7fb140">TXMPIterator</a>(XMP_StringPtr schemaNS, XMP_StringPtr propName, XMP_OptionBits options)</td><td><a class="el" href="classTXMPIterator.html">TXMPIterator&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPIterator.html#911554533e8a3f09ab8870bd54462196">~TXMPIterator</a>()</td><td><a class="el" href="classTXMPIterator.html">TXMPIterator&lt; tStringObj &gt;</a></td><td><code> [virtual]</code></td></tr>
+</table><hr size="1"><address style="align: right;"><small>Generated on Thu May 3 14:54:58 2007 for Adobe XMP Toolkit by&nbsp;
+<a href="http://www.doxygen.org/index.html">
+<img src="doxygen.png" alt="doxygen" align="middle" border="0"></a> 1.5.1 </small></address>
+</body>
+</html>
diff --git a/docs/XMPToolkit/classTXMPIterator.html b/docs/XMPToolkit/classTXMPIterator.html
new file mode 100644
index 0000000..195b213
--- /dev/null
+++ b/docs/XMPToolkit/classTXMPIterator.html
@@ -0,0 +1,328 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
+<title>Adobe XMP Toolkit: TXMPIterator&lt; tStringObj &gt; Class Template Reference</title>
+<link href="doxygen.css" rel="stylesheet" type="text/css">
+<link href="tabs.css" rel="stylesheet" type="text/css">
+</head><body>
+<!-- Generated by Doxygen 1.5.1 -->
+<div class="tabs">
+ <ul>
+ <li><a href="index.html"><span>Main&nbsp;Page</span></a></li>
+ <li><a href="modules.html"><span>Modules</span></a></li>
+ <li id="current"><a href="annotated.html"><span>Classes</span></a></li>
+ <li><a href="files.html"><span>Files</span></a></li>
+ </ul></div>
+<div class="tabs">
+ <ul>
+ <li><a href="annotated.html"><span>Class&nbsp;List</span></a></li>
+ <li><a href="functions.html"><span>Class&nbsp;Members</span></a></li>
+ </ul></div>
+<h1>TXMPIterator&lt; tStringObj &gt; Class Template Reference</h1><!-- doxytag: class="TXMPIterator" -->Template class for the XMP Toolkit iteration services.
+<a href="#_details">More...</a>
+<p>
+<code>#include &lt;<a class="el" href="TXMPIterator_8hpp-source.html">TXMPIterator.hpp</a>&gt;</code>
+<p>
+<a href="classTXMPIterator-members.html">List of all members.</a><table border="0" cellpadding="0" cellspacing="0">
+<tr><td></td></tr>
+<tr><td colspan="2"><br><h2>Public Member Functions</h2></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPIterator.html#d767d731320d3f4c997c6ce9f7f8fa63">operator=</a> (const <a class="el" href="classTXMPIterator.html">TXMPIterator</a>&lt; tStringObj &gt; &amp;rhs)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Assignment operator, assigns the internal ref and increments the ref count. <a href="#d767d731320d3f4c997c6ce9f7f8fa63"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPIterator.html#88e855c18b2b15f7b8a5ccf3b9398352">TXMPIterator</a> (const <a class="el" href="classTXMPIterator.html">TXMPIterator</a>&lt; tStringObj &gt; &amp;original)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Copy constructor, creates a client object refering to the same internal object. <a href="#88e855c18b2b15f7b8a5ccf3b9398352"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPIterator.html#5c1bd03e776a91cbb6fd02991fe08e1b">TXMPIterator</a> (const <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt; &amp;xmpObj, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> propName, <a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options=0)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Construct an iterator for the properties within an XMP object. <a href="#5c1bd03e776a91cbb6fd02991fe08e1b"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPIterator.html#6b2b7a3d6359aec216adf32bdf7fb140">TXMPIterator</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> propName, <a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Construct an iterator for the global tables of the XMP toolkit. <a href="#6b2b7a3d6359aec216adf32bdf7fb140"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="911554533e8a3f09ab8870bd54462196"></a><!-- doxytag: member="TXMPIterator::~TXMPIterator" ref="911554533e8a3f09ab8870bd54462196" args="()" -->
+virtual&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPIterator.html#911554533e8a3f09ab8870bd54462196">~TXMPIterator</a> () throw ()</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Destructor, typical virtual destructor. <br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">bool&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPIterator.html#124a1dd1ab3ff0d236e4d4b967dafcd9">Next</a> (tStringObj *schemaNS=0, tStringObj *propPath=0, tStringObj *propValue=0, <a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> *options=0)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Visit the next node in the iteration. <a href="#124a1dd1ab3ff0d236e4d4b967dafcd9"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPIterator.html#30b4d78974b347e4fcd275f1f65a61b2">Skip</a> (<a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Skip some portion of the remaining iterations. <a href="#30b4d78974b347e4fcd275f1f65a61b2"></a><br></td></tr>
+</table>
+<hr><a name="_details"></a><h2>Detailed Description</h2>
+<h3>template&lt;class tStringObj&gt;<br>
+ class TXMPIterator&lt; tStringObj &gt;</h3>
+
+Template class for the XMP Toolkit iteration services.
+<p>
+This template class provides iteration services for the XMP Toolkit. It should be instantiated with a string class such as <code>std::string</code>. Please read the general usage notes for information on the overall architecture of the XMP API.<p>
+<code><a class="el" href="classTXMPIterator.html">TXMPIterator</a></code> provides a uniform means to iterate over several XMP data structures, including the schema and properties within an XMP object plus global tables such as registered namespaces. The template wraps a string class around the raw XMP API, so that output strings are automatically copied and access is fully thread safe. String objects are only necessary for output strings. Input string are literals and passed as typical C <code>const char *</code>.<p>
+The template parameter, class <code>TtStringObj</code>, is described in the XMP.hpp umbrella header.<p>
+<dl class="note" compact><dt><b>Note:</b></dt><dd>Only XMP object iteration is implemented at this time. There are no table iterators yet.</dd></dl>
+Iteration over the schema and properties within an XMP object is the most important and complex use of <code>TTXMPIterator</code>. It is helpful to have a thorough understanding of the XMP data tree. One way to learn this is to create some complex XMP and examine the output of <code><a class="el" href="classTXMPMeta.html#976c1eb889f44080f76628805712b618">TXMPMeta::DumpObject</a></code>. This is also described in the XMP Specification, in the XMP Data Model chapter.<p>
+The top of the XMP data tree is a single root node. This does not explicitly appear in the dump and is never visited by an iterator (that is, it is never returned from <code><a class="el" href="classTXMPIterator.html#124a1dd1ab3ff0d236e4d4b967dafcd9">TXMPIterator::Next</a></code>). Beneath the root are schema nodes. These are just collectors for top level properties in the same namespace. They are created and destroyed implicitly. Beneath the schema nodes are the property nodes. The nodes below a property node depend on its type (simple, struct, or array) and whether it has qualifiers.<p>
+A <code><a class="el" href="classTXMPIterator.html">TXMPIterator</a></code> constructor defines a starting point for the iteration and options that control how it proceeds. By default the iteration starts at the root and visits all nodes beneath it in a depth first manner. The root node is not visited, the first visited node is a schema node. You can provide a schema name or property path to select a different starting node. By default this visits the named root node first then all nodes beneath it in a depth first manner.<p>
+The <code><a class="el" href="classTXMPIterator.html#124a1dd1ab3ff0d236e4d4b967dafcd9">TXMPIterator::Next</a></code> method delivers the schema URI, path, and option flags for the node being visited. If the node is simple it also delivers the value. Qualifiers for this node are visited next. The fields of a struct or items of an array are visited after the qualifiers of the parent.<p>
+The options to control the iteration are:<p>
+<ul>
+<li><code>kXMP_IterJustChildren</code> - Visit just the immediate children of the root. Skip the root itself and all nodes below the immediate children. This omits the qualifiers of the immediate children, the qualifier nodes being below what they qualify.</li>
+</ul>
+<ul>
+<li><code>kXMP_IterJustLeafNodes</code> - Visit just the leaf property nodes and their qualifiers.</li>
+</ul>
+<ul>
+<li><code>kXMP_IterJustLeafName</code> - Return just the leaf component of the node names. The default is to return the full path name.</li>
+</ul>
+<ul>
+<li><code>kXMP_IterIncludeAliases</code> - Include aliases as part of the iteration. Since aliases are not actual nodes the default iteration does not visit them.</li>
+</ul>
+<ul>
+<li><code>kXMP_IterOmitQualifiers</code> - Do not visit the qualifiers of a node. </li>
+</ul>
+
+<p>
+<hr><h2>Constructor &amp; Destructor Documentation</h2>
+<a class="anchor" name="88e855c18b2b15f7b8a5ccf3b9398352"></a><!-- doxytag: member="TXMPIterator::TXMPIterator" ref="88e855c18b2b15f7b8a5ccf3b9398352" args="(const TXMPIterator&lt; tStringObj &gt; &amp;original)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname"><a class="el" href="classTXMPIterator.html">TXMPIterator</a>&lt; tStringObj &gt;::<a class="el" href="classTXMPIterator.html">TXMPIterator</a> </td>
+ <td>(</td>
+ <td class="paramtype">const <a class="el" href="classTXMPIterator.html">TXMPIterator</a>&lt; tStringObj &gt; &amp;&nbsp;</td>
+ <td class="paramname"> <em>original</em> </td>
+ <td>&nbsp;)&nbsp;</td>
+ <td width="100%"></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Copy constructor, creates a client object refering to the same internal object.
+<p>
+The copy constructor creates a new client iterator that refers to the same underlying iterator.
+</div>
+</div><p>
+<a class="anchor" name="5c1bd03e776a91cbb6fd02991fe08e1b"></a><!-- doxytag: member="TXMPIterator::TXMPIterator" ref="5c1bd03e776a91cbb6fd02991fe08e1b" args="(const TXMPMeta&lt; tStringObj &gt; &amp;xmpObj, XMP_StringPtr schemaNS, XMP_StringPtr propName, XMP_OptionBits options=0)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname"><a class="el" href="classTXMPIterator.html">TXMPIterator</a>&lt; tStringObj &gt;::<a class="el" href="classTXMPIterator.html">TXMPIterator</a> </td>
+ <td>(</td>
+ <td class="paramtype">const <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt; &amp;&nbsp;</td>
+ <td class="paramname"> <em>xmpObj</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>schemaNS</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>propName</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a>&nbsp;</td>
+ <td class="paramname"> <em>options</em> = <code>0</code></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Construct an iterator for the properties within an XMP object.
+<p>
+Construct an iterator for the properties within an XMP object. The general operation of an XMP object iterator was described above. Overloaded forms are provided to iterate the entire data tree, properties within a specific schema, or a subtree rooted at a specific node.<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>xmpObj</em>&nbsp;</td><td>The XMP object over which to iterate.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>schemaNS</em>&nbsp;</td><td>Optional schema namespace URI to restrict the iteration. Omitted (visit all schema) by passing 0 or "".</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>propName</em>&nbsp;</td><td>Optional property name to restrict the iteration. May be an arbitrary path expression. Omitted (visit all properties) by passing 0 or "". If not null/empty a schema URI must also be provided.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>options</em>&nbsp;</td><td>Option flags to control the iteration.</td></tr>
+ </table>
+</dl>
+The available option flags are:<p>
+<ul>
+<li><code>kXMP_IterJustChildren</code> - Just visit the immediate children of the root, default is subtree. </li>
+<li><code>kXMP_IterJustLeafNodes</code> - Just visit the leaf nodes, default visits all nodes. </li>
+<li><code>kXMP_IterJustLeafName</code> - Return just the leaf part of the path, default is the full path. </li>
+<li><code>kXMP_IterOmitQualifiers</code> - Omit all qualifiers. </li>
+</ul>
+
+</div>
+</div><p>
+<a class="anchor" name="6b2b7a3d6359aec216adf32bdf7fb140"></a><!-- doxytag: member="TXMPIterator::TXMPIterator" ref="6b2b7a3d6359aec216adf32bdf7fb140" args="(XMP_StringPtr schemaNS, XMP_StringPtr propName, XMP_OptionBits options)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname"><a class="el" href="classTXMPIterator.html">TXMPIterator</a>&lt; tStringObj &gt;::<a class="el" href="classTXMPIterator.html">TXMPIterator</a> </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>schemaNS</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>propName</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a>&nbsp;</td>
+ <td class="paramname"> <em>options</em></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Construct an iterator for the global tables of the XMP toolkit.
+<p>
+<dl class="note" compact><dt><b>Note:</b></dt><dd><b>Not yet implemented.</b> File a bug if you need this. </dd></dl>
+
+</div>
+</div><p>
+<hr><h2>Member Function Documentation</h2>
+<a class="anchor" name="d767d731320d3f4c997c6ce9f7f8fa63"></a><!-- doxytag: member="TXMPIterator::operator=" ref="d767d731320d3f4c997c6ce9f7f8fa63" args="(const TXMPIterator&lt; tStringObj &gt; &amp;rhs)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">void <a class="el" href="classTXMPIterator.html">TXMPIterator</a>&lt; tStringObj &gt;::operator= </td>
+ <td>(</td>
+ <td class="paramtype">const <a class="el" href="classTXMPIterator.html">TXMPIterator</a>&lt; tStringObj &gt; &amp;&nbsp;</td>
+ <td class="paramname"> <em>rhs</em> </td>
+ <td>&nbsp;)&nbsp;</td>
+ <td width="100%"></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Assignment operator, assigns the internal ref and increments the ref count.
+<p>
+The assignment operator assigns the internal ref from the rhs object and increments the reference count on the underlying internal XMP iterator.
+</div>
+</div><p>
+<a class="anchor" name="124a1dd1ab3ff0d236e4d4b967dafcd9"></a><!-- doxytag: member="TXMPIterator::Next" ref="124a1dd1ab3ff0d236e4d4b967dafcd9" args="(tStringObj *schemaNS=0, tStringObj *propPath=0, tStringObj *propValue=0, XMP_OptionBits *options=0)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">bool <a class="el" href="classTXMPIterator.html">TXMPIterator</a>&lt; tStringObj &gt;::Next </td>
+ <td>(</td>
+ <td class="paramtype">tStringObj *&nbsp;</td>
+ <td class="paramname"> <em>schemaNS</em> = <code>0</code>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">tStringObj *&nbsp;</td>
+ <td class="paramname"> <em>propPath</em> = <code>0</code>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">tStringObj *&nbsp;</td>
+ <td class="paramname"> <em>propValue</em> = <code>0</code>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> *&nbsp;</td>
+ <td class="paramname"> <em>options</em> = <code>0</code></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Visit the next node in the iteration.
+<p>
+<dl class="return" compact><dt><b>Returns:</b></dt><dd>Returns true if there was another node to visit, false if the iteration is done.</dd></dl>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>schemaNS</em>&nbsp;</td><td>A pointer to the string that is assigned the schema namespace URI of the current property. May be null if the value is not wanted.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>propPath</em>&nbsp;</td><td>A pointer to the string that is assigned the XPath name of the current property. May be null if the value is not wanted.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>propValue</em>&nbsp;</td><td>A pointer to the string that is assigned the value of the current property. May be null if the value is not wanted.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>options</em>&nbsp;</td><td>A pointer to the XMP_OptionBits variable that is assigned the flags describing the current property. </td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<a class="anchor" name="30b4d78974b347e4fcd275f1f65a61b2"></a><!-- doxytag: member="TXMPIterator::Skip" ref="30b4d78974b347e4fcd275f1f65a61b2" args="(XMP_OptionBits options)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">void <a class="el" href="classTXMPIterator.html">TXMPIterator</a>&lt; tStringObj &gt;::Skip </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a>&nbsp;</td>
+ <td class="paramname"> <em>options</em> </td>
+ <td>&nbsp;)&nbsp;</td>
+ <td width="100%"></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Skip some portion of the remaining iterations.
+<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>options</em>&nbsp;</td><td>Option flags to control the iteration.</td></tr>
+ </table>
+</dl>
+The available option flags are:<p>
+<ul>
+<li><code>kXMP_IterSkipSubtree</code> - Skip the subtree below the current node. </li>
+<li><code>kXMP_IterSkipSiblings</code> - Skip the subtree below and remaining siblings of the current node. </li>
+</ul>
+
+</div>
+</div><p>
+<hr>The documentation for this class was generated from the following file:<ul>
+<li><a class="el" href="TXMPIterator_8hpp-source.html">TXMPIterator.hpp</a></ul>
+<hr size="1"><address style="align: right;"><small>Generated on Thu May 3 14:54:58 2007 for Adobe XMP Toolkit by&nbsp;
+<a href="http://www.doxygen.org/index.html">
+<img src="doxygen.png" alt="doxygen" align="middle" border="0"></a> 1.5.1 </small></address>
+</body>
+</html>
diff --git a/docs/XMPToolkit/classTXMPMeta-members.html b/docs/XMPToolkit/classTXMPMeta-members.html
new file mode 100644
index 0000000..8df4145
--- /dev/null
+++ b/docs/XMPToolkit/classTXMPMeta-members.html
@@ -0,0 +1,93 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
+<title>Adobe XMP Toolkit: Member List</title>
+<link href="doxygen.css" rel="stylesheet" type="text/css">
+<link href="tabs.css" rel="stylesheet" type="text/css">
+</head><body>
+<!-- Generated by Doxygen 1.5.1 -->
+<div class="tabs">
+ <ul>
+ <li><a href="index.html"><span>Main&nbsp;Page</span></a></li>
+ <li><a href="modules.html"><span>Modules</span></a></li>
+ <li id="current"><a href="annotated.html"><span>Classes</span></a></li>
+ <li><a href="files.html"><span>Files</span></a></li>
+ </ul></div>
+<div class="tabs">
+ <ul>
+ <li><a href="annotated.html"><span>Class&nbsp;List</span></a></li>
+ <li><a href="functions.html"><span>Class&nbsp;Members</span></a></li>
+ </ul></div>
+<h1>TXMPMeta&lt; tStringObj &gt; Member List</h1>This is the complete list of members for <a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a>, including all inherited members.<p><table>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#00d7314dc970ad390499ce9db27d314a">AppendArrayItem</a>(XMP_StringPtr schemaNS, XMP_StringPtr arrayName, XMP_OptionBits arrayOptions, XMP_StringPtr itemValue, XMP_OptionBits itemOptions=0)</td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#4f768a8cb35cabff1cf4187aa6a88dd3">AppendArrayItem</a>(XMP_StringPtr schemaNS, XMP_StringPtr arrayName, XMP_OptionBits arrayOptions, const tStringObj &amp;itemValue, XMP_OptionBits itemOptions=0)</td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#6ca653436995bbb76315efe7934afd4c">Clone</a>(XMP_OptionBits options=0) const </td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#b79aae864b3ce190d0699252f48e0acc">CountArrayItems</a>(XMP_StringPtr schemaNS, XMP_StringPtr arrayName) const </td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#af64964e983235247ef65c86a42a4675">DeleteAlias</a>(XMP_StringPtr aliasNS, XMP_StringPtr aliasProp)</td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#bc1211f47225b5973a170ff952743264">DeleteArrayItem</a>(XMP_StringPtr schemaNS, XMP_StringPtr arrayName, XMP_Index itemIndex)</td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#3f989597e95db929676273cacd4ea09a">DeleteNamespace</a>(XMP_StringPtr namespaceURI)</td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#c8b555ba99904fa49bb4851a60cc3844">DeleteProperty</a>(XMP_StringPtr schemaNS, XMP_StringPtr propName)</td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#8ce15f7de7fd3b258f07158ab5fa88be">DeleteQualifier</a>(XMP_StringPtr schemaNS, XMP_StringPtr propName, XMP_StringPtr qualNS, XMP_StringPtr qualName)</td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#bc258e027780a15be65a88fcfd4e1fd4">DeleteStructField</a>(XMP_StringPtr schemaNS, XMP_StringPtr structName, XMP_StringPtr fieldNS, XMP_StringPtr fieldName)</td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#492465c588d6d4cb8e30f94790e66f58">DoesArrayItemExist</a>(XMP_StringPtr schemaNS, XMP_StringPtr arrayName, XMP_Index itemIndex) const </td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#f22b116d71ecbbebea016ec5337e7066">DoesPropertyExist</a>(XMP_StringPtr schemaNS, XMP_StringPtr propName) const </td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#81347a92becd387a14f4d47c582f129a">DoesQualifierExist</a>(XMP_StringPtr schemaNS, XMP_StringPtr propName, XMP_StringPtr qualNS, XMP_StringPtr qualName) const </td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#9261b80d62e77a10ff1a89843bfa10a5">DoesStructFieldExist</a>(XMP_StringPtr schemaNS, XMP_StringPtr structName, XMP_StringPtr fieldNS, XMP_StringPtr fieldName) const </td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#afb027f200b85467298d237a0c23949b">DumpAliases</a>(XMP_TextOutputProc outProc, void *refCon)</td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#44250140a710c0b7c5cc0881e387d004">DumpNamespaces</a>(XMP_TextOutputProc outProc, void *refCon)</td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#976c1eb889f44080f76628805712b618">DumpObject</a>(XMP_TextOutputProc outProc, void *refCon) const </td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#c64a4251d157937f69b73f2ffac4f7cc">GetArrayItem</a>(XMP_StringPtr schemaNS, XMP_StringPtr arrayName, XMP_Index itemIndex, tStringObj *itemValue, XMP_OptionBits *options) const </td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#12b2435ba039c62a164951948c016eb4">GetGlobalOptions</a>()</td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#4d35b44f1f017a27772ee902a3dacf04">GetInternalRef</a>() const</td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#eefe49bbf669770d769f4fe0ea566bd0">GetLocalizedText</a>(XMP_StringPtr schemaNS, XMP_StringPtr altTextName, XMP_StringPtr genericLang, XMP_StringPtr specificLang, tStringObj *actualLang, tStringObj *itemValue, XMP_OptionBits *options) const </td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#f28589472d8c0397db6cef868f2b8c97">GetNamespacePrefix</a>(XMP_StringPtr namespaceURI, tStringObj *namespacePrefix)</td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#a20c84e7549d0a3252fa29a1e83a757a">GetNamespaceURI</a>(XMP_StringPtr namespacePrefix, tStringObj *namespaceURI)</td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#b0d179ed95487d4fd4f2680c1fbe0d40">GetObjectName</a>(tStringObj *name) const </td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#39aeaf9eb83cfc1c5455807b95f055f9">GetObjectOptions</a>() const</td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#06a3241c7fa5df87f61dff02fca23a0c">GetProperty</a>(XMP_StringPtr schemaNS, XMP_StringPtr propName, tStringObj *propValue, XMP_OptionBits *options) const </td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#dcf8a1959a8bd42641a42cbd4d64a5b7">GetProperty_Bool</a>(XMP_StringPtr schemaNS, XMP_StringPtr propName, bool *propValue, XMP_OptionBits *options) const </td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#2f561295e73047ee90765558d29bd650">GetProperty_Date</a>(XMP_StringPtr schemaNS, XMP_StringPtr propName, XMP_DateTime *propValue, XMP_OptionBits *options) const </td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#7708c31c9af3e740b27a4893dcd9aa47">GetProperty_Float</a>(XMP_StringPtr schemaNS, XMP_StringPtr propName, double *propValue, XMP_OptionBits *options) const </td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#3b6ba486c02607b544917091c43b05cc">GetProperty_Int</a>(XMP_StringPtr schemaNS, XMP_StringPtr propName, long *propValue, XMP_OptionBits *options) const </td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#d1a6629b0466981b67d31c9dc3840ea7">GetProperty_Int64</a>(XMP_StringPtr schemaNS, XMP_StringPtr propName, long long *propValue, XMP_OptionBits *options) const</td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#2cc58d8316043b035643e7c21633bc13">GetQualifier</a>(XMP_StringPtr schemaNS, XMP_StringPtr propName, XMP_StringPtr qualNS, XMP_StringPtr qualName, tStringObj *qualValue, XMP_OptionBits *options) const </td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#e99d2bc414d5cd68851147aef6710d4a">GetStructField</a>(XMP_StringPtr schemaNS, XMP_StringPtr structName, XMP_StringPtr fieldNS, XMP_StringPtr fieldName, tStringObj *fieldValue, XMP_OptionBits *options) const</td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#5415cfc01a9cb8786939246571a23a9d">GetVersionInfo</a>(XMP_VersionInfo *info)</td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#bfddf1df0e01ab33d5636a80edc973ca">Initialize</a>()</td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#4d5a601c9b77f6f6ab5f14e658de58ef">operator=</a>(const TXMPMeta&lt; tStringObj &gt; &amp;rhs)</td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#7b383f5b357fff040cdbde82f4f43f26">ParseFromBuffer</a>(XMP_StringPtr buffer, XMP_StringLen bufferSize, XMP_OptionBits options=0)</td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#b9463c7459125ca0038db2e586c5e4df">RegisterAlias</a>(XMP_StringPtr aliasNS, XMP_StringPtr aliasProp, XMP_StringPtr actualNS, XMP_StringPtr actualProp, XMP_OptionBits arrayForm=kXMP_NoOptions)</td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#4c69d31a37ff24c85679229c479aa1ac">RegisterNamespace</a>(XMP_StringPtr namespaceURI, XMP_StringPtr suggestedPrefix, tStringObj *registeredPrefix)</td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#b77cf73fa0cc63d845f113b3d1c83602">RegisterStandardAliases</a>(XMP_StringPtr schemaNS)</td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#c4b9c75202f2b961ad92f10a9e504e9a">ResolveAlias</a>(XMP_StringPtr aliasNS, XMP_StringPtr aliasProp, tStringObj *actualNS, tStringObj *actualProp, XMP_OptionBits *arrayForm)</td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#2774a6f15ae22f0002201b58c46bfb49">SerializeToBuffer</a>(tStringObj *rdfString, XMP_OptionBits options, XMP_StringLen padding, XMP_StringPtr newline, XMP_StringPtr indent=&quot;&quot;, XMP_Index baseIndent=0) const </td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#34143727d979b47a2f2209367aec9a1c">SerializeToBuffer</a>(tStringObj *rdfString, XMP_OptionBits options=0, XMP_StringLen padding=0) const</td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#1570eb89d613b4a94ca572e4644168cc">SetArrayItem</a>(XMP_StringPtr schemaNS, XMP_StringPtr arrayName, XMP_Index itemIndex, XMP_StringPtr itemValue, XMP_OptionBits options=0)</td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#15720ee8e732232fa25989870cf99846">SetArrayItem</a>(XMP_StringPtr schemaNS, XMP_StringPtr arrayName, XMP_Index itemIndex, const tStringObj &amp;itemValue, XMP_OptionBits options=0)</td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#e7bb38d9b3857b08106630a386b47332">SetGlobalOptions</a>(XMP_OptionBits options)</td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#f9531b949a462f5663b1f3fd99464c19">SetLocalizedText</a>(XMP_StringPtr schemaNS, XMP_StringPtr altTextName, XMP_StringPtr genericLang, XMP_StringPtr specificLang, XMP_StringPtr itemValue, XMP_OptionBits options=0)</td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#81273a152fb7b19e99c62ee39bf723f2">SetLocalizedText</a>(XMP_StringPtr schemaNS, XMP_StringPtr altTextName, XMP_StringPtr genericLang, XMP_StringPtr specificLang, const tStringObj &amp;itemValue, XMP_OptionBits options=0)</td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#cf1935be8e4849976dfc02325424960a">SetObjectName</a>(XMP_StringPtr name)</td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#fd059cc7cd9f906e12dab04e380e495c">SetObjectName</a>(tStringObj name)</td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#92055b3ae18dfd5e5491108f59318f17">SetObjectOptions</a>(XMP_OptionBits options)</td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#1dfd6a08ebfd1a6364b3a7b6584bcc28">SetProperty</a>(XMP_StringPtr schemaNS, XMP_StringPtr propName, XMP_StringPtr propValue, XMP_OptionBits options=0)</td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#cc50625611f6aad405aa47197b6d0055">SetProperty</a>(XMP_StringPtr schemaNS, XMP_StringPtr propName, const tStringObj &amp;propValue, XMP_OptionBits options=0)</td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#9521e3838272ec501ffdb60ff3eb482f">SetProperty_Bool</a>(XMP_StringPtr schemaNS, XMP_StringPtr propName, bool propValue, XMP_OptionBits options=0)</td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#eee10669445f77139d5634199ff01079">SetProperty_Date</a>(XMP_StringPtr schemaNS, XMP_StringPtr propName, const XMP_DateTime &amp;propValue, XMP_OptionBits options=0)</td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#3b0f2f6bae57931ea96775f03608c0ed">SetProperty_Float</a>(XMP_StringPtr schemaNS, XMP_StringPtr propName, double propValue, XMP_OptionBits options=0)</td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#b8ae94130d9a05c1b9a3ee25588b6421">SetProperty_Int</a>(XMP_StringPtr schemaNS, XMP_StringPtr propName, long propValue, XMP_OptionBits options=0)</td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#df919aff205e934e4c8250a067f7b377">SetProperty_Int64</a>(XMP_StringPtr schemaNS, XMP_StringPtr propName, long long propValue, XMP_OptionBits options=0)</td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#c2e798da5f9d94e486382a41e73fcea3">SetQualifier</a>(XMP_StringPtr schemaNS, XMP_StringPtr propName, XMP_StringPtr qualNS, XMP_StringPtr qualName, XMP_StringPtr qualValue, XMP_OptionBits options=0)</td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#c395e094cab251a0593d508594b21521">SetQualifier</a>(XMP_StringPtr schemaNS, XMP_StringPtr propName, XMP_StringPtr qualNS, XMP_StringPtr qualName, const tStringObj &amp;qualValue, XMP_OptionBits options=0)</td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#0e44c30e7527064909e5f7035d53c4f5">SetStructField</a>(XMP_StringPtr schemaNS, XMP_StringPtr structName, XMP_StringPtr fieldNS, XMP_StringPtr fieldName, XMP_StringPtr fieldValue, XMP_OptionBits options=0)</td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#77d4a1bf7831f39073af9ea1544ebefa">SetStructField</a>(XMP_StringPtr schemaNS, XMP_StringPtr structName, XMP_StringPtr fieldNS, XMP_StringPtr fieldName, const tStringObj &amp;fieldValue, XMP_OptionBits options=0)</td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#6c30fae26173167958b6f0da95a53865">Terminate</a>()</td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#7729cbce91956632289b88d85fdc65ae">TXMPMeta</a>()</td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#21a4d06fc2e77b28991bb900f0f48e50">TXMPMeta</a>(const TXMPMeta&lt; tStringObj &gt; &amp;original)</td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#cbe8f556a5b32542c44fa9de9648ad41">TXMPMeta</a>(XMPMetaRef xmpRef)</td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#05199e2a4bc61db7aed207759e899bc2">TXMPMeta</a>(XMP_StringPtr buffer, XMP_StringLen xmpSize)</td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPMeta.html#bab5013870cd47eb0d9d701653735a02">~TXMPMeta</a>()</td><td><a class="el" href="classTXMPMeta.html">TXMPMeta&lt; tStringObj &gt;</a></td><td><code> [virtual]</code></td></tr>
+</table><hr size="1"><address style="align: right;"><small>Generated on Thu May 3 14:54:59 2007 for Adobe XMP Toolkit by&nbsp;
+<a href="http://www.doxygen.org/index.html">
+<img src="doxygen.png" alt="doxygen" align="middle" border="0"></a> 1.5.1 </small></address>
+</body>
+</html>
diff --git a/docs/XMPToolkit/classTXMPMeta.html b/docs/XMPToolkit/classTXMPMeta.html
new file mode 100644
index 0000000..3207227
--- /dev/null
+++ b/docs/XMPToolkit/classTXMPMeta.html
@@ -0,0 +1,2781 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
+<title>Adobe XMP Toolkit: TXMPMeta&lt; tStringObj &gt; Class Template Reference</title>
+<link href="doxygen.css" rel="stylesheet" type="text/css">
+<link href="tabs.css" rel="stylesheet" type="text/css">
+</head><body>
+<!-- Generated by Doxygen 1.5.1 -->
+<div class="tabs">
+ <ul>
+ <li><a href="index.html"><span>Main&nbsp;Page</span></a></li>
+ <li><a href="modules.html"><span>Modules</span></a></li>
+ <li id="current"><a href="annotated.html"><span>Classes</span></a></li>
+ <li><a href="files.html"><span>Files</span></a></li>
+ </ul></div>
+<div class="tabs">
+ <ul>
+ <li><a href="annotated.html"><span>Class&nbsp;List</span></a></li>
+ <li><a href="functions.html"><span>Class&nbsp;Members</span></a></li>
+ </ul></div>
+<h1>TXMPMeta&lt; tStringObj &gt; Class Template Reference</h1><!-- doxytag: class="TXMPMeta" -->Template class for the XMP Toolkit core services.
+<a href="#_details">More...</a>
+<p>
+<code>#include &lt;<a class="el" href="TXMPMeta_8hpp-source.html">TXMPMeta.hpp</a>&gt;</code>
+<p>
+<a href="classTXMPMeta-members.html">List of all members.</a><table border="0" cellpadding="0" cellspacing="0">
+<tr><td></td></tr>
+<tr><td colspan="2"><br><h2>Constructors and destructor</h2></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#7729cbce91956632289b88d85fdc65ae">TXMPMeta</a> ()</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Default constructor, creates an empty object. <a href="#7729cbce91956632289b88d85fdc65ae"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#21a4d06fc2e77b28991bb900f0f48e50">TXMPMeta</a> (const <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt; &amp;original)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Copy constructor, creates a client object refering to the same internal object. <a href="#21a4d06fc2e77b28991bb900f0f48e50"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#4d5a601c9b77f6f6ab5f14e658de58ef">operator=</a> (const <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt; &amp;rhs)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Assignment operator, assigns the internal ref and increments the ref count. <a href="#4d5a601c9b77f6f6ab5f14e658de58ef"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#cbe8f556a5b32542c44fa9de9648ad41">TXMPMeta</a> (<a class="el" href="XMP__Const_8h.html#5912613564f80e17eb10acef9236f70a">XMPMetaRef</a> xmpRef)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Reconstruct an XMP object from an internal ref. <a href="#cbe8f556a5b32542c44fa9de9648ad41"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#05199e2a4bc61db7aed207759e899bc2">TXMPMeta</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> buffer, <a class="el" href="XMP__Const_8h.html#9f7dcc184f901c713274edfdac5bcc9a">XMP_StringLen</a> xmpSize)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Construct an object and parse one buffer of RDF into it. <a href="#05199e2a4bc61db7aed207759e899bc2"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="bab5013870cd47eb0d9d701653735a02"></a><!-- doxytag: member="TXMPMeta::~TXMPMeta" ref="bab5013870cd47eb0d9d701653735a02" args="()" -->
+virtual&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#bab5013870cd47eb0d9d701653735a02">~TXMPMeta</a> () throw ()</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Destructor, typical virtual destructor. <br></td></tr>
+<tr><td colspan="2"><br><h2>Public Member Functions</h2></td></tr>
+<tr><td colspan="2"><div class="groupHeader">Functions for getting property values</div></td></tr>
+<tr><td colspan="2"><div class="groupText">The property value "getters" all take a property specification, The first two parameters are always the top level namespace URI (the "schema" namespace) and the basic name of the property being referenced. See the introductory discussion of path expression usage for more information.<p>
+All of the functions return a Boolean result telling if the property exists, and if it does they also return option flags describing the property. If the property exists and has a value, the string value is also returned. The string is Unicode in UTF-8 encoding. Arrays and the non-leaf levels of structs do not have values. The possible option flags that describe properties are:<p>
+<ul>
+<li><code>kXMP_PropValueIsURI</code> - The property value is a URI. It is serialized to RDF using the <code>rdf:resource</code> attribute. Not mandatory for URIs, but considered RDF-savvy.</li>
+</ul>
+<ul>
+<li><code>kXMP_PropHasQualifiers</code> - The property has qualifiers. These could be an <code>xml:lang</code> attribute, an <code>rdf:type</code> property, or a general qualifier. See the introductory discussion of qualified properties for more information.</li>
+</ul>
+<ul>
+<li><code>kXMP_PropIsQualifier</code> - This property is a qualifier for some other property. Note that if the qualifier itself has a structured value, this flag is only set for the top node of the qualifier's subtree. Qualifiers may have arbitrary structure, and may even have qualifiers.</li>
+</ul>
+<ul>
+<li><code>kXMP_PropHasLang</code> - This property has an <code>xml:lang</code> qualifier.</li>
+</ul>
+<ul>
+<li><code>kXMP_PropHasType</code> - This property has an <code>rdf:type</code> qualifier.</li>
+</ul>
+<ul>
+<li><code>kXMP_PropValueIsStruct</code> - This property contains nested fields (models a C struct).</li>
+</ul>
+<ul>
+<li><code>kXMP_PropValueIsArray</code> - This property is an array. By itself (no ...ArrayIs... flags), this indicates a general unordered array. It is serialized using an <code>rdf:Bag</code> container.</li>
+</ul>
+<ul>
+<li><code>kXMP_PropArrayIsOrdered</code> - This property is an ordered array. Appears in conjunction with <code>kXMP_PropValueIsArray</code>. It is serialized using an <code>rdf:Seq</code> container.</li>
+</ul>
+<ul>
+<li><code>kXMP_PropArrayIsAlternate</code> - This property is an alternative array. Appears in conjunction with <code>kXMP_PropValueIsArray</code>. It is serialized using an <code>rdf:Alt</code> container.</li>
+</ul>
+<ul>
+<li><code>kXMP_PropArrayIsAltText</code> - This property is an alt-text array. Appears in conjunction with <code>kXMP_PropArrayIsAlternate</code>. It is serialized using an <code>rdf:Alt</code> container. Each array element is a simple property with an <code>xml:lang</code> attribute.</li>
+</ul>
+<ul>
+<li><code>kXMP_PropIsAlias</code> - The given property name is an alias. This is only returned by <code>GetProperty</code> and then only if the property name is simple, not an path expression.</li>
+</ul>
+<ul>
+<li><code>kXMP_PropHasAliases</code> - The given property name has aliases. This is only returned by <code>GetProperty</code> and then only if the property name is simple, not an path expression.</li>
+</ul>
+<ul>
+<li><code>kXMP_PropIsStable</code> - The value of this property is not related to the document content.</li>
+</ul>
+<ul>
+<li><code>kXMP_PropIsDerived</code> - The value of this property is derived from the document content.</li>
+</ul>
+<ul>
+<li><code>kXMP_PropIsInternal</code> - The value of this property is "owned" by the application, it should not generally be editable in a UI. </li>
+</ul>
+<br><br></div></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">bool&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#06a3241c7fa5df87f61dff02fca23a0c">GetProperty</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> propName, tStringObj *propValue, <a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> *options) const </td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight"><code>GetProperty</code> is the simplest property getter, mainly for top level simple properties or after using the path composition functions in <code><a class="el" href="classTXMPUtils.html">TXMPUtils</a></code>. <a href="#06a3241c7fa5df87f61dff02fca23a0c"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">bool&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#c64a4251d157937f69b73f2ffac4f7cc">GetArrayItem</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> arrayName, <a class="el" href="XMP__Const_8h.html#00e9d9a76c144421105a4c2742203315">XMP_Index</a> itemIndex, tStringObj *itemValue, <a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> *options) const </td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight"><code>GetArrayItem</code> provides access to items within an array. The index is passed as an integer, you need not worry about the path string syntax for array items, convert a loop index to a string, etc. <a href="#c64a4251d157937f69b73f2ffac4f7cc"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">bool&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#e99d2bc414d5cd68851147aef6710d4a">GetStructField</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> structName, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> fieldNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> fieldName, tStringObj *fieldValue, <a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> *options) const</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight"><code>GetStructField</code> provides access to fields within a nested structure. The namespace for the field is passed as a URI, you need not worry about the path string syntax. <a href="#e99d2bc414d5cd68851147aef6710d4a"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">bool&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#2cc58d8316043b035643e7c21633bc13">GetQualifier</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> propName, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> qualNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> qualName, tStringObj *qualValue, <a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> *options) const </td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight"><code>GetQualifier</code> provides access to a qualifier attached to a property. The namespace for the qualifier is passed as a URI, you need not worry about the path string syntax. In many regards qualifiers are like struct fields. See the introductory discussion of qualified properties for more information. <a href="#2cc58d8316043b035643e7c21633bc13"></a><br></td></tr>
+<tr><td colspan="2"><div class="groupHeader">Functions for setting property values</div></td></tr>
+<tr><td colspan="2"><div class="groupText">The property value "setters" all take a property specification, their differences are in the form of this. The first two parameters are always the top level namespace URI (the "schema" namespace) and the basic name of the property being referenced. See the introductory discussion of path expression usage for more information.<p>
+All of the functions take a string value for the property and option flags describing the property. The value must be Unicode in UTF-8 encoding. Arrays and non-leaf levels of structs do not have values. Empty arrays and structs may be created using appropriate option flags. All levels of structs that is assigned implicitly are created if necessary. <code>AppendArayItem</code> implicitly creates the named array if necessary.<p>
+The canonical form of these functions take the value as an <code>XMP_StringPtr</code>, a pointer to a null terminated string. (<code>XMP_StringPtr</code> is a typedef for <code>const char *</code>.) They also have overloaded forms that take a string object. These are implemented in the template instantiation as a call to the canonical form, using <code>value.c_str()</code> to obtain the <code>XMP_StringPtr</code>.<p>
+The possible option flags are:<p>
+<ul>
+<li><code>kXMP_PropValueIsURI</code> - The property value is a URI. It is serialized to RDF using the <code>rdf:resource</code> attribute. Not mandatory for URIs, but considered RDF-savvy.</li>
+</ul>
+<ul>
+<li><code>kXMP_PropValueIsStruct</code> - This property contains nested fields (models a C struct). Not necessary, may be used to create an empty struct. A struct is implicitly created when first field is set.</li>
+</ul>
+<ul>
+<li><code>kXMP_PropValueIsArray</code> - This property is an array. By itself (no ...ArrayIs... flags), this indicates a general unordered array. It is serialized using an <code>rdf:Bag</code> container.</li>
+</ul>
+<ul>
+<li><code>kXMP_PropArrayIsOrdered</code> - This property is an ordered array. Implies <code>kXMP_PropValueIsArray</code>, may be used together. It is serialized using an <code>rdf:Seq</code> container.</li>
+</ul>
+<ul>
+<li><code>kXMP_PropArrayIsAlternate</code> - This property is an alternative array. Implies <code>kXMP_PropArrayIsOrdered</code>, may be used together. It is serialized using an <code>rdf:Alt</code> container.</li>
+</ul>
+<ul>
+<li><code>kXMP_PropArrayIsAltText</code> - This property is an alt-text array. Implies <code>kXMP_PropArrayIsAlternate</code>, may be used together. It is serialized using an <code>rdf:Alt</code> container. Each array element must be a simple property with an <code>xml:lang</code> attribute. </li>
+</ul>
+<br><br></div></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#1dfd6a08ebfd1a6364b3a7b6584bcc28">SetProperty</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> propName, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> propValue, <a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options=0)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight"><code>SetProperty</code> is the simplest property setter, mainly for top level simple properties or after using the path composition functions in <code><a class="el" href="classTXMPUtils.html">TXMPUtils</a></code>. <a href="#1dfd6a08ebfd1a6364b3a7b6584bcc28"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="cc50625611f6aad405aa47197b6d0055"></a><!-- doxytag: member="TXMPMeta::SetProperty" ref="cc50625611f6aad405aa47197b6d0055" args="(XMP_StringPtr schemaNS, XMP_StringPtr propName, const tStringObj &amp;propValue, XMP_OptionBits options=0)" -->
+void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#cc50625611f6aad405aa47197b6d0055">SetProperty</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> propName, const tStringObj &amp;propValue, <a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options=0)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">This form of <code>SetProperty</code> is a simple overload in the template that calls the above form passing <code>propValue.c_str()</code>. <br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#1570eb89d613b4a94ca572e4644168cc">SetArrayItem</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> arrayName, <a class="el" href="XMP__Const_8h.html#00e9d9a76c144421105a4c2742203315">XMP_Index</a> itemIndex, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> itemValue, <a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options=0)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight"><code>SetArrayItem</code> provides access to items within an array. The index is passed as an integer, you need not worry about the path string syntax for array items, convert a loop index to a string, etc. The array passed to <code>SetArrayItem</code> must already exist. See also <code>AppendArrayItem</code>. <a href="#1570eb89d613b4a94ca572e4644168cc"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="15720ee8e732232fa25989870cf99846"></a><!-- doxytag: member="TXMPMeta::SetArrayItem" ref="15720ee8e732232fa25989870cf99846" args="(XMP_StringPtr schemaNS, XMP_StringPtr arrayName, XMP_Index itemIndex, const tStringObj &amp;itemValue, XMP_OptionBits options=0)" -->
+void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#15720ee8e732232fa25989870cf99846">SetArrayItem</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> arrayName, <a class="el" href="XMP__Const_8h.html#00e9d9a76c144421105a4c2742203315">XMP_Index</a> itemIndex, const tStringObj &amp;itemValue, <a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options=0)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">This form of <code>SetArrayItem</code> is a simple overload in the template that calls the above form passing <code>itemValue.c_str()</code>. <br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#00d7314dc970ad390499ce9db27d314a">AppendArrayItem</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> arrayName, <a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> arrayOptions, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> itemValue, <a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> itemOptions=0)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight"><code>AppendArrayItem</code> simplifies construction of an array by not requiring that you pre-create an empty array. The array that is assigned is created automatically if it does not yet exist. Each call to <code>AppendArrayItem</code> appends an item to the array. The corresponding parameters have the same use as <code>SetArrayItem</code>. The <code>arrayOptions</code> parameter is used to specify what kind of array. If the array exists, it must have the specified form. <a href="#00d7314dc970ad390499ce9db27d314a"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="4f768a8cb35cabff1cf4187aa6a88dd3"></a><!-- doxytag: member="TXMPMeta::AppendArrayItem" ref="4f768a8cb35cabff1cf4187aa6a88dd3" args="(XMP_StringPtr schemaNS, XMP_StringPtr arrayName, XMP_OptionBits arrayOptions, const tStringObj &amp;itemValue, XMP_OptionBits itemOptions=0)" -->
+void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#4f768a8cb35cabff1cf4187aa6a88dd3">AppendArrayItem</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> arrayName, <a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> arrayOptions, const tStringObj &amp;itemValue, <a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> itemOptions=0)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">This form of <code>AppendArrayItem</code> is a simple overload in the template that calls the above form passing <code>itemValue.c_str()</code>. <br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#0e44c30e7527064909e5f7035d53c4f5">SetStructField</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> structName, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> fieldNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> fieldName, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> fieldValue, <a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options=0)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight"><code>SetStructField</code> provides access to fields within a nested structure. The namespace for the field is passed as a URI, you need not worry about the path string syntax. <a href="#0e44c30e7527064909e5f7035d53c4f5"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="77d4a1bf7831f39073af9ea1544ebefa"></a><!-- doxytag: member="TXMPMeta::SetStructField" ref="77d4a1bf7831f39073af9ea1544ebefa" args="(XMP_StringPtr schemaNS, XMP_StringPtr structName, XMP_StringPtr fieldNS, XMP_StringPtr fieldName, const tStringObj &amp;fieldValue, XMP_OptionBits options=0)" -->
+void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#77d4a1bf7831f39073af9ea1544ebefa">SetStructField</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> structName, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> fieldNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> fieldName, const tStringObj &amp;fieldValue, <a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options=0)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">This form of <code>SetStructField</code> is a simple overload in the template that calls the above form passing <code>fieldValue.c_str()</code>. <br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#c2e798da5f9d94e486382a41e73fcea3">SetQualifier</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> propName, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> qualNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> qualName, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> qualValue, <a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options=0)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight"><code>SetQualifier</code> provides access to a qualifier attached to a property. The namespace for the qualifier is passed as a URI, you need not worry about the path string syntax. In many regards qualifiers are like struct fields. See the introductory discussion of qualified properties for more information. <a href="#c2e798da5f9d94e486382a41e73fcea3"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="c395e094cab251a0593d508594b21521"></a><!-- doxytag: member="TXMPMeta::SetQualifier" ref="c395e094cab251a0593d508594b21521" args="(XMP_StringPtr schemaNS, XMP_StringPtr propName, XMP_StringPtr qualNS, XMP_StringPtr qualName, const tStringObj &amp;qualValue, XMP_OptionBits options=0)" -->
+void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#c395e094cab251a0593d508594b21521">SetQualifier</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> propName, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> qualNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> qualName, const tStringObj &amp;qualValue, <a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options=0)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">This form of <code>SetQualifier</code> is a simple overload in the template that calls the above form passing <code>qualValue.c_str()</code>. <br></td></tr>
+<tr><td colspan="2"><div class="groupHeader">Functions for deleting and detecting properties.</div></td></tr>
+<tr><td colspan="2"><div class="groupText">These should be obvious from the descriptions of the getters and setters. <br><br></div></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#c8b555ba99904fa49bb4851a60cc3844">DeleteProperty</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> propName)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight"><code>DeleteProperty</code> deletes the given XMP subtree rooted at the given property. It is not an error if the property does not exist. <a href="#c8b555ba99904fa49bb4851a60cc3844"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#bc1211f47225b5973a170ff952743264">DeleteArrayItem</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> arrayName, <a class="el" href="XMP__Const_8h.html#00e9d9a76c144421105a4c2742203315">XMP_Index</a> itemIndex)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight"><code>DeleteArrayItem</code> deletes the given XMP subtree rooted at the given array item. It is not an error if the array item does not exist. <a href="#bc1211f47225b5973a170ff952743264"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#bc258e027780a15be65a88fcfd4e1fd4">DeleteStructField</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> structName, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> fieldNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> fieldName)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight"><code>DeleteStructField</code> deletes the given XMP subtree rooted at the given struct field. It is not an error if the field does not exist. <a href="#bc258e027780a15be65a88fcfd4e1fd4"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#8ce15f7de7fd3b258f07158ab5fa88be">DeleteQualifier</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> propName, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> qualNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> qualName)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight"><code>DeleteQualifier</code> deletes the given XMP subtree rooted at the given qualifier. It is not an error if the qualifier does not exist. <a href="#8ce15f7de7fd3b258f07158ab5fa88be"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">bool&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#f22b116d71ecbbebea016ec5337e7066">DoesPropertyExist</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> propName) const </td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight"><code>DoesPropertyExist</code> tells if the property exists. <a href="#f22b116d71ecbbebea016ec5337e7066"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">bool&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#492465c588d6d4cb8e30f94790e66f58">DoesArrayItemExist</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> arrayName, <a class="el" href="XMP__Const_8h.html#00e9d9a76c144421105a4c2742203315">XMP_Index</a> itemIndex) const </td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight"><code>DoesArrayItemExist</code> tells if the array item exists. <a href="#492465c588d6d4cb8e30f94790e66f58"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">bool&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#9261b80d62e77a10ff1a89843bfa10a5">DoesStructFieldExist</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> structName, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> fieldNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> fieldName) const </td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight"><code>DoesStructFieldExist</code> tells if the struct field exists. <a href="#9261b80d62e77a10ff1a89843bfa10a5"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">bool&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#81347a92becd387a14f4d47c582f129a">DoesQualifierExist</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> propName, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> qualNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> qualName) const </td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight"><code>DoesQualifierExist</code> tells if the qualifier exists. <a href="#81347a92becd387a14f4d47c582f129a"></a><br></td></tr>
+<tr><td colspan="2"><div class="groupHeader">Functions for accessing localized text (alt-text) properties.</div></td></tr>
+<tr><td colspan="2"><div class="groupText">These functions provide convenient support for localized text properties, including a number of special and obscure aspects. Localized text properties are stored in alt-text arrays. They allow multiple concurrent localizations of a property value, for example a document title or copyright in several languages.<p>
+The most important aspect of these functions is that they select an appropriate array item based on one or two RFC 3066 language tags. One of these languages, the "specific" language, is preferred and selected if there is an exact match. For many languages it is also possible to define a "generic" language that may be used if there is no specific language match. The generic language must be a valid RFC 3066 primary subtag, or the empty string.<p>
+For example, a specific language of "en-US" should be used in the US, and a specific language of "en-UK" should be used in England. It is also appropriate to use "en" as the generic language in each case. If a US document goes to England, the "en-US" title is selected by using the "en" generic language and the "en-UK" specific language.<p>
+It is considered poor practice, but allowed, to pass a specific language that is just an RFC 3066 primary tag. For example "en" is not a good specific language, it should only be used as a generic language. Passing "i" or "x" as the generic language is also considered poor practice but allowed.<p>
+Advice from the W3C about the use of RFC 3066 language tags can be found at: <ul>
+<li><a href="http://www.w3.org/International/articles/language-tags/">http://www.w3.org/International/articles/language-tags/</a></li>
+</ul>
+<dl class="note" compact><dt><b>Note:</b></dt><dd>RFC 3066 language tags must be treated in a case insensitive manner. The XMP toolkit does this by normalizing their capitalization:</dd></dl>
+<ul>
+<li>The primary subtag is lower case, the suggested practice of ISO 639. </li>
+<li>All 2 letter secondary subtags are upper case, the suggested practice of ISO 3166. </li>
+<li>All other subtags are lower case.</li>
+</ul>
+The XMP specification defines an artificial language, "x-default", that is used to explicitly denote a default item in an alt-text array. The XMP toolkit normalizes alt-text arrays such that the x-default item is the first item. The <code>SetLocalizedText</code> function has several special features related to the x-default item, see its description for details.<p>
+The selection of the array item is the same for <code>GetLocalizedText</code> and <code>SetLocalizedText:</code> <p>
+<ul>
+<li>Look for an exact match with the specific language. </li>
+<li>If a generic language is given, look for a partial match. </li>
+<li>Look for an x-default item. </li>
+<li>Choose the first item.</li>
+</ul>
+A partial match with the generic language is where the start of the item's language matches the generic string and the next character is '-'. An exact match is also recognized as a degenerate case.<p>
+It is fine to pass x-default as the specific language. In this case, selection of an x-default item is an exact match by the first rule, not a selection by the 3rd rule. The last 2 rules are fallbacks used when the specific and generic languages fail to produce a match. <br><br></div></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">bool&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#eefe49bbf669770d769f4fe0ea566bd0">GetLocalizedText</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> altTextName, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> genericLang, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> specificLang, tStringObj *actualLang, tStringObj *itemValue, <a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> *options) const </td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight"><code>GetLocalizedText</code> returns information about a selected item in an alt-text array. The array item is selected according to the rules given above. <a href="#eefe49bbf669770d769f4fe0ea566bd0"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#f9531b949a462f5663b1f3fd99464c19">SetLocalizedText</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> altTextName, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> genericLang, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> specificLang, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> itemValue, <a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options=0)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight"><code>SetLocalizedText</code> modifies the value of a selected item in an alt-text array. Creates an appropriate array item if necessary, and handles special cases for the x-default item. <a href="#f9531b949a462f5663b1f3fd99464c19"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="81273a152fb7b19e99c62ee39bf723f2"></a><!-- doxytag: member="TXMPMeta::SetLocalizedText" ref="81273a152fb7b19e99c62ee39bf723f2" args="(XMP_StringPtr schemaNS, XMP_StringPtr altTextName, XMP_StringPtr genericLang, XMP_StringPtr specificLang, const tStringObj &amp;itemValue, XMP_OptionBits options=0)" -->
+void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#81273a152fb7b19e99c62ee39bf723f2">SetLocalizedText</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> altTextName, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> genericLang, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> specificLang, const tStringObj &amp;itemValue, <a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options=0)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">This form of <code>SetLocalizedText</code> is a simple overload in the template that calls the above form passing <code>itemValue.c_str()</code>. <br></td></tr>
+<tr><td colspan="2"><div class="groupHeader">Functions accessing properties as binary values.</div></td></tr>
+<tr><td colspan="2"><div class="groupText">These are very similar to <code>GetProperty</code> and <code>SetProperty</code> above, but the value is returned or provided in binary form instead of as a UTF-8 string. The path composition functions in <code><a class="el" href="classTXMPUtils.html">TXMPUtils</a></code> may be used to compose an path expression for fields in nested structures, items in arrays, or qualifiers. <br><br></div></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">bool&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#dcf8a1959a8bd42641a42cbd4d64a5b7">GetProperty_Bool</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> propName, bool *propValue, <a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> *options) const </td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight"><code>GetProperty_Bool</code> returns the value of a Boolean property as a C++ bool. <a href="#dcf8a1959a8bd42641a42cbd4d64a5b7"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">bool&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#3b6ba486c02607b544917091c43b05cc">GetProperty_Int</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> propName, long *propValue, <a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> *options) const </td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight"><code>GetProperty_Int</code> returns the value of an integer property as a C long integer. <a href="#3b6ba486c02607b544917091c43b05cc"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">bool&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#d1a6629b0466981b67d31c9dc3840ea7">GetProperty_Int64</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> propName, long long *propValue, <a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> *options) const</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight"><code>GetProperty_Int64</code> returns the value of an integer property as a C long long integer. <a href="#d1a6629b0466981b67d31c9dc3840ea7"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">bool&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#7708c31c9af3e740b27a4893dcd9aa47">GetProperty_Float</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> propName, double *propValue, <a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> *options) const </td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight"><code>GetProperty_Float</code> returns the value of a flaoting point property as a C double float. <a href="#7708c31c9af3e740b27a4893dcd9aa47"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">bool&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#2f561295e73047ee90765558d29bd650">GetProperty_Date</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> propName, <a class="el" href="structXMP__DateTime.html">XMP_DateTime</a> *propValue, <a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> *options) const </td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight"><code>GetProperty_Date</code> returns the value of a date/time property as an <code><a class="el" href="structXMP__DateTime.html">XMP_DateTime</a></code> struct. <a href="#2f561295e73047ee90765558d29bd650"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#9521e3838272ec501ffdb60ff3eb482f">SetProperty_Bool</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> propName, bool propValue, <a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options=0)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight"><code>SetProperty_Bool</code> sets the value of a Boolean property from a C++ bool. <a href="#9521e3838272ec501ffdb60ff3eb482f"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#b8ae94130d9a05c1b9a3ee25588b6421">SetProperty_Int</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> propName, long propValue, <a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options=0)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight"><code>SetProperty_Int</code> sets the value of an integer property from a C long integer. <a href="#b8ae94130d9a05c1b9a3ee25588b6421"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#df919aff205e934e4c8250a067f7b377">SetProperty_Int64</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> propName, long long propValue, <a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options=0)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight"><code>SetProperty_Int64</code> sets the value of an integer property from a C long long integer. <a href="#df919aff205e934e4c8250a067f7b377"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#3b0f2f6bae57931ea96775f03608c0ed">SetProperty_Float</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> propName, double propValue, <a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options=0)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight"><code>SetProperty_Float</code> sets the value of a floating point property from a C double float. <a href="#3b0f2f6bae57931ea96775f03608c0ed"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#eee10669445f77139d5634199ff01079">SetProperty_Date</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> propName, const <a class="el" href="structXMP__DateTime.html">XMP_DateTime</a> &amp;propValue, <a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options=0)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight"><code>SetProperty_Date</code> sets the value of a date/time property from an <code><a class="el" href="structXMP__DateTime.html">XMP_DateTime</a></code> struct. <a href="#eee10669445f77139d5634199ff01079"></a><br></td></tr>
+<tr><td colspan="2"><div class="groupHeader">Misceallaneous functions.</div></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="4d35b44f1f017a27772ee902a3dacf04"></a><!-- doxytag: member="TXMPMeta::GetInternalRef" ref="4d35b44f1f017a27772ee902a3dacf04" args="() const" -->
+<a class="el" href="XMP__Const_8h.html#5912613564f80e17eb10acef9236f70a">XMPMetaRef</a>&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#4d35b44f1f017a27772ee902a3dacf04">GetInternalRef</a> () const</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">GetInternalRef Returns an internal reference that may be safely passed across DLL boundaries and reconstructed. <br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="b0d179ed95487d4fd4f2680c1fbe0d40"></a><!-- doxytag: member="TXMPMeta::GetObjectName" ref="b0d179ed95487d4fd4f2680c1fbe0d40" args="(tStringObj *name) const " -->
+void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#b0d179ed95487d4fd4f2680c1fbe0d40">GetObjectName</a> (tStringObj *name) const </td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">GetObjectName --TBD--. <br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="cf1935be8e4849976dfc02325424960a"></a><!-- doxytag: member="TXMPMeta::SetObjectName" ref="cf1935be8e4849976dfc02325424960a" args="(XMP_StringPtr name)" -->
+void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#cf1935be8e4849976dfc02325424960a">SetObjectName</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> name)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">SetObjectName --TBD--. <br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="fd059cc7cd9f906e12dab04e380e495c"></a><!-- doxytag: member="TXMPMeta::SetObjectName" ref="fd059cc7cd9f906e12dab04e380e495c" args="(tStringObj name)" -->
+void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#fd059cc7cd9f906e12dab04e380e495c">SetObjectName</a> (tStringObj name)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">SetObjectName --TBD--. <br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="39aeaf9eb83cfc1c5455807b95f055f9"></a><!-- doxytag: member="TXMPMeta::GetObjectOptions" ref="39aeaf9eb83cfc1c5455807b95f055f9" args="() const" -->
+<a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a>&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#39aeaf9eb83cfc1c5455807b95f055f9">GetObjectOptions</a> () const</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">GetObjectOptions --TBD--. <br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#92055b3ae18dfd5e5491108f59318f17">SetObjectOptions</a> (<a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">SetObjectOptions --TBD--. <a href="#92055b3ae18dfd5e5491108f59318f17"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="el" href="classTXMPMeta.html">TXMPMeta</a>&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#6ca653436995bbb76315efe7934afd4c">Clone</a> (<a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options=0) const </td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight"><code>Clone</code> creates a deep clone of the XMP object. <a href="#6ca653436995bbb76315efe7934afd4c"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="b79aae864b3ce190d0699252f48e0acc"></a><!-- doxytag: member="TXMPMeta::CountArrayItems" ref="b79aae864b3ce190d0699252f48e0acc" args="(XMP_StringPtr schemaNS, XMP_StringPtr arrayName) const " -->
+<a class="el" href="XMP__Const_8h.html#00e9d9a76c144421105a4c2742203315">XMP_Index</a>&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#b79aae864b3ce190d0699252f48e0acc">CountArrayItems</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> arrayName) const </td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">CountArrayItems --TBD--. <br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="976c1eb889f44080f76628805712b618"></a><!-- doxytag: member="TXMPMeta::DumpObject" ref="976c1eb889f44080f76628805712b618" args="(XMP_TextOutputProc outProc, void *refCon) const " -->
+<a class="el" href="XMP__Const_8h.html#91efdc0a7fbe6e1d42ca34e6ce589b98">XMP_Status</a>&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#976c1eb889f44080f76628805712b618">DumpObject</a> (<a class="el" href="XMP__Const_8h.html#36eab570ab85ff8fb5789661692d13c2">XMP_TextOutputProc</a> outProc, void *refCon) const </td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight"><code>DumpObject</code> dumps the content of an XMP object. <br></td></tr>
+<tr><td colspan="2"><div class="groupHeader">Functions for parsing and serializing.</div></td></tr>
+<tr><td colspan="2"><div class="groupText">These functions support parsing serialized RDF into an XMP object, and serailizing an XMP object into RDF. The input for parsing may be any valid Unicode encoding. ISO Latin-1 is also recognized, but its use is strongly discouraged. Serialization is always as UTF-8. <br><br></div></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#7b383f5b357fff040cdbde82f4f43f26">ParseFromBuffer</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> buffer, <a class="el" href="XMP__Const_8h.html#9f7dcc184f901c713274edfdac5bcc9a">XMP_StringLen</a> bufferSize, <a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options=0)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight"><code>ParseFromBuffer</code> parses RDF from a series of input buffers. The buffers may be any length. The buffer boundaries need not respect XML tokens or even Unicode characters. <a href="#7b383f5b357fff040cdbde82f4f43f26"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#2774a6f15ae22f0002201b58c46bfb49">SerializeToBuffer</a> (tStringObj *rdfString, <a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options, <a class="el" href="XMP__Const_8h.html#9f7dcc184f901c713274edfdac5bcc9a">XMP_StringLen</a> padding, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> newline, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> indent=&quot;&quot;, <a class="el" href="XMP__Const_8h.html#00e9d9a76c144421105a4c2742203315">XMP_Index</a> baseIndent=0) const </td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight"><code>SerializeToBuffer</code> serializes an XMP object into a string as RDF. <a href="#2774a6f15ae22f0002201b58c46bfb49"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="34143727d979b47a2f2209367aec9a1c"></a><!-- doxytag: member="TXMPMeta::SerializeToBuffer" ref="34143727d979b47a2f2209367aec9a1c" args="(tStringObj *rdfString, XMP_OptionBits options=0, XMP_StringLen padding=0) const" -->
+void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#34143727d979b47a2f2209367aec9a1c">SerializeToBuffer</a> (tStringObj *rdfString, <a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options=0, <a class="el" href="XMP__Const_8h.html#9f7dcc184f901c713274edfdac5bcc9a">XMP_StringLen</a> padding=0) const</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">This form of <code>SerializeToBuffer</code> is a simple overload in the template that calls the above form passing default values for the <code>newline</code>, <code>indent</code>, and <code>baseIndent</code> parameters. <br></td></tr>
+<tr><td colspan="2"><br><h2>Static Public Member Functions</h2></td></tr>
+<tr><td colspan="2"><div class="groupHeader">Initialization and termination</div></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="5415cfc01a9cb8786939246571a23a9d"></a><!-- doxytag: member="TXMPMeta::GetVersionInfo" ref="5415cfc01a9cb8786939246571a23a9d" args="(XMP_VersionInfo *info)" -->
+static void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#5415cfc01a9cb8786939246571a23a9d">GetVersionInfo</a> (XMP_VersionInfo *info)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Obtain version information. <br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">static bool&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#bfddf1df0e01ab33d5636a80edc973ca">Initialize</a> ()</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Initialize the XMP Toolkit. <a href="#bfddf1df0e01ab33d5636a80edc973ca"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="6c30fae26173167958b6f0da95a53865"></a><!-- doxytag: member="TXMPMeta::Terminate" ref="6c30fae26173167958b6f0da95a53865" args="()" -->
+static void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#6c30fae26173167958b6f0da95a53865">Terminate</a> ()</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Terminate the XMP Toolkit. <br></td></tr>
+<tr><td colspan="2"><div class="groupHeader">Global option flags</div></td></tr>
+<tr><td colspan="2"><div class="groupText">The global option flags affect the overall behavior of the XMP Toolkit. The available options are declared in <code><a class="el" href="XMP__Const_8h.html">XMP_Const.h</a></code>. <b>(There are none at present.)</b> <br><br></div></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="12b2435ba039c62a164951948c016eb4"></a><!-- doxytag: member="TXMPMeta::GetGlobalOptions" ref="12b2435ba039c62a164951948c016eb4" args="()" -->
+static <a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a>&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#12b2435ba039c62a164951948c016eb4">GetGlobalOptions</a> ()</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">GetGlobalOptions returns the set of global option flags. <br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">static void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#e7bb38d9b3857b08106630a386b47332">SetGlobalOptions</a> (<a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight"><code>SetGlobalOptions</code> updates the set of global option flags. The entire set is replaced with the new values. If only one flag is to be modified, use <code>GetGlobalOptions</code> to obtain the current set, modify the desired flag, then use <code>SetGlobalOptions</code>. <a href="#e7bb38d9b3857b08106630a386b47332"></a><br></td></tr>
+<tr><td colspan="2"><div class="groupHeader">Internal data structure dump utilities</div></td></tr>
+<tr><td colspan="2"><div class="groupText">These are debugging utilities that dump internal data structures. The output callback is described in <code><a class="el" href="XMP__Const_8h.html">XMP_Const.h</a></code>. <br><br></div></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="44250140a710c0b7c5cc0881e387d004"></a><!-- doxytag: member="TXMPMeta::DumpNamespaces" ref="44250140a710c0b7c5cc0881e387d004" args="(XMP_TextOutputProc outProc, void *refCon)" -->
+static <a class="el" href="XMP__Const_8h.html#91efdc0a7fbe6e1d42ca34e6ce589b98">XMP_Status</a>&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#44250140a710c0b7c5cc0881e387d004">DumpNamespaces</a> (<a class="el" href="XMP__Const_8h.html#36eab570ab85ff8fb5789661692d13c2">XMP_TextOutputProc</a> outProc, void *refCon)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight"><code>DumpNamespaces</code> dumps the list of registered namespace URIs and prefixes. <br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="afb027f200b85467298d237a0c23949b"></a><!-- doxytag: member="TXMPMeta::DumpAliases" ref="afb027f200b85467298d237a0c23949b" args="(XMP_TextOutputProc outProc, void *refCon)" -->
+static <a class="el" href="XMP__Const_8h.html#91efdc0a7fbe6e1d42ca34e6ce589b98">XMP_Status</a>&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#afb027f200b85467298d237a0c23949b">DumpAliases</a> (<a class="el" href="XMP__Const_8h.html#36eab570ab85ff8fb5789661692d13c2">XMP_TextOutputProc</a> outProc, void *refCon)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight"><code>DumpAliases</code> dumps the list of registered aliases and corresponding actuals. <br></td></tr>
+<tr><td colspan="2"><div class="groupHeader">Namespace Functions</div></td></tr>
+<tr><td colspan="2"><div class="groupText">Namespaces must be registered before use in namespace URI parameters or path expressions. Within the XMP Toolkit the registered namespace URIs and prefixes must be unique. Additional namespaces encountered when parsing RDF are automatically registered.<p>
+The namespace URI should always end in an XML name separator such as '/' or '#'. This is because some forms of RDF shorthand catenate a namespace URI with an element name to form a new URI. <br><br></div></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">static bool&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#4c69d31a37ff24c85679229c479aa1ac">RegisterNamespace</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> namespaceURI, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> suggestedPrefix, tStringObj *registeredPrefix)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Register a namespace URI with a suggested prefix. <a href="#4c69d31a37ff24c85679229c479aa1ac"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">static bool&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#f28589472d8c0397db6cef868f2b8c97">GetNamespacePrefix</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> namespaceURI, tStringObj *namespacePrefix)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Obtain the prefix for a registered namespace URI. <a href="#f28589472d8c0397db6cef868f2b8c97"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">static bool&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#a20c84e7549d0a3252fa29a1e83a757a">GetNamespaceURI</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> namespacePrefix, tStringObj *namespaceURI)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Obtain the URI for a registered namespace prefix. <a href="#a20c84e7549d0a3252fa29a1e83a757a"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">static void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#3f989597e95db929676273cacd4ea09a">DeleteNamespace</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> namespaceURI)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Delete a namespace from the registry. <a href="#3f989597e95db929676273cacd4ea09a"></a><br></td></tr>
+<tr><td colspan="2"><div class="groupHeader">Alias Functions</div></td></tr>
+<tr><td colspan="2"><div class="groupText">Aliases in XMP serve the same purpose as Windows file shortcuts, Macintosh file aliases, or UNIX file symbolic links. The aliases are simply multiple names for the same property. One distinction of XMP aliases is that they are ordered, there is an alias name pointing to an actual name. The primary significance of the actual name is that it is the preferred name for output, generally the most widely recognized name.<p>
+The names that can be aliased in XMP are restricted. The alias must be a top level property name, not a field within a structure or an element within an array. The actual may be a top level property name, the first element within a top level array, or the default element in an alt-text array. This does not mean the alias can only be a simple property. It is OK to alias a top level structure or array to an identical top level structure or array, or to the first item of an array of structures. <br><br></div></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">static void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#b9463c7459125ca0038db2e586c5e4df">RegisterAlias</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> aliasNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> aliasProp, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> actualNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> actualProp, <a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> arrayForm=kXMP_NoOptions)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Associates an alias name with an actual name. <a href="#b9463c7459125ca0038db2e586c5e4df"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">static bool&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#c4b9c75202f2b961ad92f10a9e504e9a">ResolveAlias</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> aliasNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> aliasProp, tStringObj *actualNS, tStringObj *actualProp, <a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> *arrayForm)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Determines if a name is an alias, and what it is aliased to. <a href="#c4b9c75202f2b961ad92f10a9e504e9a"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">static void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#af64964e983235247ef65c86a42a4675">DeleteAlias</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> aliasNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> aliasProp)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Delete an alias. <a href="#af64964e983235247ef65c86a42a4675"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">static void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPMeta.html#b77cf73fa0cc63d845f113b3d1c83602">RegisterStandardAliases</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Registers all of the built-in aliases for a standard namespace. <a href="#b77cf73fa0cc63d845f113b3d1c83602"></a><br></td></tr>
+</table>
+<hr><a name="_details"></a><h2>Detailed Description</h2>
+<h3>template&lt;class tStringObj&gt;<br>
+ class TXMPMeta&lt; tStringObj &gt;</h3>
+
+Template class for the XMP Toolkit core services.
+<p>
+<code><a class="el" href="classTXMPMeta.html">TXMPMeta</a></code> is the template class providing the core services of the XMP Toolkit. It should be instantiated with a string class such as std::string. Please read the general toolkit usage notes for information about the overall architecture of the XMP API.<p>
+This template wraps a string object class around the raw XMP API. This provides two significant benefits, output strings are automatically copied and access is fully thread safe. The umbrella header, <code>XMP.hpp</code>, provides an <code>SXMPMeta</code> typedef for the instantiated template. String objects are only necessary for output strings. Input string are literals and passed as typical C <code>const char *</code>.<p>
+The template parameter, class <code>TtStringObj</code>, is described in the XMP.hpp umbrella header.<p>
+<b>Be aware that the <code><a class="el" href="classTXMPMeta.html">TXMPMeta</a></code> class is a normal C++ template, it is instantiated and local to each client executable. As are the other TXMP* classes. Different clients might not even use the same string type to instantiate <code><a class="el" href="classTXMPMeta.html">TXMPMeta</a></code>.</b><p>
+Because of this you should not pass <code>SXMPMeta</code> objects, or pointers to <code>SXMPMeta</code> objects, across DLL boundaries. There is a safe internal reference that you can pass, then construct a local object on the callee side. This construction does not create a cloned XMP tree, it is the same underlying XMP object safely wrapped in each client's <code>SXMPMeta</code> object.<p>
+Use GetInternalRef and the associated constructor like this: <div class="fragment"><pre class="fragment"> --- The callee's header contains:
+ CalleeMethod ( <a class="code" href="XMP__Const_8h.html#5912613564f80e17eb10acef9236f70a">XMPMetaRef</a> xmpRef );
+
+ --- The caller's code contains:
+ SXMPMeta callerXMP;
+ CalleeMethod ( callerXMP.GetInternalRef() );
+
+ --- The callee's code contains:
+ SXMPMeta calleeXMP ( xmpRef );
+</pre></div>
+<p>
+<hr><h2>Constructor &amp; Destructor Documentation</h2>
+<a class="anchor" name="7729cbce91956632289b88d85fdc65ae"></a><!-- doxytag: member="TXMPMeta::TXMPMeta" ref="7729cbce91956632289b88d85fdc65ae" args="()" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname"><a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt;::<a class="el" href="classTXMPMeta.html">TXMPMeta</a> </td>
+ <td>(</td>
+ <td class="paramname"> </td>
+ <td>&nbsp;)&nbsp;</td>
+ <td width="100%"></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Default constructor, creates an empty object.
+<p>
+The default constructor creates a new empty <code><a class="el" href="classTXMPMeta.html">TXMPMeta</a></code> object.
+</div>
+</div><p>
+<a class="anchor" name="21a4d06fc2e77b28991bb900f0f48e50"></a><!-- doxytag: member="TXMPMeta::TXMPMeta" ref="21a4d06fc2e77b28991bb900f0f48e50" args="(const TXMPMeta&lt; tStringObj &gt; &amp;original)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname"><a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt;::<a class="el" href="classTXMPMeta.html">TXMPMeta</a> </td>
+ <td>(</td>
+ <td class="paramtype">const <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt; &amp;&nbsp;</td>
+ <td class="paramname"> <em>original</em> </td>
+ <td>&nbsp;)&nbsp;</td>
+ <td width="100%"></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Copy constructor, creates a client object refering to the same internal object.
+<p>
+The copy constructor creates a new <code><a class="el" href="classTXMPMeta.html">TXMPMeta</a></code> object that refers to the same internal XMP object.
+</div>
+</div><p>
+<a class="anchor" name="cbe8f556a5b32542c44fa9de9648ad41"></a><!-- doxytag: member="TXMPMeta::TXMPMeta" ref="cbe8f556a5b32542c44fa9de9648ad41" args="(XMPMetaRef xmpRef)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname"><a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt;::<a class="el" href="classTXMPMeta.html">TXMPMeta</a> </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#5912613564f80e17eb10acef9236f70a">XMPMetaRef</a>&nbsp;</td>
+ <td class="paramname"> <em>xmpRef</em> </td>
+ <td>&nbsp;)&nbsp;</td>
+ <td width="100%"></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Reconstruct an XMP object from an internal ref.
+<p>
+This constructor creates a new <code><a class="el" href="classTXMPMeta.html">TXMPMeta</a></code> object that refers to the underlying <code>xmpRef</code>, which was obtained from some other XMP object by the <code>GetInternalRef</code> method. This is used to safely pass XMP objects across DLL boundaries.
+</div>
+</div><p>
+<a class="anchor" name="05199e2a4bc61db7aed207759e899bc2"></a><!-- doxytag: member="TXMPMeta::TXMPMeta" ref="05199e2a4bc61db7aed207759e899bc2" args="(XMP_StringPtr buffer, XMP_StringLen xmpSize)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname"><a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt;::<a class="el" href="classTXMPMeta.html">TXMPMeta</a> </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>buffer</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#9f7dcc184f901c713274edfdac5bcc9a">XMP_StringLen</a>&nbsp;</td>
+ <td class="paramname"> <em>xmpSize</em></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Construct an object and parse one buffer of RDF into it.
+<p>
+This constructor creates a new <code><a class="el" href="classTXMPMeta.html">TXMPMeta</a></code> object and populates it with metadata from a buffer containing serialized RDF. This buffer must be a complete RDF parse stream. Pass (0,0) to construct an empty <code><a class="el" href="classTXMPMeta.html">TXMPMeta</a></code> object. The result of an actual parse is identical to creating an empty object then calling <code><a class="el" href="classTXMPMeta.html#7b383f5b357fff040cdbde82f4f43f26">TXMPMeta::ParseFromBuffer</a></code>. The RDF must be complete. If you need to parse with multiple buffers, create an empty object and use <code><a class="el" href="classTXMPMeta.html#7b383f5b357fff040cdbde82f4f43f26">TXMPMeta::ParseFromBuffer</a></code>.<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>buffer</em>&nbsp;</td><td>A pointer to the buffer of RDF to be parsed. May be null if the length is 0.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>xmpSize</em>&nbsp;</td><td>The length in bytes of the buffer. </td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<hr><h2>Member Function Documentation</h2>
+<a class="anchor" name="bfddf1df0e01ab33d5636a80edc973ca"></a><!-- doxytag: member="TXMPMeta::Initialize" ref="bfddf1df0e01ab33d5636a80edc973ca" args="()" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">static bool <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt;::Initialize </td>
+ <td>(</td>
+ <td class="paramname"> </td>
+ <td>&nbsp;)&nbsp;</td>
+ <td width="100%"><code> [static]</code></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Initialize the XMP Toolkit.
+<p>
+The XMP Toolkit may be explicitly initialized before use. The allocate/delete parameters must be either both null (0), or both non-null.
+</div>
+</div><p>
+<a class="anchor" name="4d5a601c9b77f6f6ab5f14e658de58ef"></a><!-- doxytag: member="TXMPMeta::operator=" ref="4d5a601c9b77f6f6ab5f14e658de58ef" args="(const TXMPMeta&lt; tStringObj &gt; &amp;rhs)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">void <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt;::operator= </td>
+ <td>(</td>
+ <td class="paramtype">const <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt; &amp;&nbsp;</td>
+ <td class="paramname"> <em>rhs</em> </td>
+ <td>&nbsp;)&nbsp;</td>
+ <td width="100%"></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Assignment operator, assigns the internal ref and increments the ref count.
+<p>
+The assignment operator assigns the internal ref from the rhs object and increments the reference count on the underlying internal XMP object.
+</div>
+</div><p>
+<a class="anchor" name="e7bb38d9b3857b08106630a386b47332"></a><!-- doxytag: member="TXMPMeta::SetGlobalOptions" ref="e7bb38d9b3857b08106630a386b47332" args="(XMP_OptionBits options)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">static void <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt;::SetGlobalOptions </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a>&nbsp;</td>
+ <td class="paramname"> <em>options</em> </td>
+ <td>&nbsp;)&nbsp;</td>
+ <td width="100%"><code> [static]</code></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+<code>SetGlobalOptions</code> updates the set of global option flags. The entire set is replaced with the new values. If only one flag is to be modified, use <code>GetGlobalOptions</code> to obtain the current set, modify the desired flag, then use <code>SetGlobalOptions</code>.
+<p>
+<dl class="note" compact><dt><b>Note:</b></dt><dd>There are no options to set yet. </dd></dl>
+
+</div>
+</div><p>
+<a class="anchor" name="4c69d31a37ff24c85679229c479aa1ac"></a><!-- doxytag: member="TXMPMeta::RegisterNamespace" ref="4c69d31a37ff24c85679229c479aa1ac" args="(XMP_StringPtr namespaceURI, XMP_StringPtr suggestedPrefix, tStringObj *registeredPrefix)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">static bool <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt;::RegisterNamespace </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>namespaceURI</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>suggestedPrefix</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">tStringObj *&nbsp;</td>
+ <td class="paramname"> <em>registeredPrefix</em></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"><code> [static]</code></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Register a namespace URI with a suggested prefix.
+<p>
+It is not an error if the URI is already registered, no matter what the prefix is. If the URI is not registered but the suggested prefix is in use, a unique prefix is created from the suggested one. The actual registeed prefix is always returned. The function result tells if the registered prefix is the suggested one.<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>namespaceURI</em>&nbsp;</td><td>The URI for the namespace. Must be a valid XML URI.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>suggestedPrefix</em>&nbsp;</td><td>The suggested prefix to be used if the URI is not yet registered. Must be a valid XML name.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>registeredPrefix</em>&nbsp;</td><td>Returns the prefix actually registered for this URI.</td></tr>
+ </table>
+</dl>
+<dl class="return" compact><dt><b>Returns:</b></dt><dd>Returns true if the registered prefix matches the suggested prefix.</dd></dl>
+<dl class="note" compact><dt><b>Note:</b></dt><dd>No checking is presently done on either the URI or the prefix. </dd></dl>
+
+</div>
+</div><p>
+<a class="anchor" name="f28589472d8c0397db6cef868f2b8c97"></a><!-- doxytag: member="TXMPMeta::GetNamespacePrefix" ref="f28589472d8c0397db6cef868f2b8c97" args="(XMP_StringPtr namespaceURI, tStringObj *namespacePrefix)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">static bool <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt;::GetNamespacePrefix </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>namespaceURI</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">tStringObj *&nbsp;</td>
+ <td class="paramname"> <em>namespacePrefix</em></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"><code> [static]</code></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Obtain the prefix for a registered namespace URI.
+<p>
+It is not an error if the namespace URI is not registered. The output <code>namespacePrefix</code> string is not modified if the namespace URI is not registered.<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>namespaceURI</em>&nbsp;</td><td>The URI for the namespace. Must not be null or the empty string.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>namespacePrefix</em>&nbsp;</td><td>Returns the prefix registered for this URI, with a terminating ':'.</td></tr>
+ </table>
+</dl>
+<dl class="return" compact><dt><b>Returns:</b></dt><dd>Returns true if the namespace URI is registered. </dd></dl>
+
+</div>
+</div><p>
+<a class="anchor" name="a20c84e7549d0a3252fa29a1e83a757a"></a><!-- doxytag: member="TXMPMeta::GetNamespaceURI" ref="a20c84e7549d0a3252fa29a1e83a757a" args="(XMP_StringPtr namespacePrefix, tStringObj *namespaceURI)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">static bool <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt;::GetNamespaceURI </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>namespacePrefix</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">tStringObj *&nbsp;</td>
+ <td class="paramname"> <em>namespaceURI</em></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"><code> [static]</code></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Obtain the URI for a registered namespace prefix.
+<p>
+It is not an error if the namespace prefix is not registered. The output <code>namespaceURI</code> string is not modified if the namespace prefix is not registered.<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>namespacePrefix</em>&nbsp;</td><td>The prefix for the namespace. Must not be null or the empty string.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>namespaceURI</em>&nbsp;</td><td>Returns the URI registered for this prefix.</td></tr>
+ </table>
+</dl>
+<dl class="return" compact><dt><b>Returns:</b></dt><dd>Returns true if the namespace prefix is registered. </dd></dl>
+
+</div>
+</div><p>
+<a class="anchor" name="3f989597e95db929676273cacd4ea09a"></a><!-- doxytag: member="TXMPMeta::DeleteNamespace" ref="3f989597e95db929676273cacd4ea09a" args="(XMP_StringPtr namespaceURI)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">static void <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt;::DeleteNamespace </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>namespaceURI</em> </td>
+ <td>&nbsp;)&nbsp;</td>
+ <td width="100%"><code> [static]</code></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Delete a namespace from the registry.
+<p>
+Does nothing if the URI is not registered, or if the <code>namespaceURI</code> parameter is null or the empty string.<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>namespaceURI</em>&nbsp;</td><td>The URI for the namespace.</td></tr>
+ </table>
+</dl>
+<dl class="note" compact><dt><b>Note:</b></dt><dd><b>Not yet implemented.</b> </dd></dl>
+
+</div>
+</div><p>
+<a class="anchor" name="b9463c7459125ca0038db2e586c5e4df"></a><!-- doxytag: member="TXMPMeta::RegisterAlias" ref="b9463c7459125ca0038db2e586c5e4df" args="(XMP_StringPtr aliasNS, XMP_StringPtr aliasProp, XMP_StringPtr actualNS, XMP_StringPtr actualProp, XMP_OptionBits arrayForm=kXMP_NoOptions)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">static void <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt;::RegisterAlias </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>aliasNS</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>aliasProp</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>actualNS</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>actualProp</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a>&nbsp;</td>
+ <td class="paramname"> <em>arrayForm</em> = <code>kXMP_NoOptions</code></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"><code> [static]</code></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Associates an alias name with an actual name.
+<p>
+Define a alias mapping from one namespace/property to another. Both property names must be simple names. An alias can be a direct mapping, where the alias and actual have the same data type. It is also possible to map a simple alias to an item in an array. This can either be to the first item in the array, or to the 'x-default' item in an alt-text array. Multiple alias names may map to the same actual, as long as the forms match. It is a no-op to reregister an alias in an identical fashion.<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>aliasNS</em>&nbsp;</td><td>The namespace URI for the alias. Must not be null or the empty string.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>aliasProp</em>&nbsp;</td><td>The name of the alias. Must be a simple name, not null or the empty string and not a general path expression.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>actualNS</em>&nbsp;</td><td>The namespace URI for the actual. Must not be null or the empty string.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>actualProp</em>&nbsp;</td><td>The name of the actual. Must be a simple name, not null or the empty string and not a general path expression.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>arrayForm</em>&nbsp;</td><td>Provides the array form for simple aliases to an array item. This is needed to know what kind of array to create if set for the first time via the simple alias. Pass <code>kXMP_NoOptions</code>, the default value, for all direct aliases regardless of whether the actual data type is an array or not.</td></tr>
+ </table>
+</dl>
+Constants for the arrayForm parameter:<p>
+<ul>
+<li><code>kXMP_NoOptions</code> - This is a direct mapping. The actual data type does not matter. </li>
+<li><code>kXMP_PropValueIsArray</code> - The actual is an unordered array, the alias is to the first element of the array. </li>
+<li><code>kXMP_PropArrayIsOrdered</code> - The actual is an ordered array, the alias is to the first element of the array. </li>
+<li><code>kXMP_PropArrayIsAlternate</code> - The actual is an alternate array, the alias is to the first element of the array. </li>
+<li><code>kXMP_PropArrayIsAltText</code> - The actual is an alternate text array, the alias is to the 'x-default' element of the array. </li>
+</ul>
+
+</div>
+</div><p>
+<a class="anchor" name="c4b9c75202f2b961ad92f10a9e504e9a"></a><!-- doxytag: member="TXMPMeta::ResolveAlias" ref="c4b9c75202f2b961ad92f10a9e504e9a" args="(XMP_StringPtr aliasNS, XMP_StringPtr aliasProp, tStringObj *actualNS, tStringObj *actualProp, XMP_OptionBits *arrayForm)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">static bool <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt;::ResolveAlias </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>aliasNS</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>aliasProp</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">tStringObj *&nbsp;</td>
+ <td class="paramname"> <em>actualNS</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">tStringObj *&nbsp;</td>
+ <td class="paramname"> <em>actualProp</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> *&nbsp;</td>
+ <td class="paramname"> <em>arrayForm</em></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"><code> [static]</code></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Determines if a name is an alias, and what it is aliased to.
+<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>aliasNS</em>&nbsp;</td><td>The namespace URI for the alias. Must not be null or the empty string.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>aliasProp</em>&nbsp;</td><td>The name of the alias. May be an arbitrary path expression path, must not null or the empty string.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>actualNS</em>&nbsp;</td><td>Untouched if <code>aliasNS:aliasProp</code> is not an alias. Otherwise returns the namespace URI for the actual. May be null if the namespace URI is not wanted.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>actualProp</em>&nbsp;</td><td>Untouched if <code>aliasNS:aliasProp</code> is not an alias. Otherwise returns the path of the actual. May be null if the actual's path is not wanted.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>arrayForm</em>&nbsp;</td><td>Untouched if <code>aliasNS:aliasProp</code> is not an alias. Otherwise returns the form of the actual. This is 0 (<code>kXMP_NoOptions</code>) if the alias and actual forms match, otherwise it is the options passed to <code><a class="el" href="classTXMPMeta.html#b9463c7459125ca0038db2e586c5e4df">TXMPMeta::RegisterAlias</a></code>. May be null if the actual's form is not wanted.</td></tr>
+ </table>
+</dl>
+<dl class="return" compact><dt><b>Returns:</b></dt><dd>Returns true if the input is an alias.</dd></dl>
+<dl class="note" compact><dt><b>Note:</b></dt><dd>The client output strings are not written until return, so a call like the following may be used to "reduce" a path to the base form: <div class="fragment"><pre class="fragment"> isAlias = SXMPMeta::ResolveAlias ( ns.c_str(), path.c_str(), &amp;ns, &amp;path, 0 );
+</pre></div> </dd></dl>
+
+</div>
+</div><p>
+<a class="anchor" name="af64964e983235247ef65c86a42a4675"></a><!-- doxytag: member="TXMPMeta::DeleteAlias" ref="af64964e983235247ef65c86a42a4675" args="(XMP_StringPtr aliasNS, XMP_StringPtr aliasProp)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">static void <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt;::DeleteAlias </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>aliasNS</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>aliasProp</em></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"><code> [static]</code></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Delete an alias.
+<p>
+This only deletes the registration of the alias, it does not delete the actual property. It does delete any view of the property through the alias name. It is OK to attempt to delete an alias that does not exist, that is if the alias name is not registered as an alias.<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>aliasNS</em>&nbsp;</td><td>The namespace URI for the alias. Must not be null or the empty string.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>aliasProp</em>&nbsp;</td><td>The name of the alias. Must be a simple name, not null or the empty string and not a general path expression. </td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<a class="anchor" name="b77cf73fa0cc63d845f113b3d1c83602"></a><!-- doxytag: member="TXMPMeta::RegisterStandardAliases" ref="b77cf73fa0cc63d845f113b3d1c83602" args="(XMP_StringPtr schemaNS)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">static void <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt;::RegisterStandardAliases </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>schemaNS</em> </td>
+ <td>&nbsp;)&nbsp;</td>
+ <td width="100%"><code> [static]</code></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Registers all of the built-in aliases for a standard namespace.
+<p>
+The built-in aliases are documented in the XMP Specification. This registers the aliases in the given namespace, that is the aliases from this namespace to actuals in other namespaces.<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>schemaNS</em>&nbsp;</td><td>The namespace URI for the aliases. Must not be null or the empty string. </td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<a class="anchor" name="06a3241c7fa5df87f61dff02fca23a0c"></a><!-- doxytag: member="TXMPMeta::GetProperty" ref="06a3241c7fa5df87f61dff02fca23a0c" args="(XMP_StringPtr schemaNS, XMP_StringPtr propName, tStringObj *propValue, XMP_OptionBits *options) const " -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">bool <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt;::GetProperty </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>schemaNS</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>propName</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">tStringObj *&nbsp;</td>
+ <td class="paramname"> <em>propValue</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> *&nbsp;</td>
+ <td class="paramname"> <em>options</em></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"> const</td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+<code>GetProperty</code> is the simplest property getter, mainly for top level simple properties or after using the path composition functions in <code><a class="el" href="classTXMPUtils.html">TXMPUtils</a></code>.
+<p>
+<dl class="return" compact><dt><b>Returns:</b></dt><dd>Returns true if the property exists.</dd></dl>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>schemaNS</em>&nbsp;</td><td>The namespace URI for the property. May be null or the empty string if the first component of the propName path contains a namespace prefix. The URI must be for a registered namespace.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>propName</em>&nbsp;</td><td>The name of the property. May be a general path expression, must not be null or the empty string. Using a namespace prefix on the first component is optional. If present without a <code>schemaNS</code> value then the prefix specifies the namespace. The prefix must be for a registered namespace. If both a <code>schemaNS</code> URI and <code>propName</code> prefix are present, they must be corresponding parts of a registered namespace.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>propValue</em>&nbsp;</td><td>A pointer to the string that is assigned the value of the property, if the property has a value. Arrays and non-leaf levels of structs do not have values. May be null if the value is not wanted.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>options</em>&nbsp;</td><td>A pointer to the <code>XMP_OptionBits</code> variable that is assigned option flags describing the property. May be null if the flags are not wanted. </td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<a class="anchor" name="c64a4251d157937f69b73f2ffac4f7cc"></a><!-- doxytag: member="TXMPMeta::GetArrayItem" ref="c64a4251d157937f69b73f2ffac4f7cc" args="(XMP_StringPtr schemaNS, XMP_StringPtr arrayName, XMP_Index itemIndex, tStringObj *itemValue, XMP_OptionBits *options) const " -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">bool <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt;::GetArrayItem </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>schemaNS</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>arrayName</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#00e9d9a76c144421105a4c2742203315">XMP_Index</a>&nbsp;</td>
+ <td class="paramname"> <em>itemIndex</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">tStringObj *&nbsp;</td>
+ <td class="paramname"> <em>itemValue</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> *&nbsp;</td>
+ <td class="paramname"> <em>options</em></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"> const</td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+<code>GetArrayItem</code> provides access to items within an array. The index is passed as an integer, you need not worry about the path string syntax for array items, convert a loop index to a string, etc.
+<p>
+<dl class="return" compact><dt><b>Returns:</b></dt><dd>Returns true if the array item exists.</dd></dl>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>schemaNS</em>&nbsp;</td><td>The namespace URI for the array. Has the same usage as in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>arrayName</em>&nbsp;</td><td>The name of the array. May be a general path expression, must not be null or the empty string. Has the same namespace prefix usage as <code>propName</code> in <code>GeProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>itemIndex</em>&nbsp;</td><td>The index of the desired item. Arrays in XMP are indexed from 1. The constant <code>kXMP_ArrayLastItem</code> always refers to the last existing array item.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>itemValue</em>&nbsp;</td><td>A pointer to the string that is assigned the value of the array item, if the array item has a value. Arrays and non-leaf levels of structs do not have values. May be null if the value is not wanted.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>options</em>&nbsp;</td><td>A pointer to the <code>XMP_OptionBits</code> variable that is assigned option flags describing the array item. May be null if the flags are not wanted. </td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<a class="anchor" name="e99d2bc414d5cd68851147aef6710d4a"></a><!-- doxytag: member="TXMPMeta::GetStructField" ref="e99d2bc414d5cd68851147aef6710d4a" args="(XMP_StringPtr schemaNS, XMP_StringPtr structName, XMP_StringPtr fieldNS, XMP_StringPtr fieldName, tStringObj *fieldValue, XMP_OptionBits *options) const" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">bool <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt;::GetStructField </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>schemaNS</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>structName</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>fieldNS</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>fieldName</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">tStringObj *&nbsp;</td>
+ <td class="paramname"> <em>fieldValue</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> *&nbsp;</td>
+ <td class="paramname"> <em>options</em></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"> const</td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+<code>GetStructField</code> provides access to fields within a nested structure. The namespace for the field is passed as a URI, you need not worry about the path string syntax.
+<p>
+The names of fields should be XML qualified names, that is within an XML namespace. The path syntax for a qualified name uses the namespace prefix. This is unreliable since the prefix is never guaranteed. The URI is the formal name, the prefix is just a local shorthand in a given sequence of XML text.<p>
+<dl class="return" compact><dt><b>Returns:</b></dt><dd>Returns true if the field exists.</dd></dl>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>schemaNS</em>&nbsp;</td><td>The namespace URI for the struct. Has the same usage as in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>structName</em>&nbsp;</td><td>The name of the struct. May be a general path expression, must not be null or the empty string. Has the same namespace prefix usage as <code>propName</code> in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>fieldNS</em>&nbsp;</td><td>The namespace URI for the field. Has the same URI and prefix usage as the <code>schemaNS</code> parameter.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>fieldName</em>&nbsp;</td><td>The name of the field. Must be a single XML name, must not be null or the empty string. Has the same namespace prefix usage as the <code>structName</code> parameter.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>fieldValue</em>&nbsp;</td><td>A pointer to the string that is assigned the value of the field, if the field has a value. Arrays and non-leaf levels of structs do not have values. May be null if the value is not wanted.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>options</em>&nbsp;</td><td>A pointer to the <code>XMP_OptionBits</code> variable that is assigned option flags describing the field. May be null if the flags are not wanted. </td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<a class="anchor" name="2cc58d8316043b035643e7c21633bc13"></a><!-- doxytag: member="TXMPMeta::GetQualifier" ref="2cc58d8316043b035643e7c21633bc13" args="(XMP_StringPtr schemaNS, XMP_StringPtr propName, XMP_StringPtr qualNS, XMP_StringPtr qualName, tStringObj *qualValue, XMP_OptionBits *options) const " -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">bool <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt;::GetQualifier </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>schemaNS</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>propName</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>qualNS</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>qualName</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">tStringObj *&nbsp;</td>
+ <td class="paramname"> <em>qualValue</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> *&nbsp;</td>
+ <td class="paramname"> <em>options</em></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"> const</td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+<code>GetQualifier</code> provides access to a qualifier attached to a property. The namespace for the qualifier is passed as a URI, you need not worry about the path string syntax. In many regards qualifiers are like struct fields. See the introductory discussion of qualified properties for more information.
+<p>
+The names of qualifiers should be XML qualified names, that is within an XML namespace. The path syntax for a qualified name uses the namespace prefix. This is unreliable since the prefix is never guaranteed. The URI is the formal name, the prefix is just a local shorthand in a given sequence of XML text.<p>
+<dl class="note" compact><dt><b>Note:</b></dt><dd>Qualifiers are only supported for simple leaf properties at this time.</dd></dl>
+<dl class="return" compact><dt><b>Returns:</b></dt><dd>Returns true if the qualifier exists.</dd></dl>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>schemaNS</em>&nbsp;</td><td>The namespace URI for the struct. Has the same usage as in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>propName</em>&nbsp;</td><td>The name of the property to which the qualifier is attached. May be a general path expression, must not be null or the empty string. Has the same namespace prefix usage as in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>qualNS</em>&nbsp;</td><td>The namespace URI for the qualifier. Has the same URI and prefix usage as the <code>schemaNS</code> parameter.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>qualName</em>&nbsp;</td><td>The name of the qualifier. Must be a single XML name, must not be null or the empty string. Has the same namespace prefix usage as the <code>propName</code> parameter.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>qualValue</em>&nbsp;</td><td>A pointer to the string that is assigned the value of the qualifier, if the qualifier has a value. Arrays and non-leaf levels of structs do not have values. May be null if the value is not wanted.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>options</em>&nbsp;</td><td>A pointer to the <code>XMP_OptionBits</code> variable that is assigned option flags describing the qualifier. May be null if the flags are not wanted. </td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<a class="anchor" name="1dfd6a08ebfd1a6364b3a7b6584bcc28"></a><!-- doxytag: member="TXMPMeta::SetProperty" ref="1dfd6a08ebfd1a6364b3a7b6584bcc28" args="(XMP_StringPtr schemaNS, XMP_StringPtr propName, XMP_StringPtr propValue, XMP_OptionBits options=0)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">void <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt;::SetProperty </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>schemaNS</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>propName</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>propValue</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a>&nbsp;</td>
+ <td class="paramname"> <em>options</em> = <code>0</code></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+<code>SetProperty</code> is the simplest property setter, mainly for top level simple properties or after using the path composition functions in <code><a class="el" href="classTXMPUtils.html">TXMPUtils</a></code>.
+<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>schemaNS</em>&nbsp;</td><td>The namespace URI for the property. Has the same usage as in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>propName</em>&nbsp;</td><td>The name of the property. Has the same usage as in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>propValue</em>&nbsp;</td><td>A pointer to the null terminated UTF-8 string that is the value of the property, if the property has a value. Arrays and non-leaf levels of structs do not have values. Must be null if the value is not relevant.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>options</em>&nbsp;</td><td>Option flags describing the property. See the earlier description. </td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<a class="anchor" name="1570eb89d613b4a94ca572e4644168cc"></a><!-- doxytag: member="TXMPMeta::SetArrayItem" ref="1570eb89d613b4a94ca572e4644168cc" args="(XMP_StringPtr schemaNS, XMP_StringPtr arrayName, XMP_Index itemIndex, XMP_StringPtr itemValue, XMP_OptionBits options=0)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">void <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt;::SetArrayItem </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>schemaNS</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>arrayName</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#00e9d9a76c144421105a4c2742203315">XMP_Index</a>&nbsp;</td>
+ <td class="paramname"> <em>itemIndex</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>itemValue</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a>&nbsp;</td>
+ <td class="paramname"> <em>options</em> = <code>0</code></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+<code>SetArrayItem</code> provides access to items within an array. The index is passed as an integer, you need not worry about the path string syntax for array items, convert a loop index to a string, etc. The array passed to <code>SetArrayItem</code> must already exist. See also <code>AppendArrayItem</code>.
+<p>
+In normal usage the selected array item is modified. A new item is automatically appended if the index is the array size plus 1. A new item may be inserted before or after any item by using one of the following option flags:<p>
+<ul>
+<li><code>kXMP_InsertBeforeItem</code> - Insert a new array item before the selected one. </li>
+<li><code>kXMP_InsertAfterItem</code> - Insert a new array item after the selected one.</li>
+</ul>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>schemaNS</em>&nbsp;</td><td>The namespace URI for the array. Has the same usage as in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>arrayName</em>&nbsp;</td><td>The name of the array. May be a general path expression, must not be null or the empty string. Has the same namespace prefix usage as <code>propName</code> in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>itemIndex</em>&nbsp;</td><td>The index of the desired item. Arrays in XMP are indexed from 1. The constant <code>kXMP_ArrayLastItem</code> always refers to the last existing array item.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>itemValue</em>&nbsp;</td><td>A pointer to the null terminated UTF-8 string that is the value of the array item, if the array item has a value. Has the same usage as <code>propValue</code> in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>options</em>&nbsp;</td><td>Option flags describing the item. See the earlier description. </td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<a class="anchor" name="00d7314dc970ad390499ce9db27d314a"></a><!-- doxytag: member="TXMPMeta::AppendArrayItem" ref="00d7314dc970ad390499ce9db27d314a" args="(XMP_StringPtr schemaNS, XMP_StringPtr arrayName, XMP_OptionBits arrayOptions, XMP_StringPtr itemValue, XMP_OptionBits itemOptions=0)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">void <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt;::AppendArrayItem </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>schemaNS</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>arrayName</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a>&nbsp;</td>
+ <td class="paramname"> <em>arrayOptions</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>itemValue</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a>&nbsp;</td>
+ <td class="paramname"> <em>itemOptions</em> = <code>0</code></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+<code>AppendArrayItem</code> simplifies construction of an array by not requiring that you pre-create an empty array. The array that is assigned is created automatically if it does not yet exist. Each call to <code>AppendArrayItem</code> appends an item to the array. The corresponding parameters have the same use as <code>SetArrayItem</code>. The <code>arrayOptions</code> parameter is used to specify what kind of array. If the array exists, it must have the specified form.
+<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>schemaNS</em>&nbsp;</td><td>The namespace URI for the array. Has the same usage as in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>arrayName</em>&nbsp;</td><td>The name of the array. May be a general path expression, must not be null or the empty string. Has the same namespace prefix usage as <code>propPath</code> in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>arrayOptions</em>&nbsp;</td><td>Option flags describing the array form. The only valid bits are those that are part of <code>kXMP_PropArrayFormMask:</code> <code>kXMP_PropValueIsArray</code>, <code>kXMP_PropArrayIsOrdered</code>, <code>kXMP_PropArrayIsAlternate</code>, or <code>kXMP_PropArrayIsAltText</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>itemValue</em>&nbsp;</td><td>A pointer to the null terminated UTF-8 string that is the value of the array item, if the array item has a value. Has the same usage as <code>propValue</code> in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>itemOptions</em>&nbsp;</td><td>Option flags describing the item. See the earlier description. </td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<a class="anchor" name="0e44c30e7527064909e5f7035d53c4f5"></a><!-- doxytag: member="TXMPMeta::SetStructField" ref="0e44c30e7527064909e5f7035d53c4f5" args="(XMP_StringPtr schemaNS, XMP_StringPtr structName, XMP_StringPtr fieldNS, XMP_StringPtr fieldName, XMP_StringPtr fieldValue, XMP_OptionBits options=0)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">void <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt;::SetStructField </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>schemaNS</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>structName</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>fieldNS</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>fieldName</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>fieldValue</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a>&nbsp;</td>
+ <td class="paramname"> <em>options</em> = <code>0</code></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+<code>SetStructField</code> provides access to fields within a nested structure. The namespace for the field is passed as a URI, you need not worry about the path string syntax.
+<p>
+The names of fields should be XML qualified names, that is within an XML namespace. The path syntax for a qualified name uses the namespace prefix, which is unreliable because the prefix is never guaranteed. The URI is the formal name, the prefix is just a local shorthand in a given sequence of XML text.<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>schemaNS</em>&nbsp;</td><td>The namespace URI for the struct. Has the same usage as in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>structName</em>&nbsp;</td><td>The name of the struct. May be a general path expression, must not be null or the empty string. Has the same namespace prefix usage as <code>propName</code> in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>fieldNS</em>&nbsp;</td><td>The namespace URI for the field. Has the same URI and prefix usage as the <code>schemaNS</code> parameter.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>fieldName</em>&nbsp;</td><td>The name of the field. Must be a single XML name, must not be null or the empty string. Has the same namespace prefix usage as the <code>structName</code> parameter.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>fieldValue</em>&nbsp;</td><td>A pointer to the null terminated UTF-8 string that is the value of the field, if the field has a value. Has the same usage as <code>propValue</code> in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>options</em>&nbsp;</td><td>Option flags describing the field. See the earlier description. </td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<a class="anchor" name="c2e798da5f9d94e486382a41e73fcea3"></a><!-- doxytag: member="TXMPMeta::SetQualifier" ref="c2e798da5f9d94e486382a41e73fcea3" args="(XMP_StringPtr schemaNS, XMP_StringPtr propName, XMP_StringPtr qualNS, XMP_StringPtr qualName, XMP_StringPtr qualValue, XMP_OptionBits options=0)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">void <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt;::SetQualifier </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>schemaNS</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>propName</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>qualNS</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>qualName</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>qualValue</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a>&nbsp;</td>
+ <td class="paramname"> <em>options</em> = <code>0</code></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+<code>SetQualifier</code> provides access to a qualifier attached to a property. The namespace for the qualifier is passed as a URI, you need not worry about the path string syntax. In many regards qualifiers are like struct fields. See the introductory discussion of qualified properties for more information.
+<p>
+The names of qualifiers should be XML qualified names, that is within an XML namespace. The path syntax for a qualified name uses the namespace prefix, which is unreliable because the prefix is never guaranteed. The URI is the formal name, the prefix is just a local shorthand in a given sequence of XML text.<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>schemaNS</em>&nbsp;</td><td>The namespace URI for the struct. Has the same usage as in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>propName</em>&nbsp;</td><td>The name of the property to which the qualifier is attached. Has the same usage as in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>qualNS</em>&nbsp;</td><td>The namespace URI for the qualifier. Has the same URI and prefix usage as the <code>schemaNS</code> parameter.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>qualName</em>&nbsp;</td><td>The name of the qualifier. Must be a single XML name, must not be null or the empty string. Has the same namespace prefix usage as the <code>propName</code> parameter.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>qualValue</em>&nbsp;</td><td>A pointer to the null terminated UTF-8 string that is the value of the qualifier, if the qualifier has a value. Has the same usage as <code>propValue</code> in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>options</em>&nbsp;</td><td>Option flags describing the qualifier. See the earlier description. </td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<a class="anchor" name="c8b555ba99904fa49bb4851a60cc3844"></a><!-- doxytag: member="TXMPMeta::DeleteProperty" ref="c8b555ba99904fa49bb4851a60cc3844" args="(XMP_StringPtr schemaNS, XMP_StringPtr propName)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">void <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt;::DeleteProperty </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>schemaNS</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>propName</em></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+<code>DeleteProperty</code> deletes the given XMP subtree rooted at the given property. It is not an error if the property does not exist.
+<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>schemaNS</em>&nbsp;</td><td>The namespace URI for the property. Has the same usage as in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>propName</em>&nbsp;</td><td>The name of the property. Has the same usage as in <code>GetProperty</code>. </td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<a class="anchor" name="bc1211f47225b5973a170ff952743264"></a><!-- doxytag: member="TXMPMeta::DeleteArrayItem" ref="bc1211f47225b5973a170ff952743264" args="(XMP_StringPtr schemaNS, XMP_StringPtr arrayName, XMP_Index itemIndex)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">void <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt;::DeleteArrayItem </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>schemaNS</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>arrayName</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#00e9d9a76c144421105a4c2742203315">XMP_Index</a>&nbsp;</td>
+ <td class="paramname"> <em>itemIndex</em></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+<code>DeleteArrayItem</code> deletes the given XMP subtree rooted at the given array item. It is not an error if the array item does not exist.
+<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>schemaNS</em>&nbsp;</td><td>The namespace URI for the array. Has the same usage as in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>arrayName</em>&nbsp;</td><td>The name of the array. May be a general path expression, must not be null or the empty string. Has the same namespace prefix usage as <code>propName</code> in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>itemIndex</em>&nbsp;</td><td>The index of the desired item. Arrays in XMP are indexed from 1. The constant <code>kXMP_ArrayLastItem</code> always refers to the last existing array item. </td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<a class="anchor" name="bc258e027780a15be65a88fcfd4e1fd4"></a><!-- doxytag: member="TXMPMeta::DeleteStructField" ref="bc258e027780a15be65a88fcfd4e1fd4" args="(XMP_StringPtr schemaNS, XMP_StringPtr structName, XMP_StringPtr fieldNS, XMP_StringPtr fieldName)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">void <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt;::DeleteStructField </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>schemaNS</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>structName</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>fieldNS</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>fieldName</em></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+<code>DeleteStructField</code> deletes the given XMP subtree rooted at the given struct field. It is not an error if the field does not exist.
+<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>schemaNS</em>&nbsp;</td><td>The namespace URI for the struct. Has the same usage as in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>structName</em>&nbsp;</td><td>The name of the struct. May be a general path expression, must not be null or the empty string. Has the same namespace prefix usage as <code>propName</code> in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>fieldNS</em>&nbsp;</td><td>The namespace URI for the field. Has the same URI and prefix usage as the <code>schemaNS</code> parameter.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>fieldName</em>&nbsp;</td><td>The name of the field. Must be a single XML name, must not be null or the empty string. Has the same namespace prefix usage as the <code>structName</code> parameter. </td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<a class="anchor" name="8ce15f7de7fd3b258f07158ab5fa88be"></a><!-- doxytag: member="TXMPMeta::DeleteQualifier" ref="8ce15f7de7fd3b258f07158ab5fa88be" args="(XMP_StringPtr schemaNS, XMP_StringPtr propName, XMP_StringPtr qualNS, XMP_StringPtr qualName)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">void <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt;::DeleteQualifier </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>schemaNS</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>propName</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>qualNS</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>qualName</em></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+<code>DeleteQualifier</code> deletes the given XMP subtree rooted at the given qualifier. It is not an error if the qualifier does not exist.
+<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>schemaNS</em>&nbsp;</td><td>The namespace URI for the struct. Has the same usage as in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>propName</em>&nbsp;</td><td>The name of the property to which the qualifier is attached. Has the same usage as in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>qualNS</em>&nbsp;</td><td>The namespace URI for the qualifier. Has the same URI and prefix usage as the <code>schemaNS</code> parameter.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>qualName</em>&nbsp;</td><td>The name of the qualifier. Must be a single XML name, must not be null or the empty string. Has the same namespace prefix usage as the <code>propName</code> parameter. </td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<a class="anchor" name="f22b116d71ecbbebea016ec5337e7066"></a><!-- doxytag: member="TXMPMeta::DoesPropertyExist" ref="f22b116d71ecbbebea016ec5337e7066" args="(XMP_StringPtr schemaNS, XMP_StringPtr propName) const " -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">bool <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt;::DoesPropertyExist </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>schemaNS</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>propName</em></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"> const</td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+<code>DoesPropertyExist</code> tells if the property exists.
+<p>
+<dl class="return" compact><dt><b>Returns:</b></dt><dd>Returns true if the property exists.</dd></dl>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>schemaNS</em>&nbsp;</td><td>The namespace URI for the property. Has the same usage as in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>propName</em>&nbsp;</td><td>The name of the property. Has the same usage as in <code>GetProperty</code>. </td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<a class="anchor" name="492465c588d6d4cb8e30f94790e66f58"></a><!-- doxytag: member="TXMPMeta::DoesArrayItemExist" ref="492465c588d6d4cb8e30f94790e66f58" args="(XMP_StringPtr schemaNS, XMP_StringPtr arrayName, XMP_Index itemIndex) const " -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">bool <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt;::DoesArrayItemExist </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>schemaNS</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>arrayName</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#00e9d9a76c144421105a4c2742203315">XMP_Index</a>&nbsp;</td>
+ <td class="paramname"> <em>itemIndex</em></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"> const</td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+<code>DoesArrayItemExist</code> tells if the array item exists.
+<p>
+<dl class="return" compact><dt><b>Returns:</b></dt><dd>Returns true if the array item exists.</dd></dl>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>schemaNS</em>&nbsp;</td><td>The namespace URI for the array. Has the same usage as in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>arrayName</em>&nbsp;</td><td>The name of the array. May be a general path expression, must not be null or the empty string. Has the same namespace prefix usage as <code>propName</code> in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>itemIndex</em>&nbsp;</td><td>The index of the desired item. Arrays in XMP are indexed from 1. The constant <code>kXMP_ArrayLastItem</code> always refers to the last existing array item. </td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<a class="anchor" name="9261b80d62e77a10ff1a89843bfa10a5"></a><!-- doxytag: member="TXMPMeta::DoesStructFieldExist" ref="9261b80d62e77a10ff1a89843bfa10a5" args="(XMP_StringPtr schemaNS, XMP_StringPtr structName, XMP_StringPtr fieldNS, XMP_StringPtr fieldName) const " -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">bool <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt;::DoesStructFieldExist </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>schemaNS</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>structName</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>fieldNS</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>fieldName</em></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"> const</td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+<code>DoesStructFieldExist</code> tells if the struct field exists.
+<p>
+<dl class="return" compact><dt><b>Returns:</b></dt><dd>Returns true if the field exists.</dd></dl>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>schemaNS</em>&nbsp;</td><td>The namespace URI for the struct. Has the same usage as in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>structName</em>&nbsp;</td><td>The name of the struct. May be a general path expression, must not be null or the empty string. Has the same namespace prefix usage as <code>propName</code> in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>fieldNS</em>&nbsp;</td><td>The namespace URI for the field. Has the same URI and prefix usage as the <code>schemaNS</code> parameter.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>fieldName</em>&nbsp;</td><td>The name of the field. Must be a single XML name, must not be null or the empty string. Has the same namespace prefix usage as the <code>structName</code> parameter. </td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<a class="anchor" name="81347a92becd387a14f4d47c582f129a"></a><!-- doxytag: member="TXMPMeta::DoesQualifierExist" ref="81347a92becd387a14f4d47c582f129a" args="(XMP_StringPtr schemaNS, XMP_StringPtr propName, XMP_StringPtr qualNS, XMP_StringPtr qualName) const " -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">bool <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt;::DoesQualifierExist </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>schemaNS</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>propName</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>qualNS</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>qualName</em></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"> const</td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+<code>DoesQualifierExist</code> tells if the qualifier exists.
+<p>
+<dl class="return" compact><dt><b>Returns:</b></dt><dd>Returns true if the qualifier exists.</dd></dl>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>schemaNS</em>&nbsp;</td><td>The namespace URI for the struct. Has the same usage as in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>propName</em>&nbsp;</td><td>The name of the property to which the qualifier is attached. Has the same usage as in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>qualNS</em>&nbsp;</td><td>The namespace URI for the qualifier. Has the same URI and prefix usage as the <code>schemaNS</code> parameter.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>qualName</em>&nbsp;</td><td>The name of the qualifier. Must be a single XML name, must not be null or the empty string. Has the same namespace prefix usage as the <code>propName</code> parameter. </td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<a class="anchor" name="eefe49bbf669770d769f4fe0ea566bd0"></a><!-- doxytag: member="TXMPMeta::GetLocalizedText" ref="eefe49bbf669770d769f4fe0ea566bd0" args="(XMP_StringPtr schemaNS, XMP_StringPtr altTextName, XMP_StringPtr genericLang, XMP_StringPtr specificLang, tStringObj *actualLang, tStringObj *itemValue, XMP_OptionBits *options) const " -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">bool <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt;::GetLocalizedText </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>schemaNS</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>altTextName</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>genericLang</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>specificLang</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">tStringObj *&nbsp;</td>
+ <td class="paramname"> <em>actualLang</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">tStringObj *&nbsp;</td>
+ <td class="paramname"> <em>itemValue</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> *&nbsp;</td>
+ <td class="paramname"> <em>options</em></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"> const</td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+<code>GetLocalizedText</code> returns information about a selected item in an alt-text array. The array item is selected according to the rules given above.
+<p>
+<dl class="return" compact><dt><b>Returns:</b></dt><dd>Returns true if an appropriate array item exists.</dd></dl>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>schemaNS</em>&nbsp;</td><td>The namespace URI for the alt-text array. Has the same usage as in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>altTextName</em>&nbsp;</td><td>The name of the alt-text array. May be a general path expression, must not be null or the empty string. Has the same namespace prefix usage as <code>propName</code> in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>genericLang</em>&nbsp;</td><td>The name of the generic language as an RFC 3066 primary subtag. May be null or the empty string if no generic language is wanted.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>specificLang</em>&nbsp;</td><td>The name of the specific language as an RFC 3066 tag. Must not be null or the empty string.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>actualLang</em>&nbsp;</td><td>A pointer to the string that is assigned the language of the selected array item, if an appropriate array item is found. May be null if the language is not wanted.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>itemValue</em>&nbsp;</td><td>A pointer to the string that is assigned the value of the array item, if an appropriate array item is found. May be null if the value is not wanted.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>options</em>&nbsp;</td><td>A pointer to the <code>XMP_OptionBits</code> variable that is assigned option flags describing the array item. May be null if the flags are not wanted. </td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<a class="anchor" name="f9531b949a462f5663b1f3fd99464c19"></a><!-- doxytag: member="TXMPMeta::SetLocalizedText" ref="f9531b949a462f5663b1f3fd99464c19" args="(XMP_StringPtr schemaNS, XMP_StringPtr altTextName, XMP_StringPtr genericLang, XMP_StringPtr specificLang, XMP_StringPtr itemValue, XMP_OptionBits options=0)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">void <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt;::SetLocalizedText </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>schemaNS</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>altTextName</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>genericLang</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>specificLang</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>itemValue</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a>&nbsp;</td>
+ <td class="paramname"> <em>options</em> = <code>0</code></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+<code>SetLocalizedText</code> modifies the value of a selected item in an alt-text array. Creates an appropriate array item if necessary, and handles special cases for the x-default item.
+<p>
+If the selected item is from a match with the specific language, the value of that item is modified. If the existing value of that item matches the existing value of the x-default item, the x-default item is also modified. If the array only has 1 existing item (which is not x-default), an x-default item is added with the given value.<p>
+If the selected item is from a match with the generic language and there are no other generic matches, the value of that item is modified. If the existing value of that item matches the existing value of the x-default item, the x-default item is also modified. If the array only has 1 existing item (which is not x-default), an x-default item is added with the given value.<p>
+If the selected item is from a partial match with the generic language and there are other partial matches, a new item is created for the specific language. The x-default item is not modified.<p>
+If the selected item is from the last 2 rules then a new item is created for the specific language. If the array only had an x-default item, the x-default item is also modified. If the array was empty, items are created for the specific language and x-default.<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>schemaNS</em>&nbsp;</td><td>The namespace URI for the alt-text array. Has the same usage as in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>altTextName</em>&nbsp;</td><td>The name of the alt-text array. May be a general path expression, must not be null or the empty string. Has the same namespace prefix usage as <code>propName</code> in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>genericLang</em>&nbsp;</td><td>The name of the generic language as an RFC 3066 primary subtag. May be null or the empty string if no generic language is wanted.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>specificLang</em>&nbsp;</td><td>The name of the specific language as an RFC 3066 tag. Must not be null or the empty string.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>itemValue</em>&nbsp;</td><td>A pointer to the null terminated UTF-8 string that is the new value for the appropriate array item.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>options</em>&nbsp;</td><td>Option flags, none are defined at present. </td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<a class="anchor" name="dcf8a1959a8bd42641a42cbd4d64a5b7"></a><!-- doxytag: member="TXMPMeta::GetProperty_Bool" ref="dcf8a1959a8bd42641a42cbd4d64a5b7" args="(XMP_StringPtr schemaNS, XMP_StringPtr propName, bool *propValue, XMP_OptionBits *options) const " -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">bool <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt;::GetProperty_Bool </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>schemaNS</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>propName</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">bool *&nbsp;</td>
+ <td class="paramname"> <em>propValue</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> *&nbsp;</td>
+ <td class="paramname"> <em>options</em></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"> const</td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+<code>GetProperty_Bool</code> returns the value of a Boolean property as a C++ bool.
+<p>
+<dl class="return" compact><dt><b>Returns:</b></dt><dd>Returns true if the property exists.</dd></dl>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>schemaNS</em>&nbsp;</td><td>The namespace URI for the property. Has the same usage as in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>propName</em>&nbsp;</td><td>The name of the property. Has the same usage as in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>propValue</em>&nbsp;</td><td>A pointer to the bool variable that is assigned the value of the property. May be null if the value is not wanted.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>options</em>&nbsp;</td><td>A pointer to the <code>XMP_OptionBits</code> variable that is assigned option flags describing the property. May be null if the flags are not wanted. </td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<a class="anchor" name="3b6ba486c02607b544917091c43b05cc"></a><!-- doxytag: member="TXMPMeta::GetProperty_Int" ref="3b6ba486c02607b544917091c43b05cc" args="(XMP_StringPtr schemaNS, XMP_StringPtr propName, long *propValue, XMP_OptionBits *options) const " -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">bool <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt;::GetProperty_Int </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>schemaNS</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>propName</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">long *&nbsp;</td>
+ <td class="paramname"> <em>propValue</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> *&nbsp;</td>
+ <td class="paramname"> <em>options</em></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"> const</td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+<code>GetProperty_Int</code> returns the value of an integer property as a C long integer.
+<p>
+<dl class="return" compact><dt><b>Returns:</b></dt><dd>Returns true if the property exists.</dd></dl>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>schemaNS</em>&nbsp;</td><td>The namespace URI for the property. Has the same usage as in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>propName</em>&nbsp;</td><td>The name of the property. Has the same usage as in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>propValue</em>&nbsp;</td><td>A pointer to the long integer variable that is assigned the value of the property. May be null if the value is not wanted.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>options</em>&nbsp;</td><td>A pointer to the <code>XMP_OptionBits</code> variable that is assigned option flags describing the property. May be null if the flags are not wanted. </td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<a class="anchor" name="d1a6629b0466981b67d31c9dc3840ea7"></a><!-- doxytag: member="TXMPMeta::GetProperty_Int64" ref="d1a6629b0466981b67d31c9dc3840ea7" args="(XMP_StringPtr schemaNS, XMP_StringPtr propName, long long *propValue, XMP_OptionBits *options) const" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">bool <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt;::GetProperty_Int64 </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>schemaNS</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>propName</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">long long *&nbsp;</td>
+ <td class="paramname"> <em>propValue</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> *&nbsp;</td>
+ <td class="paramname"> <em>options</em></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"> const</td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+<code>GetProperty_Int64</code> returns the value of an integer property as a C long long integer.
+<p>
+<dl class="return" compact><dt><b>Returns:</b></dt><dd>Returns true if the property exists.</dd></dl>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>schemaNS</em>&nbsp;</td><td>The namespace URI for the property. Has the same usage as in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>propName</em>&nbsp;</td><td>The name of the property. Has the same usage as in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>propValue</em>&nbsp;</td><td>A pointer to the long long integer variable that is assigned the value of the property. May be null if the value is not wanted.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>options</em>&nbsp;</td><td>A pointer to the <code>XMP_OptionBits</code> variable that is assigned option flags describing the property. May be null if the flags are not wanted. </td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<a class="anchor" name="7708c31c9af3e740b27a4893dcd9aa47"></a><!-- doxytag: member="TXMPMeta::GetProperty_Float" ref="7708c31c9af3e740b27a4893dcd9aa47" args="(XMP_StringPtr schemaNS, XMP_StringPtr propName, double *propValue, XMP_OptionBits *options) const " -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">bool <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt;::GetProperty_Float </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>schemaNS</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>propName</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">double *&nbsp;</td>
+ <td class="paramname"> <em>propValue</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> *&nbsp;</td>
+ <td class="paramname"> <em>options</em></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"> const</td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+<code>GetProperty_Float</code> returns the value of a flaoting point property as a C double float.
+<p>
+<dl class="return" compact><dt><b>Returns:</b></dt><dd>Returns true if the property exists.</dd></dl>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>schemaNS</em>&nbsp;</td><td>The namespace URI for the property. Has the same usage as in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>propName</em>&nbsp;</td><td>The name of the property. Has the same usage as in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>propValue</em>&nbsp;</td><td>A pointer to the double float variable that is assigned the value of the property. May be null if the value is not wanted.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>options</em>&nbsp;</td><td>A pointer to the <code>XMP_OptionBits</code> variable that is assigned option flags describing the property. May be null if the flags are not wanted. </td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<a class="anchor" name="2f561295e73047ee90765558d29bd650"></a><!-- doxytag: member="TXMPMeta::GetProperty_Date" ref="2f561295e73047ee90765558d29bd650" args="(XMP_StringPtr schemaNS, XMP_StringPtr propName, XMP_DateTime *propValue, XMP_OptionBits *options) const " -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">bool <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt;::GetProperty_Date </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>schemaNS</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>propName</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="structXMP__DateTime.html">XMP_DateTime</a> *&nbsp;</td>
+ <td class="paramname"> <em>propValue</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> *&nbsp;</td>
+ <td class="paramname"> <em>options</em></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"> const</td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+<code>GetProperty_Date</code> returns the value of a date/time property as an <code><a class="el" href="structXMP__DateTime.html">XMP_DateTime</a></code> struct.
+<p>
+<dl class="return" compact><dt><b>Returns:</b></dt><dd>Returns true if the property exists.</dd></dl>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>schemaNS</em>&nbsp;</td><td>The namespace URI for the property. Has the same usage as in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>propName</em>&nbsp;</td><td>The name of the property. Has the same usage as in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>propValue</em>&nbsp;</td><td>A pointer to the <code><a class="el" href="structXMP__DateTime.html">XMP_DateTime</a></code> variable that is assigned the value of the property. May be null if the value is not wanted.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>options</em>&nbsp;</td><td>A pointer to the <code>XMP_OptionBits</code> variable that is assigned option flags describing the property. May be null if the flags are not wanted. </td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<a class="anchor" name="9521e3838272ec501ffdb60ff3eb482f"></a><!-- doxytag: member="TXMPMeta::SetProperty_Bool" ref="9521e3838272ec501ffdb60ff3eb482f" args="(XMP_StringPtr schemaNS, XMP_StringPtr propName, bool propValue, XMP_OptionBits options=0)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">void <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt;::SetProperty_Bool </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>schemaNS</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>propName</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">bool&nbsp;</td>
+ <td class="paramname"> <em>propValue</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a>&nbsp;</td>
+ <td class="paramname"> <em>options</em> = <code>0</code></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+<code>SetProperty_Bool</code> sets the value of a Boolean property from a C++ bool.
+<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>schemaNS</em>&nbsp;</td><td>The namespace URI for the property. Has the same usage as in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>propName</em>&nbsp;</td><td>The name of the property. Has the same usage as in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>propValue</em>&nbsp;</td><td>The bool value to be assigned to the property.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>options</em>&nbsp;</td><td>A pointer to the <code>XMP_OptionBits</code> variable that is assigned option flags describing the property. May be null if the flags are not wanted. </td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<a class="anchor" name="b8ae94130d9a05c1b9a3ee25588b6421"></a><!-- doxytag: member="TXMPMeta::SetProperty_Int" ref="b8ae94130d9a05c1b9a3ee25588b6421" args="(XMP_StringPtr schemaNS, XMP_StringPtr propName, long propValue, XMP_OptionBits options=0)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">void <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt;::SetProperty_Int </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>schemaNS</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>propName</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">long&nbsp;</td>
+ <td class="paramname"> <em>propValue</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a>&nbsp;</td>
+ <td class="paramname"> <em>options</em> = <code>0</code></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+<code>SetProperty_Int</code> sets the value of an integer property from a C long integer.
+<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>schemaNS</em>&nbsp;</td><td>The namespace URI for the property. Has the same usage as in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>propName</em>&nbsp;</td><td>The name of the property. Has the same usage as in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>propValue</em>&nbsp;</td><td>The long integer value to be assigned to the property.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>options</em>&nbsp;</td><td>Option flags describing the property. </td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<a class="anchor" name="df919aff205e934e4c8250a067f7b377"></a><!-- doxytag: member="TXMPMeta::SetProperty_Int64" ref="df919aff205e934e4c8250a067f7b377" args="(XMP_StringPtr schemaNS, XMP_StringPtr propName, long long propValue, XMP_OptionBits options=0)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">void <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt;::SetProperty_Int64 </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>schemaNS</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>propName</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">long long&nbsp;</td>
+ <td class="paramname"> <em>propValue</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a>&nbsp;</td>
+ <td class="paramname"> <em>options</em> = <code>0</code></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+<code>SetProperty_Int64</code> sets the value of an integer property from a C long long integer.
+<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>schemaNS</em>&nbsp;</td><td>The namespace URI for the property. Has the same usage as in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>propName</em>&nbsp;</td><td>The name of the property. Has the same usage as in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>propValue</em>&nbsp;</td><td>The long long integer value to be assigned to the property.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>options</em>&nbsp;</td><td>Option flags describing the property. </td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<a class="anchor" name="3b0f2f6bae57931ea96775f03608c0ed"></a><!-- doxytag: member="TXMPMeta::SetProperty_Float" ref="3b0f2f6bae57931ea96775f03608c0ed" args="(XMP_StringPtr schemaNS, XMP_StringPtr propName, double propValue, XMP_OptionBits options=0)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">void <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt;::SetProperty_Float </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>schemaNS</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>propName</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">double&nbsp;</td>
+ <td class="paramname"> <em>propValue</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a>&nbsp;</td>
+ <td class="paramname"> <em>options</em> = <code>0</code></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+<code>SetProperty_Float</code> sets the value of a floating point property from a C double float.
+<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>schemaNS</em>&nbsp;</td><td>The namespace URI for the property. Has the same usage as in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>propName</em>&nbsp;</td><td>The name of the property. Has the same usage as in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>propValue</em>&nbsp;</td><td>The double float value to be assigned to the property.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>options</em>&nbsp;</td><td>Option flags describing the property. </td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<a class="anchor" name="eee10669445f77139d5634199ff01079"></a><!-- doxytag: member="TXMPMeta::SetProperty_Date" ref="eee10669445f77139d5634199ff01079" args="(XMP_StringPtr schemaNS, XMP_StringPtr propName, const XMP_DateTime &amp;propValue, XMP_OptionBits options=0)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">void <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt;::SetProperty_Date </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>schemaNS</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>propName</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">const <a class="el" href="structXMP__DateTime.html">XMP_DateTime</a> &amp;&nbsp;</td>
+ <td class="paramname"> <em>propValue</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a>&nbsp;</td>
+ <td class="paramname"> <em>options</em> = <code>0</code></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+<code>SetProperty_Date</code> sets the value of a date/time property from an <code><a class="el" href="structXMP__DateTime.html">XMP_DateTime</a></code> struct.
+<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>schemaNS</em>&nbsp;</td><td>The namespace URI for the property. Has the same usage as in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>propName</em>&nbsp;</td><td>The name of the property. Has the same usage as in <code>GetProperty</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>propValue</em>&nbsp;</td><td>The <code><a class="el" href="structXMP__DateTime.html">XMP_DateTime</a></code> value to be assigned to the property.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>options</em>&nbsp;</td><td>Option flags describing the property. </td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<a class="anchor" name="92055b3ae18dfd5e5491108f59318f17"></a><!-- doxytag: member="TXMPMeta::SetObjectOptions" ref="92055b3ae18dfd5e5491108f59318f17" args="(XMP_OptionBits options)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">void <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt;::SetObjectOptions </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a>&nbsp;</td>
+ <td class="paramname"> <em>options</em> </td>
+ <td>&nbsp;)&nbsp;</td>
+ <td width="100%"></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+SetObjectOptions --TBD--.
+<p>
+<dl class="note" compact><dt><b>Note:</b></dt><dd><b>Not yet implemented.</b> File a bug if you need this. </dd></dl>
+
+</div>
+</div><p>
+<a class="anchor" name="6ca653436995bbb76315efe7934afd4c"></a><!-- doxytag: member="TXMPMeta::Clone" ref="6ca653436995bbb76315efe7934afd4c" args="(XMP_OptionBits options=0) const " -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname"><a class="el" href="classTXMPMeta.html">TXMPMeta</a> <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt;::Clone </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a>&nbsp;</td>
+ <td class="paramname"> <em>options</em> = <code>0</code> </td>
+ <td>&nbsp;)&nbsp;</td>
+ <td width="100%"> const</td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+<code>Clone</code> creates a deep clone of the XMP object.
+<p>
+This function creates a deep clone of the XMP object. Assignment and copy constructors do not, they just increment a reference count. Note that <code>Clone</code> returns an object, not a pointer. This is easy to misuse:<p>
+<div class="fragment"><pre class="fragment"> SXMPMeta * clone1 = &amp;sourceXMP.Clone(); <span class="comment">// ! This does not work!</span>
+ SXMPMeta * clone2 = <span class="keyword">new</span> SXMPMeta ( sourceXMP.Clone() ); <span class="comment">// This works.</span>
+ SXMPMeta clone3 ( sourceXMP.Clone ); <span class="comment">// This works also. (Not a pointer.)</span>
+</pre></div><p>
+In the code above, the assignment to <code>clone1</code> creates a temporary object, initializes it with the clone, assigns the address of the temporary to <code>clone1</code>, then deletes the temporary. The <code>clone3</code> example also works, you do not have to use an explicit pointer. This is good for local usage, you don't have to worry about memory leaks.<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>options</em>&nbsp;</td><td>Option flags, not are defined at present.</td></tr>
+ </table>
+</dl>
+<dl class="return" compact><dt><b>Returns:</b></dt><dd>An XMP object cloned from the original. </dd></dl>
+
+</div>
+</div><p>
+<a class="anchor" name="7b383f5b357fff040cdbde82f4f43f26"></a><!-- doxytag: member="TXMPMeta::ParseFromBuffer" ref="7b383f5b357fff040cdbde82f4f43f26" args="(XMP_StringPtr buffer, XMP_StringLen bufferSize, XMP_OptionBits options=0)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">void <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt;::ParseFromBuffer </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>buffer</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#9f7dcc184f901c713274edfdac5bcc9a">XMP_StringLen</a>&nbsp;</td>
+ <td class="paramname"> <em>bufferSize</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a>&nbsp;</td>
+ <td class="paramname"> <em>options</em> = <code>0</code></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+<code>ParseFromBuffer</code> parses RDF from a series of input buffers. The buffers may be any length. The buffer boundaries need not respect XML tokens or even Unicode characters.
+<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>buffer</em>&nbsp;</td><td>A pointer to a buffer of input. May be null if <code>bufferSize</code> is 0.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>bufferSize</em>&nbsp;</td><td>The length of this buffer in bytes. Zero is a valid value. Termination of an input loop is convenient by passing <code>kXMP_ParseMoreBuffers</code> for all real input, then having a final call with a zero length and <code>kXMP_NoOptions</code>.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>options</em>&nbsp;</td><td>Options controlling the parsing.</td></tr>
+ </table>
+</dl>
+The available options are:<p>
+<ul>
+<li><code>kXMP_ParseMoreBuffers</code> - This is not the last buffer of input, more calls follow. </li>
+<li><code>kXMP_RequireXMPMeta</code> - The x:xmpmeta XML element is required around <code>rdf:RDF</code>. </li>
+<li><code>kXMP_StrictAliasing</code> - Do not reconcile alias differences, throw an exception.</li>
+</ul>
+<dl class="note" compact><dt><b>Note:</b></dt><dd>The <code>kXMP_StrictAliasing</code> option is not yet implemented. </dd></dl>
+
+</div>
+</div><p>
+<a class="anchor" name="2774a6f15ae22f0002201b58c46bfb49"></a><!-- doxytag: member="TXMPMeta::SerializeToBuffer" ref="2774a6f15ae22f0002201b58c46bfb49" args="(tStringObj *rdfString, XMP_OptionBits options, XMP_StringLen padding, XMP_StringPtr newline, XMP_StringPtr indent=&quot;&quot;, XMP_Index baseIndent=0) const " -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">void <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt;::SerializeToBuffer </td>
+ <td>(</td>
+ <td class="paramtype">tStringObj *&nbsp;</td>
+ <td class="paramname"> <em>rdfString</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a>&nbsp;</td>
+ <td class="paramname"> <em>options</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#9f7dcc184f901c713274edfdac5bcc9a">XMP_StringLen</a>&nbsp;</td>
+ <td class="paramname"> <em>padding</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>newline</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>indent</em> = <code>&quot;&quot;</code>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#00e9d9a76c144421105a4c2742203315">XMP_Index</a>&nbsp;</td>
+ <td class="paramname"> <em>baseIndent</em> = <code>0</code></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"> const</td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+<code>SerializeToBuffer</code> serializes an XMP object into a string as RDF.
+<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>rdfString</em>&nbsp;</td><td>A pointer to the string to receive the serialized RDF. Must not be null.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>options</em>&nbsp;</td><td>Option flags to control the serialization.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>padding</em>&nbsp;</td><td>The amount of padding to be added if a writeable XML packet is created. If zero is passed (the default) an appropriate amount of padding is computed.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>newline</em>&nbsp;</td><td>The string to be used as a line terminator. If empty it defaults to linefeed, U+000A, the standard XML newline.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>indent</em>&nbsp;</td><td>The string to be used for each level of indentation in the serialized RDF. If empty it defaults to two ASCII spaces, U+0020.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>baseIndent</em>&nbsp;</td><td>The number of levels of indentation to be used for the outermost XML element in the serialized RDF. This is convenient when embedding the RDF in other text.</td></tr>
+ </table>
+</dl>
+The available option flags are:<p>
+<ul>
+<li><code>kXMP_OmitPacketWrapper</code> - Do not include an XML packet wrapper. </li>
+<li><code>kXMP_ReadOnlyPacket</code> - Create a read-only XML packet wapper. </li>
+<li><code>kXMP_UseCompactFormat</code> - Use a highly compact RDF syntax and layout. </li>
+<li><code>kXMP_WriteAliasComments</code> - Include XML comments for aliases. </li>
+<li><code>kXMP_IncludeThumbnailPad</code> - Include typical space for a JPEG thumbnail in the padding if no <code>xmp:Thumbnails</code> property is present. </li>
+<li><code>kXMP_ExactPacketLength</code> - The padding parameter provides the overall packet length. The actual amount of padding is computed. An exception is thrown if the packet exceeds this length with no padding.</li>
+</ul>
+The specified options must be logically consistent, an exception is thrown if not. You cannot specify both <code>kXMP_OmitPacketWrapper</code> along with <code>kXMP_ReadOnlyPacket</code>, <code>kXMP_IncludeThumbnailPad</code>, or <code>kXMP_ExactPacketLength</code>.<p>
+In addition, one of the following encoding options may be included:<p>
+<ul>
+<li><code>kXMP_EncodeUTF8</code> - Encode as UTF-8, the default. </li>
+<li><code>kXMP_EncodeUTF16Big</code> - Encode as big-endian UTF-16. </li>
+<li><code>kXMP_EncodeUTF16Little</code> - Encode as little-endian UTF-16. </li>
+<li><code>kXMP_EncodeUTF32Big</code> - Encode as big-endian UTF-32. </li>
+<li><code>kXMP_EncodeUTF32Little</code> - Encode as little-endian UTF-32. </li>
+</ul>
+
+</div>
+</div><p>
+<hr>The documentation for this class was generated from the following file:<ul>
+<li><a class="el" href="TXMPMeta_8hpp-source.html">TXMPMeta.hpp</a></ul>
+<hr size="1"><address style="align: right;"><small>Generated on Thu May 3 14:54:59 2007 for Adobe XMP Toolkit by&nbsp;
+<a href="http://www.doxygen.org/index.html">
+<img src="doxygen.png" alt="doxygen" align="middle" border="0"></a> 1.5.1 </small></address>
+</body>
+</html>
diff --git a/docs/XMPToolkit/classTXMPUtils-members.html b/docs/XMPToolkit/classTXMPUtils-members.html
new file mode 100644
index 0000000..f905f69
--- /dev/null
+++ b/docs/XMPToolkit/classTXMPUtils-members.html
@@ -0,0 +1,63 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
+<title>Adobe XMP Toolkit: Member List</title>
+<link href="doxygen.css" rel="stylesheet" type="text/css">
+<link href="tabs.css" rel="stylesheet" type="text/css">
+</head><body>
+<!-- Generated by Doxygen 1.5.1 -->
+<div class="tabs">
+ <ul>
+ <li><a href="index.html"><span>Main&nbsp;Page</span></a></li>
+ <li><a href="modules.html"><span>Modules</span></a></li>
+ <li id="current"><a href="annotated.html"><span>Classes</span></a></li>
+ <li><a href="files.html"><span>Files</span></a></li>
+ </ul></div>
+<div class="tabs">
+ <ul>
+ <li><a href="annotated.html"><span>Class&nbsp;List</span></a></li>
+ <li><a href="functions.html"><span>Class&nbsp;Members</span></a></li>
+ </ul></div>
+<h1>TXMPUtils&lt; tStringObj &gt; Member List</h1>This is the complete list of members for <a class="el" href="classTXMPUtils.html">TXMPUtils&lt; tStringObj &gt;</a>, including all inherited members.<p><table>
+ <tr class="memlist"><td><a class="el" href="classTXMPUtils.html#4795244ffcbda927800f789b0e40c262">AppendProperties</a>(const TXMPMeta&lt; tStringObj &gt; &amp;source, TXMPMeta&lt; tStringObj &gt; *dest, XMP_OptionBits options=0)</td><td><a class="el" href="classTXMPUtils.html">TXMPUtils&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPUtils.html#d7e1aa7928252fb88a24fb5c3aef22ba">CatenateArrayItems</a>(const TXMPMeta&lt; tStringObj &gt; &amp;xmpObj, XMP_StringPtr schemaNS, XMP_StringPtr arrayName, XMP_StringPtr separator, XMP_StringPtr quotes, XMP_OptionBits options, tStringObj *catedStr)</td><td><a class="el" href="classTXMPUtils.html">TXMPUtils&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPUtils.html#9fc7f1771032f59f9020aeda4f91991d">CompareDateTime</a>(const XMP_DateTime &amp;left, const XMP_DateTime &amp;right)</td><td><a class="el" href="classTXMPUtils.html">TXMPUtils&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPUtils.html#47fa195aa2e1457aa1f74f7e1ed06da6">ComposeArrayItemPath</a>(XMP_StringPtr schemaNS, XMP_StringPtr arrayName, XMP_Index itemIndex, tStringObj *fullPath)</td><td><a class="el" href="classTXMPUtils.html">TXMPUtils&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPUtils.html#458f8e8729e2334fe54ca8f691a9db23">ComposeFieldSelector</a>(XMP_StringPtr schemaNS, XMP_StringPtr arrayName, XMP_StringPtr fieldNS, XMP_StringPtr fieldName, XMP_StringPtr fieldValue, tStringObj *fullPath)</td><td><a class="el" href="classTXMPUtils.html">TXMPUtils&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPUtils.html#d2d2361b8a4d0709ec9e3bd837265cba">ComposeFieldSelector</a>(XMP_StringPtr schemaNS, XMP_StringPtr arrayName, XMP_StringPtr fieldNS, XMP_StringPtr fieldName, const tStringObj &amp;fieldValue, tStringObj *fullPath)</td><td><a class="el" href="classTXMPUtils.html">TXMPUtils&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPUtils.html#e4989e5c199a2a4287ee3ae89b872e69">ComposeLangSelector</a>(XMP_StringPtr schemaNS, XMP_StringPtr arrayName, XMP_StringPtr langName, tStringObj *fullPath)</td><td><a class="el" href="classTXMPUtils.html">TXMPUtils&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPUtils.html#7882bbc2e412ff476c2d97d98808d91c">ComposeLangSelector</a>(XMP_StringPtr schemaNS, XMP_StringPtr arrayName, const tStringObj &amp;langName, tStringObj *fullPath)</td><td><a class="el" href="classTXMPUtils.html">TXMPUtils&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPUtils.html#40ae0ce2065fcb71725e37137884e172">ComposeQualifierPath</a>(XMP_StringPtr schemaNS, XMP_StringPtr propName, XMP_StringPtr qualNS, XMP_StringPtr qualName, tStringObj *fullPath)</td><td><a class="el" href="classTXMPUtils.html">TXMPUtils&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPUtils.html#706eb85b8401b8682a01348f7e25ee3d">ComposeStructFieldPath</a>(XMP_StringPtr schemaNS, XMP_StringPtr structName, XMP_StringPtr fieldNS, XMP_StringPtr fieldName, tStringObj *fullPath)</td><td><a class="el" href="classTXMPUtils.html">TXMPUtils&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPUtils.html#509691eb270988de6a770c9c8304ab6b">ConvertFromBool</a>(bool binValue, tStringObj *strValue)</td><td><a class="el" href="classTXMPUtils.html">TXMPUtils&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPUtils.html#6146a522a3974b4088d6e8241e9cd223">ConvertFromDate</a>(const XMP_DateTime &amp;binValue, tStringObj *strValue)</td><td><a class="el" href="classTXMPUtils.html">TXMPUtils&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPUtils.html#e67ef3931836432b7e574832f0610ed0">ConvertFromFloat</a>(double binValue, XMP_StringPtr format, tStringObj *strValue)</td><td><a class="el" href="classTXMPUtils.html">TXMPUtils&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPUtils.html#eec45b4d1a26717290105c9f4e8b4235">ConvertFromInt</a>(long binValue, XMP_StringPtr format, tStringObj *strValue)</td><td><a class="el" href="classTXMPUtils.html">TXMPUtils&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPUtils.html#aaaaadb23f4089daa795f50cba4f405c">ConvertToBool</a>(XMP_StringPtr strValue)</td><td><a class="el" href="classTXMPUtils.html">TXMPUtils&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPUtils.html#84f2a7b3960a17315032915674e21960">ConvertToBool</a>(const tStringObj &amp;strValue)</td><td><a class="el" href="classTXMPUtils.html">TXMPUtils&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPUtils.html#60d33e6ce30286028acca47b2b6e7a0b">ConvertToDate</a>(XMP_StringPtr strValue, XMP_DateTime *binValue)</td><td><a class="el" href="classTXMPUtils.html">TXMPUtils&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPUtils.html#265559d1b4b78e34a460e935c11177d7">ConvertToDate</a>(const tStringObj &amp;strValue, XMP_DateTime *binValue)</td><td><a class="el" href="classTXMPUtils.html">TXMPUtils&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPUtils.html#8a507b006286460814e0486c622d828c">ConvertToFloat</a>(XMP_StringPtr strValue)</td><td><a class="el" href="classTXMPUtils.html">TXMPUtils&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPUtils.html#abd4e479d2708a9ea3135cd441faa7ea">ConvertToFloat</a>(const tStringObj &amp;strValue)</td><td><a class="el" href="classTXMPUtils.html">TXMPUtils&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPUtils.html#dfd9d1c522377d5db4ad667a7973ba00">ConvertToInt</a>(XMP_StringPtr strValue)</td><td><a class="el" href="classTXMPUtils.html">TXMPUtils&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPUtils.html#47d93f9cb4acd9d7ec6b450100209bec">ConvertToInt</a>(const tStringObj &amp;strValue)</td><td><a class="el" href="classTXMPUtils.html">TXMPUtils&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPUtils.html#be5d2dcc03c5442202203bba5ca7b172">ConvertToInt64</a>(XMP_StringPtr strValue)</td><td><a class="el" href="classTXMPUtils.html">TXMPUtils&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPUtils.html#711cae0cb1b673ff5e208b4ae458d120">ConvertToInt64</a>(const tStringObj &amp;strValue)</td><td><a class="el" href="classTXMPUtils.html">TXMPUtils&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPUtils.html#61852aaba494c8fbad5a6c0c4caf21f5">ConvertToLocalTime</a>(XMP_DateTime *time)</td><td><a class="el" href="classTXMPUtils.html">TXMPUtils&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPUtils.html#bbd4d691c83287ea2fc6b1e33e5858b8">ConvertToUTCTime</a>(XMP_DateTime *time)</td><td><a class="el" href="classTXMPUtils.html">TXMPUtils&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPUtils.html#c83f0b963ea64d7eee0b481e15a8439c">CurrentDateTime</a>(XMP_DateTime *time)</td><td><a class="el" href="classTXMPUtils.html">TXMPUtils&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPUtils.html#e5bdd91c0c3ee9262dc0a8b9f591b921">DecodeFromBase64</a>(XMP_StringPtr encodedStr, XMP_StringLen encodedLen, tStringObj *rawStr)</td><td><a class="el" href="classTXMPUtils.html">TXMPUtils&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPUtils.html#1e61e273065b10517ca127d5a553a8dc">DecodeFromBase64</a>(const tStringObj &amp;encodedStr, tStringObj *rawStr)</td><td><a class="el" href="classTXMPUtils.html">TXMPUtils&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPUtils.html#a17838f062e5414bc0929f67ac94a3aa">DuplicateSubtree</a>(const TXMPMeta&lt; tStringObj &gt; &amp;source, TXMPMeta&lt; tStringObj &gt; *dest, XMP_StringPtr sourceNS, XMP_StringPtr sourceRoot, XMP_StringPtr destNS=0, XMP_StringPtr destRoot=0, XMP_OptionBits options=0)</td><td><a class="el" href="classTXMPUtils.html">TXMPUtils&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPUtils.html#ef3b23bbc152480f699e269620ecad4a">EncodeToBase64</a>(XMP_StringPtr rawStr, XMP_StringLen rawLen, tStringObj *encodedStr)</td><td><a class="el" href="classTXMPUtils.html">TXMPUtils&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPUtils.html#39d5de77b29441a30f2f879755b8e7d8">EncodeToBase64</a>(const tStringObj &amp;rawStr, tStringObj *encodedStr)</td><td><a class="el" href="classTXMPUtils.html">TXMPUtils&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPUtils.html#6187cd5fef0eccecac6805d4114dcd2e">MergeFromJPEG</a>(TXMPMeta&lt; tStringObj &gt; *fullXMP, const TXMPMeta&lt; tStringObj &gt; &amp;extendedXMP)</td><td><a class="el" href="classTXMPUtils.html">TXMPUtils&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPUtils.html#6001b4ff54c60fdf0c40e6b78a5c457a">PackageForJPEG</a>(const TXMPMeta&lt; tStringObj &gt; &amp;xmpObj, tStringObj *standardXMP, tStringObj *extendedXMP, tStringObj *extendedDigest)</td><td><a class="el" href="classTXMPUtils.html">TXMPUtils&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPUtils.html#40c645803530662e08d042b4b7c6190d">RemoveProperties</a>(TXMPMeta&lt; tStringObj &gt; *xmpObj, XMP_StringPtr schemaNS=0, XMP_StringPtr propName=0, XMP_OptionBits options=0)</td><td><a class="el" href="classTXMPUtils.html">TXMPUtils&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPUtils.html#66c5ddee47aa36ed906353f94ca18d2e">SeparateArrayItems</a>(TXMPMeta&lt; tStringObj &gt; *xmpObj, XMP_StringPtr schemaNS, XMP_StringPtr arrayName, XMP_OptionBits options, XMP_StringPtr catedStr)</td><td><a class="el" href="classTXMPUtils.html">TXMPUtils&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPUtils.html#1bb2ed614886ff67863744ec56041c43">SeparateArrayItems</a>(TXMPMeta&lt; tStringObj &gt; *xmpObj, XMP_StringPtr schemaNS, XMP_StringPtr arrayName, XMP_OptionBits options, const tStringObj &amp;catedStr)</td><td><a class="el" href="classTXMPUtils.html">TXMPUtils&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+ <tr class="memlist"><td><a class="el" href="classTXMPUtils.html#96bcc45febac55f6c49951815b7de2ef">SetTimeZone</a>(XMP_DateTime *time)</td><td><a class="el" href="classTXMPUtils.html">TXMPUtils&lt; tStringObj &gt;</a></td><td><code> [static]</code></td></tr>
+</table><hr size="1"><address style="align: right;"><small>Generated on Thu May 3 14:54:59 2007 for Adobe XMP Toolkit by&nbsp;
+<a href="http://www.doxygen.org/index.html">
+<img src="doxygen.png" alt="doxygen" align="middle" border="0"></a> 1.5.1 </small></address>
+</body>
+</html>
diff --git a/docs/XMPToolkit/classTXMPUtils.html b/docs/XMPToolkit/classTXMPUtils.html
new file mode 100644
index 0000000..2d2eb21
--- /dev/null
+++ b/docs/XMPToolkit/classTXMPUtils.html
@@ -0,0 +1,1540 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
+<title>Adobe XMP Toolkit: TXMPUtils&lt; tStringObj &gt; Class Template Reference</title>
+<link href="doxygen.css" rel="stylesheet" type="text/css">
+<link href="tabs.css" rel="stylesheet" type="text/css">
+</head><body>
+<!-- Generated by Doxygen 1.5.1 -->
+<div class="tabs">
+ <ul>
+ <li><a href="index.html"><span>Main&nbsp;Page</span></a></li>
+ <li><a href="modules.html"><span>Modules</span></a></li>
+ <li id="current"><a href="annotated.html"><span>Classes</span></a></li>
+ <li><a href="files.html"><span>Files</span></a></li>
+ </ul></div>
+<div class="tabs">
+ <ul>
+ <li><a href="annotated.html"><span>Class&nbsp;List</span></a></li>
+ <li><a href="functions.html"><span>Class&nbsp;Members</span></a></li>
+ </ul></div>
+<h1>TXMPUtils&lt; tStringObj &gt; Class Template Reference</h1><!-- doxytag: class="TXMPUtils" -->Template class for the XMP Toolkit utility services.
+<a href="#_details">More...</a>
+<p>
+<code>#include &lt;<a class="el" href="TXMPUtils_8hpp-source.html">TXMPUtils.hpp</a>&gt;</code>
+<p>
+<a href="classTXMPUtils-members.html">List of all members.</a><table border="0" cellpadding="0" cellspacing="0">
+<tr><td></td></tr>
+<tr><td colspan="2"><br><h2>Static Public Member Functions</h2></td></tr>
+<tr><td colspan="2"><div class="groupHeader">Path composition functions</div></td></tr>
+<tr><td colspan="2"><div class="groupText">These functions provide support for composing path expressions to deeply nested properties. The functions in <code><a class="el" href="classTXMPMeta.html">TXMPMeta</a></code> such as <code>GetProperty</code>, <code>GetArrayItem</code>, and <code>GetStructField</code> provide easy access to top level simple properties, items in top level arrays, and fields of top level structs. They do not provide convenient access to more complex things like fields several levels deep in a complex struct, or fields within an array of structs, or items of an array that is a field of a struct. These functions can also be used to compose paths to top level array items or struct fields so that you can use the binary accessors like <code>GetProperty_Int</code>.<p>
+You can use these functions is to compose a complete path expression, or all but the last component. Suppose you have a property that is an array of integers within a struct. You can access one of the array items like this:<p>
+<div class="fragment"><pre class="fragment">
+ /// SXMPUtils::ComposeStructFieldPath ( schemaNS, "Struct", fieldNS, "Array", &amp;path );
+ /// SXMPUtils::ComposeArrayItemPath ( schemaNS, path, index, &amp;path );
+ /// exists = xmpObj.GetProperty_Int ( schemaNS, path, &amp;value, &amp;options );
+ /// </pre></div><p>
+You could also use this code if you want the string form of the integer:<p>
+<div class="fragment"><pre class="fragment">
+ /// SXMPUtils::ComposeStructFieldPath ( schemaNS, "Struct", fieldNS, "Array", &amp;path );
+ /// xmpObj.GetArrayItem ( schemaNS, path, index, &amp;value, &amp;options );
+ /// </pre></div><p>
+<dl class="note" compact><dt><b>Note:</b></dt><dd>It might look confusing that the <code>schemaNS</code> is passed in all of the calls above. This is because the XMP toolkit keeps the top level "schema" namespace separate from the rest of the path expression. </dd></dl>
+<br><br></div></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">static void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPUtils.html#47fa195aa2e1457aa1f74f7e1ed06da6">ComposeArrayItemPath</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> arrayName, <a class="el" href="XMP__Const_8h.html#00e9d9a76c144421105a4c2742203315">XMP_Index</a> itemIndex, tStringObj *fullPath)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Compose the path expression for an item in an array. <a href="#47fa195aa2e1457aa1f74f7e1ed06da6"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">static void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPUtils.html#706eb85b8401b8682a01348f7e25ee3d">ComposeStructFieldPath</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> structName, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> fieldNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> fieldName, tStringObj *fullPath)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Compose the path expression for a field in a struct. <a href="#706eb85b8401b8682a01348f7e25ee3d"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">static void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPUtils.html#40ae0ce2065fcb71725e37137884e172">ComposeQualifierPath</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> propName, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> qualNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> qualName, tStringObj *fullPath)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Compose the path expression for a qualifier. <a href="#40ae0ce2065fcb71725e37137884e172"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">static void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPUtils.html#e4989e5c199a2a4287ee3ae89b872e69">ComposeLangSelector</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> arrayName, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> langName, tStringObj *fullPath)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Compose the path expression to select an alternate item by language. <a href="#e4989e5c199a2a4287ee3ae89b872e69"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="7882bbc2e412ff476c2d97d98808d91c"></a><!-- doxytag: member="TXMPUtils::ComposeLangSelector" ref="7882bbc2e412ff476c2d97d98808d91c" args="(XMP_StringPtr schemaNS, XMP_StringPtr arrayName, const tStringObj &amp;langName, tStringObj *fullPath)" -->
+static void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPUtils.html#7882bbc2e412ff476c2d97d98808d91c">ComposeLangSelector</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> arrayName, const tStringObj &amp;langName, tStringObj *fullPath)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">This form of <code>ComposeLangSelector</code> is a simple overload in the template that calls the above form passing <code>langName.c_str()</code>. <br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">static void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPUtils.html#458f8e8729e2334fe54ca8f691a9db23">ComposeFieldSelector</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> arrayName, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> fieldNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> fieldName, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> fieldValue, tStringObj *fullPath)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Compose the path expression to select an alternate item by a field's value. <a href="#458f8e8729e2334fe54ca8f691a9db23"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="d2d2361b8a4d0709ec9e3bd837265cba"></a><!-- doxytag: member="TXMPUtils::ComposeFieldSelector" ref="d2d2361b8a4d0709ec9e3bd837265cba" args="(XMP_StringPtr schemaNS, XMP_StringPtr arrayName, XMP_StringPtr fieldNS, XMP_StringPtr fieldName, const tStringObj &amp;fieldValue, tStringObj *fullPath)" -->
+static void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPUtils.html#d2d2361b8a4d0709ec9e3bd837265cba">ComposeFieldSelector</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> arrayName, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> fieldNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> fieldName, const tStringObj &amp;fieldValue, tStringObj *fullPath)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">This form of ComposeFieldSelector is a simple overload in the template that calls the above form passing <code>fieldValue.c_str()</code>. <br></td></tr>
+<tr><td colspan="2"><div class="groupHeader">Binary-String conversion functions</div></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">static void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPUtils.html#509691eb270988de6a770c9c8304ab6b">ConvertFromBool</a> (bool binValue, tStringObj *strValue)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Convert from Boolean to string. <a href="#509691eb270988de6a770c9c8304ab6b"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">static void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPUtils.html#eec45b4d1a26717290105c9f4e8b4235">ConvertFromInt</a> (long binValue, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> format, tStringObj *strValue)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Convert from integer to string. <a href="#eec45b4d1a26717290105c9f4e8b4235"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">static void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPUtils.html#e67ef3931836432b7e574832f0610ed0">ConvertFromFloat</a> (double binValue, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> format, tStringObj *strValue)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Convert from floating point to string. <a href="#e67ef3931836432b7e574832f0610ed0"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">static void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPUtils.html#6146a522a3974b4088d6e8241e9cd223">ConvertFromDate</a> (const <a class="el" href="structXMP__DateTime.html">XMP_DateTime</a> &amp;binValue, tStringObj *strValue)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Convert from date/time to string. <a href="#6146a522a3974b4088d6e8241e9cd223"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">static bool&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPUtils.html#aaaaadb23f4089daa795f50cba4f405c">ConvertToBool</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> strValue)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Convert from string to Boolean. <a href="#aaaaadb23f4089daa795f50cba4f405c"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="84f2a7b3960a17315032915674e21960"></a><!-- doxytag: member="TXMPUtils::ConvertToBool" ref="84f2a7b3960a17315032915674e21960" args="(const tStringObj &amp;strValue)" -->
+static bool&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPUtils.html#84f2a7b3960a17315032915674e21960">ConvertToBool</a> (const tStringObj &amp;strValue)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">This form of <code>ConvertToBool</code> is a simple overload in the template that calls the above form passing <code>strValue.c_str()</code>. <br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">static long&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPUtils.html#dfd9d1c522377d5db4ad667a7973ba00">ConvertToInt</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> strValue)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Convert from string to integer. <a href="#dfd9d1c522377d5db4ad667a7973ba00"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="47d93f9cb4acd9d7ec6b450100209bec"></a><!-- doxytag: member="TXMPUtils::ConvertToInt" ref="47d93f9cb4acd9d7ec6b450100209bec" args="(const tStringObj &amp;strValue)" -->
+static long&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPUtils.html#47d93f9cb4acd9d7ec6b450100209bec">ConvertToInt</a> (const tStringObj &amp;strValue)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">This form of <code>ConvertToInt</code> is a simple overload in the template that calls the above form passing <code>strValue.c_str()</code>. <br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">static long long&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPUtils.html#be5d2dcc03c5442202203bba5ca7b172">ConvertToInt64</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> strValue)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Convert from string to 64 bit integer. <a href="#be5d2dcc03c5442202203bba5ca7b172"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="711cae0cb1b673ff5e208b4ae458d120"></a><!-- doxytag: member="TXMPUtils::ConvertToInt64" ref="711cae0cb1b673ff5e208b4ae458d120" args="(const tStringObj &amp;strValue)" -->
+static long long&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPUtils.html#711cae0cb1b673ff5e208b4ae458d120">ConvertToInt64</a> (const tStringObj &amp;strValue)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">This form of ConvertToInt64 is a simple overload in the template that calls the above form passing <code>strValue.c_str()</code>. <br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">static double&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPUtils.html#8a507b006286460814e0486c622d828c">ConvertToFloat</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> strValue)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Convert from string to floating point. <a href="#8a507b006286460814e0486c622d828c"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="abd4e479d2708a9ea3135cd441faa7ea"></a><!-- doxytag: member="TXMPUtils::ConvertToFloat" ref="abd4e479d2708a9ea3135cd441faa7ea" args="(const tStringObj &amp;strValue)" -->
+static double&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPUtils.html#abd4e479d2708a9ea3135cd441faa7ea">ConvertToFloat</a> (const tStringObj &amp;strValue)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">This form of <code>ConvertToFloat</code> is a simple overload in the template that calls the above form passing <code>strValue.c_str()</code>. <br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">static void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPUtils.html#60d33e6ce30286028acca47b2b6e7a0b">ConvertToDate</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> strValue, <a class="el" href="structXMP__DateTime.html">XMP_DateTime</a> *binValue)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Convert from string to date/time. <a href="#60d33e6ce30286028acca47b2b6e7a0b"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="265559d1b4b78e34a460e935c11177d7"></a><!-- doxytag: member="TXMPUtils::ConvertToDate" ref="265559d1b4b78e34a460e935c11177d7" args="(const tStringObj &amp;strValue, XMP_DateTime *binValue)" -->
+static void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPUtils.html#265559d1b4b78e34a460e935c11177d7">ConvertToDate</a> (const tStringObj &amp;strValue, <a class="el" href="structXMP__DateTime.html">XMP_DateTime</a> *binValue)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">This form of <code>ConvertToDate</code> is a simple overload in the template that calls the above form passing s<code>strValue.c_str()</code>. <br></td></tr>
+<tr><td colspan="2"><div class="groupHeader">Date/Time functions</div></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">static void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPUtils.html#c83f0b963ea64d7eee0b481e15a8439c">CurrentDateTime</a> (<a class="el" href="structXMP__DateTime.html">XMP_DateTime</a> *time)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Obtain the current date and time. <a href="#c83f0b963ea64d7eee0b481e15a8439c"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">static void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPUtils.html#96bcc45febac55f6c49951815b7de2ef">SetTimeZone</a> (<a class="el" href="structXMP__DateTime.html">XMP_DateTime</a> *time)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Set the local time zone. <a href="#96bcc45febac55f6c49951815b7de2ef"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">static void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPUtils.html#bbd4d691c83287ea2fc6b1e33e5858b8">ConvertToUTCTime</a> (<a class="el" href="structXMP__DateTime.html">XMP_DateTime</a> *time)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Make sure a time is UTC. <a href="#bbd4d691c83287ea2fc6b1e33e5858b8"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">static void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPUtils.html#61852aaba494c8fbad5a6c0c4caf21f5">ConvertToLocalTime</a> (<a class="el" href="structXMP__DateTime.html">XMP_DateTime</a> *time)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Make sure a time is local. <a href="#61852aaba494c8fbad5a6c0c4caf21f5"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">static int&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPUtils.html#9fc7f1771032f59f9020aeda4f91991d">CompareDateTime</a> (const <a class="el" href="structXMP__DateTime.html">XMP_DateTime</a> &amp;left, const <a class="el" href="structXMP__DateTime.html">XMP_DateTime</a> &amp;right)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Compare the order of two date/time values. <a href="#9fc7f1771032f59f9020aeda4f91991d"></a><br></td></tr>
+<tr><td colspan="2"><div class="groupHeader">Base 64 Encoding and Decoding</div></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">static void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPUtils.html#ef3b23bbc152480f699e269620ecad4a">EncodeToBase64</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> rawStr, <a class="el" href="XMP__Const_8h.html#9f7dcc184f901c713274edfdac5bcc9a">XMP_StringLen</a> rawLen, tStringObj *encodedStr)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Convert from raw data to Base64 encoded string. <a href="#ef3b23bbc152480f699e269620ecad4a"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="39d5de77b29441a30f2f879755b8e7d8"></a><!-- doxytag: member="TXMPUtils::EncodeToBase64" ref="39d5de77b29441a30f2f879755b8e7d8" args="(const tStringObj &amp;rawStr, tStringObj *encodedStr)" -->
+static void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPUtils.html#39d5de77b29441a30f2f879755b8e7d8">EncodeToBase64</a> (const tStringObj &amp;rawStr, tStringObj *encodedStr)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">This form of <code>EncodeToBase64</code> is a simple overload in the template that calls the above form passing <code>rawStr.c_str()</code>, and <code>rawStr.size()</code>. <br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">static void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPUtils.html#e5bdd91c0c3ee9262dc0a8b9f591b921">DecodeFromBase64</a> (<a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> encodedStr, <a class="el" href="XMP__Const_8h.html#9f7dcc184f901c713274edfdac5bcc9a">XMP_StringLen</a> encodedLen, tStringObj *rawStr)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Decode from Base64 encoded string to raw data. <a href="#e5bdd91c0c3ee9262dc0a8b9f591b921"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="1e61e273065b10517ca127d5a553a8dc"></a><!-- doxytag: member="TXMPUtils::DecodeFromBase64" ref="1e61e273065b10517ca127d5a553a8dc" args="(const tStringObj &amp;encodedStr, tStringObj *rawStr)" -->
+static void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPUtils.html#1e61e273065b10517ca127d5a553a8dc">DecodeFromBase64</a> (const tStringObj &amp;encodedStr, tStringObj *rawStr)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">This form of <code>DecodeFromBase64</code> is a simple overload in the template that calls the above form passing <code>encodedStr.c_str()</code>, and <code>encodedStr.size()</code>. <br></td></tr>
+<tr><td colspan="2"><div class="groupHeader">JPEG file handling</div></td></tr>
+<tr><td colspan="2"><div class="groupText">These functions support the partitioning of XMP in JPEG files into standard and extended portions in order to work around the 64KB size limit of JPEG marker segments. <br><br></div></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">static void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPUtils.html#6001b4ff54c60fdf0c40e6b78a5c457a">PackageForJPEG</a> (const <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt; &amp;xmpObj, tStringObj *standardXMP, tStringObj *extendedXMP, tStringObj *extendedDigest)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Create XMP serializations appropriate for a JPEG file. The standard XMP in a JPEG file is limited to about 65500 bytes. <code>PackageForJPEG</code> attempts to fit the serialization within that limit. If necessary it will partition the XMP into 2 serializations. <a href="#6001b4ff54c60fdf0c40e6b78a5c457a"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">static void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPUtils.html#6187cd5fef0eccecac6805d4114dcd2e">MergeFromJPEG</a> (<a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt; *fullXMP, const <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt; &amp;extendedXMP)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Put the extended XMP properties back into the full XMP. <a href="#6187cd5fef0eccecac6805d4114dcd2e"></a><br></td></tr>
+<tr><td colspan="2"><div class="groupHeader">UI helper functions</div></td></tr>
+<tr><td colspan="2"><div class="groupText">These functions are mainly of interest in implementing a user interface for editing XMP. <br><br></div></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">static void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPUtils.html#d7e1aa7928252fb88a24fb5c3aef22ba">CatenateArrayItems</a> (const <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt; &amp;xmpObj, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> arrayName, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> separator, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> quotes, <a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options, tStringObj *catedStr)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Create a single edit string from an array of strings. <a href="#d7e1aa7928252fb88a24fb5c3aef22ba"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">static void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPUtils.html#66c5ddee47aa36ed906353f94ca18d2e">SeparateArrayItems</a> (<a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt; *xmpObj, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> arrayName, <a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> catedStr)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Separate a single edit string into an array of strings. <a href="#66c5ddee47aa36ed906353f94ca18d2e"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top"><a class="anchor" name="1bb2ed614886ff67863744ec56041c43"></a><!-- doxytag: member="TXMPUtils::SeparateArrayItems" ref="1bb2ed614886ff67863744ec56041c43" args="(TXMPMeta&lt; tStringObj &gt; *xmpObj, XMP_StringPtr schemaNS, XMP_StringPtr arrayName, XMP_OptionBits options, const tStringObj &amp;catedStr)" -->
+static void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPUtils.html#1bb2ed614886ff67863744ec56041c43">SeparateArrayItems</a> (<a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt; *xmpObj, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> arrayName, <a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options, const tStringObj &amp;catedStr)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">This form of <code>SeparateArrayItems</code> is a simple overload in the template that calls the aboveform passing <code>catedStr.c_str()</code>. <br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">static void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPUtils.html#40c645803530662e08d042b4b7c6190d">RemoveProperties</a> (<a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt; *xmpObj, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS=0, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> propName=0, <a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options=0)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Remove multiple properties from an XMP object. <a href="#40c645803530662e08d042b4b7c6190d"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">static void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPUtils.html#4795244ffcbda927800f789b0e40c262">AppendProperties</a> (const <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt; &amp;source, <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt; *dest, <a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options=0)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Append properties from one XMP object to another. <a href="#4795244ffcbda927800f789b0e40c262"></a><br></td></tr>
+<tr><td class="memItemLeft" nowrap align="right" valign="top">static void&nbsp;</td><td class="memItemRight" valign="bottom"><a class="el" href="classTXMPUtils.html#a17838f062e5414bc0929f67ac94a3aa">DuplicateSubtree</a> (const <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt; &amp;source, <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt; *dest, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> sourceNS, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> sourceRoot, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> destNS=0, <a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> destRoot=0, <a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options=0)</td></tr>
+
+<tr><td class="mdescLeft">&nbsp;</td><td class="mdescRight">Replicate a subtree from one XMP object into another, possibly at a different location. <a href="#a17838f062e5414bc0929f67ac94a3aa"></a><br></td></tr>
+</table>
+<hr><a name="_details"></a><h2>Detailed Description</h2>
+<h3>template&lt;class tStringObj&gt;<br>
+ class TXMPUtils&lt; tStringObj &gt;</h3>
+
+Template class for the XMP Toolkit utility services.
+<p>
+<code><a class="el" href="classTXMPUtils.html">TXMPUtils</a></code> is the template class providing utility services for the XMP Toolkit. It should be instantiated with a string class such as <code>std::string</code>. Please read the general toolkit usage notes for information about the overall architecture of the XMP API.<p>
+This is a class for C++ scoping purposes only. It has only static functions, you cannot create an object. These are all functions that layer cleanly on top of the core XMP toolkit. The template wraps a string class around the raw XMP API, so that output strings are automatically copied and access is fully thread safe. String objects are only necessary for output strings. Input strings are literals and passed as typical C <code>const char *</code>.<p>
+The template parameter, class <code>TtStringObj</code>, is described in the XMP.hpp umbrella header.
+<p>
+<hr><h2>Member Function Documentation</h2>
+<a class="anchor" name="47fa195aa2e1457aa1f74f7e1ed06da6"></a><!-- doxytag: member="TXMPUtils::ComposeArrayItemPath" ref="47fa195aa2e1457aa1f74f7e1ed06da6" args="(XMP_StringPtr schemaNS, XMP_StringPtr arrayName, XMP_Index itemIndex, tStringObj *fullPath)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">static void <a class="el" href="classTXMPUtils.html">TXMPUtils</a>&lt; tStringObj &gt;::ComposeArrayItemPath </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>schemaNS</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>arrayName</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#00e9d9a76c144421105a4c2742203315">XMP_Index</a>&nbsp;</td>
+ <td class="paramname"> <em>itemIndex</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">tStringObj *&nbsp;</td>
+ <td class="paramname"> <em>fullPath</em></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"><code> [static]</code></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Compose the path expression for an item in an array.
+<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>schemaNS</em>&nbsp;</td><td>The namespace URI for the array. Must not be null or the empty string.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>arrayName</em>&nbsp;</td><td>The name of the array. May be a general path expression, must not be null or the empty string.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>itemIndex</em>&nbsp;</td><td>The index of the desired item. Arrays in XMP are indexed from 1. The constant <code>kXMP_ArrayLastItem</code> always refers to the last existing array item.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>fullPath</em>&nbsp;</td><td>A pointer to the string that will be assigned the composed path. This will be of the form <code>ns:arrayName[i]</code>, where "ns" is the prefix for <code>schemaNS</code> and "i" is the decimal representation of <code>itemIndex</code>. If the value of <code>itemIndex</code> is <code>kXMP_ArrayLastItem</code>, the path is <code>ns:arrayName[last()]</code>. </td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<a class="anchor" name="706eb85b8401b8682a01348f7e25ee3d"></a><!-- doxytag: member="TXMPUtils::ComposeStructFieldPath" ref="706eb85b8401b8682a01348f7e25ee3d" args="(XMP_StringPtr schemaNS, XMP_StringPtr structName, XMP_StringPtr fieldNS, XMP_StringPtr fieldName, tStringObj *fullPath)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">static void <a class="el" href="classTXMPUtils.html">TXMPUtils</a>&lt; tStringObj &gt;::ComposeStructFieldPath </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>schemaNS</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>structName</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>fieldNS</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>fieldName</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">tStringObj *&nbsp;</td>
+ <td class="paramname"> <em>fullPath</em></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"><code> [static]</code></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Compose the path expression for a field in a struct.
+<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>schemaNS</em>&nbsp;</td><td>The namespace URI for the struct. Must not be null or the empty string.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>structName</em>&nbsp;</td><td>The name of the struct. May be a general path expression, must not be null or the empty string.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>fieldNS</em>&nbsp;</td><td>The namespace URI for the field. Must not be null or the empty string.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>fieldName</em>&nbsp;</td><td>The name of the field. Must be a simple XML name, must not be null or the empty string.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>fullPath</em>&nbsp;</td><td>A pointer to the string that will be assigned the composed path. This will be of the form <code>ns:structName/fNS:fieldName</code>, where "ns" is the prefix for <code>schemaNS</code> and "fNS" is the prefix for <code>fieldNS</code>. </td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<a class="anchor" name="40ae0ce2065fcb71725e37137884e172"></a><!-- doxytag: member="TXMPUtils::ComposeQualifierPath" ref="40ae0ce2065fcb71725e37137884e172" args="(XMP_StringPtr schemaNS, XMP_StringPtr propName, XMP_StringPtr qualNS, XMP_StringPtr qualName, tStringObj *fullPath)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">static void <a class="el" href="classTXMPUtils.html">TXMPUtils</a>&lt; tStringObj &gt;::ComposeQualifierPath </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>schemaNS</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>propName</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>qualNS</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>qualName</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">tStringObj *&nbsp;</td>
+ <td class="paramname"> <em>fullPath</em></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"><code> [static]</code></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Compose the path expression for a qualifier.
+<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>schemaNS</em>&nbsp;</td><td>The namespace URI for the property to which the qualifier is attached. Must not be null or the empty string.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>propName</em>&nbsp;</td><td>The name of the property to which the qualifier is attached. May be a general path expression, must not be null or the empty string.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>qualNS</em>&nbsp;</td><td>The namespace URI for the qualifier. May be null or the empty string if the qualifier is in the XML empty namespace.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>qualName</em>&nbsp;</td><td>The name of the qualifier. Must be a simple XML name, must not be null or the empty string.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>fullPath</em>&nbsp;</td><td>A pointer to the string that will be assigned the composed path. This will be of the form <code>ns:propName/?qNS:qualName</code>, where "ns" is the prefix for <code>schemaNS</code> and "qNS" is the prefix for <code>qualNS</code>. </td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<a class="anchor" name="e4989e5c199a2a4287ee3ae89b872e69"></a><!-- doxytag: member="TXMPUtils::ComposeLangSelector" ref="e4989e5c199a2a4287ee3ae89b872e69" args="(XMP_StringPtr schemaNS, XMP_StringPtr arrayName, XMP_StringPtr langName, tStringObj *fullPath)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">static void <a class="el" href="classTXMPUtils.html">TXMPUtils</a>&lt; tStringObj &gt;::ComposeLangSelector </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>schemaNS</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>arrayName</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>langName</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">tStringObj *&nbsp;</td>
+ <td class="paramname"> <em>fullPath</em></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"><code> [static]</code></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Compose the path expression to select an alternate item by language.
+<p>
+The path syntax allows two forms of "content addressing" that may be used to select an item in an array of alternatives. The form used in <code>ComposeLangSelector</code> lets you select an item in an alt-text array based on the value of its <code>xml:lang</code> qualifier. The other form of content addressing is shown in <code>ComposeFieldSelector</code>.<p>
+<dl class="note" compact><dt><b>Note:</b></dt><dd><code>ComposeLangSelector</code> does not supplant <code>SetLocalizedText</code> or <code>GetLocalizedText</code>. They should generally be used, as they provide extra logic to choose the appropriate language and maintain consistency with the 'x-default' value. <code>ComposeLangSelector</code> gives you an path expression that is explicitly and only for the language given in the <code>langName</code> parameter.</dd></dl>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>schemaNS</em>&nbsp;</td><td>The namespace URI for the array. Must not be null or the empty string.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>arrayName</em>&nbsp;</td><td>The name of the array. May be a general path expression, must not be null or the empty string.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>langName</em>&nbsp;</td><td>The RFC 3066 code for the desired language.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>fullPath</em>&nbsp;</td><td>A pointer to the string that will be assigned the composed path. This will be of the form <code>ns:arrayName[@xml:lang='langName']</code>, where "ns" is the prefix for <code>schemaNS</code>. </td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<a class="anchor" name="458f8e8729e2334fe54ca8f691a9db23"></a><!-- doxytag: member="TXMPUtils::ComposeFieldSelector" ref="458f8e8729e2334fe54ca8f691a9db23" args="(XMP_StringPtr schemaNS, XMP_StringPtr arrayName, XMP_StringPtr fieldNS, XMP_StringPtr fieldName, XMP_StringPtr fieldValue, tStringObj *fullPath)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">static void <a class="el" href="classTXMPUtils.html">TXMPUtils</a>&lt; tStringObj &gt;::ComposeFieldSelector </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>schemaNS</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>arrayName</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>fieldNS</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>fieldName</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>fieldValue</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">tStringObj *&nbsp;</td>
+ <td class="paramname"> <em>fullPath</em></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"><code> [static]</code></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Compose the path expression to select an alternate item by a field's value.
+<p>
+The path syntax allows two forms of "content addressing" that may be used to select an item in an array of alternatives. The form used in <code>ComposeFieldSelector</code> lets you select an item in an array of structs based on the value of one of the fields in the structs. The other form of content addressing is shown in <code>ComposeLangSelector</code>.<p>
+For example, consider a simple struct that has two fields, the name of a city and the URI of an FTP site in that city. Use this to create an array of download alternatives. You can show the user a popup built from the values of the city fields. You can then get the corresponding URI as follows:<p>
+<div class="fragment"><pre class="fragment">
+ /// ComposeFieldSelector ( schemaNS, "Downloads", fieldNS, "City", chosenCity, &amp;path );
+ /// exists = GetStructField ( schemaNS, path, fieldNS, "URI", &amp;uri );
+ /// </pre></div><p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>schemaNS</em>&nbsp;</td><td>The namespace URI for the array. Must not be null or the empty string.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>arrayName</em>&nbsp;</td><td>The name of the array. May be a general path expression, must not be null or the empty string.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>fieldNS</em>&nbsp;</td><td>The namespace URI for the field used as the selector. Must not be null or the empty string.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>fieldName</em>&nbsp;</td><td>The name of the field used as the selector. Must be a simple XML name, must not be null or the empty string. It must be the name of a field that is itself simple.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>fieldValue</em>&nbsp;</td><td>The desired value of the field.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>fullPath</em>&nbsp;</td><td>A pointer to the string that will be assigned the composed path. This will be of the form <code>ns:arrayName[fNS:fieldName='fieldValue']</code>, where "ns" is the prefix for <code>schemaNS</code> and "fNS" is the prefix for <code>fieldNS</code>. </td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<a class="anchor" name="509691eb270988de6a770c9c8304ab6b"></a><!-- doxytag: member="TXMPUtils::ConvertFromBool" ref="509691eb270988de6a770c9c8304ab6b" args="(bool binValue, tStringObj *strValue)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">static void <a class="el" href="classTXMPUtils.html">TXMPUtils</a>&lt; tStringObj &gt;::ConvertFromBool </td>
+ <td>(</td>
+ <td class="paramtype">bool&nbsp;</td>
+ <td class="paramname"> <em>binValue</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">tStringObj *&nbsp;</td>
+ <td class="paramname"> <em>strValue</em></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"><code> [static]</code></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Convert from Boolean to string.
+<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>binValue</em>&nbsp;</td><td>The Boolean value to be converted.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>strValue</em>&nbsp;</td><td>The string representation of the Boolean. The values used are given by the macros <code>kXMP_TrueStr</code> and <code>kXMP_FalseStr</code> found in <code><a class="el" href="XMP__Const_8h.html">XMP_Const.h</a></code>. </td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<a class="anchor" name="eec45b4d1a26717290105c9f4e8b4235"></a><!-- doxytag: member="TXMPUtils::ConvertFromInt" ref="eec45b4d1a26717290105c9f4e8b4235" args="(long binValue, XMP_StringPtr format, tStringObj *strValue)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">static void <a class="el" href="classTXMPUtils.html">TXMPUtils</a>&lt; tStringObj &gt;::ConvertFromInt </td>
+ <td>(</td>
+ <td class="paramtype">long&nbsp;</td>
+ <td class="paramname"> <em>binValue</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>format</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">tStringObj *&nbsp;</td>
+ <td class="paramname"> <em>strValue</em></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"><code> [static]</code></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Convert from integer to string.
+<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>binValue</em>&nbsp;</td><td>The integer value to be converted.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>format</em>&nbsp;</td><td>Optional C sprintf format for the conversion. Defaults to "%d".</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>strValue</em>&nbsp;</td><td>The string representation of the integer. </td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<a class="anchor" name="e67ef3931836432b7e574832f0610ed0"></a><!-- doxytag: member="TXMPUtils::ConvertFromFloat" ref="e67ef3931836432b7e574832f0610ed0" args="(double binValue, XMP_StringPtr format, tStringObj *strValue)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">static void <a class="el" href="classTXMPUtils.html">TXMPUtils</a>&lt; tStringObj &gt;::ConvertFromFloat </td>
+ <td>(</td>
+ <td class="paramtype">double&nbsp;</td>
+ <td class="paramname"> <em>binValue</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>format</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">tStringObj *&nbsp;</td>
+ <td class="paramname"> <em>strValue</em></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"><code> [static]</code></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Convert from floating point to string.
+<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>binValue</em>&nbsp;</td><td>The floating point value to be converted.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>format</em>&nbsp;</td><td>Optional C sprintf format for the conversion. Defaults to "%f".</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>strValue</em>&nbsp;</td><td>The string representation of the floating point value. </td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<a class="anchor" name="6146a522a3974b4088d6e8241e9cd223"></a><!-- doxytag: member="TXMPUtils::ConvertFromDate" ref="6146a522a3974b4088d6e8241e9cd223" args="(const XMP_DateTime &amp;binValue, tStringObj *strValue)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">static void <a class="el" href="classTXMPUtils.html">TXMPUtils</a>&lt; tStringObj &gt;::ConvertFromDate </td>
+ <td>(</td>
+ <td class="paramtype">const <a class="el" href="structXMP__DateTime.html">XMP_DateTime</a> &amp;&nbsp;</td>
+ <td class="paramname"> <em>binValue</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">tStringObj *&nbsp;</td>
+ <td class="paramname"> <em>strValue</em></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"><code> [static]</code></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Convert from date/time to string.
+<p>
+Format a date according to the ISO 8601 profile in <a href="http://www.w3.org/TR/NOTE-datetime:">http://www.w3.org/TR/NOTE-datetime:</a> YYYY YYYY-MM YYYY-MM-DD YYYY-MM-DDThh:mmTZD YYYY-MM-DDThh:mm:ssTZD YYYY-MM-DDThh:mm:ss.sTZD<p>
+YYYY = four-digit year MM = two-digit month (01=January, etc.) DD = two-digit day of month (01 through 31) hh = two digits of hour (00 through 23) mm = two digits of minute (00 through 59) ss = two digits of second (00 through 59) s = one or more digits representing a decimal fraction of a second TZD = time zone designator (Z or +hh:mm or -hh:mm)<p>
+<dl class="note" compact><dt><b>Note:</b></dt><dd>ISO 8601 does not seem to allow years less than 1000 or greater than 9999. We allow any year, even negative ones. The year is formatted as "%.4d".<p>
+As a compatibility "tactic" (OK, a hack), so-called time-only input is allowed where the year, month, and day are all zero. This is output as "0000-00-00...".</dd></dl>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>binValue</em>&nbsp;</td><td>The <code><a class="el" href="structXMP__DateTime.html">XMP_DateTime</a></code> value to be converted.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>strValue</em>&nbsp;</td><td>The ISO 8601 string representation of the date/time. </td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<a class="anchor" name="aaaaadb23f4089daa795f50cba4f405c"></a><!-- doxytag: member="TXMPUtils::ConvertToBool" ref="aaaaadb23f4089daa795f50cba4f405c" args="(XMP_StringPtr strValue)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">static bool <a class="el" href="classTXMPUtils.html">TXMPUtils</a>&lt; tStringObj &gt;::ConvertToBool </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>strValue</em> </td>
+ <td>&nbsp;)&nbsp;</td>
+ <td width="100%"><code> [static]</code></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Convert from string to Boolean.
+<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>strValue</em>&nbsp;</td><td>The string representation of the Boolean.</td></tr>
+ </table>
+</dl>
+<dl class="return" compact><dt><b>Returns:</b></dt><dd>The appropriate C++ bool value for the string. The preferred strings are <code>kXMP_TrueStr</code> and <code>kXMP_FalseStr</code>. If these do not match, a case insensitive comparison is tried, then simply 't' or 'f', and finally non-zero and zero integer representations. </dd></dl>
+
+</div>
+</div><p>
+<a class="anchor" name="dfd9d1c522377d5db4ad667a7973ba00"></a><!-- doxytag: member="TXMPUtils::ConvertToInt" ref="dfd9d1c522377d5db4ad667a7973ba00" args="(XMP_StringPtr strValue)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">static long <a class="el" href="classTXMPUtils.html">TXMPUtils</a>&lt; tStringObj &gt;::ConvertToInt </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>strValue</em> </td>
+ <td>&nbsp;)&nbsp;</td>
+ <td width="100%"><code> [static]</code></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Convert from string to integer.
+<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>strValue</em>&nbsp;</td><td>The string representation of the integer.</td></tr>
+ </table>
+</dl>
+<dl class="return" compact><dt><b>Returns:</b></dt><dd>The integer value as a C long. </dd></dl>
+
+</div>
+</div><p>
+<a class="anchor" name="be5d2dcc03c5442202203bba5ca7b172"></a><!-- doxytag: member="TXMPUtils::ConvertToInt64" ref="be5d2dcc03c5442202203bba5ca7b172" args="(XMP_StringPtr strValue)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">static long long <a class="el" href="classTXMPUtils.html">TXMPUtils</a>&lt; tStringObj &gt;::ConvertToInt64 </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>strValue</em> </td>
+ <td>&nbsp;)&nbsp;</td>
+ <td width="100%"><code> [static]</code></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Convert from string to 64 bit integer.
+<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>strValue</em>&nbsp;</td><td>The string representation of the integer.</td></tr>
+ </table>
+</dl>
+<dl class="return" compact><dt><b>Returns:</b></dt><dd>The integer value as a C long long. </dd></dl>
+
+</div>
+</div><p>
+<a class="anchor" name="8a507b006286460814e0486c622d828c"></a><!-- doxytag: member="TXMPUtils::ConvertToFloat" ref="8a507b006286460814e0486c622d828c" args="(XMP_StringPtr strValue)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">static double <a class="el" href="classTXMPUtils.html">TXMPUtils</a>&lt; tStringObj &gt;::ConvertToFloat </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>strValue</em> </td>
+ <td>&nbsp;)&nbsp;</td>
+ <td width="100%"><code> [static]</code></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Convert from string to floating point.
+<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>strValue</em>&nbsp;</td><td>The string representation of the floating point value.</td></tr>
+ </table>
+</dl>
+<dl class="return" compact><dt><b>Returns:</b></dt><dd>The floating point value. </dd></dl>
+
+</div>
+</div><p>
+<a class="anchor" name="60d33e6ce30286028acca47b2b6e7a0b"></a><!-- doxytag: member="TXMPUtils::ConvertToDate" ref="60d33e6ce30286028acca47b2b6e7a0b" args="(XMP_StringPtr strValue, XMP_DateTime *binValue)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">static void <a class="el" href="classTXMPUtils.html">TXMPUtils</a>&lt; tStringObj &gt;::ConvertToDate </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>strValue</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="structXMP__DateTime.html">XMP_DateTime</a> *&nbsp;</td>
+ <td class="paramname"> <em>binValue</em></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"><code> [static]</code></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Convert from string to date/time.
+<p>
+Parse a date according to the ISO 8601 profile in <a href="http://www.w3.org/TR/NOTE-datetime:">http://www.w3.org/TR/NOTE-datetime:</a> YYYY YYYY-MM YYYY-MM-DD YYYY-MM-DDThh:mmTZD YYYY-MM-DDThh:mm:ssTZD YYYY-MM-DDThh:mm:ss.sTZD<p>
+YYYY = four-digit year MM = two-digit month (01=January, etc.) DD = two-digit day of month (01 through 31) hh = two digits of hour (00 through 23) mm = two digits of minute (00 through 59) ss = two digits of second (00 through 59) s = one or more digits representing a decimal fraction of a second TZD = time zone designator (Z or +hh:mm or -hh:mm)<p>
+<dl class="note" compact><dt><b>Note:</b></dt><dd>ISO 8601 does not seem to allow years less than 1000 or greater than 9999. We allow any year, even negative ones. The year is assumed to be formatted as "%.4d".<p>
+As compatibility "tactics" (OK, hacks), a missing date portion or missing TZD are tolerated. A missing date value may begin with "Thh:" or "hh:"; the year, month, and day are all set to zero in the <a class="el" href="structXMP__DateTime.html">XMP_DateTime</a> value. A missing TZD is assumed to be UTC.</dd></dl>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>strValue</em>&nbsp;</td><td>The ISO 8601 string representation of the date/time.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>binValue</em>&nbsp;</td><td>A pointer to the <code><a class="el" href="structXMP__DateTime.html">XMP_DateTime</a></code> variable to be assigned the date/time components. </td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<a class="anchor" name="c83f0b963ea64d7eee0b481e15a8439c"></a><!-- doxytag: member="TXMPUtils::CurrentDateTime" ref="c83f0b963ea64d7eee0b481e15a8439c" args="(XMP_DateTime *time)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">static void <a class="el" href="classTXMPUtils.html">TXMPUtils</a>&lt; tStringObj &gt;::CurrentDateTime </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="structXMP__DateTime.html">XMP_DateTime</a> *&nbsp;</td>
+ <td class="paramname"> <em>time</em> </td>
+ <td>&nbsp;)&nbsp;</td>
+ <td width="100%"><code> [static]</code></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Obtain the current date and time.
+<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>time</em>&nbsp;</td><td>A pointer to the <code><a class="el" href="structXMP__DateTime.html">XMP_DateTime</a></code> variable to be assigned the current date and time. The returned time is UTC, properly adjusted for the local time zone. The resolution of the time is not guaranteed to be finer than seconds. </td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<a class="anchor" name="96bcc45febac55f6c49951815b7de2ef"></a><!-- doxytag: member="TXMPUtils::SetTimeZone" ref="96bcc45febac55f6c49951815b7de2ef" args="(XMP_DateTime *time)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">static void <a class="el" href="classTXMPUtils.html">TXMPUtils</a>&lt; tStringObj &gt;::SetTimeZone </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="structXMP__DateTime.html">XMP_DateTime</a> *&nbsp;</td>
+ <td class="paramname"> <em>time</em> </td>
+ <td>&nbsp;)&nbsp;</td>
+ <td width="100%"><code> [static]</code></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Set the local time zone.
+<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>time</em>&nbsp;</td><td>A pointer to the <code><a class="el" href="structXMP__DateTime.html">XMP_DateTime</a></code> variable containing the value to be modified. Any existing time zone value is replaced, the other date/time fields are not adjusted in any way. </td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<a class="anchor" name="bbd4d691c83287ea2fc6b1e33e5858b8"></a><!-- doxytag: member="TXMPUtils::ConvertToUTCTime" ref="bbd4d691c83287ea2fc6b1e33e5858b8" args="(XMP_DateTime *time)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">static void <a class="el" href="classTXMPUtils.html">TXMPUtils</a>&lt; tStringObj &gt;::ConvertToUTCTime </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="structXMP__DateTime.html">XMP_DateTime</a> *&nbsp;</td>
+ <td class="paramname"> <em>time</em> </td>
+ <td>&nbsp;)&nbsp;</td>
+ <td width="100%"><code> [static]</code></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Make sure a time is UTC.
+<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>time</em>&nbsp;</td><td>A pointer to the <code><a class="el" href="structXMP__DateTime.html">XMP_DateTime</a></code> variable containing the time to be modified. If the time zone is not UTC, the time is adjusted and the time zone set to be UTC. </td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<a class="anchor" name="61852aaba494c8fbad5a6c0c4caf21f5"></a><!-- doxytag: member="TXMPUtils::ConvertToLocalTime" ref="61852aaba494c8fbad5a6c0c4caf21f5" args="(XMP_DateTime *time)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">static void <a class="el" href="classTXMPUtils.html">TXMPUtils</a>&lt; tStringObj &gt;::ConvertToLocalTime </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="structXMP__DateTime.html">XMP_DateTime</a> *&nbsp;</td>
+ <td class="paramname"> <em>time</em> </td>
+ <td>&nbsp;)&nbsp;</td>
+ <td width="100%"><code> [static]</code></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Make sure a time is local.
+<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>time</em>&nbsp;</td><td>A pointer to the <code><a class="el" href="structXMP__DateTime.html">XMP_DateTime</a></code> variable containing the time to be modified. If the time zone is not the local zone, the time is adjusted and the time zone set to be local. </td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<a class="anchor" name="9fc7f1771032f59f9020aeda4f91991d"></a><!-- doxytag: member="TXMPUtils::CompareDateTime" ref="9fc7f1771032f59f9020aeda4f91991d" args="(const XMP_DateTime &amp;left, const XMP_DateTime &amp;right)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">static int <a class="el" href="classTXMPUtils.html">TXMPUtils</a>&lt; tStringObj &gt;::CompareDateTime </td>
+ <td>(</td>
+ <td class="paramtype">const <a class="el" href="structXMP__DateTime.html">XMP_DateTime</a> &amp;&nbsp;</td>
+ <td class="paramname"> <em>left</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">const <a class="el" href="structXMP__DateTime.html">XMP_DateTime</a> &amp;&nbsp;</td>
+ <td class="paramname"> <em>right</em></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"><code> [static]</code></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Compare the order of two date/time values.
+<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>left</em>&nbsp;</td><td>The "lefthand" date/time.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>right</em>&nbsp;</td><td>The "righthand" date/time.</td></tr>
+ </table>
+</dl>
+<dl class="return" compact><dt><b>Returns:</b></dt><dd><ul>
+<li>-1 if left is before right </li>
+<li>0 if left matches right </li>
+<li>+1 if left is after right </li>
+</ul>
+</dd></dl>
+
+</div>
+</div><p>
+<a class="anchor" name="ef3b23bbc152480f699e269620ecad4a"></a><!-- doxytag: member="TXMPUtils::EncodeToBase64" ref="ef3b23bbc152480f699e269620ecad4a" args="(XMP_StringPtr rawStr, XMP_StringLen rawLen, tStringObj *encodedStr)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">static void <a class="el" href="classTXMPUtils.html">TXMPUtils</a>&lt; tStringObj &gt;::EncodeToBase64 </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>rawStr</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#9f7dcc184f901c713274edfdac5bcc9a">XMP_StringLen</a>&nbsp;</td>
+ <td class="paramname"> <em>rawLen</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">tStringObj *&nbsp;</td>
+ <td class="paramname"> <em>encodedStr</em></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"><code> [static]</code></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Convert from raw data to Base64 encoded string.
+<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>rawStr</em>&nbsp;</td><td>The pointer to raw data to be converted.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>rawLen</em>&nbsp;</td><td>The length of raw data to be converted.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>encodedStr</em>&nbsp;</td><td>The XMP object to contain the encoded string. </td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<a class="anchor" name="e5bdd91c0c3ee9262dc0a8b9f591b921"></a><!-- doxytag: member="TXMPUtils::DecodeFromBase64" ref="e5bdd91c0c3ee9262dc0a8b9f591b921" args="(XMP_StringPtr encodedStr, XMP_StringLen encodedLen, tStringObj *rawStr)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">static void <a class="el" href="classTXMPUtils.html">TXMPUtils</a>&lt; tStringObj &gt;::DecodeFromBase64 </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>encodedStr</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#9f7dcc184f901c713274edfdac5bcc9a">XMP_StringLen</a>&nbsp;</td>
+ <td class="paramname"> <em>encodedLen</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">tStringObj *&nbsp;</td>
+ <td class="paramname"> <em>rawStr</em></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"><code> [static]</code></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Decode from Base64 encoded string to raw data.
+<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>encodedStr</em>&nbsp;</td><td>The pointer to encoded data to be converted.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>encodedLen</em>&nbsp;</td><td>The length of encoded datavto be converted.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>rawStr</em>&nbsp;</td><td>The XMP object to contain the decoded string. </td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<a class="anchor" name="6001b4ff54c60fdf0c40e6b78a5c457a"></a><!-- doxytag: member="TXMPUtils::PackageForJPEG" ref="6001b4ff54c60fdf0c40e6b78a5c457a" args="(const TXMPMeta&lt; tStringObj &gt; &amp;xmpObj, tStringObj *standardXMP, tStringObj *extendedXMP, tStringObj *extendedDigest)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">static void <a class="el" href="classTXMPUtils.html">TXMPUtils</a>&lt; tStringObj &gt;::PackageForJPEG </td>
+ <td>(</td>
+ <td class="paramtype">const <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt; &amp;&nbsp;</td>
+ <td class="paramname"> <em>xmpObj</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">tStringObj *&nbsp;</td>
+ <td class="paramname"> <em>standardXMP</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">tStringObj *&nbsp;</td>
+ <td class="paramname"> <em>extendedXMP</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">tStringObj *&nbsp;</td>
+ <td class="paramname"> <em>extendedDigest</em></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"><code> [static]</code></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Create XMP serializations appropriate for a JPEG file. The standard XMP in a JPEG file is limited to about 65500 bytes. <code>PackageForJPEG</code> attempts to fit the serialization within that limit. If necessary it will partition the XMP into 2 serializations.
+<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>xmpObj</em>&nbsp;</td><td>The XMP for the JPEG file.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>standardXMP</em>&nbsp;</td><td>The full standard XMP packet.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>extendedXMP</em>&nbsp;</td><td>The serialized extended XMP, empty if not needed.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>extendedDigest</em>&nbsp;</td><td>An MD5 digest of the serialized extended XMP, empty if not needed. </td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<a class="anchor" name="6187cd5fef0eccecac6805d4114dcd2e"></a><!-- doxytag: member="TXMPUtils::MergeFromJPEG" ref="6187cd5fef0eccecac6805d4114dcd2e" args="(TXMPMeta&lt; tStringObj &gt; *fullXMP, const TXMPMeta&lt; tStringObj &gt; &amp;extendedXMP)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">static void <a class="el" href="classTXMPUtils.html">TXMPUtils</a>&lt; tStringObj &gt;::MergeFromJPEG </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt; *&nbsp;</td>
+ <td class="paramname"> <em>fullXMP</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">const <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt; &amp;&nbsp;</td>
+ <td class="paramname"> <em>extendedXMP</em></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"><code> [static]</code></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Put the extended XMP properties back into the full XMP.
+<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>fullXMP</em>&nbsp;</td><td>The full XMP, presumed to be initialized from the standard XMP packet.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>extendedXMP</em>&nbsp;</td><td>The properties that were partitioned into the extended XMP. </td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<a class="anchor" name="d7e1aa7928252fb88a24fb5c3aef22ba"></a><!-- doxytag: member="TXMPUtils::CatenateArrayItems" ref="d7e1aa7928252fb88a24fb5c3aef22ba" args="(const TXMPMeta&lt; tStringObj &gt; &amp;xmpObj, XMP_StringPtr schemaNS, XMP_StringPtr arrayName, XMP_StringPtr separator, XMP_StringPtr quotes, XMP_OptionBits options, tStringObj *catedStr)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">static void <a class="el" href="classTXMPUtils.html">TXMPUtils</a>&lt; tStringObj &gt;::CatenateArrayItems </td>
+ <td>(</td>
+ <td class="paramtype">const <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt; &amp;&nbsp;</td>
+ <td class="paramname"> <em>xmpObj</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>schemaNS</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>arrayName</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>separator</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>quotes</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a>&nbsp;</td>
+ <td class="paramname"> <em>options</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">tStringObj *&nbsp;</td>
+ <td class="paramname"> <em>catedStr</em></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"><code> [static]</code></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Create a single edit string from an array of strings.
+<p>
+TBD - needs more description<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>xmpObj</em>&nbsp;</td><td>The XMP object containing the array to be catenated.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>schemaNS</em>&nbsp;</td><td>The schema namespace URI for the array. Must not be null or the empty string.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>arrayName</em>&nbsp;</td><td>The name of the array. May be a general path expression, must not be null or the empty string. Each item in the array must be a simple string value.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>separator</em>&nbsp;</td><td>The string to be used to separate the items in the catenated string. Defaults to "; ", ASCII semicolon and space (U+003B, U+0020).</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>quotes</em>&nbsp;</td><td>The characters to be used as quotes around array items that contain a separator. Defaults to '"', ASCII quote (U+0022).</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>options</em>&nbsp;</td><td>Option flags to control the catenation.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>catedStr</em>&nbsp;</td><td>A pointer to the string to be assigned the catenated array items. </td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<a class="anchor" name="66c5ddee47aa36ed906353f94ca18d2e"></a><!-- doxytag: member="TXMPUtils::SeparateArrayItems" ref="66c5ddee47aa36ed906353f94ca18d2e" args="(TXMPMeta&lt; tStringObj &gt; *xmpObj, XMP_StringPtr schemaNS, XMP_StringPtr arrayName, XMP_OptionBits options, XMP_StringPtr catedStr)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">static void <a class="el" href="classTXMPUtils.html">TXMPUtils</a>&lt; tStringObj &gt;::SeparateArrayItems </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt; *&nbsp;</td>
+ <td class="paramname"> <em>xmpObj</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>schemaNS</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>arrayName</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a>&nbsp;</td>
+ <td class="paramname"> <em>options</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>catedStr</em></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"><code> [static]</code></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Separate a single edit string into an array of strings.
+<p>
+TBD - needs more description<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>xmpObj</em>&nbsp;</td><td>The XMP object containing the array to be updated.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>schemaNS</em>&nbsp;</td><td>The schema namespace URI for the array. Must not be null or the empty string.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>arrayName</em>&nbsp;</td><td>The name of the array. May be a general path expression, must not be null or the empty string. Each item in the array must be a simple string value.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>options</em>&nbsp;</td><td>Option flags to control the separation.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>catedStr</em>&nbsp;</td><td>The string to be separated into the array items. </td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<a class="anchor" name="40c645803530662e08d042b4b7c6190d"></a><!-- doxytag: member="TXMPUtils::RemoveProperties" ref="40c645803530662e08d042b4b7c6190d" args="(TXMPMeta&lt; tStringObj &gt; *xmpObj, XMP_StringPtr schemaNS=0, XMP_StringPtr propName=0, XMP_OptionBits options=0)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">static void <a class="el" href="classTXMPUtils.html">TXMPUtils</a>&lt; tStringObj &gt;::RemoveProperties </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt; *&nbsp;</td>
+ <td class="paramname"> <em>xmpObj</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>schemaNS</em> = <code>0</code>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>propName</em> = <code>0</code>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a>&nbsp;</td>
+ <td class="paramname"> <em>options</em> = <code>0</code></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"><code> [static]</code></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Remove multiple properties from an XMP object.
+<p>
+<code>RemoveProperties</code> was created to support the File Info dialog's Delete button, and has been been generalized somewhat from those specific needs. It operates in one of three main modes depending on the schemaNS and propName parameters:<p>
+<ul>
+<li>Non-empty <code>schemaNS</code> and <code>propName</code> - The named property is removed if it is an external property, or if the <code>kXMPUtil_DoAllProperties</code> option is passed. It does not matter whether the named property is an actual property or an alias.</li>
+</ul>
+<ul>
+<li>Non-empty <code>schemaNS</code> and empty <code>propName</code> - The all external properties in the named schema are removed. Internal properties are also removed if the <code>kXMPUtil_DoAllProperties</code> option is passed. In addition, aliases from the named schema will be removed if the <code>kXMPUtil_IncludeAliases</code> option is passed.</li>
+</ul>
+<ul>
+<li>Empty <code>schemaNS</code> and empty <code>propName</code> - All external properties in all schema are removed. Internal properties are also removed if the <code>kXMPUtil_DoAllProperties</code> option is passed. Aliases are implicitly handled because the associated actuals are.</li>
+</ul>
+It is an error to pass and empty schemaNS and non-empty propName.<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>xmpObj</em>&nbsp;</td><td>The XMP object containing the properties to be removed.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>schemaNS</em>&nbsp;</td><td>Optional schema namespace URI for the properties to be removed.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>propName</em>&nbsp;</td><td>Optional path expression for the property to be removed.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>options</em>&nbsp;</td><td>Option flags to control the deletion. The defined flags are: <ul>
+<li><code>kXMPUtil_DoAllProperties</code> - Do internal properties in addition to external properties. </li>
+<li><code>kXMPUtil_IncludeAliases</code> - Include aliases in the "named schema" case above. </li>
+</ul>
+</td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<a class="anchor" name="4795244ffcbda927800f789b0e40c262"></a><!-- doxytag: member="TXMPUtils::AppendProperties" ref="4795244ffcbda927800f789b0e40c262" args="(const TXMPMeta&lt; tStringObj &gt; &amp;source, TXMPMeta&lt; tStringObj &gt; *dest, XMP_OptionBits options=0)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">static void <a class="el" href="classTXMPUtils.html">TXMPUtils</a>&lt; tStringObj &gt;::AppendProperties </td>
+ <td>(</td>
+ <td class="paramtype">const <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt; &amp;&nbsp;</td>
+ <td class="paramname"> <em>source</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt; *&nbsp;</td>
+ <td class="paramname"> <em>dest</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a>&nbsp;</td>
+ <td class="paramname"> <em>options</em> = <code>0</code></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"><code> [static]</code></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Append properties from one XMP object to another.
+<p>
+<code>AppendProperties</code> was created to support the File Info dialog's Append button, and has been been generalized somewhat from those specific needs. It appends information from one XMP object (<code>source</code>) to another (<code>dest</code>). The default operation is to append only external properties that do not already exist in the destination. The kXMPUtil_DoAllProperties option can be used to operate on all properties, external and internal. The kXMPUtil_ReplaceOldValues option can be used to replace the values of existing properties. The notion of external versus internal applies only to top level properties. The keep-or-replace-old notion applies within structs and arrays as described below.<p>
+If kXMPUtil_ReplaceOldValues is passed then the processing is restricted to the top level properties. The processed properties from the source (according to kXMPUtil_DoAllProperties) are propagated to the destination, replacing any existing values. Properties in the destination that are not in the source are left alone.<p>
+If kXMPUtil_ReplaceOldValues is not passed then the processing is more complicated. Top level properties are added to the destination if they do not already exist. If they do exist but differ in form (simple/struct/array) then the destination is left alone. If the forms match, simple properties are left unchanged while structs and arrays are merged.<p>
+If kXMPUtil_DeleteEmptyValues is passed then an empty value in the source XMP causes the corresponding Dest XMP property to be deleted. The default is to treat empty values the same as non-empty values. An empty value is any of a simple empty string, an array with no items, or a struct with no fields. Qualifiers are ignored.<p>
+The detailed behavior is defined by the following pseudo-code: <div class="fragment"><pre class="fragment">
+ /// AppendProperties ( sourceXMP, destXMP, options ):
+ /// doAll = options &amp; kXMPUtil_DoAllProperties
+ /// replaceOld = options &amp; kXMPUtil_ReplaceOldValues
+ /// deleteEmpty = options &amp; kXMPUtil_DeleteEmptyValues
+ /// for all source schema (top level namespaces):
+ /// for all top level properties in sourceSchema:
+ /// if doAll or prop is external:
+ /// AppendSubtree ( sourceNode, destSchema, replaceOld, deleteEmpty )
+ ///
+ /// AppendSubtree ( sourceNode, destParent, replaceOld, deleteEmpty ):
+ /// if deleteEmpty and source value is empty:
+ /// delete the corresponding child from destParent
+ /// else if sourceNode not in destParent (by name):
+ /// copy sourceNode's subtree to destParent
+ /// else if replaceOld:
+ /// delete subtree from destParent
+ /// copy sourceNode's subtree to destParent
+ /// else:
+ /// // Already exists in dest and not replacing, merge structs and arrays
+ /// if sourceNode and destNode forms differ:
+ /// return, leave the destNode alone
+ /// else if form is a struct:
+ /// for each field in sourceNode:
+ /// AppendSubtree ( sourceNode.field, destNode, replaceOld )
+ /// else if form is an alt-text array:
+ /// copy new items by xml:lang value into the destination
+ /// else if form is an array:
+ /// copy new items by value into the destination, ignoring order and duplicates
+ /// </pre></div><p>
+<dl class="note" compact><dt><b>Note:</b></dt><dd><code>AppendProperties</code> can be expensive if replaceOld is not passed and the XMP contains large arrays. The array item checking described above is n-squared. Each source item is checked to see if it already exists in the destination, without regard to order or duplicates. Simple items are compared by value and xml:lang qualifier, other qualifiers are ignored. Structs are recursively compared by field names, without regard to field order. Arrays are compared by recursively comparing all items.</dd></dl>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>source</em>&nbsp;</td><td>The source XMP object.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>dest</em>&nbsp;</td><td>The destination XMP object.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>options</em>&nbsp;</td><td>Option flags to control the copying. <ul>
+<li><code>kXMPUtil_DoAllProperties</code> - Do internal properties in addition to external properties. </li>
+<li><code>kXMPUtil_ReplaceOldValues</code> - Replace the values of existing properties. </li>
+<li><code>kXMPUtil_DeleteEmptyValues</code> - Delete properties if the new value is empty. </li>
+</ul>
+</td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<a class="anchor" name="a17838f062e5414bc0929f67ac94a3aa"></a><!-- doxytag: member="TXMPUtils::DuplicateSubtree" ref="a17838f062e5414bc0929f67ac94a3aa" args="(const TXMPMeta&lt; tStringObj &gt; &amp;source, TXMPMeta&lt; tStringObj &gt; *dest, XMP_StringPtr sourceNS, XMP_StringPtr sourceRoot, XMP_StringPtr destNS=0, XMP_StringPtr destRoot=0, XMP_OptionBits options=0)" -->
+<div class="memitem">
+<div class="memproto">
+<div class="memtemplate">
+template&lt;class tStringObj&gt; </div>
+ <table class="memname">
+ <tr>
+ <td class="memname">static void <a class="el" href="classTXMPUtils.html">TXMPUtils</a>&lt; tStringObj &gt;::DuplicateSubtree </td>
+ <td>(</td>
+ <td class="paramtype">const <a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt; &amp;&nbsp;</td>
+ <td class="paramname"> <em>source</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="classTXMPMeta.html">TXMPMeta</a>&lt; tStringObj &gt; *&nbsp;</td>
+ <td class="paramname"> <em>dest</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>sourceNS</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>sourceRoot</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>destNS</em> = <code>0</code>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a>&nbsp;</td>
+ <td class="paramname"> <em>destRoot</em> = <code>0</code>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype"><a class="el" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a>&nbsp;</td>
+ <td class="paramname"> <em>options</em> = <code>0</code></td><td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td><td width="100%"><code> [static]</code></td>
+ </tr>
+ </table>
+</div>
+<div class="memdoc">
+
+<p>
+Replicate a subtree from one XMP object into another, possibly at a different location.
+<p>
+TBD - needs more description<p>
+<dl compact><dt><b>Parameters:</b></dt><dd>
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr><td valign="top"></td><td valign="top"><em>source</em>&nbsp;</td><td>The source XMP object.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>dest</em>&nbsp;</td><td>The destination XMP object.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>sourceNS</em>&nbsp;</td><td>The schema namespace URI for the source subtree.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>sourceRoot</em>&nbsp;</td><td>The root location for the source subtree. May be a general path expression, must not be null or the empty string.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>destNS</em>&nbsp;</td><td>The schema namespace URI for the destination. Defaults to the source namespace.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>destRoot</em>&nbsp;</td><td>The root location for the destination. May be a general path expression. Defaults to the source location.</td></tr>
+ <tr><td valign="top"></td><td valign="top"><em>options</em>&nbsp;</td><td>Option flags to control the separation. </td></tr>
+ </table>
+</dl>
+
+</div>
+</div><p>
+<hr>The documentation for this class was generated from the following file:<ul>
+<li><a class="el" href="TXMPUtils_8hpp-source.html">TXMPUtils.hpp</a></ul>
+<hr size="1"><address style="align: right;"><small>Generated on Thu May 3 14:54:59 2007 for Adobe XMP Toolkit by&nbsp;
+<a href="http://www.doxygen.org/index.html">
+<img src="doxygen.png" alt="doxygen" align="middle" border="0"></a> 1.5.1 </small></address>
+</body>
+</html>
diff --git a/docs/XMPToolkit/doxygen.css b/docs/XMPToolkit/doxygen.css
new file mode 100644
index 0000000..c7db1a8
--- /dev/null
+++ b/docs/XMPToolkit/doxygen.css
@@ -0,0 +1,358 @@
+BODY,H1,H2,H3,H4,H5,H6,P,CENTER,TD,TH,UL,DL,DIV {
+ font-family: Geneva, Arial, Helvetica, sans-serif;
+}
+BODY,TD {
+ font-size: 90%;
+}
+H1 {
+ text-align: center;
+ font-size: 160%;
+}
+H2 {
+ font-size: 120%;
+}
+H3 {
+ font-size: 100%;
+}
+CAPTION { font-weight: bold }
+DIV.qindex {
+ width: 100%;
+ background-color: #e8eef2;
+ border: 1px solid #84b0c7;
+ text-align: center;
+ margin: 2px;
+ padding: 2px;
+ line-height: 140%;
+}
+DIV.nav {
+ width: 100%;
+ background-color: #e8eef2;
+ border: 1px solid #84b0c7;
+ text-align: center;
+ margin: 2px;
+ padding: 2px;
+ line-height: 140%;
+}
+DIV.navtab {
+ background-color: #e8eef2;
+ border: 1px solid #84b0c7;
+ text-align: center;
+ margin: 2px;
+ margin-right: 15px;
+ padding: 2px;
+}
+TD.navtab {
+ font-size: 70%;
+}
+A.qindex {
+ text-decoration: none;
+ font-weight: bold;
+ color: #1A419D;
+}
+A.qindex:visited {
+ text-decoration: none;
+ font-weight: bold;
+ color: #1A419D
+}
+A.qindex:hover {
+ text-decoration: none;
+ background-color: #ddddff;
+}
+A.qindexHL {
+ text-decoration: none;
+ font-weight: bold;
+ background-color: #6666cc;
+ color: #ffffff;
+ border: 1px double #9295C2;
+}
+A.qindexHL:hover {
+ text-decoration: none;
+ background-color: #6666cc;
+ color: #ffffff;
+}
+A.qindexHL:visited { text-decoration: none; background-color: #6666cc; color: #ffffff }
+A.el { text-decoration: none; font-weight: bold }
+A.elRef { font-weight: bold }
+A.code:link { text-decoration: none; font-weight: normal; color: #0000FF}
+A.code:visited { text-decoration: none; font-weight: normal; color: #0000FF}
+A.codeRef:link { font-weight: normal; color: #0000FF}
+A.codeRef:visited { font-weight: normal; color: #0000FF}
+A:hover { text-decoration: none; background-color: #f2f2ff }
+DL.el { margin-left: -1cm }
+.fragment {
+ font-family: monospace, fixed;
+ font-size: 95%;
+}
+PRE.fragment {
+ border: 1px solid #CCCCCC;
+ background-color: #f5f5f5;
+ margin-top: 4px;
+ margin-bottom: 4px;
+ margin-left: 2px;
+ margin-right: 8px;
+ padding-left: 6px;
+ padding-right: 6px;
+ padding-top: 4px;
+ padding-bottom: 4px;
+}
+DIV.ah { background-color: black; font-weight: bold; color: #ffffff; margin-bottom: 3px; margin-top: 3px }
+
+DIV.groupHeader {
+ margin-left: 16px;
+ margin-top: 12px;
+ margin-bottom: 6px;
+ font-weight: bold;
+}
+DIV.groupText { margin-left: 16px; font-style: italic; font-size: 90% }
+BODY {
+ background: white;
+ color: black;
+ margin-right: 20px;
+ margin-left: 20px;
+}
+TD.indexkey {
+ background-color: #e8eef2;
+ font-weight: bold;
+ padding-right : 10px;
+ padding-top : 2px;
+ padding-left : 10px;
+ padding-bottom : 2px;
+ margin-left : 0px;
+ margin-right : 0px;
+ margin-top : 2px;
+ margin-bottom : 2px;
+ border: 1px solid #CCCCCC;
+}
+TD.indexvalue {
+ background-color: #e8eef2;
+ font-style: italic;
+ padding-right : 10px;
+ padding-top : 2px;
+ padding-left : 10px;
+ padding-bottom : 2px;
+ margin-left : 0px;
+ margin-right : 0px;
+ margin-top : 2px;
+ margin-bottom : 2px;
+ border: 1px solid #CCCCCC;
+}
+TR.memlist {
+ background-color: #f0f0f0;
+}
+P.formulaDsp { text-align: center; }
+IMG.formulaDsp { }
+IMG.formulaInl { vertical-align: middle; }
+SPAN.keyword { color: #008000 }
+SPAN.keywordtype { color: #604020 }
+SPAN.keywordflow { color: #e08000 }
+SPAN.comment { color: #800000 }
+SPAN.preprocessor { color: #806020 }
+SPAN.stringliteral { color: #002080 }
+SPAN.charliteral { color: #008080 }
+.mdescLeft {
+ padding: 0px 8px 4px 8px;
+ font-size: 80%;
+ font-style: italic;
+ background-color: #FAFAFA;
+ border-top: 1px none #E0E0E0;
+ border-right: 1px none #E0E0E0;
+ border-bottom: 1px none #E0E0E0;
+ border-left: 1px none #E0E0E0;
+ margin: 0px;
+}
+.mdescRight {
+ padding: 0px 8px 4px 8px;
+ font-size: 80%;
+ font-style: italic;
+ background-color: #FAFAFA;
+ border-top: 1px none #E0E0E0;
+ border-right: 1px none #E0E0E0;
+ border-bottom: 1px none #E0E0E0;
+ border-left: 1px none #E0E0E0;
+ margin: 0px;
+}
+.memItemLeft {
+ padding: 1px 0px 0px 8px;
+ margin: 4px;
+ border-top-width: 1px;
+ border-right-width: 1px;
+ border-bottom-width: 1px;
+ border-left-width: 1px;
+ border-top-color: #E0E0E0;
+ border-right-color: #E0E0E0;
+ border-bottom-color: #E0E0E0;
+ border-left-color: #E0E0E0;
+ border-top-style: solid;
+ border-right-style: none;
+ border-bottom-style: none;
+ border-left-style: none;
+ background-color: #FAFAFA;
+ font-size: 80%;
+}
+.memItemRight {
+ padding: 1px 8px 0px 8px;
+ margin: 4px;
+ border-top-width: 1px;
+ border-right-width: 1px;
+ border-bottom-width: 1px;
+ border-left-width: 1px;
+ border-top-color: #E0E0E0;
+ border-right-color: #E0E0E0;
+ border-bottom-color: #E0E0E0;
+ border-left-color: #E0E0E0;
+ border-top-style: solid;
+ border-right-style: none;
+ border-bottom-style: none;
+ border-left-style: none;
+ background-color: #FAFAFA;
+ font-size: 80%;
+}
+.memTemplItemLeft {
+ padding: 1px 0px 0px 8px;
+ margin: 4px;
+ border-top-width: 1px;
+ border-right-width: 1px;
+ border-bottom-width: 1px;
+ border-left-width: 1px;
+ border-top-color: #E0E0E0;
+ border-right-color: #E0E0E0;
+ border-bottom-color: #E0E0E0;
+ border-left-color: #E0E0E0;
+ border-top-style: none;
+ border-right-style: none;
+ border-bottom-style: none;
+ border-left-style: none;
+ background-color: #FAFAFA;
+ font-size: 80%;
+}
+.memTemplItemRight {
+ padding: 1px 8px 0px 8px;
+ margin: 4px;
+ border-top-width: 1px;
+ border-right-width: 1px;
+ border-bottom-width: 1px;
+ border-left-width: 1px;
+ border-top-color: #E0E0E0;
+ border-right-color: #E0E0E0;
+ border-bottom-color: #E0E0E0;
+ border-left-color: #E0E0E0;
+ border-top-style: none;
+ border-right-style: none;
+ border-bottom-style: none;
+ border-left-style: none;
+ background-color: #FAFAFA;
+ font-size: 80%;
+}
+.memTemplParams {
+ padding: 1px 0px 0px 8px;
+ margin: 4px;
+ border-top-width: 1px;
+ border-right-width: 1px;
+ border-bottom-width: 1px;
+ border-left-width: 1px;
+ border-top-color: #E0E0E0;
+ border-right-color: #E0E0E0;
+ border-bottom-color: #E0E0E0;
+ border-left-color: #E0E0E0;
+ border-top-style: solid;
+ border-right-style: none;
+ border-bottom-style: none;
+ border-left-style: none;
+ color: #606060;
+ background-color: #FAFAFA;
+ font-size: 80%;
+}
+.search { color: #003399;
+ font-weight: bold;
+}
+FORM.search {
+ margin-bottom: 0px;
+ margin-top: 0px;
+}
+INPUT.search { font-size: 75%;
+ color: #000080;
+ font-weight: normal;
+ background-color: #e8eef2;
+}
+TD.tiny { font-size: 75%;
+}
+a {
+ color: #1A41A8;
+}
+a:visited {
+ color: #2A3798;
+}
+.dirtab { padding: 4px;
+ border-collapse: collapse;
+ border: 1px solid #84b0c7;
+}
+TH.dirtab { background: #e8eef2;
+ font-weight: bold;
+}
+HR { height: 1px;
+ border: none;
+ border-top: 1px solid black;
+}
+
+/* Style for detailed member documentation */
+.memtemplate {
+ font-size: 80%;
+ color: #606060;
+ font-weight: normal;
+}
+.memnav {
+ background-color: #e8eef2;
+ border: 1px solid #84b0c7;
+ text-align: center;
+ margin: 2px;
+ margin-right: 15px;
+ padding: 2px;
+}
+.memitem {
+ padding: 4px;
+ background-color: #eef3f5;
+ border-width: 1px;
+ border-style: solid;
+ border-color: #dedeee;
+ -moz-border-radius: 8px 8px 8px 8px;
+}
+.memname {
+ white-space: nowrap;
+ font-weight: bold;
+}
+.memdoc{
+ padding-left: 10px;
+}
+.memproto {
+ background-color: #d5e1e8;
+ width: 100%;
+ border-width: 1px;
+ border-style: solid;
+ border-color: #84b0c7;
+ font-weight: bold;
+ -moz-border-radius: 8px 8px 8px 8px;
+}
+.paramkey {
+ text-align: right;
+}
+.paramtype {
+ white-space: nowrap;
+}
+.paramname {
+ color: #602020;
+ font-style: italic;
+ white-space: nowrap;
+}
+/* End Styling for detailed member documentation */
+
+/* for the tree view */
+.ftvtree {
+ font-family: sans-serif;
+ margin:0.5em;
+}
+.directory { font-size: 9pt; font-weight: bold; }
+.directory h3 { margin: 0px; margin-top: 1em; font-size: 11pt; }
+.directory > h3 { margin-top: 0; }
+.directory p { margin: 0px; white-space: nowrap; }
+.directory div { display: none; margin: 0px; }
+.directory img { vertical-align: -30%; }
diff --git a/docs/XMPToolkit/doxygen.png b/docs/XMPToolkit/doxygen.png
new file mode 100644
index 0000000..f0a274b
--- /dev/null
+++ b/docs/XMPToolkit/doxygen.png
Binary files differ
diff --git a/docs/XMPToolkit/files.html b/docs/XMPToolkit/files.html
new file mode 100644
index 0000000..98ad7cf
--- /dev/null
+++ b/docs/XMPToolkit/files.html
@@ -0,0 +1,31 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
+<title>Adobe XMP Toolkit: File Index</title>
+<link href="doxygen.css" rel="stylesheet" type="text/css">
+<link href="tabs.css" rel="stylesheet" type="text/css">
+</head><body>
+<!-- Generated by Doxygen 1.5.1 -->
+<div class="tabs">
+ <ul>
+ <li><a href="index.html"><span>Main&nbsp;Page</span></a></li>
+ <li><a href="modules.html"><span>Modules</span></a></li>
+ <li><a href="annotated.html"><span>Classes</span></a></li>
+ <li id="current"><a href="files.html"><span>Files</span></a></li>
+ </ul></div>
+<h1>Adobe XMP Toolkit File List</h1>Here is a list of all documented files with brief descriptions:<table>
+ <tr><td class="indexkey"><a class="el" href="TXMPFiles_8hpp.html">TXMPFiles.hpp</a> <a href="TXMPFiles_8hpp-source.html">[code]</a></td><td class="indexvalue">API for access to the "main" metadata in a file </td></tr>
+ <tr><td class="indexkey"><a class="el" href="TXMPFiles_8incl__cpp.html">TXMPFiles.incl_cpp</a></td><td class="indexvalue">The implementation of the <a class="el" href="classTXMPFiles.html">TXMPFiles</a> template class </td></tr>
+ <tr><td class="indexkey"><a class="el" href="TXMPIterator_8hpp.html">TXMPIterator.hpp</a> <a href="TXMPIterator_8hpp-source.html">[code]</a></td><td class="indexvalue">Template class for the XMP Toolkit iteration services </td></tr>
+ <tr><td class="indexkey"><a class="el" href="TXMPIterator_8incl__cpp.html">TXMPIterator.incl_cpp</a></td><td class="indexvalue">The implementation of the <a class="el" href="classTXMPIterator.html">TXMPIterator</a> template class </td></tr>
+ <tr><td class="indexkey"><a class="el" href="TXMPMeta_8hpp.html">TXMPMeta.hpp</a> <a href="TXMPMeta_8hpp-source.html">[code]</a></td><td class="indexvalue">Template class for the XMP Toolkit core services </td></tr>
+ <tr><td class="indexkey"><a class="el" href="TXMPMeta_8incl__cpp.html">TXMPMeta.incl_cpp</a></td><td class="indexvalue">The implementation of the <a class="el" href="classTXMPMeta.html">TXMPMeta</a> template class </td></tr>
+ <tr><td class="indexkey"><a class="el" href="TXMPUtils_8hpp.html">TXMPUtils.hpp</a> <a href="TXMPUtils_8hpp-source.html">[code]</a></td><td class="indexvalue">Template class for the XMP Toolkit utility services </td></tr>
+ <tr><td class="indexkey"><a class="el" href="TXMPUtils_8incl__cpp.html">TXMPUtils.incl_cpp</a></td><td class="indexvalue">The implementation of the <a class="el" href="classTXMPUtils.html">TXMPUtils</a> template class </td></tr>
+ <tr><td class="indexkey"><a class="el" href="XMP_8incl__cpp.html">XMP.incl_cpp</a></td><td class="indexvalue">Overall client glue file for the XMP toolkit </td></tr>
+ <tr><td class="indexkey"><a class="el" href="XMP__Const_8h.html">XMP_Const.h</a> <a href="XMP__Const_8h-source.html">[code]</a></td><td class="indexvalue">Common C/C++ types and constants for the XMP toolkit </td></tr>
+</table>
+<hr size="1"><address style="align: right;"><small>Generated on Thu May 3 14:54:59 2007 for Adobe XMP Toolkit by&nbsp;
+<a href="http://www.doxygen.org/index.html">
+<img src="doxygen.png" alt="doxygen" align="middle" border="0"></a> 1.5.1 </small></address>
+</body>
+</html>
diff --git a/docs/XMPToolkit/functions.html b/docs/XMPToolkit/functions.html
new file mode 100644
index 0000000..a083661
--- /dev/null
+++ b/docs/XMPToolkit/functions.html
@@ -0,0 +1,281 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
+<title>Adobe XMP Toolkit: Class Members</title>
+<link href="doxygen.css" rel="stylesheet" type="text/css">
+<link href="tabs.css" rel="stylesheet" type="text/css">
+</head><body>
+<!-- Generated by Doxygen 1.5.1 -->
+<div class="tabs">
+ <ul>
+ <li><a href="index.html"><span>Main&nbsp;Page</span></a></li>
+ <li><a href="modules.html"><span>Modules</span></a></li>
+ <li id="current"><a href="annotated.html"><span>Classes</span></a></li>
+ <li><a href="files.html"><span>Files</span></a></li>
+ </ul></div>
+<div class="tabs">
+ <ul>
+ <li><a href="annotated.html"><span>Class&nbsp;List</span></a></li>
+ <li id="current"><a href="functions.html"><span>Class&nbsp;Members</span></a></li>
+ </ul></div>
+<div class="tabs">
+ <ul>
+ <li id="current"><a href="functions.html"><span>All</span></a></li>
+ <li><a href="functions_func.html"><span>Functions</span></a></li>
+ </ul>
+</div>
+<div class="tabs">
+ <ul>
+ <li><a href="#index_a"><span>a</span></a></li>
+ <li><a href="#index_c"><span>c</span></a></li>
+ <li><a href="#index_d"><span>d</span></a></li>
+ <li><a href="#index_e"><span>e</span></a></li>
+ <li><a href="#index_g"><span>g</span></a></li>
+ <li><a href="#index_i"><span>i</span></a></li>
+ <li><a href="#index_m"><span>m</span></a></li>
+ <li><a href="#index_n"><span>n</span></a></li>
+ <li><a href="#index_o"><span>o</span></a></li>
+ <li><a href="#index_p"><span>p</span></a></li>
+ <li><a href="#index_r"><span>r</span></a></li>
+ <li><a href="#index_s"><span>s</span></a></li>
+ <li><a href="#index_t"><span>t</span></a></li>
+ <li><a href="#index_~"><span>~</span></a></li>
+ </ul>
+</div>
+
+<p>
+Here is a list of all documented class members with links to the class documentation for each member:
+<p>
+<h3><a class="anchor" name="index_a">- a -</a></h3><ul>
+<li>AppendArrayItem()
+: <a class="el" href="classTXMPMeta.html#00d7314dc970ad390499ce9db27d314a">TXMPMeta&lt; tStringObj &gt;</a>
+<li>AppendProperties()
+: <a class="el" href="classTXMPUtils.html#4795244ffcbda927800f789b0e40c262">TXMPUtils&lt; tStringObj &gt;</a>
+</ul>
+<h3><a class="anchor" name="index_c">- c -</a></h3><ul>
+<li>CanPutXMP()
+: <a class="el" href="classTXMPFiles.html#29a11a1539d6300da3fb4c7e9ea02bb6">TXMPFiles&lt; tStringObj &gt;</a>
+<li>CatenateArrayItems()
+: <a class="el" href="classTXMPUtils.html#d7e1aa7928252fb88a24fb5c3aef22ba">TXMPUtils&lt; tStringObj &gt;</a>
+<li>Clone()
+: <a class="el" href="classTXMPMeta.html#6ca653436995bbb76315efe7934afd4c">TXMPMeta&lt; tStringObj &gt;</a>
+<li>CloseFile()
+: <a class="el" href="classTXMPFiles.html#eca89170c7aa3e2d56e30bff04dd7927">TXMPFiles&lt; tStringObj &gt;</a>
+<li>CompareDateTime()
+: <a class="el" href="classTXMPUtils.html#9fc7f1771032f59f9020aeda4f91991d">TXMPUtils&lt; tStringObj &gt;</a>
+<li>ComposeArrayItemPath()
+: <a class="el" href="classTXMPUtils.html#47fa195aa2e1457aa1f74f7e1ed06da6">TXMPUtils&lt; tStringObj &gt;</a>
+<li>ComposeFieldSelector()
+: <a class="el" href="classTXMPUtils.html#458f8e8729e2334fe54ca8f691a9db23">TXMPUtils&lt; tStringObj &gt;</a>
+<li>ComposeLangSelector()
+: <a class="el" href="classTXMPUtils.html#e4989e5c199a2a4287ee3ae89b872e69">TXMPUtils&lt; tStringObj &gt;</a>
+<li>ComposeQualifierPath()
+: <a class="el" href="classTXMPUtils.html#40ae0ce2065fcb71725e37137884e172">TXMPUtils&lt; tStringObj &gt;</a>
+<li>ComposeStructFieldPath()
+: <a class="el" href="classTXMPUtils.html#706eb85b8401b8682a01348f7e25ee3d">TXMPUtils&lt; tStringObj &gt;</a>
+<li>ConvertFromBool()
+: <a class="el" href="classTXMPUtils.html#509691eb270988de6a770c9c8304ab6b">TXMPUtils&lt; tStringObj &gt;</a>
+<li>ConvertFromDate()
+: <a class="el" href="classTXMPUtils.html#6146a522a3974b4088d6e8241e9cd223">TXMPUtils&lt; tStringObj &gt;</a>
+<li>ConvertFromFloat()
+: <a class="el" href="classTXMPUtils.html#e67ef3931836432b7e574832f0610ed0">TXMPUtils&lt; tStringObj &gt;</a>
+<li>ConvertFromInt()
+: <a class="el" href="classTXMPUtils.html#eec45b4d1a26717290105c9f4e8b4235">TXMPUtils&lt; tStringObj &gt;</a>
+<li>ConvertToBool()
+: <a class="el" href="classTXMPUtils.html#aaaaadb23f4089daa795f50cba4f405c">TXMPUtils&lt; tStringObj &gt;</a>
+<li>ConvertToDate()
+: <a class="el" href="classTXMPUtils.html#60d33e6ce30286028acca47b2b6e7a0b">TXMPUtils&lt; tStringObj &gt;</a>
+<li>ConvertToFloat()
+: <a class="el" href="classTXMPUtils.html#abd4e479d2708a9ea3135cd441faa7ea">TXMPUtils&lt; tStringObj &gt;</a>
+<li>ConvertToInt()
+: <a class="el" href="classTXMPUtils.html#dfd9d1c522377d5db4ad667a7973ba00">TXMPUtils&lt; tStringObj &gt;</a>
+<li>ConvertToInt64()
+: <a class="el" href="classTXMPUtils.html#be5d2dcc03c5442202203bba5ca7b172">TXMPUtils&lt; tStringObj &gt;</a>
+<li>ConvertToLocalTime()
+: <a class="el" href="classTXMPUtils.html#61852aaba494c8fbad5a6c0c4caf21f5">TXMPUtils&lt; tStringObj &gt;</a>
+<li>ConvertToUTCTime()
+: <a class="el" href="classTXMPUtils.html#bbd4d691c83287ea2fc6b1e33e5858b8">TXMPUtils&lt; tStringObj &gt;</a>
+<li>CountArrayItems()
+: <a class="el" href="classTXMPMeta.html#b79aae864b3ce190d0699252f48e0acc">TXMPMeta&lt; tStringObj &gt;</a>
+<li>CurrentDateTime()
+: <a class="el" href="classTXMPUtils.html#c83f0b963ea64d7eee0b481e15a8439c">TXMPUtils&lt; tStringObj &gt;</a>
+</ul>
+<h3><a class="anchor" name="index_d">- d -</a></h3><ul>
+<li>DecodeFromBase64()
+: <a class="el" href="classTXMPUtils.html#e5bdd91c0c3ee9262dc0a8b9f591b921">TXMPUtils&lt; tStringObj &gt;</a>
+<li>DeleteAlias()
+: <a class="el" href="classTXMPMeta.html#af64964e983235247ef65c86a42a4675">TXMPMeta&lt; tStringObj &gt;</a>
+<li>DeleteArrayItem()
+: <a class="el" href="classTXMPMeta.html#bc1211f47225b5973a170ff952743264">TXMPMeta&lt; tStringObj &gt;</a>
+<li>DeleteNamespace()
+: <a class="el" href="classTXMPMeta.html#3f989597e95db929676273cacd4ea09a">TXMPMeta&lt; tStringObj &gt;</a>
+<li>DeleteProperty()
+: <a class="el" href="classTXMPMeta.html#c8b555ba99904fa49bb4851a60cc3844">TXMPMeta&lt; tStringObj &gt;</a>
+<li>DeleteQualifier()
+: <a class="el" href="classTXMPMeta.html#8ce15f7de7fd3b258f07158ab5fa88be">TXMPMeta&lt; tStringObj &gt;</a>
+<li>DeleteStructField()
+: <a class="el" href="classTXMPMeta.html#bc258e027780a15be65a88fcfd4e1fd4">TXMPMeta&lt; tStringObj &gt;</a>
+<li>DoesArrayItemExist()
+: <a class="el" href="classTXMPMeta.html#492465c588d6d4cb8e30f94790e66f58">TXMPMeta&lt; tStringObj &gt;</a>
+<li>DoesPropertyExist()
+: <a class="el" href="classTXMPMeta.html#f22b116d71ecbbebea016ec5337e7066">TXMPMeta&lt; tStringObj &gt;</a>
+<li>DoesQualifierExist()
+: <a class="el" href="classTXMPMeta.html#81347a92becd387a14f4d47c582f129a">TXMPMeta&lt; tStringObj &gt;</a>
+<li>DoesStructFieldExist()
+: <a class="el" href="classTXMPMeta.html#9261b80d62e77a10ff1a89843bfa10a5">TXMPMeta&lt; tStringObj &gt;</a>
+<li>DumpAliases()
+: <a class="el" href="classTXMPMeta.html#afb027f200b85467298d237a0c23949b">TXMPMeta&lt; tStringObj &gt;</a>
+<li>DumpNamespaces()
+: <a class="el" href="classTXMPMeta.html#44250140a710c0b7c5cc0881e387d004">TXMPMeta&lt; tStringObj &gt;</a>
+<li>DumpObject()
+: <a class="el" href="classTXMPMeta.html#976c1eb889f44080f76628805712b618">TXMPMeta&lt; tStringObj &gt;</a>
+<li>DuplicateSubtree()
+: <a class="el" href="classTXMPUtils.html#a17838f062e5414bc0929f67ac94a3aa">TXMPUtils&lt; tStringObj &gt;</a>
+</ul>
+<h3><a class="anchor" name="index_e">- e -</a></h3><ul>
+<li>EncodeToBase64()
+: <a class="el" href="classTXMPUtils.html#ef3b23bbc152480f699e269620ecad4a">TXMPUtils&lt; tStringObj &gt;</a>
+</ul>
+<h3><a class="anchor" name="index_g">- g -</a></h3><ul>
+<li>GetArrayItem()
+: <a class="el" href="classTXMPMeta.html#c64a4251d157937f69b73f2ffac4f7cc">TXMPMeta&lt; tStringObj &gt;</a>
+<li>GetFileInfo()
+: <a class="el" href="classTXMPFiles.html#f9931d081cb19f98c81e41786030765b">TXMPFiles&lt; tStringObj &gt;</a>
+<li>GetFormatInfo()
+: <a class="el" href="classTXMPFiles.html#6ac78e3c7286ca8dcb41eaa007aa00e8">TXMPFiles&lt; tStringObj &gt;</a>
+<li>GetGlobalOptions()
+: <a class="el" href="classTXMPMeta.html#12b2435ba039c62a164951948c016eb4">TXMPMeta&lt; tStringObj &gt;</a>
+<li>GetInternalRef()
+: <a class="el" href="classTXMPMeta.html#4d35b44f1f017a27772ee902a3dacf04">TXMPMeta&lt; tStringObj &gt;</a>
+<li>GetLocalizedText()
+: <a class="el" href="classTXMPMeta.html#eefe49bbf669770d769f4fe0ea566bd0">TXMPMeta&lt; tStringObj &gt;</a>
+<li>GetNamespacePrefix()
+: <a class="el" href="classTXMPMeta.html#f28589472d8c0397db6cef868f2b8c97">TXMPMeta&lt; tStringObj &gt;</a>
+<li>GetNamespaceURI()
+: <a class="el" href="classTXMPMeta.html#a20c84e7549d0a3252fa29a1e83a757a">TXMPMeta&lt; tStringObj &gt;</a>
+<li>GetObjectName()
+: <a class="el" href="classTXMPMeta.html#b0d179ed95487d4fd4f2680c1fbe0d40">TXMPMeta&lt; tStringObj &gt;</a>
+<li>GetObjectOptions()
+: <a class="el" href="classTXMPMeta.html#39aeaf9eb83cfc1c5455807b95f055f9">TXMPMeta&lt; tStringObj &gt;</a>
+<li>GetProperty()
+: <a class="el" href="classTXMPMeta.html#06a3241c7fa5df87f61dff02fca23a0c">TXMPMeta&lt; tStringObj &gt;</a>
+<li>GetProperty_Bool()
+: <a class="el" href="classTXMPMeta.html#dcf8a1959a8bd42641a42cbd4d64a5b7">TXMPMeta&lt; tStringObj &gt;</a>
+<li>GetProperty_Date()
+: <a class="el" href="classTXMPMeta.html#2f561295e73047ee90765558d29bd650">TXMPMeta&lt; tStringObj &gt;</a>
+<li>GetProperty_Float()
+: <a class="el" href="classTXMPMeta.html#7708c31c9af3e740b27a4893dcd9aa47">TXMPMeta&lt; tStringObj &gt;</a>
+<li>GetProperty_Int()
+: <a class="el" href="classTXMPMeta.html#3b6ba486c02607b544917091c43b05cc">TXMPMeta&lt; tStringObj &gt;</a>
+<li>GetProperty_Int64()
+: <a class="el" href="classTXMPMeta.html#d1a6629b0466981b67d31c9dc3840ea7">TXMPMeta&lt; tStringObj &gt;</a>
+<li>GetQualifier()
+: <a class="el" href="classTXMPMeta.html#2cc58d8316043b035643e7c21633bc13">TXMPMeta&lt; tStringObj &gt;</a>
+<li>GetStructField()
+: <a class="el" href="classTXMPMeta.html#e99d2bc414d5cd68851147aef6710d4a">TXMPMeta&lt; tStringObj &gt;</a>
+<li>GetThumbnail()
+: <a class="el" href="classTXMPFiles.html#4ea1eda39f803322e10b2a554ef8ab06">TXMPFiles&lt; tStringObj &gt;</a>
+<li>GetVersionInfo()
+: <a class="el" href="classTXMPMeta.html#5415cfc01a9cb8786939246571a23a9d">TXMPMeta&lt; tStringObj &gt;</a>
+<li>GetXMP()
+: <a class="el" href="classTXMPFiles.html#42ca0bbc5ac66a8de1710e03a7ff17b3">TXMPFiles&lt; tStringObj &gt;</a>
+</ul>
+<h3><a class="anchor" name="index_i">- i -</a></h3><ul>
+<li>Initialize()
+: <a class="el" href="classTXMPFiles.html#0874bbbf41c9490abfb613bfe297327d">TXMPFiles&lt; tStringObj &gt;</a>
+, <a class="el" href="classTXMPMeta.html#bfddf1df0e01ab33d5636a80edc973ca">TXMPMeta&lt; tStringObj &gt;</a>
+</ul>
+<h3><a class="anchor" name="index_m">- m -</a></h3><ul>
+<li>MergeFromJPEG()
+: <a class="el" href="classTXMPUtils.html#6187cd5fef0eccecac6805d4114dcd2e">TXMPUtils&lt; tStringObj &gt;</a>
+</ul>
+<h3><a class="anchor" name="index_n">- n -</a></h3><ul>
+<li>Next()
+: <a class="el" href="classTXMPIterator.html#124a1dd1ab3ff0d236e4d4b967dafcd9">TXMPIterator&lt; tStringObj &gt;</a>
+</ul>
+<h3><a class="anchor" name="index_o">- o -</a></h3><ul>
+<li>OpenFile()
+: <a class="el" href="classTXMPFiles.html#fcd21cfe5d6f13c648c5541e161919cb">TXMPFiles&lt; tStringObj &gt;</a>
+<li>operator=()
+: <a class="el" href="classTXMPMeta.html#4d5a601c9b77f6f6ab5f14e658de58ef">TXMPMeta&lt; tStringObj &gt;</a>
+, <a class="el" href="classTXMPIterator.html#d767d731320d3f4c997c6ce9f7f8fa63">TXMPIterator&lt; tStringObj &gt;</a>
+</ul>
+<h3><a class="anchor" name="index_p">- p -</a></h3><ul>
+<li>PackageForJPEG()
+: <a class="el" href="classTXMPUtils.html#6001b4ff54c60fdf0c40e6b78a5c457a">TXMPUtils&lt; tStringObj &gt;</a>
+<li>ParseFromBuffer()
+: <a class="el" href="classTXMPMeta.html#7b383f5b357fff040cdbde82f4f43f26">TXMPMeta&lt; tStringObj &gt;</a>
+<li>PutXMP()
+: <a class="el" href="classTXMPFiles.html#d3f7babdc07c7de0d0cd9a3362b4710a">TXMPFiles&lt; tStringObj &gt;</a>
+</ul>
+<h3><a class="anchor" name="index_r">- r -</a></h3><ul>
+<li>RegisterAlias()
+: <a class="el" href="classTXMPMeta.html#b9463c7459125ca0038db2e586c5e4df">TXMPMeta&lt; tStringObj &gt;</a>
+<li>RegisterNamespace()
+: <a class="el" href="classTXMPMeta.html#4c69d31a37ff24c85679229c479aa1ac">TXMPMeta&lt; tStringObj &gt;</a>
+<li>RegisterStandardAliases()
+: <a class="el" href="classTXMPMeta.html#b77cf73fa0cc63d845f113b3d1c83602">TXMPMeta&lt; tStringObj &gt;</a>
+<li>RemoveProperties()
+: <a class="el" href="classTXMPUtils.html#40c645803530662e08d042b4b7c6190d">TXMPUtils&lt; tStringObj &gt;</a>
+<li>ResolveAlias()
+: <a class="el" href="classTXMPMeta.html#c4b9c75202f2b961ad92f10a9e504e9a">TXMPMeta&lt; tStringObj &gt;</a>
+</ul>
+<h3><a class="anchor" name="index_s">- s -</a></h3><ul>
+<li>SeparateArrayItems()
+: <a class="el" href="classTXMPUtils.html#66c5ddee47aa36ed906353f94ca18d2e">TXMPUtils&lt; tStringObj &gt;</a>
+<li>SerializeToBuffer()
+: <a class="el" href="classTXMPMeta.html#34143727d979b47a2f2209367aec9a1c">TXMPMeta&lt; tStringObj &gt;</a>
+<li>SetAbortProc()
+: <a class="el" href="classTXMPFiles.html#7b86c130fdbd54b5ac158ec3fee93777">TXMPFiles&lt; tStringObj &gt;</a>
+<li>SetArrayItem()
+: <a class="el" href="classTXMPMeta.html#1570eb89d613b4a94ca572e4644168cc">TXMPMeta&lt; tStringObj &gt;</a>
+<li>SetGlobalOptions()
+: <a class="el" href="classTXMPMeta.html#e7bb38d9b3857b08106630a386b47332">TXMPMeta&lt; tStringObj &gt;</a>
+<li>SetLocalizedText()
+: <a class="el" href="classTXMPMeta.html#f9531b949a462f5663b1f3fd99464c19">TXMPMeta&lt; tStringObj &gt;</a>
+<li>SetObjectName()
+: <a class="el" href="classTXMPMeta.html#fd059cc7cd9f906e12dab04e380e495c">TXMPMeta&lt; tStringObj &gt;</a>
+<li>SetObjectOptions()
+: <a class="el" href="classTXMPMeta.html#92055b3ae18dfd5e5491108f59318f17">TXMPMeta&lt; tStringObj &gt;</a>
+<li>SetProperty()
+: <a class="el" href="classTXMPMeta.html#1dfd6a08ebfd1a6364b3a7b6584bcc28">TXMPMeta&lt; tStringObj &gt;</a>
+<li>SetProperty_Bool()
+: <a class="el" href="classTXMPMeta.html#9521e3838272ec501ffdb60ff3eb482f">TXMPMeta&lt; tStringObj &gt;</a>
+<li>SetProperty_Date()
+: <a class="el" href="classTXMPMeta.html#eee10669445f77139d5634199ff01079">TXMPMeta&lt; tStringObj &gt;</a>
+<li>SetProperty_Float()
+: <a class="el" href="classTXMPMeta.html#3b0f2f6bae57931ea96775f03608c0ed">TXMPMeta&lt; tStringObj &gt;</a>
+<li>SetProperty_Int()
+: <a class="el" href="classTXMPMeta.html#b8ae94130d9a05c1b9a3ee25588b6421">TXMPMeta&lt; tStringObj &gt;</a>
+<li>SetProperty_Int64()
+: <a class="el" href="classTXMPMeta.html#df919aff205e934e4c8250a067f7b377">TXMPMeta&lt; tStringObj &gt;</a>
+<li>SetQualifier()
+: <a class="el" href="classTXMPMeta.html#c395e094cab251a0593d508594b21521">TXMPMeta&lt; tStringObj &gt;</a>
+<li>SetStructField()
+: <a class="el" href="classTXMPMeta.html#0e44c30e7527064909e5f7035d53c4f5">TXMPMeta&lt; tStringObj &gt;</a>
+<li>SetTimeZone()
+: <a class="el" href="classTXMPUtils.html#96bcc45febac55f6c49951815b7de2ef">TXMPUtils&lt; tStringObj &gt;</a>
+<li>Skip()
+: <a class="el" href="classTXMPIterator.html#30b4d78974b347e4fcd275f1f65a61b2">TXMPIterator&lt; tStringObj &gt;</a>
+</ul>
+<h3><a class="anchor" name="index_t">- t -</a></h3><ul>
+<li>Terminate()
+: <a class="el" href="classTXMPFiles.html#1e8de80c252b60b332dc4bc524139fd8">TXMPFiles&lt; tStringObj &gt;</a>
+, <a class="el" href="classTXMPMeta.html#6c30fae26173167958b6f0da95a53865">TXMPMeta&lt; tStringObj &gt;</a>
+<li>TXMPFiles()
+: <a class="el" href="classTXMPFiles.html#14f01e38454178578fd25fff6024fd54">TXMPFiles&lt; tStringObj &gt;</a>
+<li>TXMPIterator()
+: <a class="el" href="classTXMPIterator.html#6b2b7a3d6359aec216adf32bdf7fb140">TXMPIterator&lt; tStringObj &gt;</a>
+<li>TXMPMeta()
+: <a class="el" href="classTXMPMeta.html#21a4d06fc2e77b28991bb900f0f48e50">TXMPMeta&lt; tStringObj &gt;</a>
+</ul>
+<h3><a class="anchor" name="index_~">- ~ -</a></h3><ul>
+<li>~TXMPIterator()
+: <a class="el" href="classTXMPIterator.html#911554533e8a3f09ab8870bd54462196">TXMPIterator&lt; tStringObj &gt;</a>
+<li>~TXMPMeta()
+: <a class="el" href="classTXMPMeta.html#bab5013870cd47eb0d9d701653735a02">TXMPMeta&lt; tStringObj &gt;</a>
+</ul>
+<hr size="1"><address style="align: right;"><small>Generated on Thu May 3 14:54:58 2007 for Adobe XMP Toolkit by&nbsp;
+<a href="http://www.doxygen.org/index.html">
+<img src="doxygen.png" alt="doxygen" align="middle" border="0"></a> 1.5.1 </small></address>
+</body>
+</html>
diff --git a/docs/XMPToolkit/functions_func.html b/docs/XMPToolkit/functions_func.html
new file mode 100644
index 0000000..8ae4376
--- /dev/null
+++ b/docs/XMPToolkit/functions_func.html
@@ -0,0 +1,281 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
+<title>Adobe XMP Toolkit: Class Members - Functions</title>
+<link href="doxygen.css" rel="stylesheet" type="text/css">
+<link href="tabs.css" rel="stylesheet" type="text/css">
+</head><body>
+<!-- Generated by Doxygen 1.5.1 -->
+<div class="tabs">
+ <ul>
+ <li><a href="index.html"><span>Main&nbsp;Page</span></a></li>
+ <li><a href="modules.html"><span>Modules</span></a></li>
+ <li id="current"><a href="annotated.html"><span>Classes</span></a></li>
+ <li><a href="files.html"><span>Files</span></a></li>
+ </ul></div>
+<div class="tabs">
+ <ul>
+ <li><a href="annotated.html"><span>Class&nbsp;List</span></a></li>
+ <li id="current"><a href="functions.html"><span>Class&nbsp;Members</span></a></li>
+ </ul></div>
+<div class="tabs">
+ <ul>
+ <li><a href="functions.html"><span>All</span></a></li>
+ <li id="current"><a href="functions_func.html"><span>Functions</span></a></li>
+ </ul>
+</div>
+<div class="tabs">
+ <ul>
+ <li><a href="#index_a"><span>a</span></a></li>
+ <li><a href="#index_c"><span>c</span></a></li>
+ <li><a href="#index_d"><span>d</span></a></li>
+ <li><a href="#index_e"><span>e</span></a></li>
+ <li><a href="#index_g"><span>g</span></a></li>
+ <li><a href="#index_i"><span>i</span></a></li>
+ <li><a href="#index_m"><span>m</span></a></li>
+ <li><a href="#index_n"><span>n</span></a></li>
+ <li><a href="#index_o"><span>o</span></a></li>
+ <li><a href="#index_p"><span>p</span></a></li>
+ <li><a href="#index_r"><span>r</span></a></li>
+ <li><a href="#index_s"><span>s</span></a></li>
+ <li><a href="#index_t"><span>t</span></a></li>
+ <li><a href="#index_~"><span>~</span></a></li>
+ </ul>
+</div>
+
+<p>
+&nbsp;
+<p>
+<h3><a class="anchor" name="index_a">- a -</a></h3><ul>
+<li>AppendArrayItem()
+: <a class="el" href="classTXMPMeta.html#00d7314dc970ad390499ce9db27d314a">TXMPMeta&lt; tStringObj &gt;</a>
+<li>AppendProperties()
+: <a class="el" href="classTXMPUtils.html#4795244ffcbda927800f789b0e40c262">TXMPUtils&lt; tStringObj &gt;</a>
+</ul>
+<h3><a class="anchor" name="index_c">- c -</a></h3><ul>
+<li>CanPutXMP()
+: <a class="el" href="classTXMPFiles.html#29a11a1539d6300da3fb4c7e9ea02bb6">TXMPFiles&lt; tStringObj &gt;</a>
+<li>CatenateArrayItems()
+: <a class="el" href="classTXMPUtils.html#d7e1aa7928252fb88a24fb5c3aef22ba">TXMPUtils&lt; tStringObj &gt;</a>
+<li>Clone()
+: <a class="el" href="classTXMPMeta.html#6ca653436995bbb76315efe7934afd4c">TXMPMeta&lt; tStringObj &gt;</a>
+<li>CloseFile()
+: <a class="el" href="classTXMPFiles.html#eca89170c7aa3e2d56e30bff04dd7927">TXMPFiles&lt; tStringObj &gt;</a>
+<li>CompareDateTime()
+: <a class="el" href="classTXMPUtils.html#9fc7f1771032f59f9020aeda4f91991d">TXMPUtils&lt; tStringObj &gt;</a>
+<li>ComposeArrayItemPath()
+: <a class="el" href="classTXMPUtils.html#47fa195aa2e1457aa1f74f7e1ed06da6">TXMPUtils&lt; tStringObj &gt;</a>
+<li>ComposeFieldSelector()
+: <a class="el" href="classTXMPUtils.html#458f8e8729e2334fe54ca8f691a9db23">TXMPUtils&lt; tStringObj &gt;</a>
+<li>ComposeLangSelector()
+: <a class="el" href="classTXMPUtils.html#e4989e5c199a2a4287ee3ae89b872e69">TXMPUtils&lt; tStringObj &gt;</a>
+<li>ComposeQualifierPath()
+: <a class="el" href="classTXMPUtils.html#40ae0ce2065fcb71725e37137884e172">TXMPUtils&lt; tStringObj &gt;</a>
+<li>ComposeStructFieldPath()
+: <a class="el" href="classTXMPUtils.html#706eb85b8401b8682a01348f7e25ee3d">TXMPUtils&lt; tStringObj &gt;</a>
+<li>ConvertFromBool()
+: <a class="el" href="classTXMPUtils.html#509691eb270988de6a770c9c8304ab6b">TXMPUtils&lt; tStringObj &gt;</a>
+<li>ConvertFromDate()
+: <a class="el" href="classTXMPUtils.html#6146a522a3974b4088d6e8241e9cd223">TXMPUtils&lt; tStringObj &gt;</a>
+<li>ConvertFromFloat()
+: <a class="el" href="classTXMPUtils.html#e67ef3931836432b7e574832f0610ed0">TXMPUtils&lt; tStringObj &gt;</a>
+<li>ConvertFromInt()
+: <a class="el" href="classTXMPUtils.html#eec45b4d1a26717290105c9f4e8b4235">TXMPUtils&lt; tStringObj &gt;</a>
+<li>ConvertToBool()
+: <a class="el" href="classTXMPUtils.html#aaaaadb23f4089daa795f50cba4f405c">TXMPUtils&lt; tStringObj &gt;</a>
+<li>ConvertToDate()
+: <a class="el" href="classTXMPUtils.html#60d33e6ce30286028acca47b2b6e7a0b">TXMPUtils&lt; tStringObj &gt;</a>
+<li>ConvertToFloat()
+: <a class="el" href="classTXMPUtils.html#abd4e479d2708a9ea3135cd441faa7ea">TXMPUtils&lt; tStringObj &gt;</a>
+<li>ConvertToInt()
+: <a class="el" href="classTXMPUtils.html#dfd9d1c522377d5db4ad667a7973ba00">TXMPUtils&lt; tStringObj &gt;</a>
+<li>ConvertToInt64()
+: <a class="el" href="classTXMPUtils.html#be5d2dcc03c5442202203bba5ca7b172">TXMPUtils&lt; tStringObj &gt;</a>
+<li>ConvertToLocalTime()
+: <a class="el" href="classTXMPUtils.html#61852aaba494c8fbad5a6c0c4caf21f5">TXMPUtils&lt; tStringObj &gt;</a>
+<li>ConvertToUTCTime()
+: <a class="el" href="classTXMPUtils.html#bbd4d691c83287ea2fc6b1e33e5858b8">TXMPUtils&lt; tStringObj &gt;</a>
+<li>CountArrayItems()
+: <a class="el" href="classTXMPMeta.html#b79aae864b3ce190d0699252f48e0acc">TXMPMeta&lt; tStringObj &gt;</a>
+<li>CurrentDateTime()
+: <a class="el" href="classTXMPUtils.html#c83f0b963ea64d7eee0b481e15a8439c">TXMPUtils&lt; tStringObj &gt;</a>
+</ul>
+<h3><a class="anchor" name="index_d">- d -</a></h3><ul>
+<li>DecodeFromBase64()
+: <a class="el" href="classTXMPUtils.html#e5bdd91c0c3ee9262dc0a8b9f591b921">TXMPUtils&lt; tStringObj &gt;</a>
+<li>DeleteAlias()
+: <a class="el" href="classTXMPMeta.html#af64964e983235247ef65c86a42a4675">TXMPMeta&lt; tStringObj &gt;</a>
+<li>DeleteArrayItem()
+: <a class="el" href="classTXMPMeta.html#bc1211f47225b5973a170ff952743264">TXMPMeta&lt; tStringObj &gt;</a>
+<li>DeleteNamespace()
+: <a class="el" href="classTXMPMeta.html#3f989597e95db929676273cacd4ea09a">TXMPMeta&lt; tStringObj &gt;</a>
+<li>DeleteProperty()
+: <a class="el" href="classTXMPMeta.html#c8b555ba99904fa49bb4851a60cc3844">TXMPMeta&lt; tStringObj &gt;</a>
+<li>DeleteQualifier()
+: <a class="el" href="classTXMPMeta.html#8ce15f7de7fd3b258f07158ab5fa88be">TXMPMeta&lt; tStringObj &gt;</a>
+<li>DeleteStructField()
+: <a class="el" href="classTXMPMeta.html#bc258e027780a15be65a88fcfd4e1fd4">TXMPMeta&lt; tStringObj &gt;</a>
+<li>DoesArrayItemExist()
+: <a class="el" href="classTXMPMeta.html#492465c588d6d4cb8e30f94790e66f58">TXMPMeta&lt; tStringObj &gt;</a>
+<li>DoesPropertyExist()
+: <a class="el" href="classTXMPMeta.html#f22b116d71ecbbebea016ec5337e7066">TXMPMeta&lt; tStringObj &gt;</a>
+<li>DoesQualifierExist()
+: <a class="el" href="classTXMPMeta.html#81347a92becd387a14f4d47c582f129a">TXMPMeta&lt; tStringObj &gt;</a>
+<li>DoesStructFieldExist()
+: <a class="el" href="classTXMPMeta.html#9261b80d62e77a10ff1a89843bfa10a5">TXMPMeta&lt; tStringObj &gt;</a>
+<li>DumpAliases()
+: <a class="el" href="classTXMPMeta.html#afb027f200b85467298d237a0c23949b">TXMPMeta&lt; tStringObj &gt;</a>
+<li>DumpNamespaces()
+: <a class="el" href="classTXMPMeta.html#44250140a710c0b7c5cc0881e387d004">TXMPMeta&lt; tStringObj &gt;</a>
+<li>DumpObject()
+: <a class="el" href="classTXMPMeta.html#976c1eb889f44080f76628805712b618">TXMPMeta&lt; tStringObj &gt;</a>
+<li>DuplicateSubtree()
+: <a class="el" href="classTXMPUtils.html#a17838f062e5414bc0929f67ac94a3aa">TXMPUtils&lt; tStringObj &gt;</a>
+</ul>
+<h3><a class="anchor" name="index_e">- e -</a></h3><ul>
+<li>EncodeToBase64()
+: <a class="el" href="classTXMPUtils.html#ef3b23bbc152480f699e269620ecad4a">TXMPUtils&lt; tStringObj &gt;</a>
+</ul>
+<h3><a class="anchor" name="index_g">- g -</a></h3><ul>
+<li>GetArrayItem()
+: <a class="el" href="classTXMPMeta.html#c64a4251d157937f69b73f2ffac4f7cc">TXMPMeta&lt; tStringObj &gt;</a>
+<li>GetFileInfo()
+: <a class="el" href="classTXMPFiles.html#f9931d081cb19f98c81e41786030765b">TXMPFiles&lt; tStringObj &gt;</a>
+<li>GetFormatInfo()
+: <a class="el" href="classTXMPFiles.html#6ac78e3c7286ca8dcb41eaa007aa00e8">TXMPFiles&lt; tStringObj &gt;</a>
+<li>GetGlobalOptions()
+: <a class="el" href="classTXMPMeta.html#12b2435ba039c62a164951948c016eb4">TXMPMeta&lt; tStringObj &gt;</a>
+<li>GetInternalRef()
+: <a class="el" href="classTXMPMeta.html#4d35b44f1f017a27772ee902a3dacf04">TXMPMeta&lt; tStringObj &gt;</a>
+<li>GetLocalizedText()
+: <a class="el" href="classTXMPMeta.html#eefe49bbf669770d769f4fe0ea566bd0">TXMPMeta&lt; tStringObj &gt;</a>
+<li>GetNamespacePrefix()
+: <a class="el" href="classTXMPMeta.html#f28589472d8c0397db6cef868f2b8c97">TXMPMeta&lt; tStringObj &gt;</a>
+<li>GetNamespaceURI()
+: <a class="el" href="classTXMPMeta.html#a20c84e7549d0a3252fa29a1e83a757a">TXMPMeta&lt; tStringObj &gt;</a>
+<li>GetObjectName()
+: <a class="el" href="classTXMPMeta.html#b0d179ed95487d4fd4f2680c1fbe0d40">TXMPMeta&lt; tStringObj &gt;</a>
+<li>GetObjectOptions()
+: <a class="el" href="classTXMPMeta.html#39aeaf9eb83cfc1c5455807b95f055f9">TXMPMeta&lt; tStringObj &gt;</a>
+<li>GetProperty()
+: <a class="el" href="classTXMPMeta.html#06a3241c7fa5df87f61dff02fca23a0c">TXMPMeta&lt; tStringObj &gt;</a>
+<li>GetProperty_Bool()
+: <a class="el" href="classTXMPMeta.html#dcf8a1959a8bd42641a42cbd4d64a5b7">TXMPMeta&lt; tStringObj &gt;</a>
+<li>GetProperty_Date()
+: <a class="el" href="classTXMPMeta.html#2f561295e73047ee90765558d29bd650">TXMPMeta&lt; tStringObj &gt;</a>
+<li>GetProperty_Float()
+: <a class="el" href="classTXMPMeta.html#7708c31c9af3e740b27a4893dcd9aa47">TXMPMeta&lt; tStringObj &gt;</a>
+<li>GetProperty_Int()
+: <a class="el" href="classTXMPMeta.html#3b6ba486c02607b544917091c43b05cc">TXMPMeta&lt; tStringObj &gt;</a>
+<li>GetProperty_Int64()
+: <a class="el" href="classTXMPMeta.html#d1a6629b0466981b67d31c9dc3840ea7">TXMPMeta&lt; tStringObj &gt;</a>
+<li>GetQualifier()
+: <a class="el" href="classTXMPMeta.html#2cc58d8316043b035643e7c21633bc13">TXMPMeta&lt; tStringObj &gt;</a>
+<li>GetStructField()
+: <a class="el" href="classTXMPMeta.html#e99d2bc414d5cd68851147aef6710d4a">TXMPMeta&lt; tStringObj &gt;</a>
+<li>GetThumbnail()
+: <a class="el" href="classTXMPFiles.html#4ea1eda39f803322e10b2a554ef8ab06">TXMPFiles&lt; tStringObj &gt;</a>
+<li>GetVersionInfo()
+: <a class="el" href="classTXMPMeta.html#5415cfc01a9cb8786939246571a23a9d">TXMPMeta&lt; tStringObj &gt;</a>
+<li>GetXMP()
+: <a class="el" href="classTXMPFiles.html#42ca0bbc5ac66a8de1710e03a7ff17b3">TXMPFiles&lt; tStringObj &gt;</a>
+</ul>
+<h3><a class="anchor" name="index_i">- i -</a></h3><ul>
+<li>Initialize()
+: <a class="el" href="classTXMPFiles.html#0874bbbf41c9490abfb613bfe297327d">TXMPFiles&lt; tStringObj &gt;</a>
+, <a class="el" href="classTXMPMeta.html#bfddf1df0e01ab33d5636a80edc973ca">TXMPMeta&lt; tStringObj &gt;</a>
+</ul>
+<h3><a class="anchor" name="index_m">- m -</a></h3><ul>
+<li>MergeFromJPEG()
+: <a class="el" href="classTXMPUtils.html#6187cd5fef0eccecac6805d4114dcd2e">TXMPUtils&lt; tStringObj &gt;</a>
+</ul>
+<h3><a class="anchor" name="index_n">- n -</a></h3><ul>
+<li>Next()
+: <a class="el" href="classTXMPIterator.html#124a1dd1ab3ff0d236e4d4b967dafcd9">TXMPIterator&lt; tStringObj &gt;</a>
+</ul>
+<h3><a class="anchor" name="index_o">- o -</a></h3><ul>
+<li>OpenFile()
+: <a class="el" href="classTXMPFiles.html#fcd21cfe5d6f13c648c5541e161919cb">TXMPFiles&lt; tStringObj &gt;</a>
+<li>operator=()
+: <a class="el" href="classTXMPMeta.html#4d5a601c9b77f6f6ab5f14e658de58ef">TXMPMeta&lt; tStringObj &gt;</a>
+, <a class="el" href="classTXMPIterator.html#d767d731320d3f4c997c6ce9f7f8fa63">TXMPIterator&lt; tStringObj &gt;</a>
+</ul>
+<h3><a class="anchor" name="index_p">- p -</a></h3><ul>
+<li>PackageForJPEG()
+: <a class="el" href="classTXMPUtils.html#6001b4ff54c60fdf0c40e6b78a5c457a">TXMPUtils&lt; tStringObj &gt;</a>
+<li>ParseFromBuffer()
+: <a class="el" href="classTXMPMeta.html#7b383f5b357fff040cdbde82f4f43f26">TXMPMeta&lt; tStringObj &gt;</a>
+<li>PutXMP()
+: <a class="el" href="classTXMPFiles.html#d3f7babdc07c7de0d0cd9a3362b4710a">TXMPFiles&lt; tStringObj &gt;</a>
+</ul>
+<h3><a class="anchor" name="index_r">- r -</a></h3><ul>
+<li>RegisterAlias()
+: <a class="el" href="classTXMPMeta.html#b9463c7459125ca0038db2e586c5e4df">TXMPMeta&lt; tStringObj &gt;</a>
+<li>RegisterNamespace()
+: <a class="el" href="classTXMPMeta.html#4c69d31a37ff24c85679229c479aa1ac">TXMPMeta&lt; tStringObj &gt;</a>
+<li>RegisterStandardAliases()
+: <a class="el" href="classTXMPMeta.html#b77cf73fa0cc63d845f113b3d1c83602">TXMPMeta&lt; tStringObj &gt;</a>
+<li>RemoveProperties()
+: <a class="el" href="classTXMPUtils.html#40c645803530662e08d042b4b7c6190d">TXMPUtils&lt; tStringObj &gt;</a>
+<li>ResolveAlias()
+: <a class="el" href="classTXMPMeta.html#c4b9c75202f2b961ad92f10a9e504e9a">TXMPMeta&lt; tStringObj &gt;</a>
+</ul>
+<h3><a class="anchor" name="index_s">- s -</a></h3><ul>
+<li>SeparateArrayItems()
+: <a class="el" href="classTXMPUtils.html#66c5ddee47aa36ed906353f94ca18d2e">TXMPUtils&lt; tStringObj &gt;</a>
+<li>SerializeToBuffer()
+: <a class="el" href="classTXMPMeta.html#34143727d979b47a2f2209367aec9a1c">TXMPMeta&lt; tStringObj &gt;</a>
+<li>SetAbortProc()
+: <a class="el" href="classTXMPFiles.html#7b86c130fdbd54b5ac158ec3fee93777">TXMPFiles&lt; tStringObj &gt;</a>
+<li>SetArrayItem()
+: <a class="el" href="classTXMPMeta.html#1570eb89d613b4a94ca572e4644168cc">TXMPMeta&lt; tStringObj &gt;</a>
+<li>SetGlobalOptions()
+: <a class="el" href="classTXMPMeta.html#e7bb38d9b3857b08106630a386b47332">TXMPMeta&lt; tStringObj &gt;</a>
+<li>SetLocalizedText()
+: <a class="el" href="classTXMPMeta.html#f9531b949a462f5663b1f3fd99464c19">TXMPMeta&lt; tStringObj &gt;</a>
+<li>SetObjectName()
+: <a class="el" href="classTXMPMeta.html#fd059cc7cd9f906e12dab04e380e495c">TXMPMeta&lt; tStringObj &gt;</a>
+<li>SetObjectOptions()
+: <a class="el" href="classTXMPMeta.html#92055b3ae18dfd5e5491108f59318f17">TXMPMeta&lt; tStringObj &gt;</a>
+<li>SetProperty()
+: <a class="el" href="classTXMPMeta.html#1dfd6a08ebfd1a6364b3a7b6584bcc28">TXMPMeta&lt; tStringObj &gt;</a>
+<li>SetProperty_Bool()
+: <a class="el" href="classTXMPMeta.html#9521e3838272ec501ffdb60ff3eb482f">TXMPMeta&lt; tStringObj &gt;</a>
+<li>SetProperty_Date()
+: <a class="el" href="classTXMPMeta.html#eee10669445f77139d5634199ff01079">TXMPMeta&lt; tStringObj &gt;</a>
+<li>SetProperty_Float()
+: <a class="el" href="classTXMPMeta.html#3b0f2f6bae57931ea96775f03608c0ed">TXMPMeta&lt; tStringObj &gt;</a>
+<li>SetProperty_Int()
+: <a class="el" href="classTXMPMeta.html#b8ae94130d9a05c1b9a3ee25588b6421">TXMPMeta&lt; tStringObj &gt;</a>
+<li>SetProperty_Int64()
+: <a class="el" href="classTXMPMeta.html#df919aff205e934e4c8250a067f7b377">TXMPMeta&lt; tStringObj &gt;</a>
+<li>SetQualifier()
+: <a class="el" href="classTXMPMeta.html#c395e094cab251a0593d508594b21521">TXMPMeta&lt; tStringObj &gt;</a>
+<li>SetStructField()
+: <a class="el" href="classTXMPMeta.html#0e44c30e7527064909e5f7035d53c4f5">TXMPMeta&lt; tStringObj &gt;</a>
+<li>SetTimeZone()
+: <a class="el" href="classTXMPUtils.html#96bcc45febac55f6c49951815b7de2ef">TXMPUtils&lt; tStringObj &gt;</a>
+<li>Skip()
+: <a class="el" href="classTXMPIterator.html#30b4d78974b347e4fcd275f1f65a61b2">TXMPIterator&lt; tStringObj &gt;</a>
+</ul>
+<h3><a class="anchor" name="index_t">- t -</a></h3><ul>
+<li>Terminate()
+: <a class="el" href="classTXMPFiles.html#1e8de80c252b60b332dc4bc524139fd8">TXMPFiles&lt; tStringObj &gt;</a>
+, <a class="el" href="classTXMPMeta.html#6c30fae26173167958b6f0da95a53865">TXMPMeta&lt; tStringObj &gt;</a>
+<li>TXMPFiles()
+: <a class="el" href="classTXMPFiles.html#14f01e38454178578fd25fff6024fd54">TXMPFiles&lt; tStringObj &gt;</a>
+<li>TXMPIterator()
+: <a class="el" href="classTXMPIterator.html#6b2b7a3d6359aec216adf32bdf7fb140">TXMPIterator&lt; tStringObj &gt;</a>
+<li>TXMPMeta()
+: <a class="el" href="classTXMPMeta.html#21a4d06fc2e77b28991bb900f0f48e50">TXMPMeta&lt; tStringObj &gt;</a>
+</ul>
+<h3><a class="anchor" name="index_~">- ~ -</a></h3><ul>
+<li>~TXMPIterator()
+: <a class="el" href="classTXMPIterator.html#911554533e8a3f09ab8870bd54462196">TXMPIterator&lt; tStringObj &gt;</a>
+<li>~TXMPMeta()
+: <a class="el" href="classTXMPMeta.html#bab5013870cd47eb0d9d701653735a02">TXMPMeta&lt; tStringObj &gt;</a>
+</ul>
+<hr size="1"><address style="align: right;"><small>Generated on Thu May 3 14:54:58 2007 for Adobe XMP Toolkit by&nbsp;
+<a href="http://www.doxygen.org/index.html">
+<img src="doxygen.png" alt="doxygen" align="middle" border="0"></a> 1.5.1 </small></address>
+</body>
+</html>
diff --git a/docs/XMPToolkit/graph_legend.dot b/docs/XMPToolkit/graph_legend.dot
new file mode 100644
index 0000000..4a1a09c
--- /dev/null
+++ b/docs/XMPToolkit/graph_legend.dot
@@ -0,0 +1,22 @@
+digraph G
+{
+ edge [fontname="FreeSans.ttf",fontsize=10,labelfontname="FreeSans.ttf",labelfontsize=10];
+ node [fontname="FreeSans.ttf",fontsize=10,shape=record];
+ Node9 [shape="box",label="Inherited",fontsize=10,height=0.2,width=0.4,fontname="FreeSans.ttf",fillcolor="grey75",style="filled" fontcolor="black"];
+ Node10 -> Node9 [dir=back,color="midnightblue",fontsize=10,style="solid",fontname="FreeSans.ttf"];
+ Node10 [shape="box",label="PublicBase",fontsize=10,height=0.2,width=0.4,fontname="FreeSans.ttf",color="black",URL="$classPublicBase.html"];
+ Node11 -> Node10 [dir=back,color="midnightblue",fontsize=10,style="solid",fontname="FreeSans.ttf"];
+ Node11 [shape="box",label="Truncated",fontsize=10,height=0.2,width=0.4,fontname="FreeSans.ttf",color="red",URL="$classTruncated.html"];
+ Node13 -> Node9 [dir=back,color="darkgreen",fontsize=10,style="solid",fontname="FreeSans.ttf"];
+ Node13 [shape="box",label="ProtectedBase",fontsize=10,height=0.2,width=0.4,fontname="FreeSans.ttf",color="black",URL="$classProtectedBase.html"];
+ Node14 -> Node9 [dir=back,color="firebrick4",fontsize=10,style="solid",fontname="FreeSans.ttf"];
+ Node14 [shape="box",label="PrivateBase",fontsize=10,height=0.2,width=0.4,fontname="FreeSans.ttf",color="black",URL="$classPrivateBase.html"];
+ Node15 -> Node9 [dir=back,color="midnightblue",fontsize=10,style="solid",fontname="FreeSans.ttf"];
+ Node15 [shape="box",label="Undocumented",fontsize=10,height=0.2,width=0.4,fontname="FreeSans.ttf",color="grey75"];
+ Node16 -> Node9 [dir=back,color="midnightblue",fontsize=10,style="solid",fontname="FreeSans.ttf"];
+ Node16 [shape="box",label="Templ< int >",fontsize=10,height=0.2,width=0.4,fontname="FreeSans.ttf",color="black",URL="$classTempl.html"];
+ Node17 -> Node16 [dir=back,color="orange",fontsize=10,style="dashed",label="< int >",fontname="FreeSans.ttf"];
+ Node17 [shape="box",label="Templ< T >",fontsize=10,height=0.2,width=0.4,fontname="FreeSans.ttf",color="black",URL="$classTempl.html"];
+ Node18 -> Node9 [dir=back,color="darkorchid3",fontsize=10,style="dashed",label="m_usedClass",fontname="FreeSans.ttf"];
+ Node18 [shape="box",label="Used",fontsize=10,height=0.2,width=0.4,fontname="FreeSans.ttf",color="black",URL="$classUsed.html"];
+}
diff --git a/docs/XMPToolkit/graph_legend.html b/docs/XMPToolkit/graph_legend.html
new file mode 100644
index 0000000..d259d70
--- /dev/null
+++ b/docs/XMPToolkit/graph_legend.html
@@ -0,0 +1,81 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
+<title>Adobe XMP Toolkit: Graph Legend</title>
+<link href="doxygen.css" rel="stylesheet" type="text/css">
+<link href="tabs.css" rel="stylesheet" type="text/css">
+</head><body>
+<!-- Generated by Doxygen 1.5.1 -->
+<div class="tabs">
+ <ul>
+ <li><a href="index.html"><span>Main&nbsp;Page</span></a></li>
+ <li><a href="modules.html"><span>Modules</span></a></li>
+ <li><a href="annotated.html"><span>Classes</span></a></li>
+ <li><a href="files.html"><span>Files</span></a></li>
+ </ul></div>
+<h1>Graph Legend</h1>This page explains how to interpret the graphs that are generated by doxygen.<p>
+Consider the following example: <div class="fragment"><pre class="fragment"><span class="comment">/*! Invisible class because of truncation */</span>
+<span class="keyword">class </span>Invisible { };
+<span class="comment"></span>
+<span class="comment">/*! Truncated class, inheritance relation is hidden */</span>
+<span class="keyword">class </span>Truncated : <span class="keyword">public</span> Invisible { };
+
+<span class="comment">/* Class not documented with doxygen comments */</span>
+<span class="keyword">class </span>Undocumented { };
+<span class="comment"></span>
+<span class="comment">/*! Class that is inherited using public inheritance */</span>
+<span class="keyword">class </span>PublicBase : <span class="keyword">public</span> Truncated { };
+<span class="comment"></span>
+<span class="comment">/*! A template class */</span>
+<span class="keyword">template</span>&lt;<span class="keyword">class</span> T&gt; <span class="keyword">class </span>Templ { };
+<span class="comment"></span>
+<span class="comment">/*! Class that is inherited using protected inheritance */</span>
+<span class="keyword">class </span>ProtectedBase { };
+<span class="comment"></span>
+<span class="comment">/*! Class that is inherited using private inheritance */</span>
+<span class="keyword">class </span>PrivateBase { };
+<span class="comment"></span>
+<span class="comment">/*! Class that is used by the Inherited class */</span>
+<span class="keyword">class </span>Used { };
+<span class="comment"></span>
+<span class="comment">/*! Super class that inherits a number of other classes */</span>
+<span class="keyword">class </span>Inherited : <span class="keyword">public</span> PublicBase,
+ <span class="keyword">protected</span> ProtectedBase,
+ <span class="keyword">private</span> PrivateBase,
+ <span class="keyword">public</span> Undocumented
+ <span class="keyword">public</span> Templ&lt;int&gt;
+{
+ <span class="keyword">private</span>:
+ Used *m_usedClass;
+};
+</pre></div> If the <code>MAX_DOT_GRAPH_HEIGHT</code> tag in the configuration file is set to 240 this will result in the following graph:<p>
+<center><div align="center">
+<img src="graph_legend.png" alt="graph_legend.png">
+</div>
+</center> <p>
+The boxes in the above graph have the following meaning: <ul>
+<li>
+A filled black box represents the struct or class for which the graph is generated. </li>
+<li>
+A box with a black border denotes a documented struct or class. </li>
+<li>
+A box with a grey border denotes an undocumented struct or class. </li>
+<li>
+A box with a red border denotes a documented struct or class forwhich not all inheritance/containment relations are shown. A graph is truncated if it does not fit within the specified boundaries. </li>
+</ul>
+The arrows have the following meaning: <ul>
+<li>
+A dark blue arrow is used to visualize a public inheritance relation between two classes. </li>
+<li>
+A dark green arrow is used for protected inheritance. </li>
+<li>
+A dark red arrow is used for private inheritance. </li>
+<li>
+A purple dashed arrow is used if a class is contained or used by another class. The arrow is labeled with the variable(s) through which the pointed class or struct is accessible. </li>
+<li>
+A yellow dashed arrow denotes a relation between a template instance and the template class it was instantiated from. The arrow is labeled with the template parameters of the instance. </li>
+</ul>
+<hr size="1"><address style="align: right;"><small>Generated on Thu May 3 14:54:59 2007 for Adobe XMP Toolkit by&nbsp;
+<a href="http://www.doxygen.org/index.html">
+<img src="doxygen.png" alt="doxygen" align="middle" border="0"></a> 1.5.1 </small></address>
+</body>
+</html>
diff --git a/docs/XMPToolkit/graph_legend.png b/docs/XMPToolkit/graph_legend.png
new file mode 100644
index 0000000..9b96937
--- /dev/null
+++ b/docs/XMPToolkit/graph_legend.png
Binary files differ
diff --git a/docs/XMPToolkit/group__Transition.html b/docs/XMPToolkit/group__Transition.html
new file mode 100644
index 0000000..398d5b7
--- /dev/null
+++ b/docs/XMPToolkit/group__Transition.html
@@ -0,0 +1,259 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
+<title>Adobe XMP Toolkit: XMP API Transition Guide</title>
+<link href="doxygen.css" rel="stylesheet" type="text/css">
+<link href="tabs.css" rel="stylesheet" type="text/css">
+</head><body>
+<!-- Generated by Doxygen 1.5.1 -->
+<div class="tabs">
+ <ul>
+ <li><a href="index.html"><span>Main&nbsp;Page</span></a></li>
+ <li><a href="modules.html"><span>Modules</span></a></li>
+ <li><a href="annotated.html"><span>Classes</span></a></li>
+ <li><a href="files.html"><span>Files</span></a></li>
+ </ul></div>
+<h1>XMP API Transition Guide</h1><table border="0" cellpadding="0" cellspacing="0">
+<tr><td></td></tr>
+</table>
+This is a guide for XMP clients making the transition from the original C++ API to the revamped C++ API. The reader is assumed to be familiar with the old API, at least as far as used in the software being ported. The guide is presented as a series of old-to-new examples of typical usage. Reading the new API overview might provide background and motivation, but should not be necessary.<p>
+The new API is totally different in detail, the names of all include files, functions, types, and constants have changed. Many of the changes though are fairly cosmetic and trivial to port. In most other cases the new API should be more convenient to use. The iteration/enumeration functions are the only ones with significant visible semantic change.<p>
+This guide does not describe all of the old XMP functions, only those which have some non-trivial aspect for porting. If something is not described here, look at the old and new function signatures. They should be similar enough to make the transition obvious.<p>
+This is particularly true for the old UtilityXAP functions, they all have obvious mappings. Some of the UtilityXAP functions have been moved to <a class="el" href="classTXMPMeta.html">TXMPMeta</a>, mainly the binary get/set functions (UtilityXAP::GetBoolean has become <a class="el" href="classTXMPMeta.html#dcf8a1959a8bd42641a42cbd4d64a5b7">TXMPMeta::GetProperty_Bool</a>). Low value functions like UtilityXAP::AnalyzeStep or UtilityXAP::FilterPropPath have been removed.<p>
+<b>Classes</b><p>
+The client API is defined by 3 C++ template classes: <a class="el" href="classTXMPMeta.html">TXMPMeta</a>, <a class="el" href="classTXMPIterator.html">TXMPIterator</a>, and <a class="el" href="classTXMPUtils.html">TXMPUtils</a>. These correspond to the old MetaXAP, XAPPaths, and UtilityXAP classes. The templates are instantiated with a string class which is used for the return of UTF-8 strings. The XMP headers will declare instantiated classes with the names SXMPMeta, SXMPIterator, and SXMPUtils.<p>
+The associated string class must provide these member functions, identical to those of std::string: <div class="fragment"><pre class="fragment"> assign ( <span class="keyword">const</span> <span class="keywordtype">char</span> * str, size_t len )
+ <span class="keyword">const</span> <span class="keywordtype">char</span> * c_str()
+ size_t size()
+</pre></div><p>
+The result of assign does not matter, it is only used in a "void" manner.<p>
+<dl class="note" compact><dt><b>Note:</b></dt><dd>All of the code examples below assume the templates are instantiated using std::string.</dd></dl>
+<b>Headers</b><p>
+Clients should only include XMP.hpp to access XMP, and <a class="el" href="XMP_8incl__cpp.html">XMP.incl_cpp</a> to compile the template instantiations and client-side glue. The template string class is specified by defining TXMP_STRING_TYPE before the #include of either. A simple example is: <div class="fragment"><pre class="fragment"><span class="preprocessor"> #define TXMP_STRING_TYPE std::string</span>
+<span class="preprocessor"></span><span class="preprocessor"> #include "XMP.hpp"</span>
+<span class="preprocessor"> #include "<a class="code" href="XMP_8incl__cpp.html">XMP.incl_cpp</a>"</span>
+</pre></div><p>
+<b>Basic Property Access</b><p>
+The old functions MetaXAP::get and MetaXAP::set are replaced by <a class="el" href="classTXMPMeta.html#06a3241c7fa5df87f61dff02fca23a0c">TXMPMeta::GetProperty</a> and <a class="el" href="classTXMPMeta.html#1dfd6a08ebfd1a6364b3a7b6584bcc28">TXMPMeta::SetProperty</a>. The basic mapping for these is very simple.<p>
+The old way to set a simple property: <div class="fragment"><pre class="fragment"> meta.set ( XAP_NS_XAP, <span class="stringliteral">"CreatorTool"</span>, <span class="stringliteral">"Adobe Illustrator"</span> );
+</pre></div><p>
+The new way to set a simple property: <div class="fragment"><pre class="fragment"> meta.SetProperty ( <a class="code" href="XMP__Const_8h.html#030875c9dc0861c9251a3374ca14a376">kXMP_NS_XMP</a>, <span class="stringliteral">"CreatorTool"</span>, <span class="stringliteral">"Adobe Illustrator"</span> );
+</pre></div><p>
+The old way to get a simple property: <div class="fragment"><pre class="fragment"> <span class="keywordtype">bool</span> found;
+ std::string value;
+ XAPFeatures features;
+
+ found = meta.get ( XAP_NS_XAP, <span class="stringliteral">"CreatorTool"</span>, value, features );
+</pre></div><p>
+The new way to get a simple property: <div class="fragment"><pre class="fragment"> <span class="keywordtype">bool</span> found;
+ std::string value;
+ <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options;
+
+ found = meta.GetProperty ( <a class="code" href="XMP__Const_8h.html#030875c9dc0861c9251a3374ca14a376">kXMP_NS_XMP</a>, <span class="stringliteral">"CreatorTool"</span>, &amp;value, &amp;options );
+</pre></div><p>
+As before, you can pass XPath expressions for the second parameter to access elements of arrays or fields of structs. But there are new routines to make that easier. In addition, the new API allows you to eliminate the annoying '/*' for array items, reducing "Array/*[1]" to "Array[1]".<p>
+The options parameter returns considerably more information than the old features parameter. See the enum constants in <a class="el" href="XMP__Const_8h.html">XMP_Const.h</a> for details.<p>
+<b>Accessing Array Items</b><p>
+There are now special get/set functions for array items that take the index as an integer. This relieves you of the burden of formatting a path expression with the index as a decimal string. The examples below for the first element generalizes to any index in the obvious ways.<p>
+<dl class="note" compact><dt><b>Note:</b></dt><dd>The old get/set functions could only be used for existing array items. The new forms can be used to insert or append new items. See also the section on <b>Creating Array Items</b>.</dd></dl>
+The old way to access the first element of an array: <div class="fragment"><pre class="fragment"> meta.set ( XAP_NS_XAP, <span class="stringliteral">"Authors/*[1]"</span>, <span class="stringliteral">"Frank Zappa"</span> );
+ found = meta.get ( XAP_NS_XAP, <span class="stringliteral">"Authors/*[1]"</span>, value, features );
+</pre></div><p>
+The new way to access the first element of an array: <div class="fragment"><pre class="fragment"> meta.SetArrayItem ( <a class="code" href="XMP__Const_8h.html#030875c9dc0861c9251a3374ca14a376">kXMP_NS_XMP</a>, <span class="stringliteral">"Authors"</span>, 1, <span class="stringliteral">"Frank Zappa"</span> );
+ meta.GetArrayItem ( <a class="code" href="XMP__Const_8h.html#030875c9dc0861c9251a3374ca14a376">kXMP_NS_XMP</a>, <span class="stringliteral">"Authors"</span>, 1, &amp;value, &amp;options );
+</pre></div><p>
+The old way to access the last element of an array: <div class="fragment"><pre class="fragment"> meta.set ( XAP_NS_XAP, <span class="stringliteral">"Authors/*[last()]"</span>, <span class="stringliteral">"Frank Zappa"</span> );
+ found = meta.get ( XAP_NS_XAP, <span class="stringliteral">"Authors/*[last()]"</span>, value, features );
+</pre></div><p>
+The new way to access the last element of an array: <div class="fragment"><pre class="fragment"> meta.SetArrayItem ( <a class="code" href="XMP__Const_8h.html#030875c9dc0861c9251a3374ca14a376">kXMP_NS_XMP</a>, <span class="stringliteral">"Authors"</span>, kXMP_ArrayLastItem, <span class="stringliteral">"Frank Zappa"</span> );
+ meta.GetArrayItem ( <a class="code" href="XMP__Const_8h.html#030875c9dc0861c9251a3374ca14a376">kXMP_NS_XMP</a>, <span class="stringliteral">"Authors"</span>, kXMP_ArrayLastItem, &amp;value, &amp;options );
+</pre></div><p>
+<b>Creating Array Items</b><p>
+The old API had rather cumbersome createFirstItem and append functions to use when adding an item to an array. The new API has a more convenient AppendArrayItem function.<p>
+The old way to create an array item, appending to the end: <div class="fragment"><pre class="fragment"> size_t count;
+
+ <span class="keywordflow">try</span> {
+ count = meta.count ( XAP_NS_XAP, <span class="stringliteral">"Authors/*"</span> );
+ } <span class="keywordflow">catch</span> ( ... ) {
+ count = 0
+ }
+
+ <span class="keywordflow">if</span> ( count == 0 ) {
+ meta.createFirstItem ( XAP_NS_XAP, <span class="stringliteral">"Authors"</span>, <span class="stringliteral">"Frank Zappa"</span>, xap_seq );
+ } <span class="keywordflow">else</span> {
+ meta.append ( XAP_NS_XAP, <span class="stringliteral">"Authors/*[last()]"</span>, <span class="stringliteral">"Frank Zappa"</span> )
+ }
+</pre></div><p>
+The new way to create an array item, appending to the end: <div class="fragment"><pre class="fragment"> meta.AppendArrayItem ( <a class="code" href="XMP__Const_8h.html#030875c9dc0861c9251a3374ca14a376">kXMP_NS_XMP</a>, <span class="stringliteral">"Authors"</span>, kXMP_PropArrayIsOrdered, <span class="stringliteral">"Frank Zappa"</span> );
+</pre></div><p>
+Here's how to see if an array exists or how big it is: <div class="fragment"><pre class="fragment"> <span class="keywordtype">bool</span> exists = meta.DoesPropertyExist ( <a class="code" href="XMP__Const_8h.html#030875c9dc0861c9251a3374ca14a376">kXMP_NS_XMP</a>, <span class="stringliteral">"Authors"</span> );
+ size_t count = meta.CountArrayItems ( <a class="code" href="XMP__Const_8h.html#030875c9dc0861c9251a3374ca14a376">kXMP_NS_XMP</a>, <span class="stringliteral">"Authors"</span> );
+</pre></div> There are also DoesArrayItemExist and DoesStructFieldExist functions.<p>
+<b>Accessing Struct Fields</b><p>
+In the old API you accessed a field in a struct by writing an XPath expression of the general form "Struct/ns:Field". This has the subtle drawback that you must use the namespace prefix in the XPath expression. But prefixes are not guaranteed! The new API has functions that take the namespace URI.<p>
+The old way to access a field in a struct: <div class="fragment"><pre class="fragment"> meta.set ( XAP_NS_XAP_T_PG, <span class="stringliteral">"MaxPageSize/stDim:unit"</span>, <span class="stringliteral">"inch"</span> );
+ found = meta.get ( XAP_NS_XAP_T_PG, <span class="stringliteral">"MaxPageSize/stDim:unit"</span>, value, features );
+</pre></div><p>
+The new way to access a field in a struct: <div class="fragment"><pre class="fragment"> meta.SetStructField ( XAP_NS_XAP_T_PG, <span class="stringliteral">"MaxPageSize"</span>, kXMP_NS_ST_Dim, <span class="stringliteral">"unit"</span> <span class="stringliteral">"inch"</span> );
+ found = meta.GetStructField ( XAP_NS_XAP_T_PG, <span class="stringliteral">"MaxPageSize"</span>, kXMP_NS_ST_Dim, <span class="stringliteral">"unit"</span>, &amp;value, &amp;options );
+</pre></div><p>
+<b>Accessing Composite Data Structures</b><p>
+The old API forced you to write full XPath expressions for composite data structures with arrays or structs nested inside each other. This forced you to know the XPath syntax, and suffer the risks of using namespace prefixes for struct fields. The new API has path composition functions in XMPUtils to avoid both of these problems. You can compose the entire path then call Get/SetProperty, or compose all but the last portion then use Get/SetArrayItem or Get/SetStructField.<p>
+The examples here only show ComposeArrayItemPath, ComposeStructFieldPath is an obvious analog.<p>
+The old way to access a struct field within an array item: <div class="fragment"><pre class="fragment"> found = meta.get ( XAP_NS_XAP, <span class="stringliteral">"Thumbnails/*[1]/xapGImg:format"</span>, value, features );
+</pre></div><p>
+The new way to access a struct field within an array item: <div class="fragment"><pre class="fragment"> std::string itemPath;
+
+ XMPUtils::ComposeArrayItemPath ( <a class="code" href="XMP__Const_8h.html#030875c9dc0861c9251a3374ca14a376">kXMP_NS_XMP</a>, <span class="stringliteral">"Thumbnails"</span>, 1, &amp;itemPath );
+ found = meta.GetStructField ( <a class="code" href="XMP__Const_8h.html#030875c9dc0861c9251a3374ca14a376">kXMP_NS_XMP</a>, itemPath.c_str(),
+ kXMP_NS_XMP_G_IMG, <span class="stringliteral">"format"</span>, &amp;value, &amp;options );
+</pre></div><p>
+<dl class="note" compact><dt><b>Note:</b></dt><dd>As in the old API, the outermost, or "schema", namespace is the first parameter to all functions that manipulate properties. Even if the second parameter is a complex path expression.</dd></dl>
+<b>Parsing and Serializing</b><p>
+The new API has the same construct-and-parse capability as the old API. This parses one buffer that must be a complete collection of XMP. Parsing multiple buffers where you do the I/O is similar to before, differing mainly in a reversal of the "I'm done" signal.<p>
+The old way to read and parse: <div class="fragment"><pre class="fragment"> MetaXAP meta;
+ <span class="keywordtype">char</span> buffer [...];
+ size_t length;
+
+ <span class="keywordflow">while</span> ( <span class="keyword">true</span> ) {
+ -- read into buffer, setting length
+ <span class="keywordflow">if</span> ( length != 0 ) <span class="keywordflow">break</span>;
+ meta.parse ( buffer, length );
+ }
+ meta.parse ( buffer, 0, <span class="keyword">true</span> );
+</pre></div><p>
+The new way to read and parse: <div class="fragment"><pre class="fragment"> SXMPMeta meta ( 0, 0 );
+ <span class="keywordtype">char</span> buffer [...];
+ size_t length;
+
+ <span class="keywordflow">while</span> ( <span class="keyword">true</span> ) {
+ -- read into buffer, setting length
+ <span class="keywordflow">if</span> ( length != 0 ) <span class="keywordflow">break</span>;
+ meta.ParseFromBuffer ( buffer, length, kXMP_ParseMoreBuffers );
+ }
+ meta.ParseFromBuffer ( buffer, 0 );
+</pre></div><p>
+Serialization in the old API was a multi-step process. You used MetaXAP::serialize to generate a hidden serialization, then used MetaXAP::extractSerialization to extract that, then used UtilityXAP::CreateXMLPacket to get the XMP packet wrapping. The New API combines all of this into <a class="el" href="classTXMPMeta.html#2774a6f15ae22f0002201b58c46bfb49">TXMPMeta::SerializeToBuffer</a>.<p>
+The old way to write a serialized packet: <div class="fragment"><pre class="fragment"> size_t rdfLength = meta.serialize();
+ std::string header, trailer;
+ <span class="keywordtype">char</span> buffer [...];
+
+ UtilityXAP::CreateXMLPacket ( <span class="stringliteral">""</span>, <span class="keyword">true</span>, 4096, <span class="stringliteral">"\n"</span>, header, trailer );
+ -- write the header string
+ <span class="keywordflow">while</span> ( rdfLength &gt; <span class="keyword">sizeof</span>(buffer) ) {
+ meta.extractSerialization ( buffer, <span class="keyword">sizeof</span>(buffer) );
+ -- write <span class="keyword">this</span> buffer
+ rdfLength -= <span class="keyword">sizeof</span>(buffer);
+ }
+ meta.extractSerialization ( buffer, rdfLength );
+ -- write <span class="keyword">this</span> buffer (only rdfLength bytes)
+ -- write the trailer string
+</pre></div><p>
+The new way to write a serialized packet: <div class="fragment"><pre class="fragment"> std::string packet;
+
+ meta.SerializeToBuffer ( &amp;packet );
+ -- write the packet string
+</pre></div><p>
+<b>Iteration</b><p>
+The functions to iterate over the XMP data tree have not changed a lot at first glance, but the way they operate has changed considerably.<p>
+The old API essentially offered two ways to do an iteration: <ul>
+<li>One call to generate a list of all leaf nodes </li>
+<li>Program your own full traversal, recursively one level at a time</li>
+</ul>
+The new API performs a typical depth first traversal, visiting every node by default, with options to omit certain classes of nodes. Instead of mapping old patterns to new, it might make more sense to just use the new API and understand what it will return. It will also help to review the XMP data model, first documented in the November 2003 version of the XMP Specification. Pay attention to the option bits returned during iteration, they tell you what kind of node you're visiting.<p>
+Simple, default iteration code in the new API: <div class="fragment"><pre class="fragment"> std::string str1, str2, str3;
+ <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> options;
+
+ SXMPIterator iter ( meta );
+ <span class="keywordflow">while</span> ( iter.Next ( &amp;str1, &amp;str2, &amp;str3, &amp;options ) ) {
+ fprintf ( log, <span class="stringliteral">" %s %s = \"%s\", 0x%X\n"</span>,
+ str1.c_str(), str2.c_str(), str3.c_str(), options );
+ }
+</pre></div><p>
+For this RDF input: <div class="fragment"><pre class="fragment"> &lt;rdf:RDF xmlns:rdf='http:<span class="comment">//www.w3.org/1999/02/22-rdf-syntax-ns#'&gt;</span>
+ &lt;rdf:Description rdf:about='' xmlns:ns1='ns:test1/' xmlns:ns2='ns:test2/'&gt;
+
+ &lt;ns1:SimpleProp1&gt;Simple1 value&lt;/ns1:SimpleProp1&gt;
+ &lt;ns1:SimpleProp2 xml:lang='x-<span class="keywordflow">default</span>'&gt;Simple2 value&lt;/ns1:SimpleProp2&gt;
+
+ &lt;ns1:ArrayProp1&gt;
+ &lt;rdf:Bag&gt;
+ &lt;rdf:li&gt;Item1.1 value&lt;/rdf:li&gt;
+ &lt;rdf:li&gt;Item1.2 value&lt;/rdf:li&gt;
+ &lt;/rdf:Bag&gt;
+ &lt;/ns1:ArrayProp1&gt;
+
+ &lt;ns1:ArrayProp2&gt;
+ &lt;rdf:Alt&gt;
+ &lt;rdf:li xml:lang='x-one'&gt;Item2.1 value&lt;/rdf:li&gt;
+ &lt;rdf:li xml:lang='x-two'&gt;Item2.2 value&lt;/rdf:li&gt;
+ &lt;/rdf:Alt&gt;
+ &lt;/ns1:ArrayProp2&gt;
+
+ &lt;ns1:StructProp rdf:parseType='Resource'&gt;
+ &lt;ns2:Field1&gt;Field1 value&lt;/ns2:Field1&gt;
+ &lt;ns2:Field2&gt;Field2 value&lt;/ns2:Field2&gt;
+ &lt;/ns1:StructProp&gt;
+
+ &lt;ns1:QualProp1 rdf:parseType='Resource'&gt;
+ &lt;rdf:value&gt;Prop value&lt;/rdf:value&gt;
+ &lt;ns2:Qual&gt;Qual value&lt;/ns2:Qual&gt;
+ &lt;/ns1:QualProp1&gt;
+
+ &lt;ns1:QualProp2 rdf:parseType='Resource'&gt;
+ &lt;rdf:value xml:lang='x-<span class="keywordflow">default</span>'&gt;Prop value&lt;/rdf:value&gt;
+ &lt;ns2:Qual&gt;Qual value&lt;/ns2:Qual&gt;
+ &lt;/ns1:QualProp2&gt;
+
+ &lt;ns1:NestedStructProp rdf:parseType='Resource'&gt;
+ &lt;ns2:Outer rdf:parseType='Resource'&gt;
+ &lt;ns2:Middle rdf:parseType='Resource'&gt;
+ &lt;ns2:Inner rdf:parseType='Resource'&gt;
+ &lt;ns2:Field1&gt;Field1 value&lt;/ns2:Field1&gt;
+ &lt;ns2:Field2&gt;Field2 value&lt;/ns2:Field2&gt;
+ &lt;/ns2:Inner&gt;
+ &lt;/ns2:Middle&gt;
+ &lt;/ns2:Outer&gt;
+ &lt;/ns1:NestedStructProp&gt;
+
+ &lt;/rdf:Description&gt;
+ &lt;/rdf:RDF&gt;
+</pre></div><p>
+The iteration shown above would print (spacing added by hand for legibility): <div class="fragment"><pre class="fragment"> ns:test1/ = <span class="stringliteral">""</span>, 0x80000000
+
+ ns:test1/ SimpleProp1 = <span class="stringliteral">"Simple1 value"</span>, 0x0
+
+ ns:test1/ SimpleProp2 = <span class="stringliteral">"Simple2 value"</span>, 0x50
+ ns:test1/ SimpleProp2/?xml:lang = <span class="stringliteral">"x-default"</span>, 0x20
+
+ ns:test1/ ArrayProp1 = <span class="stringliteral">""</span>, 0x200
+ ns:test1/ ArrayProp1[1] = <span class="stringliteral">"Item1.1 value"</span>, 0x0
+ ns:test1/ ArrayProp1[2] = <span class="stringliteral">"Item1.2 value"</span>, 0x0
+
+ ns:test1/ ArrayProp2 = <span class="stringliteral">""</span>, 0xE00
+ ns:test1/ ArrayProp2[1] = <span class="stringliteral">"Item2.1 value"</span>, 0x50
+ ns:test1/ ArrayProp2[1]/?xml:lang = <span class="stringliteral">"x-one"</span>, 0x20
+ ns:test1/ ArrayProp2[2] = <span class="stringliteral">"Item2.2 value"</span>, 0x50
+ ns:test1/ ArrayProp2[2]/?xml:lang = <span class="stringliteral">"x-two"</span>, 0x20
+
+ ns:test1/ StructProp = <span class="stringliteral">""</span>, 0x100
+ ns:test1/ StructProp/ns2:Field1 = <span class="stringliteral">"Field1 value"</span>, 0x0
+ ns:test1/ StructProp/ns2:Field2 = <span class="stringliteral">"Field2 value"</span>, 0x0
+
+ ns:test1/ QualProp1 = <span class="stringliteral">"Prop value"</span>, 0x10
+ ns:test1/ QualProp1/?ns2:Qual = <span class="stringliteral">"Qual value"</span>, 0x20
+
+ ns:test1/ QualProp2 = <span class="stringliteral">"Prop value"</span>, 0x50
+ ns:test1/ QualProp2/?xml:lang = <span class="stringliteral">"x-default"</span>, 0x20
+ ns:test1/ QualProp2/?ns2:Qual = <span class="stringliteral">"Qual value"</span>, 0x20
+
+ ns:test1/ NestedStructProp = <span class="stringliteral">""</span>, 0x100
+ ns:test1/ NestedStructProp/ns2:Outer = <span class="stringliteral">""</span>, 0x100
+ ns:test1/ NestedStructProp/ns2:Outer/ns2:Middle = <span class="stringliteral">""</span>, 0x100
+ ns:test1/ NestedStructProp/ns2:Outer/ns2:Middle/ns2:Inner = <span class="stringliteral">""</span>, 0x100
+ ns:test1/ NestedStructProp/ns2:Outer/ns2:Middle/ns2:Inner/ns2:Field1 = <span class="stringliteral">"Field1 value"</span>, 0x0
+ ns:test1/ NestedStructProp/ns2:Outer/ns2:Middle/ns2:Inner/ns2:Field2 = <span class="stringliteral">"Field2 value"</span>, 0x0
+</pre></div> <hr size="1"><address style="align: right;"><small>Generated on Thu May 3 14:54:58 2007 for Adobe XMP Toolkit by&nbsp;
+<a href="http://www.doxygen.org/index.html">
+<img src="doxygen.png" alt="doxygen" align="middle" border="0"></a> 1.5.1 </small></address>
+</body>
+</html>
diff --git a/docs/XMPToolkit/index.html b/docs/XMPToolkit/index.html
new file mode 100644
index 0000000..492a6ce
--- /dev/null
+++ b/docs/XMPToolkit/index.html
@@ -0,0 +1,112 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
+<title>Adobe XMP Toolkit: Overview XMP Toolkit Overview</title>
+<link href="doxygen.css" rel="stylesheet" type="text/css">
+<link href="tabs.css" rel="stylesheet" type="text/css">
+</head><body>
+<!-- Generated by Doxygen 1.5.1 -->
+<div class="tabs">
+ <ul>
+ <li id="current"><a href="index.html"><span>Main&nbsp;Page</span></a></li>
+ <li><a href="modules.html"><span>Modules</span></a></li>
+ <li><a href="annotated.html"><span>Classes</span></a></li>
+ <li><a href="files.html"><span>Files</span></a></li>
+ </ul></div>
+<h1>Overview XMP Toolkit Overview</h1>
+<p>
+<h2><a class="anchor" name="intro-sec">
+This XMP Toolkit Release</a></h2>
+This release provides the following features: <ul>
+<li>Improved, simpler API. If you need to port code from a previous version, see the <a class="el" href="group__Transition.html">XMP API Transition Guide</a> (under Modules). </li>
+<li>Updates to make the code compatible with Adobe Acrobat 7 and Adobe Creative Suite 2. </li>
+<li>Improved performance, in some cases significantly improved. </li>
+<li>Code cleanup that makes the source more readable and easier to maintain. </li>
+<li>Single source with UNIX-style newlines; this version works in all operating systems </li>
+<li>Improved namespace handling. </li>
+<li>Numerous bug fixes.</li>
+</ul>
+<h2><a class="anchor" name="first-sec">
+General Overview of the XMP API and Internal Architecture.</a></h2>
+The client view of the XMP API is provided through three C++ class templates: <ul>
+<li><code><a class="el" href="classTXMPMeta.html">TXMPMeta</a></code> provides the fundamental methods for manipulating XMP metadata. </li>
+<li><code><a class="el" href="classTXMPIterator.html">TXMPIterator</a></code> provides methods to iterate over existing XMP metadata. </li>
+<li><code><a class="el" href="classTXMPUtils.html">TXMPUtils</a></code> provides additional utilities layered on top of <code><a class="el" href="classTXMPMeta.html">TXMPMeta</a></code>. Use a string class to instantiate the templates; you can use <code>std::string</code>. The string class is a template parameter, which simplifies its use for clients that have an existing string model different from <code>std::string</code>.</li>
+</ul>
+Developers should understand the XMP data model before working with the XMP Toolkit. The data model is documented in chapter 2 of the XMP Specification. The XMPCoverage sample provides an in-depth illustration of the use of the XMP Toolkit.<p>
+<dl class="note" compact><dt><b>Note:</b></dt><dd>Earlier versions of the Adobe XMP Toolkit had a different API and implementation. See the <a class="el" href="group__Transition.html">XMP API Transition Guide</a> page for information about adapting to the new API.</dd></dl>
+The XMP Toolkit is implemented in three layers, which isolate the return of string values, synchronization for multi-threaded use, and exception propagation. While the SDK as provided from Adobe builds a static library, this layering can easily be adapted to build a DLL. <ul>
+<li>The top layer is the implementation of the client template classes. This layer is for copying string results and releasing the threading lock if necessary. </li>
+<li>The middle layer consists of the three classes <code>WXMPMeta</code>, <code>WXMPIterator</code>, and <code>WXMPUtils</code>. They provide wrappers between the top client layer and the actual implementation. The middle layer is responsible for acquiring the threading lock, basic parameter checking, catching propagated exceptions, and releasing the threading lock when appropriate. </li>
+<li>The inner layer is the actual implementation, contained in the three classes <code>XMPMeta</code>, <code>XMPIterator</code>, and <code>XMPUtils</code>.</li>
+</ul>
+<h2><a class="anchor" name="second-sec">
+Use of the XMP API</a></h2>
+Client code obtains access to the XMP API by including a single header, XMP.hpp. You should read the template header files, <a class="el" href="TXMPMeta_8hpp.html">TXMPMeta.hpp</a>, and so on, for detailed information, but do not #include them. You should also read <a class="el" href="XMP__Const_8h.html">XMP_Const.h</a> for detailed information about types and constants for namespace URIs and option flags. The client templates are instantiated by including <a class="el" href="XMP_8incl__cpp.html">XMP.incl_cpp</a> in exactly one source file. The macro <code>TXMP_STRING_TYPE</code> must be defined first to provide the string class.<p>
+The string class used to instantiate the templates must have the following member functions, which match those of <code>std::string:</code> <div class="fragment"><pre class="fragment"> assign ( <span class="keyword">const</span> <span class="keywordtype">char</span> * str, size_t len )
+ size_t size() const
+ const <span class="keywordtype">char</span> * c_str() const
+</pre></div> The result type of <code>assign</code> does not matter, it is always ignored.<p>
+Use of the XMP Toolkit is reasonably straightforward once you understand the XMP data model. Some tips to keep in mind:<p>
+<ul>
+<li>All strings passed as parameters must be UTF-8. </li>
+<li>All strings returned will be UTF-8. </li>
+<li>Register private namespaces before use. </li>
+<li>Don't depend on specific namespace prefixes. Don't hardwire the prefixes for struct fields, use functions like <code>Get/SetStructField</code> or <code>ComposeStructFieldPath</code>. </li>
+<li>Use the path composition functions for complex paths with nested structs or arrays. </li>
+<li>Use <code>Get/SetLocalizedText</code> when dealing with language alternative (alt-text) arrays.</li>
+</ul>
+<h3><a class="anchor" name="callchain">
+Implementation Call Chain</a></h3>
+The implementation of <code>GetProperty</code> provides a good illustration of the toolkit layering. The declaration below for <code><a class="el" href="classTXMPMeta.html#06a3241c7fa5df87f61dff02fca23a0c">TXMPMeta::GetProperty</a></code> is simplified by hardwiring <code>std::string</code>. The <code>XMP_StringPtr</code> type is simply <code>const char *</code>.<p>
+<div class="fragment"><pre class="fragment"> <span class="keywordtype">bool</span> <a class="code" href="classTXMPMeta.html#06a3241c7fa5df87f61dff02fca23a0c">TXMPMeta::GetProperty</a> ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS,
+ <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> propName,
+ std::string * propValue,
+ <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> * options )<span class="keyword"> const</span>
+<span class="keyword"> </span>{
+ <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> resultPtr = 0;
+ <a class="code" href="XMP__Const_8h.html#9f7dcc184f901c713274edfdac5bcc9a">XMP_StringLen</a> resultLen = 0;
+
+ <span class="keywordtype">bool</span> found = this-&gt;xmpObj.GetProperty ( schemaNS, propName,
+ &amp;resultPtr, &amp;resultLen, options );
+
+ <span class="keywordflow">if</span> ( found ) {
+ <span class="keywordflow">if</span> ( propValue != 0 ) propValue-&gt;assign ( resultPtr, resultLen );
+ this-&gt;xmpObj.UnlockObject ( kXMP_NoOptions );
+ }
+ <span class="keywordflow">return</span> found;
+
+ }
+</pre></div><p>
+The template object contains a data member pointer to the underlying <code>WXMPMeta</code> object. This is used to dispatch the call to the middle layer. The actual implementation of the XMP toolkit returns string values as a pointer and length, the pointer references private internal storage of the toolkit. The client code copies the string value to the client's string object. This minimizes the amount of string copying, and should the XMP toolkit be built as a DLL ensures that any memory allocation for the client's value is done on the client side. The call to <code>WXMPMeta::UnlockObject</code> is explained below.<p>
+<div class="fragment"><pre class="fragment"> <span class="keywordtype">bool</span> WXMPMeta::GetProperty ( <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> schemaNS,
+ <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> propName,
+ <a class="code" href="XMP__Const_8h.html#d439e3ceeb4590d310f6125aa12c6df6">XMP_StringPtr</a> * propValue,
+ <a class="code" href="XMP__Const_8h.html#9f7dcc184f901c713274edfdac5bcc9a">XMP_StringLen</a> * valueSize,
+ <a class="code" href="XMP__Const_8h.html#eb865118433be92d88e5f49ed11487c8">XMP_OptionBits</a> * options )<span class="keyword"> const</span>
+<span class="keyword"> </span>{
+ XMP_Bool found;
+ XMP_ENTER_WRAPPER ( <span class="stringliteral">"WXMPMeta::GetProperty"</span> )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) {
+ XMP_Throw ( <span class="stringliteral">"Empty schema namespace URI"</span>, kXMPErr_BadSchema );
+ }
+ <span class="keywordflow">if</span> ( (propName == 0) || (*propName == 0) ) {
+ XMP_Throw ( <span class="stringliteral">"Empty property name"</span>, kXMPErr_BadXPath );
+ }
+
+ <span class="keywordflow">if</span> ( propValue == 0 ) propValue = &amp;voidStringPtr;
+ <span class="keywordflow">if</span> ( valueSize == 0 ) valueSize = &amp;voidStringLen;
+ <span class="keywordflow">if</span> ( options == 0 ) options = &amp;voidOptionBits;
+
+ <span class="keyword">const</span> XMPMeta &amp; meta = WtoXMPMeta_Ref ( *<span class="keyword">this</span> );
+ found = meta.GetProperty ( schemaNS, propName, propValue, valueSize, options );
+
+ XMP_EXIT_WRAPPER_KEEP_LOCK ( found )
+ return found;
+ }
+</pre></div><p>
+The entry and exit macros in the <code>WXMPMeta</code> layer acquire the threading lock on entry and usually release it on exit. The lock is kept on exit whenever a string value is returned. Since a pointer to internal data is returned, the threading lock can't be released until after the template code in the client copies the string. The entry and exit macros also prevent uncontrolled exception propagation from the lower layer back to the client. This is not critical for use of the XMP Toolkit as a static library. But it is generally not safe to propagate C++ exceptions across DLL boundaries. <hr size="1"><address style="align: right;"><small>Generated on Thu May 3 14:54:57 2007 for Adobe XMP Toolkit by&nbsp;
+<a href="http://www.doxygen.org/index.html">
+<img src="doxygen.png" alt="doxygen" align="middle" border="0"></a> 1.5.1 </small></address>
+</body>
+</html>
diff --git a/docs/XMPToolkit/modules.html b/docs/XMPToolkit/modules.html
new file mode 100644
index 0000000..8054bd0
--- /dev/null
+++ b/docs/XMPToolkit/modules.html
@@ -0,0 +1,22 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
+<title>Adobe XMP Toolkit: Module Index</title>
+<link href="doxygen.css" rel="stylesheet" type="text/css">
+<link href="tabs.css" rel="stylesheet" type="text/css">
+</head><body>
+<!-- Generated by Doxygen 1.5.1 -->
+<div class="tabs">
+ <ul>
+ <li><a href="index.html"><span>Main&nbsp;Page</span></a></li>
+ <li id="current"><a href="modules.html"><span>Modules</span></a></li>
+ <li><a href="annotated.html"><span>Classes</span></a></li>
+ <li><a href="files.html"><span>Files</span></a></li>
+ </ul></div>
+<h1>Adobe XMP Toolkit Modules</h1>Here is a list of all modules:<ul>
+<li><a class="el" href="group__Transition.html">XMP API Transition Guide</a>
+</ul>
+<hr size="1"><address style="align: right;"><small>Generated on Thu May 3 14:54:58 2007 for Adobe XMP Toolkit by&nbsp;
+<a href="http://www.doxygen.org/index.html">
+<img src="doxygen.png" alt="doxygen" align="middle" border="0"></a> 1.5.1 </small></address>
+</body>
+</html>
diff --git a/docs/XMPToolkit/structXMP__DateTime-members.html b/docs/XMPToolkit/structXMP__DateTime-members.html
new file mode 100644
index 0000000..b12b74d
--- /dev/null
+++ b/docs/XMPToolkit/structXMP__DateTime-members.html
@@ -0,0 +1,25 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
+<title>Adobe XMP Toolkit: Member List</title>
+<link href="doxygen.css" rel="stylesheet" type="text/css">
+<link href="tabs.css" rel="stylesheet" type="text/css">
+</head><body>
+<!-- Generated by Doxygen 1.5.1 -->
+<div class="tabs">
+ <ul>
+ <li><a href="index.html"><span>Main&nbsp;Page</span></a></li>
+ <li><a href="modules.html"><span>Modules</span></a></li>
+ <li id="current"><a href="annotated.html"><span>Classes</span></a></li>
+ <li><a href="files.html"><span>Files</span></a></li>
+ </ul></div>
+<div class="tabs">
+ <ul>
+ <li><a href="annotated.html"><span>Class&nbsp;List</span></a></li>
+ <li><a href="functions.html"><span>Class&nbsp;Members</span></a></li>
+ </ul></div>
+<h1>XMP_DateTime Member List</h1>This is the complete list of members for <a class="el" href="structXMP__DateTime.html">XMP_DateTime</a>, including all inherited members.<p><table>
+</table><hr size="1"><address style="align: right;"><small>Generated on Thu May 3 14:54:59 2007 for Adobe XMP Toolkit by&nbsp;
+<a href="http://www.doxygen.org/index.html">
+<img src="doxygen.png" alt="doxygen" align="middle" border="0"></a> 1.5.1 </small></address>
+</body>
+</html>
diff --git a/docs/XMPToolkit/structXMP__DateTime.html b/docs/XMPToolkit/structXMP__DateTime.html
new file mode 100644
index 0000000..4ff3fb3
--- /dev/null
+++ b/docs/XMPToolkit/structXMP__DateTime.html
@@ -0,0 +1,59 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
+<title>Adobe XMP Toolkit: XMP_DateTime Struct Reference</title>
+<link href="doxygen.css" rel="stylesheet" type="text/css">
+<link href="tabs.css" rel="stylesheet" type="text/css">
+</head><body>
+<!-- Generated by Doxygen 1.5.1 -->
+<div class="tabs">
+ <ul>
+ <li><a href="index.html"><span>Main&nbsp;Page</span></a></li>
+ <li><a href="modules.html"><span>Modules</span></a></li>
+ <li id="current"><a href="annotated.html"><span>Classes</span></a></li>
+ <li><a href="files.html"><span>Files</span></a></li>
+ </ul></div>
+<div class="tabs">
+ <ul>
+ <li><a href="annotated.html"><span>Class&nbsp;List</span></a></li>
+ <li><a href="functions.html"><span>Class&nbsp;Members</span></a></li>
+ </ul></div>
+<h1>XMP_DateTime Struct Reference</h1><!-- doxytag: class="XMP_DateTime" -->The expanded type for a date and time. Dates and time in the serialized XMP are ISO 8601 strings. The <code><a class="el" href="structXMP__DateTime.html">XMP_DateTime</a></code> struct allows easy conversion with other formats.
+<a href="#_details">More...</a>
+<p>
+<code>#include &lt;<a class="el" href="XMP__Const_8h-source.html">XMP_Const.h</a>&gt;</code>
+<p>
+<a href="structXMP__DateTime-members.html">List of all members.</a><table border="0" cellpadding="0" cellspacing="0">
+<tr><td></td></tr>
+</table>
+<hr><a name="_details"></a><h2>Detailed Description</h2>
+The expanded type for a date and time. Dates and time in the serialized XMP are ISO 8601 strings. The <code><a class="el" href="structXMP__DateTime.html">XMP_DateTime</a></code> struct allows easy conversion with other formats.
+<p>
+All of the fields are 32 bit, even though most could be 8 bit. This avoids overflow when doing carries for arithmetic or normalization. All fields have signed values for the same reasons.<p>
+The fields of the <code><a class="el" href="structXMP__DateTime.html">XMP_DateTime</a></code> struct are:<p>
+<ul>
+<li>year- The year, can be negative. </li>
+<li>month - The month in the range 1..12. </li>
+<li>day - The day of the month in the range 1..31. </li>
+<li>hour - The hour in the range 0..23. </li>
+<li>minute - The minute in the range 0..59. </li>
+<li>second - The second in the range 0..59. </li>
+<li>tzSign - The "sign" of the time zone, 0 means UTC, -1 is west, +1 is east. </li>
+<li>tzHour - The time zone hour in the range 0..23. </li>
+<li>tzMinute - The time zone minute in the range 0..59. </li>
+<li>nanoSecond - Nanoseconds within a second, often left as zero.</li>
+</ul>
+Constants for the <code>tzSign</code> are:<p>
+<ul>
+<li><code>kXMP_TimeIsUTC</code> - The time is UTC. </li>
+<li><code>kXMP_TimeWestOfUTC</code> - The time zone is west of UTC, behind in time. </li>
+<li><code>kXMP_TimeEastOfUTC</code> - The time zone is east of UTC, ahead in time.</li>
+</ul>
+DateTime values are occasionally used in cases with only a date or only a time component. A date without a time has zeros in the <code><a class="el" href="structXMP__DateTime.html">XMP_DateTime</a></code> struct for all time fields. A time without a date has zeros for all date fields (year, month, and day).
+<p>
+<hr>The documentation for this struct was generated from the following file:<ul>
+<li><a class="el" href="XMP__Const_8h-source.html">XMP_Const.h</a></ul>
+<hr size="1"><address style="align: right;"><small>Generated on Thu May 3 14:54:59 2007 for Adobe XMP Toolkit by&nbsp;
+<a href="http://www.doxygen.org/index.html">
+<img src="doxygen.png" alt="doxygen" align="middle" border="0"></a> 1.5.1 </small></address>
+</body>
+</html>
diff --git a/docs/XMPToolkit/tab_b.gif b/docs/XMPToolkit/tab_b.gif
new file mode 100644
index 0000000..0d62348
--- /dev/null
+++ b/docs/XMPToolkit/tab_b.gif
Binary files differ
diff --git a/docs/XMPToolkit/tab_l.gif b/docs/XMPToolkit/tab_l.gif
new file mode 100644
index 0000000..9b1e633
--- /dev/null
+++ b/docs/XMPToolkit/tab_l.gif
Binary files differ
diff --git a/docs/XMPToolkit/tab_r.gif b/docs/XMPToolkit/tab_r.gif
new file mode 100644
index 0000000..ce9dd9f
--- /dev/null
+++ b/docs/XMPToolkit/tab_r.gif
Binary files differ
diff --git a/docs/XMPToolkit/tabs.css b/docs/XMPToolkit/tabs.css
new file mode 100644
index 0000000..a61552a
--- /dev/null
+++ b/docs/XMPToolkit/tabs.css
@@ -0,0 +1,102 @@
+/* tabs styles, based on http://www.alistapart.com/articles/slidingdoors */
+
+DIV.tabs
+{
+ float : left;
+ width : 100%;
+ background : url("tab_b.gif") repeat-x bottom;
+ margin-bottom : 4px;
+}
+
+DIV.tabs UL
+{
+ margin : 0px;
+ padding-left : 10px;
+ list-style : none;
+}
+
+DIV.tabs LI, DIV.tabs FORM
+{
+ display : inline;
+ margin : 0px;
+ padding : 0px;
+}
+
+DIV.tabs FORM
+{
+ float : right;
+}
+
+DIV.tabs A
+{
+ float : left;
+ background : url("tab_r.gif") no-repeat right top;
+ border-bottom : 1px solid #84B0C7;
+ font-size : x-small;
+ font-weight : bold;
+ text-decoration : none;
+}
+
+DIV.tabs A:hover
+{
+ background-position: 100% -150px;
+}
+
+DIV.tabs A:link, DIV.tabs A:visited,
+DIV.tabs A:active, DIV.tabs A:hover
+{
+ color: #1A419D;
+}
+
+DIV.tabs SPAN
+{
+ float : left;
+ display : block;
+ background : url("tab_l.gif") no-repeat left top;
+ padding : 5px 9px;
+ white-space : nowrap;
+}
+
+DIV.tabs INPUT
+{
+ float : right;
+ display : inline;
+ font-size : 1em;
+}
+
+DIV.tabs TD
+{
+ font-size : x-small;
+ font-weight : bold;
+ text-decoration : none;
+}
+
+
+
+/* Commented Backslash Hack hides rule from IE5-Mac \*/
+DIV.tabs SPAN {float : none;}
+/* End IE5-Mac hack */
+
+DIV.tabs A:hover SPAN
+{
+ background-position: 0% -150px;
+}
+
+DIV.tabs LI#current A
+{
+ background-position: 100% -150px;
+ border-width : 0px;
+}
+
+DIV.tabs LI#current SPAN
+{
+ background-position: 0% -150px;
+ padding-bottom : 6px;
+}
+
+DIV.nav
+{
+ background : none;
+ border : none;
+ border-bottom : 1px solid #84B0C7;
+}
diff --git a/java/XMPCore/.classpath b/java/XMPCore/.classpath
new file mode 100644
index 0000000..fb50116
--- /dev/null
+++ b/java/XMPCore/.classpath
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/java/XMPCore/.project b/java/XMPCore/.project
new file mode 100644
index 0000000..2a52c9b
--- /dev/null
+++ b/java/XMPCore/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>XMPCore</name>
+ <comment>Copyright 2006-2007 Adobe Systems Incorporated, All Rights Reserved. NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms of the Adobe license agreement accompanying it.</comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/java/XMPCore/build.xml b/java/XMPCore/build.xml
new file mode 100644
index 0000000..734ed49
--- /dev/null
+++ b/java/XMPCore/build.xml
@@ -0,0 +1,176 @@
+<!--
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+-->
+
+<project name="XMPCore Build File" default="build">
+
+ <!-- Project Properties -->
+ <property name='implementation.title' value='Adobe XMP Core'/>
+ <property name='implementation.copyright' value='Copyright 2006-2007 Adobe Systems Incorporated. All rights reserved'/>
+ <property name='implementation.version.major' value='4'/>
+ <property name='implementation.version.minor' value='1'/>
+ <property name='implementation.version.micro' value='1'/>
+ <property name='implementation.version.tag' value='RC'/>
+ <property name='app.name' value='xmpcore'/>
+ <property name='src.dir' value='${basedir}/src'/>
+ <property name='intermediate.dir' value='${basedir}/intermediate'/>
+ <property name='target.dir' value='${basedir}/target'/>
+ <property file='${src.dir}/com/adobe/xmp/version.properties'/>
+
+ <!-- Sets the build timestamp -->
+ <tstamp>
+ <format property="BuildDate" pattern="yyyy MMM dd HH:mm:ss-z" locale="en" />
+ </tstamp>
+
+
+ <!-- =================================================================== -->
+ <!-- Build -->
+ <!-- =================================================================== -->
+
+ <target name="build" depends="clean, compile, createjars" />
+
+
+ <!-- =================================================================== -->
+ <!-- Compile -->
+ <!-- =================================================================== -->
+
+ <target name="compile">
+ <echo message="Compiling ..." level="info" />
+
+ <!-- debug -->
+ <antcall target="prepareVersionInfo">
+ <param name="debug" value="true" />
+ <param name="path" value="debug" />
+ </antcall>
+ <antcall target="javac">
+ <param name="debug" value="true" />
+ <param name="path" value="debug" />
+ </antcall>
+
+ <!-- release -->
+ <antcall target="prepareVersionInfo">
+ <param name="debug" value="false" />
+ <param name="path" value="release" />
+ </antcall>
+
+ <antcall target="javac">
+ <param name="debug" value="false" />
+ <param name="path" value="release" />
+ </antcall>
+ </target>
+
+
+ <target name="prepareVersionInfo">
+ <condition property="debugStr" value=" (debug)">
+ <equals arg1="${debug}" arg2="true"/>
+ </condition>
+ <condition property="debugStr" value="">
+ <isfalse value="${isDebug}" />
+ </condition>
+
+ <property name='implementation.version' value='${implementation.title} ${implementation.version.major}.${implementation.version.minor}-${implementation.version.product}${implementation.version.engbuild} ${rel_version}, ${BuildDate}${debugStr}' />
+
+ <!-- copies build information into Java readable property file -->
+ <copy todir="${intermediate.dir}/${path}" overwrite="true">
+ <fileset dir="src">
+ <include name="**/version.properties" />
+ </fileset>
+ </copy>
+ <replaceregexp
+ byline="true"
+ match="^(implementation\.version\s+.+)$"
+ replace="\1${debugStr}"
+ encoding="UTF-8">
+ <fileset dir="${intermediate.dir}/${path}">
+ <include name="**/version.properties" />
+ </fileset>
+ </replaceregexp>
+ <replaceregexp
+ byline="true"
+ match="^(implementation\.version\.debug\s+).+$"
+ replace="\1${debug}"
+ encoding="UTF-8">
+ <fileset dir="${intermediate.dir}/${path}">
+ <include name="**/version.properties" />
+ </fileset>
+ </replaceregexp>
+ </target>
+
+ <target name="javac">
+ <mkdir dir="${intermediate.dir}/${path}" />
+ <javac debug="${debug}" destdir="${intermediate.dir}/${path}" source="1.4">
+ <src path="${src.dir}" />
+ </javac>
+ </target>
+
+
+ <!-- =================================================================== -->
+ <!-- Crate Jar Libraries -->
+ <!-- =================================================================== -->
+
+ <target name="createjars" depends="compile">
+ <echo message="Create Libs ..." level="info" />
+ <antcall target="createjar">
+ <param name="path" value="debug" />
+ </antcall>
+ <antcall target="createjar">
+ <param name="path" value="release" />
+ </antcall>
+ <zip destfile="${target.dir}/debug/${app.name}-src.zip">
+ <fileset dir="${src.dir}" excludes="**/package.html"/>
+ </zip>
+ </target>
+
+ <target name="createjar">
+ <mkdir dir="${target.dir}/${path}" />
+ <condition property="debugStr" value=" (debug)">
+ <equals arg1="${path}" arg2="debug" />
+ </condition>
+ <condition property="debugStr" value="">
+ <equals arg1="${path}" arg2="release" />
+ </condition>
+
+ <property name='implementation.version' value='${implementation.title} ${implementation.version.major}.${implementation.version.minor} ${implementation.version.tag}${debugStr}' />
+
+ <jar destfile="${target.dir}/${path}/${app.name}.jar" update="false">
+ <fileset dir="${intermediate.dir}/${path}">
+ <patternset refid="jar.classes" />
+ </fileset>
+ <manifest>
+ <attribute name="Implementation-Title" value="${implementation.title}" />
+ <attribute name="Implementation-Version" value="${implementation.version}" />
+ <attribute name="Implementation-Vendor" value="${implementation.copyright}" />
+ <attribute name="BuildDate" value="${BuildDate}" />
+ </manifest>
+ </jar>
+ </target>
+
+
+ <!-- =================================================================== -->
+ <!-- Clean -->
+ <!-- =================================================================== -->
+
+ <target name="clean">
+ <echo message="Clean..." level="info" />
+ <delete dir="${intermediate.dir}" />
+ <delete dir="${target.dir}" />
+ </target>
+
+
+ <!-- =================================================================== -->
+ <!-- Filesets -->
+ <!-- =================================================================== -->
+
+ <!-- contents of the library jar -->
+ <patternset id="jar.classes">
+ <include name="**/*.class" />
+ <include name="**/version.properties" />
+ </patternset>
+</project> \ No newline at end of file
diff --git a/java/XMPCore/docs/allclasses-frame.html b/java/XMPCore/docs/allclasses-frame.html
new file mode 100644
index 0000000..e9f6291
--- /dev/null
+++ b/java/XMPCore/docs/allclasses-frame.html
@@ -0,0 +1,70 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:51 CEST 2007 -->
+<TITLE>
+All Classes
+</TITLE>
+
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="stylesheet.css" TITLE="Style">
+
+
+</HEAD>
+
+<BODY BGCOLOR="white">
+<FONT size="+1" CLASS="FrameHeadingFont">
+<B>All Classes</B></FONT>
+<BR>
+
+<TABLE BORDER="0" WIDTH="100%" SUMMARY="">
+<TR>
+<TD NOWRAP><FONT CLASS="FrameItemFont"><A HREF="com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options" target="classFrame">AliasOptions</A>
+<BR>
+<A HREF="com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options" target="classFrame">IteratorOptions</A>
+<BR>
+<A HREF="com/adobe/xmp/options/Options.html" title="class in com.adobe.xmp.options" target="classFrame">Options</A>
+<BR>
+<A HREF="com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options" target="classFrame">ParseOptions</A>
+<BR>
+<A HREF="com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options" target="classFrame">PropertyOptions</A>
+<BR>
+<A HREF="com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options" target="classFrame">SerializeOptions</A>
+<BR>
+<A HREF="com/adobe/xmp/properties/XMPAliasInfo.html" title="interface in com.adobe.xmp.properties" target="classFrame"><I>XMPAliasInfo</I></A>
+<BR>
+<A HREF="com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp" target="classFrame"><I>XMPConst</I></A>
+<BR>
+<A HREF="com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp" target="classFrame"><I>XMPDateTime</I></A>
+<BR>
+<A HREF="com/adobe/xmp/XMPDateTimeFactory.html" title="class in com.adobe.xmp" target="classFrame">XMPDateTimeFactory</A>
+<BR>
+<A HREF="com/adobe/xmp/XMPError.html" title="interface in com.adobe.xmp" target="classFrame"><I>XMPError</I></A>
+<BR>
+<A HREF="com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp" target="classFrame">XMPException</A>
+<BR>
+<A HREF="com/adobe/xmp/XMPIterator.html" title="interface in com.adobe.xmp" target="classFrame"><I>XMPIterator</I></A>
+<BR>
+<A HREF="com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp" target="classFrame"><I>XMPMeta</I></A>
+<BR>
+<A HREF="com/adobe/xmp/XMPMetaFactory.html" title="class in com.adobe.xmp" target="classFrame">XMPMetaFactory</A>
+<BR>
+<A HREF="com/adobe/xmp/XMPPathFactory.html" title="class in com.adobe.xmp" target="classFrame">XMPPathFactory</A>
+<BR>
+<A HREF="com/adobe/xmp/properties/XMPProperty.html" title="interface in com.adobe.xmp.properties" target="classFrame"><I>XMPProperty</I></A>
+<BR>
+<A HREF="com/adobe/xmp/properties/XMPPropertyInfo.html" title="interface in com.adobe.xmp.properties" target="classFrame"><I>XMPPropertyInfo</I></A>
+<BR>
+<A HREF="com/adobe/xmp/XMPSchemaRegistry.html" title="interface in com.adobe.xmp" target="classFrame"><I>XMPSchemaRegistry</I></A>
+<BR>
+<A HREF="com/adobe/xmp/XMPUtils.html" title="class in com.adobe.xmp" target="classFrame">XMPUtils</A>
+<BR>
+<A HREF="com/adobe/xmp/XMPVersionInfo.html" title="interface in com.adobe.xmp" target="classFrame"><I>XMPVersionInfo</I></A>
+<BR>
+</FONT></TD>
+</TR>
+</TABLE>
+
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/allclasses-noframe.html b/java/XMPCore/docs/allclasses-noframe.html
new file mode 100644
index 0000000..9fedde7
--- /dev/null
+++ b/java/XMPCore/docs/allclasses-noframe.html
@@ -0,0 +1,70 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:51 CEST 2007 -->
+<TITLE>
+All Classes
+</TITLE>
+
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="stylesheet.css" TITLE="Style">
+
+
+</HEAD>
+
+<BODY BGCOLOR="white">
+<FONT size="+1" CLASS="FrameHeadingFont">
+<B>All Classes</B></FONT>
+<BR>
+
+<TABLE BORDER="0" WIDTH="100%" SUMMARY="">
+<TR>
+<TD NOWRAP><FONT CLASS="FrameItemFont"><A HREF="com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options">AliasOptions</A>
+<BR>
+<A HREF="com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options">IteratorOptions</A>
+<BR>
+<A HREF="com/adobe/xmp/options/Options.html" title="class in com.adobe.xmp.options">Options</A>
+<BR>
+<A HREF="com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options">ParseOptions</A>
+<BR>
+<A HREF="com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>
+<BR>
+<A HREF="com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>
+<BR>
+<A HREF="com/adobe/xmp/properties/XMPAliasInfo.html" title="interface in com.adobe.xmp.properties"><I>XMPAliasInfo</I></A>
+<BR>
+<A HREF="com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp"><I>XMPConst</I></A>
+<BR>
+<A HREF="com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp"><I>XMPDateTime</I></A>
+<BR>
+<A HREF="com/adobe/xmp/XMPDateTimeFactory.html" title="class in com.adobe.xmp">XMPDateTimeFactory</A>
+<BR>
+<A HREF="com/adobe/xmp/XMPError.html" title="interface in com.adobe.xmp"><I>XMPError</I></A>
+<BR>
+<A HREF="com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A>
+<BR>
+<A HREF="com/adobe/xmp/XMPIterator.html" title="interface in com.adobe.xmp"><I>XMPIterator</I></A>
+<BR>
+<A HREF="com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp"><I>XMPMeta</I></A>
+<BR>
+<A HREF="com/adobe/xmp/XMPMetaFactory.html" title="class in com.adobe.xmp">XMPMetaFactory</A>
+<BR>
+<A HREF="com/adobe/xmp/XMPPathFactory.html" title="class in com.adobe.xmp">XMPPathFactory</A>
+<BR>
+<A HREF="com/adobe/xmp/properties/XMPProperty.html" title="interface in com.adobe.xmp.properties"><I>XMPProperty</I></A>
+<BR>
+<A HREF="com/adobe/xmp/properties/XMPPropertyInfo.html" title="interface in com.adobe.xmp.properties"><I>XMPPropertyInfo</I></A>
+<BR>
+<A HREF="com/adobe/xmp/XMPSchemaRegistry.html" title="interface in com.adobe.xmp"><I>XMPSchemaRegistry</I></A>
+<BR>
+<A HREF="com/adobe/xmp/XMPUtils.html" title="class in com.adobe.xmp">XMPUtils</A>
+<BR>
+<A HREF="com/adobe/xmp/XMPVersionInfo.html" title="interface in com.adobe.xmp"><I>XMPVersionInfo</I></A>
+<BR>
+</FONT></TD>
+</TR>
+</TABLE>
+
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/com/adobe/xmp/XMPConst.html b/java/XMPCore/docs/com/adobe/xmp/XMPConst.html
new file mode 100644
index 0000000..690c54e
--- /dev/null
+++ b/java/XMPCore/docs/com/adobe/xmp/XMPConst.html
@@ -0,0 +1,1227 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:49 CEST 2007 -->
+<TITLE>
+XMPConst
+</TITLE>
+
+<META NAME="keywords" CONTENT="com.adobe.xmp.XMPConst interface">
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="XMPConst";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="class-use/XMPConst.html"><FONT CLASS="NavBarFont1"><B>Use</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV CLASS&nbsp;
+&nbsp;<A HREF="../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../index.html?com/adobe/xmp/XMPConst.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPConst.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+ SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;<A HREF="#field_summary">FIELD</A>&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;METHOD</FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;<A HREF="#field_detail">FIELD</A>&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;METHOD</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<!-- ======== START OF CLASS DATA ======== -->
+<H2>
+<FONT SIZE="-1">
+com.adobe.xmp</FONT>
+<BR>
+Interface XMPConst</H2>
+<HR>
+<DL>
+<DT><PRE>public interface <B>XMPConst</B></DL>
+</PRE>
+
+<P>
+Common constants for the XMP Toolkit.
+<P>
+
+<P>
+<DL>
+<DT><B>Since:</B></DT>
+ <DD>20.01.2006</DD>
+</DL>
+<HR>
+
+<P>
+<!-- =========== FIELD SUMMARY =========== -->
+
+<A NAME="field_summary"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+<B>Field Summary</B></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPConst.html#ARRAY_ITEM_NAME">ARRAY_ITEM_NAME</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Node name of an array item.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPConst.html#ARRAY_LAST_ITEM">ARRAY_LAST_ITEM</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Index that has the meaning to be always the last item in an array.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPConst.html#FALSESTR">FALSESTR</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The canonical false string value for Booleans in serialized XMP.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPConst.html#NS_ADOBESTOCKPHOTO">NS_ADOBESTOCKPHOTO</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPConst.html#NS_ASF">NS_ASF</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPConst.html#NS_CAMERARAW">NS_CAMERARAW</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPConst.html#NS_DC">NS_DC</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The XML namespace for the Dublin Core schema.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPConst.html#NS_DC_DEPRECATED">NS_DC_DEPRECATED</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;legaciy dublin core NS, will be converted to NS_DC</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPConst.html#NS_DM">NS_DM</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPConst.html#NS_EXIF">NS_EXIF</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The XML namespace for Adobe's EXIF schema.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPConst.html#NS_EXIF_AUX">NS_EXIF_AUX</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPConst.html#NS_IPTCCORE">NS_IPTCCORE</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The XML namespace for the IPTC Core schema.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPConst.html#NS_IX">NS_IX</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPConst.html#NS_JP2K">NS_JP2K</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPConst.html#NS_JPEG">NS_JPEG</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPConst.html#NS_PDF">NS_PDF</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The XML namespace for the PDF schema.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPConst.html#NS_PDFA_EXTENSION">NS_PDFA_EXTENSION</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPConst.html#NS_PDFA_FIELD">NS_PDFA_FIELD</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPConst.html#NS_PDFA_ID">NS_PDFA_ID</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPConst.html#NS_PDFA_PROPERTY">NS_PDFA_PROPERTY</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPConst.html#NS_PDFA_SCHEMA">NS_PDFA_SCHEMA</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPConst.html#NS_PDFA_TYPE">NS_PDFA_TYPE</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPConst.html#NS_PDFX">NS_PDFX</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The XML namespace for the PDF schema.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPConst.html#NS_PDFX_ID">NS_PDFX_ID</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPConst.html#NS_PHOTOSHOP">NS_PHOTOSHOP</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The XML namespace for the Photoshop custom schema.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPConst.html#NS_PNG">NS_PNG</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPConst.html#NS_PSALBUM">NS_PSALBUM</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The XML namespace for the Photoshop Album schema.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPConst.html#NS_RDF">NS_RDF</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The XML namespace for RDF.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPConst.html#NS_TIFF">NS_TIFF</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The XML namespace for Adobe's TIFF schema.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPConst.html#NS_TRANSIENT">NS_TRANSIENT</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPConst.html#NS_WAV">NS_WAV</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPConst.html#NS_X">NS_X</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The XML namespace Adobe XMP Metadata.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPConst.html#NS_XML">NS_XML</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The XML namespace for XML.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPConst.html#NS_XMP">NS_XMP</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The XML namespace for the XMP "basic" schema.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPConst.html#NS_XMP_BJ">NS_XMP_BJ</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The XML namespace for the job management schema.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPConst.html#NS_XMP_MM">NS_XMP_MM</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The XML namespace for the XMP digital asset management schema.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPConst.html#NS_XMP_NOTE">NS_XMP_NOTE</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The XML namespace for the job management schema.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPConst.html#NS_XMP_RIGHTS">NS_XMP_RIGHTS</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The XML namespace for the XMP copyright schema.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPConst.html#RDF_TYPE">RDF_TYPE</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rdf:type qualfifier</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPConst.html#TRUESTR">TRUESTR</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The canonical true string value for Booleans in serialized XMP.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPConst.html#TYPE_DIMENSIONS">TYPE_DIMENSIONS</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The XML namespace for fields of the Dimensions type.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPConst.html#TYPE_FONT">TYPE_FONT</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPConst.html#TYPE_GRAPHICS">TYPE_GRAPHICS</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPConst.html#TYPE_IDENTIFIERQUAL">TYPE_IDENTIFIERQUAL</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The XML namespace for qualifiers of the xmp:Identifier property.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPConst.html#TYPE_IMAGE">TYPE_IMAGE</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The XML namespace for fields of a graphical image.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPConst.html#TYPE_MANIFESTITEM">TYPE_MANIFESTITEM</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPConst.html#TYPE_PAGEDFILE">TYPE_PAGEDFILE</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPConst.html#TYPE_RESOURCEEVENT">TYPE_RESOURCEEVENT</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The XML namespace for fields of the ResourceEvent type.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPConst.html#TYPE_RESOURCEREF">TYPE_RESOURCEREF</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The XML namespace for fields of the ResourceRef type.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPConst.html#TYPE_ST_JOB">TYPE_ST_JOB</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The XML namespace for fields of the JobRef type.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPConst.html#TYPE_ST_VERSION">TYPE_ST_VERSION</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The XML namespace for fields of the Version type.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPConst.html#TYPE_TEXT">TYPE_TEXT</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPConst.html#X_DEFAULT">X_DEFAULT</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The x-default string for localized properties</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPConst.html#XML_LANG">XML_LANG</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;xml:lang qualfifier</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<!-- ============ FIELD DETAIL =========== -->
+
+<A NAME="field_detail"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="1"><FONT SIZE="+2">
+<B>Field Detail</B></FONT></TH>
+</TR>
+</TABLE>
+
+<A NAME="NS_XML"><!-- --></A><H3>
+NS_XML</H3>
+<PRE>
+static final java.lang.String <B>NS_XML</B></PRE>
+<DL>
+<DD>The XML namespace for XML.
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPConst.NS_XML">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="NS_RDF"><!-- --></A><H3>
+NS_RDF</H3>
+<PRE>
+static final java.lang.String <B>NS_RDF</B></PRE>
+<DL>
+<DD>The XML namespace for RDF.
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPConst.NS_RDF">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="NS_DC"><!-- --></A><H3>
+NS_DC</H3>
+<PRE>
+static final java.lang.String <B>NS_DC</B></PRE>
+<DL>
+<DD>The XML namespace for the Dublin Core schema.
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPConst.NS_DC">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="NS_IPTCCORE"><!-- --></A><H3>
+NS_IPTCCORE</H3>
+<PRE>
+static final java.lang.String <B>NS_IPTCCORE</B></PRE>
+<DL>
+<DD>The XML namespace for the IPTC Core schema.
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPConst.NS_IPTCCORE">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="NS_X"><!-- --></A><H3>
+NS_X</H3>
+<PRE>
+static final java.lang.String <B>NS_X</B></PRE>
+<DL>
+<DD>The XML namespace Adobe XMP Metadata.
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPConst.NS_X">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="NS_IX"><!-- --></A><H3>
+NS_IX</H3>
+<PRE>
+static final java.lang.String <B>NS_IX</B></PRE>
+<DL>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPConst.NS_IX">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="NS_XMP"><!-- --></A><H3>
+NS_XMP</H3>
+<PRE>
+static final java.lang.String <B>NS_XMP</B></PRE>
+<DL>
+<DD>The XML namespace for the XMP "basic" schema.
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPConst.NS_XMP">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="NS_XMP_RIGHTS"><!-- --></A><H3>
+NS_XMP_RIGHTS</H3>
+<PRE>
+static final java.lang.String <B>NS_XMP_RIGHTS</B></PRE>
+<DL>
+<DD>The XML namespace for the XMP copyright schema.
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPConst.NS_XMP_RIGHTS">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="NS_XMP_MM"><!-- --></A><H3>
+NS_XMP_MM</H3>
+<PRE>
+static final java.lang.String <B>NS_XMP_MM</B></PRE>
+<DL>
+<DD>The XML namespace for the XMP digital asset management schema.
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPConst.NS_XMP_MM">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="NS_XMP_BJ"><!-- --></A><H3>
+NS_XMP_BJ</H3>
+<PRE>
+static final java.lang.String <B>NS_XMP_BJ</B></PRE>
+<DL>
+<DD>The XML namespace for the job management schema.
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPConst.NS_XMP_BJ">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="NS_XMP_NOTE"><!-- --></A><H3>
+NS_XMP_NOTE</H3>
+<PRE>
+static final java.lang.String <B>NS_XMP_NOTE</B></PRE>
+<DL>
+<DD>The XML namespace for the job management schema.
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPConst.NS_XMP_NOTE">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="NS_PDF"><!-- --></A><H3>
+NS_PDF</H3>
+<PRE>
+static final java.lang.String <B>NS_PDF</B></PRE>
+<DL>
+<DD>The XML namespace for the PDF schema.
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPConst.NS_PDF">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="NS_PDFX"><!-- --></A><H3>
+NS_PDFX</H3>
+<PRE>
+static final java.lang.String <B>NS_PDFX</B></PRE>
+<DL>
+<DD>The XML namespace for the PDF schema.
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPConst.NS_PDFX">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="NS_PDFX_ID"><!-- --></A><H3>
+NS_PDFX_ID</H3>
+<PRE>
+static final java.lang.String <B>NS_PDFX_ID</B></PRE>
+<DL>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPConst.NS_PDFX_ID">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="NS_PDFA_SCHEMA"><!-- --></A><H3>
+NS_PDFA_SCHEMA</H3>
+<PRE>
+static final java.lang.String <B>NS_PDFA_SCHEMA</B></PRE>
+<DL>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPConst.NS_PDFA_SCHEMA">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="NS_PDFA_PROPERTY"><!-- --></A><H3>
+NS_PDFA_PROPERTY</H3>
+<PRE>
+static final java.lang.String <B>NS_PDFA_PROPERTY</B></PRE>
+<DL>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPConst.NS_PDFA_PROPERTY">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="NS_PDFA_TYPE"><!-- --></A><H3>
+NS_PDFA_TYPE</H3>
+<PRE>
+static final java.lang.String <B>NS_PDFA_TYPE</B></PRE>
+<DL>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPConst.NS_PDFA_TYPE">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="NS_PDFA_FIELD"><!-- --></A><H3>
+NS_PDFA_FIELD</H3>
+<PRE>
+static final java.lang.String <B>NS_PDFA_FIELD</B></PRE>
+<DL>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPConst.NS_PDFA_FIELD">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="NS_PDFA_ID"><!-- --></A><H3>
+NS_PDFA_ID</H3>
+<PRE>
+static final java.lang.String <B>NS_PDFA_ID</B></PRE>
+<DL>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPConst.NS_PDFA_ID">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="NS_PDFA_EXTENSION"><!-- --></A><H3>
+NS_PDFA_EXTENSION</H3>
+<PRE>
+static final java.lang.String <B>NS_PDFA_EXTENSION</B></PRE>
+<DL>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPConst.NS_PDFA_EXTENSION">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="NS_PHOTOSHOP"><!-- --></A><H3>
+NS_PHOTOSHOP</H3>
+<PRE>
+static final java.lang.String <B>NS_PHOTOSHOP</B></PRE>
+<DL>
+<DD>The XML namespace for the Photoshop custom schema.
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPConst.NS_PHOTOSHOP">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="NS_PSALBUM"><!-- --></A><H3>
+NS_PSALBUM</H3>
+<PRE>
+static final java.lang.String <B>NS_PSALBUM</B></PRE>
+<DL>
+<DD>The XML namespace for the Photoshop Album schema.
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPConst.NS_PSALBUM">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="NS_EXIF"><!-- --></A><H3>
+NS_EXIF</H3>
+<PRE>
+static final java.lang.String <B>NS_EXIF</B></PRE>
+<DL>
+<DD>The XML namespace for Adobe's EXIF schema.
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPConst.NS_EXIF">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="NS_EXIF_AUX"><!-- --></A><H3>
+NS_EXIF_AUX</H3>
+<PRE>
+static final java.lang.String <B>NS_EXIF_AUX</B></PRE>
+<DL>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPConst.NS_EXIF_AUX">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="NS_TIFF"><!-- --></A><H3>
+NS_TIFF</H3>
+<PRE>
+static final java.lang.String <B>NS_TIFF</B></PRE>
+<DL>
+<DD>The XML namespace for Adobe's TIFF schema.
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPConst.NS_TIFF">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="NS_PNG"><!-- --></A><H3>
+NS_PNG</H3>
+<PRE>
+static final java.lang.String <B>NS_PNG</B></PRE>
+<DL>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPConst.NS_PNG">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="NS_JPEG"><!-- --></A><H3>
+NS_JPEG</H3>
+<PRE>
+static final java.lang.String <B>NS_JPEG</B></PRE>
+<DL>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPConst.NS_JPEG">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="NS_JP2K"><!-- --></A><H3>
+NS_JP2K</H3>
+<PRE>
+static final java.lang.String <B>NS_JP2K</B></PRE>
+<DL>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPConst.NS_JP2K">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="NS_CAMERARAW"><!-- --></A><H3>
+NS_CAMERARAW</H3>
+<PRE>
+static final java.lang.String <B>NS_CAMERARAW</B></PRE>
+<DL>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPConst.NS_CAMERARAW">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="NS_ADOBESTOCKPHOTO"><!-- --></A><H3>
+NS_ADOBESTOCKPHOTO</H3>
+<PRE>
+static final java.lang.String <B>NS_ADOBESTOCKPHOTO</B></PRE>
+<DL>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPConst.NS_ADOBESTOCKPHOTO">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="NS_ASF"><!-- --></A><H3>
+NS_ASF</H3>
+<PRE>
+static final java.lang.String <B>NS_ASF</B></PRE>
+<DL>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPConst.NS_ASF">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="NS_WAV"><!-- --></A><H3>
+NS_WAV</H3>
+<PRE>
+static final java.lang.String <B>NS_WAV</B></PRE>
+<DL>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPConst.NS_WAV">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="NS_DM"><!-- --></A><H3>
+NS_DM</H3>
+<PRE>
+static final java.lang.String <B>NS_DM</B></PRE>
+<DL>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPConst.NS_DM">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="NS_TRANSIENT"><!-- --></A><H3>
+NS_TRANSIENT</H3>
+<PRE>
+static final java.lang.String <B>NS_TRANSIENT</B></PRE>
+<DL>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPConst.NS_TRANSIENT">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="TYPE_IDENTIFIERQUAL"><!-- --></A><H3>
+TYPE_IDENTIFIERQUAL</H3>
+<PRE>
+static final java.lang.String <B>TYPE_IDENTIFIERQUAL</B></PRE>
+<DL>
+<DD>The XML namespace for qualifiers of the xmp:Identifier property.
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPConst.TYPE_IDENTIFIERQUAL">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="TYPE_DIMENSIONS"><!-- --></A><H3>
+TYPE_DIMENSIONS</H3>
+<PRE>
+static final java.lang.String <B>TYPE_DIMENSIONS</B></PRE>
+<DL>
+<DD>The XML namespace for fields of the Dimensions type.
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPConst.TYPE_DIMENSIONS">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="TYPE_TEXT"><!-- --></A><H3>
+TYPE_TEXT</H3>
+<PRE>
+static final java.lang.String <B>TYPE_TEXT</B></PRE>
+<DL>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPConst.TYPE_TEXT">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="TYPE_PAGEDFILE"><!-- --></A><H3>
+TYPE_PAGEDFILE</H3>
+<PRE>
+static final java.lang.String <B>TYPE_PAGEDFILE</B></PRE>
+<DL>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPConst.TYPE_PAGEDFILE">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="TYPE_GRAPHICS"><!-- --></A><H3>
+TYPE_GRAPHICS</H3>
+<PRE>
+static final java.lang.String <B>TYPE_GRAPHICS</B></PRE>
+<DL>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPConst.TYPE_GRAPHICS">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="TYPE_IMAGE"><!-- --></A><H3>
+TYPE_IMAGE</H3>
+<PRE>
+static final java.lang.String <B>TYPE_IMAGE</B></PRE>
+<DL>
+<DD>The XML namespace for fields of a graphical image. Used for the Thumbnail type.
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPConst.TYPE_IMAGE">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="TYPE_FONT"><!-- --></A><H3>
+TYPE_FONT</H3>
+<PRE>
+static final java.lang.String <B>TYPE_FONT</B></PRE>
+<DL>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPConst.TYPE_FONT">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="TYPE_RESOURCEEVENT"><!-- --></A><H3>
+TYPE_RESOURCEEVENT</H3>
+<PRE>
+static final java.lang.String <B>TYPE_RESOURCEEVENT</B></PRE>
+<DL>
+<DD>The XML namespace for fields of the ResourceEvent type.
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPConst.TYPE_RESOURCEEVENT">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="TYPE_RESOURCEREF"><!-- --></A><H3>
+TYPE_RESOURCEREF</H3>
+<PRE>
+static final java.lang.String <B>TYPE_RESOURCEREF</B></PRE>
+<DL>
+<DD>The XML namespace for fields of the ResourceRef type.
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPConst.TYPE_RESOURCEREF">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="TYPE_ST_VERSION"><!-- --></A><H3>
+TYPE_ST_VERSION</H3>
+<PRE>
+static final java.lang.String <B>TYPE_ST_VERSION</B></PRE>
+<DL>
+<DD>The XML namespace for fields of the Version type.
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPConst.TYPE_ST_VERSION">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="TYPE_ST_JOB"><!-- --></A><H3>
+TYPE_ST_JOB</H3>
+<PRE>
+static final java.lang.String <B>TYPE_ST_JOB</B></PRE>
+<DL>
+<DD>The XML namespace for fields of the JobRef type.
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPConst.TYPE_ST_JOB">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="TYPE_MANIFESTITEM"><!-- --></A><H3>
+TYPE_MANIFESTITEM</H3>
+<PRE>
+static final java.lang.String <B>TYPE_MANIFESTITEM</B></PRE>
+<DL>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPConst.TYPE_MANIFESTITEM">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="TRUESTR"><!-- --></A><H3>
+TRUESTR</H3>
+<PRE>
+static final java.lang.String <B>TRUESTR</B></PRE>
+<DL>
+<DD>The canonical true string value for Booleans in serialized XMP. Code that converts from the
+ string to a bool should be case insensitive, and even allow "1".
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPConst.TRUESTR">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="FALSESTR"><!-- --></A><H3>
+FALSESTR</H3>
+<PRE>
+static final java.lang.String <B>FALSESTR</B></PRE>
+<DL>
+<DD>The canonical false string value for Booleans in serialized XMP. Code that converts from the
+ string to a bool should be case insensitive, and even allow "0".
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPConst.FALSESTR">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="ARRAY_LAST_ITEM"><!-- --></A><H3>
+ARRAY_LAST_ITEM</H3>
+<PRE>
+static final int <B>ARRAY_LAST_ITEM</B></PRE>
+<DL>
+<DD>Index that has the meaning to be always the last item in an array.
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPConst.ARRAY_LAST_ITEM">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="ARRAY_ITEM_NAME"><!-- --></A><H3>
+ARRAY_ITEM_NAME</H3>
+<PRE>
+static final java.lang.String <B>ARRAY_ITEM_NAME</B></PRE>
+<DL>
+<DD>Node name of an array item.
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPConst.ARRAY_ITEM_NAME">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="X_DEFAULT"><!-- --></A><H3>
+X_DEFAULT</H3>
+<PRE>
+static final java.lang.String <B>X_DEFAULT</B></PRE>
+<DL>
+<DD>The x-default string for localized properties
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPConst.X_DEFAULT">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="XML_LANG"><!-- --></A><H3>
+XML_LANG</H3>
+<PRE>
+static final java.lang.String <B>XML_LANG</B></PRE>
+<DL>
+<DD>xml:lang qualfifier
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPConst.XML_LANG">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="RDF_TYPE"><!-- --></A><H3>
+RDF_TYPE</H3>
+<PRE>
+static final java.lang.String <B>RDF_TYPE</B></PRE>
+<DL>
+<DD>rdf:type qualfifier
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPConst.RDF_TYPE">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="NS_DC_DEPRECATED"><!-- --></A><H3>
+NS_DC_DEPRECATED</H3>
+<PRE>
+static final java.lang.String <B>NS_DC_DEPRECATED</B></PRE>
+<DL>
+<DD>legaciy dublin core NS, will be converted to NS_DC
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPConst.NS_DC_DEPRECATED">Constant Field Values</A></DL>
+</DL>
+<!-- ========= END OF CLASS DATA ========= -->
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="class-use/XMPConst.html"><FONT CLASS="NavBarFont1"><B>Use</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV CLASS&nbsp;
+&nbsp;<A HREF="../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../index.html?com/adobe/xmp/XMPConst.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPConst.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+ SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;<A HREF="#field_summary">FIELD</A>&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;METHOD</FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;<A HREF="#field_detail">FIELD</A>&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;METHOD</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/com/adobe/xmp/XMPDateTime.html b/java/XMPCore/docs/com/adobe/xmp/XMPDateTime.html
new file mode 100644
index 0000000..8c89d97
--- /dev/null
+++ b/java/XMPCore/docs/com/adobe/xmp/XMPDateTime.html
@@ -0,0 +1,624 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:49 CEST 2007 -->
+<TITLE>
+XMPDateTime
+</TITLE>
+
+<META NAME="keywords" CONTENT="com.adobe.xmp.XMPDateTime interface">
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="XMPDateTime";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="class-use/XMPDateTime.html"><FONT CLASS="NavBarFont1"><B>Use</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="../../../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;<A HREF="../../../com/adobe/xmp/XMPDateTimeFactory.html" title="class in com.adobe.xmp"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../index.html?com/adobe/xmp/XMPDateTime.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPDateTime.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+ SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;FIELD&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;FIELD&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<!-- ======== START OF CLASS DATA ======== -->
+<H2>
+<FONT SIZE="-1">
+com.adobe.xmp</FONT>
+<BR>
+Interface XMPDateTime</H2>
+<DL>
+<DT><B>All Superinterfaces:</B> <DD>java.lang.Comparable</DD>
+</DL>
+<HR>
+<DL>
+<DT><PRE>public interface <B>XMPDateTime</B><DT>extends java.lang.Comparable</DL>
+</PRE>
+
+<P>
+The <code>XMPDateTime</code>-class represents a point in time up to a resolution of nano
+ seconds. Dates and time in the serialized XMP are ISO 8601 strings. There are utility functions
+ to convert to the ISO format, a <code>Calendar</code> or get the Timezone. The fields of
+ <code>XMPDateTime</code> are:
+ <ul>
+ <li> month - The month in the range 1..12.
+ <li> day - The day of the month in the range 1..31.
+ <li> minute - The minute in the range 0..59.
+ <li> hour - The time zone hour in the range 0..23.
+ <li> minute - The time zone minute in the range 0..59.
+ <li> nanoSecond - The nano seconds within a second. <em>Note:</em> if the XMPDateTime is
+ converted into a calendar, the resolution is reduced to milli seconds.
+ <li> timeZone - a <code>TimeZone</code>-object.
+ </ul>
+ DateTime values are occasionally used in cases with only a date or only a time component. A date
+ without a time has zeros for all the time fields. A time without a date has zeros for all date
+ fields (year, month, and day).
+<P>
+
+<P>
+<HR>
+
+<P>
+
+<!-- ========== METHOD SUMMARY =========== -->
+
+<A NAME="method_summary"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+<B>Method Summary</B></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.util.Calendar</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPDateTime.html#getCalendar()">getCalendar</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPDateTime.html#getDay()">getDay</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPDateTime.html#getHour()">getHour</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPDateTime.html#getISO8601String()">getISO8601String</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPDateTime.html#getMinute()">getMinute</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPDateTime.html#getMonth()">getMonth</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPDateTime.html#getNanoSecond()">getNanoSecond</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPDateTime.html#getSecond()">getSecond</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.util.TimeZone</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPDateTime.html#getTimeZone()">getTimeZone</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPDateTime.html#getYear()">getYear</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPDateTime.html#setDay(int)">setDay</A></B>(int&nbsp;day)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPDateTime.html#setHour(int)">setHour</A></B>(int&nbsp;hour)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPDateTime.html#setMinute(int)">setMinute</A></B>(int&nbsp;minute)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPDateTime.html#setMonth(int)">setMonth</A></B>(int&nbsp;month)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPDateTime.html#setNanoSecond(int)">setNanoSecond</A></B>(int&nbsp;nanoSecond)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPDateTime.html#setSecond(int)">setSecond</A></B>(int&nbsp;second)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPDateTime.html#setTimeZone(java.util.TimeZone)">setTimeZone</A></B>(java.util.TimeZone&nbsp;tz)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPDateTime.html#setYear(int)">setYear</A></B>(int&nbsp;year)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;<A NAME="methods_inherited_from_class_java.lang.Comparable"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#EEEEFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="left"><B>Methods inherited from interface java.lang.Comparable</B></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE>compareTo</CODE></TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<!-- ============ METHOD DETAIL ========== -->
+
+<A NAME="method_detail"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="1"><FONT SIZE="+2">
+<B>Method Detail</B></FONT></TH>
+</TR>
+</TABLE>
+
+<A NAME="getYear()"><!-- --></A><H3>
+getYear</H3>
+<PRE>
+int <B>getYear</B>()</PRE>
+<DL>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns the year, can be negative.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setYear(int)"><!-- --></A><H3>
+setYear</H3>
+<PRE>
+void <B>setYear</B>(int&nbsp;year)</PRE>
+<DL>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>year</CODE> - Sets the year</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getMonth()"><!-- --></A><H3>
+getMonth</H3>
+<PRE>
+int <B>getMonth</B>()</PRE>
+<DL>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns The month in the range 1..12.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setMonth(int)"><!-- --></A><H3>
+setMonth</H3>
+<PRE>
+void <B>setMonth</B>(int&nbsp;month)</PRE>
+<DL>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>month</CODE> - Sets the month 1..12</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getDay()"><!-- --></A><H3>
+getDay</H3>
+<PRE>
+int <B>getDay</B>()</PRE>
+<DL>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns the day of the month in the range 1..31.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setDay(int)"><!-- --></A><H3>
+setDay</H3>
+<PRE>
+void <B>setDay</B>(int&nbsp;day)</PRE>
+<DL>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>day</CODE> - Sets the day 1..31</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getHour()"><!-- --></A><H3>
+getHour</H3>
+<PRE>
+int <B>getHour</B>()</PRE>
+<DL>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns hour - The hour in the range 0..23.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setHour(int)"><!-- --></A><H3>
+setHour</H3>
+<PRE>
+void <B>setHour</B>(int&nbsp;hour)</PRE>
+<DL>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>hour</CODE> - Sets the hour in the range 0..23.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getMinute()"><!-- --></A><H3>
+getMinute</H3>
+<PRE>
+int <B>getMinute</B>()</PRE>
+<DL>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns the minute in the range 0..59.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setMinute(int)"><!-- --></A><H3>
+setMinute</H3>
+<PRE>
+void <B>setMinute</B>(int&nbsp;minute)</PRE>
+<DL>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>minute</CODE> - Sets the minute in the range 0..59.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getSecond()"><!-- --></A><H3>
+getSecond</H3>
+<PRE>
+int <B>getSecond</B>()</PRE>
+<DL>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns the second in the range 0..59.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setSecond(int)"><!-- --></A><H3>
+setSecond</H3>
+<PRE>
+void <B>setSecond</B>(int&nbsp;second)</PRE>
+<DL>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>second</CODE> - Sets the second in the range 0..59.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getNanoSecond()"><!-- --></A><H3>
+getNanoSecond</H3>
+<PRE>
+int <B>getNanoSecond</B>()</PRE>
+<DL>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns milli-, micro- and nano seconds.
+ Nanoseconds within a second, often left as zero?</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setNanoSecond(int)"><!-- --></A><H3>
+setNanoSecond</H3>
+<PRE>
+void <B>setNanoSecond</B>(int&nbsp;nanoSecond)</PRE>
+<DL>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>nanoSecond</CODE> - Sets the milli-, micro- and nano seconds.
+ Granularity goes down to milli seconds.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getTimeZone()"><!-- --></A><H3>
+getTimeZone</H3>
+<PRE>
+java.util.TimeZone <B>getTimeZone</B>()</PRE>
+<DL>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns the time zone.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setTimeZone(java.util.TimeZone)"><!-- --></A><H3>
+setTimeZone</H3>
+<PRE>
+void <B>setTimeZone</B>(java.util.TimeZone&nbsp;tz)</PRE>
+<DL>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>tz</CODE> - a time zone to set</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getCalendar()"><!-- --></A><H3>
+getCalendar</H3>
+<PRE>
+java.util.Calendar <B>getCalendar</B>()</PRE>
+<DL>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns a calendar (only with milli second precision).</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getISO8601String()"><!-- --></A><H3>
+getISO8601String</H3>
+<PRE>
+java.lang.String <B>getISO8601String</B>()</PRE>
+<DL>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns the ISO 8601 string representation of the date and time.</DL>
+</DD>
+</DL>
+<!-- ========= END OF CLASS DATA ========= -->
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="class-use/XMPDateTime.html"><FONT CLASS="NavBarFont1"><B>Use</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="../../../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;<A HREF="../../../com/adobe/xmp/XMPDateTimeFactory.html" title="class in com.adobe.xmp"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../index.html?com/adobe/xmp/XMPDateTime.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPDateTime.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+ SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;FIELD&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;FIELD&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/com/adobe/xmp/XMPDateTimeFactory.html b/java/XMPCore/docs/com/adobe/xmp/XMPDateTimeFactory.html
new file mode 100644
index 0000000..ba3b8ee
--- /dev/null
+++ b/java/XMPCore/docs/com/adobe/xmp/XMPDateTimeFactory.html
@@ -0,0 +1,381 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:49 CEST 2007 -->
+<TITLE>
+XMPDateTimeFactory
+</TITLE>
+
+<META NAME="keywords" CONTENT="com.adobe.xmp.XMPDateTimeFactory class">
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="XMPDateTimeFactory";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="class-use/XMPDateTimeFactory.html"><FONT CLASS="NavBarFont1"><B>Use</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;<A HREF="../../../com/adobe/xmp/XMPError.html" title="interface in com.adobe.xmp"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../index.html?com/adobe/xmp/XMPDateTimeFactory.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPDateTimeFactory.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+ SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;FIELD&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;FIELD&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<!-- ======== START OF CLASS DATA ======== -->
+<H2>
+<FONT SIZE="-1">
+com.adobe.xmp</FONT>
+<BR>
+Class XMPDateTimeFactory</H2>
+<PRE>
+java.lang.Object
+ <IMG SRC="../../../resources/inherit.gif" ALT="extended by "><B>com.adobe.xmp.XMPDateTimeFactory</B>
+</PRE>
+<HR>
+<DL>
+<DT><PRE>public final class <B>XMPDateTimeFactory</B><DT>extends java.lang.Object</DL>
+</PRE>
+
+<P>
+A factory to create <code>XMPDateTime</code>-instances from a <code>Calendar</code> or an
+ ISO 8601 string or for the current time.
+<P>
+
+<P>
+<DL>
+<DT><B>Since:</B></DT>
+ <DD>16.02.2006</DD>
+</DL>
+<HR>
+
+<P>
+
+<!-- ========== METHOD SUMMARY =========== -->
+
+<A NAME="method_summary"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+<B>Method Summary</B></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;<A HREF="../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPDateTimeFactory.html#convertToLocalTime(com.adobe.xmp.XMPDateTime)">convertToLocalTime</A></B>(<A HREF="../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A>&nbsp;dateTime)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Make sure a time is local.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;<A HREF="../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPDateTimeFactory.html#convertToUTCTime(com.adobe.xmp.XMPDateTime)">convertToUTCTime</A></B>(<A HREF="../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A>&nbsp;dateTime)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Make sure a time is UTC.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;<A HREF="../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPDateTimeFactory.html#create(int, int, int, int, int, int, int)">create</A></B>(int&nbsp;year,
+ int&nbsp;month,
+ int&nbsp;day,
+ int&nbsp;hour,
+ int&nbsp;minute,
+ int&nbsp;second,
+ int&nbsp;nanoSecond)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Creates an <code>XMPDateTime</code>-object from initial values.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;<A HREF="../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPDateTimeFactory.html#createFromCalendar(java.util.Calendar)">createFromCalendar</A></B>(java.util.Calendar&nbsp;calendar)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Creates an <code>XMPDateTime</code> from a <code>Calendar</code>-object.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;<A HREF="../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPDateTimeFactory.html#createFromISO8601(java.lang.String)">createFromISO8601</A></B>(java.lang.String&nbsp;strValue)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Creates an <code>XMPDateTime</code> from an ISO 8601 string.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;<A HREF="../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPDateTimeFactory.html#getCurrentDateTime()">getCurrentDateTime</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Obtain the current date and time.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;<A HREF="../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPDateTimeFactory.html#setLocalTimeZone(com.adobe.xmp.XMPDateTime)">setLocalTimeZone</A></B>(<A HREF="../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A>&nbsp;dateTime)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sets the local time zone without touching any other Any existing time zone value is replaced,
+ the other date/time fields are not adjusted in any way.</TD>
+</TR>
+</TABLE>
+&nbsp;<A NAME="methods_inherited_from_class_java.lang.Object"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#EEEEFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="left"><B>Methods inherited from class java.lang.Object</B></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE>equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait</CODE></TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<!-- ============ METHOD DETAIL ========== -->
+
+<A NAME="method_detail"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="1"><FONT SIZE="+2">
+<B>Method Detail</B></FONT></TH>
+</TR>
+</TABLE>
+
+<A NAME="createFromCalendar(java.util.Calendar)"><!-- --></A><H3>
+createFromCalendar</H3>
+<PRE>
+public static <A HREF="../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A> <B>createFromCalendar</B>(java.util.Calendar&nbsp;calendar)</PRE>
+<DL>
+<DD>Creates an <code>XMPDateTime</code> from a <code>Calendar</code>-object.
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>calendar</CODE> - a <code>Calendar</code>-object.
+<DT><B>Returns:</B><DD>An <code>XMPDateTime</code>-object.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="create(int, int, int, int, int, int, int)"><!-- --></A><H3>
+create</H3>
+<PRE>
+public static <A HREF="../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A> <B>create</B>(int&nbsp;year,
+ int&nbsp;month,
+ int&nbsp;day,
+ int&nbsp;hour,
+ int&nbsp;minute,
+ int&nbsp;second,
+ int&nbsp;nanoSecond)</PRE>
+<DL>
+<DD>Creates an <code>XMPDateTime</code>-object from initial values.
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>year</CODE> - years<DD><CODE>month</CODE> - months<DD><CODE>day</CODE> - days<DD><CODE>hour</CODE> - hours<DD><CODE>minute</CODE> - minutes<DD><CODE>second</CODE> - seconds<DD><CODE>nanoSecond</CODE> - nanoseconds
+<DT><B>Returns:</B><DD>Returns an <code>XMPDateTime</code>-object.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="createFromISO8601(java.lang.String)"><!-- --></A><H3>
+createFromISO8601</H3>
+<PRE>
+public static <A HREF="../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A> <B>createFromISO8601</B>(java.lang.String&nbsp;strValue)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Creates an <code>XMPDateTime</code> from an ISO 8601 string.
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>strValue</CODE> - The ISO 8601 string representation of the date/time.
+<DT><B>Returns:</B><DD>An <code>XMPDateTime</code>-object.
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - When the ISO 8601 string is non-conform</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getCurrentDateTime()"><!-- --></A><H3>
+getCurrentDateTime</H3>
+<PRE>
+public static <A HREF="../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A> <B>getCurrentDateTime</B>()</PRE>
+<DL>
+<DD>Obtain the current date and time.
+<P>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns The returned time is UTC, properly adjusted for the local time zone. The
+ resolution of the time is not guaranteed to be finer than seconds.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setLocalTimeZone(com.adobe.xmp.XMPDateTime)"><!-- --></A><H3>
+setLocalTimeZone</H3>
+<PRE>
+public static <A HREF="../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A> <B>setLocalTimeZone</B>(<A HREF="../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A>&nbsp;dateTime)</PRE>
+<DL>
+<DD>Sets the local time zone without touching any other Any existing time zone value is replaced,
+ the other date/time fields are not adjusted in any way.
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>dateTime</CODE> - the <code>XMPDateTime</code> variable containing the value to be modified.
+<DT><B>Returns:</B><DD>Returns an updated <code>XMPDateTime</code>-object.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="convertToUTCTime(com.adobe.xmp.XMPDateTime)"><!-- --></A><H3>
+convertToUTCTime</H3>
+<PRE>
+public static <A HREF="../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A> <B>convertToUTCTime</B>(<A HREF="../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A>&nbsp;dateTime)</PRE>
+<DL>
+<DD>Make sure a time is UTC. If the time zone is not UTC, the time is
+ adjusted and the time zone set to be UTC.
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>dateTime</CODE> - the <code>XMPDateTime</code> variable containing the time to
+ be modified.
+<DT><B>Returns:</B><DD>Returns an updated <code>XMPDateTime</code>-object.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="convertToLocalTime(com.adobe.xmp.XMPDateTime)"><!-- --></A><H3>
+convertToLocalTime</H3>
+<PRE>
+public static <A HREF="../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A> <B>convertToLocalTime</B>(<A HREF="../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A>&nbsp;dateTime)</PRE>
+<DL>
+<DD>Make sure a time is local. If the time zone is not the local zone, the time is adjusted and
+ the time zone set to be local.
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>dateTime</CODE> - the <code>XMPDateTime</code> variable containing the time to be modified.
+<DT><B>Returns:</B><DD>Returns an updated <code>XMPDateTime</code>-object.</DL>
+</DD>
+</DL>
+<!-- ========= END OF CLASS DATA ========= -->
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="class-use/XMPDateTimeFactory.html"><FONT CLASS="NavBarFont1"><B>Use</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;<A HREF="../../../com/adobe/xmp/XMPError.html" title="interface in com.adobe.xmp"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../index.html?com/adobe/xmp/XMPDateTimeFactory.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPDateTimeFactory.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+ SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;FIELD&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;FIELD&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/com/adobe/xmp/XMPError.html b/java/XMPCore/docs/com/adobe/xmp/XMPError.html
new file mode 100644
index 0000000..9cabd0d
--- /dev/null
+++ b/java/XMPCore/docs/com/adobe/xmp/XMPError.html
@@ -0,0 +1,423 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:49 CEST 2007 -->
+<TITLE>
+XMPError
+</TITLE>
+
+<META NAME="keywords" CONTENT="com.adobe.xmp.XMPError interface">
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="XMPError";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="class-use/XMPError.html"><FONT CLASS="NavBarFont1"><B>Use</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="../../../com/adobe/xmp/XMPDateTimeFactory.html" title="class in com.adobe.xmp"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;<A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../index.html?com/adobe/xmp/XMPError.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPError.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+ SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;<A HREF="#field_summary">FIELD</A>&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;METHOD</FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;<A HREF="#field_detail">FIELD</A>&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;METHOD</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<!-- ======== START OF CLASS DATA ======== -->
+<H2>
+<FONT SIZE="-1">
+com.adobe.xmp</FONT>
+<BR>
+Interface XMPError</H2>
+<HR>
+<DL>
+<DT><PRE>public interface <B>XMPError</B></DL>
+</PRE>
+
+<P>
+<DL>
+<DT><B>Since:</B></DT>
+ <DD>21.09.2006</DD>
+</DL>
+<HR>
+
+<P>
+<!-- =========== FIELD SUMMARY =========== -->
+
+<A NAME="field_summary"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+<B>Field Summary</B></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPError.html#BADINDEX">BADINDEX</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPError.html#BADOPTIONS">BADOPTIONS</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPError.html#BADPARAM">BADPARAM</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPError.html#BADRDF">BADRDF</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPError.html#BADSCHEMA">BADSCHEMA</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPError.html#BADSERIALIZE">BADSERIALIZE</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPError.html#BADSTREAM">BADSTREAM</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<em>Note:</em> This is an error code introduced by Java.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPError.html#BADVALUE">BADVALUE</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPError.html#BADXML">BADXML</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPError.html#BADXMP">BADXMP</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPError.html#BADXPATH">BADXPATH</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPError.html#INTERNALFAILURE">INTERNALFAILURE</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPError.html#UNKNOWN">UNKNOWN</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<!-- ============ FIELD DETAIL =========== -->
+
+<A NAME="field_detail"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="1"><FONT SIZE="+2">
+<B>Field Detail</B></FONT></TH>
+</TR>
+</TABLE>
+
+<A NAME="UNKNOWN"><!-- --></A><H3>
+UNKNOWN</H3>
+<PRE>
+static final int <B>UNKNOWN</B></PRE>
+<DL>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPError.UNKNOWN">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="BADPARAM"><!-- --></A><H3>
+BADPARAM</H3>
+<PRE>
+static final int <B>BADPARAM</B></PRE>
+<DL>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPError.BADPARAM">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="BADVALUE"><!-- --></A><H3>
+BADVALUE</H3>
+<PRE>
+static final int <B>BADVALUE</B></PRE>
+<DL>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPError.BADVALUE">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="INTERNALFAILURE"><!-- --></A><H3>
+INTERNALFAILURE</H3>
+<PRE>
+static final int <B>INTERNALFAILURE</B></PRE>
+<DL>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPError.INTERNALFAILURE">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="BADSCHEMA"><!-- --></A><H3>
+BADSCHEMA</H3>
+<PRE>
+static final int <B>BADSCHEMA</B></PRE>
+<DL>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPError.BADSCHEMA">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="BADXPATH"><!-- --></A><H3>
+BADXPATH</H3>
+<PRE>
+static final int <B>BADXPATH</B></PRE>
+<DL>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPError.BADXPATH">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="BADOPTIONS"><!-- --></A><H3>
+BADOPTIONS</H3>
+<PRE>
+static final int <B>BADOPTIONS</B></PRE>
+<DL>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPError.BADOPTIONS">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="BADINDEX"><!-- --></A><H3>
+BADINDEX</H3>
+<PRE>
+static final int <B>BADINDEX</B></PRE>
+<DL>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPError.BADINDEX">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="BADSERIALIZE"><!-- --></A><H3>
+BADSERIALIZE</H3>
+<PRE>
+static final int <B>BADSERIALIZE</B></PRE>
+<DL>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPError.BADSERIALIZE">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="BADXML"><!-- --></A><H3>
+BADXML</H3>
+<PRE>
+static final int <B>BADXML</B></PRE>
+<DL>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPError.BADXML">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="BADRDF"><!-- --></A><H3>
+BADRDF</H3>
+<PRE>
+static final int <B>BADRDF</B></PRE>
+<DL>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPError.BADRDF">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="BADXMP"><!-- --></A><H3>
+BADXMP</H3>
+<PRE>
+static final int <B>BADXMP</B></PRE>
+<DL>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPError.BADXMP">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="BADSTREAM"><!-- --></A><H3>
+BADSTREAM</H3>
+<PRE>
+static final int <B>BADSTREAM</B></PRE>
+<DL>
+<DD><em>Note:</em> This is an error code introduced by Java.
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../constant-values.html#com.adobe.xmp.XMPError.BADSTREAM">Constant Field Values</A></DL>
+</DL>
+<!-- ========= END OF CLASS DATA ========= -->
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="class-use/XMPError.html"><FONT CLASS="NavBarFont1"><B>Use</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="../../../com/adobe/xmp/XMPDateTimeFactory.html" title="class in com.adobe.xmp"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;<A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../index.html?com/adobe/xmp/XMPError.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPError.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+ SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;<A HREF="#field_summary">FIELD</A>&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;METHOD</FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;<A HREF="#field_detail">FIELD</A>&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;METHOD</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/com/adobe/xmp/XMPException.html b/java/XMPCore/docs/com/adobe/xmp/XMPException.html
new file mode 100644
index 0000000..d2c4f13
--- /dev/null
+++ b/java/XMPCore/docs/com/adobe/xmp/XMPException.html
@@ -0,0 +1,300 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:49 CEST 2007 -->
+<TITLE>
+XMPException
+</TITLE>
+
+<META NAME="keywords" CONTENT="com.adobe.xmp.XMPException class">
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="XMPException";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="class-use/XMPException.html"><FONT CLASS="NavBarFont1"><B>Use</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="../../../com/adobe/xmp/XMPError.html" title="interface in com.adobe.xmp"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;<A HREF="../../../com/adobe/xmp/XMPIterator.html" title="interface in com.adobe.xmp"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../index.html?com/adobe/xmp/XMPException.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPException.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+ SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;FIELD&nbsp;|&nbsp;<A HREF="#constructor_summary">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;FIELD&nbsp;|&nbsp;<A HREF="#constructor_detail">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<!-- ======== START OF CLASS DATA ======== -->
+<H2>
+<FONT SIZE="-1">
+com.adobe.xmp</FONT>
+<BR>
+Class XMPException</H2>
+<PRE>
+java.lang.Object
+ <IMG SRC="../../../resources/inherit.gif" ALT="extended by ">java.lang.Throwable
+ <IMG SRC="../../../resources/inherit.gif" ALT="extended by ">java.lang.Exception
+ <IMG SRC="../../../resources/inherit.gif" ALT="extended by "><B>com.adobe.xmp.XMPException</B>
+</PRE>
+<DL>
+<DT><B>All Implemented Interfaces:</B> <DD>java.io.Serializable</DD>
+</DL>
+<HR>
+<DL>
+<DT><PRE>public class <B>XMPException</B><DT>extends java.lang.Exception</DL>
+</PRE>
+
+<P>
+This exception wraps all errors that occur in the XMP Toolkit.
+<P>
+
+<P>
+<DL>
+<DT><B>Since:</B></DT>
+ <DD>16.02.2006</DD>
+<DT><B>See Also:</B><DD><A HREF="../../../serialized-form.html#com.adobe.xmp.XMPException">Serialized Form</A></DL>
+<HR>
+
+<P>
+
+<!-- ======== CONSTRUCTOR SUMMARY ======== -->
+
+<A NAME="constructor_summary"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+<B>Constructor Summary</B></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPException.html#XMPException(java.lang.String, int)">XMPException</A></B>(java.lang.String&nbsp;message,
+ int&nbsp;errorCode)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Constructs an exception with a message and an error code.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPException.html#XMPException(java.lang.String, int, java.lang.Throwable)">XMPException</A></B>(java.lang.String&nbsp;message,
+ int&nbsp;errorCode,
+ java.lang.Throwable&nbsp;t)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Constructs an exception with a message, an error code and a <code>Throwable</code></TD>
+</TR>
+</TABLE>
+&nbsp;
+<!-- ========== METHOD SUMMARY =========== -->
+
+<A NAME="method_summary"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+<B>Method Summary</B></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPException.html#getErrorCode()">getErrorCode</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;<A NAME="methods_inherited_from_class_java.lang.Throwable"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#EEEEFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="left"><B>Methods inherited from class java.lang.Throwable</B></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE>fillInStackTrace, getCause, getLocalizedMessage, getMessage, getStackTrace, initCause, printStackTrace, printStackTrace, printStackTrace, setStackTrace, toString</CODE></TD>
+</TR>
+</TABLE>
+&nbsp;<A NAME="methods_inherited_from_class_java.lang.Object"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#EEEEFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="left"><B>Methods inherited from class java.lang.Object</B></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE>equals, getClass, hashCode, notify, notifyAll, wait, wait, wait</CODE></TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<!-- ========= CONSTRUCTOR DETAIL ======== -->
+
+<A NAME="constructor_detail"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="1"><FONT SIZE="+2">
+<B>Constructor Detail</B></FONT></TH>
+</TR>
+</TABLE>
+
+<A NAME="XMPException(java.lang.String, int)"><!-- --></A><H3>
+XMPException</H3>
+<PRE>
+public <B>XMPException</B>(java.lang.String&nbsp;message,
+ int&nbsp;errorCode)</PRE>
+<DL>
+<DD>Constructs an exception with a message and an error code.
+<P>
+<DL>
+<DT><B>Parameters:</B><DD><CODE>message</CODE> - the message<DD><CODE>errorCode</CODE> - the error code</DL>
+</DL>
+<HR>
+
+<A NAME="XMPException(java.lang.String, int, java.lang.Throwable)"><!-- --></A><H3>
+XMPException</H3>
+<PRE>
+public <B>XMPException</B>(java.lang.String&nbsp;message,
+ int&nbsp;errorCode,
+ java.lang.Throwable&nbsp;t)</PRE>
+<DL>
+<DD>Constructs an exception with a message, an error code and a <code>Throwable</code>
+<P>
+<DL>
+<DT><B>Parameters:</B><DD><CODE>message</CODE> - the error message.<DD><CODE>errorCode</CODE> - the error code<DD><CODE>t</CODE> - the exception source</DL>
+</DL>
+
+<!-- ============ METHOD DETAIL ========== -->
+
+<A NAME="method_detail"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="1"><FONT SIZE="+2">
+<B>Method Detail</B></FONT></TH>
+</TR>
+</TABLE>
+
+<A NAME="getErrorCode()"><!-- --></A><H3>
+getErrorCode</H3>
+<PRE>
+public int <B>getErrorCode</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns the errorCode.</DL>
+</DD>
+</DL>
+<!-- ========= END OF CLASS DATA ========= -->
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="class-use/XMPException.html"><FONT CLASS="NavBarFont1"><B>Use</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="../../../com/adobe/xmp/XMPError.html" title="interface in com.adobe.xmp"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;<A HREF="../../../com/adobe/xmp/XMPIterator.html" title="interface in com.adobe.xmp"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../index.html?com/adobe/xmp/XMPException.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPException.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+ SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;FIELD&nbsp;|&nbsp;<A HREF="#constructor_summary">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;FIELD&nbsp;|&nbsp;<A HREF="#constructor_detail">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/com/adobe/xmp/XMPIterator.html b/java/XMPCore/docs/com/adobe/xmp/XMPIterator.html
new file mode 100644
index 0000000..8231e93
--- /dev/null
+++ b/java/XMPCore/docs/com/adobe/xmp/XMPIterator.html
@@ -0,0 +1,304 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:49 CEST 2007 -->
+<TITLE>
+XMPIterator
+</TITLE>
+
+<META NAME="keywords" CONTENT="com.adobe.xmp.XMPIterator interface">
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="XMPIterator";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="class-use/XMPIterator.html"><FONT CLASS="NavBarFont1"><B>Use</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;<A HREF="../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../index.html?com/adobe/xmp/XMPIterator.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPIterator.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+ SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;FIELD&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;FIELD&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<!-- ======== START OF CLASS DATA ======== -->
+<H2>
+<FONT SIZE="-1">
+com.adobe.xmp</FONT>
+<BR>
+Interface XMPIterator</H2>
+<DL>
+<DT><B>All Superinterfaces:</B> <DD>java.util.Iterator</DD>
+</DL>
+<HR>
+<DL>
+<DT><PRE>public interface <B>XMPIterator</B><DT>extends java.util.Iterator</DL>
+</PRE>
+
+<P>
+Interface for the <code>XMPMeta</code> iteration services.
+ <code>XMPIterator</code> provides a uniform means to iterate over the
+ schema and properties within an XMP object.
+ <p>
+ The iteration over the schema and properties within an XMP object is very
+ complex. It is helpful to have a thorough understanding of the XMP data tree.
+ One way to learn this is to create some complex XMP and examine the output of
+ <code>XMPMeta#toString</code>. This is also described in the XMP
+ Specification, in the XMP Data Model chapter.
+ <p>
+ The top of the XMP data tree is a single root node. This does not explicitly
+ appear in the dump and is never visited by an iterator (that is, it is never
+ returned from <code>XMPIterator#next()</code>). Beneath the root are
+ schema nodes. These are just collectors for top level properties in the same
+ namespace. They are created and destroyed implicitly. Beneath the schema
+ nodes are the property nodes. The nodes below a property node depend on its
+ type (simple, struct, or array) and whether it has qualifiers.
+ <p>
+ An <code>XMPIterator</code> is created by XMPMeta#interator() constructor
+ defines a starting point for the iteration and options that control how it
+ proceeds. By default the iteration starts at the root and visits all nodes
+ beneath it in a depth first manner. The root node is not visited, the first
+ visited node is a schema node. You can provide a schema name or property path
+ to select a different starting node. By default this visits the named root
+ node first then all nodes beneath it in a depth first manner.
+ <p>
+ The <code>XMPIterator#next()</code> method delivers the schema URI, path,
+ and option flags for the node being visited. If the node is simple it also
+ delivers the value. Qualifiers for this node are visited next. The fields of
+ a struct or items of an array are visited after the qualifiers of the parent.
+ <p>
+ The options to control the iteration are:
+ <ul>
+ <li>JUST_CHILDREN - Visit just the immediate children of the root. Skip
+ the root itself and all nodes below the immediate children. This omits the
+ qualifiers of the immediate children, the qualifier nodes being below what
+ they qualify, default is to visit the complete subtree.
+ <li>UST_LEAFNODES - Visit just the leaf property nodes and their
+ qualifiers.
+ <li>JUST_LEAFNAME - Return just the leaf component of the node names.
+ The default is to return the full xmp path.
+ <li>OMIT_QUALIFIERS - Do not visit the qualifiers.
+ <li>INCLUDE_ALIASES - Adds known alias properties to the properties in the iteration.
+ <em>Note:</em> Not supported in Java XMPCore!
+ </ul>
+ <p>
+ <code>next()</code> returns <code>XMPPropertyInfo</code>-objects and throws
+ a <code>NoSuchElementException</code> if there are no more properties to
+ return.
+<P>
+
+<P>
+<DL>
+<DT><B>Since:</B></DT>
+ <DD>25.01.2006</DD>
+</DL>
+<HR>
+
+<P>
+
+<!-- ========== METHOD SUMMARY =========== -->
+
+<A NAME="method_summary"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+<B>Method Summary</B></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPIterator.html#skipSiblings()">skipSiblings</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Skip the subtree below and remaining siblings of the current node when
+ <code>next()</code> is called.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPIterator.html#skipSubtree()">skipSubtree</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Skip the subtree below the current node when <code>next()</code> is
+ called.</TD>
+</TR>
+</TABLE>
+&nbsp;<A NAME="methods_inherited_from_class_java.util.Iterator"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#EEEEFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="left"><B>Methods inherited from interface java.util.Iterator</B></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE>hasNext, next, remove</CODE></TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<!-- ============ METHOD DETAIL ========== -->
+
+<A NAME="method_detail"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="1"><FONT SIZE="+2">
+<B>Method Detail</B></FONT></TH>
+</TR>
+</TABLE>
+
+<A NAME="skipSubtree()"><!-- --></A><H3>
+skipSubtree</H3>
+<PRE>
+void <B>skipSubtree</B>()</PRE>
+<DL>
+<DD>Skip the subtree below the current node when <code>next()</code> is
+ called.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="skipSiblings()"><!-- --></A><H3>
+skipSiblings</H3>
+<PRE>
+void <B>skipSiblings</B>()</PRE>
+<DL>
+<DD>Skip the subtree below and remaining siblings of the current node when
+ <code>next()</code> is called.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+</DL>
+</DD>
+</DL>
+<!-- ========= END OF CLASS DATA ========= -->
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="class-use/XMPIterator.html"><FONT CLASS="NavBarFont1"><B>Use</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;<A HREF="../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../index.html?com/adobe/xmp/XMPIterator.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPIterator.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+ SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;FIELD&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;FIELD&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/com/adobe/xmp/XMPMeta.html b/java/XMPCore/docs/com/adobe/xmp/XMPMeta.html
new file mode 100644
index 0000000..4c800af
--- /dev/null
+++ b/java/XMPCore/docs/com/adobe/xmp/XMPMeta.html
@@ -0,0 +1,2301 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:49 CEST 2007 -->
+<TITLE>
+XMPMeta
+</TITLE>
+
+<META NAME="keywords" CONTENT="com.adobe.xmp.XMPMeta interface">
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="XMPMeta";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="class-use/XMPMeta.html"><FONT CLASS="NavBarFont1"><B>Use</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="../../../com/adobe/xmp/XMPIterator.html" title="interface in com.adobe.xmp"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;<A HREF="../../../com/adobe/xmp/XMPMetaFactory.html" title="class in com.adobe.xmp"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../index.html?com/adobe/xmp/XMPMeta.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPMeta.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+ SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;FIELD&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;FIELD&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<!-- ======== START OF CLASS DATA ======== -->
+<H2>
+<FONT SIZE="-1">
+com.adobe.xmp</FONT>
+<BR>
+Interface XMPMeta</H2>
+<DL>
+<DT><B>All Superinterfaces:</B> <DD>java.lang.Cloneable</DD>
+</DL>
+<HR>
+<DL>
+<DT><PRE>public interface <B>XMPMeta</B><DT>extends java.lang.Cloneable</DL>
+</PRE>
+
+<P>
+This class represents the set of XMP metadata as a DOM representation. It has methods to read and
+ modify all kinds of properties, create an iterator over all properties and serialize the metadata
+ to a String, byte-array or <code>OutputStream</code>.
+<P>
+
+<P>
+<DL>
+<DT><B>Since:</B></DT>
+ <DD>20.01.2006</DD>
+</DL>
+<HR>
+
+<P>
+
+<!-- ========== METHOD SUMMARY =========== -->
+
+<A NAME="method_summary"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+<B>Method Summary</B></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#appendArrayItem(java.lang.String, java.lang.String, com.adobe.xmp.options.PropertyOptions, java.lang.String, com.adobe.xmp.options.PropertyOptions)">appendArrayItem</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;arrayName,
+ <A HREF="../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;arrayOptions,
+ java.lang.String&nbsp;itemValue,
+ <A HREF="../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;itemOptions)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Simplifies the construction of an array by not requiring that you pre-create an empty array.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#appendArrayItem(java.lang.String, java.lang.String, java.lang.String)">appendArrayItem</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;arrayName,
+ java.lang.String&nbsp;itemValue)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.lang.Object</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#clone()">clone</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Clones the complete metadata tree.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#countArrayItems(java.lang.String, java.lang.String)">countArrayItems</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;arrayName)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Returns the number of items in the array.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#deleteArrayItem(java.lang.String, java.lang.String, int)">deleteArrayItem</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;arrayName,
+ int&nbsp;itemIndex)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Deletes the given XMP subtree rooted at the given array item.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#deleteProperty(java.lang.String, java.lang.String)">deleteProperty</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Deletes the given XMP subtree rooted at the given property.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#deleteQualifier(java.lang.String, java.lang.String, java.lang.String, java.lang.String)">deleteQualifier</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ java.lang.String&nbsp;qualNS,
+ java.lang.String&nbsp;qualName)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Deletes the given XMP subtree rooted at the given qualifier.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#deleteStructField(java.lang.String, java.lang.String, java.lang.String, java.lang.String)">deleteStructField</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;structName,
+ java.lang.String&nbsp;fieldNS,
+ java.lang.String&nbsp;fieldName)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Deletes the given XMP subtree rooted at the given struct field.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#doesArrayItemExist(java.lang.String, java.lang.String, int)">doesArrayItemExist</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;arrayName,
+ int&nbsp;itemIndex)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Tells if the array item exists.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#doesPropertyExist(java.lang.String, java.lang.String)">doesPropertyExist</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Returns whether the property exists.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#doesQualifierExist(java.lang.String, java.lang.String, java.lang.String, java.lang.String)">doesQualifierExist</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ java.lang.String&nbsp;qualNS,
+ java.lang.String&nbsp;qualName)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DoesQualifierExist tells if the qualifier exists.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#doesStructFieldExist(java.lang.String, java.lang.String, java.lang.String, java.lang.String)">doesStructFieldExist</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;structName,
+ java.lang.String&nbsp;fieldNS,
+ java.lang.String&nbsp;fieldName)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DoesStructFieldExist tells if the struct field exists.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#dumpObject()">dumpObject</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Renders this node and the tree unter this node in a human readable form.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../com/adobe/xmp/properties/XMPProperty.html" title="interface in com.adobe.xmp.properties">XMPProperty</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#getArrayItem(java.lang.String, java.lang.String, int)">getArrayItem</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;arrayName,
+ int&nbsp;itemIndex)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Provides access to items within an array.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../com/adobe/xmp/properties/XMPProperty.html" title="interface in com.adobe.xmp.properties">XMPProperty</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#getLocalizedText(java.lang.String, java.lang.String, java.lang.String, java.lang.String)">getLocalizedText</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;altTextName,
+ java.lang.String&nbsp;genericLang,
+ java.lang.String&nbsp;specificLang)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;These functions provide convenient support for localized text properties, including a number
+ of special and obscure aspects.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#getObjectName()">getObjectName</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;This correlates to the about-attribute,
+ returns the empty String if no name is set.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../com/adobe/xmp/properties/XMPProperty.html" title="interface in com.adobe.xmp.properties">XMPProperty</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#getProperty(java.lang.String, java.lang.String)">getProperty</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The property value getter-methods all take a property specification: the first two parameters
+ are always the top level namespace URI (the &quot;schema&quot; namespace) and the basic name
+ of the property being referenced.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;byte[]</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#getPropertyBase64(java.lang.String, java.lang.String)">getPropertyBase64</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convenience method to retrieve the literal value of a property.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.lang.Boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#getPropertyBoolean(java.lang.String, java.lang.String)">getPropertyBoolean</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;These are very similar to <code>getProperty()</code> and <code>SetProperty()</code> above,
+ but the value is returned or provided in a literal form instead of as a UTF-8 string.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.util.Calendar</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#getPropertyCalendar(java.lang.String, java.lang.String)">getPropertyCalendar</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convenience method to retrieve the literal value of a property.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#getPropertyDate(java.lang.String, java.lang.String)">getPropertyDate</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convenience method to retrieve the literal value of a property.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.lang.Double</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#getPropertyDouble(java.lang.String, java.lang.String)">getPropertyDouble</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convenience method to retrieve the literal value of a property.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.lang.Integer</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#getPropertyInteger(java.lang.String, java.lang.String)">getPropertyInteger</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convenience method to retrieve the literal value of a property.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.lang.Long</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#getPropertyLong(java.lang.String, java.lang.String)">getPropertyLong</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convenience method to retrieve the literal value of a property.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#getPropertyString(java.lang.String, java.lang.String)">getPropertyString</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convenience method to retrieve the literal value of a property.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../com/adobe/xmp/properties/XMPProperty.html" title="interface in com.adobe.xmp.properties">XMPProperty</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#getQualifier(java.lang.String, java.lang.String, java.lang.String, java.lang.String)">getQualifier</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ java.lang.String&nbsp;qualNS,
+ java.lang.String&nbsp;qualName)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Provides access to a qualifier attached to a property.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../com/adobe/xmp/properties/XMPProperty.html" title="interface in com.adobe.xmp.properties">XMPProperty</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#getStructField(java.lang.String, java.lang.String, java.lang.String, java.lang.String)">getStructField</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;structName,
+ java.lang.String&nbsp;fieldNS,
+ java.lang.String&nbsp;fieldName)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Provides access to fields within a nested structure.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#insertArrayItem(java.lang.String, java.lang.String, int, java.lang.String)">insertArrayItem</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;arrayName,
+ int&nbsp;itemIndex,
+ java.lang.String&nbsp;itemValue)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#insertArrayItem(java.lang.String, java.lang.String, int, java.lang.String, com.adobe.xmp.options.PropertyOptions)">insertArrayItem</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;arrayName,
+ int&nbsp;itemIndex,
+ java.lang.String&nbsp;itemValue,
+ <A HREF="../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Inserts an item into an array previous to the given index.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../com/adobe/xmp/XMPIterator.html" title="interface in com.adobe.xmp">XMPIterator</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#iterator()">iterator</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Constructs an iterator for the properties within this XMP object.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../com/adobe/xmp/XMPIterator.html" title="interface in com.adobe.xmp">XMPIterator</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#iterator(com.adobe.xmp.options.IteratorOptions)">iterator</A></B>(<A HREF="../../../com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options">IteratorOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Constructs an iterator for the properties within this XMP object using some options.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../com/adobe/xmp/XMPIterator.html" title="interface in com.adobe.xmp">XMPIterator</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#iterator(java.lang.String, java.lang.String, com.adobe.xmp.options.IteratorOptions)">iterator</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ <A HREF="../../../com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options">IteratorOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Construct an iterator for the properties within an XMP object.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#setArrayItem(java.lang.String, java.lang.String, int, java.lang.String)">setArrayItem</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;arrayName,
+ int&nbsp;itemIndex,
+ java.lang.String&nbsp;itemValue)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#setArrayItem(java.lang.String, java.lang.String, int, java.lang.String, com.adobe.xmp.options.PropertyOptions)">setArrayItem</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;arrayName,
+ int&nbsp;itemIndex,
+ java.lang.String&nbsp;itemValue,
+ <A HREF="../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Replaces an item within an array.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#setLocalizedText(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String)">setLocalizedText</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;altTextName,
+ java.lang.String&nbsp;genericLang,
+ java.lang.String&nbsp;specificLang,
+ java.lang.String&nbsp;itemValue)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#setLocalizedText(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, com.adobe.xmp.options.PropertyOptions)">setLocalizedText</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;altTextName,
+ java.lang.String&nbsp;genericLang,
+ java.lang.String&nbsp;specificLang,
+ java.lang.String&nbsp;itemValue,
+ <A HREF="../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Modifies the value of a selected item in an alt-text array.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#setObjectName(java.lang.String)">setObjectName</A></B>(java.lang.String&nbsp;name)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#setProperty(java.lang.String, java.lang.String, java.lang.Object)">setProperty</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ java.lang.Object&nbsp;propValue)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#setProperty(java.lang.String, java.lang.String, java.lang.Object, com.adobe.xmp.options.PropertyOptions)">setProperty</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ java.lang.Object&nbsp;propValue,
+ <A HREF="../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The property value <code>setters</code> all take a property specification, their
+ differences are in the form of this.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#setPropertyBase64(java.lang.String, java.lang.String, byte[])">setPropertyBase64</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ byte[]&nbsp;propValue)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#setPropertyBase64(java.lang.String, java.lang.String, byte[], com.adobe.xmp.options.PropertyOptions)">setPropertyBase64</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ byte[]&nbsp;propValue,
+ <A HREF="../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convenience method to set a property from a binary <code>byte[]</code>-array,
+ which is serialized as base64-string.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#setPropertyBoolean(java.lang.String, java.lang.String, boolean)">setPropertyBoolean</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ boolean&nbsp;propValue)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#setPropertyBoolean(java.lang.String, java.lang.String, boolean, com.adobe.xmp.options.PropertyOptions)">setPropertyBoolean</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ boolean&nbsp;propValue,
+ <A HREF="../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convenience method to set a property to a literal <code>boolean</code> value.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#setPropertyCalendar(java.lang.String, java.lang.String, java.util.Calendar)">setPropertyCalendar</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ java.util.Calendar&nbsp;propValue)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#setPropertyCalendar(java.lang.String, java.lang.String, java.util.Calendar, com.adobe.xmp.options.PropertyOptions)">setPropertyCalendar</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ java.util.Calendar&nbsp;propValue,
+ <A HREF="../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convenience method to set a property with a Java Calendar-object,
+ which is serialized to an ISO8601 date.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#setPropertyDate(java.lang.String, java.lang.String, com.adobe.xmp.XMPDateTime)">setPropertyDate</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ <A HREF="../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A>&nbsp;propValue)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#setPropertyDate(java.lang.String, java.lang.String, com.adobe.xmp.XMPDateTime, com.adobe.xmp.options.PropertyOptions)">setPropertyDate</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ <A HREF="../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A>&nbsp;propValue,
+ <A HREF="../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convenience method to set a property with an XMPDateTime-object,
+ which is serialized to an ISO8601 date.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#setPropertyDouble(java.lang.String, java.lang.String, double)">setPropertyDouble</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ double&nbsp;propValue)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#setPropertyDouble(java.lang.String, java.lang.String, double, com.adobe.xmp.options.PropertyOptions)">setPropertyDouble</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ double&nbsp;propValue,
+ <A HREF="../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convenience method to set a property to a literal <code>double</code> value.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#setPropertyInteger(java.lang.String, java.lang.String, int)">setPropertyInteger</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ int&nbsp;propValue)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#setPropertyInteger(java.lang.String, java.lang.String, int, com.adobe.xmp.options.PropertyOptions)">setPropertyInteger</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ int&nbsp;propValue,
+ <A HREF="../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convenience method to set a property to a literal <code>int</code> value.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#setPropertyLong(java.lang.String, java.lang.String, long)">setPropertyLong</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ long&nbsp;propValue)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#setPropertyLong(java.lang.String, java.lang.String, long, com.adobe.xmp.options.PropertyOptions)">setPropertyLong</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ long&nbsp;propValue,
+ <A HREF="../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convenience method to set a property to a literal <code>long</code> value.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#setQualifier(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String)">setQualifier</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ java.lang.String&nbsp;qualNS,
+ java.lang.String&nbsp;qualName,
+ java.lang.String&nbsp;qualValue)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#setQualifier(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, com.adobe.xmp.options.PropertyOptions)">setQualifier</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ java.lang.String&nbsp;qualNS,
+ java.lang.String&nbsp;qualName,
+ java.lang.String&nbsp;qualValue,
+ <A HREF="../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Provides access to a qualifier attached to a property.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#setStructField(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String)">setStructField</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;structName,
+ java.lang.String&nbsp;fieldNS,
+ java.lang.String&nbsp;fieldName,
+ java.lang.String&nbsp;fieldValue)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#setStructField(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, com.adobe.xmp.options.PropertyOptions)">setStructField</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;structName,
+ java.lang.String&nbsp;fieldNS,
+ java.lang.String&nbsp;fieldName,
+ java.lang.String&nbsp;fieldValue,
+ <A HREF="../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Provides access to fields within a nested structure.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMeta.html#sort()">sort</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sorts the complete datamodel according to the following rules:
+
+ Schema nodes are sorted by prefix.</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<!-- ============ METHOD DETAIL ========== -->
+
+<A NAME="method_detail"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="1"><FONT SIZE="+2">
+<B>Method Detail</B></FONT></TH>
+</TR>
+</TABLE>
+
+<A NAME="getProperty(java.lang.String, java.lang.String)"><!-- --></A><H3>
+getProperty</H3>
+<PRE>
+<A HREF="../../../com/adobe/xmp/properties/XMPProperty.html" title="interface in com.adobe.xmp.properties">XMPProperty</A> <B>getProperty</B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>The property value getter-methods all take a property specification: the first two parameters
+ are always the top level namespace URI (the &quot;schema&quot; namespace) and the basic name
+ of the property being referenced. See the introductory discussion of path expression usage
+ for more information.
+ <p>
+ All of the functions return an object inherited from <code>PropertyBase</code> or
+ <code>null</code> if the property does not exists. The result object contains the value of
+ the property and option flags describing the property. Arrays and the non-leaf levels of
+ nodes do not have values.
+ <p>
+ See <A HREF="../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options"><CODE>PropertyOptions</CODE></A> for detailed information about the options.
+ <p>
+ This is the simplest property getter, mainly for top level simple properties or after using
+ the path composition functions in XMPPathFactory.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>schemaNS</CODE> - The namespace URI for the property. May be <code>null</code> or the empty
+ string if the first component of the propName path contains a namespace prefix. The
+ URI must be for a registered namespace.<DD><CODE>propName</CODE> - The name of the property. May be a general path expression, must not be
+ <code>null</code> or the empty string. Using a namespace prefix on the first
+ component is optional. If present without a schemaNS value then the prefix specifies
+ the namespace. The prefix must be for a registered namespace. If both a schemaNS URI
+ and propName prefix are present, they must be corresponding parts of a registered
+ namespace.
+<DT><B>Returns:</B><DD>Returns a <code>XMPProperty</code> containing the value and the options or
+ <code>null</code> if the property does not exist.
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Wraps all errors and exceptions that may occur.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getArrayItem(java.lang.String, java.lang.String, int)"><!-- --></A><H3>
+getArrayItem</H3>
+<PRE>
+<A HREF="../../../com/adobe/xmp/properties/XMPProperty.html" title="interface in com.adobe.xmp.properties">XMPProperty</A> <B>getArrayItem</B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;arrayName,
+ int&nbsp;itemIndex)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Provides access to items within an array. The index is passed as an integer, you need not
+ worry about the path string syntax for array items, convert a loop index to a string, etc.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>schemaNS</CODE> - The namespace URI for the array. Has the same usage as in getProperty.<DD><CODE>arrayName</CODE> - The name of the array. May be a general path expression, must not be
+ <code>null</code> or the empty string. Has the same namespace prefix usage as
+ propName in <code>getProperty()</code>.<DD><CODE>itemIndex</CODE> - The index of the desired item. Arrays in XMP are indexed from 1. The
+ constant <A HREF="../../../com/adobe/xmp/XMPConst.html#ARRAY_LAST_ITEM"><CODE>XMPConst.ARRAY_LAST_ITEM</CODE></A> always refers to the last existing array
+ item.
+<DT><B>Returns:</B><DD>Returns a <code>XMPProperty</code> containing the value and the options or
+ <code>null</code> if the property does not exist.
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Wraps all errors and exceptions that may occur.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="countArrayItems(java.lang.String, java.lang.String)"><!-- --></A><H3>
+countArrayItems</H3>
+<PRE>
+int <B>countArrayItems</B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;arrayName)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Returns the number of items in the array.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>schemaNS</CODE> - The namespace URI for the array. Has the same usage as in getProperty.<DD><CODE>arrayName</CODE> - The name of the array. May be a general path expression, must not be
+ <code>null</code> or the empty string. Has the same namespace prefix usage as
+ propName in <code>getProperty()</code>.
+<DT><B>Returns:</B><DD>Returns the number of items in the array.
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Wraps all errors and exceptions that may occur.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getStructField(java.lang.String, java.lang.String, java.lang.String, java.lang.String)"><!-- --></A><H3>
+getStructField</H3>
+<PRE>
+<A HREF="../../../com/adobe/xmp/properties/XMPProperty.html" title="interface in com.adobe.xmp.properties">XMPProperty</A> <B>getStructField</B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;structName,
+ java.lang.String&nbsp;fieldNS,
+ java.lang.String&nbsp;fieldName)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Provides access to fields within a nested structure. The namespace for the field is passed as
+ a URI, you need not worry about the path string syntax.
+ <p>
+ The names of fields should be XML qualified names, that is within an XML namespace. The path
+ syntax for a qualified name uses the namespace prefix. This is unreliable since the prefix is
+ never guaranteed. The URI is the formal name, the prefix is just a local shorthand in a given
+ sequence of XML text.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>schemaNS</CODE> - The namespace URI for the struct. Has the same usage as in getProperty.<DD><CODE>structName</CODE> - The name of the struct. May be a general path expression, must not be
+ <code>null</code> or the empty string. Has the same namespace prefix usage as
+ propName in <code>getProperty()</code>.<DD><CODE>fieldNS</CODE> - The namespace URI for the field. Has the same URI and prefix usage as the
+ schemaNS parameter.<DD><CODE>fieldName</CODE> - The name of the field. Must be a single XML name, must not be
+ <code>null</code> or the empty string. Has the same namespace prefix usage as the
+ structName parameter.
+<DT><B>Returns:</B><DD>Returns a <code>XMPProperty</code> containing the value and the options or
+ <code>null</code> if the property does not exist. Arrays and non-leaf levels of
+ structs do not have values.
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Wraps all errors and exceptions that may occur.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getQualifier(java.lang.String, java.lang.String, java.lang.String, java.lang.String)"><!-- --></A><H3>
+getQualifier</H3>
+<PRE>
+<A HREF="../../../com/adobe/xmp/properties/XMPProperty.html" title="interface in com.adobe.xmp.properties">XMPProperty</A> <B>getQualifier</B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ java.lang.String&nbsp;qualNS,
+ java.lang.String&nbsp;qualName)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Provides access to a qualifier attached to a property. The namespace for the qualifier is
+ passed as a URI, you need not worry about the path string syntax. In many regards qualifiers
+ are like struct fields. See the introductory discussion of qualified properties for more
+ information.
+ <p>
+ The names of qualifiers should be XML qualified names, that is within an XML namespace. The
+ path syntax for a qualified name uses the namespace prefix. This is unreliable since the
+ prefix is never guaranteed. The URI is the formal name, the prefix is just a local shorthand
+ in a given sequence of XML text.
+ <p>
+ <em>Note:</em> Qualifiers are only supported for simple leaf properties at this time.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>schemaNS</CODE> - The namespace URI for the struct. Has the same usage as in getProperty.<DD><CODE>propName</CODE> - The name of the property to which the qualifier is attached. May be a general
+ path expression, must not be <code>null</code> or the empty string. Has the same
+ namespace prefix usage as in <code>getProperty()</code>.<DD><CODE>qualNS</CODE> - The namespace URI for the qualifier. Has the same URI and prefix usage as the
+ schemaNS parameter.<DD><CODE>qualName</CODE> - The name of the qualifier. Must be a single XML name, must not be
+ <code>null</code> or the empty string. Has the same namespace prefix usage as the
+ propName parameter.
+<DT><B>Returns:</B><DD>Returns a <code>XMPProperty</code> containing the value and the options of the
+ qualifier or <code>null</code> if the property does not exist. The name of the
+ qualifier must be a single XML name, must not be <code>null</code> or the empty
+ string. Has the same namespace prefix usage as the propName parameter.
+ <p>
+ The value of the qualifier is only set if it has one (Arrays and non-leaf levels of
+ structs do not have values).
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Wraps all errors and exceptions that may occur.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setProperty(java.lang.String, java.lang.String, java.lang.Object, com.adobe.xmp.options.PropertyOptions)"><!-- --></A><H3>
+setProperty</H3>
+<PRE>
+void <B>setProperty</B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ java.lang.Object&nbsp;propValue,
+ <A HREF="../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>The property value <code>setters</code> all take a property specification, their
+ differences are in the form of this. The first two parameters are always the top level
+ namespace URI (the <code>schema</code> namespace) and the basic name of the property being
+ referenced. See the introductory discussion of path expression usage for more information.
+ <p>
+ All of the functions take a string value for the property and option flags describing the
+ property. The value must be Unicode in UTF-8 encoding. Arrays and non-leaf levels of structs
+ do not have values. Empty arrays and structs may be created using appropriate option flags.
+ All levels of structs that is assigned implicitly are created if necessary. appendArayItem
+ implicitly creates the named array if necessary.
+ <p>
+ See <A HREF="../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options"><CODE>PropertyOptions</CODE></A> for detailed information about the options.
+ <p>
+ This is the simplest property setter, mainly for top level simple properties or after using
+ the path composition functions in <A HREF="../../../com/adobe/xmp/XMPPathFactory.html" title="class in com.adobe.xmp"><CODE>XMPPathFactory</CODE></A>.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>schemaNS</CODE> - The namespace URI for the property. Has the same usage as in getProperty.<DD><CODE>propName</CODE> - The name of the property.
+ Has the same usage as in <code>getProperty()</code>.<DD><CODE>propValue</CODE> - the value for the property (only leaf properties have a value).
+ Arrays and non-leaf levels of structs do not have values.
+ Must be <code>null</code> if the value is not relevant.<br/>
+ The value is automatically detected: Boolean, Integer, Long, Double, XMPDateTime and
+ byte[] are handled, on all other <code>toString()</code> is called.<DD><CODE>options</CODE> - Option flags describing the property. See the earlier description.
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Wraps all errors and exceptions that may occur.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setProperty(java.lang.String, java.lang.String, java.lang.Object)"><!-- --></A><H3>
+setProperty</H3>
+<PRE>
+void <B>setProperty</B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ java.lang.Object&nbsp;propValue)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>schemaNS</CODE> - The namespace URI<DD><CODE>propName</CODE> - The name of the property<DD><CODE>propValue</CODE> - the value for the property
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Wraps all errors and exceptions<DT><B>See Also:</B><DD><A HREF="../../../com/adobe/xmp/XMPMeta.html#setProperty(java.lang.String, java.lang.String, java.lang.Object, com.adobe.xmp.options.PropertyOptions)"><CODE>setProperty(String, String, Object, PropertyOptions)</CODE></A></DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setArrayItem(java.lang.String, java.lang.String, int, java.lang.String, com.adobe.xmp.options.PropertyOptions)"><!-- --></A><H3>
+setArrayItem</H3>
+<PRE>
+void <B>setArrayItem</B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;arrayName,
+ int&nbsp;itemIndex,
+ java.lang.String&nbsp;itemValue,
+ <A HREF="../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Replaces an item within an array. The index is passed as an integer, you need not worry about
+ the path string syntax for array items, convert a loop index to a string, etc. The array
+ passed must already exist. In normal usage the selected array item is modified. A new item is
+ automatically appended if the index is the array size plus 1.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>schemaNS</CODE> - The namespace URI for the array. Has the same usage as in getProperty.<DD><CODE>arrayName</CODE> - The name of the array. May be a general path expression, must not be
+ <code>null</code> or the empty string. Has the same namespace prefix usage as
+ propName in getProperty.<DD><CODE>itemIndex</CODE> - The index of the desired item. Arrays in XMP are indexed from 1. To address
+ the last existing item, use <A HREF="../../../com/adobe/xmp/XMPMeta.html#countArrayItems(java.lang.String, java.lang.String)"><CODE>countArrayItems(String, String)</CODE></A> to find
+ out the length of the array.<DD><CODE>itemValue</CODE> - the new value of the array item. Has the same usage as propValue in
+ <code>setProperty()</code>.<DD><CODE>options</CODE> - the set options for the item.
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Wraps all errors and exceptions that may occur.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setArrayItem(java.lang.String, java.lang.String, int, java.lang.String)"><!-- --></A><H3>
+setArrayItem</H3>
+<PRE>
+void <B>setArrayItem</B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;arrayName,
+ int&nbsp;itemIndex,
+ java.lang.String&nbsp;itemValue)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>schemaNS</CODE> - The namespace URI<DD><CODE>arrayName</CODE> - The name of the array<DD><CODE>itemIndex</CODE> - The index to insert the new item<DD><CODE>itemValue</CODE> - the new value of the array item
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Wraps all errors and exceptions<DT><B>See Also:</B><DD><A HREF="../../../com/adobe/xmp/XMPMeta.html#setArrayItem(java.lang.String, java.lang.String, int, java.lang.String, com.adobe.xmp.options.PropertyOptions)"><CODE>setArrayItem(String, String, int, String, PropertyOptions)</CODE></A></DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="insertArrayItem(java.lang.String, java.lang.String, int, java.lang.String, com.adobe.xmp.options.PropertyOptions)"><!-- --></A><H3>
+insertArrayItem</H3>
+<PRE>
+void <B>insertArrayItem</B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;arrayName,
+ int&nbsp;itemIndex,
+ java.lang.String&nbsp;itemValue,
+ <A HREF="../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Inserts an item into an array previous to the given index. The index is passed as an integer,
+ you need not worry about the path string syntax for array items, convert a loop index to a
+ string, etc. The array passed must already exist. In normal usage the selected array item is
+ modified. A new item is automatically appended if the index is the array size plus 1.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>schemaNS</CODE> - The namespace URI for the array. Has the same usage as in getProperty.<DD><CODE>arrayName</CODE> - The name of the array. May be a general path expression, must not be
+ <code>null</code> or the empty string. Has the same namespace prefix usage as
+ propName in getProperty.<DD><CODE>itemIndex</CODE> - The index to insert the new item. Arrays in XMP are indexed from 1. Use
+ <code>XMPConst.ARRAY_LAST_ITEM</code> to append items.<DD><CODE>itemValue</CODE> - the new value of the array item. Has the same usage as
+ propValue in <code>setProperty()</code>.<DD><CODE>options</CODE> - the set options that decide about the kind of the node.
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Wraps all errors and exceptions that may occur.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="insertArrayItem(java.lang.String, java.lang.String, int, java.lang.String)"><!-- --></A><H3>
+insertArrayItem</H3>
+<PRE>
+void <B>insertArrayItem</B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;arrayName,
+ int&nbsp;itemIndex,
+ java.lang.String&nbsp;itemValue)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>schemaNS</CODE> - The namespace URI for the array<DD><CODE>arrayName</CODE> - The name of the array<DD><CODE>itemIndex</CODE> - The index to insert the new item<DD><CODE>itemValue</CODE> - the value of the array item
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Wraps all errors and exceptions<DT><B>See Also:</B><DD><A HREF="../../../com/adobe/xmp/XMPMeta.html#insertArrayItem(java.lang.String, java.lang.String, int, java.lang.String, com.adobe.xmp.options.PropertyOptions)"><CODE>insertArrayItem(String, String, int, String, PropertyOptions)</CODE></A></DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="appendArrayItem(java.lang.String, java.lang.String, com.adobe.xmp.options.PropertyOptions, java.lang.String, com.adobe.xmp.options.PropertyOptions)"><!-- --></A><H3>
+appendArrayItem</H3>
+<PRE>
+void <B>appendArrayItem</B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;arrayName,
+ <A HREF="../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;arrayOptions,
+ java.lang.String&nbsp;itemValue,
+ <A HREF="../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;itemOptions)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Simplifies the construction of an array by not requiring that you pre-create an empty array.
+ The array that is assigned is created automatically if it does not yet exist. Each call to
+ appendArrayItem() appends an item to the array. The corresponding parameters have the same
+ use as setArrayItem(). The arrayOptions parameter is used to specify what kind of array. If
+ the array exists, it must have the specified form.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>schemaNS</CODE> - The namespace URI for the array. Has the same usage as in getProperty.<DD><CODE>arrayName</CODE> - The name of the array. May be a general path expression, must not be null or
+ the empty string. Has the same namespace prefix usage as propPath in getProperty.<DD><CODE>arrayOptions</CODE> - Option flags describing the array form. The only valid options are
+ <ul>
+ <li> <A HREF="../../../com/adobe/xmp/options/PropertyOptions.html#ARRAY"><CODE>PropertyOptions.ARRAY</CODE></A>,
+ <li> <A HREF="../../../com/adobe/xmp/options/PropertyOptions.html#ARRAY_ORDERED"><CODE>PropertyOptions.ARRAY_ORDERED</CODE></A>,
+ <li> <A HREF="../../../com/adobe/xmp/options/PropertyOptions.html#ARRAY_ALTERNATE"><CODE>PropertyOptions.ARRAY_ALTERNATE</CODE></A> or
+ <li> <A HREF="../../../com/adobe/xmp/options/PropertyOptions.html#ARRAY_ALT_TEXT"><CODE>PropertyOptions.ARRAY_ALT_TEXT</CODE></A>.
+ </ul>
+ <em>Note:</em> the array options only need to be provided if the array is not
+ already existing, otherwise you can set them to <code>null</code> or use
+ <A HREF="../../../com/adobe/xmp/XMPMeta.html#appendArrayItem(java.lang.String, java.lang.String, java.lang.String)"><CODE>appendArrayItem(String, String, String)</CODE></A>.<DD><CODE>itemValue</CODE> - the value of the array item. Has the same usage as propValue in getProperty.<DD><CODE>itemOptions</CODE> - Option flags describing the item to append (<A HREF="../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options"><CODE>PropertyOptions</CODE></A>)
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Wraps all errors and exceptions that may occur.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="appendArrayItem(java.lang.String, java.lang.String, java.lang.String)"><!-- --></A><H3>
+appendArrayItem</H3>
+<PRE>
+void <B>appendArrayItem</B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;arrayName,
+ java.lang.String&nbsp;itemValue)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>schemaNS</CODE> - The namespace URI for the array<DD><CODE>arrayName</CODE> - The name of the array<DD><CODE>itemValue</CODE> - the value of the array item
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Wraps all errors and exceptions<DT><B>See Also:</B><DD><A HREF="../../../com/adobe/xmp/XMPMeta.html#appendArrayItem(java.lang.String, java.lang.String, com.adobe.xmp.options.PropertyOptions, java.lang.String, com.adobe.xmp.options.PropertyOptions)"><CODE>appendArrayItem(String, String, PropertyOptions, String, PropertyOptions)</CODE></A></DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setStructField(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, com.adobe.xmp.options.PropertyOptions)"><!-- --></A><H3>
+setStructField</H3>
+<PRE>
+void <B>setStructField</B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;structName,
+ java.lang.String&nbsp;fieldNS,
+ java.lang.String&nbsp;fieldName,
+ java.lang.String&nbsp;fieldValue,
+ <A HREF="../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Provides access to fields within a nested structure. The namespace for the field is passed as
+ a URI, you need not worry about the path string syntax. The names of fields should be XML
+ qualified names, that is within an XML namespace. The path syntax for a qualified name uses
+ the namespace prefix, which is unreliable because the prefix is never guaranteed. The URI is
+ the formal name, the prefix is just a local shorthand in a given sequence of XML text.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>schemaNS</CODE> - The namespace URI for the struct. Has the same usage as in getProperty.<DD><CODE>structName</CODE> - The name of the struct. May be a general path expression, must not be null
+ or the empty string. Has the same namespace prefix usage as propName in getProperty.<DD><CODE>fieldNS</CODE> - The namespace URI for the field. Has the same URI and prefix usage as the
+ schemaNS parameter.<DD><CODE>fieldName</CODE> - The name of the field. Must be a single XML name, must not be null or the
+ empty string. Has the same namespace prefix usage as the structName parameter.<DD><CODE>fieldValue</CODE> - the value of thefield, if the field has a value.
+ Has the same usage as propValue in getProperty.<DD><CODE>options</CODE> - Option flags describing the field. See the earlier description.
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Wraps all errors and exceptions that may occur.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setStructField(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String)"><!-- --></A><H3>
+setStructField</H3>
+<PRE>
+void <B>setStructField</B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;structName,
+ java.lang.String&nbsp;fieldNS,
+ java.lang.String&nbsp;fieldName,
+ java.lang.String&nbsp;fieldValue)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>schemaNS</CODE> - The namespace URI for the struct<DD><CODE>structName</CODE> - The name of the struct<DD><CODE>fieldNS</CODE> - The namespace URI for the field<DD><CODE>fieldName</CODE> - The name of the field<DD><CODE>fieldValue</CODE> - the value of the field
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Wraps all errors and exceptions<DT><B>See Also:</B><DD><A HREF="../../../com/adobe/xmp/XMPMeta.html#setStructField(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, com.adobe.xmp.options.PropertyOptions)"><CODE>setStructField(String, String, String, String, String, PropertyOptions)</CODE></A></DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setQualifier(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, com.adobe.xmp.options.PropertyOptions)"><!-- --></A><H3>
+setQualifier</H3>
+<PRE>
+void <B>setQualifier</B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ java.lang.String&nbsp;qualNS,
+ java.lang.String&nbsp;qualName,
+ java.lang.String&nbsp;qualValue,
+ <A HREF="../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Provides access to a qualifier attached to a property. The namespace for the qualifier is
+ passed as a URI, you need not worry about the path string syntax. In many regards qualifiers
+ are like struct fields. See the introductory discussion of qualified properties for more
+ information. The names of qualifiers should be XML qualified names, that is within an XML
+ namespace. The path syntax for a qualified name uses the namespace prefix, which is
+ unreliable because the prefix is never guaranteed. The URI is the formal name, the prefix is
+ just a local shorthand in a given sequence of XML text. The property the qualifier
+ will be attached has to exist.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>schemaNS</CODE> - The namespace URI for the struct. Has the same usage as in getProperty.<DD><CODE>propName</CODE> - The name of the property to which the qualifier is attached. Has the same
+ usage as in getProperty.<DD><CODE>qualNS</CODE> - The namespace URI for the qualifier. Has the same URI and prefix usage as the
+ schemaNS parameter.<DD><CODE>qualName</CODE> - The name of the qualifier. Must be a single XML name, must not be
+ <code>null</code> or the empty string. Has the same namespace prefix usage as the
+ propName parameter.<DD><CODE>qualValue</CODE> - A pointer to the <code>null</code> terminated UTF-8 string that is the
+ value of the qualifier, if the qualifier has a value. Has the same usage as propValue
+ in getProperty.<DD><CODE>options</CODE> - Option flags describing the qualifier. See the earlier description.
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Wraps all errors and exceptions that may occur.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setQualifier(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String)"><!-- --></A><H3>
+setQualifier</H3>
+<PRE>
+void <B>setQualifier</B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ java.lang.String&nbsp;qualNS,
+ java.lang.String&nbsp;qualName,
+ java.lang.String&nbsp;qualValue)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>schemaNS</CODE> - The namespace URI for the struct<DD><CODE>propName</CODE> - The name of the property to which the qualifier is attached<DD><CODE>qualNS</CODE> - The namespace URI for the qualifier<DD><CODE>qualName</CODE> - The name of the qualifier<DD><CODE>qualValue</CODE> - the value of the qualifier
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Wraps all errors and exceptions<DT><B>See Also:</B><DD><A HREF="../../../com/adobe/xmp/XMPMeta.html#setQualifier(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, com.adobe.xmp.options.PropertyOptions)"><CODE>setQualifier(String, String, String, String, String, PropertyOptions)</CODE></A></DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="deleteProperty(java.lang.String, java.lang.String)"><!-- --></A><H3>
+deleteProperty</H3>
+<PRE>
+void <B>deleteProperty</B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName)</PRE>
+<DL>
+<DD>Deletes the given XMP subtree rooted at the given property. It is not an error if the
+ property does not exist.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>schemaNS</CODE> - The namespace URI for the property. Has the same usage as in
+ <code>getProperty()</code>.<DD><CODE>propName</CODE> - The name of the property. Has the same usage as in getProperty.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="deleteArrayItem(java.lang.String, java.lang.String, int)"><!-- --></A><H3>
+deleteArrayItem</H3>
+<PRE>
+void <B>deleteArrayItem</B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;arrayName,
+ int&nbsp;itemIndex)</PRE>
+<DL>
+<DD>Deletes the given XMP subtree rooted at the given array item. It is not an error if the array
+ item does not exist.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>schemaNS</CODE> - The namespace URI for the array. Has the same usage as in getProperty.<DD><CODE>arrayName</CODE> - The name of the array. May be a general path expression, must not be
+ <code>null</code> or the empty string. Has the same namespace prefix usage as
+ propName in <code>getProperty()</code>.<DD><CODE>itemIndex</CODE> - The index of the desired item. Arrays in XMP are indexed from 1. The
+ constant <code>XMPConst.ARRAY_LAST_ITEM</code> always refers to the last
+ existing array item.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="deleteStructField(java.lang.String, java.lang.String, java.lang.String, java.lang.String)"><!-- --></A><H3>
+deleteStructField</H3>
+<PRE>
+void <B>deleteStructField</B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;structName,
+ java.lang.String&nbsp;fieldNS,
+ java.lang.String&nbsp;fieldName)</PRE>
+<DL>
+<DD>Deletes the given XMP subtree rooted at the given struct field. It is not an error if the
+ field does not exist.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>schemaNS</CODE> - The namespace URI for the struct. Has the same usage as in
+ <code>getProperty()</code>.<DD><CODE>structName</CODE> - The name of the struct. May be a general path expression, must not be
+ <code>null</code> or the empty string. Has the same namespace prefix usage as
+ propName in getProperty.<DD><CODE>fieldNS</CODE> - The namespace URI for the field. Has the same URI and prefix usage as the
+ schemaNS parameter.<DD><CODE>fieldName</CODE> - The name of the field. Must be a single XML name, must not be
+ <code>null</code> or the empty string. Has the same namespace prefix usage as the
+ structName parameter.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="deleteQualifier(java.lang.String, java.lang.String, java.lang.String, java.lang.String)"><!-- --></A><H3>
+deleteQualifier</H3>
+<PRE>
+void <B>deleteQualifier</B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ java.lang.String&nbsp;qualNS,
+ java.lang.String&nbsp;qualName)</PRE>
+<DL>
+<DD>Deletes the given XMP subtree rooted at the given qualifier. It is not an error if the
+ qualifier does not exist.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>schemaNS</CODE> - The namespace URI for the struct. Has the same usage as in
+ <code>getProperty()</code>.<DD><CODE>propName</CODE> - The name of the property to which the qualifier is attached. Has the same
+ usage as in getProperty.<DD><CODE>qualNS</CODE> - The namespace URI for the qualifier. Has the same URI and prefix usage as the
+ schemaNS parameter.<DD><CODE>qualName</CODE> - The name of the qualifier. Must be a single XML name, must not be
+ <code>null</code> or the empty string. Has the same namespace prefix usage as the
+ propName parameter.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="doesPropertyExist(java.lang.String, java.lang.String)"><!-- --></A><H3>
+doesPropertyExist</H3>
+<PRE>
+boolean <B>doesPropertyExist</B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName)</PRE>
+<DL>
+<DD>Returns whether the property exists.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>schemaNS</CODE> - The namespace URI for the property. Has the same usage as in
+ <code>getProperty()</code>.<DD><CODE>propName</CODE> - The name of the property.
+ Has the same usage as in <code>getProperty()</code>.
+<DT><B>Returns:</B><DD>Returns true if the property exists.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="doesArrayItemExist(java.lang.String, java.lang.String, int)"><!-- --></A><H3>
+doesArrayItemExist</H3>
+<PRE>
+boolean <B>doesArrayItemExist</B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;arrayName,
+ int&nbsp;itemIndex)</PRE>
+<DL>
+<DD>Tells if the array item exists.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>schemaNS</CODE> - The namespace URI for the array. Has the same usage as in
+ <code>getProperty()</code>.<DD><CODE>arrayName</CODE> - The name of the array. May be a general path expression, must not be
+ <code>null</code> or the empty string. Has the same namespace prefix usage as
+ propName in <code>getProperty()</code>.<DD><CODE>itemIndex</CODE> - The index of the desired item. Arrays in XMP are indexed from 1. The
+ constant <code>XMPConst.ARRAY_LAST_ITEM</code> always refers to the last
+ existing array item.
+<DT><B>Returns:</B><DD>Returns <code>true</code> if the array exists, <code>false</code> otherwise.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="doesStructFieldExist(java.lang.String, java.lang.String, java.lang.String, java.lang.String)"><!-- --></A><H3>
+doesStructFieldExist</H3>
+<PRE>
+boolean <B>doesStructFieldExist</B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;structName,
+ java.lang.String&nbsp;fieldNS,
+ java.lang.String&nbsp;fieldName)</PRE>
+<DL>
+<DD>DoesStructFieldExist tells if the struct field exists.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>schemaNS</CODE> - The namespace URI for the struct. Has the same usage as in
+ <code>getProperty()</code>.<DD><CODE>structName</CODE> - The name of the struct. May be a general path expression, must not be
+ <code>null</code> or the empty string. Has the same namespace prefix usage as
+ propName in <code>getProperty()</code>.<DD><CODE>fieldNS</CODE> - The namespace URI for the field. Has the same URI and prefix usage as the
+ schemaNS parameter.<DD><CODE>fieldName</CODE> - The name of the field. Must be a single XML name, must not be
+ <code>null</code> or the empty string. Has the same namespace prefix usage as the
+ structName parameter.
+<DT><B>Returns:</B><DD>Returns true if the field exists.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="doesQualifierExist(java.lang.String, java.lang.String, java.lang.String, java.lang.String)"><!-- --></A><H3>
+doesQualifierExist</H3>
+<PRE>
+boolean <B>doesQualifierExist</B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ java.lang.String&nbsp;qualNS,
+ java.lang.String&nbsp;qualName)</PRE>
+<DL>
+<DD>DoesQualifierExist tells if the qualifier exists.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>schemaNS</CODE> - The namespace URI for the struct. Has the same usage as in
+ <code>getProperty()</code>.<DD><CODE>propName</CODE> - The name of the property to which the qualifier is attached. Has the same
+ usage as in <code>getProperty()</code>.<DD><CODE>qualNS</CODE> - The namespace URI for the qualifier. Has the same URI and prefix usage as the
+ schemaNS parameter.<DD><CODE>qualName</CODE> - The name of the qualifier. Must be a single XML name, must not be
+ <code>null</code> or the empty string. Has the same namespace prefix usage as the
+ propName parameter.
+<DT><B>Returns:</B><DD>Returns true if the qualifier exists.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getLocalizedText(java.lang.String, java.lang.String, java.lang.String, java.lang.String)"><!-- --></A><H3>
+getLocalizedText</H3>
+<PRE>
+<A HREF="../../../com/adobe/xmp/properties/XMPProperty.html" title="interface in com.adobe.xmp.properties">XMPProperty</A> <B>getLocalizedText</B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;altTextName,
+ java.lang.String&nbsp;genericLang,
+ java.lang.String&nbsp;specificLang)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>These functions provide convenient support for localized text properties, including a number
+ of special and obscure aspects. Localized text properties are stored in alt-text arrays. They
+ allow multiple concurrent localizations of a property value, for example a document title or
+ copyright in several languages. The most important aspect of these functions is that they
+ select an appropriate array item based on one or two RFC 3066 language tags. One of these
+ languages, the "specific" language, is preferred and selected if there is an exact match. For
+ many languages it is also possible to define a "generic" language that may be used if there
+ is no specific language match. The generic language must be a valid RFC 3066 primary subtag,
+ or the empty string. For example, a specific language of "en-US" should be used in the US,
+ and a specific language of "en-UK" should be used in England. It is also appropriate to use
+ "en" as the generic language in each case. If a US document goes to England, the "en-US"
+ title is selected by using the "en" generic language and the "en-UK" specific language. It is
+ considered poor practice, but allowed, to pass a specific language that is just an RFC 3066
+ primary tag. For example "en" is not a good specific language, it should only be used as a
+ generic language. Passing "i" or "x" as the generic language is also considered poor practice
+ but allowed. Advice from the W3C about the use of RFC 3066 language tags can be found at:
+ http://www.w3.org/International/articles/language-tags/
+ <p>
+ <em>Note:</em> RFC 3066 language tags must be treated in a case insensitive manner. The XMP
+ Toolkit does this by normalizing their capitalization:
+ <ul>
+ <li> The primary subtag is lower case, the suggested practice of ISO 639.
+ <li> All 2 letter secondary subtags are upper case, the suggested practice of ISO 3166.
+ <li> All other subtags are lower case. The XMP specification defines an artificial language,
+ <li>"x-default", that is used to explicitly denote a default item in an alt-text array.
+ </ul>
+ The XMP toolkit normalizes alt-text arrays such that the x-default item is the first item.
+ The SetLocalizedText function has several special features related to the x-default item, see
+ its description for details. The selection of the array item is the same for GetLocalizedText
+ and SetLocalizedText:
+ <ul>
+ <li> Look for an exact match with the specific language.
+ <li> If a generic language is given, look for a partial match.
+ <li> Look for an x-default item.
+ <li> Choose the first item.
+ </ul>
+ A partial match with the generic language is where the start of the item's language matches
+ the generic string and the next character is '-'. An exact match is also recognized as a
+ degenerate case. It is fine to pass x-default as the specific language. In this case,
+ selection of an x-default item is an exact match by the first rule, not a selection by the
+ 3rd rule. The last 2 rules are fallbacks used when the specific and generic languages fail to
+ produce a match. <code>getLocalizedText</code> returns information about a selected item in
+ an alt-text array. The array item is selected according to the rules given above.
+
+ <em>Note:</em> In a future version of this API a method
+ using Java <code>java.lang.Locale</code> will be added.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>schemaNS</CODE> - The namespace URI for the alt-text array. Has the same usage as in
+ <code>getProperty()</code>.<DD><CODE>altTextName</CODE> - The name of the alt-text array. May be a general path expression, must not
+ be <code>null</code> or the empty string. Has the same namespace prefix usage as
+ propName in <code>getProperty()</code>.<DD><CODE>genericLang</CODE> - The name of the generic language as an RFC 3066 primary subtag. May be
+ <code>null</code> or the empty string if no generic language is wanted.<DD><CODE>specificLang</CODE> - The name of the specific language as an RFC 3066 tag. Must not be
+ <code>null</code> or the empty string.
+<DT><B>Returns:</B><DD>Returns an <code>XMPProperty</code> containing the value, the actual language and
+ the options if an appropriate alternate collection item exists, <code>null</code>
+ if the property.
+ does not exist.
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Wraps all errors and exceptions that may occur.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setLocalizedText(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, com.adobe.xmp.options.PropertyOptions)"><!-- --></A><H3>
+setLocalizedText</H3>
+<PRE>
+void <B>setLocalizedText</B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;altTextName,
+ java.lang.String&nbsp;genericLang,
+ java.lang.String&nbsp;specificLang,
+ java.lang.String&nbsp;itemValue,
+ <A HREF="../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Modifies the value of a selected item in an alt-text array. Creates an appropriate array item
+ if necessary, and handles special cases for the x-default item. If the selected item is from
+ a match with the specific language, the value of that item is modified. If the existing value
+ of that item matches the existing value of the x-default item, the x-default item is also
+ modified. If the array only has 1 existing item (which is not x-default), an x-default item
+ is added with the given value. If the selected item is from a match with the generic language
+ and there are no other generic matches, the value of that item is modified. If the existing
+ value of that item matches the existing value of the x-default item, the x-default item is
+ also modified. If the array only has 1 existing item (which is not x-default), an x-default
+ item is added with the given value. If the selected item is from a partial match with the
+ generic language and there are other partial matches, a new item is created for the specific
+ language. The x-default item is not modified. If the selected item is from the last 2 rules
+ then a new item is created for the specific language. If the array only had an x-default
+ item, the x-default item is also modified. If the array was empty, items are created for the
+ specific language and x-default.
+
+ <em>Note:</em> In a future version of this API a method
+ using Java <code>java.lang.Locale</code> will be added.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>schemaNS</CODE> - The namespace URI for the alt-text array. Has the same usage as in
+ <code>getProperty()</code>.<DD><CODE>altTextName</CODE> - The name of the alt-text array. May be a general path expression, must not
+ be <code>null</code> or the empty string. Has the same namespace prefix usage as
+ propName in <code>getProperty()</code>.<DD><CODE>genericLang</CODE> - The name of the generic language as an RFC 3066 primary subtag. May be
+ <code>null</code> or the empty string if no generic language is wanted.<DD><CODE>specificLang</CODE> - The name of the specific language as an RFC 3066 tag. Must not be
+ <code>null</code> or the empty string.<DD><CODE>itemValue</CODE> - A pointer to the <code>null</code> terminated UTF-8 string that is the new
+ value for the appropriate array item.<DD><CODE>options</CODE> - Option flags, none are defined at present.
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Wraps all errors and exceptions that may occur.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setLocalizedText(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String)"><!-- --></A><H3>
+setLocalizedText</H3>
+<PRE>
+void <B>setLocalizedText</B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;altTextName,
+ java.lang.String&nbsp;genericLang,
+ java.lang.String&nbsp;specificLang,
+ java.lang.String&nbsp;itemValue)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>schemaNS</CODE> - The namespace URI for the alt-text array<DD><CODE>altTextName</CODE> - The name of the alt-text array<DD><CODE>genericLang</CODE> - The name of the generic language<DD><CODE>specificLang</CODE> - The name of the specific language<DD><CODE>itemValue</CODE> - the new value for the appropriate array item
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Wraps all errors and exceptions<DT><B>See Also:</B><DD><A HREF="../../../com/adobe/xmp/XMPMeta.html#setLocalizedText(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, com.adobe.xmp.options.PropertyOptions)"><CODE>setLocalizedText(String, String, String, String, String, PropertyOptions)</CODE></A></DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getPropertyBoolean(java.lang.String, java.lang.String)"><!-- --></A><H3>
+getPropertyBoolean</H3>
+<PRE>
+java.lang.Boolean <B>getPropertyBoolean</B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>These are very similar to <code>getProperty()</code> and <code>SetProperty()</code> above,
+ but the value is returned or provided in a literal form instead of as a UTF-8 string.
+ The path composition functions in <code>XMPPathFactory</code> may be used to compose an path
+ expression for fields in nested structures, items in arrays, or qualifiers.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>schemaNS</CODE> - The namespace URI for the property. Has the same usage as in
+ <code>getProperty()</code>.<DD><CODE>propName</CODE> - The name of the property.
+ Has the same usage as in <code>getProperty()</code>.
+<DT><B>Returns:</B><DD>Returns a <code>Boolean</code> value or <code>null</code>
+ if the property does not exist.
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Wraps all exceptions that may occur,
+ especially conversion errors.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getPropertyInteger(java.lang.String, java.lang.String)"><!-- --></A><H3>
+getPropertyInteger</H3>
+<PRE>
+java.lang.Integer <B>getPropertyInteger</B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Convenience method to retrieve the literal value of a property.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>schemaNS</CODE> - The namespace URI for the property. Has the same usage as in
+ <code>getProperty()</code>.<DD><CODE>propName</CODE> - The name of the property.
+ Has the same usage as in <code>getProperty()</code>.
+<DT><B>Returns:</B><DD>Returns an <code>Integer</code> value or <code>null</code>
+ if the property does not exist.
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Wraps all exceptions that may occur,
+ especially conversion errors.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getPropertyLong(java.lang.String, java.lang.String)"><!-- --></A><H3>
+getPropertyLong</H3>
+<PRE>
+java.lang.Long <B>getPropertyLong</B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Convenience method to retrieve the literal value of a property.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>schemaNS</CODE> - The namespace URI for the property. Has the same usage as in
+ <code>getProperty()</code>.<DD><CODE>propName</CODE> - The name of the property.
+ Has the same usage as in <code>getProperty()</code>.
+<DT><B>Returns:</B><DD>Returns a <code>Long</code> value or <code>null</code>
+ if the property does not exist.
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Wraps all exceptions that may occur,
+ especially conversion errors.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getPropertyDouble(java.lang.String, java.lang.String)"><!-- --></A><H3>
+getPropertyDouble</H3>
+<PRE>
+java.lang.Double <B>getPropertyDouble</B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Convenience method to retrieve the literal value of a property.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>schemaNS</CODE> - The namespace URI for the property. Has the same usage as in
+ <code>getProperty()</code>.<DD><CODE>propName</CODE> - The name of the property.
+ Has the same usage as in <code>getProperty()</code>.
+<DT><B>Returns:</B><DD>Returns a <code>Double</code> value or <code>null</code>
+ if the property does not exist.
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Wraps all exceptions that may occur,
+ especially conversion errors.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getPropertyDate(java.lang.String, java.lang.String)"><!-- --></A><H3>
+getPropertyDate</H3>
+<PRE>
+<A HREF="../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A> <B>getPropertyDate</B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Convenience method to retrieve the literal value of a property.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>schemaNS</CODE> - The namespace URI for the property. Has the same usage as in
+ <code>getProperty()</code>.<DD><CODE>propName</CODE> - The name of the property.
+ Has the same usage as in <code>getProperty()</code>.
+<DT><B>Returns:</B><DD>Returns a <code>XMPDateTime</code>-object or <code>null</code>
+ if the property does not exist.
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Wraps all exceptions that may occur,
+ especially conversion errors.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getPropertyCalendar(java.lang.String, java.lang.String)"><!-- --></A><H3>
+getPropertyCalendar</H3>
+<PRE>
+java.util.Calendar <B>getPropertyCalendar</B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Convenience method to retrieve the literal value of a property.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>schemaNS</CODE> - The namespace URI for the property. Has the same usage as in
+ <code>getProperty()</code>.<DD><CODE>propName</CODE> - The name of the property.
+ Has the same usage as in <code>getProperty()</code>.
+<DT><B>Returns:</B><DD>Returns a Java <code>Calendar</code>-object or <code>null</code>
+ if the property does not exist.
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Wraps all exceptions that may occur,
+ especially conversion errors.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getPropertyBase64(java.lang.String, java.lang.String)"><!-- --></A><H3>
+getPropertyBase64</H3>
+<PRE>
+byte[] <B>getPropertyBase64</B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Convenience method to retrieve the literal value of a property.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>schemaNS</CODE> - The namespace URI for the property. Has the same usage as in
+ <code>getProperty()</code>.<DD><CODE>propName</CODE> - The name of the property.
+ Has the same usage as in <code>getProperty()</code>.
+<DT><B>Returns:</B><DD>Returns a <code>byte[]</code>-array contained the decoded base64 value
+ or <code>null</code> if the property does not exist.
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Wraps all exceptions that may occur,
+ especially conversion errors.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getPropertyString(java.lang.String, java.lang.String)"><!-- --></A><H3>
+getPropertyString</H3>
+<PRE>
+java.lang.String <B>getPropertyString</B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Convenience method to retrieve the literal value of a property.
+ <em>Note:</em> There is no <code>setPropertyString()</code>,
+ because <code>setProperty()</code> sets a string value.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>schemaNS</CODE> - The namespace URI for the property. Has the same usage as in
+ <code>getProperty()</code>.<DD><CODE>propName</CODE> - The name of the property.
+ Has the same usage as in <code>getProperty()</code>.
+<DT><B>Returns:</B><DD>Returns a <code>String</code> value or <code>null</code>
+ if the property does not exist.
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Wraps all exceptions that may occur,
+ especially conversion errors.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setPropertyBoolean(java.lang.String, java.lang.String, boolean, com.adobe.xmp.options.PropertyOptions)"><!-- --></A><H3>
+setPropertyBoolean</H3>
+<PRE>
+void <B>setPropertyBoolean</B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ boolean&nbsp;propValue,
+ <A HREF="../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Convenience method to set a property to a literal <code>boolean</code> value.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>schemaNS</CODE> - The namespace URI for the property. Has the same usage as in
+ <code>setProperty()</code>.<DD><CODE>propName</CODE> - The name of the property.
+ Has the same usage as in <code>getProperty()</code>.<DD><CODE>propValue</CODE> - the literal property value as <code>boolean</code>.<DD><CODE>options</CODE> - options of the property to set (optional).
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Wraps all exceptions that may occur.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setPropertyBoolean(java.lang.String, java.lang.String, boolean)"><!-- --></A><H3>
+setPropertyBoolean</H3>
+<PRE>
+void <B>setPropertyBoolean</B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ boolean&nbsp;propValue)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>schemaNS</CODE> - The namespace URI for the property<DD><CODE>propName</CODE> - The name of the property<DD><CODE>propValue</CODE> - the literal property value as <code>boolean</code>
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Wraps all exceptions<DT><B>See Also:</B><DD><A HREF="../../../com/adobe/xmp/XMPMeta.html#setPropertyBoolean(java.lang.String, java.lang.String, boolean, com.adobe.xmp.options.PropertyOptions)"><CODE>setPropertyBoolean(String, String, boolean, PropertyOptions)</CODE></A></DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setPropertyInteger(java.lang.String, java.lang.String, int, com.adobe.xmp.options.PropertyOptions)"><!-- --></A><H3>
+setPropertyInteger</H3>
+<PRE>
+void <B>setPropertyInteger</B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ int&nbsp;propValue,
+ <A HREF="../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Convenience method to set a property to a literal <code>int</code> value.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>schemaNS</CODE> - The namespace URI for the property. Has the same usage as in
+ <code>setProperty()</code>.<DD><CODE>propName</CODE> - The name of the property.
+ Has the same usage as in <code>getProperty()</code>.<DD><CODE>propValue</CODE> - the literal property value as <code>int</code>.<DD><CODE>options</CODE> - options of the property to set (optional).
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Wraps all exceptions that may occur.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setPropertyInteger(java.lang.String, java.lang.String, int)"><!-- --></A><H3>
+setPropertyInteger</H3>
+<PRE>
+void <B>setPropertyInteger</B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ int&nbsp;propValue)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>schemaNS</CODE> - The namespace URI for the property<DD><CODE>propName</CODE> - The name of the property<DD><CODE>propValue</CODE> - the literal property value as <code>int</code>
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Wraps all exceptions<DT><B>See Also:</B><DD><A HREF="../../../com/adobe/xmp/XMPMeta.html#setPropertyInteger(java.lang.String, java.lang.String, int, com.adobe.xmp.options.PropertyOptions)"><CODE>setPropertyInteger(String, String, int, PropertyOptions)</CODE></A></DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setPropertyLong(java.lang.String, java.lang.String, long, com.adobe.xmp.options.PropertyOptions)"><!-- --></A><H3>
+setPropertyLong</H3>
+<PRE>
+void <B>setPropertyLong</B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ long&nbsp;propValue,
+ <A HREF="../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Convenience method to set a property to a literal <code>long</code> value.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>schemaNS</CODE> - The namespace URI for the property. Has the same usage as in
+ <code>setProperty()</code>.<DD><CODE>propName</CODE> - The name of the property.
+ Has the same usage as in <code>getProperty()</code>.<DD><CODE>propValue</CODE> - the literal property value as <code>long</code>.<DD><CODE>options</CODE> - options of the property to set (optional).
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Wraps all exceptions that may occur.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setPropertyLong(java.lang.String, java.lang.String, long)"><!-- --></A><H3>
+setPropertyLong</H3>
+<PRE>
+void <B>setPropertyLong</B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ long&nbsp;propValue)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>schemaNS</CODE> - The namespace URI for the property<DD><CODE>propName</CODE> - The name of the property<DD><CODE>propValue</CODE> - the literal property value as <code>long</code>
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Wraps all exceptions<DT><B>See Also:</B><DD><A HREF="../../../com/adobe/xmp/XMPMeta.html#setPropertyLong(java.lang.String, java.lang.String, long, com.adobe.xmp.options.PropertyOptions)"><CODE>setPropertyLong(String, String, long, PropertyOptions)</CODE></A></DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setPropertyDouble(java.lang.String, java.lang.String, double, com.adobe.xmp.options.PropertyOptions)"><!-- --></A><H3>
+setPropertyDouble</H3>
+<PRE>
+void <B>setPropertyDouble</B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ double&nbsp;propValue,
+ <A HREF="../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Convenience method to set a property to a literal <code>double</code> value.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>schemaNS</CODE> - The namespace URI for the property. Has the same usage as in
+ <code>setProperty()</code>.<DD><CODE>propName</CODE> - The name of the property.
+ Has the same usage as in <code>getProperty()</code>.<DD><CODE>propValue</CODE> - the literal property value as <code>double</code>.<DD><CODE>options</CODE> - options of the property to set (optional).
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Wraps all exceptions that may occur.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setPropertyDouble(java.lang.String, java.lang.String, double)"><!-- --></A><H3>
+setPropertyDouble</H3>
+<PRE>
+void <B>setPropertyDouble</B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ double&nbsp;propValue)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>schemaNS</CODE> - The namespace URI for the property<DD><CODE>propName</CODE> - The name of the property<DD><CODE>propValue</CODE> - the literal property value as <code>double</code>
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Wraps all exceptions<DT><B>See Also:</B><DD><A HREF="../../../com/adobe/xmp/XMPMeta.html#setPropertyDouble(java.lang.String, java.lang.String, double, com.adobe.xmp.options.PropertyOptions)"><CODE>setPropertyDouble(String, String, double, PropertyOptions)</CODE></A></DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setPropertyDate(java.lang.String, java.lang.String, com.adobe.xmp.XMPDateTime, com.adobe.xmp.options.PropertyOptions)"><!-- --></A><H3>
+setPropertyDate</H3>
+<PRE>
+void <B>setPropertyDate</B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ <A HREF="../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A>&nbsp;propValue,
+ <A HREF="../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Convenience method to set a property with an XMPDateTime-object,
+ which is serialized to an ISO8601 date.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>schemaNS</CODE> - The namespace URI for the property. Has the same usage as in
+ <code>setProperty()</code>.<DD><CODE>propName</CODE> - The name of the property.
+ Has the same usage as in <code>getProperty()</code>.<DD><CODE>propValue</CODE> - the property value as <code>XMPDateTime</code>.<DD><CODE>options</CODE> - options of the property to set (optional).
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Wraps all exceptions that may occur.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setPropertyDate(java.lang.String, java.lang.String, com.adobe.xmp.XMPDateTime)"><!-- --></A><H3>
+setPropertyDate</H3>
+<PRE>
+void <B>setPropertyDate</B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ <A HREF="../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A>&nbsp;propValue)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>schemaNS</CODE> - The namespace URI for the property<DD><CODE>propName</CODE> - The name of the property<DD><CODE>propValue</CODE> - the property value as <code>XMPDateTime</code>
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Wraps all exceptions<DT><B>See Also:</B><DD><A HREF="../../../com/adobe/xmp/XMPMeta.html#setPropertyDate(java.lang.String, java.lang.String, com.adobe.xmp.XMPDateTime, com.adobe.xmp.options.PropertyOptions)"><CODE>setPropertyDate(String, String, XMPDateTime, PropertyOptions)</CODE></A></DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setPropertyCalendar(java.lang.String, java.lang.String, java.util.Calendar, com.adobe.xmp.options.PropertyOptions)"><!-- --></A><H3>
+setPropertyCalendar</H3>
+<PRE>
+void <B>setPropertyCalendar</B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ java.util.Calendar&nbsp;propValue,
+ <A HREF="../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Convenience method to set a property with a Java Calendar-object,
+ which is serialized to an ISO8601 date.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>schemaNS</CODE> - The namespace URI for the property. Has the same usage as in
+ <code>setProperty()</code>.<DD><CODE>propName</CODE> - The name of the property.
+ Has the same usage as in <code>getProperty()</code>.<DD><CODE>propValue</CODE> - the property value as Java <code>Calendar</code>.<DD><CODE>options</CODE> - options of the property to set (optional).
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Wraps all exceptions that may occur.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setPropertyCalendar(java.lang.String, java.lang.String, java.util.Calendar)"><!-- --></A><H3>
+setPropertyCalendar</H3>
+<PRE>
+void <B>setPropertyCalendar</B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ java.util.Calendar&nbsp;propValue)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>schemaNS</CODE> - The namespace URI for the property<DD><CODE>propName</CODE> - The name of the property<DD><CODE>propValue</CODE> - the property value as <code>Calendar</code>
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Wraps all exceptions<DT><B>See Also:</B><DD><A HREF="../../../com/adobe/xmp/XMPMeta.html#setPropertyCalendar(java.lang.String, java.lang.String, java.util.Calendar, com.adobe.xmp.options.PropertyOptions)"><CODE>setPropertyCalendar(String, String, Calendar, PropertyOptions)</CODE></A></DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setPropertyBase64(java.lang.String, java.lang.String, byte[], com.adobe.xmp.options.PropertyOptions)"><!-- --></A><H3>
+setPropertyBase64</H3>
+<PRE>
+void <B>setPropertyBase64</B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ byte[]&nbsp;propValue,
+ <A HREF="../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Convenience method to set a property from a binary <code>byte[]</code>-array,
+ which is serialized as base64-string.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>schemaNS</CODE> - The namespace URI for the property. Has the same usage as in
+ <code>setProperty()</code>.<DD><CODE>propName</CODE> - The name of the property.
+ Has the same usage as in <code>getProperty()</code>.<DD><CODE>propValue</CODE> - the literal property value as byte array.<DD><CODE>options</CODE> - options of the property to set (optional).
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Wraps all exceptions that may occur.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setPropertyBase64(java.lang.String, java.lang.String, byte[])"><!-- --></A><H3>
+setPropertyBase64</H3>
+<PRE>
+void <B>setPropertyBase64</B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ byte[]&nbsp;propValue)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>schemaNS</CODE> - The namespace URI for the property<DD><CODE>propName</CODE> - The name of the property<DD><CODE>propValue</CODE> - the literal property value as byte array
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Wraps all exceptions<DT><B>See Also:</B><DD><A HREF="../../../com/adobe/xmp/XMPMeta.html#setPropertyBase64(java.lang.String, java.lang.String, byte[], com.adobe.xmp.options.PropertyOptions)"><CODE>setPropertyBase64(String, String, byte[], PropertyOptions)</CODE></A></DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="iterator()"><!-- --></A><H3>
+iterator</H3>
+<PRE>
+<A HREF="../../../com/adobe/xmp/XMPIterator.html" title="interface in com.adobe.xmp">XMPIterator</A> <B>iterator</B>()
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Constructs an iterator for the properties within this XMP object.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns an <code>XMPIterator</code>.
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Wraps all errors and exceptions that may occur.<DT><B>See Also:</B><DD><A HREF="../../../com/adobe/xmp/XMPMeta.html#iterator(java.lang.String, java.lang.String, com.adobe.xmp.options.IteratorOptions)"><CODE>iterator(String, String, IteratorOptions)</CODE></A></DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="iterator(com.adobe.xmp.options.IteratorOptions)"><!-- --></A><H3>
+iterator</H3>
+<PRE>
+<A HREF="../../../com/adobe/xmp/XMPIterator.html" title="interface in com.adobe.xmp">XMPIterator</A> <B>iterator</B>(<A HREF="../../../com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options">IteratorOptions</A>&nbsp;options)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Constructs an iterator for the properties within this XMP object using some options.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>options</CODE> - Option flags to control the iteration.
+<DT><B>Returns:</B><DD>Returns an <code>XMPIterator</code>.
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Wraps all errors and exceptions that may occur.<DT><B>See Also:</B><DD><A HREF="../../../com/adobe/xmp/XMPMeta.html#iterator(java.lang.String, java.lang.String, com.adobe.xmp.options.IteratorOptions)"><CODE>iterator(String, String, IteratorOptions)</CODE></A></DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="iterator(java.lang.String, java.lang.String, com.adobe.xmp.options.IteratorOptions)"><!-- --></A><H3>
+iterator</H3>
+<PRE>
+<A HREF="../../../com/adobe/xmp/XMPIterator.html" title="interface in com.adobe.xmp">XMPIterator</A> <B>iterator</B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ <A HREF="../../../com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options">IteratorOptions</A>&nbsp;options)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Construct an iterator for the properties within an XMP object. The general operation of an
+ XMP object iterator was. According to the parameters it iterates the entire data tree,
+ properties within a specific schema, or a subtree rooted at a specific node.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>schemaNS</CODE> - Optional schema namespace URI to restrict the iteration. Omitted (visit all
+ schema) by passing <code>null</code> or empty String.<DD><CODE>propName</CODE> - Optional property name to restrict the iteration. May be an arbitrary path
+ expression. Omitted (visit all properties) by passing <code>null</code> or empty
+ String. If no schema URI is given, it is ignored.<DD><CODE>options</CODE> - Option flags to control the iteration. See <A HREF="../../../com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options"><CODE>IteratorOptions</CODE></A> for
+ details.
+<DT><B>Returns:</B><DD>Returns an <code>XMPIterator</code> for this <code>XMPMeta</code>-object
+ considering the given options.
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Wraps all errors and exceptions that may occur.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getObjectName()"><!-- --></A><H3>
+getObjectName</H3>
+<PRE>
+java.lang.String <B>getObjectName</B>()</PRE>
+<DL>
+<DD>This correlates to the about-attribute,
+ returns the empty String if no name is set.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns the name of the XMP object.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setObjectName(java.lang.String)"><!-- --></A><H3>
+setObjectName</H3>
+<PRE>
+void <B>setObjectName</B>(java.lang.String&nbsp;name)</PRE>
+<DL>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>name</CODE> - Sets the name of the XMP object.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="clone()"><!-- --></A><H3>
+clone</H3>
+<PRE>
+java.lang.Object <B>clone</B>()</PRE>
+<DL>
+<DD>Clones the complete metadata tree.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns a deep copy of this instance.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="sort()"><!-- --></A><H3>
+sort</H3>
+<PRE>
+void <B>sort</B>()</PRE>
+<DL>
+<DD>Sorts the complete datamodel according to the following rules:
+ <ul>
+ <li>Schema nodes are sorted by prefix.
+ <li>Properties at top level and within structs are sorted by full name, that is
+ prefix + local name.
+ <li>Array items are not sorted, even if they have no certain order such as bags.
+ <li>Qualifier are sorted, with the exception of "xml:lang" and/or "rdf:type"
+ that stay at the top of the list in that order.
+ </ul>
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="dumpObject()"><!-- --></A><H3>
+dumpObject</H3>
+<PRE>
+java.lang.String <B>dumpObject</B>()</PRE>
+<DL>
+<DD>Renders this node and the tree unter this node in a human readable form.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns a multiline string containing the dump.</DL>
+</DD>
+</DL>
+<!-- ========= END OF CLASS DATA ========= -->
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="class-use/XMPMeta.html"><FONT CLASS="NavBarFont1"><B>Use</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="../../../com/adobe/xmp/XMPIterator.html" title="interface in com.adobe.xmp"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;<A HREF="../../../com/adobe/xmp/XMPMetaFactory.html" title="class in com.adobe.xmp"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../index.html?com/adobe/xmp/XMPMeta.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPMeta.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+ SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;FIELD&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;FIELD&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/com/adobe/xmp/XMPMetaFactory.html b/java/XMPCore/docs/com/adobe/xmp/XMPMetaFactory.html
new file mode 100644
index 0000000..6dbe0aa
--- /dev/null
+++ b/java/XMPCore/docs/com/adobe/xmp/XMPMetaFactory.html
@@ -0,0 +1,571 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:50 CEST 2007 -->
+<TITLE>
+XMPMetaFactory
+</TITLE>
+
+<META NAME="keywords" CONTENT="com.adobe.xmp.XMPMetaFactory class">
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="XMPMetaFactory";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="class-use/XMPMetaFactory.html"><FONT CLASS="NavBarFont1"><B>Use</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;<A HREF="../../../com/adobe/xmp/XMPPathFactory.html" title="class in com.adobe.xmp"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../index.html?com/adobe/xmp/XMPMetaFactory.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPMetaFactory.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+ SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;FIELD&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;FIELD&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<!-- ======== START OF CLASS DATA ======== -->
+<H2>
+<FONT SIZE="-1">
+com.adobe.xmp</FONT>
+<BR>
+Class XMPMetaFactory</H2>
+<PRE>
+java.lang.Object
+ <IMG SRC="../../../resources/inherit.gif" ALT="extended by "><B>com.adobe.xmp.XMPMetaFactory</B>
+</PRE>
+<HR>
+<DL>
+<DT><PRE>public final class <B>XMPMetaFactory</B><DT>extends java.lang.Object</DL>
+</PRE>
+
+<P>
+Creates <code>XMPMeta</code>-instances from an <code>InputStream</code>
+<P>
+
+<P>
+<DL>
+<DT><B>Since:</B></DT>
+ <DD>30.01.2006</DD>
+</DL>
+<HR>
+
+<P>
+
+<!-- ========== METHOD SUMMARY =========== -->
+
+<A NAME="method_summary"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+<B>Method Summary</B></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;<A HREF="../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMetaFactory.html#create()">create</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;<A HREF="../../../com/adobe/xmp/XMPSchemaRegistry.html" title="interface in com.adobe.xmp">XMPSchemaRegistry</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMetaFactory.html#getSchemaRegistry()">getSchemaRegistry</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;<A HREF="../../../com/adobe/xmp/XMPVersionInfo.html" title="interface in com.adobe.xmp">XMPVersionInfo</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMetaFactory.html#getVersionInfo()">getVersionInfo</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Obtain version information.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;<A HREF="../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMetaFactory.html#parse(java.io.InputStream)">parse</A></B>(java.io.InputStream&nbsp;in)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Parsing with default options.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;<A HREF="../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMetaFactory.html#parse(java.io.InputStream, com.adobe.xmp.options.ParseOptions)">parse</A></B>(java.io.InputStream&nbsp;in,
+ <A HREF="../../../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options">ParseOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;These functions support parsing serialized RDF into an XMP object, and serailizing an XMP
+ object into RDF.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;<A HREF="../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMetaFactory.html#parseFromBuffer(byte[])">parseFromBuffer</A></B>(byte[]&nbsp;buffer)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Parsing with default options.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;<A HREF="../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMetaFactory.html#parseFromBuffer(byte[], com.adobe.xmp.options.ParseOptions)">parseFromBuffer</A></B>(byte[]&nbsp;buffer,
+ <A HREF="../../../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options">ParseOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Creates an <code>XMPMeta</code>-object from a byte-buffer.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;<A HREF="../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMetaFactory.html#parseFromString(java.lang.String)">parseFromString</A></B>(java.lang.String&nbsp;packet)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Parsing with default options.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;<A HREF="../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMetaFactory.html#parseFromString(java.lang.String, com.adobe.xmp.options.ParseOptions)">parseFromString</A></B>(java.lang.String&nbsp;packet,
+ <A HREF="../../../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options">ParseOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Creates an <code>XMPMeta</code>-object from a string.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMetaFactory.html#reset()">reset</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Resets the schema registry to its original state (creates a new one).</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMetaFactory.html#serialize(com.adobe.xmp.XMPMeta, java.io.OutputStream)">serialize</A></B>(<A HREF="../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>&nbsp;xmp,
+ java.io.OutputStream&nbsp;out)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Serializes an <code>XMPMeta</code>-object as RDF into an <code>OutputStream</code>
+ with default options.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMetaFactory.html#serialize(com.adobe.xmp.XMPMeta, java.io.OutputStream, com.adobe.xmp.options.SerializeOptions)">serialize</A></B>(<A HREF="../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>&nbsp;xmp,
+ java.io.OutputStream&nbsp;out,
+ <A HREF="../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Serializes an <code>XMPMeta</code>-object as RDF into an <code>OutputStream</code>.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;byte[]</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMetaFactory.html#serializeToBuffer(com.adobe.xmp.XMPMeta, com.adobe.xmp.options.SerializeOptions)">serializeToBuffer</A></B>(<A HREF="../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>&nbsp;xmp,
+ <A HREF="../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Serializes an <code>XMPMeta</code>-object as RDF into a byte buffer.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPMetaFactory.html#serializeToString(com.adobe.xmp.XMPMeta, com.adobe.xmp.options.SerializeOptions)">serializeToString</A></B>(<A HREF="../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>&nbsp;xmp,
+ <A HREF="../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Serializes an <code>XMPMeta</code>-object as RDF into a string.</TD>
+</TR>
+</TABLE>
+&nbsp;<A NAME="methods_inherited_from_class_java.lang.Object"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#EEEEFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="left"><B>Methods inherited from class java.lang.Object</B></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE>equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait</CODE></TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<!-- ============ METHOD DETAIL ========== -->
+
+<A NAME="method_detail"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="1"><FONT SIZE="+2">
+<B>Method Detail</B></FONT></TH>
+</TR>
+</TABLE>
+
+<A NAME="getSchemaRegistry()"><!-- --></A><H3>
+getSchemaRegistry</H3>
+<PRE>
+public static <A HREF="../../../com/adobe/xmp/XMPSchemaRegistry.html" title="interface in com.adobe.xmp">XMPSchemaRegistry</A> <B>getSchemaRegistry</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns the singleton instance of the <code>XMPSchemaRegistry</code>.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="create()"><!-- --></A><H3>
+create</H3>
+<PRE>
+public static <A HREF="../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A> <B>create</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns an empty <code>XMPMeta</code>-object.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="parse(java.io.InputStream)"><!-- --></A><H3>
+parse</H3>
+<PRE>
+public static <A HREF="../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A> <B>parse</B>(java.io.InputStream&nbsp;in)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Parsing with default options.
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>in</CODE> - an <code>InputStream</code>
+<DT><B>Returns:</B><DD>Returns the <code>XMPMeta</code>-object created from the input.
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - If the file is not well-formed XML or if the parsing fails.<DT><B>See Also:</B><DD><A HREF="../../../com/adobe/xmp/XMPMetaFactory.html#parse(java.io.InputStream, com.adobe.xmp.options.ParseOptions)"><CODE>parse(InputStream, ParseOptions)</CODE></A></DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="parse(java.io.InputStream, com.adobe.xmp.options.ParseOptions)"><!-- --></A><H3>
+parse</H3>
+<PRE>
+public static <A HREF="../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A> <B>parse</B>(java.io.InputStream&nbsp;in,
+ <A HREF="../../../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options">ParseOptions</A>&nbsp;options)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>These functions support parsing serialized RDF into an XMP object, and serailizing an XMP
+ object into RDF. The input for parsing may be any valid Unicode
+ encoding. ISO Latin-1 is also recognized, but its use is strongly discouraged. Serialization
+ is always as UTF-8.
+ <p>
+ <code>parseFromBuffer()</code> parses RDF from an <code>InputStream</code>. The encoding
+ is recognized automatically.
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>in</CODE> - an <code>InputStream</code><DD><CODE>options</CODE> - Options controlling the parsing.<br>
+ The available options are:
+ <ul>
+ <li> XMP_REQUIRE_XMPMETA - The &lt;x:xmpmeta&gt; XML element is required around
+ <tt>&lt;rdf:RDF&gt;</tt>.
+ <li> XMP_STRICT_ALIASING - Do not reconcile alias differences, throw an exception.
+ </ul>
+ <em>Note:</em>The XMP_STRICT_ALIASING option is not yet implemented.
+<DT><B>Returns:</B><DD>Returns the <code>XMPMeta</code>-object created from the input.
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - If the file is not well-formed XML or if the parsing fails.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="parseFromString(java.lang.String)"><!-- --></A><H3>
+parseFromString</H3>
+<PRE>
+public static <A HREF="../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A> <B>parseFromString</B>(java.lang.String&nbsp;packet)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Parsing with default options.
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>packet</CODE> - a String contain an XMP-file.
+<DT><B>Returns:</B><DD>Returns the <code>XMPMeta</code>-object created from the input.
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - If the file is not well-formed XML or if the parsing fails.<DT><B>See Also:</B><DD><A HREF="../../../com/adobe/xmp/XMPMetaFactory.html#parse(java.io.InputStream)"><CODE>parse(InputStream)</CODE></A></DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="parseFromString(java.lang.String, com.adobe.xmp.options.ParseOptions)"><!-- --></A><H3>
+parseFromString</H3>
+<PRE>
+public static <A HREF="../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A> <B>parseFromString</B>(java.lang.String&nbsp;packet,
+ <A HREF="../../../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options">ParseOptions</A>&nbsp;options)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Creates an <code>XMPMeta</code>-object from a string.
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>packet</CODE> - a String contain an XMP-file.<DD><CODE>options</CODE> - Options controlling the parsing.
+<DT><B>Returns:</B><DD>Returns the <code>XMPMeta</code>-object created from the input.
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - If the file is not well-formed XML or if the parsing fails.<DT><B>See Also:</B><DD><A HREF="../../../com/adobe/xmp/XMPMetaFactory.html#parseFromString(java.lang.String, com.adobe.xmp.options.ParseOptions)"><CODE>parseFromString(String, ParseOptions)</CODE></A></DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="parseFromBuffer(byte[])"><!-- --></A><H3>
+parseFromBuffer</H3>
+<PRE>
+public static <A HREF="../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A> <B>parseFromBuffer</B>(byte[]&nbsp;buffer)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Parsing with default options.
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>buffer</CODE> - a String contain an XMP-file.
+<DT><B>Returns:</B><DD>Returns the <code>XMPMeta</code>-object created from the input.
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - If the file is not well-formed XML or if the parsing fails.<DT><B>See Also:</B><DD><A HREF="../../../com/adobe/xmp/XMPMetaFactory.html#parseFromBuffer(byte[], com.adobe.xmp.options.ParseOptions)"><CODE>parseFromBuffer(byte[], ParseOptions)</CODE></A></DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="parseFromBuffer(byte[], com.adobe.xmp.options.ParseOptions)"><!-- --></A><H3>
+parseFromBuffer</H3>
+<PRE>
+public static <A HREF="../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A> <B>parseFromBuffer</B>(byte[]&nbsp;buffer,
+ <A HREF="../../../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options">ParseOptions</A>&nbsp;options)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Creates an <code>XMPMeta</code>-object from a byte-buffer.
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>buffer</CODE> - a String contain an XMP-file.<DD><CODE>options</CODE> - Options controlling the parsing.
+<DT><B>Returns:</B><DD>Returns the <code>XMPMeta</code>-object created from the input.
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - If the file is not well-formed XML or if the parsing fails.<DT><B>See Also:</B><DD><A HREF="../../../com/adobe/xmp/XMPMetaFactory.html#parse(java.io.InputStream, com.adobe.xmp.options.ParseOptions)"><CODE>parse(InputStream, ParseOptions)</CODE></A></DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="serialize(com.adobe.xmp.XMPMeta, java.io.OutputStream)"><!-- --></A><H3>
+serialize</H3>
+<PRE>
+public static void <B>serialize</B>(<A HREF="../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>&nbsp;xmp,
+ java.io.OutputStream&nbsp;out)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Serializes an <code>XMPMeta</code>-object as RDF into an <code>OutputStream</code>
+ with default options.
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>xmp</CODE> - a metadata object<DD><CODE>out</CODE> - an <code>OutputStream</code> to write the serialized RDF to.
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - on serializsation errors.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="serialize(com.adobe.xmp.XMPMeta, java.io.OutputStream, com.adobe.xmp.options.SerializeOptions)"><!-- --></A><H3>
+serialize</H3>
+<PRE>
+public static void <B>serialize</B>(<A HREF="../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>&nbsp;xmp,
+ java.io.OutputStream&nbsp;out,
+ <A HREF="../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>&nbsp;options)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Serializes an <code>XMPMeta</code>-object as RDF into an <code>OutputStream</code>.
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>xmp</CODE> - a metadata object<DD><CODE>options</CODE> - Options to control the serialization (see <A HREF="../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options"><CODE>SerializeOptions</CODE></A>).<DD><CODE>out</CODE> - an <code>OutputStream</code> to write the serialized RDF to.
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - on serializsation errors.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="serializeToBuffer(com.adobe.xmp.XMPMeta, com.adobe.xmp.options.SerializeOptions)"><!-- --></A><H3>
+serializeToBuffer</H3>
+<PRE>
+public static byte[] <B>serializeToBuffer</B>(<A HREF="../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>&nbsp;xmp,
+ <A HREF="../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>&nbsp;options)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Serializes an <code>XMPMeta</code>-object as RDF into a byte buffer.
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>xmp</CODE> - a metadata object<DD><CODE>options</CODE> - Options to control the serialization (see <A HREF="../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options"><CODE>SerializeOptions</CODE></A>).
+<DT><B>Returns:</B><DD>Returns a byte buffer containing the serialized RDF.
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - on serializsation errors.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="serializeToString(com.adobe.xmp.XMPMeta, com.adobe.xmp.options.SerializeOptions)"><!-- --></A><H3>
+serializeToString</H3>
+<PRE>
+public static java.lang.String <B>serializeToString</B>(<A HREF="../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>&nbsp;xmp,
+ <A HREF="../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>&nbsp;options)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Serializes an <code>XMPMeta</code>-object as RDF into a string. <em>Note:</em> Encoding
+ is ignored when serializing to a string.
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>xmp</CODE> - a metadata object<DD><CODE>options</CODE> - Options to control the serialization (see <A HREF="../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options"><CODE>SerializeOptions</CODE></A>).
+<DT><B>Returns:</B><DD>Returns a string containing the serialized RDF.
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - on serializsation errors.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="reset()"><!-- --></A><H3>
+reset</H3>
+<PRE>
+public static void <B>reset</B>()</PRE>
+<DL>
+<DD>Resets the schema registry to its original state (creates a new one).
+ Be careful this might break all existing XMPMeta-objects and should be used
+ only for testing purpurses.
+<P>
+<DD><DL>
+</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getVersionInfo()"><!-- --></A><H3>
+getVersionInfo</H3>
+<PRE>
+public static <A HREF="../../../com/adobe/xmp/XMPVersionInfo.html" title="interface in com.adobe.xmp">XMPVersionInfo</A> <B>getVersionInfo</B>()</PRE>
+<DL>
+<DD>Obtain version information.
+<P>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns the version information.</DL>
+</DD>
+</DL>
+<!-- ========= END OF CLASS DATA ========= -->
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="class-use/XMPMetaFactory.html"><FONT CLASS="NavBarFont1"><B>Use</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;<A HREF="../../../com/adobe/xmp/XMPPathFactory.html" title="class in com.adobe.xmp"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../index.html?com/adobe/xmp/XMPMetaFactory.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPMetaFactory.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+ SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;FIELD&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;FIELD&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/com/adobe/xmp/XMPPathFactory.html b/java/XMPCore/docs/com/adobe/xmp/XMPPathFactory.html
new file mode 100644
index 0000000..b58ed92
--- /dev/null
+++ b/java/XMPCore/docs/com/adobe/xmp/XMPPathFactory.html
@@ -0,0 +1,427 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:50 CEST 2007 -->
+<TITLE>
+XMPPathFactory
+</TITLE>
+
+<META NAME="keywords" CONTENT="com.adobe.xmp.XMPPathFactory class">
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="XMPPathFactory";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="class-use/XMPPathFactory.html"><FONT CLASS="NavBarFont1"><B>Use</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="../../../com/adobe/xmp/XMPMetaFactory.html" title="class in com.adobe.xmp"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;<A HREF="../../../com/adobe/xmp/XMPSchemaRegistry.html" title="interface in com.adobe.xmp"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../index.html?com/adobe/xmp/XMPPathFactory.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPPathFactory.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+ SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;FIELD&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;FIELD&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<!-- ======== START OF CLASS DATA ======== -->
+<H2>
+<FONT SIZE="-1">
+com.adobe.xmp</FONT>
+<BR>
+Class XMPPathFactory</H2>
+<PRE>
+java.lang.Object
+ <IMG SRC="../../../resources/inherit.gif" ALT="extended by "><B>com.adobe.xmp.XMPPathFactory</B>
+</PRE>
+<HR>
+<DL>
+<DT><PRE>public final class <B>XMPPathFactory</B><DT>extends java.lang.Object</DL>
+</PRE>
+
+<P>
+Utility services for the metadata object. It has only public static functions, you cannot create
+ an object. These are all functions that layer cleanly on top of the core XMP toolkit.
+ <p>
+ These functions provide support for composing path expressions to deeply nested properties. The
+ functions <code>XMPMeta</code> such as <code>getProperty()</code>,
+ <code>getArrayItem()</code> and <code>getStructField()</code> provide easy access to top
+ level simple properties, items in top level arrays, and fields of top level structs. They do not
+ provide convenient access to more complex things like fields several levels deep in a complex
+ struct, or fields within an array of structs, or items of an array that is a field of a struct.
+ These functions can also be used to compose paths to top level array items or struct fields so
+ that you can use the binary accessors like <code>getPropertyAsInteger()</code>.
+ <p>
+ You can use these functions is to compose a complete path expression, or all but the last
+ component. Suppose you have a property that is an array of integers within a struct. You can
+ access one of the array items like this:
+ <p>
+ <blockquote>
+
+ <pre>
+ String path = XMPPathFactory.composeStructFieldPath (schemaNS, &quot;Struct&quot;, fieldNS,
+ &quot;Array&quot;);
+ String path += XMPPathFactory.composeArrayItemPath (schemaNS, &quot;Array&quot; index);
+ PropertyInteger result = xmpObj.getPropertyAsInteger(schemaNS, path);
+ </pre>
+
+ </blockquote> You could also use this code if you want the string form of the integer:
+ <blockquote>
+
+ <pre>
+ String path = XMPPathFactory.composeStructFieldPath (schemaNS, &quot;Struct&quot;, fieldNS,
+ &quot;Array&quot;);
+ PropertyText xmpObj.getArrayItem (schemaNS, path, index);
+ </pre>
+
+ </blockquote>
+ <p>
+ <em>Note:</em> It might look confusing that the schemaNS is passed in all of the calls above.
+ This is because the XMP toolkit keeps the top level &quot;schema&quot; namespace separate from
+ the rest of the path expression.
+ <em>Note:</em> These methods are much simpler than in the C++-API, they don't check the given
+ path or array indices.
+<P>
+
+<P>
+<DL>
+<DT><B>Since:</B></DT>
+ <DD>25.01.2006</DD>
+</DL>
+<HR>
+
+<P>
+
+<!-- ========== METHOD SUMMARY =========== -->
+
+<A NAME="method_summary"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+<B>Method Summary</B></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPPathFactory.html#composeArrayItemPath(java.lang.String, int)">composeArrayItemPath</A></B>(java.lang.String&nbsp;arrayName,
+ int&nbsp;itemIndex)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Compose the path expression for an item in an array.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPPathFactory.html#composeFieldSelector(java.lang.String, java.lang.String, java.lang.String, java.lang.String)">composeFieldSelector</A></B>(java.lang.String&nbsp;arrayName,
+ java.lang.String&nbsp;fieldNS,
+ java.lang.String&nbsp;fieldName,
+ java.lang.String&nbsp;fieldValue)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Compose the path expression to select an alternate item by a field's value.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPPathFactory.html#composeLangSelector(java.lang.String, java.lang.String)">composeLangSelector</A></B>(java.lang.String&nbsp;arrayName,
+ java.lang.String&nbsp;langName)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Compose the path expression to select an alternate item by language.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPPathFactory.html#composeQualifierPath(java.lang.String, java.lang.String)">composeQualifierPath</A></B>(java.lang.String&nbsp;qualNS,
+ java.lang.String&nbsp;qualName)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Compose the path expression for a qualifier.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPPathFactory.html#composeStructFieldPath(java.lang.String, java.lang.String)">composeStructFieldPath</A></B>(java.lang.String&nbsp;fieldNS,
+ java.lang.String&nbsp;fieldName)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Compose the path expression for a field in a struct.</TD>
+</TR>
+</TABLE>
+&nbsp;<A NAME="methods_inherited_from_class_java.lang.Object"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#EEEEFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="left"><B>Methods inherited from class java.lang.Object</B></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE>equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait</CODE></TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<!-- ============ METHOD DETAIL ========== -->
+
+<A NAME="method_detail"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="1"><FONT SIZE="+2">
+<B>Method Detail</B></FONT></TH>
+</TR>
+</TABLE>
+
+<A NAME="composeArrayItemPath(java.lang.String, int)"><!-- --></A><H3>
+composeArrayItemPath</H3>
+<PRE>
+public static java.lang.String <B>composeArrayItemPath</B>(java.lang.String&nbsp;arrayName,
+ int&nbsp;itemIndex)</PRE>
+<DL>
+<DD>Compose the path expression for an item in an array.
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>arrayName</CODE> - The name of the array. May be a general path expression, must not be
+ <code>null</code> or the empty string.<DD><CODE>itemIndex</CODE> - The index of the desired item. Arrays in XMP are indexed from 1.
+ 0 and below means last array item and renders as <code>[last()]</code>.
+<DT><B>Returns:</B><DD>Returns the composed path basing on fullPath. This will be of the form
+ <tt>ns:arrayName[i]</tt>, where &quot;ns&quot; is the prefix for schemaNS and
+ &quot;i&quot; is the decimal representation of itemIndex.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="composeStructFieldPath(java.lang.String, java.lang.String)"><!-- --></A><H3>
+composeStructFieldPath</H3>
+<PRE>
+public static java.lang.String <B>composeStructFieldPath</B>(java.lang.String&nbsp;fieldNS,
+ java.lang.String&nbsp;fieldName)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Compose the path expression for a field in a struct. The result can be added to the
+ path of
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>fieldNS</CODE> - The namespace URI for the field. Must not be <code>null</code> or the empty
+ string.<DD><CODE>fieldName</CODE> - The name of the field. Must be a simple XML name, must not be
+ <code>null</code> or the empty string.
+<DT><B>Returns:</B><DD>Returns the composed path. This will be of the form
+ <tt>ns:structName/fNS:fieldName</tt>, where &quot;ns&quot; is the prefix for
+ schemaNS and &quot;fNS&quot; is the prefix for fieldNS.
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Thrown if the path to create is not valid.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="composeQualifierPath(java.lang.String, java.lang.String)"><!-- --></A><H3>
+composeQualifierPath</H3>
+<PRE>
+public static java.lang.String <B>composeQualifierPath</B>(java.lang.String&nbsp;qualNS,
+ java.lang.String&nbsp;qualName)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Compose the path expression for a qualifier.
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>qualNS</CODE> - The namespace URI for the qualifier. May be <code>null</code> or the empty
+ string if the qualifier is in the XML empty namespace.<DD><CODE>qualName</CODE> - The name of the qualifier. Must be a simple XML name, must not be
+ <code>null</code> or the empty string.
+<DT><B>Returns:</B><DD>Returns the composed path. This will be of the form
+ <tt>ns:propName/?qNS:qualName</tt>, where &quot;ns&quot; is the prefix for
+ schemaNS and &quot;qNS&quot; is the prefix for qualNS.
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Thrown if the path to create is not valid.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="composeLangSelector(java.lang.String, java.lang.String)"><!-- --></A><H3>
+composeLangSelector</H3>
+<PRE>
+public static java.lang.String <B>composeLangSelector</B>(java.lang.String&nbsp;arrayName,
+ java.lang.String&nbsp;langName)</PRE>
+<DL>
+<DD>Compose the path expression to select an alternate item by language. The
+ path syntax allows two forms of &quot;content addressing&quot; that may
+ be used to select an item in an array of alternatives. The form used in
+ ComposeLangSelector lets you select an item in an alt-text array based on
+ the value of its <tt>xml:lang</tt> qualifier. The other form of content
+ addressing is shown in ComposeFieldSelector. \note ComposeLangSelector
+ does not supplant SetLocalizedText or GetLocalizedText. They should
+ generally be used, as they provide extra logic to choose the appropriate
+ language and maintain consistency with the 'x-default' value.
+ ComposeLangSelector gives you an path expression that is explicitly and
+ only for the language given in the langName parameter.
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>arrayName</CODE> - The name of the array. May be a general path expression, must
+ not be <code>null</code> or the empty string.<DD><CODE>langName</CODE> - The RFC 3066 code for the desired language.
+<DT><B>Returns:</B><DD>Returns the composed path. This will be of the form
+ <tt>ns:arrayName[@xml:lang='langName']</tt>, where
+ &quot;ns&quot; is the prefix for schemaNS.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="composeFieldSelector(java.lang.String, java.lang.String, java.lang.String, java.lang.String)"><!-- --></A><H3>
+composeFieldSelector</H3>
+<PRE>
+public static java.lang.String <B>composeFieldSelector</B>(java.lang.String&nbsp;arrayName,
+ java.lang.String&nbsp;fieldNS,
+ java.lang.String&nbsp;fieldName,
+ java.lang.String&nbsp;fieldValue)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Compose the path expression to select an alternate item by a field's value. The path syntax
+ allows two forms of &quot;content addressing&quot; that may be used to select an item in an
+ array of alternatives. The form used in ComposeFieldSelector lets you select an item in an
+ array of structs based on the value of one of the fields in the structs. The other form of
+ content addressing is shown in ComposeLangSelector. For example, consider a simple struct
+ that has two fields, the name of a city and the URI of an FTP site in that city. Use this to
+ create an array of download alternatives. You can show the user a popup built from the values
+ of the city fields. You can then get the corresponding URI as follows:
+ <p>
+ <blockquote>
+
+ <pre>
+ String path = composeFieldSelector ( schemaNS, &quot;Downloads&quot;, fieldNS,
+ &quot;City&quot;, chosenCity );
+ XMPProperty prop = xmpObj.getStructField ( schemaNS, path, fieldNS, &quot;URI&quot; );
+ </pre>
+
+ </blockquote>
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>arrayName</CODE> - The name of the array. May be a general path expression, must not be
+ <code>null</code> or the empty string.<DD><CODE>fieldNS</CODE> - The namespace URI for the field used as the selector. Must not be
+ <code>null</code> or the empty string.<DD><CODE>fieldName</CODE> - The name of the field used as the selector. Must be a simple XML name, must
+ not be <code>null</code> or the empty string. It must be the name of a field that is
+ itself simple.<DD><CODE>fieldValue</CODE> - The desired value of the field.
+<DT><B>Returns:</B><DD>Returns the composed path. This will be of the form
+ <tt>ns:arrayName[fNS:fieldName='fieldValue']</tt>, where &quot;ns&quot; is the
+ prefix for schemaNS and &quot;fNS&quot; is the prefix for fieldNS.
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Thrown if the path to create is not valid.</DL>
+</DD>
+</DL>
+<!-- ========= END OF CLASS DATA ========= -->
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="class-use/XMPPathFactory.html"><FONT CLASS="NavBarFont1"><B>Use</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="../../../com/adobe/xmp/XMPMetaFactory.html" title="class in com.adobe.xmp"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;<A HREF="../../../com/adobe/xmp/XMPSchemaRegistry.html" title="interface in com.adobe.xmp"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../index.html?com/adobe/xmp/XMPPathFactory.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPPathFactory.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+ SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;FIELD&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;FIELD&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/com/adobe/xmp/XMPSchemaRegistry.html b/java/XMPCore/docs/com/adobe/xmp/XMPSchemaRegistry.html
new file mode 100644
index 0000000..3b4d4b3
--- /dev/null
+++ b/java/XMPCore/docs/com/adobe/xmp/XMPSchemaRegistry.html
@@ -0,0 +1,547 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:50 CEST 2007 -->
+<TITLE>
+XMPSchemaRegistry
+</TITLE>
+
+<META NAME="keywords" CONTENT="com.adobe.xmp.XMPSchemaRegistry interface">
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="XMPSchemaRegistry";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="class-use/XMPSchemaRegistry.html"><FONT CLASS="NavBarFont1"><B>Use</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="../../../com/adobe/xmp/XMPPathFactory.html" title="class in com.adobe.xmp"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;<A HREF="../../../com/adobe/xmp/XMPUtils.html" title="class in com.adobe.xmp"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../index.html?com/adobe/xmp/XMPSchemaRegistry.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPSchemaRegistry.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+ SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;FIELD&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;FIELD&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<!-- ======== START OF CLASS DATA ======== -->
+<H2>
+<FONT SIZE="-1">
+com.adobe.xmp</FONT>
+<BR>
+Interface XMPSchemaRegistry</H2>
+<HR>
+<DL>
+<DT><PRE>public interface <B>XMPSchemaRegistry</B></DL>
+</PRE>
+
+<P>
+The schema registry keeps track of all namespaces and aliases used in the XMP
+ metadata. At initialisation time, the default namespaces and default aliases
+ are automatically registered. <b>Namespaces</b> must be registered before
+ used in namespace URI parameters or path expressions. Within the XMP Toolkit
+ the registered namespace URIs and prefixes must be unique. Additional
+ namespaces encountered when parsing RDF are automatically registered. The
+ namespace URI should always end in an XML name separator such as '/' or '#'.
+ This is because some forms of RDF shorthand catenate a namespace URI with an
+ element name to form a new URI.
+ <p>
+ <b>Aliases</b> in XMP serve the same purpose as Windows file shortcuts,
+ Macintosh file aliases, or UNIX file symbolic links. The aliases are simply
+ multiple names for the same property. One distinction of XMP aliases is that
+ they are ordered, there is an alias name pointing to an actual name. The
+ primary significance of the actual name is that it is the preferred name for
+ output, generally the most widely recognized name.
+ <p>
+ The names that can be aliased in XMP are restricted. The alias must be a top
+ level property name, not a field within a structure or an element within an
+ array. The actual may be a top level property name, the first element within
+ a top level array, or the default element in an alt-text array. This does not
+ mean the alias can only be a simple property. It is OK to alias a top level
+ structure or array to an identical top level structure or array, or to the
+ first item of an array of structures.
+<P>
+
+<P>
+<DL>
+<DT><B>Since:</B></DT>
+ <DD>27.01.2006</DD>
+</DL>
+<HR>
+
+<P>
+
+<!-- ========== METHOD SUMMARY =========== -->
+
+<A NAME="method_summary"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+<B>Method Summary</B></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPSchemaRegistry.html#deleteAlias(java.lang.String, java.lang.String)">deleteAlias</A></B>(java.lang.String&nbsp;aliasNS,
+ java.lang.String&nbsp;aliasProp)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Delete an alias.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPSchemaRegistry.html#deleteNamespace(java.lang.String)">deleteNamespace</A></B>(java.lang.String&nbsp;namespaceURI)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Deletes a namespace from the registry.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../com/adobe/xmp/properties/XMPAliasInfo.html" title="interface in com.adobe.xmp.properties">XMPAliasInfo</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPSchemaRegistry.html#findAlias(java.lang.String)">findAlias</A></B>(java.lang.String&nbsp;qname)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Searches for registered aliases.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../com/adobe/xmp/properties/XMPAliasInfo.html" title="interface in com.adobe.xmp.properties">XMPAliasInfo</A>[]</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPSchemaRegistry.html#findAliases(java.lang.String)">findAliases</A></B>(java.lang.String&nbsp;aliasNS)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Collects all aliases that are contained in the provided namespace.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.util.Map</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPSchemaRegistry.html#getAliases()">getAliases</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPSchemaRegistry.html#getNamespacePrefix(java.lang.String)">getNamespacePrefix</A></B>(java.lang.String&nbsp;namespaceURI)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Obtain the prefix for a registered namespace URI.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.util.Map</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPSchemaRegistry.html#getNamespaces()">getNamespaces</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPSchemaRegistry.html#getNamespaceURI(java.lang.String)">getNamespaceURI</A></B>(java.lang.String&nbsp;namespacePrefix)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Obtain the URI for a registered namespace prefix.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.util.Map</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPSchemaRegistry.html#getPrefixes()">getPrefixes</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPSchemaRegistry.html#registerAlias(java.lang.String, java.lang.String, java.lang.String, java.lang.String, com.adobe.xmp.options.AliasOptions)">registerAlias</A></B>(java.lang.String&nbsp;aliasNS,
+ java.lang.String&nbsp;aliasProp,
+ java.lang.String&nbsp;actualNS,
+ java.lang.String&nbsp;actualProp,
+ <A HREF="../../../com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options">AliasOptions</A>&nbsp;aliasForm)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Associates an alias name with an actual name.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPSchemaRegistry.html#registerNamespace(java.lang.String, java.lang.String)">registerNamespace</A></B>(java.lang.String&nbsp;namespaceURI,
+ java.lang.String&nbsp;suggestedPrefix)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Register a namespace URI with a suggested prefix.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../com/adobe/xmp/properties/XMPAliasInfo.html" title="interface in com.adobe.xmp.properties">XMPAliasInfo</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPSchemaRegistry.html#resolveAlias(java.lang.String, java.lang.String)">resolveAlias</A></B>(java.lang.String&nbsp;aliasNS,
+ java.lang.String&nbsp;aliasProp)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Determines if a name is an alias, and what it is aliased to.</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<!-- ============ METHOD DETAIL ========== -->
+
+<A NAME="method_detail"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="1"><FONT SIZE="+2">
+<B>Method Detail</B></FONT></TH>
+</TR>
+</TABLE>
+
+<A NAME="registerNamespace(java.lang.String, java.lang.String)"><!-- --></A><H3>
+registerNamespace</H3>
+<PRE>
+java.lang.String <B>registerNamespace</B>(java.lang.String&nbsp;namespaceURI,
+ java.lang.String&nbsp;suggestedPrefix)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Register a namespace URI with a suggested prefix. It is not an error if
+ the URI is already registered, no matter what the prefix is. If the URI
+ is not registered but the suggested prefix is in use, a unique prefix is
+ created from the suggested one. The actual registeed prefix is always
+ returned. The function result tells if the registered prefix is the
+ suggested one.
+ <p>
+ Note: No checking is presently done on either the URI or the prefix.
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>namespaceURI</CODE> - The URI for the namespace. Must be a valid XML URI.<DD><CODE>suggestedPrefix</CODE> - The suggested prefix to be used if the URI is not yet
+ registered. Must be a valid XML name.
+<DT><B>Returns:</B><DD>Returns the registered prefix for this URI, is equal to the
+ suggestedPrefix if the namespace hasn't been registered before,
+ otherwise the existing prefix.
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - If the parameters are not accordingly set</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getNamespacePrefix(java.lang.String)"><!-- --></A><H3>
+getNamespacePrefix</H3>
+<PRE>
+java.lang.String <B>getNamespacePrefix</B>(java.lang.String&nbsp;namespaceURI)</PRE>
+<DL>
+<DD>Obtain the prefix for a registered namespace URI.
+ <p>
+ It is not an error if the namespace URI is not registered. The output
+ namespacePrefix string is not modified if the namespace URI is not
+ registered.
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>namespaceURI</CODE> - The URI for the namespace. Must not be null or the empty
+ string.
+<DT><B>Returns:</B><DD>Returns true if the namespace URI is registered.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getNamespaceURI(java.lang.String)"><!-- --></A><H3>
+getNamespaceURI</H3>
+<PRE>
+java.lang.String <B>getNamespaceURI</B>(java.lang.String&nbsp;namespacePrefix)</PRE>
+<DL>
+<DD>Obtain the URI for a registered namespace prefix.
+ <p>
+ It is not an error if the namespace prefix is not registered. The output
+ namespaceURI string is not modified if the namespace prefix is not
+ registered.
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>namespacePrefix</CODE> - The prefix for the namespace. Must not be null or the empty
+ string.
+<DT><B>Returns:</B><DD>Returns the URI registered for this prefix.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getNamespaces()"><!-- --></A><H3>
+getNamespaces</H3>
+<PRE>
+java.util.Map <B>getNamespaces</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns the registered prefix/namespace-pairs as map, where the keys are the
+ namespaces and the values are the prefixes.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getPrefixes()"><!-- --></A><H3>
+getPrefixes</H3>
+<PRE>
+java.util.Map <B>getPrefixes</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns the registered namespace/prefix-pairs as map, where the keys are the
+ prefixes and the values are the namespaces.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="deleteNamespace(java.lang.String)"><!-- --></A><H3>
+deleteNamespace</H3>
+<PRE>
+void <B>deleteNamespace</B>(java.lang.String&nbsp;namespaceURI)</PRE>
+<DL>
+<DD>Deletes a namespace from the registry.
+ <p>
+ Does nothing if the URI is not registered, or if the namespaceURI
+ parameter is null or the empty string.
+ <p>
+ Note: Not yet implemented.
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>namespaceURI</CODE> - The URI for the namespace.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="registerAlias(java.lang.String, java.lang.String, java.lang.String, java.lang.String, com.adobe.xmp.options.AliasOptions)"><!-- --></A><H3>
+registerAlias</H3>
+<PRE>
+void <B>registerAlias</B>(java.lang.String&nbsp;aliasNS,
+ java.lang.String&nbsp;aliasProp,
+ java.lang.String&nbsp;actualNS,
+ java.lang.String&nbsp;actualProp,
+ <A HREF="../../../com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options">AliasOptions</A>&nbsp;aliasForm)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Associates an alias name with an actual name.
+ <p>
+ Define a alias mapping from one namespace/property to another. Both
+ property names must be simple names. An alias can be a direct mapping,
+ where the alias and actual have the same data type. It is also possible
+ to map a simple alias to an item in an array. This can either be to the
+ first item in the array, or to the 'x-default' item in an alt-text array.
+ Multiple alias names may map to the same actual, as long as the forms
+ match. It is a no-op to reregister an alias in an identical fashion.
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>aliasNS</CODE> - The namespace URI for the alias. Must not be null or the empty
+ string.<DD><CODE>aliasProp</CODE> - The name of the alias. Must be a simple name, not null or the
+ empty string and not a general path expression.<DD><CODE>actualNS</CODE> - The namespace URI for the actual. Must not be null or the
+ empty string.<DD><CODE>actualProp</CODE> - The name of the actual. Must be a simple name, not null or the
+ empty string and not a general path expression.<DD><CODE>aliasForm</CODE> - Provides options for aliases for simple aliases to array
+ items. This is needed to know what kind of array to create if
+ set for the first time via the simple alias. Pass
+ <code>XMP_NoOptions</code>, the default value, for all
+ direct aliases regardless of whether the actual data type is
+ an array or not (see <A HREF="../../../com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options"><CODE>AliasOptions</CODE></A>).
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - for inconsistant aliases.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="resolveAlias(java.lang.String, java.lang.String)"><!-- --></A><H3>
+resolveAlias</H3>
+<PRE>
+<A HREF="../../../com/adobe/xmp/properties/XMPAliasInfo.html" title="interface in com.adobe.xmp.properties">XMPAliasInfo</A> <B>resolveAlias</B>(java.lang.String&nbsp;aliasNS,
+ java.lang.String&nbsp;aliasProp)</PRE>
+<DL>
+<DD>Determines if a name is an alias, and what it is aliased to.
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>aliasNS</CODE> - The namespace URI of the alias. Must not be <code>null</code> or the empty
+ string.<DD><CODE>aliasProp</CODE> - The name of the alias. May be an arbitrary path expression
+ path, must not be <code>null</code> or the empty string.
+<DT><B>Returns:</B><DD>Returns the <code>XMPAliasInfo</code> for the given alias namespace and property or
+ <code>null</code> if there is no such alias.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="findAliases(java.lang.String)"><!-- --></A><H3>
+findAliases</H3>
+<PRE>
+<A HREF="../../../com/adobe/xmp/properties/XMPAliasInfo.html" title="interface in com.adobe.xmp.properties">XMPAliasInfo</A>[] <B>findAliases</B>(java.lang.String&nbsp;aliasNS)</PRE>
+<DL>
+<DD>Collects all aliases that are contained in the provided namespace.
+ If nothing is found, an empty array is returned.
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>aliasNS</CODE> - a schema namespace URI
+<DT><B>Returns:</B><DD>Returns all alias infos from aliases that are contained in the provided namespace.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="findAlias(java.lang.String)"><!-- --></A><H3>
+findAlias</H3>
+<PRE>
+<A HREF="../../../com/adobe/xmp/properties/XMPAliasInfo.html" title="interface in com.adobe.xmp.properties">XMPAliasInfo</A> <B>findAlias</B>(java.lang.String&nbsp;qname)</PRE>
+<DL>
+<DD>Searches for registered aliases.
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>qname</CODE> - an XML conform qname
+<DT><B>Returns:</B><DD>Returns if an alias definition for the given qname to another
+ schema and property is registered.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="deleteAlias(java.lang.String, java.lang.String)"><!-- --></A><H3>
+deleteAlias</H3>
+<PRE>
+void <B>deleteAlias</B>(java.lang.String&nbsp;aliasNS,
+ java.lang.String&nbsp;aliasProp)</PRE>
+<DL>
+<DD>Delete an alias.
+ <p>
+ This only deletes the registration of the alias, it does not delete the
+ actual property. It does delete any view of the property through the
+ alias name. It is OK to attempt to delete an alias that does not exist,
+ that is if the alias name is not registered as an alias.
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>aliasNS</CODE> - The namespace URI for the alias. Must not be null or the empty
+ string.<DD><CODE>aliasProp</CODE> - The name of the alias. Must be a simple name, not null or the
+ empty string and not a general path expression.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getAliases()"><!-- --></A><H3>
+getAliases</H3>
+<PRE>
+java.util.Map <B>getAliases</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns the registered aliases as map, where the key is the "qname" (prefix and name)
+ and the value an <code>XMPAliasInfo</code>-object.</DL>
+</DD>
+</DL>
+<!-- ========= END OF CLASS DATA ========= -->
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="class-use/XMPSchemaRegistry.html"><FONT CLASS="NavBarFont1"><B>Use</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="../../../com/adobe/xmp/XMPPathFactory.html" title="class in com.adobe.xmp"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;<A HREF="../../../com/adobe/xmp/XMPUtils.html" title="class in com.adobe.xmp"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../index.html?com/adobe/xmp/XMPSchemaRegistry.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPSchemaRegistry.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+ SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;FIELD&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;FIELD&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/com/adobe/xmp/XMPUtils.html b/java/XMPCore/docs/com/adobe/xmp/XMPUtils.html
new file mode 100644
index 0000000..2a4ed42
--- /dev/null
+++ b/java/XMPCore/docs/com/adobe/xmp/XMPUtils.html
@@ -0,0 +1,770 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:50 CEST 2007 -->
+<TITLE>
+XMPUtils
+</TITLE>
+
+<META NAME="keywords" CONTENT="com.adobe.xmp.XMPUtils class">
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="XMPUtils";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="class-use/XMPUtils.html"><FONT CLASS="NavBarFont1"><B>Use</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="../../../com/adobe/xmp/XMPSchemaRegistry.html" title="interface in com.adobe.xmp"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;<A HREF="../../../com/adobe/xmp/XMPVersionInfo.html" title="interface in com.adobe.xmp"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../index.html?com/adobe/xmp/XMPUtils.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPUtils.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+ SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;FIELD&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;FIELD&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<!-- ======== START OF CLASS DATA ======== -->
+<H2>
+<FONT SIZE="-1">
+com.adobe.xmp</FONT>
+<BR>
+Class XMPUtils</H2>
+<PRE>
+java.lang.Object
+ <IMG SRC="../../../resources/inherit.gif" ALT="extended by "><B>com.adobe.xmp.XMPUtils</B>
+</PRE>
+<HR>
+<DL>
+<DT><PRE>public class <B>XMPUtils</B><DT>extends java.lang.Object</DL>
+</PRE>
+
+<P>
+Utility methods for XMP. I included only those that are different from the
+ Java default conversion utilities.
+<P>
+
+<P>
+<DL>
+<DT><B>Since:</B></DT>
+ <DD>21.02.2006</DD>
+</DL>
+<HR>
+
+<P>
+
+<!-- ========== METHOD SUMMARY =========== -->
+
+<A NAME="method_summary"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+<B>Method Summary</B></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPUtils.html#appendProperties(com.adobe.xmp.XMPMeta, com.adobe.xmp.XMPMeta, boolean, boolean)">appendProperties</A></B>(<A HREF="../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>&nbsp;source,
+ <A HREF="../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>&nbsp;dest,
+ boolean&nbsp;doAllProperties,
+ boolean&nbsp;replaceOldValues)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Alias without the new option <code>deleteEmptyValues</code>.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPUtils.html#appendProperties(com.adobe.xmp.XMPMeta, com.adobe.xmp.XMPMeta, boolean, boolean, boolean)">appendProperties</A></B>(<A HREF="../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>&nbsp;source,
+ <A HREF="../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>&nbsp;dest,
+ boolean&nbsp;doAllProperties,
+ boolean&nbsp;replaceOldValues,
+ boolean&nbsp;deleteEmptyValues)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Append properties from one XMP object to another.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPUtils.html#catenateArrayItems(com.adobe.xmp.XMPMeta, java.lang.String, java.lang.String, java.lang.String, java.lang.String, boolean)">catenateArrayItems</A></B>(<A HREF="../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>&nbsp;xmp,
+ java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;arrayName,
+ java.lang.String&nbsp;separator,
+ java.lang.String&nbsp;quotes,
+ boolean&nbsp;allowCommas)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Create a single edit string from an array of strings.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPUtils.html#convertFromBoolean(boolean)">convertFromBoolean</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convert from boolean to string.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPUtils.html#convertFromDate(com.adobe.xmp.XMPDateTime)">convertFromDate</A></B>(<A HREF="../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A>&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convert from <code>XMPDateTime</code> to string.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPUtils.html#convertFromDouble(double)">convertFromDouble</A></B>(double&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convert from long to string.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPUtils.html#convertFromInteger(int)">convertFromInteger</A></B>(int&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convert from int to string.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPUtils.html#convertFromLong(long)">convertFromLong</A></B>(long&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convert from long to string.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPUtils.html#convertToBoolean(java.lang.String)">convertToBoolean</A></B>(java.lang.String&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convert from string to Boolean.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;<A HREF="../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPUtils.html#convertToDate(java.lang.String)">convertToDate</A></B>(java.lang.String&nbsp;rawValue)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Converts a string value to an <code>XMPDateTime</code>.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;double</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPUtils.html#convertToDouble(java.lang.String)">convertToDouble</A></B>(java.lang.String&nbsp;rawValue)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Converts a string value to a <code>double</code>.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPUtils.html#convertToInteger(java.lang.String)">convertToInteger</A></B>(java.lang.String&nbsp;rawValue)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Converts a string value to an <code>int</code>.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;long</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPUtils.html#convertToLong(java.lang.String)">convertToLong</A></B>(java.lang.String&nbsp;rawValue)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Converts a string value to a <code>long</code>.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;byte[]</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPUtils.html#decodeBase64(java.lang.String)">decodeBase64</A></B>(java.lang.String&nbsp;base64String)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Decode from Base64 encoded string to raw data.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPUtils.html#encodeBase64(byte[])">encodeBase64</A></B>(byte[]&nbsp;buffer)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convert from a byte array to a base64 encoded string.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPUtils.html#removeProperties(com.adobe.xmp.XMPMeta, java.lang.String, java.lang.String, boolean, boolean)">removeProperties</A></B>(<A HREF="../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>&nbsp;xmp,
+ java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ boolean&nbsp;doAllProperties,
+ boolean&nbsp;includeAliases)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Remove multiple properties from an XMP object.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPUtils.html#separateArrayItems(com.adobe.xmp.XMPMeta, java.lang.String, java.lang.String, java.lang.String, com.adobe.xmp.options.PropertyOptions, boolean)">separateArrayItems</A></B>(<A HREF="../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>&nbsp;xmp,
+ java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;arrayName,
+ java.lang.String&nbsp;catedStr,
+ <A HREF="../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;arrayOptions,
+ boolean&nbsp;preserveCommas)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Separate a single edit string into an array of strings.</TD>
+</TR>
+</TABLE>
+&nbsp;<A NAME="methods_inherited_from_class_java.lang.Object"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#EEEEFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="left"><B>Methods inherited from class java.lang.Object</B></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE>equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait</CODE></TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<!-- ============ METHOD DETAIL ========== -->
+
+<A NAME="method_detail"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="1"><FONT SIZE="+2">
+<B>Method Detail</B></FONT></TH>
+</TR>
+</TABLE>
+
+<A NAME="catenateArrayItems(com.adobe.xmp.XMPMeta, java.lang.String, java.lang.String, java.lang.String, java.lang.String, boolean)"><!-- --></A><H3>
+catenateArrayItems</H3>
+<PRE>
+public static java.lang.String <B>catenateArrayItems</B>(<A HREF="../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>&nbsp;xmp,
+ java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;arrayName,
+ java.lang.String&nbsp;separator,
+ java.lang.String&nbsp;quotes,
+ boolean&nbsp;allowCommas)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Create a single edit string from an array of strings.
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>xmp</CODE> - The XMP object containing the array to be catenated.<DD><CODE>schemaNS</CODE> - The schema namespace URI for the array. Must not be null or
+ the empty string.<DD><CODE>arrayName</CODE> - The name of the array. May be a general path expression, must
+ not be null or the empty string. Each item in the array must
+ be a simple string value.<DD><CODE>separator</CODE> - The string to be used to separate the items in the catenated
+ string. Defaults to &quot;; &quot;, ASCII semicolon and space
+ (U+003B, U+0020).<DD><CODE>quotes</CODE> - The characters to be used as quotes around array items that
+ contain a separator. Defaults to &apos;&quot;&apos;<DD><CODE>allowCommas</CODE> - Option flag to control the catenation.
+<DT><B>Returns:</B><DD>Returns the string containing the catenated array items.
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Forwards the Exceptions from the metadata processing</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="separateArrayItems(com.adobe.xmp.XMPMeta, java.lang.String, java.lang.String, java.lang.String, com.adobe.xmp.options.PropertyOptions, boolean)"><!-- --></A><H3>
+separateArrayItems</H3>
+<PRE>
+public static void <B>separateArrayItems</B>(<A HREF="../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>&nbsp;xmp,
+ java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;arrayName,
+ java.lang.String&nbsp;catedStr,
+ <A HREF="../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;arrayOptions,
+ boolean&nbsp;preserveCommas)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Separate a single edit string into an array of strings.
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>xmp</CODE> - The XMP object containing the array to be updated.<DD><CODE>schemaNS</CODE> - The schema namespace URI for the array. Must not be null or
+ the empty string.<DD><CODE>arrayName</CODE> - The name of the array. May be a general path expression, must
+ not be null or the empty string. Each item in the array must
+ be a simple string value.<DD><CODE>catedStr</CODE> - The string to be separated into the array items.<DD><CODE>arrayOptions</CODE> - Option flags to control the separation.<DD><CODE>preserveCommas</CODE> - Flag if commas shall be preserved
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Forwards the Exceptions from the metadata processing</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="removeProperties(com.adobe.xmp.XMPMeta, java.lang.String, java.lang.String, boolean, boolean)"><!-- --></A><H3>
+removeProperties</H3>
+<PRE>
+public static void <B>removeProperties</B>(<A HREF="../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>&nbsp;xmp,
+ java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ boolean&nbsp;doAllProperties,
+ boolean&nbsp;includeAliases)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Remove multiple properties from an XMP object.
+
+ RemoveProperties was created to support the File Info dialog's Delete
+ button, and has been been generalized somewhat from those specific needs.
+ It operates in one of three main modes depending on the schemaNS and
+ propName parameters:
+
+ <ul>
+ <li> Non-empty <code>schemaNS</code> and <code>propName</code> - The named property is
+ removed if it is an external property, or if the
+ flag <code>doAllProperties</code> option is true. It does not matter whether the
+ named property is an actual property or an alias.
+
+ <li> Non-empty <code>schemaNS</code> and empty <code>propName</code> - The all external
+ properties in the named schema are removed. Internal properties are also
+ removed if the flag <code>doAllProperties</code> option is set. In addition,
+ aliases from the named schema will be removed if the flag <code>includeAliases</code>
+ option is set.
+
+ <li> Empty <code>schemaNS</code> and empty <code>propName</code> - All external properties in
+ all schema are removed. Internal properties are also removed if the
+ flag <code>doAllProperties</code> option is passed. Aliases are implicitly handled
+ because the associated actuals are internal if the alias is.
+ </ul>
+
+ It is an error to pass an empty <code>schemaNS</code> and non-empty <code>propName</code>.
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>xmp</CODE> - The XMP object containing the properties to be removed.<DD><CODE>schemaNS</CODE> - Optional schema namespace URI for the properties to be
+ removed.<DD><CODE>propName</CODE> - Optional path expression for the property to be removed.<DD><CODE>doAllProperties</CODE> - Option flag to control the deletion: do internal properties in
+ addition to external properties.<DD><CODE>includeAliases</CODE> - Option flag to control the deletion:
+ Include aliases in the "named schema" case above.
+ <em>Note:</em> Currently not supported.
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Forwards the Exceptions from the metadata processing</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="appendProperties(com.adobe.xmp.XMPMeta, com.adobe.xmp.XMPMeta, boolean, boolean)"><!-- --></A><H3>
+appendProperties</H3>
+<PRE>
+public static void <B>appendProperties</B>(<A HREF="../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>&nbsp;source,
+ <A HREF="../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>&nbsp;dest,
+ boolean&nbsp;doAllProperties,
+ boolean&nbsp;replaceOldValues)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Alias without the new option <code>deleteEmptyValues</code>.
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>source</CODE> - The source XMP object.<DD><CODE>dest</CODE> - The destination XMP object.<DD><CODE>doAllProperties</CODE> - Do internal properties in addition to external properties.<DD><CODE>replaceOldValues</CODE> - Replace the values of existing properties.
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Forwards the Exceptions from the metadata processing</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="appendProperties(com.adobe.xmp.XMPMeta, com.adobe.xmp.XMPMeta, boolean, boolean, boolean)"><!-- --></A><H3>
+appendProperties</H3>
+<PRE>
+public static void <B>appendProperties</B>(<A HREF="../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>&nbsp;source,
+ <A HREF="../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>&nbsp;dest,
+ boolean&nbsp;doAllProperties,
+ boolean&nbsp;replaceOldValues,
+ boolean&nbsp;deleteEmptyValues)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD><p>Append properties from one XMP object to another.
+
+ <p>XMPUtils#appendProperties was created to support the File Info dialog's Append button, and
+ has been been generalized somewhat from those specific needs. It appends information from one
+ XMP object (source) to another (dest). The default operation is to append only external
+ properties that do not already exist in the destination. The flag
+ <code>doAllProperties</code> can be used to operate on all properties, external and internal.
+ The flag <code>replaceOldValues</code> option can be used to replace the values
+ of existing properties. The notion of external
+ versus internal applies only to top level properties. The keep-or-replace-old notion applies
+ within structs and arrays as described below.
+ <ul>
+ <li>If <code>replaceOldValues</code> is true then the processing is restricted to the top
+ level properties. The processed properties from the source (according to
+ <code>doAllProperties</code>) are propagated to the destination,
+ replacing any existing values.Properties in the destination that are not in the source
+ are left alone.
+
+ <li>If <code>replaceOldValues</code> is not passed then the processing is more complicated.
+ Top level properties are added to the destination if they do not already exist.
+ If they do exist but differ in form (simple/struct/array) then the destination is left alone.
+ If the forms match, simple properties are left unchanged while structs and arrays are merged.
+
+ <li>If <code>deleteEmptyValues</code> is passed then an empty value in the source XMP causes
+ the corresponding destination XMP property to be deleted. The default is to treat empty
+ values the same as non-empty values. An empty value is any of a simple empty string, an array
+ with no items, or a struct with no fields. Qualifiers are ignored.
+ </ul>
+
+ <p>The detailed behavior is defined by the following pseudo-code:
+ <blockquote>
+ <pre>
+ appendProperties ( sourceXMP, destXMP, doAllProperties,
+ replaceOldValues, deleteEmptyValues ):
+ for all source schema (top level namespaces):
+ for all top level properties in sourceSchema:
+ if doAllProperties or prop is external:
+ appendSubtree ( sourceNode, destSchema, replaceOldValues, deleteEmptyValues )
+
+ appendSubtree ( sourceNode, destParent, replaceOldValues, deleteEmptyValues ):
+ if deleteEmptyValues and source value is empty:
+ delete the corresponding child from destParent
+ else if sourceNode not in destParent (by name):
+ copy sourceNode's subtree to destParent
+ else if replaceOld:
+ delete subtree from destParent
+ copy sourceNode's subtree to destParent
+ else:
+ // Already exists in dest and not replacing, merge structs and arrays
+ if sourceNode and destNode forms differ:
+ return, leave the destNode alone
+ else if form is a struct:
+ for each field in sourceNode:
+ AppendSubtree ( sourceNode.field, destNode, replaceOldValues )
+ else if form is an alt-text array:
+ copy new items by "xml:lang" value into the destination
+ else if form is an array:
+ copy new items by value into the destination, ignoring order and duplicates
+ </pre>
+ </blockquote>
+
+ <p><em>Note:</em> appendProperties can be expensive if replaceOldValues is not passed and
+ the XMP contains large arrays. The array item checking described above is n-squared.
+ Each source item is checked to see if it already exists in the destination,
+ without regard to order or duplicates.
+ <p>Simple items are compared by value and "xml:lang" qualifier, other qualifiers are ignored.
+ Structs are recursively compared by field names, without regard to field order. Arrays are
+ compared by recursively comparing all items.
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>source</CODE> - The source XMP object.<DD><CODE>dest</CODE> - The destination XMP object.<DD><CODE>doAllProperties</CODE> - Do internal properties in addition to external properties.<DD><CODE>replaceOldValues</CODE> - Replace the values of existing properties.<DD><CODE>deleteEmptyValues</CODE> - Delete destination values if source property is empty.
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Forwards the Exceptions from the metadata processing</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="convertToBoolean(java.lang.String)"><!-- --></A><H3>
+convertToBoolean</H3>
+<PRE>
+public static boolean <B>convertToBoolean</B>(java.lang.String&nbsp;value)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Convert from string to Boolean.
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>value</CODE> - The string representation of the Boolean.
+<DT><B>Returns:</B><DD>The appropriate boolean value for the string. The checked values
+ for <code>true</code> and <code>false</code> are:
+ <ul>
+ <li><A HREF="../../../com/adobe/xmp/XMPConst.html#TRUESTR"><CODE>XMPConst.TRUESTR</CODE></A> and <A HREF="../../../com/adobe/xmp/XMPConst.html#FALSESTR"><CODE>XMPConst.FALSESTR</CODE></A>
+ <li>&quot;t&quot; and &quot;f&quot;
+ <li>&quot;on&quot; and &quot;off&quot;
+ <li>&quot;yes&quot; and &quot;no&quot;
+ <li>&quot;value <> 0&quot; and &quot;value == 0&quot;
+ </ul>
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - If an empty string is passed.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="convertFromBoolean(boolean)"><!-- --></A><H3>
+convertFromBoolean</H3>
+<PRE>
+public static java.lang.String <B>convertFromBoolean</B>(boolean&nbsp;value)</PRE>
+<DL>
+<DD>Convert from boolean to string.
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>value</CODE> - a boolean value
+<DT><B>Returns:</B><DD>The XMP string representation of the boolean. The values used are
+ given by the constnts <A HREF="../../../com/adobe/xmp/XMPConst.html#TRUESTR"><CODE>XMPConst.TRUESTR</CODE></A> and
+ <A HREF="../../../com/adobe/xmp/XMPConst.html#FALSESTR"><CODE>XMPConst.FALSESTR</CODE></A>.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="convertToInteger(java.lang.String)"><!-- --></A><H3>
+convertToInteger</H3>
+<PRE>
+public static int <B>convertToInteger</B>(java.lang.String&nbsp;rawValue)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Converts a string value to an <code>int</code>.
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>rawValue</CODE> - the string value
+<DT><B>Returns:</B><DD>Returns an int.
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - If the <code>rawValue</code> is <code>null</code> or empty or the
+ conversion fails.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="convertFromInteger(int)"><!-- --></A><H3>
+convertFromInteger</H3>
+<PRE>
+public static java.lang.String <B>convertFromInteger</B>(int&nbsp;value)</PRE>
+<DL>
+<DD>Convert from int to string.
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>value</CODE> - an int value
+<DT><B>Returns:</B><DD>The string representation of the int.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="convertToLong(java.lang.String)"><!-- --></A><H3>
+convertToLong</H3>
+<PRE>
+public static long <B>convertToLong</B>(java.lang.String&nbsp;rawValue)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Converts a string value to a <code>long</code>.
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>rawValue</CODE> - the string value
+<DT><B>Returns:</B><DD>Returns a long.
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - If the <code>rawValue</code> is <code>null</code> or empty or the
+ conversion fails.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="convertFromLong(long)"><!-- --></A><H3>
+convertFromLong</H3>
+<PRE>
+public static java.lang.String <B>convertFromLong</B>(long&nbsp;value)</PRE>
+<DL>
+<DD>Convert from long to string.
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>value</CODE> - a long value
+<DT><B>Returns:</B><DD>The string representation of the long.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="convertToDouble(java.lang.String)"><!-- --></A><H3>
+convertToDouble</H3>
+<PRE>
+public static double <B>convertToDouble</B>(java.lang.String&nbsp;rawValue)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Converts a string value to a <code>double</code>.
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>rawValue</CODE> - the string value
+<DT><B>Returns:</B><DD>Returns a double.
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - If the <code>rawValue</code> is <code>null</code> or empty or the
+ conversion fails.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="convertFromDouble(double)"><!-- --></A><H3>
+convertFromDouble</H3>
+<PRE>
+public static java.lang.String <B>convertFromDouble</B>(double&nbsp;value)</PRE>
+<DL>
+<DD>Convert from long to string.
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>value</CODE> - a long value
+<DT><B>Returns:</B><DD>The string representation of the long.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="convertToDate(java.lang.String)"><!-- --></A><H3>
+convertToDate</H3>
+<PRE>
+public static <A HREF="../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A> <B>convertToDate</B>(java.lang.String&nbsp;rawValue)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Converts a string value to an <code>XMPDateTime</code>.
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>rawValue</CODE> - the string value
+<DT><B>Returns:</B><DD>Returns an <code>XMPDateTime</code>-object.
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - If the <code>rawValue</code> is <code>null</code> or empty or the
+ conversion fails.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="convertFromDate(com.adobe.xmp.XMPDateTime)"><!-- --></A><H3>
+convertFromDate</H3>
+<PRE>
+public static java.lang.String <B>convertFromDate</B>(<A HREF="../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A>&nbsp;value)</PRE>
+<DL>
+<DD>Convert from <code>XMPDateTime</code> to string.
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>value</CODE> - an <code>XMPDateTime</code>
+<DT><B>Returns:</B><DD>The string representation of the long.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="encodeBase64(byte[])"><!-- --></A><H3>
+encodeBase64</H3>
+<PRE>
+public static java.lang.String <B>encodeBase64</B>(byte[]&nbsp;buffer)</PRE>
+<DL>
+<DD>Convert from a byte array to a base64 encoded string.
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>buffer</CODE> - the byte array to be converted
+<DT><B>Returns:</B><DD>Returns the base64 string.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="decodeBase64(java.lang.String)"><!-- --></A><H3>
+decodeBase64</H3>
+<PRE>
+public static byte[] <B>decodeBase64</B>(java.lang.String&nbsp;base64String)
+ throws <A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Decode from Base64 encoded string to raw data.
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>base64String</CODE> - a base64 encoded string
+<DT><B>Returns:</B><DD>Returns a byte array containg the decoded string.
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Thrown if the given string is not property base64 encoded</DL>
+</DD>
+</DL>
+<!-- ========= END OF CLASS DATA ========= -->
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="class-use/XMPUtils.html"><FONT CLASS="NavBarFont1"><B>Use</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="../../../com/adobe/xmp/XMPSchemaRegistry.html" title="interface in com.adobe.xmp"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;<A HREF="../../../com/adobe/xmp/XMPVersionInfo.html" title="interface in com.adobe.xmp"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../index.html?com/adobe/xmp/XMPUtils.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPUtils.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+ SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;FIELD&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;FIELD&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/com/adobe/xmp/XMPVersionInfo.html b/java/XMPCore/docs/com/adobe/xmp/XMPVersionInfo.html
new file mode 100644
index 0000000..06f3ae0
--- /dev/null
+++ b/java/XMPCore/docs/com/adobe/xmp/XMPVersionInfo.html
@@ -0,0 +1,316 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:50 CEST 2007 -->
+<TITLE>
+XMPVersionInfo
+</TITLE>
+
+<META NAME="keywords" CONTENT="com.adobe.xmp.XMPVersionInfo interface">
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="XMPVersionInfo";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="class-use/XMPVersionInfo.html"><FONT CLASS="NavBarFont1"><B>Use</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="../../../com/adobe/xmp/XMPUtils.html" title="class in com.adobe.xmp"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;NEXT CLASS</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../index.html?com/adobe/xmp/XMPVersionInfo.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPVersionInfo.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+ SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;FIELD&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;FIELD&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<!-- ======== START OF CLASS DATA ======== -->
+<H2>
+<FONT SIZE="-1">
+com.adobe.xmp</FONT>
+<BR>
+Interface XMPVersionInfo</H2>
+<HR>
+<DL>
+<DT><PRE>public interface <B>XMPVersionInfo</B></DL>
+</PRE>
+
+<P>
+XMP Toolkit Version Information
+ <p>
+ Version information for the XMP toolkit is stored in the jar-library and available through a
+ runtime call, <A HREF="../../../com/adobe/xmp/XMPMetaFactory.html#getVersionInfo()"><CODE>XMPMetaFactory.getVersionInfo()</CODE></A>, addition static version numbers are
+ defined in "version.properties".
+<P>
+
+<P>
+<DL>
+<DT><B>Since:</B></DT>
+ <DD>23.01.2006</DD>
+</DL>
+<HR>
+
+<P>
+
+<!-- ========== METHOD SUMMARY =========== -->
+
+<A NAME="method_summary"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+<B>Method Summary</B></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPVersionInfo.html#getBuild()">getBuild</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPVersionInfo.html#getMajor()">getMajor</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPVersionInfo.html#getMessage()">getMessage</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPVersionInfo.html#getMicro()">getMicro</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPVersionInfo.html#getMinor()">getMinor</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../com/adobe/xmp/XMPVersionInfo.html#isDebug()">isDebug</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<!-- ============ METHOD DETAIL ========== -->
+
+<A NAME="method_detail"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="1"><FONT SIZE="+2">
+<B>Method Detail</B></FONT></TH>
+</TR>
+</TABLE>
+
+<A NAME="getMajor()"><!-- --></A><H3>
+getMajor</H3>
+<PRE>
+int <B>getMajor</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns the primary release number, the "1" in version "1.2.3".</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getMinor()"><!-- --></A><H3>
+getMinor</H3>
+<PRE>
+int <B>getMinor</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns the secondary release number, the "2" in version "1.2.3".</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getMicro()"><!-- --></A><H3>
+getMicro</H3>
+<PRE>
+int <B>getMicro</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns the tertiary release number, the "3" in version "1.2.3".</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="isDebug()"><!-- --></A><H3>
+isDebug</H3>
+<PRE>
+boolean <B>isDebug</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns true if this is a debug build.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getBuild()"><!-- --></A><H3>
+getBuild</H3>
+<PRE>
+int <B>getBuild</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns a rolling build number, monotonically increasing in a release.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getMessage()"><!-- --></A><H3>
+getMessage</H3>
+<PRE>
+java.lang.String <B>getMessage</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns a comprehensive version information string.</DL>
+</DD>
+</DL>
+<!-- ========= END OF CLASS DATA ========= -->
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="class-use/XMPVersionInfo.html"><FONT CLASS="NavBarFont1"><B>Use</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="../../../com/adobe/xmp/XMPUtils.html" title="class in com.adobe.xmp"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;NEXT CLASS</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../index.html?com/adobe/xmp/XMPVersionInfo.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPVersionInfo.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+ SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;FIELD&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;FIELD&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/com/adobe/xmp/class-use/XMPConst.html b/java/XMPCore/docs/com/adobe/xmp/class-use/XMPConst.html
new file mode 100644
index 0000000..c51a66f
--- /dev/null
+++ b/java/XMPCore/docs/com/adobe/xmp/class-use/XMPConst.html
@@ -0,0 +1,140 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:51 CEST 2007 -->
+<TITLE>
+Uses of Interface com.adobe.xmp.XMPConst
+</TITLE>
+
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="Uses of Interface com.adobe.xmp.XMPConst";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp"><FONT CLASS="NavBarFont1"><B>Class</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Use</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../index.html?com/adobe/xmp//class-useXMPConst.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPConst.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<CENTER>
+<H2>
+<B>Uses of Interface<br>com.adobe.xmp.XMPConst</B></H2>
+</CENTER>
+No usage of com.adobe.xmp.XMPConst
+<P>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp"><FONT CLASS="NavBarFont1"><B>Class</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Use</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../index.html?com/adobe/xmp//class-useXMPConst.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPConst.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/com/adobe/xmp/class-use/XMPDateTime.html b/java/XMPCore/docs/com/adobe/xmp/class-use/XMPDateTime.html
new file mode 100644
index 0000000..0356533
--- /dev/null
+++ b/java/XMPCore/docs/com/adobe/xmp/class-use/XMPDateTime.html
@@ -0,0 +1,311 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:51 CEST 2007 -->
+<TITLE>
+Uses of Interface com.adobe.xmp.XMPDateTime
+</TITLE>
+
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="Uses of Interface com.adobe.xmp.XMPDateTime";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp"><FONT CLASS="NavBarFont1"><B>Class</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Use</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../index.html?com/adobe/xmp//class-useXMPDateTime.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPDateTime.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<CENTER>
+<H2>
+<B>Uses of Interface<br>com.adobe.xmp.XMPDateTime</B></H2>
+</CENTER>
+
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+Packages that use <A HREF="../../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><A HREF="#com.adobe.xmp"><B>com.adobe.xmp</B></A></TD>
+<TD>Package containing the xmpcore interface.&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+<A NAME="com.adobe.xmp"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+Uses of <A HREF="../../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A> in <A HREF="../../../../com/adobe/xmp/package-summary.html">com.adobe.xmp</A></FONT></TH>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="left" COLSPAN="2">Methods in <A HREF="../../../../com/adobe/xmp/package-summary.html">com.adobe.xmp</A> that return <A HREF="../../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;<A HREF="../../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A></CODE></FONT></TD>
+<TD><CODE><B>XMPUtils.</B><B><A HREF="../../../../com/adobe/xmp/XMPUtils.html#convertToDate(java.lang.String)">convertToDate</A></B>(java.lang.String&nbsp;rawValue)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Converts a string value to an <code>XMPDateTime</code>.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;<A HREF="../../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A></CODE></FONT></TD>
+<TD><CODE><B>XMPDateTimeFactory.</B><B><A HREF="../../../../com/adobe/xmp/XMPDateTimeFactory.html#convertToLocalTime(com.adobe.xmp.XMPDateTime)">convertToLocalTime</A></B>(<A HREF="../../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A>&nbsp;dateTime)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Make sure a time is local.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;<A HREF="../../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A></CODE></FONT></TD>
+<TD><CODE><B>XMPDateTimeFactory.</B><B><A HREF="../../../../com/adobe/xmp/XMPDateTimeFactory.html#convertToUTCTime(com.adobe.xmp.XMPDateTime)">convertToUTCTime</A></B>(<A HREF="../../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A>&nbsp;dateTime)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Make sure a time is UTC.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;<A HREF="../../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A></CODE></FONT></TD>
+<TD><CODE><B>XMPDateTimeFactory.</B><B><A HREF="../../../../com/adobe/xmp/XMPDateTimeFactory.html#create(int, int, int, int, int, int, int)">create</A></B>(int&nbsp;year,
+ int&nbsp;month,
+ int&nbsp;day,
+ int&nbsp;hour,
+ int&nbsp;minute,
+ int&nbsp;second,
+ int&nbsp;nanoSecond)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Creates an <code>XMPDateTime</code>-object from initial values.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;<A HREF="../../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A></CODE></FONT></TD>
+<TD><CODE><B>XMPDateTimeFactory.</B><B><A HREF="../../../../com/adobe/xmp/XMPDateTimeFactory.html#createFromCalendar(java.util.Calendar)">createFromCalendar</A></B>(java.util.Calendar&nbsp;calendar)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Creates an <code>XMPDateTime</code> from a <code>Calendar</code>-object.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;<A HREF="../../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A></CODE></FONT></TD>
+<TD><CODE><B>XMPDateTimeFactory.</B><B><A HREF="../../../../com/adobe/xmp/XMPDateTimeFactory.html#createFromISO8601(java.lang.String)">createFromISO8601</A></B>(java.lang.String&nbsp;strValue)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Creates an <code>XMPDateTime</code> from an ISO 8601 string.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;<A HREF="../../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A></CODE></FONT></TD>
+<TD><CODE><B>XMPDateTimeFactory.</B><B><A HREF="../../../../com/adobe/xmp/XMPDateTimeFactory.html#getCurrentDateTime()">getCurrentDateTime</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Obtain the current date and time.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A></CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../com/adobe/xmp/XMPMeta.html#getPropertyDate(java.lang.String, java.lang.String)">getPropertyDate</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convenience method to retrieve the literal value of a property.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;<A HREF="../../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A></CODE></FONT></TD>
+<TD><CODE><B>XMPDateTimeFactory.</B><B><A HREF="../../../../com/adobe/xmp/XMPDateTimeFactory.html#setLocalTimeZone(com.adobe.xmp.XMPDateTime)">setLocalTimeZone</A></B>(<A HREF="../../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A>&nbsp;dateTime)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sets the local time zone without touching any other Any existing time zone value is replaced,
+ the other date/time fields are not adjusted in any way.</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="left" COLSPAN="2">Methods in <A HREF="../../../../com/adobe/xmp/package-summary.html">com.adobe.xmp</A> with parameters of type <A HREF="../../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B>XMPUtils.</B><B><A HREF="../../../../com/adobe/xmp/XMPUtils.html#convertFromDate(com.adobe.xmp.XMPDateTime)">convertFromDate</A></B>(<A HREF="../../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A>&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convert from <code>XMPDateTime</code> to string.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;<A HREF="../../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A></CODE></FONT></TD>
+<TD><CODE><B>XMPDateTimeFactory.</B><B><A HREF="../../../../com/adobe/xmp/XMPDateTimeFactory.html#convertToLocalTime(com.adobe.xmp.XMPDateTime)">convertToLocalTime</A></B>(<A HREF="../../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A>&nbsp;dateTime)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Make sure a time is local.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;<A HREF="../../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A></CODE></FONT></TD>
+<TD><CODE><B>XMPDateTimeFactory.</B><B><A HREF="../../../../com/adobe/xmp/XMPDateTimeFactory.html#convertToUTCTime(com.adobe.xmp.XMPDateTime)">convertToUTCTime</A></B>(<A HREF="../../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A>&nbsp;dateTime)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Make sure a time is UTC.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;<A HREF="../../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A></CODE></FONT></TD>
+<TD><CODE><B>XMPDateTimeFactory.</B><B><A HREF="../../../../com/adobe/xmp/XMPDateTimeFactory.html#setLocalTimeZone(com.adobe.xmp.XMPDateTime)">setLocalTimeZone</A></B>(<A HREF="../../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A>&nbsp;dateTime)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sets the local time zone without touching any other Any existing time zone value is replaced,
+ the other date/time fields are not adjusted in any way.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../com/adobe/xmp/XMPMeta.html#setPropertyDate(java.lang.String, java.lang.String, com.adobe.xmp.XMPDateTime)">setPropertyDate</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ <A HREF="../../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A>&nbsp;propValue)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../com/adobe/xmp/XMPMeta.html#setPropertyDate(java.lang.String, java.lang.String, com.adobe.xmp.XMPDateTime, com.adobe.xmp.options.PropertyOptions)">setPropertyDate</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ <A HREF="../../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A>&nbsp;propValue,
+ <A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convenience method to set a property with an XMPDateTime-object,
+ which is serialized to an ISO8601 date.</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp"><FONT CLASS="NavBarFont1"><B>Class</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Use</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../index.html?com/adobe/xmp//class-useXMPDateTime.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPDateTime.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/com/adobe/xmp/class-use/XMPDateTimeFactory.html b/java/XMPCore/docs/com/adobe/xmp/class-use/XMPDateTimeFactory.html
new file mode 100644
index 0000000..44b66db
--- /dev/null
+++ b/java/XMPCore/docs/com/adobe/xmp/class-use/XMPDateTimeFactory.html
@@ -0,0 +1,140 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:51 CEST 2007 -->
+<TITLE>
+Uses of Class com.adobe.xmp.XMPDateTimeFactory
+</TITLE>
+
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="Uses of Class com.adobe.xmp.XMPDateTimeFactory";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../com/adobe/xmp/XMPDateTimeFactory.html" title="class in com.adobe.xmp"><FONT CLASS="NavBarFont1"><B>Class</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Use</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../index.html?com/adobe/xmp//class-useXMPDateTimeFactory.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPDateTimeFactory.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<CENTER>
+<H2>
+<B>Uses of Class<br>com.adobe.xmp.XMPDateTimeFactory</B></H2>
+</CENTER>
+No usage of com.adobe.xmp.XMPDateTimeFactory
+<P>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../com/adobe/xmp/XMPDateTimeFactory.html" title="class in com.adobe.xmp"><FONT CLASS="NavBarFont1"><B>Class</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Use</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../index.html?com/adobe/xmp//class-useXMPDateTimeFactory.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPDateTimeFactory.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/com/adobe/xmp/class-use/XMPError.html b/java/XMPCore/docs/com/adobe/xmp/class-use/XMPError.html
new file mode 100644
index 0000000..ee642e6
--- /dev/null
+++ b/java/XMPCore/docs/com/adobe/xmp/class-use/XMPError.html
@@ -0,0 +1,140 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:51 CEST 2007 -->
+<TITLE>
+Uses of Interface com.adobe.xmp.XMPError
+</TITLE>
+
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="Uses of Interface com.adobe.xmp.XMPError";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../com/adobe/xmp/XMPError.html" title="interface in com.adobe.xmp"><FONT CLASS="NavBarFont1"><B>Class</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Use</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../index.html?com/adobe/xmp//class-useXMPError.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPError.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<CENTER>
+<H2>
+<B>Uses of Interface<br>com.adobe.xmp.XMPError</B></H2>
+</CENTER>
+No usage of com.adobe.xmp.XMPError
+<P>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../com/adobe/xmp/XMPError.html" title="interface in com.adobe.xmp"><FONT CLASS="NavBarFont1"><B>Class</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Use</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../index.html?com/adobe/xmp//class-useXMPError.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPError.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/com/adobe/xmp/class-use/XMPException.html b/java/XMPCore/docs/com/adobe/xmp/class-use/XMPException.html
new file mode 100644
index 0000000..a75d4c5
--- /dev/null
+++ b/java/XMPCore/docs/com/adobe/xmp/class-use/XMPException.html
@@ -0,0 +1,989 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:51 CEST 2007 -->
+<TITLE>
+Uses of Class com.adobe.xmp.XMPException
+</TITLE>
+
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="Uses of Class com.adobe.xmp.XMPException";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp"><FONT CLASS="NavBarFont1"><B>Class</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Use</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../index.html?com/adobe/xmp//class-useXMPException.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPException.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<CENTER>
+<H2>
+<B>Uses of Class<br>com.adobe.xmp.XMPException</B></H2>
+</CENTER>
+
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+Packages that use <A HREF="../../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><A HREF="#com.adobe.xmp"><B>com.adobe.xmp</B></A></TD>
+<TD>Package containing the xmpcore interface.&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><A HREF="#com.adobe.xmp.options"><B>com.adobe.xmp.options</B></A></TD>
+<TD>Package containing the option classes.&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+<A NAME="com.adobe.xmp"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+Uses of <A HREF="../../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A> in <A HREF="../../../../com/adobe/xmp/package-summary.html">com.adobe.xmp</A></FONT></TH>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="left" COLSPAN="2">Methods in <A HREF="../../../../com/adobe/xmp/package-summary.html">com.adobe.xmp</A> that throw <A HREF="../../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../com/adobe/xmp/XMPMeta.html#appendArrayItem(java.lang.String, java.lang.String, com.adobe.xmp.options.PropertyOptions, java.lang.String, com.adobe.xmp.options.PropertyOptions)">appendArrayItem</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;arrayName,
+ <A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;arrayOptions,
+ java.lang.String&nbsp;itemValue,
+ <A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;itemOptions)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Simplifies the construction of an array by not requiring that you pre-create an empty array.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../com/adobe/xmp/XMPMeta.html#appendArrayItem(java.lang.String, java.lang.String, java.lang.String)">appendArrayItem</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;arrayName,
+ java.lang.String&nbsp;itemValue)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPUtils.</B><B><A HREF="../../../../com/adobe/xmp/XMPUtils.html#appendProperties(com.adobe.xmp.XMPMeta, com.adobe.xmp.XMPMeta, boolean, boolean)">appendProperties</A></B>(<A HREF="../../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>&nbsp;source,
+ <A HREF="../../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>&nbsp;dest,
+ boolean&nbsp;doAllProperties,
+ boolean&nbsp;replaceOldValues)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Alias without the new option <code>deleteEmptyValues</code>.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPUtils.</B><B><A HREF="../../../../com/adobe/xmp/XMPUtils.html#appendProperties(com.adobe.xmp.XMPMeta, com.adobe.xmp.XMPMeta, boolean, boolean, boolean)">appendProperties</A></B>(<A HREF="../../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>&nbsp;source,
+ <A HREF="../../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>&nbsp;dest,
+ boolean&nbsp;doAllProperties,
+ boolean&nbsp;replaceOldValues,
+ boolean&nbsp;deleteEmptyValues)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Append properties from one XMP object to another.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B>XMPUtils.</B><B><A HREF="../../../../com/adobe/xmp/XMPUtils.html#catenateArrayItems(com.adobe.xmp.XMPMeta, java.lang.String, java.lang.String, java.lang.String, java.lang.String, boolean)">catenateArrayItems</A></B>(<A HREF="../../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>&nbsp;xmp,
+ java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;arrayName,
+ java.lang.String&nbsp;separator,
+ java.lang.String&nbsp;quotes,
+ boolean&nbsp;allowCommas)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Create a single edit string from an array of strings.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B>XMPPathFactory.</B><B><A HREF="../../../../com/adobe/xmp/XMPPathFactory.html#composeFieldSelector(java.lang.String, java.lang.String, java.lang.String, java.lang.String)">composeFieldSelector</A></B>(java.lang.String&nbsp;arrayName,
+ java.lang.String&nbsp;fieldNS,
+ java.lang.String&nbsp;fieldName,
+ java.lang.String&nbsp;fieldValue)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Compose the path expression to select an alternate item by a field's value.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B>XMPPathFactory.</B><B><A HREF="../../../../com/adobe/xmp/XMPPathFactory.html#composeQualifierPath(java.lang.String, java.lang.String)">composeQualifierPath</A></B>(java.lang.String&nbsp;qualNS,
+ java.lang.String&nbsp;qualName)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Compose the path expression for a qualifier.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B>XMPPathFactory.</B><B><A HREF="../../../../com/adobe/xmp/XMPPathFactory.html#composeStructFieldPath(java.lang.String, java.lang.String)">composeStructFieldPath</A></B>(java.lang.String&nbsp;fieldNS,
+ java.lang.String&nbsp;fieldName)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Compose the path expression for a field in a struct.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B>XMPUtils.</B><B><A HREF="../../../../com/adobe/xmp/XMPUtils.html#convertToBoolean(java.lang.String)">convertToBoolean</A></B>(java.lang.String&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convert from string to Boolean.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;<A HREF="../../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A></CODE></FONT></TD>
+<TD><CODE><B>XMPUtils.</B><B><A HREF="../../../../com/adobe/xmp/XMPUtils.html#convertToDate(java.lang.String)">convertToDate</A></B>(java.lang.String&nbsp;rawValue)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Converts a string value to an <code>XMPDateTime</code>.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;double</CODE></FONT></TD>
+<TD><CODE><B>XMPUtils.</B><B><A HREF="../../../../com/adobe/xmp/XMPUtils.html#convertToDouble(java.lang.String)">convertToDouble</A></B>(java.lang.String&nbsp;rawValue)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Converts a string value to a <code>double</code>.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B>XMPUtils.</B><B><A HREF="../../../../com/adobe/xmp/XMPUtils.html#convertToInteger(java.lang.String)">convertToInteger</A></B>(java.lang.String&nbsp;rawValue)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Converts a string value to an <code>int</code>.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;long</CODE></FONT></TD>
+<TD><CODE><B>XMPUtils.</B><B><A HREF="../../../../com/adobe/xmp/XMPUtils.html#convertToLong(java.lang.String)">convertToLong</A></B>(java.lang.String&nbsp;rawValue)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Converts a string value to a <code>long</code>.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../com/adobe/xmp/XMPMeta.html#countArrayItems(java.lang.String, java.lang.String)">countArrayItems</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;arrayName)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Returns the number of items in the array.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;<A HREF="../../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A></CODE></FONT></TD>
+<TD><CODE><B>XMPDateTimeFactory.</B><B><A HREF="../../../../com/adobe/xmp/XMPDateTimeFactory.html#createFromISO8601(java.lang.String)">createFromISO8601</A></B>(java.lang.String&nbsp;strValue)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Creates an <code>XMPDateTime</code> from an ISO 8601 string.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;byte[]</CODE></FONT></TD>
+<TD><CODE><B>XMPUtils.</B><B><A HREF="../../../../com/adobe/xmp/XMPUtils.html#decodeBase64(java.lang.String)">decodeBase64</A></B>(java.lang.String&nbsp;base64String)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Decode from Base64 encoded string to raw data.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../com/adobe/xmp/properties/XMPProperty.html" title="interface in com.adobe.xmp.properties">XMPProperty</A></CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../com/adobe/xmp/XMPMeta.html#getArrayItem(java.lang.String, java.lang.String, int)">getArrayItem</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;arrayName,
+ int&nbsp;itemIndex)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Provides access to items within an array.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../com/adobe/xmp/properties/XMPProperty.html" title="interface in com.adobe.xmp.properties">XMPProperty</A></CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../com/adobe/xmp/XMPMeta.html#getLocalizedText(java.lang.String, java.lang.String, java.lang.String, java.lang.String)">getLocalizedText</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;altTextName,
+ java.lang.String&nbsp;genericLang,
+ java.lang.String&nbsp;specificLang)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;These functions provide convenient support for localized text properties, including a number
+ of special and obscure aspects.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../com/adobe/xmp/properties/XMPProperty.html" title="interface in com.adobe.xmp.properties">XMPProperty</A></CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../com/adobe/xmp/XMPMeta.html#getProperty(java.lang.String, java.lang.String)">getProperty</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The property value getter-methods all take a property specification: the first two parameters
+ are always the top level namespace URI (the &quot;schema&quot; namespace) and the basic name
+ of the property being referenced.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;byte[]</CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../com/adobe/xmp/XMPMeta.html#getPropertyBase64(java.lang.String, java.lang.String)">getPropertyBase64</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convenience method to retrieve the literal value of a property.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.lang.Boolean</CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../com/adobe/xmp/XMPMeta.html#getPropertyBoolean(java.lang.String, java.lang.String)">getPropertyBoolean</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;These are very similar to <code>getProperty()</code> and <code>SetProperty()</code> above,
+ but the value is returned or provided in a literal form instead of as a UTF-8 string.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.util.Calendar</CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../com/adobe/xmp/XMPMeta.html#getPropertyCalendar(java.lang.String, java.lang.String)">getPropertyCalendar</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convenience method to retrieve the literal value of a property.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A></CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../com/adobe/xmp/XMPMeta.html#getPropertyDate(java.lang.String, java.lang.String)">getPropertyDate</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convenience method to retrieve the literal value of a property.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.lang.Double</CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../com/adobe/xmp/XMPMeta.html#getPropertyDouble(java.lang.String, java.lang.String)">getPropertyDouble</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convenience method to retrieve the literal value of a property.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.lang.Integer</CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../com/adobe/xmp/XMPMeta.html#getPropertyInteger(java.lang.String, java.lang.String)">getPropertyInteger</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convenience method to retrieve the literal value of a property.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.lang.Long</CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../com/adobe/xmp/XMPMeta.html#getPropertyLong(java.lang.String, java.lang.String)">getPropertyLong</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convenience method to retrieve the literal value of a property.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../com/adobe/xmp/XMPMeta.html#getPropertyString(java.lang.String, java.lang.String)">getPropertyString</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convenience method to retrieve the literal value of a property.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../com/adobe/xmp/properties/XMPProperty.html" title="interface in com.adobe.xmp.properties">XMPProperty</A></CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../com/adobe/xmp/XMPMeta.html#getQualifier(java.lang.String, java.lang.String, java.lang.String, java.lang.String)">getQualifier</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ java.lang.String&nbsp;qualNS,
+ java.lang.String&nbsp;qualName)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Provides access to a qualifier attached to a property.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../com/adobe/xmp/properties/XMPProperty.html" title="interface in com.adobe.xmp.properties">XMPProperty</A></CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../com/adobe/xmp/XMPMeta.html#getStructField(java.lang.String, java.lang.String, java.lang.String, java.lang.String)">getStructField</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;structName,
+ java.lang.String&nbsp;fieldNS,
+ java.lang.String&nbsp;fieldName)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Provides access to fields within a nested structure.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../com/adobe/xmp/XMPMeta.html#insertArrayItem(java.lang.String, java.lang.String, int, java.lang.String)">insertArrayItem</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;arrayName,
+ int&nbsp;itemIndex,
+ java.lang.String&nbsp;itemValue)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../com/adobe/xmp/XMPMeta.html#insertArrayItem(java.lang.String, java.lang.String, int, java.lang.String, com.adobe.xmp.options.PropertyOptions)">insertArrayItem</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;arrayName,
+ int&nbsp;itemIndex,
+ java.lang.String&nbsp;itemValue,
+ <A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Inserts an item into an array previous to the given index.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../com/adobe/xmp/XMPIterator.html" title="interface in com.adobe.xmp">XMPIterator</A></CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../com/adobe/xmp/XMPMeta.html#iterator()">iterator</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Constructs an iterator for the properties within this XMP object.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../com/adobe/xmp/XMPIterator.html" title="interface in com.adobe.xmp">XMPIterator</A></CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../com/adobe/xmp/XMPMeta.html#iterator(com.adobe.xmp.options.IteratorOptions)">iterator</A></B>(<A HREF="../../../../com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options">IteratorOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Constructs an iterator for the properties within this XMP object using some options.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../com/adobe/xmp/XMPIterator.html" title="interface in com.adobe.xmp">XMPIterator</A></CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../com/adobe/xmp/XMPMeta.html#iterator(java.lang.String, java.lang.String, com.adobe.xmp.options.IteratorOptions)">iterator</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ <A HREF="../../../../com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options">IteratorOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Construct an iterator for the properties within an XMP object.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;<A HREF="../../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A></CODE></FONT></TD>
+<TD><CODE><B>XMPMetaFactory.</B><B><A HREF="../../../../com/adobe/xmp/XMPMetaFactory.html#parse(java.io.InputStream)">parse</A></B>(java.io.InputStream&nbsp;in)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Parsing with default options.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;<A HREF="../../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A></CODE></FONT></TD>
+<TD><CODE><B>XMPMetaFactory.</B><B><A HREF="../../../../com/adobe/xmp/XMPMetaFactory.html#parse(java.io.InputStream, com.adobe.xmp.options.ParseOptions)">parse</A></B>(java.io.InputStream&nbsp;in,
+ <A HREF="../../../../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options">ParseOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;These functions support parsing serialized RDF into an XMP object, and serailizing an XMP
+ object into RDF.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;<A HREF="../../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A></CODE></FONT></TD>
+<TD><CODE><B>XMPMetaFactory.</B><B><A HREF="../../../../com/adobe/xmp/XMPMetaFactory.html#parseFromBuffer(byte[])">parseFromBuffer</A></B>(byte[]&nbsp;buffer)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Parsing with default options.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;<A HREF="../../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A></CODE></FONT></TD>
+<TD><CODE><B>XMPMetaFactory.</B><B><A HREF="../../../../com/adobe/xmp/XMPMetaFactory.html#parseFromBuffer(byte[], com.adobe.xmp.options.ParseOptions)">parseFromBuffer</A></B>(byte[]&nbsp;buffer,
+ <A HREF="../../../../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options">ParseOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Creates an <code>XMPMeta</code>-object from a byte-buffer.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;<A HREF="../../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A></CODE></FONT></TD>
+<TD><CODE><B>XMPMetaFactory.</B><B><A HREF="../../../../com/adobe/xmp/XMPMetaFactory.html#parseFromString(java.lang.String)">parseFromString</A></B>(java.lang.String&nbsp;packet)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Parsing with default options.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;<A HREF="../../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A></CODE></FONT></TD>
+<TD><CODE><B>XMPMetaFactory.</B><B><A HREF="../../../../com/adobe/xmp/XMPMetaFactory.html#parseFromString(java.lang.String, com.adobe.xmp.options.ParseOptions)">parseFromString</A></B>(java.lang.String&nbsp;packet,
+ <A HREF="../../../../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options">ParseOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Creates an <code>XMPMeta</code>-object from a string.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPSchemaRegistry.</B><B><A HREF="../../../../com/adobe/xmp/XMPSchemaRegistry.html#registerAlias(java.lang.String, java.lang.String, java.lang.String, java.lang.String, com.adobe.xmp.options.AliasOptions)">registerAlias</A></B>(java.lang.String&nbsp;aliasNS,
+ java.lang.String&nbsp;aliasProp,
+ java.lang.String&nbsp;actualNS,
+ java.lang.String&nbsp;actualProp,
+ <A HREF="../../../../com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options">AliasOptions</A>&nbsp;aliasForm)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Associates an alias name with an actual name.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B>XMPSchemaRegistry.</B><B><A HREF="../../../../com/adobe/xmp/XMPSchemaRegistry.html#registerNamespace(java.lang.String, java.lang.String)">registerNamespace</A></B>(java.lang.String&nbsp;namespaceURI,
+ java.lang.String&nbsp;suggestedPrefix)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Register a namespace URI with a suggested prefix.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPUtils.</B><B><A HREF="../../../../com/adobe/xmp/XMPUtils.html#removeProperties(com.adobe.xmp.XMPMeta, java.lang.String, java.lang.String, boolean, boolean)">removeProperties</A></B>(<A HREF="../../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>&nbsp;xmp,
+ java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ boolean&nbsp;doAllProperties,
+ boolean&nbsp;includeAliases)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Remove multiple properties from an XMP object.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPUtils.</B><B><A HREF="../../../../com/adobe/xmp/XMPUtils.html#separateArrayItems(com.adobe.xmp.XMPMeta, java.lang.String, java.lang.String, java.lang.String, com.adobe.xmp.options.PropertyOptions, boolean)">separateArrayItems</A></B>(<A HREF="../../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>&nbsp;xmp,
+ java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;arrayName,
+ java.lang.String&nbsp;catedStr,
+ <A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;arrayOptions,
+ boolean&nbsp;preserveCommas)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Separate a single edit string into an array of strings.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPMetaFactory.</B><B><A HREF="../../../../com/adobe/xmp/XMPMetaFactory.html#serialize(com.adobe.xmp.XMPMeta, java.io.OutputStream)">serialize</A></B>(<A HREF="../../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>&nbsp;xmp,
+ java.io.OutputStream&nbsp;out)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Serializes an <code>XMPMeta</code>-object as RDF into an <code>OutputStream</code>
+ with default options.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPMetaFactory.</B><B><A HREF="../../../../com/adobe/xmp/XMPMetaFactory.html#serialize(com.adobe.xmp.XMPMeta, java.io.OutputStream, com.adobe.xmp.options.SerializeOptions)">serialize</A></B>(<A HREF="../../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>&nbsp;xmp,
+ java.io.OutputStream&nbsp;out,
+ <A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Serializes an <code>XMPMeta</code>-object as RDF into an <code>OutputStream</code>.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;byte[]</CODE></FONT></TD>
+<TD><CODE><B>XMPMetaFactory.</B><B><A HREF="../../../../com/adobe/xmp/XMPMetaFactory.html#serializeToBuffer(com.adobe.xmp.XMPMeta, com.adobe.xmp.options.SerializeOptions)">serializeToBuffer</A></B>(<A HREF="../../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>&nbsp;xmp,
+ <A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Serializes an <code>XMPMeta</code>-object as RDF into a byte buffer.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B>XMPMetaFactory.</B><B><A HREF="../../../../com/adobe/xmp/XMPMetaFactory.html#serializeToString(com.adobe.xmp.XMPMeta, com.adobe.xmp.options.SerializeOptions)">serializeToString</A></B>(<A HREF="../../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>&nbsp;xmp,
+ <A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Serializes an <code>XMPMeta</code>-object as RDF into a string.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../com/adobe/xmp/XMPMeta.html#setArrayItem(java.lang.String, java.lang.String, int, java.lang.String)">setArrayItem</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;arrayName,
+ int&nbsp;itemIndex,
+ java.lang.String&nbsp;itemValue)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../com/adobe/xmp/XMPMeta.html#setArrayItem(java.lang.String, java.lang.String, int, java.lang.String, com.adobe.xmp.options.PropertyOptions)">setArrayItem</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;arrayName,
+ int&nbsp;itemIndex,
+ java.lang.String&nbsp;itemValue,
+ <A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Replaces an item within an array.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../com/adobe/xmp/XMPMeta.html#setLocalizedText(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String)">setLocalizedText</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;altTextName,
+ java.lang.String&nbsp;genericLang,
+ java.lang.String&nbsp;specificLang,
+ java.lang.String&nbsp;itemValue)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../com/adobe/xmp/XMPMeta.html#setLocalizedText(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, com.adobe.xmp.options.PropertyOptions)">setLocalizedText</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;altTextName,
+ java.lang.String&nbsp;genericLang,
+ java.lang.String&nbsp;specificLang,
+ java.lang.String&nbsp;itemValue,
+ <A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Modifies the value of a selected item in an alt-text array.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../com/adobe/xmp/XMPMeta.html#setProperty(java.lang.String, java.lang.String, java.lang.Object)">setProperty</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ java.lang.Object&nbsp;propValue)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../com/adobe/xmp/XMPMeta.html#setProperty(java.lang.String, java.lang.String, java.lang.Object, com.adobe.xmp.options.PropertyOptions)">setProperty</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ java.lang.Object&nbsp;propValue,
+ <A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The property value <code>setters</code> all take a property specification, their
+ differences are in the form of this.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../com/adobe/xmp/XMPMeta.html#setPropertyBase64(java.lang.String, java.lang.String, byte[])">setPropertyBase64</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ byte[]&nbsp;propValue)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../com/adobe/xmp/XMPMeta.html#setPropertyBase64(java.lang.String, java.lang.String, byte[], com.adobe.xmp.options.PropertyOptions)">setPropertyBase64</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ byte[]&nbsp;propValue,
+ <A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convenience method to set a property from a binary <code>byte[]</code>-array,
+ which is serialized as base64-string.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../com/adobe/xmp/XMPMeta.html#setPropertyBoolean(java.lang.String, java.lang.String, boolean)">setPropertyBoolean</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ boolean&nbsp;propValue)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../com/adobe/xmp/XMPMeta.html#setPropertyBoolean(java.lang.String, java.lang.String, boolean, com.adobe.xmp.options.PropertyOptions)">setPropertyBoolean</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ boolean&nbsp;propValue,
+ <A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convenience method to set a property to a literal <code>boolean</code> value.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../com/adobe/xmp/XMPMeta.html#setPropertyCalendar(java.lang.String, java.lang.String, java.util.Calendar)">setPropertyCalendar</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ java.util.Calendar&nbsp;propValue)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../com/adobe/xmp/XMPMeta.html#setPropertyCalendar(java.lang.String, java.lang.String, java.util.Calendar, com.adobe.xmp.options.PropertyOptions)">setPropertyCalendar</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ java.util.Calendar&nbsp;propValue,
+ <A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convenience method to set a property with a Java Calendar-object,
+ which is serialized to an ISO8601 date.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../com/adobe/xmp/XMPMeta.html#setPropertyDate(java.lang.String, java.lang.String, com.adobe.xmp.XMPDateTime)">setPropertyDate</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ <A HREF="../../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A>&nbsp;propValue)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../com/adobe/xmp/XMPMeta.html#setPropertyDate(java.lang.String, java.lang.String, com.adobe.xmp.XMPDateTime, com.adobe.xmp.options.PropertyOptions)">setPropertyDate</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ <A HREF="../../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A>&nbsp;propValue,
+ <A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convenience method to set a property with an XMPDateTime-object,
+ which is serialized to an ISO8601 date.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../com/adobe/xmp/XMPMeta.html#setPropertyDouble(java.lang.String, java.lang.String, double)">setPropertyDouble</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ double&nbsp;propValue)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../com/adobe/xmp/XMPMeta.html#setPropertyDouble(java.lang.String, java.lang.String, double, com.adobe.xmp.options.PropertyOptions)">setPropertyDouble</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ double&nbsp;propValue,
+ <A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convenience method to set a property to a literal <code>double</code> value.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../com/adobe/xmp/XMPMeta.html#setPropertyInteger(java.lang.String, java.lang.String, int)">setPropertyInteger</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ int&nbsp;propValue)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../com/adobe/xmp/XMPMeta.html#setPropertyInteger(java.lang.String, java.lang.String, int, com.adobe.xmp.options.PropertyOptions)">setPropertyInteger</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ int&nbsp;propValue,
+ <A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convenience method to set a property to a literal <code>int</code> value.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../com/adobe/xmp/XMPMeta.html#setPropertyLong(java.lang.String, java.lang.String, long)">setPropertyLong</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ long&nbsp;propValue)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../com/adobe/xmp/XMPMeta.html#setPropertyLong(java.lang.String, java.lang.String, long, com.adobe.xmp.options.PropertyOptions)">setPropertyLong</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ long&nbsp;propValue,
+ <A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convenience method to set a property to a literal <code>long</code> value.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../com/adobe/xmp/XMPMeta.html#setQualifier(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String)">setQualifier</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ java.lang.String&nbsp;qualNS,
+ java.lang.String&nbsp;qualName,
+ java.lang.String&nbsp;qualValue)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../com/adobe/xmp/XMPMeta.html#setQualifier(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, com.adobe.xmp.options.PropertyOptions)">setQualifier</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ java.lang.String&nbsp;qualNS,
+ java.lang.String&nbsp;qualName,
+ java.lang.String&nbsp;qualValue,
+ <A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Provides access to a qualifier attached to a property.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../com/adobe/xmp/XMPMeta.html#setStructField(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String)">setStructField</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;structName,
+ java.lang.String&nbsp;fieldNS,
+ java.lang.String&nbsp;fieldName,
+ java.lang.String&nbsp;fieldValue)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../com/adobe/xmp/XMPMeta.html#setStructField(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, com.adobe.xmp.options.PropertyOptions)">setStructField</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;structName,
+ java.lang.String&nbsp;fieldNS,
+ java.lang.String&nbsp;fieldName,
+ java.lang.String&nbsp;fieldValue,
+ <A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Provides access to fields within a nested structure.</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+<A NAME="com.adobe.xmp.options"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+Uses of <A HREF="../../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A> in <A HREF="../../../../com/adobe/xmp/options/package-summary.html">com.adobe.xmp.options</A></FONT></TH>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="left" COLSPAN="2">Methods in <A HREF="../../../../com/adobe/xmp/options/package-summary.html">com.adobe.xmp.options</A> that throw <A HREF="../../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>PropertyOptions.</B><B><A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html#assertConsistency(int)">assertConsistency</A></B>(int&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Checks that a node not a struct and array at the same time;
+ and URI cannot be a struct.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>PropertyOptions.</B><B><A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html#mergeWith(com.adobe.xmp.options.PropertyOptions)">mergeWith</A></B>(<A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Merges the set options of a another options object with this.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>Options.</B><B><A HREF="../../../../com/adobe/xmp/options/Options.html#setOptions(int)">setOptions</A></B>(int&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A></CODE></FONT></TD>
+<TD><CODE><B>AliasOptions.</B><B><A HREF="../../../../com/adobe/xmp/options/AliasOptions.html#toPropertyOptions()">toPropertyOptions</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="left" COLSPAN="2">Constructors in <A HREF="../../../../com/adobe/xmp/options/package-summary.html">com.adobe.xmp.options</A> that throw <A HREF="../../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/AliasOptions.html#AliasOptions(int)">AliasOptions</A></B>(int&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/Options.html#Options(int)">Options</A></B>(int&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Constructor with the options bit mask.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html#PropertyOptions(int)">PropertyOptions</A></B>(int&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Intialization constructor</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html#SerializeOptions(int)">SerializeOptions</A></B>(int&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Constructor using inital options</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp"><FONT CLASS="NavBarFont1"><B>Class</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Use</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../index.html?com/adobe/xmp//class-useXMPException.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPException.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/com/adobe/xmp/class-use/XMPIterator.html b/java/XMPCore/docs/com/adobe/xmp/class-use/XMPIterator.html
new file mode 100644
index 0000000..4571da1
--- /dev/null
+++ b/java/XMPCore/docs/com/adobe/xmp/class-use/XMPIterator.html
@@ -0,0 +1,194 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:51 CEST 2007 -->
+<TITLE>
+Uses of Interface com.adobe.xmp.XMPIterator
+</TITLE>
+
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="Uses of Interface com.adobe.xmp.XMPIterator";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../com/adobe/xmp/XMPIterator.html" title="interface in com.adobe.xmp"><FONT CLASS="NavBarFont1"><B>Class</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Use</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../index.html?com/adobe/xmp//class-useXMPIterator.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPIterator.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<CENTER>
+<H2>
+<B>Uses of Interface<br>com.adobe.xmp.XMPIterator</B></H2>
+</CENTER>
+
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+Packages that use <A HREF="../../../../com/adobe/xmp/XMPIterator.html" title="interface in com.adobe.xmp">XMPIterator</A></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><A HREF="#com.adobe.xmp"><B>com.adobe.xmp</B></A></TD>
+<TD>Package containing the xmpcore interface.&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+<A NAME="com.adobe.xmp"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+Uses of <A HREF="../../../../com/adobe/xmp/XMPIterator.html" title="interface in com.adobe.xmp">XMPIterator</A> in <A HREF="../../../../com/adobe/xmp/package-summary.html">com.adobe.xmp</A></FONT></TH>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="left" COLSPAN="2">Methods in <A HREF="../../../../com/adobe/xmp/package-summary.html">com.adobe.xmp</A> that return <A HREF="../../../../com/adobe/xmp/XMPIterator.html" title="interface in com.adobe.xmp">XMPIterator</A></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../com/adobe/xmp/XMPIterator.html" title="interface in com.adobe.xmp">XMPIterator</A></CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../com/adobe/xmp/XMPMeta.html#iterator()">iterator</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Constructs an iterator for the properties within this XMP object.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../com/adobe/xmp/XMPIterator.html" title="interface in com.adobe.xmp">XMPIterator</A></CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../com/adobe/xmp/XMPMeta.html#iterator(com.adobe.xmp.options.IteratorOptions)">iterator</A></B>(<A HREF="../../../../com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options">IteratorOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Constructs an iterator for the properties within this XMP object using some options.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../com/adobe/xmp/XMPIterator.html" title="interface in com.adobe.xmp">XMPIterator</A></CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../com/adobe/xmp/XMPMeta.html#iterator(java.lang.String, java.lang.String, com.adobe.xmp.options.IteratorOptions)">iterator</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ <A HREF="../../../../com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options">IteratorOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Construct an iterator for the properties within an XMP object.</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../com/adobe/xmp/XMPIterator.html" title="interface in com.adobe.xmp"><FONT CLASS="NavBarFont1"><B>Class</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Use</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../index.html?com/adobe/xmp//class-useXMPIterator.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPIterator.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/com/adobe/xmp/class-use/XMPMeta.html b/java/XMPCore/docs/com/adobe/xmp/class-use/XMPMeta.html
new file mode 100644
index 0000000..558b38c
--- /dev/null
+++ b/java/XMPCore/docs/com/adobe/xmp/class-use/XMPMeta.html
@@ -0,0 +1,335 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:51 CEST 2007 -->
+<TITLE>
+Uses of Interface com.adobe.xmp.XMPMeta
+</TITLE>
+
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="Uses of Interface com.adobe.xmp.XMPMeta";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp"><FONT CLASS="NavBarFont1"><B>Class</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Use</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../index.html?com/adobe/xmp//class-useXMPMeta.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPMeta.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<CENTER>
+<H2>
+<B>Uses of Interface<br>com.adobe.xmp.XMPMeta</B></H2>
+</CENTER>
+
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+Packages that use <A HREF="../../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><A HREF="#com.adobe.xmp"><B>com.adobe.xmp</B></A></TD>
+<TD>Package containing the xmpcore interface.&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+<A NAME="com.adobe.xmp"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+Uses of <A HREF="../../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A> in <A HREF="../../../../com/adobe/xmp/package-summary.html">com.adobe.xmp</A></FONT></TH>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="left" COLSPAN="2">Methods in <A HREF="../../../../com/adobe/xmp/package-summary.html">com.adobe.xmp</A> that return <A HREF="../../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;<A HREF="../../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A></CODE></FONT></TD>
+<TD><CODE><B>XMPMetaFactory.</B><B><A HREF="../../../../com/adobe/xmp/XMPMetaFactory.html#create()">create</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;<A HREF="../../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A></CODE></FONT></TD>
+<TD><CODE><B>XMPMetaFactory.</B><B><A HREF="../../../../com/adobe/xmp/XMPMetaFactory.html#parse(java.io.InputStream)">parse</A></B>(java.io.InputStream&nbsp;in)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Parsing with default options.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;<A HREF="../../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A></CODE></FONT></TD>
+<TD><CODE><B>XMPMetaFactory.</B><B><A HREF="../../../../com/adobe/xmp/XMPMetaFactory.html#parse(java.io.InputStream, com.adobe.xmp.options.ParseOptions)">parse</A></B>(java.io.InputStream&nbsp;in,
+ <A HREF="../../../../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options">ParseOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;These functions support parsing serialized RDF into an XMP object, and serailizing an XMP
+ object into RDF.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;<A HREF="../../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A></CODE></FONT></TD>
+<TD><CODE><B>XMPMetaFactory.</B><B><A HREF="../../../../com/adobe/xmp/XMPMetaFactory.html#parseFromBuffer(byte[])">parseFromBuffer</A></B>(byte[]&nbsp;buffer)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Parsing with default options.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;<A HREF="../../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A></CODE></FONT></TD>
+<TD><CODE><B>XMPMetaFactory.</B><B><A HREF="../../../../com/adobe/xmp/XMPMetaFactory.html#parseFromBuffer(byte[], com.adobe.xmp.options.ParseOptions)">parseFromBuffer</A></B>(byte[]&nbsp;buffer,
+ <A HREF="../../../../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options">ParseOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Creates an <code>XMPMeta</code>-object from a byte-buffer.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;<A HREF="../../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A></CODE></FONT></TD>
+<TD><CODE><B>XMPMetaFactory.</B><B><A HREF="../../../../com/adobe/xmp/XMPMetaFactory.html#parseFromString(java.lang.String)">parseFromString</A></B>(java.lang.String&nbsp;packet)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Parsing with default options.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;<A HREF="../../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A></CODE></FONT></TD>
+<TD><CODE><B>XMPMetaFactory.</B><B><A HREF="../../../../com/adobe/xmp/XMPMetaFactory.html#parseFromString(java.lang.String, com.adobe.xmp.options.ParseOptions)">parseFromString</A></B>(java.lang.String&nbsp;packet,
+ <A HREF="../../../../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options">ParseOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Creates an <code>XMPMeta</code>-object from a string.</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="left" COLSPAN="2">Methods in <A HREF="../../../../com/adobe/xmp/package-summary.html">com.adobe.xmp</A> with parameters of type <A HREF="../../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPUtils.</B><B><A HREF="../../../../com/adobe/xmp/XMPUtils.html#appendProperties(com.adobe.xmp.XMPMeta, com.adobe.xmp.XMPMeta, boolean, boolean)">appendProperties</A></B>(<A HREF="../../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>&nbsp;source,
+ <A HREF="../../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>&nbsp;dest,
+ boolean&nbsp;doAllProperties,
+ boolean&nbsp;replaceOldValues)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Alias without the new option <code>deleteEmptyValues</code>.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPUtils.</B><B><A HREF="../../../../com/adobe/xmp/XMPUtils.html#appendProperties(com.adobe.xmp.XMPMeta, com.adobe.xmp.XMPMeta, boolean, boolean, boolean)">appendProperties</A></B>(<A HREF="../../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>&nbsp;source,
+ <A HREF="../../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>&nbsp;dest,
+ boolean&nbsp;doAllProperties,
+ boolean&nbsp;replaceOldValues,
+ boolean&nbsp;deleteEmptyValues)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Append properties from one XMP object to another.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B>XMPUtils.</B><B><A HREF="../../../../com/adobe/xmp/XMPUtils.html#catenateArrayItems(com.adobe.xmp.XMPMeta, java.lang.String, java.lang.String, java.lang.String, java.lang.String, boolean)">catenateArrayItems</A></B>(<A HREF="../../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>&nbsp;xmp,
+ java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;arrayName,
+ java.lang.String&nbsp;separator,
+ java.lang.String&nbsp;quotes,
+ boolean&nbsp;allowCommas)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Create a single edit string from an array of strings.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPUtils.</B><B><A HREF="../../../../com/adobe/xmp/XMPUtils.html#removeProperties(com.adobe.xmp.XMPMeta, java.lang.String, java.lang.String, boolean, boolean)">removeProperties</A></B>(<A HREF="../../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>&nbsp;xmp,
+ java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ boolean&nbsp;doAllProperties,
+ boolean&nbsp;includeAliases)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Remove multiple properties from an XMP object.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPUtils.</B><B><A HREF="../../../../com/adobe/xmp/XMPUtils.html#separateArrayItems(com.adobe.xmp.XMPMeta, java.lang.String, java.lang.String, java.lang.String, com.adobe.xmp.options.PropertyOptions, boolean)">separateArrayItems</A></B>(<A HREF="../../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>&nbsp;xmp,
+ java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;arrayName,
+ java.lang.String&nbsp;catedStr,
+ <A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;arrayOptions,
+ boolean&nbsp;preserveCommas)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Separate a single edit string into an array of strings.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPMetaFactory.</B><B><A HREF="../../../../com/adobe/xmp/XMPMetaFactory.html#serialize(com.adobe.xmp.XMPMeta, java.io.OutputStream)">serialize</A></B>(<A HREF="../../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>&nbsp;xmp,
+ java.io.OutputStream&nbsp;out)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Serializes an <code>XMPMeta</code>-object as RDF into an <code>OutputStream</code>
+ with default options.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPMetaFactory.</B><B><A HREF="../../../../com/adobe/xmp/XMPMetaFactory.html#serialize(com.adobe.xmp.XMPMeta, java.io.OutputStream, com.adobe.xmp.options.SerializeOptions)">serialize</A></B>(<A HREF="../../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>&nbsp;xmp,
+ java.io.OutputStream&nbsp;out,
+ <A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Serializes an <code>XMPMeta</code>-object as RDF into an <code>OutputStream</code>.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;byte[]</CODE></FONT></TD>
+<TD><CODE><B>XMPMetaFactory.</B><B><A HREF="../../../../com/adobe/xmp/XMPMetaFactory.html#serializeToBuffer(com.adobe.xmp.XMPMeta, com.adobe.xmp.options.SerializeOptions)">serializeToBuffer</A></B>(<A HREF="../../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>&nbsp;xmp,
+ <A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Serializes an <code>XMPMeta</code>-object as RDF into a byte buffer.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B>XMPMetaFactory.</B><B><A HREF="../../../../com/adobe/xmp/XMPMetaFactory.html#serializeToString(com.adobe.xmp.XMPMeta, com.adobe.xmp.options.SerializeOptions)">serializeToString</A></B>(<A HREF="../../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>&nbsp;xmp,
+ <A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Serializes an <code>XMPMeta</code>-object as RDF into a string.</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp"><FONT CLASS="NavBarFont1"><B>Class</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Use</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../index.html?com/adobe/xmp//class-useXMPMeta.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPMeta.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/com/adobe/xmp/class-use/XMPMetaFactory.html b/java/XMPCore/docs/com/adobe/xmp/class-use/XMPMetaFactory.html
new file mode 100644
index 0000000..f0e76be
--- /dev/null
+++ b/java/XMPCore/docs/com/adobe/xmp/class-use/XMPMetaFactory.html
@@ -0,0 +1,140 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:51 CEST 2007 -->
+<TITLE>
+Uses of Class com.adobe.xmp.XMPMetaFactory
+</TITLE>
+
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="Uses of Class com.adobe.xmp.XMPMetaFactory";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../com/adobe/xmp/XMPMetaFactory.html" title="class in com.adobe.xmp"><FONT CLASS="NavBarFont1"><B>Class</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Use</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../index.html?com/adobe/xmp//class-useXMPMetaFactory.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPMetaFactory.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<CENTER>
+<H2>
+<B>Uses of Class<br>com.adobe.xmp.XMPMetaFactory</B></H2>
+</CENTER>
+No usage of com.adobe.xmp.XMPMetaFactory
+<P>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../com/adobe/xmp/XMPMetaFactory.html" title="class in com.adobe.xmp"><FONT CLASS="NavBarFont1"><B>Class</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Use</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../index.html?com/adobe/xmp//class-useXMPMetaFactory.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPMetaFactory.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/com/adobe/xmp/class-use/XMPPathFactory.html b/java/XMPCore/docs/com/adobe/xmp/class-use/XMPPathFactory.html
new file mode 100644
index 0000000..4e3f415
--- /dev/null
+++ b/java/XMPCore/docs/com/adobe/xmp/class-use/XMPPathFactory.html
@@ -0,0 +1,140 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:51 CEST 2007 -->
+<TITLE>
+Uses of Class com.adobe.xmp.XMPPathFactory
+</TITLE>
+
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="Uses of Class com.adobe.xmp.XMPPathFactory";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../com/adobe/xmp/XMPPathFactory.html" title="class in com.adobe.xmp"><FONT CLASS="NavBarFont1"><B>Class</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Use</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../index.html?com/adobe/xmp//class-useXMPPathFactory.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPPathFactory.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<CENTER>
+<H2>
+<B>Uses of Class<br>com.adobe.xmp.XMPPathFactory</B></H2>
+</CENTER>
+No usage of com.adobe.xmp.XMPPathFactory
+<P>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../com/adobe/xmp/XMPPathFactory.html" title="class in com.adobe.xmp"><FONT CLASS="NavBarFont1"><B>Class</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Use</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../index.html?com/adobe/xmp//class-useXMPPathFactory.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPPathFactory.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/com/adobe/xmp/class-use/XMPSchemaRegistry.html b/java/XMPCore/docs/com/adobe/xmp/class-use/XMPSchemaRegistry.html
new file mode 100644
index 0000000..58898f2
--- /dev/null
+++ b/java/XMPCore/docs/com/adobe/xmp/class-use/XMPSchemaRegistry.html
@@ -0,0 +1,176 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:51 CEST 2007 -->
+<TITLE>
+Uses of Interface com.adobe.xmp.XMPSchemaRegistry
+</TITLE>
+
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="Uses of Interface com.adobe.xmp.XMPSchemaRegistry";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../com/adobe/xmp/XMPSchemaRegistry.html" title="interface in com.adobe.xmp"><FONT CLASS="NavBarFont1"><B>Class</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Use</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../index.html?com/adobe/xmp//class-useXMPSchemaRegistry.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPSchemaRegistry.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<CENTER>
+<H2>
+<B>Uses of Interface<br>com.adobe.xmp.XMPSchemaRegistry</B></H2>
+</CENTER>
+
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+Packages that use <A HREF="../../../../com/adobe/xmp/XMPSchemaRegistry.html" title="interface in com.adobe.xmp">XMPSchemaRegistry</A></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><A HREF="#com.adobe.xmp"><B>com.adobe.xmp</B></A></TD>
+<TD>Package containing the xmpcore interface.&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+<A NAME="com.adobe.xmp"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+Uses of <A HREF="../../../../com/adobe/xmp/XMPSchemaRegistry.html" title="interface in com.adobe.xmp">XMPSchemaRegistry</A> in <A HREF="../../../../com/adobe/xmp/package-summary.html">com.adobe.xmp</A></FONT></TH>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="left" COLSPAN="2">Methods in <A HREF="../../../../com/adobe/xmp/package-summary.html">com.adobe.xmp</A> that return <A HREF="../../../../com/adobe/xmp/XMPSchemaRegistry.html" title="interface in com.adobe.xmp">XMPSchemaRegistry</A></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;<A HREF="../../../../com/adobe/xmp/XMPSchemaRegistry.html" title="interface in com.adobe.xmp">XMPSchemaRegistry</A></CODE></FONT></TD>
+<TD><CODE><B>XMPMetaFactory.</B><B><A HREF="../../../../com/adobe/xmp/XMPMetaFactory.html#getSchemaRegistry()">getSchemaRegistry</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../com/adobe/xmp/XMPSchemaRegistry.html" title="interface in com.adobe.xmp"><FONT CLASS="NavBarFont1"><B>Class</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Use</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../index.html?com/adobe/xmp//class-useXMPSchemaRegistry.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPSchemaRegistry.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/com/adobe/xmp/class-use/XMPUtils.html b/java/XMPCore/docs/com/adobe/xmp/class-use/XMPUtils.html
new file mode 100644
index 0000000..6e9177c
--- /dev/null
+++ b/java/XMPCore/docs/com/adobe/xmp/class-use/XMPUtils.html
@@ -0,0 +1,140 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:51 CEST 2007 -->
+<TITLE>
+Uses of Class com.adobe.xmp.XMPUtils
+</TITLE>
+
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="Uses of Class com.adobe.xmp.XMPUtils";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../com/adobe/xmp/XMPUtils.html" title="class in com.adobe.xmp"><FONT CLASS="NavBarFont1"><B>Class</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Use</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../index.html?com/adobe/xmp//class-useXMPUtils.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPUtils.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<CENTER>
+<H2>
+<B>Uses of Class<br>com.adobe.xmp.XMPUtils</B></H2>
+</CENTER>
+No usage of com.adobe.xmp.XMPUtils
+<P>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../com/adobe/xmp/XMPUtils.html" title="class in com.adobe.xmp"><FONT CLASS="NavBarFont1"><B>Class</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Use</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../index.html?com/adobe/xmp//class-useXMPUtils.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPUtils.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/com/adobe/xmp/class-use/XMPVersionInfo.html b/java/XMPCore/docs/com/adobe/xmp/class-use/XMPVersionInfo.html
new file mode 100644
index 0000000..33feddb
--- /dev/null
+++ b/java/XMPCore/docs/com/adobe/xmp/class-use/XMPVersionInfo.html
@@ -0,0 +1,176 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:51 CEST 2007 -->
+<TITLE>
+Uses of Interface com.adobe.xmp.XMPVersionInfo
+</TITLE>
+
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="Uses of Interface com.adobe.xmp.XMPVersionInfo";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../com/adobe/xmp/XMPVersionInfo.html" title="interface in com.adobe.xmp"><FONT CLASS="NavBarFont1"><B>Class</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Use</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../index.html?com/adobe/xmp//class-useXMPVersionInfo.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPVersionInfo.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<CENTER>
+<H2>
+<B>Uses of Interface<br>com.adobe.xmp.XMPVersionInfo</B></H2>
+</CENTER>
+
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+Packages that use <A HREF="../../../../com/adobe/xmp/XMPVersionInfo.html" title="interface in com.adobe.xmp">XMPVersionInfo</A></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><A HREF="#com.adobe.xmp"><B>com.adobe.xmp</B></A></TD>
+<TD>Package containing the xmpcore interface.&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+<A NAME="com.adobe.xmp"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+Uses of <A HREF="../../../../com/adobe/xmp/XMPVersionInfo.html" title="interface in com.adobe.xmp">XMPVersionInfo</A> in <A HREF="../../../../com/adobe/xmp/package-summary.html">com.adobe.xmp</A></FONT></TH>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="left" COLSPAN="2">Methods in <A HREF="../../../../com/adobe/xmp/package-summary.html">com.adobe.xmp</A> that return <A HREF="../../../../com/adobe/xmp/XMPVersionInfo.html" title="interface in com.adobe.xmp">XMPVersionInfo</A></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;<A HREF="../../../../com/adobe/xmp/XMPVersionInfo.html" title="interface in com.adobe.xmp">XMPVersionInfo</A></CODE></FONT></TD>
+<TD><CODE><B>XMPMetaFactory.</B><B><A HREF="../../../../com/adobe/xmp/XMPMetaFactory.html#getVersionInfo()">getVersionInfo</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Obtain version information.</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../com/adobe/xmp/XMPVersionInfo.html" title="interface in com.adobe.xmp"><FONT CLASS="NavBarFont1"><B>Class</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Use</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../index.html?com/adobe/xmp//class-useXMPVersionInfo.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPVersionInfo.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/com/adobe/xmp/options/AliasOptions.html b/java/XMPCore/docs/com/adobe/xmp/options/AliasOptions.html
new file mode 100644
index 0000000..183234e
--- /dev/null
+++ b/java/XMPCore/docs/com/adobe/xmp/options/AliasOptions.html
@@ -0,0 +1,591 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:50 CEST 2007 -->
+<TITLE>
+AliasOptions
+</TITLE>
+
+<META NAME="keywords" CONTENT="com.adobe.xmp.options.AliasOptions class">
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="AliasOptions";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="class-use/AliasOptions.html"><FONT CLASS="NavBarFont1"><B>Use</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV CLASS&nbsp;
+&nbsp;<A HREF="../../../../com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../index.html?com/adobe/xmp/options/AliasOptions.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="AliasOptions.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+ SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;<A HREF="#field_summary">FIELD</A>&nbsp;|&nbsp;<A HREF="#constructor_summary">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;<A HREF="#field_detail">FIELD</A>&nbsp;|&nbsp;<A HREF="#constructor_detail">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<!-- ======== START OF CLASS DATA ======== -->
+<H2>
+<FONT SIZE="-1">
+com.adobe.xmp.options</FONT>
+<BR>
+Class AliasOptions</H2>
+<PRE>
+java.lang.Object
+ <IMG SRC="../../../../resources/inherit.gif" ALT="extended by "><A HREF="../../../../com/adobe/xmp/options/Options.html" title="class in com.adobe.xmp.options">com.adobe.xmp.options.Options</A>
+ <IMG SRC="../../../../resources/inherit.gif" ALT="extended by "><B>com.adobe.xmp.options.AliasOptions</B>
+</PRE>
+<HR>
+<DL>
+<DT><PRE>public final class <B>AliasOptions</B><DT>extends <A HREF="../../../../com/adobe/xmp/options/Options.html" title="class in com.adobe.xmp.options">Options</A></DL>
+</PRE>
+
+<P>
+Options for <A HREF="../../../../com/adobe/xmp/XMPSchemaRegistry.html#registerAlias(java.lang.String, java.lang.String, java.lang.String, java.lang.String, com.adobe.xmp.options.AliasOptions)"><CODE>XMPSchemaRegistry.registerAlias( String, String, String, String,
+ AliasOptions)</CODE></A>.
+<P>
+
+<P>
+<DL>
+<DT><B>Since:</B></DT>
+ <DD>20.02.2006</DD>
+</DL>
+<HR>
+
+<P>
+<!-- =========== FIELD SUMMARY =========== -->
+
+<A NAME="field_summary"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+<B>Field Summary</B></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/AliasOptions.html#PROP_ARRAY">PROP_ARRAY</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The actual is an unordered array, the alias is to the first element of the array.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/AliasOptions.html#PROP_ARRAY_ALT_TEXT">PROP_ARRAY_ALT_TEXT</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The actual is an alternate text array, the alias is to the 'x-default' element of the array.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/AliasOptions.html#PROP_ARRAY_ALTERNATE">PROP_ARRAY_ALTERNATE</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The actual is an alternate array, the alias is to the first element of the array.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/AliasOptions.html#PROP_ARRAY_ORDERED">PROP_ARRAY_ORDERED</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The actual is an ordered array, the alias is to the first element of the array.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/AliasOptions.html#PROP_DIRECT">PROP_DIRECT</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;This is a direct mapping.</TD>
+</TR>
+</TABLE>
+&nbsp;
+<!-- ======== CONSTRUCTOR SUMMARY ======== -->
+
+<A NAME="constructor_summary"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+<B>Constructor Summary</B></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/AliasOptions.html#AliasOptions()">AliasOptions</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/AliasOptions.html#AliasOptions(int)">AliasOptions</A></B>(int&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<!-- ========== METHOD SUMMARY =========== -->
+
+<A NAME="method_summary"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+<B>Method Summary</B></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/AliasOptions.html#isArray()">isArray</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/AliasOptions.html#isArrayAlternate()">isArrayAlternate</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/AliasOptions.html#isArrayAltText()">isArrayAltText</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/AliasOptions.html#isArrayOrdered()">isArrayOrdered</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/AliasOptions.html#isSimple()">isSimple</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options">AliasOptions</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/AliasOptions.html#setArray(boolean)">setArray</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options">AliasOptions</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/AliasOptions.html#setArrayAlternate(boolean)">setArrayAlternate</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options">AliasOptions</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/AliasOptions.html#setArrayAltText(boolean)">setArrayAltText</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options">AliasOptions</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/AliasOptions.html#setArrayOrdered(boolean)">setArrayOrdered</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/AliasOptions.html#toPropertyOptions()">toPropertyOptions</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;<A NAME="methods_inherited_from_class_com.adobe.xmp.options.Options"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#EEEEFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="left"><B>Methods inherited from class com.adobe.xmp.options.<A HREF="../../../../com/adobe/xmp/options/Options.html" title="class in com.adobe.xmp.options">Options</A></B></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE><A HREF="../../../../com/adobe/xmp/options/Options.html#clear()">clear</A>, <A HREF="../../../../com/adobe/xmp/options/Options.html#containsAllOptions(int)">containsAllOptions</A>, <A HREF="../../../../com/adobe/xmp/options/Options.html#containsOneOf(int)">containsOneOf</A>, <A HREF="../../../../com/adobe/xmp/options/Options.html#equals(java.lang.Object)">equals</A>, <A HREF="../../../../com/adobe/xmp/options/Options.html#getOptions()">getOptions</A>, <A HREF="../../../../com/adobe/xmp/options/Options.html#getOptionsString()">getOptionsString</A>, <A HREF="../../../../com/adobe/xmp/options/Options.html#hashCode()">hashCode</A>, <A HREF="../../../../com/adobe/xmp/options/Options.html#isExactly(int)">isExactly</A>, <A HREF="../../../../com/adobe/xmp/options/Options.html#setOption(int, boolean)">setOption</A>, <A HREF="../../../../com/adobe/xmp/options/Options.html#setOptions(int)">setOptions</A>, <A HREF="../../../../com/adobe/xmp/options/Options.html#toString()">toString</A></CODE></TD>
+</TR>
+</TABLE>
+&nbsp;<A NAME="methods_inherited_from_class_java.lang.Object"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#EEEEFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="left"><B>Methods inherited from class java.lang.Object</B></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE>getClass, notify, notifyAll, wait, wait, wait</CODE></TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<!-- ============ FIELD DETAIL =========== -->
+
+<A NAME="field_detail"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="1"><FONT SIZE="+2">
+<B>Field Detail</B></FONT></TH>
+</TR>
+</TABLE>
+
+<A NAME="PROP_DIRECT"><!-- --></A><H3>
+PROP_DIRECT</H3>
+<PRE>
+public static final int <B>PROP_DIRECT</B></PRE>
+<DL>
+<DD>This is a direct mapping. The actual data type does not matter.
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../../constant-values.html#com.adobe.xmp.options.AliasOptions.PROP_DIRECT">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="PROP_ARRAY"><!-- --></A><H3>
+PROP_ARRAY</H3>
+<PRE>
+public static final int <B>PROP_ARRAY</B></PRE>
+<DL>
+<DD>The actual is an unordered array, the alias is to the first element of the array.
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../../constant-values.html#com.adobe.xmp.options.AliasOptions.PROP_ARRAY">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="PROP_ARRAY_ORDERED"><!-- --></A><H3>
+PROP_ARRAY_ORDERED</H3>
+<PRE>
+public static final int <B>PROP_ARRAY_ORDERED</B></PRE>
+<DL>
+<DD>The actual is an ordered array, the alias is to the first element of the array.
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../../constant-values.html#com.adobe.xmp.options.AliasOptions.PROP_ARRAY_ORDERED">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="PROP_ARRAY_ALTERNATE"><!-- --></A><H3>
+PROP_ARRAY_ALTERNATE</H3>
+<PRE>
+public static final int <B>PROP_ARRAY_ALTERNATE</B></PRE>
+<DL>
+<DD>The actual is an alternate array, the alias is to the first element of the array.
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../../constant-values.html#com.adobe.xmp.options.AliasOptions.PROP_ARRAY_ALTERNATE">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="PROP_ARRAY_ALT_TEXT"><!-- --></A><H3>
+PROP_ARRAY_ALT_TEXT</H3>
+<PRE>
+public static final int <B>PROP_ARRAY_ALT_TEXT</B></PRE>
+<DL>
+<DD>The actual is an alternate text array, the alias is to the 'x-default' element of the array.
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../../constant-values.html#com.adobe.xmp.options.AliasOptions.PROP_ARRAY_ALT_TEXT">Constant Field Values</A></DL>
+</DL>
+
+<!-- ========= CONSTRUCTOR DETAIL ======== -->
+
+<A NAME="constructor_detail"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="1"><FONT SIZE="+2">
+<B>Constructor Detail</B></FONT></TH>
+</TR>
+</TABLE>
+
+<A NAME="AliasOptions()"><!-- --></A><H3>
+AliasOptions</H3>
+<PRE>
+public <B>AliasOptions</B>()</PRE>
+<DL>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../../com/adobe/xmp/options/Options.html#Options()"><CODE>Options.Options()</CODE></A></DL>
+</DL>
+<HR>
+
+<A NAME="AliasOptions(int)"><!-- --></A><H3>
+AliasOptions</H3>
+<PRE>
+public <B>AliasOptions</B>(int&nbsp;options)
+ throws <A HREF="../../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DL>
+<DT><B>Parameters:</B><DD><CODE>options</CODE> - the options to init with
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - If options are not consistant</DL>
+</DL>
+
+<!-- ============ METHOD DETAIL ========== -->
+
+<A NAME="method_detail"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="1"><FONT SIZE="+2">
+<B>Method Detail</B></FONT></TH>
+</TR>
+</TABLE>
+
+<A NAME="isSimple()"><!-- --></A><H3>
+isSimple</H3>
+<PRE>
+public boolean <B>isSimple</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns if the alias is of the simple form.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="isArray()"><!-- --></A><H3>
+isArray</H3>
+<PRE>
+public boolean <B>isArray</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns the option.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setArray(boolean)"><!-- --></A><H3>
+setArray</H3>
+<PRE>
+public <A HREF="../../../../com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options">AliasOptions</A> <B>setArray</B>(boolean&nbsp;value)</PRE>
+<DL>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>value</CODE> - the value to set
+<DT><B>Returns:</B><DD>Returns the instance to call more set-methods.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="isArrayOrdered()"><!-- --></A><H3>
+isArrayOrdered</H3>
+<PRE>
+public boolean <B>isArrayOrdered</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns the option.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setArrayOrdered(boolean)"><!-- --></A><H3>
+setArrayOrdered</H3>
+<PRE>
+public <A HREF="../../../../com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options">AliasOptions</A> <B>setArrayOrdered</B>(boolean&nbsp;value)</PRE>
+<DL>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>value</CODE> - the value to set
+<DT><B>Returns:</B><DD>Returns the instance to call more set-methods.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="isArrayAlternate()"><!-- --></A><H3>
+isArrayAlternate</H3>
+<PRE>
+public boolean <B>isArrayAlternate</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns the option.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setArrayAlternate(boolean)"><!-- --></A><H3>
+setArrayAlternate</H3>
+<PRE>
+public <A HREF="../../../../com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options">AliasOptions</A> <B>setArrayAlternate</B>(boolean&nbsp;value)</PRE>
+<DL>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>value</CODE> - the value to set
+<DT><B>Returns:</B><DD>Returns the instance to call more set-methods.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="isArrayAltText()"><!-- --></A><H3>
+isArrayAltText</H3>
+<PRE>
+public boolean <B>isArrayAltText</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns the option.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setArrayAltText(boolean)"><!-- --></A><H3>
+setArrayAltText</H3>
+<PRE>
+public <A HREF="../../../../com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options">AliasOptions</A> <B>setArrayAltText</B>(boolean&nbsp;value)</PRE>
+<DL>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>value</CODE> - the value to set
+<DT><B>Returns:</B><DD>Returns the instance to call more set-methods.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="toPropertyOptions()"><!-- --></A><H3>
+toPropertyOptions</H3>
+<PRE>
+public <A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A> <B>toPropertyOptions</B>()
+ throws <A HREF="../../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>returns a <A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options"><CODE>PropertyOptions</CODE></A>s object
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - If the options are not consistant.</DL>
+</DD>
+</DL>
+<!-- ========= END OF CLASS DATA ========= -->
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="class-use/AliasOptions.html"><FONT CLASS="NavBarFont1"><B>Use</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV CLASS&nbsp;
+&nbsp;<A HREF="../../../../com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../index.html?com/adobe/xmp/options/AliasOptions.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="AliasOptions.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+ SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;<A HREF="#field_summary">FIELD</A>&nbsp;|&nbsp;<A HREF="#constructor_summary">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;<A HREF="#field_detail">FIELD</A>&nbsp;|&nbsp;<A HREF="#constructor_detail">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/com/adobe/xmp/options/IteratorOptions.html b/java/XMPCore/docs/com/adobe/xmp/options/IteratorOptions.html
new file mode 100644
index 0000000..50d8bef
--- /dev/null
+++ b/java/XMPCore/docs/com/adobe/xmp/options/IteratorOptions.html
@@ -0,0 +1,534 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:50 CEST 2007 -->
+<TITLE>
+IteratorOptions
+</TITLE>
+
+<META NAME="keywords" CONTENT="com.adobe.xmp.options.IteratorOptions class">
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="IteratorOptions";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="class-use/IteratorOptions.html"><FONT CLASS="NavBarFont1"><B>Use</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="../../../../com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;<A HREF="../../../../com/adobe/xmp/options/Options.html" title="class in com.adobe.xmp.options"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../index.html?com/adobe/xmp/options/IteratorOptions.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="IteratorOptions.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+ SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;<A HREF="#field_summary">FIELD</A>&nbsp;|&nbsp;<A HREF="#constructor_summary">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;<A HREF="#field_detail">FIELD</A>&nbsp;|&nbsp;<A HREF="#constructor_detail">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<!-- ======== START OF CLASS DATA ======== -->
+<H2>
+<FONT SIZE="-1">
+com.adobe.xmp.options</FONT>
+<BR>
+Class IteratorOptions</H2>
+<PRE>
+java.lang.Object
+ <IMG SRC="../../../../resources/inherit.gif" ALT="extended by "><A HREF="../../../../com/adobe/xmp/options/Options.html" title="class in com.adobe.xmp.options">com.adobe.xmp.options.Options</A>
+ <IMG SRC="../../../../resources/inherit.gif" ALT="extended by "><B>com.adobe.xmp.options.IteratorOptions</B>
+</PRE>
+<HR>
+<DL>
+<DT><PRE>public final class <B>IteratorOptions</B><DT>extends <A HREF="../../../../com/adobe/xmp/options/Options.html" title="class in com.adobe.xmp.options">Options</A></DL>
+</PRE>
+
+<P>
+Options for <code>XMPIterator</code> construction.
+<P>
+
+<P>
+<DL>
+<DT><B>Since:</B></DT>
+ <DD>24.01.2006</DD>
+</DL>
+<HR>
+
+<P>
+<!-- =========== FIELD SUMMARY =========== -->
+
+<A NAME="field_summary"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+<B>Field Summary</B></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/IteratorOptions.html#INCLUDE_ALIASES">INCLUDE_ALIASES</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<B>Deprecated.</B>&nbsp;<I>it is commonly preferred to work with the base properties</I></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/IteratorOptions.html#JUST_CHILDREN">JUST_CHILDREN</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Just do the immediate children of the root, default is subtree.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/IteratorOptions.html#JUST_LEAFNAME">JUST_LEAFNAME</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Return just the leaf part of the path, default is the full path.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/IteratorOptions.html#JUST_LEAFNODES">JUST_LEAFNODES</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Just do the leaf nodes, default is all nodes in the subtree.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/IteratorOptions.html#OMIT_QUALIFIERS">OMIT_QUALIFIERS</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Omit all qualifiers.</TD>
+</TR>
+</TABLE>
+&nbsp;
+<!-- ======== CONSTRUCTOR SUMMARY ======== -->
+
+<A NAME="constructor_summary"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+<B>Constructor Summary</B></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/IteratorOptions.html#IteratorOptions()">IteratorOptions</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<!-- ========== METHOD SUMMARY =========== -->
+
+<A NAME="method_summary"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+<B>Method Summary</B></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/IteratorOptions.html#isJustChildren()">isJustChildren</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/IteratorOptions.html#isJustLeafname()">isJustLeafname</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/IteratorOptions.html#isJustLeafnodes()">isJustLeafnodes</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/IteratorOptions.html#isOmitQualifiers()">isOmitQualifiers</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options">IteratorOptions</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/IteratorOptions.html#setJustChildren(boolean)">setJustChildren</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sets the option and returns the instance.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options">IteratorOptions</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/IteratorOptions.html#setJustLeafname(boolean)">setJustLeafname</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sets the option and returns the instance.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options">IteratorOptions</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/IteratorOptions.html#setJustLeafnodes(boolean)">setJustLeafnodes</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sets the option and returns the instance.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options">IteratorOptions</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/IteratorOptions.html#setOmitQualifiers(boolean)">setOmitQualifiers</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sets the option and returns the instance.</TD>
+</TR>
+</TABLE>
+&nbsp;<A NAME="methods_inherited_from_class_com.adobe.xmp.options.Options"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#EEEEFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="left"><B>Methods inherited from class com.adobe.xmp.options.<A HREF="../../../../com/adobe/xmp/options/Options.html" title="class in com.adobe.xmp.options">Options</A></B></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE><A HREF="../../../../com/adobe/xmp/options/Options.html#clear()">clear</A>, <A HREF="../../../../com/adobe/xmp/options/Options.html#containsAllOptions(int)">containsAllOptions</A>, <A HREF="../../../../com/adobe/xmp/options/Options.html#containsOneOf(int)">containsOneOf</A>, <A HREF="../../../../com/adobe/xmp/options/Options.html#equals(java.lang.Object)">equals</A>, <A HREF="../../../../com/adobe/xmp/options/Options.html#getOptions()">getOptions</A>, <A HREF="../../../../com/adobe/xmp/options/Options.html#getOptionsString()">getOptionsString</A>, <A HREF="../../../../com/adobe/xmp/options/Options.html#hashCode()">hashCode</A>, <A HREF="../../../../com/adobe/xmp/options/Options.html#isExactly(int)">isExactly</A>, <A HREF="../../../../com/adobe/xmp/options/Options.html#setOption(int, boolean)">setOption</A>, <A HREF="../../../../com/adobe/xmp/options/Options.html#setOptions(int)">setOptions</A>, <A HREF="../../../../com/adobe/xmp/options/Options.html#toString()">toString</A></CODE></TD>
+</TR>
+</TABLE>
+&nbsp;<A NAME="methods_inherited_from_class_java.lang.Object"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#EEEEFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="left"><B>Methods inherited from class java.lang.Object</B></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE>getClass, notify, notifyAll, wait, wait, wait</CODE></TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<!-- ============ FIELD DETAIL =========== -->
+
+<A NAME="field_detail"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="1"><FONT SIZE="+2">
+<B>Field Detail</B></FONT></TH>
+</TR>
+</TABLE>
+
+<A NAME="JUST_CHILDREN"><!-- --></A><H3>
+JUST_CHILDREN</H3>
+<PRE>
+public static final int <B>JUST_CHILDREN</B></PRE>
+<DL>
+<DD>Just do the immediate children of the root, default is subtree.
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../../constant-values.html#com.adobe.xmp.options.IteratorOptions.JUST_CHILDREN">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="JUST_LEAFNODES"><!-- --></A><H3>
+JUST_LEAFNODES</H3>
+<PRE>
+public static final int <B>JUST_LEAFNODES</B></PRE>
+<DL>
+<DD>Just do the leaf nodes, default is all nodes in the subtree.
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../../constant-values.html#com.adobe.xmp.options.IteratorOptions.JUST_LEAFNODES">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="JUST_LEAFNAME"><!-- --></A><H3>
+JUST_LEAFNAME</H3>
+<PRE>
+public static final int <B>JUST_LEAFNAME</B></PRE>
+<DL>
+<DD>Return just the leaf part of the path, default is the full path.
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../../constant-values.html#com.adobe.xmp.options.IteratorOptions.JUST_LEAFNAME">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="INCLUDE_ALIASES"><!-- --></A><H3>
+INCLUDE_ALIASES</H3>
+<PRE>
+public static final int <B>INCLUDE_ALIASES</B></PRE>
+<DL>
+<DD><B>Deprecated.</B>&nbsp;<I>it is commonly preferred to work with the base properties</I><DD>Include aliases, default is just actual properties. <em>Note:</em> Not supported.
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../../constant-values.html#com.adobe.xmp.options.IteratorOptions.INCLUDE_ALIASES">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="OMIT_QUALIFIERS"><!-- --></A><H3>
+OMIT_QUALIFIERS</H3>
+<PRE>
+public static final int <B>OMIT_QUALIFIERS</B></PRE>
+<DL>
+<DD>Omit all qualifiers.
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../../constant-values.html#com.adobe.xmp.options.IteratorOptions.OMIT_QUALIFIERS">Constant Field Values</A></DL>
+</DL>
+
+<!-- ========= CONSTRUCTOR DETAIL ======== -->
+
+<A NAME="constructor_detail"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="1"><FONT SIZE="+2">
+<B>Constructor Detail</B></FONT></TH>
+</TR>
+</TABLE>
+
+<A NAME="IteratorOptions()"><!-- --></A><H3>
+IteratorOptions</H3>
+<PRE>
+public <B>IteratorOptions</B>()</PRE>
+<DL>
+</DL>
+
+<!-- ============ METHOD DETAIL ========== -->
+
+<A NAME="method_detail"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="1"><FONT SIZE="+2">
+<B>Method Detail</B></FONT></TH>
+</TR>
+</TABLE>
+
+<A NAME="isJustChildren()"><!-- --></A><H3>
+isJustChildren</H3>
+<PRE>
+public boolean <B>isJustChildren</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns whether the option is set.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="isJustLeafname()"><!-- --></A><H3>
+isJustLeafname</H3>
+<PRE>
+public boolean <B>isJustLeafname</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns whether the option is set.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="isJustLeafnodes()"><!-- --></A><H3>
+isJustLeafnodes</H3>
+<PRE>
+public boolean <B>isJustLeafnodes</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns whether the option is set.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="isOmitQualifiers()"><!-- --></A><H3>
+isOmitQualifiers</H3>
+<PRE>
+public boolean <B>isOmitQualifiers</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns whether the option is set.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setJustChildren(boolean)"><!-- --></A><H3>
+setJustChildren</H3>
+<PRE>
+public <A HREF="../../../../com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options">IteratorOptions</A> <B>setJustChildren</B>(boolean&nbsp;value)</PRE>
+<DL>
+<DD>Sets the option and returns the instance.
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>value</CODE> - the value to set
+<DT><B>Returns:</B><DD>Returns the instance to call more set-methods.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setJustLeafname(boolean)"><!-- --></A><H3>
+setJustLeafname</H3>
+<PRE>
+public <A HREF="../../../../com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options">IteratorOptions</A> <B>setJustLeafname</B>(boolean&nbsp;value)</PRE>
+<DL>
+<DD>Sets the option and returns the instance.
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>value</CODE> - the value to set
+<DT><B>Returns:</B><DD>Returns the instance to call more set-methods.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setJustLeafnodes(boolean)"><!-- --></A><H3>
+setJustLeafnodes</H3>
+<PRE>
+public <A HREF="../../../../com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options">IteratorOptions</A> <B>setJustLeafnodes</B>(boolean&nbsp;value)</PRE>
+<DL>
+<DD>Sets the option and returns the instance.
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>value</CODE> - the value to set
+<DT><B>Returns:</B><DD>Returns the instance to call more set-methods.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setOmitQualifiers(boolean)"><!-- --></A><H3>
+setOmitQualifiers</H3>
+<PRE>
+public <A HREF="../../../../com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options">IteratorOptions</A> <B>setOmitQualifiers</B>(boolean&nbsp;value)</PRE>
+<DL>
+<DD>Sets the option and returns the instance.
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>value</CODE> - the value to set
+<DT><B>Returns:</B><DD>Returns the instance to call more set-methods.</DL>
+</DD>
+</DL>
+<!-- ========= END OF CLASS DATA ========= -->
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="class-use/IteratorOptions.html"><FONT CLASS="NavBarFont1"><B>Use</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="../../../../com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;<A HREF="../../../../com/adobe/xmp/options/Options.html" title="class in com.adobe.xmp.options"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../index.html?com/adobe/xmp/options/IteratorOptions.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="IteratorOptions.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+ SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;<A HREF="#field_summary">FIELD</A>&nbsp;|&nbsp;<A HREF="#constructor_summary">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;<A HREF="#field_detail">FIELD</A>&nbsp;|&nbsp;<A HREF="#constructor_detail">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/com/adobe/xmp/options/Options.html b/java/XMPCore/docs/com/adobe/xmp/options/Options.html
new file mode 100644
index 0000000..ea766eb
--- /dev/null
+++ b/java/XMPCore/docs/com/adobe/xmp/options/Options.html
@@ -0,0 +1,502 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:50 CEST 2007 -->
+<TITLE>
+Options
+</TITLE>
+
+<META NAME="keywords" CONTENT="com.adobe.xmp.options.Options class">
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="Options";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="class-use/Options.html"><FONT CLASS="NavBarFont1"><B>Use</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="../../../../com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;<A HREF="../../../../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../index.html?com/adobe/xmp/options/Options.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="Options.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+ SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;FIELD&nbsp;|&nbsp;<A HREF="#constructor_summary">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;FIELD&nbsp;|&nbsp;<A HREF="#constructor_detail">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<!-- ======== START OF CLASS DATA ======== -->
+<H2>
+<FONT SIZE="-1">
+com.adobe.xmp.options</FONT>
+<BR>
+Class Options</H2>
+<PRE>
+java.lang.Object
+ <IMG SRC="../../../../resources/inherit.gif" ALT="extended by "><B>com.adobe.xmp.options.Options</B>
+</PRE>
+<DL>
+<DT><B>Direct Known Subclasses:</B> <DD><A HREF="../../../../com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options">AliasOptions</A>, <A HREF="../../../../com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options">IteratorOptions</A>, <A HREF="../../../../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options">ParseOptions</A>, <A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>, <A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A></DD>
+</DL>
+<HR>
+<DL>
+<DT><PRE>public abstract class <B>Options</B><DT>extends java.lang.Object</DL>
+</PRE>
+
+<P>
+The base class for a collection of 32 flag bits. Individual flags are defined as enum value bit
+ masks. Inheriting classes add convenience accessor methods.
+<P>
+
+<P>
+<DL>
+<DT><B>Since:</B></DT>
+ <DD>24.01.2006</DD>
+</DL>
+<HR>
+
+<P>
+
+<!-- ======== CONSTRUCTOR SUMMARY ======== -->
+
+<A NAME="constructor_summary"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+<B>Constructor Summary</B></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/Options.html#Options()">Options</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The default constructor.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/Options.html#Options(int)">Options</A></B>(int&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Constructor with the options bit mask.</TD>
+</TR>
+</TABLE>
+&nbsp;
+<!-- ========== METHOD SUMMARY =========== -->
+
+<A NAME="method_summary"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+<B>Method Summary</B></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/Options.html#clear()">clear</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Resets the options.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/Options.html#containsAllOptions(int)">containsAllOptions</A></B>(int&nbsp;optionBits)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/Options.html#containsOneOf(int)">containsOneOf</A></B>(int&nbsp;optionBits)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/Options.html#equals(java.lang.Object)">equals</A></B>(java.lang.Object&nbsp;obj)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/Options.html#getOptions()">getOptions</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Is friendly to access it during the tests.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/Options.html#getOptionsString()">getOptionsString</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Creates a human readable string from the set options.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/Options.html#hashCode()">hashCode</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/Options.html#isExactly(int)">isExactly</A></B>(int&nbsp;optionBits)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/Options.html#setOption(int, boolean)">setOption</A></B>(int&nbsp;optionBits,
+ boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/Options.html#setOptions(int)">setOptions</A></B>(int&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/Options.html#toString()">toString</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;<A NAME="methods_inherited_from_class_java.lang.Object"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#EEEEFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="left"><B>Methods inherited from class java.lang.Object</B></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE>getClass, notify, notifyAll, wait, wait, wait</CODE></TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<!-- ========= CONSTRUCTOR DETAIL ======== -->
+
+<A NAME="constructor_detail"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="1"><FONT SIZE="+2">
+<B>Constructor Detail</B></FONT></TH>
+</TR>
+</TABLE>
+
+<A NAME="Options()"><!-- --></A><H3>
+Options</H3>
+<PRE>
+public <B>Options</B>()</PRE>
+<DL>
+<DD>The default constructor.
+<P>
+</DL>
+<HR>
+
+<A NAME="Options(int)"><!-- --></A><H3>
+Options</H3>
+<PRE>
+public <B>Options</B>(int&nbsp;options)
+ throws <A HREF="../../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Constructor with the options bit mask.
+<P>
+<DL>
+<DT><B>Parameters:</B><DD><CODE>options</CODE> - the options bit mask
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - If the options are not correct</DL>
+</DL>
+
+<!-- ============ METHOD DETAIL ========== -->
+
+<A NAME="method_detail"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="1"><FONT SIZE="+2">
+<B>Method Detail</B></FONT></TH>
+</TR>
+</TABLE>
+
+<A NAME="clear()"><!-- --></A><H3>
+clear</H3>
+<PRE>
+public void <B>clear</B>()</PRE>
+<DL>
+<DD>Resets the options.
+<P>
+<DD><DL>
+</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="isExactly(int)"><!-- --></A><H3>
+isExactly</H3>
+<PRE>
+public boolean <B>isExactly</B>(int&nbsp;optionBits)</PRE>
+<DL>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>optionBits</CODE> - an option bitmask
+<DT><B>Returns:</B><DD>Returns true, if this object is equal to the given options.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="containsAllOptions(int)"><!-- --></A><H3>
+containsAllOptions</H3>
+<PRE>
+public boolean <B>containsAllOptions</B>(int&nbsp;optionBits)</PRE>
+<DL>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>optionBits</CODE> - an option bitmask
+<DT><B>Returns:</B><DD>Returns true, if this object contains all given options.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="containsOneOf(int)"><!-- --></A><H3>
+containsOneOf</H3>
+<PRE>
+public boolean <B>containsOneOf</B>(int&nbsp;optionBits)</PRE>
+<DL>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>optionBits</CODE> - an option bitmask
+<DT><B>Returns:</B><DD>Returns true, if this object contain at least one of the given options.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setOption(int, boolean)"><!-- --></A><H3>
+setOption</H3>
+<PRE>
+public void <B>setOption</B>(int&nbsp;optionBits,
+ boolean&nbsp;value)</PRE>
+<DL>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>optionBits</CODE> - the binary bit or bits that shall be set to the given value<DD><CODE>value</CODE> - the boolean value to set</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getOptions()"><!-- --></A><H3>
+getOptions</H3>
+<PRE>
+public int <B>getOptions</B>()</PRE>
+<DL>
+<DD>Is friendly to access it during the tests.
+<P>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns the options.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setOptions(int)"><!-- --></A><H3>
+setOptions</H3>
+<PRE>
+public void <B>setOptions</B>(int&nbsp;options)
+ throws <A HREF="../../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>options</CODE> - The options to set.
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE></DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="equals(java.lang.Object)"><!-- --></A><H3>
+equals</H3>
+<PRE>
+public boolean <B>equals</B>(java.lang.Object&nbsp;obj)</PRE>
+<DL>
+<DD><DL>
+<DT><B>Overrides:</B><DD><CODE>equals</CODE> in class <CODE>java.lang.Object</CODE></DL>
+</DD>
+<DD><DL>
+<DT><B>See Also:</B><DD><CODE>Object.equals(Object)</CODE></DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="hashCode()"><!-- --></A><H3>
+hashCode</H3>
+<PRE>
+public int <B>hashCode</B>()</PRE>
+<DL>
+<DD><DL>
+<DT><B>Overrides:</B><DD><CODE>hashCode</CODE> in class <CODE>java.lang.Object</CODE></DL>
+</DD>
+<DD><DL>
+<DT><B>See Also:</B><DD><CODE>Object.hashCode()</CODE></DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getOptionsString()"><!-- --></A><H3>
+getOptionsString</H3>
+<PRE>
+public java.lang.String <B>getOptionsString</B>()</PRE>
+<DL>
+<DD>Creates a human readable string from the set options. <em>Note:</em> This method is quite
+ expensive and should only be used within tests or as
+<P>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns a String listing all options that are set to <code>true</code> by their name,
+ like &quot;option1 | option4&quot;.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="toString()"><!-- --></A><H3>
+toString</H3>
+<PRE>
+public java.lang.String <B>toString</B>()</PRE>
+<DL>
+<DD><DL>
+<DT><B>Overrides:</B><DD><CODE>toString</CODE> in class <CODE>java.lang.Object</CODE></DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns the options as hex bitmask.</DL>
+</DD>
+</DL>
+<!-- ========= END OF CLASS DATA ========= -->
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="class-use/Options.html"><FONT CLASS="NavBarFont1"><B>Use</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="../../../../com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;<A HREF="../../../../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../index.html?com/adobe/xmp/options/Options.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="Options.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+ SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;FIELD&nbsp;|&nbsp;<A HREF="#constructor_summary">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;FIELD&nbsp;|&nbsp;<A HREF="#constructor_detail">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/com/adobe/xmp/options/ParseOptions.html b/java/XMPCore/docs/com/adobe/xmp/options/ParseOptions.html
new file mode 100644
index 0000000..62e59bb
--- /dev/null
+++ b/java/XMPCore/docs/com/adobe/xmp/options/ParseOptions.html
@@ -0,0 +1,508 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:50 CEST 2007 -->
+<TITLE>
+ParseOptions
+</TITLE>
+
+<META NAME="keywords" CONTENT="com.adobe.xmp.options.ParseOptions class">
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="ParseOptions";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="class-use/ParseOptions.html"><FONT CLASS="NavBarFont1"><B>Use</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="../../../../com/adobe/xmp/options/Options.html" title="class in com.adobe.xmp.options"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;<A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../index.html?com/adobe/xmp/options/ParseOptions.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="ParseOptions.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+ SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;<A HREF="#field_summary">FIELD</A>&nbsp;|&nbsp;<A HREF="#constructor_summary">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;<A HREF="#field_detail">FIELD</A>&nbsp;|&nbsp;<A HREF="#constructor_detail">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<!-- ======== START OF CLASS DATA ======== -->
+<H2>
+<FONT SIZE="-1">
+com.adobe.xmp.options</FONT>
+<BR>
+Class ParseOptions</H2>
+<PRE>
+java.lang.Object
+ <IMG SRC="../../../../resources/inherit.gif" ALT="extended by "><A HREF="../../../../com/adobe/xmp/options/Options.html" title="class in com.adobe.xmp.options">com.adobe.xmp.options.Options</A>
+ <IMG SRC="../../../../resources/inherit.gif" ALT="extended by "><B>com.adobe.xmp.options.ParseOptions</B>
+</PRE>
+<HR>
+<DL>
+<DT><PRE>public final class <B>ParseOptions</B><DT>extends <A HREF="../../../../com/adobe/xmp/options/Options.html" title="class in com.adobe.xmp.options">Options</A></DL>
+</PRE>
+
+<P>
+Options for <A HREF="../../../../com/adobe/xmp/XMPMetaFactory.html#parse(java.io.InputStream, com.adobe.xmp.options.ParseOptions)"><CODE>XMPMetaFactory.parse(InputStream, ParseOptions)</CODE></A>.
+<P>
+
+<P>
+<DL>
+<DT><B>Since:</B></DT>
+ <DD>24.01.2006</DD>
+</DL>
+<HR>
+
+<P>
+<!-- =========== FIELD SUMMARY =========== -->
+
+<A NAME="field_summary"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+<B>Field Summary</B></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/ParseOptions.html#ACCEPT_LATIN_1">ACCEPT_LATIN_1</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;If the input is not unicode, try to parse it as ISO-8859-1.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/ParseOptions.html#FIX_CONTROL_CHARS">FIX_CONTROL_CHARS</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convert ASCII control characters 0x01 - 0x1F (except tab, cr, and lf) to spaces.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/ParseOptions.html#REQUIRE_XMP_META">REQUIRE_XMP_META</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Require a surrounding &quot;x:xmpmeta&quot; element in the xml-document.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/ParseOptions.html#STRICT_ALIASING">STRICT_ALIASING</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Do not reconcile alias differences, throw an exception instead.</TD>
+</TR>
+</TABLE>
+&nbsp;
+<!-- ======== CONSTRUCTOR SUMMARY ======== -->
+
+<A NAME="constructor_summary"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+<B>Constructor Summary</B></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/ParseOptions.html#ParseOptions()">ParseOptions</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sets the options to the default values.</TD>
+</TR>
+</TABLE>
+&nbsp;
+<!-- ========== METHOD SUMMARY =========== -->
+
+<A NAME="method_summary"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+<B>Method Summary</B></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/ParseOptions.html#getAcceptLatin1()">getAcceptLatin1</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/ParseOptions.html#getFixControlChars()">getFixControlChars</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/ParseOptions.html#getRequireXMPMeta()">getRequireXMPMeta</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/ParseOptions.html#getStrictAliasing()">getStrictAliasing</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options">ParseOptions</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/ParseOptions.html#setAcceptLatin1(boolean)">setAcceptLatin1</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options">ParseOptions</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/ParseOptions.html#setFixControlChars(boolean)">setFixControlChars</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options">ParseOptions</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/ParseOptions.html#setRequireXMPMeta(boolean)">setRequireXMPMeta</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options">ParseOptions</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/ParseOptions.html#setStrictAliasing(boolean)">setStrictAliasing</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;<A NAME="methods_inherited_from_class_com.adobe.xmp.options.Options"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#EEEEFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="left"><B>Methods inherited from class com.adobe.xmp.options.<A HREF="../../../../com/adobe/xmp/options/Options.html" title="class in com.adobe.xmp.options">Options</A></B></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE><A HREF="../../../../com/adobe/xmp/options/Options.html#clear()">clear</A>, <A HREF="../../../../com/adobe/xmp/options/Options.html#containsAllOptions(int)">containsAllOptions</A>, <A HREF="../../../../com/adobe/xmp/options/Options.html#containsOneOf(int)">containsOneOf</A>, <A HREF="../../../../com/adobe/xmp/options/Options.html#equals(java.lang.Object)">equals</A>, <A HREF="../../../../com/adobe/xmp/options/Options.html#getOptions()">getOptions</A>, <A HREF="../../../../com/adobe/xmp/options/Options.html#getOptionsString()">getOptionsString</A>, <A HREF="../../../../com/adobe/xmp/options/Options.html#hashCode()">hashCode</A>, <A HREF="../../../../com/adobe/xmp/options/Options.html#isExactly(int)">isExactly</A>, <A HREF="../../../../com/adobe/xmp/options/Options.html#setOption(int, boolean)">setOption</A>, <A HREF="../../../../com/adobe/xmp/options/Options.html#setOptions(int)">setOptions</A>, <A HREF="../../../../com/adobe/xmp/options/Options.html#toString()">toString</A></CODE></TD>
+</TR>
+</TABLE>
+&nbsp;<A NAME="methods_inherited_from_class_java.lang.Object"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#EEEEFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="left"><B>Methods inherited from class java.lang.Object</B></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE>getClass, notify, notifyAll, wait, wait, wait</CODE></TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<!-- ============ FIELD DETAIL =========== -->
+
+<A NAME="field_detail"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="1"><FONT SIZE="+2">
+<B>Field Detail</B></FONT></TH>
+</TR>
+</TABLE>
+
+<A NAME="REQUIRE_XMP_META"><!-- --></A><H3>
+REQUIRE_XMP_META</H3>
+<PRE>
+public static final int <B>REQUIRE_XMP_META</B></PRE>
+<DL>
+<DD>Require a surrounding &quot;x:xmpmeta&quot; element in the xml-document.
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../../constant-values.html#com.adobe.xmp.options.ParseOptions.REQUIRE_XMP_META">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="STRICT_ALIASING"><!-- --></A><H3>
+STRICT_ALIASING</H3>
+<PRE>
+public static final int <B>STRICT_ALIASING</B></PRE>
+<DL>
+<DD>Do not reconcile alias differences, throw an exception instead.
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../../constant-values.html#com.adobe.xmp.options.ParseOptions.STRICT_ALIASING">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="FIX_CONTROL_CHARS"><!-- --></A><H3>
+FIX_CONTROL_CHARS</H3>
+<PRE>
+public static final int <B>FIX_CONTROL_CHARS</B></PRE>
+<DL>
+<DD>Convert ASCII control characters 0x01 - 0x1F (except tab, cr, and lf) to spaces.
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../../constant-values.html#com.adobe.xmp.options.ParseOptions.FIX_CONTROL_CHARS">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="ACCEPT_LATIN_1"><!-- --></A><H3>
+ACCEPT_LATIN_1</H3>
+<PRE>
+public static final int <B>ACCEPT_LATIN_1</B></PRE>
+<DL>
+<DD>If the input is not unicode, try to parse it as ISO-8859-1.
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../../constant-values.html#com.adobe.xmp.options.ParseOptions.ACCEPT_LATIN_1">Constant Field Values</A></DL>
+</DL>
+
+<!-- ========= CONSTRUCTOR DETAIL ======== -->
+
+<A NAME="constructor_detail"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="1"><FONT SIZE="+2">
+<B>Constructor Detail</B></FONT></TH>
+</TR>
+</TABLE>
+
+<A NAME="ParseOptions()"><!-- --></A><H3>
+ParseOptions</H3>
+<PRE>
+public <B>ParseOptions</B>()</PRE>
+<DL>
+<DD>Sets the options to the default values.
+<P>
+</DL>
+
+<!-- ============ METHOD DETAIL ========== -->
+
+<A NAME="method_detail"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="1"><FONT SIZE="+2">
+<B>Method Detail</B></FONT></TH>
+</TR>
+</TABLE>
+
+<A NAME="getRequireXMPMeta()"><!-- --></A><H3>
+getRequireXMPMeta</H3>
+<PRE>
+public boolean <B>getRequireXMPMeta</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns the requireXMPMeta.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setRequireXMPMeta(boolean)"><!-- --></A><H3>
+setRequireXMPMeta</H3>
+<PRE>
+public <A HREF="../../../../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options">ParseOptions</A> <B>setRequireXMPMeta</B>(boolean&nbsp;value)</PRE>
+<DL>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>value</CODE> - the value to set
+<DT><B>Returns:</B><DD>Returns the instance to call more set-methods.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getStrictAliasing()"><!-- --></A><H3>
+getStrictAliasing</H3>
+<PRE>
+public boolean <B>getStrictAliasing</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns the strictAliasing.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setStrictAliasing(boolean)"><!-- --></A><H3>
+setStrictAliasing</H3>
+<PRE>
+public <A HREF="../../../../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options">ParseOptions</A> <B>setStrictAliasing</B>(boolean&nbsp;value)</PRE>
+<DL>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>value</CODE> - the value to set
+<DT><B>Returns:</B><DD>Returns the instance to call more set-methods.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getFixControlChars()"><!-- --></A><H3>
+getFixControlChars</H3>
+<PRE>
+public boolean <B>getFixControlChars</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns the strictAliasing.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setFixControlChars(boolean)"><!-- --></A><H3>
+setFixControlChars</H3>
+<PRE>
+public <A HREF="../../../../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options">ParseOptions</A> <B>setFixControlChars</B>(boolean&nbsp;value)</PRE>
+<DL>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>value</CODE> - the value to set
+<DT><B>Returns:</B><DD>Returns the instance to call more set-methods.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getAcceptLatin1()"><!-- --></A><H3>
+getAcceptLatin1</H3>
+<PRE>
+public boolean <B>getAcceptLatin1</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns the strictAliasing.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setAcceptLatin1(boolean)"><!-- --></A><H3>
+setAcceptLatin1</H3>
+<PRE>
+public <A HREF="../../../../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options">ParseOptions</A> <B>setAcceptLatin1</B>(boolean&nbsp;value)</PRE>
+<DL>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>value</CODE> - the value to set
+<DT><B>Returns:</B><DD>Returns the instance to call more set-methods.</DL>
+</DD>
+</DL>
+<!-- ========= END OF CLASS DATA ========= -->
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="class-use/ParseOptions.html"><FONT CLASS="NavBarFont1"><B>Use</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="../../../../com/adobe/xmp/options/Options.html" title="class in com.adobe.xmp.options"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;<A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../index.html?com/adobe/xmp/options/ParseOptions.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="ParseOptions.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+ SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;<A HREF="#field_summary">FIELD</A>&nbsp;|&nbsp;<A HREF="#constructor_summary">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;<A HREF="#field_detail">FIELD</A>&nbsp;|&nbsp;<A HREF="#constructor_detail">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/com/adobe/xmp/options/PropertyOptions.html b/java/XMPCore/docs/com/adobe/xmp/options/PropertyOptions.html
new file mode 100644
index 0000000..0f0e7e3
--- /dev/null
+++ b/java/XMPCore/docs/com/adobe/xmp/options/PropertyOptions.html
@@ -0,0 +1,1171 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:50 CEST 2007 -->
+<TITLE>
+PropertyOptions
+</TITLE>
+
+<META NAME="keywords" CONTENT="com.adobe.xmp.options.PropertyOptions class">
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="PropertyOptions";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="class-use/PropertyOptions.html"><FONT CLASS="NavBarFont1"><B>Use</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="../../../../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;<A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../index.html?com/adobe/xmp/options/PropertyOptions.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="PropertyOptions.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+ SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;<A HREF="#field_summary">FIELD</A>&nbsp;|&nbsp;<A HREF="#constructor_summary">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;<A HREF="#field_detail">FIELD</A>&nbsp;|&nbsp;<A HREF="#constructor_detail">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<!-- ======== START OF CLASS DATA ======== -->
+<H2>
+<FONT SIZE="-1">
+com.adobe.xmp.options</FONT>
+<BR>
+Class PropertyOptions</H2>
+<PRE>
+java.lang.Object
+ <IMG SRC="../../../../resources/inherit.gif" ALT="extended by "><A HREF="../../../../com/adobe/xmp/options/Options.html" title="class in com.adobe.xmp.options">com.adobe.xmp.options.Options</A>
+ <IMG SRC="../../../../resources/inherit.gif" ALT="extended by "><B>com.adobe.xmp.options.PropertyOptions</B>
+</PRE>
+<HR>
+<DL>
+<DT><PRE>public final class <B>PropertyOptions</B><DT>extends <A HREF="../../../../com/adobe/xmp/options/Options.html" title="class in com.adobe.xmp.options">Options</A></DL>
+</PRE>
+
+<P>
+The property flags are used when properties are fetched from the <code>XMPMeta</code>-object
+ and provide more detailed information about the property.
+<P>
+
+<P>
+<DL>
+<DT><B>Since:</B></DT>
+ <DD>03.07.2006</DD>
+</DL>
+<HR>
+
+<P>
+<!-- =========== FIELD SUMMARY =========== -->
+
+<A NAME="field_summary"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+<B>Field Summary</B></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html#ARRAY">ARRAY</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html#ARRAY_ALT_TEXT">ARRAY_ALT_TEXT</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html#ARRAY_ALTERNATE">ARRAY_ALTERNATE</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html#ARRAY_ORDERED">ARRAY_ORDERED</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html#COMPACT">COMPACT</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html#DELETE_EXISTING">DELETE_EXISTING</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;may be used in the future</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html#HAS_LANGUAGE">HAS_LANGUAGE</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html#HAS_QUALIFIERS">HAS_QUALIFIERS</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html#HAS_TYPE">HAS_TYPE</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html#NO_OPTIONS">NO_OPTIONS</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html#QUALIFIER">QUALIFIER</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html#SCHEMA_NODE">SCHEMA_NODE</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html#STRUCT">STRUCT</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html#URI">URI</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<!-- ======== CONSTRUCTOR SUMMARY ======== -->
+
+<A NAME="constructor_summary"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+<B>Constructor Summary</B></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html#PropertyOptions()">PropertyOptions</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Default constructor</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html#PropertyOptions(int)">PropertyOptions</A></B>(int&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Intialization constructor</TD>
+</TR>
+</TABLE>
+&nbsp;
+<!-- ========== METHOD SUMMARY =========== -->
+
+<A NAME="method_summary"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+<B>Method Summary</B></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html#assertConsistency(int)">assertConsistency</A></B>(int&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Checks that a node not a struct and array at the same time;
+ and URI cannot be a struct.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html#equalArrayTypes(com.adobe.xmp.options.PropertyOptions)">equalArrayTypes</A></B>(<A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Compares two options set for array compatibility.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html#getHasLanguage()">getHasLanguage</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html#getHasQualifiers()">getHasQualifiers</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html#getHasType()">getHasType</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html#isArray()">isArray</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html#isArrayAlternate()">isArrayAlternate</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html#isArrayAltText()">isArrayAltText</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html#isArrayOrdered()">isArrayOrdered</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html#isCompact()">isCompact</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html#isCompositeProperty()">isCompositeProperty</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html#isOnlyArrayOptions()">isOnlyArrayOptions</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html#isQualifier()">isQualifier</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html#isSchemaNode()">isSchemaNode</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html#isSimple()">isSimple</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html#isStruct()">isStruct</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html#isURI()">isURI</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html#mergeWith(com.adobe.xmp.options.PropertyOptions)">mergeWith</A></B>(<A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Merges the set options of a another options object with this.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html#setArray(boolean)">setArray</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html#setArrayAlternate(boolean)">setArrayAlternate</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html#setArrayAltText(boolean)">setArrayAltText</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html#setArrayOrdered(boolean)">setArrayOrdered</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html#setCompact(boolean)">setCompact</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html#setHasLanguage(boolean)">setHasLanguage</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html#setHasQualifiers(boolean)">setHasQualifiers</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html#setHasType(boolean)">setHasType</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html#setQualifier(boolean)">setQualifier</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html#setSchemaNode(boolean)">setSchemaNode</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html#setStruct(boolean)">setStruct</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html#setURI(boolean)">setURI</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;<A NAME="methods_inherited_from_class_com.adobe.xmp.options.Options"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#EEEEFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="left"><B>Methods inherited from class com.adobe.xmp.options.<A HREF="../../../../com/adobe/xmp/options/Options.html" title="class in com.adobe.xmp.options">Options</A></B></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE><A HREF="../../../../com/adobe/xmp/options/Options.html#clear()">clear</A>, <A HREF="../../../../com/adobe/xmp/options/Options.html#containsAllOptions(int)">containsAllOptions</A>, <A HREF="../../../../com/adobe/xmp/options/Options.html#containsOneOf(int)">containsOneOf</A>, <A HREF="../../../../com/adobe/xmp/options/Options.html#equals(java.lang.Object)">equals</A>, <A HREF="../../../../com/adobe/xmp/options/Options.html#getOptions()">getOptions</A>, <A HREF="../../../../com/adobe/xmp/options/Options.html#getOptionsString()">getOptionsString</A>, <A HREF="../../../../com/adobe/xmp/options/Options.html#hashCode()">hashCode</A>, <A HREF="../../../../com/adobe/xmp/options/Options.html#isExactly(int)">isExactly</A>, <A HREF="../../../../com/adobe/xmp/options/Options.html#setOption(int, boolean)">setOption</A>, <A HREF="../../../../com/adobe/xmp/options/Options.html#setOptions(int)">setOptions</A>, <A HREF="../../../../com/adobe/xmp/options/Options.html#toString()">toString</A></CODE></TD>
+</TR>
+</TABLE>
+&nbsp;<A NAME="methods_inherited_from_class_java.lang.Object"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#EEEEFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="left"><B>Methods inherited from class java.lang.Object</B></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE>getClass, notify, notifyAll, wait, wait, wait</CODE></TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<!-- ============ FIELD DETAIL =========== -->
+
+<A NAME="field_detail"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="1"><FONT SIZE="+2">
+<B>Field Detail</B></FONT></TH>
+</TR>
+</TABLE>
+
+<A NAME="NO_OPTIONS"><!-- --></A><H3>
+NO_OPTIONS</H3>
+<PRE>
+public static final int <B>NO_OPTIONS</B></PRE>
+<DL>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../../constant-values.html#com.adobe.xmp.options.PropertyOptions.NO_OPTIONS">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="URI"><!-- --></A><H3>
+URI</H3>
+<PRE>
+public static final int <B>URI</B></PRE>
+<DL>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../../constant-values.html#com.adobe.xmp.options.PropertyOptions.URI">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="HAS_QUALIFIERS"><!-- --></A><H3>
+HAS_QUALIFIERS</H3>
+<PRE>
+public static final int <B>HAS_QUALIFIERS</B></PRE>
+<DL>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../../constant-values.html#com.adobe.xmp.options.PropertyOptions.HAS_QUALIFIERS">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="QUALIFIER"><!-- --></A><H3>
+QUALIFIER</H3>
+<PRE>
+public static final int <B>QUALIFIER</B></PRE>
+<DL>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../../constant-values.html#com.adobe.xmp.options.PropertyOptions.QUALIFIER">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="HAS_LANGUAGE"><!-- --></A><H3>
+HAS_LANGUAGE</H3>
+<PRE>
+public static final int <B>HAS_LANGUAGE</B></PRE>
+<DL>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../../constant-values.html#com.adobe.xmp.options.PropertyOptions.HAS_LANGUAGE">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="HAS_TYPE"><!-- --></A><H3>
+HAS_TYPE</H3>
+<PRE>
+public static final int <B>HAS_TYPE</B></PRE>
+<DL>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../../constant-values.html#com.adobe.xmp.options.PropertyOptions.HAS_TYPE">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="STRUCT"><!-- --></A><H3>
+STRUCT</H3>
+<PRE>
+public static final int <B>STRUCT</B></PRE>
+<DL>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../../constant-values.html#com.adobe.xmp.options.PropertyOptions.STRUCT">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="ARRAY"><!-- --></A><H3>
+ARRAY</H3>
+<PRE>
+public static final int <B>ARRAY</B></PRE>
+<DL>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../../constant-values.html#com.adobe.xmp.options.PropertyOptions.ARRAY">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="ARRAY_ORDERED"><!-- --></A><H3>
+ARRAY_ORDERED</H3>
+<PRE>
+public static final int <B>ARRAY_ORDERED</B></PRE>
+<DL>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../../constant-values.html#com.adobe.xmp.options.PropertyOptions.ARRAY_ORDERED">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="ARRAY_ALTERNATE"><!-- --></A><H3>
+ARRAY_ALTERNATE</H3>
+<PRE>
+public static final int <B>ARRAY_ALTERNATE</B></PRE>
+<DL>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../../constant-values.html#com.adobe.xmp.options.PropertyOptions.ARRAY_ALTERNATE">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="ARRAY_ALT_TEXT"><!-- --></A><H3>
+ARRAY_ALT_TEXT</H3>
+<PRE>
+public static final int <B>ARRAY_ALT_TEXT</B></PRE>
+<DL>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../../constant-values.html#com.adobe.xmp.options.PropertyOptions.ARRAY_ALT_TEXT">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="COMPACT"><!-- --></A><H3>
+COMPACT</H3>
+<PRE>
+public static final int <B>COMPACT</B></PRE>
+<DL>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../../constant-values.html#com.adobe.xmp.options.PropertyOptions.COMPACT">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="SCHEMA_NODE"><!-- --></A><H3>
+SCHEMA_NODE</H3>
+<PRE>
+public static final int <B>SCHEMA_NODE</B></PRE>
+<DL>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../../constant-values.html#com.adobe.xmp.options.PropertyOptions.SCHEMA_NODE">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="DELETE_EXISTING"><!-- --></A><H3>
+DELETE_EXISTING</H3>
+<PRE>
+public static final int <B>DELETE_EXISTING</B></PRE>
+<DL>
+<DD>may be used in the future
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../../constant-values.html#com.adobe.xmp.options.PropertyOptions.DELETE_EXISTING">Constant Field Values</A></DL>
+</DL>
+
+<!-- ========= CONSTRUCTOR DETAIL ======== -->
+
+<A NAME="constructor_detail"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="1"><FONT SIZE="+2">
+<B>Constructor Detail</B></FONT></TH>
+</TR>
+</TABLE>
+
+<A NAME="PropertyOptions()"><!-- --></A><H3>
+PropertyOptions</H3>
+<PRE>
+public <B>PropertyOptions</B>()</PRE>
+<DL>
+<DD>Default constructor
+<P>
+</DL>
+<HR>
+
+<A NAME="PropertyOptions(int)"><!-- --></A><H3>
+PropertyOptions</H3>
+<PRE>
+public <B>PropertyOptions</B>(int&nbsp;options)
+ throws <A HREF="../../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Intialization constructor
+<P>
+<DL>
+<DT><B>Parameters:</B><DD><CODE>options</CODE> - the initialization options
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - If the options are not valid</DL>
+</DL>
+
+<!-- ============ METHOD DETAIL ========== -->
+
+<A NAME="method_detail"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="1"><FONT SIZE="+2">
+<B>Method Detail</B></FONT></TH>
+</TR>
+</TABLE>
+
+<A NAME="isURI()"><!-- --></A><H3>
+isURI</H3>
+<PRE>
+public boolean <B>isURI</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Return whether the property value is a URI. It is serialized to RDF using the
+ <tt>rdf:resource</tt> attribute. Not mandatory for URIs, but considered RDF-savvy.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setURI(boolean)"><!-- --></A><H3>
+setURI</H3>
+<PRE>
+public <A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A> <B>setURI</B>(boolean&nbsp;value)</PRE>
+<DL>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>value</CODE> - the value to set
+<DT><B>Returns:</B><DD>Returns this to enable cascaded options.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getHasQualifiers()"><!-- --></A><H3>
+getHasQualifiers</H3>
+<PRE>
+public boolean <B>getHasQualifiers</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Return whether the property has qualifiers. These could be an <tt>xml:lang</tt>
+ attribute, an <tt>rdf:type</tt> property, or a general qualifier. See the
+ introductory discussion of qualified properties for more information.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setHasQualifiers(boolean)"><!-- --></A><H3>
+setHasQualifiers</H3>
+<PRE>
+public <A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A> <B>setHasQualifiers</B>(boolean&nbsp;value)</PRE>
+<DL>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>value</CODE> - the value to set
+<DT><B>Returns:</B><DD>Returns this to enable cascaded options.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="isQualifier()"><!-- --></A><H3>
+isQualifier</H3>
+<PRE>
+public boolean <B>isQualifier</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Return whether this property is a qualifier for some other property. Note that if the
+ qualifier itself has a structured value, this flag is only set for the top node of
+ the qualifier's subtree. Qualifiers may have arbitrary structure, and may even have
+ qualifiers.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setQualifier(boolean)"><!-- --></A><H3>
+setQualifier</H3>
+<PRE>
+public <A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A> <B>setQualifier</B>(boolean&nbsp;value)</PRE>
+<DL>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>value</CODE> - the value to set
+<DT><B>Returns:</B><DD>Returns this to enable cascaded options.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getHasLanguage()"><!-- --></A><H3>
+getHasLanguage</H3>
+<PRE>
+public boolean <B>getHasLanguage</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Return whether this property has an <tt>xml:lang</tt> qualifier.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setHasLanguage(boolean)"><!-- --></A><H3>
+setHasLanguage</H3>
+<PRE>
+public <A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A> <B>setHasLanguage</B>(boolean&nbsp;value)</PRE>
+<DL>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>value</CODE> - the value to set
+<DT><B>Returns:</B><DD>Returns this to enable cascaded options.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getHasType()"><!-- --></A><H3>
+getHasType</H3>
+<PRE>
+public boolean <B>getHasType</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Return whether this property has an <tt>rdf:type</tt> qualifier.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setHasType(boolean)"><!-- --></A><H3>
+setHasType</H3>
+<PRE>
+public <A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A> <B>setHasType</B>(boolean&nbsp;value)</PRE>
+<DL>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>value</CODE> - the value to set
+<DT><B>Returns:</B><DD>Returns this to enable cascaded options.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="isStruct()"><!-- --></A><H3>
+isStruct</H3>
+<PRE>
+public boolean <B>isStruct</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Return whether this property contains nested fields.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setStruct(boolean)"><!-- --></A><H3>
+setStruct</H3>
+<PRE>
+public <A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A> <B>setStruct</B>(boolean&nbsp;value)</PRE>
+<DL>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>value</CODE> - the value to set
+<DT><B>Returns:</B><DD>Returns this to enable cascaded options.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="isArray()"><!-- --></A><H3>
+isArray</H3>
+<PRE>
+public boolean <B>isArray</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Return whether this property is an array. By itself this indicates a general
+ unordered array. It is serialized using an <tt>rdf:Bag</tt> container.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setArray(boolean)"><!-- --></A><H3>
+setArray</H3>
+<PRE>
+public <A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A> <B>setArray</B>(boolean&nbsp;value)</PRE>
+<DL>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>value</CODE> - the value to set
+<DT><B>Returns:</B><DD>Returns this to enable cascaded options.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="isArrayOrdered()"><!-- --></A><H3>
+isArrayOrdered</H3>
+<PRE>
+public boolean <B>isArrayOrdered</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Return whether this property is an ordered array. Appears in conjunction with
+ getPropValueIsArray(). It is serialized using an <tt>rdf:Seq</tt> container.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setArrayOrdered(boolean)"><!-- --></A><H3>
+setArrayOrdered</H3>
+<PRE>
+public <A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A> <B>setArrayOrdered</B>(boolean&nbsp;value)</PRE>
+<DL>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>value</CODE> - the value to set
+<DT><B>Returns:</B><DD>Returns this to enable cascaded options.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="isArrayAlternate()"><!-- --></A><H3>
+isArrayAlternate</H3>
+<PRE>
+public boolean <B>isArrayAlternate</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Return whether this property is an alternative array. Appears in conjunction with
+ getPropValueIsArray(). It is serialized using an <tt>rdf:Alt</tt> container.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setArrayAlternate(boolean)"><!-- --></A><H3>
+setArrayAlternate</H3>
+<PRE>
+public <A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A> <B>setArrayAlternate</B>(boolean&nbsp;value)</PRE>
+<DL>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>value</CODE> - the value to set
+<DT><B>Returns:</B><DD>Returns this to enable cascaded options.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="isArrayAltText()"><!-- --></A><H3>
+isArrayAltText</H3>
+<PRE>
+public boolean <B>isArrayAltText</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Return whether this property is an alt-text array. Appears in conjunction with
+ getPropArrayIsAlternate(). It is serialized using an <tt>rdf:Alt</tt> container.
+ Each array element is a simple property with an <tt>xml:lang</tt> attribute.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setArrayAltText(boolean)"><!-- --></A><H3>
+setArrayAltText</H3>
+<PRE>
+public <A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A> <B>setArrayAltText</B>(boolean&nbsp;value)</PRE>
+<DL>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>value</CODE> - the value to set
+<DT><B>Returns:</B><DD>Returns this to enable cascaded options.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="isCompact()"><!-- --></A><H3>
+isCompact</H3>
+<PRE>
+public boolean <B>isCompact</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Return whether the value is a compact struct or array.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setCompact(boolean)"><!-- --></A><H3>
+setCompact</H3>
+<PRE>
+public <A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A> <B>setCompact</B>(boolean&nbsp;value)</PRE>
+<DL>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>value</CODE> - the value to set
+<DT><B>Returns:</B><DD>Returns this to enable cascaded options.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="isSchemaNode()"><!-- --></A><H3>
+isSchemaNode</H3>
+<PRE>
+public boolean <B>isSchemaNode</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns whether the SCHEMA_NODE option is set.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setSchemaNode(boolean)"><!-- --></A><H3>
+setSchemaNode</H3>
+<PRE>
+public <A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A> <B>setSchemaNode</B>(boolean&nbsp;value)</PRE>
+<DL>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>value</CODE> - the option DELETE_EXISTING to set
+<DT><B>Returns:</B><DD>Returns this to enable cascaded options.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="isCompositeProperty()"><!-- --></A><H3>
+isCompositeProperty</H3>
+<PRE>
+public boolean <B>isCompositeProperty</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns whether the property is of composite type - an array or a struct.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="isSimple()"><!-- --></A><H3>
+isSimple</H3>
+<PRE>
+public boolean <B>isSimple</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns whether the property is of composite type - an array or a struct.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="equalArrayTypes(com.adobe.xmp.options.PropertyOptions)"><!-- --></A><H3>
+equalArrayTypes</H3>
+<PRE>
+public boolean <B>equalArrayTypes</B>(<A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)</PRE>
+<DL>
+<DD>Compares two options set for array compatibility.
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>options</CODE> - other options
+<DT><B>Returns:</B><DD>Returns true if the array options of the sets are equal.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="mergeWith(com.adobe.xmp.options.PropertyOptions)"><!-- --></A><H3>
+mergeWith</H3>
+<PRE>
+public void <B>mergeWith</B>(<A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)
+ throws <A HREF="../../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Merges the set options of a another options object with this.
+ If the other options set is null, this objects stays the same.
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>options</CODE> - other options
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - If illegal options are provided</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="isOnlyArrayOptions()"><!-- --></A><H3>
+isOnlyArrayOptions</H3>
+<PRE>
+public boolean <B>isOnlyArrayOptions</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns true if only array options are set.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="assertConsistency(int)"><!-- --></A><H3>
+assertConsistency</H3>
+<PRE>
+public void <B>assertConsistency</B>(int&nbsp;options)
+ throws <A HREF="../../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Checks that a node not a struct and array at the same time;
+ and URI cannot be a struct.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>options</CODE> - the bitmask to check.
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Thrown if the options are not consistent.</DL>
+</DD>
+</DL>
+<!-- ========= END OF CLASS DATA ========= -->
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="class-use/PropertyOptions.html"><FONT CLASS="NavBarFont1"><B>Use</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="../../../../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;<A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../index.html?com/adobe/xmp/options/PropertyOptions.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="PropertyOptions.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+ SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;<A HREF="#field_summary">FIELD</A>&nbsp;|&nbsp;<A HREF="#constructor_summary">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;<A HREF="#field_detail">FIELD</A>&nbsp;|&nbsp;<A HREF="#constructor_detail">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/com/adobe/xmp/options/SerializeOptions.html b/java/XMPCore/docs/com/adobe/xmp/options/SerializeOptions.html
new file mode 100644
index 0000000..917ef57
--- /dev/null
+++ b/java/XMPCore/docs/com/adobe/xmp/options/SerializeOptions.html
@@ -0,0 +1,1080 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:50 CEST 2007 -->
+<TITLE>
+SerializeOptions
+</TITLE>
+
+<META NAME="keywords" CONTENT="com.adobe.xmp.options.SerializeOptions class">
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="SerializeOptions";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="class-use/SerializeOptions.html"><FONT CLASS="NavBarFont1"><B>Use</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;NEXT CLASS</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../index.html?com/adobe/xmp/options/SerializeOptions.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="SerializeOptions.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+ SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;<A HREF="#field_summary">FIELD</A>&nbsp;|&nbsp;<A HREF="#constructor_summary">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;<A HREF="#field_detail">FIELD</A>&nbsp;|&nbsp;<A HREF="#constructor_detail">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<!-- ======== START OF CLASS DATA ======== -->
+<H2>
+<FONT SIZE="-1">
+com.adobe.xmp.options</FONT>
+<BR>
+Class SerializeOptions</H2>
+<PRE>
+java.lang.Object
+ <IMG SRC="../../../../resources/inherit.gif" ALT="extended by "><A HREF="../../../../com/adobe/xmp/options/Options.html" title="class in com.adobe.xmp.options">com.adobe.xmp.options.Options</A>
+ <IMG SRC="../../../../resources/inherit.gif" ALT="extended by "><B>com.adobe.xmp.options.SerializeOptions</B>
+</PRE>
+<HR>
+<DL>
+<DT><PRE>public final class <B>SerializeOptions</B><DT>extends <A HREF="../../../../com/adobe/xmp/options/Options.html" title="class in com.adobe.xmp.options">Options</A></DL>
+</PRE>
+
+<P>
+Options for <A HREF="../../../../com/adobe/xmp/XMPMetaFactory.html#serializeToBuffer(com.adobe.xmp.XMPMeta, com.adobe.xmp.options.SerializeOptions)"><CODE>XMPMetaFactory.serializeToBuffer(XMPMeta, SerializeOptions)</CODE></A>.
+<P>
+
+<P>
+<DL>
+<DT><B>Since:</B></DT>
+ <DD>24.01.2006</DD>
+</DL>
+<HR>
+
+<P>
+<!-- =========== FIELD SUMMARY =========== -->
+
+<A NAME="field_summary"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+<B>Field Summary</B></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html#ENCODE_UTF16BE">ENCODE_UTF16BE</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;UTF16BE encoding</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html#ENCODE_UTF16LE">ENCODE_UTF16LE</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;UTF16LE encoding</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html#ENCODE_UTF8">ENCODE_UTF8</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;UTF8 encoding; this is the default</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html#EXACT_PACKET_LENGTH">EXACT_PACKET_LENGTH</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The padding parameter provides the overall packet length.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html#INCLUDE_THUMBNAIL_PAD">INCLUDE_THUMBNAIL_PAD</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Include a padding allowance for a thumbnail image.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html#OMIT_PACKET_WRAPPER">OMIT_PACKET_WRAPPER</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Omit the XML packet wrapper.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html#READONLY_PACKET">READONLY_PACKET</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Mark packet as read-only.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html#SORT">SORT</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sort the struct properties and qualifier before serializing</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html#USE_COMPACT_FORMAT">USE_COMPACT_FORMAT</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Use a compact form of RDF.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html#WRITE_ALIAS_COMMENTS">WRITE_ALIAS_COMMENTS</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Show aliases as XML comments.</TD>
+</TR>
+</TABLE>
+&nbsp;
+<!-- ======== CONSTRUCTOR SUMMARY ======== -->
+
+<A NAME="constructor_summary"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+<B>Constructor Summary</B></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html#SerializeOptions()">SerializeOptions</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Default constructor.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html#SerializeOptions(int)">SerializeOptions</A></B>(int&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Constructor using inital options</TD>
+</TR>
+</TABLE>
+&nbsp;
+<!-- ========== METHOD SUMMARY =========== -->
+
+<A NAME="method_summary"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+<B>Method Summary</B></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.lang.Object</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html#clone()">clone</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html#getBaseIndent()">getBaseIndent</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html#getEncodeUTF16BE()">getEncodeUTF16BE</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html#getEncodeUTF16LE()">getEncodeUTF16LE</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html#getEncoding()">getEncoding</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html#getExactPacketLength()">getExactPacketLength</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html#getIncludeThumbnailPad()">getIncludeThumbnailPad</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html#getIndent()">getIndent</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html#getNewline()">getNewline</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html#getOmitPacketWrapper()">getOmitPacketWrapper</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html#getOmitVersionAttribute()">getOmitVersionAttribute</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html#getPadding()">getPadding</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html#getReadOnlyPacket()">getReadOnlyPacket</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html#getSort()">getSort</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html#getUseCompactFormat()">getUseCompactFormat</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html#getWriteAliasComments()">getWriteAliasComments</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html#setBaseIndent(int)">setBaseIndent</A></B>(int&nbsp;baseIndent)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html#setEncodeUTF16BE(boolean)">setEncodeUTF16BE</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html#setEncodeUTF16LE(boolean)">setEncodeUTF16LE</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html#setExactPacketLength(boolean)">setExactPacketLength</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html#setIncludeThumbnailPad(boolean)">setIncludeThumbnailPad</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html#setIndent(java.lang.String)">setIndent</A></B>(java.lang.String&nbsp;indent)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html#setNewline(java.lang.String)">setNewline</A></B>(java.lang.String&nbsp;newline)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html#setOmitPacketWrapper(boolean)">setOmitPacketWrapper</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html#setPadding(int)">setPadding</A></B>(int&nbsp;padding)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html#setReadOnlyPacket(boolean)">setReadOnlyPacket</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html#setSort(boolean)">setSort</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html#setUseCompactFormat(boolean)">setUseCompactFormat</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html#setWriteAliasComments(boolean)">setWriteAliasComments</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<em>Note:</em> This options is not supported at the moment.</TD>
+</TR>
+</TABLE>
+&nbsp;<A NAME="methods_inherited_from_class_com.adobe.xmp.options.Options"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#EEEEFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="left"><B>Methods inherited from class com.adobe.xmp.options.<A HREF="../../../../com/adobe/xmp/options/Options.html" title="class in com.adobe.xmp.options">Options</A></B></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE><A HREF="../../../../com/adobe/xmp/options/Options.html#clear()">clear</A>, <A HREF="../../../../com/adobe/xmp/options/Options.html#containsAllOptions(int)">containsAllOptions</A>, <A HREF="../../../../com/adobe/xmp/options/Options.html#containsOneOf(int)">containsOneOf</A>, <A HREF="../../../../com/adobe/xmp/options/Options.html#equals(java.lang.Object)">equals</A>, <A HREF="../../../../com/adobe/xmp/options/Options.html#getOptions()">getOptions</A>, <A HREF="../../../../com/adobe/xmp/options/Options.html#getOptionsString()">getOptionsString</A>, <A HREF="../../../../com/adobe/xmp/options/Options.html#hashCode()">hashCode</A>, <A HREF="../../../../com/adobe/xmp/options/Options.html#isExactly(int)">isExactly</A>, <A HREF="../../../../com/adobe/xmp/options/Options.html#setOption(int, boolean)">setOption</A>, <A HREF="../../../../com/adobe/xmp/options/Options.html#setOptions(int)">setOptions</A>, <A HREF="../../../../com/adobe/xmp/options/Options.html#toString()">toString</A></CODE></TD>
+</TR>
+</TABLE>
+&nbsp;<A NAME="methods_inherited_from_class_java.lang.Object"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#EEEEFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="left"><B>Methods inherited from class java.lang.Object</B></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE>getClass, notify, notifyAll, wait, wait, wait</CODE></TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<!-- ============ FIELD DETAIL =========== -->
+
+<A NAME="field_detail"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="1"><FONT SIZE="+2">
+<B>Field Detail</B></FONT></TH>
+</TR>
+</TABLE>
+
+<A NAME="OMIT_PACKET_WRAPPER"><!-- --></A><H3>
+OMIT_PACKET_WRAPPER</H3>
+<PRE>
+public static final int <B>OMIT_PACKET_WRAPPER</B></PRE>
+<DL>
+<DD>Omit the XML packet wrapper.
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../../constant-values.html#com.adobe.xmp.options.SerializeOptions.OMIT_PACKET_WRAPPER">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="READONLY_PACKET"><!-- --></A><H3>
+READONLY_PACKET</H3>
+<PRE>
+public static final int <B>READONLY_PACKET</B></PRE>
+<DL>
+<DD>Mark packet as read-only. Default is a writeable packet.
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../../constant-values.html#com.adobe.xmp.options.SerializeOptions.READONLY_PACKET">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="USE_COMPACT_FORMAT"><!-- --></A><H3>
+USE_COMPACT_FORMAT</H3>
+<PRE>
+public static final int <B>USE_COMPACT_FORMAT</B></PRE>
+<DL>
+<DD>Use a compact form of RDF.
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../../constant-values.html#com.adobe.xmp.options.SerializeOptions.USE_COMPACT_FORMAT">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="INCLUDE_THUMBNAIL_PAD"><!-- --></A><H3>
+INCLUDE_THUMBNAIL_PAD</H3>
+<PRE>
+public static final int <B>INCLUDE_THUMBNAIL_PAD</B></PRE>
+<DL>
+<DD>Include a padding allowance for a thumbnail image. If no <tt>xmp:Thumbnails</tt> property
+ is present, the typical space for a JPEG thumbnail is used.
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../../constant-values.html#com.adobe.xmp.options.SerializeOptions.INCLUDE_THUMBNAIL_PAD">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="EXACT_PACKET_LENGTH"><!-- --></A><H3>
+EXACT_PACKET_LENGTH</H3>
+<PRE>
+public static final int <B>EXACT_PACKET_LENGTH</B></PRE>
+<DL>
+<DD>The padding parameter provides the overall packet length. The actual amount of padding is
+ computed. An exception is thrown if the packet exceeds this length with no padding.
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../../constant-values.html#com.adobe.xmp.options.SerializeOptions.EXACT_PACKET_LENGTH">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="WRITE_ALIAS_COMMENTS"><!-- --></A><H3>
+WRITE_ALIAS_COMMENTS</H3>
+<PRE>
+public static final int <B>WRITE_ALIAS_COMMENTS</B></PRE>
+<DL>
+<DD>Show aliases as XML comments. <em>Note:</em> This option is currently not supported.
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../../constant-values.html#com.adobe.xmp.options.SerializeOptions.WRITE_ALIAS_COMMENTS">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="SORT"><!-- --></A><H3>
+SORT</H3>
+<PRE>
+public static final int <B>SORT</B></PRE>
+<DL>
+<DD>Sort the struct properties and qualifier before serializing
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../../constant-values.html#com.adobe.xmp.options.SerializeOptions.SORT">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="ENCODE_UTF8"><!-- --></A><H3>
+ENCODE_UTF8</H3>
+<PRE>
+public static final int <B>ENCODE_UTF8</B></PRE>
+<DL>
+<DD>UTF8 encoding; this is the default
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../../constant-values.html#com.adobe.xmp.options.SerializeOptions.ENCODE_UTF8">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="ENCODE_UTF16BE"><!-- --></A><H3>
+ENCODE_UTF16BE</H3>
+<PRE>
+public static final int <B>ENCODE_UTF16BE</B></PRE>
+<DL>
+<DD>UTF16BE encoding
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../../constant-values.html#com.adobe.xmp.options.SerializeOptions.ENCODE_UTF16BE">Constant Field Values</A></DL>
+</DL>
+<HR>
+
+<A NAME="ENCODE_UTF16LE"><!-- --></A><H3>
+ENCODE_UTF16LE</H3>
+<PRE>
+public static final int <B>ENCODE_UTF16LE</B></PRE>
+<DL>
+<DD>UTF16LE encoding
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="../../../../constant-values.html#com.adobe.xmp.options.SerializeOptions.ENCODE_UTF16LE">Constant Field Values</A></DL>
+</DL>
+
+<!-- ========= CONSTRUCTOR DETAIL ======== -->
+
+<A NAME="constructor_detail"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="1"><FONT SIZE="+2">
+<B>Constructor Detail</B></FONT></TH>
+</TR>
+</TABLE>
+
+<A NAME="SerializeOptions()"><!-- --></A><H3>
+SerializeOptions</H3>
+<PRE>
+public <B>SerializeOptions</B>()</PRE>
+<DL>
+<DD>Default constructor.
+<P>
+</DL>
+<HR>
+
+<A NAME="SerializeOptions(int)"><!-- --></A><H3>
+SerializeOptions</H3>
+<PRE>
+public <B>SerializeOptions</B>(int&nbsp;options)
+ throws <A HREF="../../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></PRE>
+<DL>
+<DD>Constructor using inital options
+<P>
+<DL>
+<DT><B>Parameters:</B><DD><CODE>options</CODE> - the inital options
+<DT><B>Throws:</B>
+<DD><CODE><A HREF="../../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></CODE> - Thrown if options are not consistant.</DL>
+</DL>
+
+<!-- ============ METHOD DETAIL ========== -->
+
+<A NAME="method_detail"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="1"><FONT SIZE="+2">
+<B>Method Detail</B></FONT></TH>
+</TR>
+</TABLE>
+
+<A NAME="getOmitPacketWrapper()"><!-- --></A><H3>
+getOmitPacketWrapper</H3>
+<PRE>
+public boolean <B>getOmitPacketWrapper</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns the option.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setOmitPacketWrapper(boolean)"><!-- --></A><H3>
+setOmitPacketWrapper</H3>
+<PRE>
+public <A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A> <B>setOmitPacketWrapper</B>(boolean&nbsp;value)</PRE>
+<DL>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>value</CODE> - the value to set
+<DT><B>Returns:</B><DD>Returns the instance to call more set-methods.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getReadOnlyPacket()"><!-- --></A><H3>
+getReadOnlyPacket</H3>
+<PRE>
+public boolean <B>getReadOnlyPacket</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns the option.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setReadOnlyPacket(boolean)"><!-- --></A><H3>
+setReadOnlyPacket</H3>
+<PRE>
+public <A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A> <B>setReadOnlyPacket</B>(boolean&nbsp;value)</PRE>
+<DL>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>value</CODE> - the value to set
+<DT><B>Returns:</B><DD>Returns the instance to call more set-methods.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getUseCompactFormat()"><!-- --></A><H3>
+getUseCompactFormat</H3>
+<PRE>
+public boolean <B>getUseCompactFormat</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns the option.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setUseCompactFormat(boolean)"><!-- --></A><H3>
+setUseCompactFormat</H3>
+<PRE>
+public <A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A> <B>setUseCompactFormat</B>(boolean&nbsp;value)</PRE>
+<DL>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>value</CODE> - the value to set
+<DT><B>Returns:</B><DD>Returns the instance to call more set-methods.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getIncludeThumbnailPad()"><!-- --></A><H3>
+getIncludeThumbnailPad</H3>
+<PRE>
+public boolean <B>getIncludeThumbnailPad</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns the option.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setIncludeThumbnailPad(boolean)"><!-- --></A><H3>
+setIncludeThumbnailPad</H3>
+<PRE>
+public <A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A> <B>setIncludeThumbnailPad</B>(boolean&nbsp;value)</PRE>
+<DL>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>value</CODE> - the value to set
+<DT><B>Returns:</B><DD>Returns the instance to call more set-methods.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getExactPacketLength()"><!-- --></A><H3>
+getExactPacketLength</H3>
+<PRE>
+public boolean <B>getExactPacketLength</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns the option.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setExactPacketLength(boolean)"><!-- --></A><H3>
+setExactPacketLength</H3>
+<PRE>
+public <A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A> <B>setExactPacketLength</B>(boolean&nbsp;value)</PRE>
+<DL>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>value</CODE> - the value to set
+<DT><B>Returns:</B><DD>Returns the instance to call more set-methods.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getWriteAliasComments()"><!-- --></A><H3>
+getWriteAliasComments</H3>
+<PRE>
+public boolean <B>getWriteAliasComments</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns the option.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setWriteAliasComments(boolean)"><!-- --></A><H3>
+setWriteAliasComments</H3>
+<PRE>
+public <A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A> <B>setWriteAliasComments</B>(boolean&nbsp;value)</PRE>
+<DL>
+<DD><em>Note:</em> This options is not supported at the moment.
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>value</CODE> - the value to set
+<DT><B>Returns:</B><DD>Returns the instance to call more set-methods.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getSort()"><!-- --></A><H3>
+getSort</H3>
+<PRE>
+public boolean <B>getSort</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns the option.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setSort(boolean)"><!-- --></A><H3>
+setSort</H3>
+<PRE>
+public <A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A> <B>setSort</B>(boolean&nbsp;value)</PRE>
+<DL>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>value</CODE> - the value to set
+<DT><B>Returns:</B><DD>Returns the instance to call more set-methods.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getEncodeUTF16BE()"><!-- --></A><H3>
+getEncodeUTF16BE</H3>
+<PRE>
+public boolean <B>getEncodeUTF16BE</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns the option.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setEncodeUTF16BE(boolean)"><!-- --></A><H3>
+setEncodeUTF16BE</H3>
+<PRE>
+public <A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A> <B>setEncodeUTF16BE</B>(boolean&nbsp;value)</PRE>
+<DL>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>value</CODE> - the value to set
+<DT><B>Returns:</B><DD>Returns the instance to call more set-methods.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getEncodeUTF16LE()"><!-- --></A><H3>
+getEncodeUTF16LE</H3>
+<PRE>
+public boolean <B>getEncodeUTF16LE</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns the option.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setEncodeUTF16LE(boolean)"><!-- --></A><H3>
+setEncodeUTF16LE</H3>
+<PRE>
+public <A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A> <B>setEncodeUTF16LE</B>(boolean&nbsp;value)</PRE>
+<DL>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>value</CODE> - the value to set
+<DT><B>Returns:</B><DD>Returns the instance to call more set-methods.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getBaseIndent()"><!-- --></A><H3>
+getBaseIndent</H3>
+<PRE>
+public int <B>getBaseIndent</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns the baseIndent.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setBaseIndent(int)"><!-- --></A><H3>
+setBaseIndent</H3>
+<PRE>
+public <A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A> <B>setBaseIndent</B>(int&nbsp;baseIndent)</PRE>
+<DL>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>baseIndent</CODE> - The baseIndent to set.
+<DT><B>Returns:</B><DD>Returns the instance to call more set-methods.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getIndent()"><!-- --></A><H3>
+getIndent</H3>
+<PRE>
+public java.lang.String <B>getIndent</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns the indent.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setIndent(java.lang.String)"><!-- --></A><H3>
+setIndent</H3>
+<PRE>
+public <A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A> <B>setIndent</B>(java.lang.String&nbsp;indent)</PRE>
+<DL>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>indent</CODE> - The indent to set.
+<DT><B>Returns:</B><DD>Returns the instance to call more set-methods.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getNewline()"><!-- --></A><H3>
+getNewline</H3>
+<PRE>
+public java.lang.String <B>getNewline</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns the newline.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setNewline(java.lang.String)"><!-- --></A><H3>
+setNewline</H3>
+<PRE>
+public <A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A> <B>setNewline</B>(java.lang.String&nbsp;newline)</PRE>
+<DL>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>newline</CODE> - The newline to set.
+<DT><B>Returns:</B><DD>Returns the instance to call more set-methods.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getPadding()"><!-- --></A><H3>
+getPadding</H3>
+<PRE>
+public int <B>getPadding</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns the padding.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setPadding(int)"><!-- --></A><H3>
+setPadding</H3>
+<PRE>
+public <A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A> <B>setPadding</B>(int&nbsp;padding)</PRE>
+<DL>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>padding</CODE> - The padding to set.
+<DT><B>Returns:</B><DD>Returns the instance to call more set-methods.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getOmitVersionAttribute()"><!-- --></A><H3>
+getOmitVersionAttribute</H3>
+<PRE>
+public boolean <B>getOmitVersionAttribute</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns whether the Toolkit version attribute shall be omitted.
+ <em>Note:</em> This options can only be set by unit tests.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getEncoding()"><!-- --></A><H3>
+getEncoding</H3>
+<PRE>
+public java.lang.String <B>getEncoding</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns the encoding as Java encoding String.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="clone()"><!-- --></A><H3>
+clone</H3>
+<PRE>
+public java.lang.Object <B>clone</B>()
+ throws java.lang.CloneNotSupportedException</PRE>
+<DL>
+<DD><DL>
+<DT><B>Overrides:</B><DD><CODE>clone</CODE> in class <CODE>java.lang.Object</CODE></DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns clone of this SerializeOptions-object with the same options set.
+<DT><B>Throws:</B>
+<DD><CODE>java.lang.CloneNotSupportedException</CODE> - Cannot happen in this place.</DL>
+</DD>
+</DL>
+<!-- ========= END OF CLASS DATA ========= -->
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="class-use/SerializeOptions.html"><FONT CLASS="NavBarFont1"><B>Use</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;NEXT CLASS</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../index.html?com/adobe/xmp/options/SerializeOptions.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="SerializeOptions.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+ SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;<A HREF="#field_summary">FIELD</A>&nbsp;|&nbsp;<A HREF="#constructor_summary">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;<A HREF="#field_detail">FIELD</A>&nbsp;|&nbsp;<A HREF="#constructor_detail">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/com/adobe/xmp/options/class-use/AliasOptions.html b/java/XMPCore/docs/com/adobe/xmp/options/class-use/AliasOptions.html
new file mode 100644
index 0000000..cad6a5f
--- /dev/null
+++ b/java/XMPCore/docs/com/adobe/xmp/options/class-use/AliasOptions.html
@@ -0,0 +1,262 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:51 CEST 2007 -->
+<TITLE>
+Uses of Class com.adobe.xmp.options.AliasOptions
+</TITLE>
+
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="Uses of Class com.adobe.xmp.options.AliasOptions";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options"><FONT CLASS="NavBarFont1"><B>Class</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Use</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../../index.html?com/adobe/xmp/options//class-useAliasOptions.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="AliasOptions.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<CENTER>
+<H2>
+<B>Uses of Class<br>com.adobe.xmp.options.AliasOptions</B></H2>
+</CENTER>
+
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+Packages that use <A HREF="../../../../../com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options">AliasOptions</A></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><A HREF="#com.adobe.xmp"><B>com.adobe.xmp</B></A></TD>
+<TD>Package containing the xmpcore interface.&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><A HREF="#com.adobe.xmp.options"><B>com.adobe.xmp.options</B></A></TD>
+<TD>Package containing the option classes.&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><A HREF="#com.adobe.xmp.properties"><B>com.adobe.xmp.properties</B></A></TD>
+<TD>Package containing the property information classes.&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+<A NAME="com.adobe.xmp"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+Uses of <A HREF="../../../../../com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options">AliasOptions</A> in <A HREF="../../../../../com/adobe/xmp/package-summary.html">com.adobe.xmp</A></FONT></TH>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="left" COLSPAN="2">Methods in <A HREF="../../../../../com/adobe/xmp/package-summary.html">com.adobe.xmp</A> with parameters of type <A HREF="../../../../../com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options">AliasOptions</A></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPSchemaRegistry.</B><B><A HREF="../../../../../com/adobe/xmp/XMPSchemaRegistry.html#registerAlias(java.lang.String, java.lang.String, java.lang.String, java.lang.String, com.adobe.xmp.options.AliasOptions)">registerAlias</A></B>(java.lang.String&nbsp;aliasNS,
+ java.lang.String&nbsp;aliasProp,
+ java.lang.String&nbsp;actualNS,
+ java.lang.String&nbsp;actualProp,
+ <A HREF="../../../../../com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options">AliasOptions</A>&nbsp;aliasForm)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Associates an alias name with an actual name.</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+<A NAME="com.adobe.xmp.options"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+Uses of <A HREF="../../../../../com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options">AliasOptions</A> in <A HREF="../../../../../com/adobe/xmp/options/package-summary.html">com.adobe.xmp.options</A></FONT></TH>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="left" COLSPAN="2">Methods in <A HREF="../../../../../com/adobe/xmp/options/package-summary.html">com.adobe.xmp.options</A> that return <A HREF="../../../../../com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options">AliasOptions</A></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../../com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options">AliasOptions</A></CODE></FONT></TD>
+<TD><CODE><B>AliasOptions.</B><B><A HREF="../../../../../com/adobe/xmp/options/AliasOptions.html#setArray(boolean)">setArray</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../../com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options">AliasOptions</A></CODE></FONT></TD>
+<TD><CODE><B>AliasOptions.</B><B><A HREF="../../../../../com/adobe/xmp/options/AliasOptions.html#setArrayAlternate(boolean)">setArrayAlternate</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../../com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options">AliasOptions</A></CODE></FONT></TD>
+<TD><CODE><B>AliasOptions.</B><B><A HREF="../../../../../com/adobe/xmp/options/AliasOptions.html#setArrayAltText(boolean)">setArrayAltText</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../../com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options">AliasOptions</A></CODE></FONT></TD>
+<TD><CODE><B>AliasOptions.</B><B><A HREF="../../../../../com/adobe/xmp/options/AliasOptions.html#setArrayOrdered(boolean)">setArrayOrdered</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+<A NAME="com.adobe.xmp.properties"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+Uses of <A HREF="../../../../../com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options">AliasOptions</A> in <A HREF="../../../../../com/adobe/xmp/properties/package-summary.html">com.adobe.xmp.properties</A></FONT></TH>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="left" COLSPAN="2">Methods in <A HREF="../../../../../com/adobe/xmp/properties/package-summary.html">com.adobe.xmp.properties</A> that return <A HREF="../../../../../com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options">AliasOptions</A></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../../com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options">AliasOptions</A></CODE></FONT></TD>
+<TD><CODE><B>XMPAliasInfo.</B><B><A HREF="../../../../../com/adobe/xmp/properties/XMPAliasInfo.html#getAliasForm()">getAliasForm</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options"><FONT CLASS="NavBarFont1"><B>Class</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Use</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../../index.html?com/adobe/xmp/options//class-useAliasOptions.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="AliasOptions.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/com/adobe/xmp/options/class-use/IteratorOptions.html b/java/XMPCore/docs/com/adobe/xmp/options/class-use/IteratorOptions.html
new file mode 100644
index 0000000..02a4726
--- /dev/null
+++ b/java/XMPCore/docs/com/adobe/xmp/options/class-use/IteratorOptions.html
@@ -0,0 +1,239 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:51 CEST 2007 -->
+<TITLE>
+Uses of Class com.adobe.xmp.options.IteratorOptions
+</TITLE>
+
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="Uses of Class com.adobe.xmp.options.IteratorOptions";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options"><FONT CLASS="NavBarFont1"><B>Class</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Use</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../../index.html?com/adobe/xmp/options//class-useIteratorOptions.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="IteratorOptions.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<CENTER>
+<H2>
+<B>Uses of Class<br>com.adobe.xmp.options.IteratorOptions</B></H2>
+</CENTER>
+
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+Packages that use <A HREF="../../../../../com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options">IteratorOptions</A></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><A HREF="#com.adobe.xmp"><B>com.adobe.xmp</B></A></TD>
+<TD>Package containing the xmpcore interface.&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><A HREF="#com.adobe.xmp.options"><B>com.adobe.xmp.options</B></A></TD>
+<TD>Package containing the option classes.&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+<A NAME="com.adobe.xmp"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+Uses of <A HREF="../../../../../com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options">IteratorOptions</A> in <A HREF="../../../../../com/adobe/xmp/package-summary.html">com.adobe.xmp</A></FONT></TH>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="left" COLSPAN="2">Methods in <A HREF="../../../../../com/adobe/xmp/package-summary.html">com.adobe.xmp</A> with parameters of type <A HREF="../../../../../com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options">IteratorOptions</A></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../../com/adobe/xmp/XMPIterator.html" title="interface in com.adobe.xmp">XMPIterator</A></CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../../com/adobe/xmp/XMPMeta.html#iterator(com.adobe.xmp.options.IteratorOptions)">iterator</A></B>(<A HREF="../../../../../com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options">IteratorOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Constructs an iterator for the properties within this XMP object using some options.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../../com/adobe/xmp/XMPIterator.html" title="interface in com.adobe.xmp">XMPIterator</A></CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../../com/adobe/xmp/XMPMeta.html#iterator(java.lang.String, java.lang.String, com.adobe.xmp.options.IteratorOptions)">iterator</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ <A HREF="../../../../../com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options">IteratorOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Construct an iterator for the properties within an XMP object.</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+<A NAME="com.adobe.xmp.options"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+Uses of <A HREF="../../../../../com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options">IteratorOptions</A> in <A HREF="../../../../../com/adobe/xmp/options/package-summary.html">com.adobe.xmp.options</A></FONT></TH>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="left" COLSPAN="2">Methods in <A HREF="../../../../../com/adobe/xmp/options/package-summary.html">com.adobe.xmp.options</A> that return <A HREF="../../../../../com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options">IteratorOptions</A></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../../com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options">IteratorOptions</A></CODE></FONT></TD>
+<TD><CODE><B>IteratorOptions.</B><B><A HREF="../../../../../com/adobe/xmp/options/IteratorOptions.html#setJustChildren(boolean)">setJustChildren</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sets the option and returns the instance.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../../com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options">IteratorOptions</A></CODE></FONT></TD>
+<TD><CODE><B>IteratorOptions.</B><B><A HREF="../../../../../com/adobe/xmp/options/IteratorOptions.html#setJustLeafname(boolean)">setJustLeafname</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sets the option and returns the instance.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../../com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options">IteratorOptions</A></CODE></FONT></TD>
+<TD><CODE><B>IteratorOptions.</B><B><A HREF="../../../../../com/adobe/xmp/options/IteratorOptions.html#setJustLeafnodes(boolean)">setJustLeafnodes</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sets the option and returns the instance.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../../com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options">IteratorOptions</A></CODE></FONT></TD>
+<TD><CODE><B>IteratorOptions.</B><B><A HREF="../../../../../com/adobe/xmp/options/IteratorOptions.html#setOmitQualifiers(boolean)">setOmitQualifiers</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sets the option and returns the instance.</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options"><FONT CLASS="NavBarFont1"><B>Class</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Use</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../../index.html?com/adobe/xmp/options//class-useIteratorOptions.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="IteratorOptions.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/com/adobe/xmp/options/class-use/Options.html b/java/XMPCore/docs/com/adobe/xmp/options/class-use/Options.html
new file mode 100644
index 0000000..57eac1b
--- /dev/null
+++ b/java/XMPCore/docs/com/adobe/xmp/options/class-use/Options.html
@@ -0,0 +1,210 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:51 CEST 2007 -->
+<TITLE>
+Uses of Class com.adobe.xmp.options.Options
+</TITLE>
+
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="Uses of Class com.adobe.xmp.options.Options";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../com/adobe/xmp/options/Options.html" title="class in com.adobe.xmp.options"><FONT CLASS="NavBarFont1"><B>Class</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Use</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../../index.html?com/adobe/xmp/options//class-useOptions.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="Options.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<CENTER>
+<H2>
+<B>Uses of Class<br>com.adobe.xmp.options.Options</B></H2>
+</CENTER>
+
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+Packages that use <A HREF="../../../../../com/adobe/xmp/options/Options.html" title="class in com.adobe.xmp.options">Options</A></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><A HREF="#com.adobe.xmp.options"><B>com.adobe.xmp.options</B></A></TD>
+<TD>Package containing the option classes.&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+<A NAME="com.adobe.xmp.options"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+Uses of <A HREF="../../../../../com/adobe/xmp/options/Options.html" title="class in com.adobe.xmp.options">Options</A> in <A HREF="../../../../../com/adobe/xmp/options/package-summary.html">com.adobe.xmp.options</A></FONT></TH>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="left" COLSPAN="2">Subclasses of <A HREF="../../../../../com/adobe/xmp/options/Options.html" title="class in com.adobe.xmp.options">Options</A> in <A HREF="../../../../../com/adobe/xmp/options/package-summary.html">com.adobe.xmp.options</A></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;class</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../../com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options">AliasOptions</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Options for <A HREF="../../../../../com/adobe/xmp/XMPSchemaRegistry.html#registerAlias(java.lang.String, java.lang.String, java.lang.String, java.lang.String, com.adobe.xmp.options.AliasOptions)"><CODE>XMPSchemaRegistry.registerAlias( String, String, String, String,
+ AliasOptions)</CODE></A>.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;class</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../../com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options">IteratorOptions</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Options for <code>XMPIterator</code> construction.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;class</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options">ParseOptions</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Options for <A HREF="../../../../../com/adobe/xmp/XMPMetaFactory.html#parse(java.io.InputStream, com.adobe.xmp.options.ParseOptions)"><CODE>XMPMetaFactory.parse(InputStream, ParseOptions)</CODE></A>.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;class</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The property flags are used when properties are fetched from the <code>XMPMeta</code>-object
+ and provide more detailed information about the property.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;class</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Options for <A HREF="../../../../../com/adobe/xmp/XMPMetaFactory.html#serializeToBuffer(com.adobe.xmp.XMPMeta, com.adobe.xmp.options.SerializeOptions)"><CODE>XMPMetaFactory.serializeToBuffer(XMPMeta, SerializeOptions)</CODE></A>.</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../com/adobe/xmp/options/Options.html" title="class in com.adobe.xmp.options"><FONT CLASS="NavBarFont1"><B>Class</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Use</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../../index.html?com/adobe/xmp/options//class-useOptions.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="Options.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/com/adobe/xmp/options/class-use/ParseOptions.html b/java/XMPCore/docs/com/adobe/xmp/options/class-use/ParseOptions.html
new file mode 100644
index 0000000..272e344
--- /dev/null
+++ b/java/XMPCore/docs/com/adobe/xmp/options/class-use/ParseOptions.html
@@ -0,0 +1,249 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:51 CEST 2007 -->
+<TITLE>
+Uses of Class com.adobe.xmp.options.ParseOptions
+</TITLE>
+
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="Uses of Class com.adobe.xmp.options.ParseOptions";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options"><FONT CLASS="NavBarFont1"><B>Class</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Use</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../../index.html?com/adobe/xmp/options//class-useParseOptions.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="ParseOptions.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<CENTER>
+<H2>
+<B>Uses of Class<br>com.adobe.xmp.options.ParseOptions</B></H2>
+</CENTER>
+
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+Packages that use <A HREF="../../../../../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options">ParseOptions</A></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><A HREF="#com.adobe.xmp"><B>com.adobe.xmp</B></A></TD>
+<TD>Package containing the xmpcore interface.&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><A HREF="#com.adobe.xmp.options"><B>com.adobe.xmp.options</B></A></TD>
+<TD>Package containing the option classes.&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+<A NAME="com.adobe.xmp"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+Uses of <A HREF="../../../../../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options">ParseOptions</A> in <A HREF="../../../../../com/adobe/xmp/package-summary.html">com.adobe.xmp</A></FONT></TH>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="left" COLSPAN="2">Methods in <A HREF="../../../../../com/adobe/xmp/package-summary.html">com.adobe.xmp</A> with parameters of type <A HREF="../../../../../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options">ParseOptions</A></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;<A HREF="../../../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A></CODE></FONT></TD>
+<TD><CODE><B>XMPMetaFactory.</B><B><A HREF="../../../../../com/adobe/xmp/XMPMetaFactory.html#parse(java.io.InputStream, com.adobe.xmp.options.ParseOptions)">parse</A></B>(java.io.InputStream&nbsp;in,
+ <A HREF="../../../../../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options">ParseOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;These functions support parsing serialized RDF into an XMP object, and serailizing an XMP
+ object into RDF.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;<A HREF="../../../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A></CODE></FONT></TD>
+<TD><CODE><B>XMPMetaFactory.</B><B><A HREF="../../../../../com/adobe/xmp/XMPMetaFactory.html#parseFromBuffer(byte[], com.adobe.xmp.options.ParseOptions)">parseFromBuffer</A></B>(byte[]&nbsp;buffer,
+ <A HREF="../../../../../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options">ParseOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Creates an <code>XMPMeta</code>-object from a byte-buffer.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;<A HREF="../../../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A></CODE></FONT></TD>
+<TD><CODE><B>XMPMetaFactory.</B><B><A HREF="../../../../../com/adobe/xmp/XMPMetaFactory.html#parseFromString(java.lang.String, com.adobe.xmp.options.ParseOptions)">parseFromString</A></B>(java.lang.String&nbsp;packet,
+ <A HREF="../../../../../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options">ParseOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Creates an <code>XMPMeta</code>-object from a string.</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+<A NAME="com.adobe.xmp.options"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+Uses of <A HREF="../../../../../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options">ParseOptions</A> in <A HREF="../../../../../com/adobe/xmp/options/package-summary.html">com.adobe.xmp.options</A></FONT></TH>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="left" COLSPAN="2">Methods in <A HREF="../../../../../com/adobe/xmp/options/package-summary.html">com.adobe.xmp.options</A> that return <A HREF="../../../../../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options">ParseOptions</A></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options">ParseOptions</A></CODE></FONT></TD>
+<TD><CODE><B>ParseOptions.</B><B><A HREF="../../../../../com/adobe/xmp/options/ParseOptions.html#setAcceptLatin1(boolean)">setAcceptLatin1</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options">ParseOptions</A></CODE></FONT></TD>
+<TD><CODE><B>ParseOptions.</B><B><A HREF="../../../../../com/adobe/xmp/options/ParseOptions.html#setFixControlChars(boolean)">setFixControlChars</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options">ParseOptions</A></CODE></FONT></TD>
+<TD><CODE><B>ParseOptions.</B><B><A HREF="../../../../../com/adobe/xmp/options/ParseOptions.html#setRequireXMPMeta(boolean)">setRequireXMPMeta</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options">ParseOptions</A></CODE></FONT></TD>
+<TD><CODE><B>ParseOptions.</B><B><A HREF="../../../../../com/adobe/xmp/options/ParseOptions.html#setStrictAliasing(boolean)">setStrictAliasing</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options"><FONT CLASS="NavBarFont1"><B>Class</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Use</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../../index.html?com/adobe/xmp/options//class-useParseOptions.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="ParseOptions.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/com/adobe/xmp/options/class-use/PropertyOptions.html b/java/XMPCore/docs/com/adobe/xmp/options/class-use/PropertyOptions.html
new file mode 100644
index 0000000..a527b0b
--- /dev/null
+++ b/java/XMPCore/docs/com/adobe/xmp/options/class-use/PropertyOptions.html
@@ -0,0 +1,534 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:51 CEST 2007 -->
+<TITLE>
+Uses of Class com.adobe.xmp.options.PropertyOptions
+</TITLE>
+
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="Uses of Class com.adobe.xmp.options.PropertyOptions";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options"><FONT CLASS="NavBarFont1"><B>Class</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Use</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../../index.html?com/adobe/xmp/options//class-usePropertyOptions.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="PropertyOptions.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<CENTER>
+<H2>
+<B>Uses of Class<br>com.adobe.xmp.options.PropertyOptions</B></H2>
+</CENTER>
+
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+Packages that use <A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><A HREF="#com.adobe.xmp"><B>com.adobe.xmp</B></A></TD>
+<TD>Package containing the xmpcore interface.&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><A HREF="#com.adobe.xmp.options"><B>com.adobe.xmp.options</B></A></TD>
+<TD>Package containing the option classes.&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><A HREF="#com.adobe.xmp.properties"><B>com.adobe.xmp.properties</B></A></TD>
+<TD>Package containing the property information classes.&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+<A NAME="com.adobe.xmp"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+Uses of <A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A> in <A HREF="../../../../../com/adobe/xmp/package-summary.html">com.adobe.xmp</A></FONT></TH>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="left" COLSPAN="2">Methods in <A HREF="../../../../../com/adobe/xmp/package-summary.html">com.adobe.xmp</A> with parameters of type <A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../../com/adobe/xmp/XMPMeta.html#appendArrayItem(java.lang.String, java.lang.String, com.adobe.xmp.options.PropertyOptions, java.lang.String, com.adobe.xmp.options.PropertyOptions)">appendArrayItem</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;arrayName,
+ <A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;arrayOptions,
+ java.lang.String&nbsp;itemValue,
+ <A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;itemOptions)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Simplifies the construction of an array by not requiring that you pre-create an empty array.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../../com/adobe/xmp/XMPMeta.html#insertArrayItem(java.lang.String, java.lang.String, int, java.lang.String, com.adobe.xmp.options.PropertyOptions)">insertArrayItem</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;arrayName,
+ int&nbsp;itemIndex,
+ java.lang.String&nbsp;itemValue,
+ <A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Inserts an item into an array previous to the given index.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPUtils.</B><B><A HREF="../../../../../com/adobe/xmp/XMPUtils.html#separateArrayItems(com.adobe.xmp.XMPMeta, java.lang.String, java.lang.String, java.lang.String, com.adobe.xmp.options.PropertyOptions, boolean)">separateArrayItems</A></B>(<A HREF="../../../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>&nbsp;xmp,
+ java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;arrayName,
+ java.lang.String&nbsp;catedStr,
+ <A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;arrayOptions,
+ boolean&nbsp;preserveCommas)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Separate a single edit string into an array of strings.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../../com/adobe/xmp/XMPMeta.html#setArrayItem(java.lang.String, java.lang.String, int, java.lang.String, com.adobe.xmp.options.PropertyOptions)">setArrayItem</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;arrayName,
+ int&nbsp;itemIndex,
+ java.lang.String&nbsp;itemValue,
+ <A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Replaces an item within an array.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../../com/adobe/xmp/XMPMeta.html#setLocalizedText(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, com.adobe.xmp.options.PropertyOptions)">setLocalizedText</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;altTextName,
+ java.lang.String&nbsp;genericLang,
+ java.lang.String&nbsp;specificLang,
+ java.lang.String&nbsp;itemValue,
+ <A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Modifies the value of a selected item in an alt-text array.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../../com/adobe/xmp/XMPMeta.html#setProperty(java.lang.String, java.lang.String, java.lang.Object, com.adobe.xmp.options.PropertyOptions)">setProperty</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ java.lang.Object&nbsp;propValue,
+ <A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The property value <code>setters</code> all take a property specification, their
+ differences are in the form of this.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../../com/adobe/xmp/XMPMeta.html#setPropertyBase64(java.lang.String, java.lang.String, byte[], com.adobe.xmp.options.PropertyOptions)">setPropertyBase64</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ byte[]&nbsp;propValue,
+ <A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convenience method to set a property from a binary <code>byte[]</code>-array,
+ which is serialized as base64-string.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../../com/adobe/xmp/XMPMeta.html#setPropertyBoolean(java.lang.String, java.lang.String, boolean, com.adobe.xmp.options.PropertyOptions)">setPropertyBoolean</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ boolean&nbsp;propValue,
+ <A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convenience method to set a property to a literal <code>boolean</code> value.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../../com/adobe/xmp/XMPMeta.html#setPropertyCalendar(java.lang.String, java.lang.String, java.util.Calendar, com.adobe.xmp.options.PropertyOptions)">setPropertyCalendar</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ java.util.Calendar&nbsp;propValue,
+ <A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convenience method to set a property with a Java Calendar-object,
+ which is serialized to an ISO8601 date.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../../com/adobe/xmp/XMPMeta.html#setPropertyDate(java.lang.String, java.lang.String, com.adobe.xmp.XMPDateTime, com.adobe.xmp.options.PropertyOptions)">setPropertyDate</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ <A HREF="../../../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A>&nbsp;propValue,
+ <A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convenience method to set a property with an XMPDateTime-object,
+ which is serialized to an ISO8601 date.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../../com/adobe/xmp/XMPMeta.html#setPropertyDouble(java.lang.String, java.lang.String, double, com.adobe.xmp.options.PropertyOptions)">setPropertyDouble</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ double&nbsp;propValue,
+ <A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convenience method to set a property to a literal <code>double</code> value.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../../com/adobe/xmp/XMPMeta.html#setPropertyInteger(java.lang.String, java.lang.String, int, com.adobe.xmp.options.PropertyOptions)">setPropertyInteger</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ int&nbsp;propValue,
+ <A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convenience method to set a property to a literal <code>int</code> value.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../../com/adobe/xmp/XMPMeta.html#setPropertyLong(java.lang.String, java.lang.String, long, com.adobe.xmp.options.PropertyOptions)">setPropertyLong</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ long&nbsp;propValue,
+ <A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convenience method to set a property to a literal <code>long</code> value.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../../com/adobe/xmp/XMPMeta.html#setQualifier(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, com.adobe.xmp.options.PropertyOptions)">setQualifier</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ java.lang.String&nbsp;qualNS,
+ java.lang.String&nbsp;qualName,
+ java.lang.String&nbsp;qualValue,
+ <A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Provides access to a qualifier attached to a property.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../../com/adobe/xmp/XMPMeta.html#setStructField(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, com.adobe.xmp.options.PropertyOptions)">setStructField</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;structName,
+ java.lang.String&nbsp;fieldNS,
+ java.lang.String&nbsp;fieldName,
+ java.lang.String&nbsp;fieldValue,
+ <A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Provides access to fields within a nested structure.</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+<A NAME="com.adobe.xmp.options"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+Uses of <A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A> in <A HREF="../../../../../com/adobe/xmp/options/package-summary.html">com.adobe.xmp.options</A></FONT></TH>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="left" COLSPAN="2">Methods in <A HREF="../../../../../com/adobe/xmp/options/package-summary.html">com.adobe.xmp.options</A> that return <A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A></CODE></FONT></TD>
+<TD><CODE><B>PropertyOptions.</B><B><A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html#setArray(boolean)">setArray</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A></CODE></FONT></TD>
+<TD><CODE><B>PropertyOptions.</B><B><A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html#setArrayAlternate(boolean)">setArrayAlternate</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A></CODE></FONT></TD>
+<TD><CODE><B>PropertyOptions.</B><B><A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html#setArrayAltText(boolean)">setArrayAltText</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A></CODE></FONT></TD>
+<TD><CODE><B>PropertyOptions.</B><B><A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html#setArrayOrdered(boolean)">setArrayOrdered</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A></CODE></FONT></TD>
+<TD><CODE><B>PropertyOptions.</B><B><A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html#setCompact(boolean)">setCompact</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A></CODE></FONT></TD>
+<TD><CODE><B>PropertyOptions.</B><B><A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html#setHasLanguage(boolean)">setHasLanguage</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A></CODE></FONT></TD>
+<TD><CODE><B>PropertyOptions.</B><B><A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html#setHasQualifiers(boolean)">setHasQualifiers</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A></CODE></FONT></TD>
+<TD><CODE><B>PropertyOptions.</B><B><A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html#setHasType(boolean)">setHasType</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A></CODE></FONT></TD>
+<TD><CODE><B>PropertyOptions.</B><B><A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html#setQualifier(boolean)">setQualifier</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A></CODE></FONT></TD>
+<TD><CODE><B>PropertyOptions.</B><B><A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html#setSchemaNode(boolean)">setSchemaNode</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A></CODE></FONT></TD>
+<TD><CODE><B>PropertyOptions.</B><B><A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html#setStruct(boolean)">setStruct</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A></CODE></FONT></TD>
+<TD><CODE><B>PropertyOptions.</B><B><A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html#setURI(boolean)">setURI</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A></CODE></FONT></TD>
+<TD><CODE><B>AliasOptions.</B><B><A HREF="../../../../../com/adobe/xmp/options/AliasOptions.html#toPropertyOptions()">toPropertyOptions</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="left" COLSPAN="2">Methods in <A HREF="../../../../../com/adobe/xmp/options/package-summary.html">com.adobe.xmp.options</A> with parameters of type <A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B>PropertyOptions.</B><B><A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html#equalArrayTypes(com.adobe.xmp.options.PropertyOptions)">equalArrayTypes</A></B>(<A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Compares two options set for array compatibility.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>PropertyOptions.</B><B><A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html#mergeWith(com.adobe.xmp.options.PropertyOptions)">mergeWith</A></B>(<A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Merges the set options of a another options object with this.</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+<A NAME="com.adobe.xmp.properties"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+Uses of <A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A> in <A HREF="../../../../../com/adobe/xmp/properties/package-summary.html">com.adobe.xmp.properties</A></FONT></TH>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="left" COLSPAN="2">Methods in <A HREF="../../../../../com/adobe/xmp/properties/package-summary.html">com.adobe.xmp.properties</A> that return <A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A></CODE></FONT></TD>
+<TD><CODE><B>XMPPropertyInfo.</B><B><A HREF="../../../../../com/adobe/xmp/properties/XMPPropertyInfo.html#getOptions()">getOptions</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A></CODE></FONT></TD>
+<TD><CODE><B>XMPProperty.</B><B><A HREF="../../../../../com/adobe/xmp/properties/XMPProperty.html#getOptions()">getOptions</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options"><FONT CLASS="NavBarFont1"><B>Class</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Use</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../../index.html?com/adobe/xmp/options//class-usePropertyOptions.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="PropertyOptions.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/com/adobe/xmp/options/class-use/SerializeOptions.html b/java/XMPCore/docs/com/adobe/xmp/options/class-use/SerializeOptions.html
new file mode 100644
index 0000000..057c96e
--- /dev/null
+++ b/java/XMPCore/docs/com/adobe/xmp/options/class-use/SerializeOptions.html
@@ -0,0 +1,321 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:51 CEST 2007 -->
+<TITLE>
+Uses of Class com.adobe.xmp.options.SerializeOptions
+</TITLE>
+
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="Uses of Class com.adobe.xmp.options.SerializeOptions";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options"><FONT CLASS="NavBarFont1"><B>Class</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Use</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../../index.html?com/adobe/xmp/options//class-useSerializeOptions.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="SerializeOptions.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<CENTER>
+<H2>
+<B>Uses of Class<br>com.adobe.xmp.options.SerializeOptions</B></H2>
+</CENTER>
+
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+Packages that use <A HREF="../../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><A HREF="#com.adobe.xmp"><B>com.adobe.xmp</B></A></TD>
+<TD>Package containing the xmpcore interface.&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><A HREF="#com.adobe.xmp.options"><B>com.adobe.xmp.options</B></A></TD>
+<TD>Package containing the option classes.&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+<A NAME="com.adobe.xmp"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+Uses of <A HREF="../../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A> in <A HREF="../../../../../com/adobe/xmp/package-summary.html">com.adobe.xmp</A></FONT></TH>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="left" COLSPAN="2">Methods in <A HREF="../../../../../com/adobe/xmp/package-summary.html">com.adobe.xmp</A> with parameters of type <A HREF="../../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B>XMPMetaFactory.</B><B><A HREF="../../../../../com/adobe/xmp/XMPMetaFactory.html#serialize(com.adobe.xmp.XMPMeta, java.io.OutputStream, com.adobe.xmp.options.SerializeOptions)">serialize</A></B>(<A HREF="../../../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>&nbsp;xmp,
+ java.io.OutputStream&nbsp;out,
+ <A HREF="../../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Serializes an <code>XMPMeta</code>-object as RDF into an <code>OutputStream</code>.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;byte[]</CODE></FONT></TD>
+<TD><CODE><B>XMPMetaFactory.</B><B><A HREF="../../../../../com/adobe/xmp/XMPMetaFactory.html#serializeToBuffer(com.adobe.xmp.XMPMeta, com.adobe.xmp.options.SerializeOptions)">serializeToBuffer</A></B>(<A HREF="../../../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>&nbsp;xmp,
+ <A HREF="../../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Serializes an <code>XMPMeta</code>-object as RDF into a byte buffer.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B>XMPMetaFactory.</B><B><A HREF="../../../../../com/adobe/xmp/XMPMetaFactory.html#serializeToString(com.adobe.xmp.XMPMeta, com.adobe.xmp.options.SerializeOptions)">serializeToString</A></B>(<A HREF="../../../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>&nbsp;xmp,
+ <A HREF="../../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Serializes an <code>XMPMeta</code>-object as RDF into a string.</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+<A NAME="com.adobe.xmp.options"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+Uses of <A HREF="../../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A> in <A HREF="../../../../../com/adobe/xmp/options/package-summary.html">com.adobe.xmp.options</A></FONT></TH>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="left" COLSPAN="2">Methods in <A HREF="../../../../../com/adobe/xmp/options/package-summary.html">com.adobe.xmp.options</A> that return <A HREF="../../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A></CODE></FONT></TD>
+<TD><CODE><B>SerializeOptions.</B><B><A HREF="../../../../../com/adobe/xmp/options/SerializeOptions.html#setBaseIndent(int)">setBaseIndent</A></B>(int&nbsp;baseIndent)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A></CODE></FONT></TD>
+<TD><CODE><B>SerializeOptions.</B><B><A HREF="../../../../../com/adobe/xmp/options/SerializeOptions.html#setEncodeUTF16BE(boolean)">setEncodeUTF16BE</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A></CODE></FONT></TD>
+<TD><CODE><B>SerializeOptions.</B><B><A HREF="../../../../../com/adobe/xmp/options/SerializeOptions.html#setEncodeUTF16LE(boolean)">setEncodeUTF16LE</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A></CODE></FONT></TD>
+<TD><CODE><B>SerializeOptions.</B><B><A HREF="../../../../../com/adobe/xmp/options/SerializeOptions.html#setExactPacketLength(boolean)">setExactPacketLength</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A></CODE></FONT></TD>
+<TD><CODE><B>SerializeOptions.</B><B><A HREF="../../../../../com/adobe/xmp/options/SerializeOptions.html#setIncludeThumbnailPad(boolean)">setIncludeThumbnailPad</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A></CODE></FONT></TD>
+<TD><CODE><B>SerializeOptions.</B><B><A HREF="../../../../../com/adobe/xmp/options/SerializeOptions.html#setIndent(java.lang.String)">setIndent</A></B>(java.lang.String&nbsp;indent)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A></CODE></FONT></TD>
+<TD><CODE><B>SerializeOptions.</B><B><A HREF="../../../../../com/adobe/xmp/options/SerializeOptions.html#setNewline(java.lang.String)">setNewline</A></B>(java.lang.String&nbsp;newline)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A></CODE></FONT></TD>
+<TD><CODE><B>SerializeOptions.</B><B><A HREF="../../../../../com/adobe/xmp/options/SerializeOptions.html#setOmitPacketWrapper(boolean)">setOmitPacketWrapper</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A></CODE></FONT></TD>
+<TD><CODE><B>SerializeOptions.</B><B><A HREF="../../../../../com/adobe/xmp/options/SerializeOptions.html#setPadding(int)">setPadding</A></B>(int&nbsp;padding)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A></CODE></FONT></TD>
+<TD><CODE><B>SerializeOptions.</B><B><A HREF="../../../../../com/adobe/xmp/options/SerializeOptions.html#setReadOnlyPacket(boolean)">setReadOnlyPacket</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A></CODE></FONT></TD>
+<TD><CODE><B>SerializeOptions.</B><B><A HREF="../../../../../com/adobe/xmp/options/SerializeOptions.html#setSort(boolean)">setSort</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A></CODE></FONT></TD>
+<TD><CODE><B>SerializeOptions.</B><B><A HREF="../../../../../com/adobe/xmp/options/SerializeOptions.html#setUseCompactFormat(boolean)">setUseCompactFormat</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A></CODE></FONT></TD>
+<TD><CODE><B>SerializeOptions.</B><B><A HREF="../../../../../com/adobe/xmp/options/SerializeOptions.html#setWriteAliasComments(boolean)">setWriteAliasComments</A></B>(boolean&nbsp;value)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<em>Note:</em> This options is not supported at the moment.</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options"><FONT CLASS="NavBarFont1"><B>Class</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Use</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../../index.html?com/adobe/xmp/options//class-useSerializeOptions.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="SerializeOptions.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/com/adobe/xmp/options/package-frame.html b/java/XMPCore/docs/com/adobe/xmp/options/package-frame.html
new file mode 100644
index 0000000..b9239df
--- /dev/null
+++ b/java/XMPCore/docs/com/adobe/xmp/options/package-frame.html
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:50 CEST 2007 -->
+<TITLE>
+com.adobe.xmp.options
+</TITLE>
+
+<META NAME="keywords" CONTENT="com.adobe.xmp.options package">
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../stylesheet.css" TITLE="Style">
+
+
+</HEAD>
+
+<BODY BGCOLOR="white">
+<FONT size="+1" CLASS="FrameTitleFont">
+<A HREF="../../../../com/adobe/xmp/options/package-summary.html" target="classFrame">com.adobe.xmp.options</A></FONT>
+<TABLE BORDER="0" WIDTH="100%" SUMMARY="">
+<TR>
+<TD NOWRAP><FONT size="+1" CLASS="FrameHeadingFont">
+Classes</FONT>&nbsp;
+<FONT CLASS="FrameItemFont">
+<BR>
+<A HREF="AliasOptions.html" title="class in com.adobe.xmp.options" target="classFrame">AliasOptions</A>
+<BR>
+<A HREF="IteratorOptions.html" title="class in com.adobe.xmp.options" target="classFrame">IteratorOptions</A>
+<BR>
+<A HREF="Options.html" title="class in com.adobe.xmp.options" target="classFrame">Options</A>
+<BR>
+<A HREF="ParseOptions.html" title="class in com.adobe.xmp.options" target="classFrame">ParseOptions</A>
+<BR>
+<A HREF="PropertyOptions.html" title="class in com.adobe.xmp.options" target="classFrame">PropertyOptions</A>
+<BR>
+<A HREF="SerializeOptions.html" title="class in com.adobe.xmp.options" target="classFrame">SerializeOptions</A></FONT></TD>
+</TR>
+</TABLE>
+
+
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/com/adobe/xmp/options/package-summary.html b/java/XMPCore/docs/com/adobe/xmp/options/package-summary.html
new file mode 100644
index 0000000..42e51e2
--- /dev/null
+++ b/java/XMPCore/docs/com/adobe/xmp/options/package-summary.html
@@ -0,0 +1,200 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:50 CEST 2007 -->
+<TITLE>
+com.adobe.xmp.options
+</TITLE>
+
+<META NAME="keywords" CONTENT="com.adobe.xmp.options package">
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="com.adobe.xmp.options";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Package</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-use.html"><FONT CLASS="NavBarFont1"><B>Use</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="../../../../com/adobe/xmp/package-summary.html"><B>PREV PACKAGE</B></A>&nbsp;
+&nbsp;<A HREF="../../../../com/adobe/xmp/properties/package-summary.html"><B>NEXT PACKAGE</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../index.html?com/adobe/xmp/options/package-summary.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="package-summary.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<H2>
+Package com.adobe.xmp.options
+</H2>
+Package containing the option classes.
+<P>
+<B>See:</B>
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<A HREF="#package_description"><B>Description</B></A>
+<P>
+
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+<B>Class Summary</B></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD WIDTH="15%"><B><A HREF="../../../../com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options">AliasOptions</A></B></TD>
+<TD>Options for <A HREF="../../../../com/adobe/xmp/XMPSchemaRegistry.html#registerAlias(java.lang.String, java.lang.String, java.lang.String, java.lang.String, com.adobe.xmp.options.AliasOptions)"><CODE>XMPSchemaRegistry.registerAlias( String, String, String, String,
+ AliasOptions)</CODE></A>.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD WIDTH="15%"><B><A HREF="../../../../com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options">IteratorOptions</A></B></TD>
+<TD>Options for <code>XMPIterator</code> construction.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD WIDTH="15%"><B><A HREF="../../../../com/adobe/xmp/options/Options.html" title="class in com.adobe.xmp.options">Options</A></B></TD>
+<TD>The base class for a collection of 32 flag bits.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD WIDTH="15%"><B><A HREF="../../../../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options">ParseOptions</A></B></TD>
+<TD>Options for <A HREF="../../../../com/adobe/xmp/XMPMetaFactory.html#parse(java.io.InputStream, com.adobe.xmp.options.ParseOptions)"><CODE>XMPMetaFactory.parse(InputStream, ParseOptions)</CODE></A>.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD WIDTH="15%"><B><A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A></B></TD>
+<TD>The property flags are used when properties are fetched from the <code>XMPMeta</code>-object
+ and provide more detailed information about the property.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD WIDTH="15%"><B><A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A></B></TD>
+<TD>Options for <A HREF="../../../../com/adobe/xmp/XMPMetaFactory.html#serializeToBuffer(com.adobe.xmp.XMPMeta, com.adobe.xmp.options.SerializeOptions)"><CODE>XMPMetaFactory.serializeToBuffer(XMPMeta, SerializeOptions)</CODE></A>.</TD>
+</TR>
+</TABLE>
+&nbsp;
+
+<P>
+<A NAME="package_description"><!-- --></A><H2>
+Package com.adobe.xmp.options Description
+</H2>
+
+<P>
+<p>Package containing the option classes.</p>
+ <p>These are used to configure diverse function calls of xmpcore:<p>
+ <ul>
+ <li>PropertyOptions - these are used to create properties and also to retrieve information about simple, array or struct properties, as well as qualifiers
+ <li>ParseOptions - used to configure the parsing of xmp metadata packets
+ <li>SerializationOptions - used to control the serialization of xmp metadata packets
+ <li>AliasOptions - used by XMPSchemaRegistry#registerAlias()
+ <li>IteratorOptions - used to set up an XMPIterator
+ <li>Options - the base class of all option classes
+ </ul>
+<P>
+
+<P>
+<DL>
+</DL>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Package</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-use.html"><FONT CLASS="NavBarFont1"><B>Use</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="../../../../com/adobe/xmp/package-summary.html"><B>PREV PACKAGE</B></A>&nbsp;
+&nbsp;<A HREF="../../../../com/adobe/xmp/properties/package-summary.html"><B>NEXT PACKAGE</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../index.html?com/adobe/xmp/options/package-summary.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="package-summary.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/com/adobe/xmp/options/package-tree.html b/java/XMPCore/docs/com/adobe/xmp/options/package-tree.html
new file mode 100644
index 0000000..79322e0
--- /dev/null
+++ b/java/XMPCore/docs/com/adobe/xmp/options/package-tree.html
@@ -0,0 +1,151 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:50 CEST 2007 -->
+<TITLE>
+com.adobe.xmp.options Class Hierarchy
+</TITLE>
+
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="com.adobe.xmp.options Class Hierarchy";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Tree</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="../../../../com/adobe/xmp/package-tree.html"><B>PREV</B></A>&nbsp;
+&nbsp;<A HREF="../../../../com/adobe/xmp/properties/package-tree.html"><B>NEXT</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../index.html?com/adobe/xmp/options/package-tree.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="package-tree.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<CENTER>
+<H2>
+Hierarchy For Package com.adobe.xmp.options
+</H2>
+</CENTER>
+<DL>
+<DT><B>Package Hierarchies:</B><DD><A HREF="../../../../overview-tree.html">All Packages</A></DL>
+<HR>
+<H2>
+Class Hierarchy
+</H2>
+<UL>
+<LI TYPE="circle">java.lang.Object<UL>
+<LI TYPE="circle">com.adobe.xmp.options.<A HREF="../../../../com/adobe/xmp/options/Options.html" title="class in com.adobe.xmp.options"><B>Options</B></A><UL>
+<LI TYPE="circle">com.adobe.xmp.options.<A HREF="../../../../com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options"><B>AliasOptions</B></A><LI TYPE="circle">com.adobe.xmp.options.<A HREF="../../../../com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options"><B>IteratorOptions</B></A><LI TYPE="circle">com.adobe.xmp.options.<A HREF="../../../../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options"><B>ParseOptions</B></A><LI TYPE="circle">com.adobe.xmp.options.<A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options"><B>PropertyOptions</B></A><LI TYPE="circle">com.adobe.xmp.options.<A HREF="../../../../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options"><B>SerializeOptions</B></A></UL>
+</UL>
+</UL>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Tree</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="../../../../com/adobe/xmp/package-tree.html"><B>PREV</B></A>&nbsp;
+&nbsp;<A HREF="../../../../com/adobe/xmp/properties/package-tree.html"><B>NEXT</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../index.html?com/adobe/xmp/options/package-tree.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="package-tree.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/com/adobe/xmp/options/package-use.html b/java/XMPCore/docs/com/adobe/xmp/options/package-use.html
new file mode 100644
index 0000000..5736c28
--- /dev/null
+++ b/java/XMPCore/docs/com/adobe/xmp/options/package-use.html
@@ -0,0 +1,270 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:51 CEST 2007 -->
+<TITLE>
+Uses of Package com.adobe.xmp.options
+</TITLE>
+
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="Uses of Package com.adobe.xmp.options";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Use</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../index.html?com/adobe/xmp/options/package-use.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="package-use.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<CENTER>
+<H2>
+<B>Uses of Package<br>com.adobe.xmp.options</B></H2>
+</CENTER>
+
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+Packages that use <A HREF="../../../../com/adobe/xmp/options/package-summary.html">com.adobe.xmp.options</A></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><A HREF="#com.adobe.xmp"><B>com.adobe.xmp</B></A></TD>
+<TD>Package containing the xmpcore interface.&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><A HREF="#com.adobe.xmp.options"><B>com.adobe.xmp.options</B></A></TD>
+<TD>Package containing the option classes.&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><A HREF="#com.adobe.xmp.properties"><B>com.adobe.xmp.properties</B></A></TD>
+<TD>Package containing the property information classes.&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+<A NAME="com.adobe.xmp"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+Classes in <A HREF="../../../../com/adobe/xmp/options/package-summary.html">com.adobe.xmp.options</A> used by <A HREF="../../../../com/adobe/xmp/package-summary.html">com.adobe.xmp</A></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><B><A HREF="../../../../com/adobe/xmp/options/class-use/AliasOptions.html#com.adobe.xmp"><B>AliasOptions</B></A></B>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Options for <A HREF="../../../../com/adobe/xmp/XMPSchemaRegistry.html#registerAlias(java.lang.String, java.lang.String, java.lang.String, java.lang.String, com.adobe.xmp.options.AliasOptions)"><CODE>XMPSchemaRegistry.registerAlias( String, String, String, String,
+ AliasOptions)</CODE></A>.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><B><A HREF="../../../../com/adobe/xmp/options/class-use/IteratorOptions.html#com.adobe.xmp"><B>IteratorOptions</B></A></B>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Options for <code>XMPIterator</code> construction.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><B><A HREF="../../../../com/adobe/xmp/options/class-use/ParseOptions.html#com.adobe.xmp"><B>ParseOptions</B></A></B>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Options for <A HREF="../../../../com/adobe/xmp/XMPMetaFactory.html#parse(java.io.InputStream, com.adobe.xmp.options.ParseOptions)"><CODE>XMPMetaFactory.parse(InputStream, ParseOptions)</CODE></A>.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><B><A HREF="../../../../com/adobe/xmp/options/class-use/PropertyOptions.html#com.adobe.xmp"><B>PropertyOptions</B></A></B>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The property flags are used when properties are fetched from the <code>XMPMeta</code>-object
+ and provide more detailed information about the property.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><B><A HREF="../../../../com/adobe/xmp/options/class-use/SerializeOptions.html#com.adobe.xmp"><B>SerializeOptions</B></A></B>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Options for <A HREF="../../../../com/adobe/xmp/XMPMetaFactory.html#serializeToBuffer(com.adobe.xmp.XMPMeta, com.adobe.xmp.options.SerializeOptions)"><CODE>XMPMetaFactory.serializeToBuffer(XMPMeta, SerializeOptions)</CODE></A>.</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+<A NAME="com.adobe.xmp.options"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+Classes in <A HREF="../../../../com/adobe/xmp/options/package-summary.html">com.adobe.xmp.options</A> used by <A HREF="../../../../com/adobe/xmp/options/package-summary.html">com.adobe.xmp.options</A></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><B><A HREF="../../../../com/adobe/xmp/options/class-use/AliasOptions.html#com.adobe.xmp.options"><B>AliasOptions</B></A></B>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Options for <A HREF="../../../../com/adobe/xmp/XMPSchemaRegistry.html#registerAlias(java.lang.String, java.lang.String, java.lang.String, java.lang.String, com.adobe.xmp.options.AliasOptions)"><CODE>XMPSchemaRegistry.registerAlias( String, String, String, String,
+ AliasOptions)</CODE></A>.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><B><A HREF="../../../../com/adobe/xmp/options/class-use/IteratorOptions.html#com.adobe.xmp.options"><B>IteratorOptions</B></A></B>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Options for <code>XMPIterator</code> construction.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><B><A HREF="../../../../com/adobe/xmp/options/class-use/Options.html#com.adobe.xmp.options"><B>Options</B></A></B>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The base class for a collection of 32 flag bits.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><B><A HREF="../../../../com/adobe/xmp/options/class-use/ParseOptions.html#com.adobe.xmp.options"><B>ParseOptions</B></A></B>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Options for <A HREF="../../../../com/adobe/xmp/XMPMetaFactory.html#parse(java.io.InputStream, com.adobe.xmp.options.ParseOptions)"><CODE>XMPMetaFactory.parse(InputStream, ParseOptions)</CODE></A>.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><B><A HREF="../../../../com/adobe/xmp/options/class-use/PropertyOptions.html#com.adobe.xmp.options"><B>PropertyOptions</B></A></B>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The property flags are used when properties are fetched from the <code>XMPMeta</code>-object
+ and provide more detailed information about the property.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><B><A HREF="../../../../com/adobe/xmp/options/class-use/SerializeOptions.html#com.adobe.xmp.options"><B>SerializeOptions</B></A></B>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Options for <A HREF="../../../../com/adobe/xmp/XMPMetaFactory.html#serializeToBuffer(com.adobe.xmp.XMPMeta, com.adobe.xmp.options.SerializeOptions)"><CODE>XMPMetaFactory.serializeToBuffer(XMPMeta, SerializeOptions)</CODE></A>.</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+<A NAME="com.adobe.xmp.properties"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+Classes in <A HREF="../../../../com/adobe/xmp/options/package-summary.html">com.adobe.xmp.options</A> used by <A HREF="../../../../com/adobe/xmp/properties/package-summary.html">com.adobe.xmp.properties</A></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><B><A HREF="../../../../com/adobe/xmp/options/class-use/AliasOptions.html#com.adobe.xmp.properties"><B>AliasOptions</B></A></B>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Options for <A HREF="../../../../com/adobe/xmp/XMPSchemaRegistry.html#registerAlias(java.lang.String, java.lang.String, java.lang.String, java.lang.String, com.adobe.xmp.options.AliasOptions)"><CODE>XMPSchemaRegistry.registerAlias( String, String, String, String,
+ AliasOptions)</CODE></A>.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><B><A HREF="../../../../com/adobe/xmp/options/class-use/PropertyOptions.html#com.adobe.xmp.properties"><B>PropertyOptions</B></A></B>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The property flags are used when properties are fetched from the <code>XMPMeta</code>-object
+ and provide more detailed information about the property.</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Use</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../index.html?com/adobe/xmp/options/package-use.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="package-use.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/com/adobe/xmp/package-frame.html b/java/XMPCore/docs/com/adobe/xmp/package-frame.html
new file mode 100644
index 0000000..763422a
--- /dev/null
+++ b/java/XMPCore/docs/com/adobe/xmp/package-frame.html
@@ -0,0 +1,72 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:50 CEST 2007 -->
+<TITLE>
+com.adobe.xmp
+</TITLE>
+
+<META NAME="keywords" CONTENT="com.adobe.xmp package">
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../stylesheet.css" TITLE="Style">
+
+
+</HEAD>
+
+<BODY BGCOLOR="white">
+<FONT size="+1" CLASS="FrameTitleFont">
+<A HREF="../../../com/adobe/xmp/package-summary.html" target="classFrame">com.adobe.xmp</A></FONT>
+<TABLE BORDER="0" WIDTH="100%" SUMMARY="">
+<TR>
+<TD NOWRAP><FONT size="+1" CLASS="FrameHeadingFont">
+Interfaces</FONT>&nbsp;
+<FONT CLASS="FrameItemFont">
+<BR>
+<A HREF="XMPConst.html" title="interface in com.adobe.xmp" target="classFrame"><I>XMPConst</I></A>
+<BR>
+<A HREF="XMPDateTime.html" title="interface in com.adobe.xmp" target="classFrame"><I>XMPDateTime</I></A>
+<BR>
+<A HREF="XMPError.html" title="interface in com.adobe.xmp" target="classFrame"><I>XMPError</I></A>
+<BR>
+<A HREF="XMPIterator.html" title="interface in com.adobe.xmp" target="classFrame"><I>XMPIterator</I></A>
+<BR>
+<A HREF="XMPMeta.html" title="interface in com.adobe.xmp" target="classFrame"><I>XMPMeta</I></A>
+<BR>
+<A HREF="XMPSchemaRegistry.html" title="interface in com.adobe.xmp" target="classFrame"><I>XMPSchemaRegistry</I></A>
+<BR>
+<A HREF="XMPVersionInfo.html" title="interface in com.adobe.xmp" target="classFrame"><I>XMPVersionInfo</I></A></FONT></TD>
+</TR>
+</TABLE>
+
+
+<TABLE BORDER="0" WIDTH="100%" SUMMARY="">
+<TR>
+<TD NOWRAP><FONT size="+1" CLASS="FrameHeadingFont">
+Classes</FONT>&nbsp;
+<FONT CLASS="FrameItemFont">
+<BR>
+<A HREF="XMPDateTimeFactory.html" title="class in com.adobe.xmp" target="classFrame">XMPDateTimeFactory</A>
+<BR>
+<A HREF="XMPMetaFactory.html" title="class in com.adobe.xmp" target="classFrame">XMPMetaFactory</A>
+<BR>
+<A HREF="XMPPathFactory.html" title="class in com.adobe.xmp" target="classFrame">XMPPathFactory</A>
+<BR>
+<A HREF="XMPUtils.html" title="class in com.adobe.xmp" target="classFrame">XMPUtils</A></FONT></TD>
+</TR>
+</TABLE>
+
+
+<TABLE BORDER="0" WIDTH="100%" SUMMARY="">
+<TR>
+<TD NOWRAP><FONT size="+1" CLASS="FrameHeadingFont">
+Exceptions</FONT>&nbsp;
+<FONT CLASS="FrameItemFont">
+<BR>
+<A HREF="XMPException.html" title="class in com.adobe.xmp" target="classFrame">XMPException</A></FONT></TD>
+</TR>
+</TABLE>
+
+
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/com/adobe/xmp/package-summary.html b/java/XMPCore/docs/com/adobe/xmp/package-summary.html
new file mode 100644
index 0000000..dff25be
--- /dev/null
+++ b/java/XMPCore/docs/com/adobe/xmp/package-summary.html
@@ -0,0 +1,240 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:50 CEST 2007 -->
+<TITLE>
+com.adobe.xmp
+</TITLE>
+
+<META NAME="keywords" CONTENT="com.adobe.xmp package">
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="com.adobe.xmp";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Package</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-use.html"><FONT CLASS="NavBarFont1"><B>Use</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV PACKAGE&nbsp;
+&nbsp;<A HREF="../../../com/adobe/xmp/options/package-summary.html"><B>NEXT PACKAGE</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../index.html?com/adobe/xmp/package-summary.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="package-summary.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<H2>
+Package com.adobe.xmp
+</H2>
+Package containing the xmpcore interface.
+<P>
+<B>See:</B>
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<A HREF="#package_description"><B>Description</B></A>
+<P>
+
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+<B>Interface Summary</B></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD WIDTH="15%"><B><A HREF="../../../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A></B></TD>
+<TD>Common constants for the XMP Toolkit.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD WIDTH="15%"><B><A HREF="../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A></B></TD>
+<TD>The <code>XMPDateTime</code>-class represents a point in time up to a resolution of nano
+ seconds.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD WIDTH="15%"><B><A HREF="../../../com/adobe/xmp/XMPError.html" title="interface in com.adobe.xmp">XMPError</A></B></TD>
+<TD>&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD WIDTH="15%"><B><A HREF="../../../com/adobe/xmp/XMPIterator.html" title="interface in com.adobe.xmp">XMPIterator</A></B></TD>
+<TD>Interface for the <code>XMPMeta</code> iteration services.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD WIDTH="15%"><B><A HREF="../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A></B></TD>
+<TD>This class represents the set of XMP metadata as a DOM representation.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD WIDTH="15%"><B><A HREF="../../../com/adobe/xmp/XMPSchemaRegistry.html" title="interface in com.adobe.xmp">XMPSchemaRegistry</A></B></TD>
+<TD>The schema registry keeps track of all namespaces and aliases used in the XMP
+ metadata.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD WIDTH="15%"><B><A HREF="../../../com/adobe/xmp/XMPVersionInfo.html" title="interface in com.adobe.xmp">XMPVersionInfo</A></B></TD>
+<TD>XMP Toolkit Version Information
+
+ Version information for the XMP toolkit is stored in the jar-library and available through a
+ runtime call, <A HREF="../../../com/adobe/xmp/XMPMetaFactory.html#getVersionInfo()"><CODE>XMPMetaFactory.getVersionInfo()</CODE></A>, addition static version numbers are
+ defined in "version.properties".</TD>
+</TR>
+</TABLE>
+&nbsp;
+
+<P>
+
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+<B>Class Summary</B></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD WIDTH="15%"><B><A HREF="../../../com/adobe/xmp/XMPDateTimeFactory.html" title="class in com.adobe.xmp">XMPDateTimeFactory</A></B></TD>
+<TD>A factory to create <code>XMPDateTime</code>-instances from a <code>Calendar</code> or an
+ ISO 8601 string or for the current time.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD WIDTH="15%"><B><A HREF="../../../com/adobe/xmp/XMPMetaFactory.html" title="class in com.adobe.xmp">XMPMetaFactory</A></B></TD>
+<TD>Creates <code>XMPMeta</code>-instances from an <code>InputStream</code></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD WIDTH="15%"><B><A HREF="../../../com/adobe/xmp/XMPPathFactory.html" title="class in com.adobe.xmp">XMPPathFactory</A></B></TD>
+<TD>Utility services for the metadata object.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD WIDTH="15%"><B><A HREF="../../../com/adobe/xmp/XMPUtils.html" title="class in com.adobe.xmp">XMPUtils</A></B></TD>
+<TD>Utility methods for XMP.</TD>
+</TR>
+</TABLE>
+&nbsp;
+
+<P>
+
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+<B>Exception Summary</B></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD WIDTH="15%"><B><A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A></B></TD>
+<TD>This exception wraps all errors that occur in the XMP Toolkit.</TD>
+</TR>
+</TABLE>
+&nbsp;
+
+<P>
+<A NAME="package_description"><!-- --></A><H2>
+Package com.adobe.xmp Description
+</H2>
+
+<P>
+<p>Package containing the xmpcore interface.</p>
+<P>
+
+<P>
+<DL>
+</DL>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Package</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-use.html"><FONT CLASS="NavBarFont1"><B>Use</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV PACKAGE&nbsp;
+&nbsp;<A HREF="../../../com/adobe/xmp/options/package-summary.html"><B>NEXT PACKAGE</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../index.html?com/adobe/xmp/package-summary.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="package-summary.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/com/adobe/xmp/package-tree.html b/java/XMPCore/docs/com/adobe/xmp/package-tree.html
new file mode 100644
index 0000000..c425633
--- /dev/null
+++ b/java/XMPCore/docs/com/adobe/xmp/package-tree.html
@@ -0,0 +1,165 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:50 CEST 2007 -->
+<TITLE>
+com.adobe.xmp Class Hierarchy
+</TITLE>
+
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="com.adobe.xmp Class Hierarchy";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Tree</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;<A HREF="../../../com/adobe/xmp/options/package-tree.html"><B>NEXT</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../index.html?com/adobe/xmp/package-tree.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="package-tree.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<CENTER>
+<H2>
+Hierarchy For Package com.adobe.xmp
+</H2>
+</CENTER>
+<DL>
+<DT><B>Package Hierarchies:</B><DD><A HREF="../../../overview-tree.html">All Packages</A></DL>
+<HR>
+<H2>
+Class Hierarchy
+</H2>
+<UL>
+<LI TYPE="circle">java.lang.Object<UL>
+<LI TYPE="circle">java.lang.Throwable (implements java.io.Serializable)
+<UL>
+<LI TYPE="circle">java.lang.Exception<UL>
+<LI TYPE="circle">com.adobe.xmp.<A HREF="../../../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp"><B>XMPException</B></A></UL>
+</UL>
+<LI TYPE="circle">com.adobe.xmp.<A HREF="../../../com/adobe/xmp/XMPDateTimeFactory.html" title="class in com.adobe.xmp"><B>XMPDateTimeFactory</B></A><LI TYPE="circle">com.adobe.xmp.<A HREF="../../../com/adobe/xmp/XMPMetaFactory.html" title="class in com.adobe.xmp"><B>XMPMetaFactory</B></A><LI TYPE="circle">com.adobe.xmp.<A HREF="../../../com/adobe/xmp/XMPPathFactory.html" title="class in com.adobe.xmp"><B>XMPPathFactory</B></A><LI TYPE="circle">com.adobe.xmp.<A HREF="../../../com/adobe/xmp/XMPUtils.html" title="class in com.adobe.xmp"><B>XMPUtils</B></A></UL>
+</UL>
+<H2>
+Interface Hierarchy
+</H2>
+<UL>
+<LI TYPE="circle">java.lang.Cloneable<UL>
+<LI TYPE="circle">com.adobe.xmp.<A HREF="../../../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp"><B>XMPMeta</B></A></UL>
+<LI TYPE="circle">java.lang.Comparable<UL>
+<LI TYPE="circle">com.adobe.xmp.<A HREF="../../../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp"><B>XMPDateTime</B></A></UL>
+<LI TYPE="circle">java.util.Iterator<UL>
+<LI TYPE="circle">com.adobe.xmp.<A HREF="../../../com/adobe/xmp/XMPIterator.html" title="interface in com.adobe.xmp"><B>XMPIterator</B></A></UL>
+<LI TYPE="circle">com.adobe.xmp.<A HREF="../../../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp"><B>XMPConst</B></A><LI TYPE="circle">com.adobe.xmp.<A HREF="../../../com/adobe/xmp/XMPError.html" title="interface in com.adobe.xmp"><B>XMPError</B></A><LI TYPE="circle">com.adobe.xmp.<A HREF="../../../com/adobe/xmp/XMPSchemaRegistry.html" title="interface in com.adobe.xmp"><B>XMPSchemaRegistry</B></A><LI TYPE="circle">com.adobe.xmp.<A HREF="../../../com/adobe/xmp/XMPVersionInfo.html" title="interface in com.adobe.xmp"><B>XMPVersionInfo</B></A></UL>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Tree</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;<A HREF="../../../com/adobe/xmp/options/package-tree.html"><B>NEXT</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../index.html?com/adobe/xmp/package-tree.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="package-tree.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/com/adobe/xmp/package-use.html b/java/XMPCore/docs/com/adobe/xmp/package-use.html
new file mode 100644
index 0000000..9671779
--- /dev/null
+++ b/java/XMPCore/docs/com/adobe/xmp/package-use.html
@@ -0,0 +1,221 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:51 CEST 2007 -->
+<TITLE>
+Uses of Package com.adobe.xmp
+</TITLE>
+
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="Uses of Package com.adobe.xmp";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Use</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../index.html?com/adobe/xmp/package-use.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="package-use.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<CENTER>
+<H2>
+<B>Uses of Package<br>com.adobe.xmp</B></H2>
+</CENTER>
+
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+Packages that use <A HREF="../../../com/adobe/xmp/package-summary.html">com.adobe.xmp</A></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><A HREF="#com.adobe.xmp"><B>com.adobe.xmp</B></A></TD>
+<TD>Package containing the xmpcore interface.&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><A HREF="#com.adobe.xmp.options"><B>com.adobe.xmp.options</B></A></TD>
+<TD>Package containing the option classes.&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+<A NAME="com.adobe.xmp"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+Classes in <A HREF="../../../com/adobe/xmp/package-summary.html">com.adobe.xmp</A> used by <A HREF="../../../com/adobe/xmp/package-summary.html">com.adobe.xmp</A></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><B><A HREF="../../../com/adobe/xmp/class-use/XMPDateTime.html#com.adobe.xmp"><B>XMPDateTime</B></A></B>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The <code>XMPDateTime</code>-class represents a point in time up to a resolution of nano
+ seconds.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><B><A HREF="../../../com/adobe/xmp/class-use/XMPException.html#com.adobe.xmp"><B>XMPException</B></A></B>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;This exception wraps all errors that occur in the XMP Toolkit.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><B><A HREF="../../../com/adobe/xmp/class-use/XMPIterator.html#com.adobe.xmp"><B>XMPIterator</B></A></B>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Interface for the <code>XMPMeta</code> iteration services.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><B><A HREF="../../../com/adobe/xmp/class-use/XMPMeta.html#com.adobe.xmp"><B>XMPMeta</B></A></B>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;This class represents the set of XMP metadata as a DOM representation.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><B><A HREF="../../../com/adobe/xmp/class-use/XMPSchemaRegistry.html#com.adobe.xmp"><B>XMPSchemaRegistry</B></A></B>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The schema registry keeps track of all namespaces and aliases used in the XMP
+ metadata.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><B><A HREF="../../../com/adobe/xmp/class-use/XMPVersionInfo.html#com.adobe.xmp"><B>XMPVersionInfo</B></A></B>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XMP Toolkit Version Information
+
+ Version information for the XMP toolkit is stored in the jar-library and available through a
+ runtime call, <A HREF="../../../com/adobe/xmp/XMPMetaFactory.html#getVersionInfo()"><CODE>XMPMetaFactory.getVersionInfo()</CODE></A>, addition static version numbers are
+ defined in "version.properties".</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+<A NAME="com.adobe.xmp.options"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+Classes in <A HREF="../../../com/adobe/xmp/package-summary.html">com.adobe.xmp</A> used by <A HREF="../../../com/adobe/xmp/options/package-summary.html">com.adobe.xmp.options</A></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><B><A HREF="../../../com/adobe/xmp/class-use/XMPException.html#com.adobe.xmp.options"><B>XMPException</B></A></B>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;This exception wraps all errors that occur in the XMP Toolkit.</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Use</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../index.html?com/adobe/xmp/package-use.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="package-use.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/com/adobe/xmp/properties/XMPAliasInfo.html b/java/XMPCore/docs/com/adobe/xmp/properties/XMPAliasInfo.html
new file mode 100644
index 0000000..ea3ec06
--- /dev/null
+++ b/java/XMPCore/docs/com/adobe/xmp/properties/XMPAliasInfo.html
@@ -0,0 +1,276 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:50 CEST 2007 -->
+<TITLE>
+XMPAliasInfo
+</TITLE>
+
+<META NAME="keywords" CONTENT="com.adobe.xmp.properties.XMPAliasInfo interface">
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="XMPAliasInfo";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="class-use/XMPAliasInfo.html"><FONT CLASS="NavBarFont1"><B>Use</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV CLASS&nbsp;
+&nbsp;<A HREF="../../../../com/adobe/xmp/properties/XMPProperty.html" title="interface in com.adobe.xmp.properties"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../index.html?com/adobe/xmp/properties/XMPAliasInfo.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPAliasInfo.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+ SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;FIELD&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;FIELD&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<!-- ======== START OF CLASS DATA ======== -->
+<H2>
+<FONT SIZE="-1">
+com.adobe.xmp.properties</FONT>
+<BR>
+Interface XMPAliasInfo</H2>
+<HR>
+<DL>
+<DT><PRE>public interface <B>XMPAliasInfo</B></DL>
+</PRE>
+
+<P>
+This interface is used to return info about an alias.
+<P>
+
+<P>
+<DL>
+<DT><B>Since:</B></DT>
+ <DD>27.01.2006</DD>
+</DL>
+<HR>
+
+<P>
+
+<!-- ========== METHOD SUMMARY =========== -->
+
+<A NAME="method_summary"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+<B>Method Summary</B></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options">AliasOptions</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/properties/XMPAliasInfo.html#getAliasForm()">getAliasForm</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/properties/XMPAliasInfo.html#getNamespace()">getNamespace</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/properties/XMPAliasInfo.html#getPrefix()">getPrefix</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/properties/XMPAliasInfo.html#getPropName()">getPropName</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<!-- ============ METHOD DETAIL ========== -->
+
+<A NAME="method_detail"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="1"><FONT SIZE="+2">
+<B>Method Detail</B></FONT></TH>
+</TR>
+</TABLE>
+
+<A NAME="getNamespace()"><!-- --></A><H3>
+getNamespace</H3>
+<PRE>
+java.lang.String <B>getNamespace</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns Returns the namespace URI for the base property.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getPrefix()"><!-- --></A><H3>
+getPrefix</H3>
+<PRE>
+java.lang.String <B>getPrefix</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns the default prefix for the given base property.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getPropName()"><!-- --></A><H3>
+getPropName</H3>
+<PRE>
+java.lang.String <B>getPropName</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns the path of the base property.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getAliasForm()"><!-- --></A><H3>
+getAliasForm</H3>
+<PRE>
+<A HREF="../../../../com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options">AliasOptions</A> <B>getAliasForm</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns the kind of the alias. This can be a direct alias
+ (ARRAY), a simple property to an ordered array
+ (ARRAY_ORDERED), to an alternate array
+ (ARRAY_ALTERNATE) or to an alternate text array
+ (ARRAY_ALT_TEXT).</DL>
+</DD>
+</DL>
+<!-- ========= END OF CLASS DATA ========= -->
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="class-use/XMPAliasInfo.html"><FONT CLASS="NavBarFont1"><B>Use</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV CLASS&nbsp;
+&nbsp;<A HREF="../../../../com/adobe/xmp/properties/XMPProperty.html" title="interface in com.adobe.xmp.properties"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../index.html?com/adobe/xmp/properties/XMPAliasInfo.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPAliasInfo.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+ SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;FIELD&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;FIELD&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/com/adobe/xmp/properties/XMPProperty.html b/java/XMPCore/docs/com/adobe/xmp/properties/XMPProperty.html
new file mode 100644
index 0000000..0303d0e
--- /dev/null
+++ b/java/XMPCore/docs/com/adobe/xmp/properties/XMPProperty.html
@@ -0,0 +1,257 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:50 CEST 2007 -->
+<TITLE>
+XMPProperty
+</TITLE>
+
+<META NAME="keywords" CONTENT="com.adobe.xmp.properties.XMPProperty interface">
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="XMPProperty";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="class-use/XMPProperty.html"><FONT CLASS="NavBarFont1"><B>Use</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="../../../../com/adobe/xmp/properties/XMPAliasInfo.html" title="interface in com.adobe.xmp.properties"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;<A HREF="../../../../com/adobe/xmp/properties/XMPPropertyInfo.html" title="interface in com.adobe.xmp.properties"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../index.html?com/adobe/xmp/properties/XMPProperty.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPProperty.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+ SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;FIELD&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;FIELD&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<!-- ======== START OF CLASS DATA ======== -->
+<H2>
+<FONT SIZE="-1">
+com.adobe.xmp.properties</FONT>
+<BR>
+Interface XMPProperty</H2>
+<DL>
+<DT><B>All Known Subinterfaces:</B> <DD><A HREF="../../../../com/adobe/xmp/properties/XMPPropertyInfo.html" title="interface in com.adobe.xmp.properties">XMPPropertyInfo</A></DD>
+</DL>
+<HR>
+<DL>
+<DT><PRE>public interface <B>XMPProperty</B></DL>
+</PRE>
+
+<P>
+This interface is used to return a text property together with its and options.
+<P>
+
+<P>
+<DL>
+<DT><B>Since:</B></DT>
+ <DD>23.01.2006</DD>
+</DL>
+<HR>
+
+<P>
+
+<!-- ========== METHOD SUMMARY =========== -->
+
+<A NAME="method_summary"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+<B>Method Summary</B></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/properties/XMPProperty.html#getLanguage()">getLanguage</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Only set by <A HREF="../../../../com/adobe/xmp/XMPMeta.html#getLocalizedText(java.lang.String, java.lang.String, java.lang.String, java.lang.String)"><CODE>XMPMeta.getLocalizedText(String, String, String, String)</CODE></A>.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/properties/XMPProperty.html#getOptions()">getOptions</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.lang.Object</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/properties/XMPProperty.html#getValue()">getValue</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<!-- ============ METHOD DETAIL ========== -->
+
+<A NAME="method_detail"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="1"><FONT SIZE="+2">
+<B>Method Detail</B></FONT></TH>
+</TR>
+</TABLE>
+
+<A NAME="getValue()"><!-- --></A><H3>
+getValue</H3>
+<PRE>
+java.lang.Object <B>getValue</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns the value of the property.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getOptions()"><!-- --></A><H3>
+getOptions</H3>
+<PRE>
+<A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A> <B>getOptions</B>()</PRE>
+<DL>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns the options of the property.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getLanguage()"><!-- --></A><H3>
+getLanguage</H3>
+<PRE>
+java.lang.String <B>getLanguage</B>()</PRE>
+<DL>
+<DD>Only set by <A HREF="../../../../com/adobe/xmp/XMPMeta.html#getLocalizedText(java.lang.String, java.lang.String, java.lang.String, java.lang.String)"><CODE>XMPMeta.getLocalizedText(String, String, String, String)</CODE></A>.
+<P>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns the language of the alt-text item.</DL>
+</DD>
+</DL>
+<!-- ========= END OF CLASS DATA ========= -->
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="class-use/XMPProperty.html"><FONT CLASS="NavBarFont1"><B>Use</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="../../../../com/adobe/xmp/properties/XMPAliasInfo.html" title="interface in com.adobe.xmp.properties"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;<A HREF="../../../../com/adobe/xmp/properties/XMPPropertyInfo.html" title="interface in com.adobe.xmp.properties"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../index.html?com/adobe/xmp/properties/XMPProperty.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPProperty.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+ SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;FIELD&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;FIELD&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/com/adobe/xmp/properties/XMPPropertyInfo.html b/java/XMPCore/docs/com/adobe/xmp/properties/XMPPropertyInfo.html
new file mode 100644
index 0000000..53122a4
--- /dev/null
+++ b/java/XMPCore/docs/com/adobe/xmp/properties/XMPPropertyInfo.html
@@ -0,0 +1,297 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:50 CEST 2007 -->
+<TITLE>
+XMPPropertyInfo
+</TITLE>
+
+<META NAME="keywords" CONTENT="com.adobe.xmp.properties.XMPPropertyInfo interface">
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="XMPPropertyInfo";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="class-use/XMPPropertyInfo.html"><FONT CLASS="NavBarFont1"><B>Use</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="../../../../com/adobe/xmp/properties/XMPProperty.html" title="interface in com.adobe.xmp.properties"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;NEXT CLASS</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../index.html?com/adobe/xmp/properties/XMPPropertyInfo.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPPropertyInfo.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+ SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;FIELD&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;FIELD&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<!-- ======== START OF CLASS DATA ======== -->
+<H2>
+<FONT SIZE="-1">
+com.adobe.xmp.properties</FONT>
+<BR>
+Interface XMPPropertyInfo</H2>
+<DL>
+<DT><B>All Superinterfaces:</B> <DD><A HREF="../../../../com/adobe/xmp/properties/XMPProperty.html" title="interface in com.adobe.xmp.properties">XMPProperty</A></DD>
+</DL>
+<HR>
+<DL>
+<DT><PRE>public interface <B>XMPPropertyInfo</B><DT>extends <A HREF="../../../../com/adobe/xmp/properties/XMPProperty.html" title="interface in com.adobe.xmp.properties">XMPProperty</A></DL>
+</PRE>
+
+<P>
+This interface is used to return a property together with its path and namespace.
+ It is returned when properties are iterated with the <code>XMPIterator</code>.
+<P>
+
+<P>
+<DL>
+<DT><B>Since:</B></DT>
+ <DD>06.07.2006</DD>
+</DL>
+<HR>
+
+<P>
+
+<!-- ========== METHOD SUMMARY =========== -->
+
+<A NAME="method_summary"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+<B>Method Summary</B></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/properties/XMPPropertyInfo.html#getNamespace()">getNamespace</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A></CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/properties/XMPPropertyInfo.html#getOptions()">getOptions</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/properties/XMPPropertyInfo.html#getPath()">getPath</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.lang.Object</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../com/adobe/xmp/properties/XMPPropertyInfo.html#getValue()">getValue</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;<A NAME="methods_inherited_from_class_com.adobe.xmp.properties.XMPProperty"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#EEEEFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="left"><B>Methods inherited from interface com.adobe.xmp.properties.<A HREF="../../../../com/adobe/xmp/properties/XMPProperty.html" title="interface in com.adobe.xmp.properties">XMPProperty</A></B></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE><A HREF="../../../../com/adobe/xmp/properties/XMPProperty.html#getLanguage()">getLanguage</A></CODE></TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<!-- ============ METHOD DETAIL ========== -->
+
+<A NAME="method_detail"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="1"><FONT SIZE="+2">
+<B>Method Detail</B></FONT></TH>
+</TR>
+</TABLE>
+
+<A NAME="getNamespace()"><!-- --></A><H3>
+getNamespace</H3>
+<PRE>
+java.lang.String <B>getNamespace</B>()</PRE>
+<DL>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns the namespace of the property</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getPath()"><!-- --></A><H3>
+getPath</H3>
+<PRE>
+java.lang.String <B>getPath</B>()</PRE>
+<DL>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns the path of the property, but only if returned by the iterator.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getValue()"><!-- --></A><H3>
+getValue</H3>
+<PRE>
+java.lang.Object <B>getValue</B>()</PRE>
+<DL>
+<DD><DL>
+<DT><B>Specified by:</B><DD><CODE><A HREF="../../../../com/adobe/xmp/properties/XMPProperty.html#getValue()">getValue</A></CODE> in interface <CODE><A HREF="../../../../com/adobe/xmp/properties/XMPProperty.html" title="interface in com.adobe.xmp.properties">XMPProperty</A></CODE></DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns the value of the property.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getOptions()"><!-- --></A><H3>
+getOptions</H3>
+<PRE>
+<A HREF="../../../../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A> <B>getOptions</B>()</PRE>
+<DL>
+<DD><DL>
+<DT><B>Specified by:</B><DD><CODE><A HREF="../../../../com/adobe/xmp/properties/XMPProperty.html#getOptions()">getOptions</A></CODE> in interface <CODE><A HREF="../../../../com/adobe/xmp/properties/XMPProperty.html" title="interface in com.adobe.xmp.properties">XMPProperty</A></CODE></DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Returns the options of the property.</DL>
+</DD>
+</DL>
+<!-- ========= END OF CLASS DATA ========= -->
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="class-use/XMPPropertyInfo.html"><FONT CLASS="NavBarFont1"><B>Use</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="../../../../com/adobe/xmp/properties/XMPProperty.html" title="interface in com.adobe.xmp.properties"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;NEXT CLASS</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../index.html?com/adobe/xmp/properties/XMPPropertyInfo.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPPropertyInfo.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+ SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;FIELD&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;FIELD&nbsp;|&nbsp;CONSTR&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/com/adobe/xmp/properties/class-use/XMPAliasInfo.html b/java/XMPCore/docs/com/adobe/xmp/properties/class-use/XMPAliasInfo.html
new file mode 100644
index 0000000..0659608
--- /dev/null
+++ b/java/XMPCore/docs/com/adobe/xmp/properties/class-use/XMPAliasInfo.html
@@ -0,0 +1,193 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:51 CEST 2007 -->
+<TITLE>
+Uses of Interface com.adobe.xmp.properties.XMPAliasInfo
+</TITLE>
+
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="Uses of Interface com.adobe.xmp.properties.XMPAliasInfo";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../com/adobe/xmp/properties/XMPAliasInfo.html" title="interface in com.adobe.xmp.properties"><FONT CLASS="NavBarFont1"><B>Class</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Use</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../../index.html?com/adobe/xmp/properties//class-useXMPAliasInfo.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPAliasInfo.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<CENTER>
+<H2>
+<B>Uses of Interface<br>com.adobe.xmp.properties.XMPAliasInfo</B></H2>
+</CENTER>
+
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+Packages that use <A HREF="../../../../../com/adobe/xmp/properties/XMPAliasInfo.html" title="interface in com.adobe.xmp.properties">XMPAliasInfo</A></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><A HREF="#com.adobe.xmp"><B>com.adobe.xmp</B></A></TD>
+<TD>Package containing the xmpcore interface.&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+<A NAME="com.adobe.xmp"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+Uses of <A HREF="../../../../../com/adobe/xmp/properties/XMPAliasInfo.html" title="interface in com.adobe.xmp.properties">XMPAliasInfo</A> in <A HREF="../../../../../com/adobe/xmp/package-summary.html">com.adobe.xmp</A></FONT></TH>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="left" COLSPAN="2">Methods in <A HREF="../../../../../com/adobe/xmp/package-summary.html">com.adobe.xmp</A> that return <A HREF="../../../../../com/adobe/xmp/properties/XMPAliasInfo.html" title="interface in com.adobe.xmp.properties">XMPAliasInfo</A></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../../com/adobe/xmp/properties/XMPAliasInfo.html" title="interface in com.adobe.xmp.properties">XMPAliasInfo</A></CODE></FONT></TD>
+<TD><CODE><B>XMPSchemaRegistry.</B><B><A HREF="../../../../../com/adobe/xmp/XMPSchemaRegistry.html#findAlias(java.lang.String)">findAlias</A></B>(java.lang.String&nbsp;qname)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Searches for registered aliases.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../../com/adobe/xmp/properties/XMPAliasInfo.html" title="interface in com.adobe.xmp.properties">XMPAliasInfo</A>[]</CODE></FONT></TD>
+<TD><CODE><B>XMPSchemaRegistry.</B><B><A HREF="../../../../../com/adobe/xmp/XMPSchemaRegistry.html#findAliases(java.lang.String)">findAliases</A></B>(java.lang.String&nbsp;aliasNS)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Collects all aliases that are contained in the provided namespace.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../../com/adobe/xmp/properties/XMPAliasInfo.html" title="interface in com.adobe.xmp.properties">XMPAliasInfo</A></CODE></FONT></TD>
+<TD><CODE><B>XMPSchemaRegistry.</B><B><A HREF="../../../../../com/adobe/xmp/XMPSchemaRegistry.html#resolveAlias(java.lang.String, java.lang.String)">resolveAlias</A></B>(java.lang.String&nbsp;aliasNS,
+ java.lang.String&nbsp;aliasProp)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Determines if a name is an alias, and what it is aliased to.</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../com/adobe/xmp/properties/XMPAliasInfo.html" title="interface in com.adobe.xmp.properties"><FONT CLASS="NavBarFont1"><B>Class</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Use</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../../index.html?com/adobe/xmp/properties//class-useXMPAliasInfo.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPAliasInfo.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/com/adobe/xmp/properties/class-use/XMPProperty.html b/java/XMPCore/docs/com/adobe/xmp/properties/class-use/XMPProperty.html
new file mode 100644
index 0000000..ab6457b
--- /dev/null
+++ b/java/XMPCore/docs/com/adobe/xmp/properties/class-use/XMPProperty.html
@@ -0,0 +1,252 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:51 CEST 2007 -->
+<TITLE>
+Uses of Interface com.adobe.xmp.properties.XMPProperty
+</TITLE>
+
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="Uses of Interface com.adobe.xmp.properties.XMPProperty";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../com/adobe/xmp/properties/XMPProperty.html" title="interface in com.adobe.xmp.properties"><FONT CLASS="NavBarFont1"><B>Class</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Use</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../../index.html?com/adobe/xmp/properties//class-useXMPProperty.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPProperty.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<CENTER>
+<H2>
+<B>Uses of Interface<br>com.adobe.xmp.properties.XMPProperty</B></H2>
+</CENTER>
+
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+Packages that use <A HREF="../../../../../com/adobe/xmp/properties/XMPProperty.html" title="interface in com.adobe.xmp.properties">XMPProperty</A></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><A HREF="#com.adobe.xmp"><B>com.adobe.xmp</B></A></TD>
+<TD>Package containing the xmpcore interface.&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><A HREF="#com.adobe.xmp.properties"><B>com.adobe.xmp.properties</B></A></TD>
+<TD>Package containing the property information classes.&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+<A NAME="com.adobe.xmp"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+Uses of <A HREF="../../../../../com/adobe/xmp/properties/XMPProperty.html" title="interface in com.adobe.xmp.properties">XMPProperty</A> in <A HREF="../../../../../com/adobe/xmp/package-summary.html">com.adobe.xmp</A></FONT></TH>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="left" COLSPAN="2">Methods in <A HREF="../../../../../com/adobe/xmp/package-summary.html">com.adobe.xmp</A> that return <A HREF="../../../../../com/adobe/xmp/properties/XMPProperty.html" title="interface in com.adobe.xmp.properties">XMPProperty</A></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../../com/adobe/xmp/properties/XMPProperty.html" title="interface in com.adobe.xmp.properties">XMPProperty</A></CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../../com/adobe/xmp/XMPMeta.html#getArrayItem(java.lang.String, java.lang.String, int)">getArrayItem</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;arrayName,
+ int&nbsp;itemIndex)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Provides access to items within an array.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../../com/adobe/xmp/properties/XMPProperty.html" title="interface in com.adobe.xmp.properties">XMPProperty</A></CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../../com/adobe/xmp/XMPMeta.html#getLocalizedText(java.lang.String, java.lang.String, java.lang.String, java.lang.String)">getLocalizedText</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;altTextName,
+ java.lang.String&nbsp;genericLang,
+ java.lang.String&nbsp;specificLang)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;These functions provide convenient support for localized text properties, including a number
+ of special and obscure aspects.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../../com/adobe/xmp/properties/XMPProperty.html" title="interface in com.adobe.xmp.properties">XMPProperty</A></CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../../com/adobe/xmp/XMPMeta.html#getProperty(java.lang.String, java.lang.String)">getProperty</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The property value getter-methods all take a property specification: the first two parameters
+ are always the top level namespace URI (the &quot;schema&quot; namespace) and the basic name
+ of the property being referenced.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../../com/adobe/xmp/properties/XMPProperty.html" title="interface in com.adobe.xmp.properties">XMPProperty</A></CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../../com/adobe/xmp/XMPMeta.html#getQualifier(java.lang.String, java.lang.String, java.lang.String, java.lang.String)">getQualifier</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;propName,
+ java.lang.String&nbsp;qualNS,
+ java.lang.String&nbsp;qualName)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Provides access to a qualifier attached to a property.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;<A HREF="../../../../../com/adobe/xmp/properties/XMPProperty.html" title="interface in com.adobe.xmp.properties">XMPProperty</A></CODE></FONT></TD>
+<TD><CODE><B>XMPMeta.</B><B><A HREF="../../../../../com/adobe/xmp/XMPMeta.html#getStructField(java.lang.String, java.lang.String, java.lang.String, java.lang.String)">getStructField</A></B>(java.lang.String&nbsp;schemaNS,
+ java.lang.String&nbsp;structName,
+ java.lang.String&nbsp;fieldNS,
+ java.lang.String&nbsp;fieldName)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Provides access to fields within a nested structure.</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+<A NAME="com.adobe.xmp.properties"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+Uses of <A HREF="../../../../../com/adobe/xmp/properties/XMPProperty.html" title="interface in com.adobe.xmp.properties">XMPProperty</A> in <A HREF="../../../../../com/adobe/xmp/properties/package-summary.html">com.adobe.xmp.properties</A></FONT></TH>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="left" COLSPAN="2">Subinterfaces of <A HREF="../../../../../com/adobe/xmp/properties/XMPProperty.html" title="interface in com.adobe.xmp.properties">XMPProperty</A> in <A HREF="../../../../../com/adobe/xmp/properties/package-summary.html">com.adobe.xmp.properties</A></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;interface</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../../../com/adobe/xmp/properties/XMPPropertyInfo.html" title="interface in com.adobe.xmp.properties">XMPPropertyInfo</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;This interface is used to return a property together with its path and namespace.</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../com/adobe/xmp/properties/XMPProperty.html" title="interface in com.adobe.xmp.properties"><FONT CLASS="NavBarFont1"><B>Class</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Use</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../../index.html?com/adobe/xmp/properties//class-useXMPProperty.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPProperty.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/com/adobe/xmp/properties/class-use/XMPPropertyInfo.html b/java/XMPCore/docs/com/adobe/xmp/properties/class-use/XMPPropertyInfo.html
new file mode 100644
index 0000000..7825f47
--- /dev/null
+++ b/java/XMPCore/docs/com/adobe/xmp/properties/class-use/XMPPropertyInfo.html
@@ -0,0 +1,140 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:51 CEST 2007 -->
+<TITLE>
+Uses of Interface com.adobe.xmp.properties.XMPPropertyInfo
+</TITLE>
+
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="Uses of Interface com.adobe.xmp.properties.XMPPropertyInfo";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../com/adobe/xmp/properties/XMPPropertyInfo.html" title="interface in com.adobe.xmp.properties"><FONT CLASS="NavBarFont1"><B>Class</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Use</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../../index.html?com/adobe/xmp/properties//class-useXMPPropertyInfo.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPPropertyInfo.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<CENTER>
+<H2>
+<B>Uses of Interface<br>com.adobe.xmp.properties.XMPPropertyInfo</B></H2>
+</CENTER>
+No usage of com.adobe.xmp.properties.XMPPropertyInfo
+<P>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../com/adobe/xmp/properties/XMPPropertyInfo.html" title="interface in com.adobe.xmp.properties"><FONT CLASS="NavBarFont1"><B>Class</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Use</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../../index.html?com/adobe/xmp/properties//class-useXMPPropertyInfo.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="XMPPropertyInfo.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/com/adobe/xmp/properties/package-frame.html b/java/XMPCore/docs/com/adobe/xmp/properties/package-frame.html
new file mode 100644
index 0000000..27a414d
--- /dev/null
+++ b/java/XMPCore/docs/com/adobe/xmp/properties/package-frame.html
@@ -0,0 +1,36 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:50 CEST 2007 -->
+<TITLE>
+com.adobe.xmp.properties
+</TITLE>
+
+<META NAME="keywords" CONTENT="com.adobe.xmp.properties package">
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../stylesheet.css" TITLE="Style">
+
+
+</HEAD>
+
+<BODY BGCOLOR="white">
+<FONT size="+1" CLASS="FrameTitleFont">
+<A HREF="../../../../com/adobe/xmp/properties/package-summary.html" target="classFrame">com.adobe.xmp.properties</A></FONT>
+<TABLE BORDER="0" WIDTH="100%" SUMMARY="">
+<TR>
+<TD NOWRAP><FONT size="+1" CLASS="FrameHeadingFont">
+Interfaces</FONT>&nbsp;
+<FONT CLASS="FrameItemFont">
+<BR>
+<A HREF="XMPAliasInfo.html" title="interface in com.adobe.xmp.properties" target="classFrame"><I>XMPAliasInfo</I></A>
+<BR>
+<A HREF="XMPProperty.html" title="interface in com.adobe.xmp.properties" target="classFrame"><I>XMPProperty</I></A>
+<BR>
+<A HREF="XMPPropertyInfo.html" title="interface in com.adobe.xmp.properties" target="classFrame"><I>XMPPropertyInfo</I></A></FONT></TD>
+</TR>
+</TABLE>
+
+
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/com/adobe/xmp/properties/package-summary.html b/java/XMPCore/docs/com/adobe/xmp/properties/package-summary.html
new file mode 100644
index 0000000..a7c55e6
--- /dev/null
+++ b/java/XMPCore/docs/com/adobe/xmp/properties/package-summary.html
@@ -0,0 +1,179 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:50 CEST 2007 -->
+<TITLE>
+com.adobe.xmp.properties
+</TITLE>
+
+<META NAME="keywords" CONTENT="com.adobe.xmp.properties package">
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="com.adobe.xmp.properties";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Package</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-use.html"><FONT CLASS="NavBarFont1"><B>Use</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="../../../../com/adobe/xmp/options/package-summary.html"><B>PREV PACKAGE</B></A>&nbsp;
+&nbsp;NEXT PACKAGE</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../index.html?com/adobe/xmp/properties/package-summary.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="package-summary.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<H2>
+Package com.adobe.xmp.properties
+</H2>
+Package containing the property information classes.
+<P>
+<B>See:</B>
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<A HREF="#package_description"><B>Description</B></A>
+<P>
+
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+<B>Interface Summary</B></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD WIDTH="15%"><B><A HREF="../../../../com/adobe/xmp/properties/XMPAliasInfo.html" title="interface in com.adobe.xmp.properties">XMPAliasInfo</A></B></TD>
+<TD>This interface is used to return info about an alias.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD WIDTH="15%"><B><A HREF="../../../../com/adobe/xmp/properties/XMPProperty.html" title="interface in com.adobe.xmp.properties">XMPProperty</A></B></TD>
+<TD>This interface is used to return a text property together with its and options.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD WIDTH="15%"><B><A HREF="../../../../com/adobe/xmp/properties/XMPPropertyInfo.html" title="interface in com.adobe.xmp.properties">XMPPropertyInfo</A></B></TD>
+<TD>This interface is used to return a property together with its path and namespace.</TD>
+</TR>
+</TABLE>
+&nbsp;
+
+<P>
+<A NAME="package_description"><!-- --></A><H2>
+Package com.adobe.xmp.properties Description
+</H2>
+
+<P>
+<p>Package containing the property information classes.</p>
+ <p>XMPProperty and XMPPropertyInfo are used to report properties when they are retrieved by get-methods or by the iterator.
+ XMPAliasInfo informs about a certain property-to-property alias.<p>
+<P>
+
+<P>
+<DL>
+</DL>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Package</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-use.html"><FONT CLASS="NavBarFont1"><B>Use</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="../../../../com/adobe/xmp/options/package-summary.html"><B>PREV PACKAGE</B></A>&nbsp;
+&nbsp;NEXT PACKAGE</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../index.html?com/adobe/xmp/properties/package-summary.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="package-summary.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/com/adobe/xmp/properties/package-tree.html b/java/XMPCore/docs/com/adobe/xmp/properties/package-tree.html
new file mode 100644
index 0000000..570ce2b
--- /dev/null
+++ b/java/XMPCore/docs/com/adobe/xmp/properties/package-tree.html
@@ -0,0 +1,149 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:50 CEST 2007 -->
+<TITLE>
+com.adobe.xmp.properties Class Hierarchy
+</TITLE>
+
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="com.adobe.xmp.properties Class Hierarchy";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Tree</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="../../../../com/adobe/xmp/options/package-tree.html"><B>PREV</B></A>&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../index.html?com/adobe/xmp/properties/package-tree.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="package-tree.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<CENTER>
+<H2>
+Hierarchy For Package com.adobe.xmp.properties
+</H2>
+</CENTER>
+<DL>
+<DT><B>Package Hierarchies:</B><DD><A HREF="../../../../overview-tree.html">All Packages</A></DL>
+<HR>
+<H2>
+Interface Hierarchy
+</H2>
+<UL>
+<LI TYPE="circle">com.adobe.xmp.properties.<A HREF="../../../../com/adobe/xmp/properties/XMPAliasInfo.html" title="interface in com.adobe.xmp.properties"><B>XMPAliasInfo</B></A><LI TYPE="circle">com.adobe.xmp.properties.<A HREF="../../../../com/adobe/xmp/properties/XMPProperty.html" title="interface in com.adobe.xmp.properties"><B>XMPProperty</B></A><UL>
+<LI TYPE="circle">com.adobe.xmp.properties.<A HREF="../../../../com/adobe/xmp/properties/XMPPropertyInfo.html" title="interface in com.adobe.xmp.properties"><B>XMPPropertyInfo</B></A></UL>
+</UL>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Tree</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="../../../../com/adobe/xmp/options/package-tree.html"><B>PREV</B></A>&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../index.html?com/adobe/xmp/properties/package-tree.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="package-tree.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/com/adobe/xmp/properties/package-use.html b/java/XMPCore/docs/com/adobe/xmp/properties/package-use.html
new file mode 100644
index 0000000..a732f18
--- /dev/null
+++ b/java/XMPCore/docs/com/adobe/xmp/properties/package-use.html
@@ -0,0 +1,191 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:51 CEST 2007 -->
+<TITLE>
+Uses of Package com.adobe.xmp.properties
+</TITLE>
+
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="Uses of Package com.adobe.xmp.properties";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Use</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../index.html?com/adobe/xmp/properties/package-use.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="package-use.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<CENTER>
+<H2>
+<B>Uses of Package<br>com.adobe.xmp.properties</B></H2>
+</CENTER>
+
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+Packages that use <A HREF="../../../../com/adobe/xmp/properties/package-summary.html">com.adobe.xmp.properties</A></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><A HREF="#com.adobe.xmp"><B>com.adobe.xmp</B></A></TD>
+<TD>Package containing the xmpcore interface.&nbsp;</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><A HREF="#com.adobe.xmp.properties"><B>com.adobe.xmp.properties</B></A></TD>
+<TD>Package containing the property information classes.&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+<A NAME="com.adobe.xmp"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+Classes in <A HREF="../../../../com/adobe/xmp/properties/package-summary.html">com.adobe.xmp.properties</A> used by <A HREF="../../../../com/adobe/xmp/package-summary.html">com.adobe.xmp</A></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><B><A HREF="../../../../com/adobe/xmp/properties/class-use/XMPAliasInfo.html#com.adobe.xmp"><B>XMPAliasInfo</B></A></B>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;This interface is used to return info about an alias.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><B><A HREF="../../../../com/adobe/xmp/properties/class-use/XMPProperty.html#com.adobe.xmp"><B>XMPProperty</B></A></B>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;This interface is used to return a text property together with its and options.</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+<A NAME="com.adobe.xmp.properties"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+Classes in <A HREF="../../../../com/adobe/xmp/properties/package-summary.html">com.adobe.xmp.properties</A> used by <A HREF="../../../../com/adobe/xmp/properties/package-summary.html">com.adobe.xmp.properties</A></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><B><A HREF="../../../../com/adobe/xmp/properties/class-use/XMPProperty.html#com.adobe.xmp.properties"><B>XMPProperty</B></A></B>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;This interface is used to return a text property together with its and options.</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-summary.html"><FONT CLASS="NavBarFont1"><B>Package</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Use</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="package-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../../../../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../../../../index.html?com/adobe/xmp/properties/package-use.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="package-use.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../../../../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/constant-values.html b/java/XMPCore/docs/constant-values.html
new file mode 100644
index 0000000..3976259
--- /dev/null
+++ b/java/XMPCore/docs/constant-values.html
@@ -0,0 +1,866 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:50 CEST 2007 -->
+<TITLE>
+Constant Field Values
+</TITLE>
+
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="Constant Field Values";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="index.html?constant-values.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="constant-values.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<CENTER>
+<H1>
+Constant Field Values</H1>
+</CENTER>
+<HR SIZE="4" NOSHADE>
+<B>Contents</B><UL>
+<LI><A HREF="#com.adobe">com.adobe.*</A>
+</UL>
+
+<A NAME="com.adobe"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left"><FONT SIZE="+2">
+com.adobe.*</FONT></TH>
+</TR>
+</TABLE>
+
+<P>
+
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#EEEEFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="left" COLSPAN="3">com.adobe.xmp.<A HREF="com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPConst.ARRAY_ITEM_NAME"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;java.lang.String</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPConst.html#ARRAY_ITEM_NAME">ARRAY_ITEM_NAME</A></CODE></TD>
+<TD ALIGN="right"><CODE>"[]"</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPConst.ARRAY_LAST_ITEM"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;int</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPConst.html#ARRAY_LAST_ITEM">ARRAY_LAST_ITEM</A></CODE></TD>
+<TD ALIGN="right"><CODE>-1</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPConst.FALSESTR"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;java.lang.String</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPConst.html#FALSESTR">FALSESTR</A></CODE></TD>
+<TD ALIGN="right"><CODE>"False"</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPConst.NS_ADOBESTOCKPHOTO"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;java.lang.String</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPConst.html#NS_ADOBESTOCKPHOTO">NS_ADOBESTOCKPHOTO</A></CODE></TD>
+<TD ALIGN="right"><CODE>"http://ns.adobe.com/StockPhoto/1.0/"</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPConst.NS_ASF"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;java.lang.String</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPConst.html#NS_ASF">NS_ASF</A></CODE></TD>
+<TD ALIGN="right"><CODE>"http://ns.adobe.com/asf/1.0/"</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPConst.NS_CAMERARAW"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;java.lang.String</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPConst.html#NS_CAMERARAW">NS_CAMERARAW</A></CODE></TD>
+<TD ALIGN="right"><CODE>"http://ns.adobe.com/camera-raw-settings/1.0/"</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPConst.NS_DC"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;java.lang.String</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPConst.html#NS_DC">NS_DC</A></CODE></TD>
+<TD ALIGN="right"><CODE>"http://purl.org/dc/elements/1.1/"</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPConst.NS_DC_DEPRECATED"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;java.lang.String</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPConst.html#NS_DC_DEPRECATED">NS_DC_DEPRECATED</A></CODE></TD>
+<TD ALIGN="right"><CODE>"http://purl.org/dc/1.1/"</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPConst.NS_DM"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;java.lang.String</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPConst.html#NS_DM">NS_DM</A></CODE></TD>
+<TD ALIGN="right"><CODE>"http://ns.adobe.com/xmp/1.0/DynamicMedia/"</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPConst.NS_EXIF"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;java.lang.String</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPConst.html#NS_EXIF">NS_EXIF</A></CODE></TD>
+<TD ALIGN="right"><CODE>"http://ns.adobe.com/exif/1.0/"</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPConst.NS_EXIF_AUX"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;java.lang.String</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPConst.html#NS_EXIF_AUX">NS_EXIF_AUX</A></CODE></TD>
+<TD ALIGN="right"><CODE>"http://ns.adobe.com/exif/1.0/aux/"</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPConst.NS_IPTCCORE"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;java.lang.String</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPConst.html#NS_IPTCCORE">NS_IPTCCORE</A></CODE></TD>
+<TD ALIGN="right"><CODE>"http://iptc.org/std/Iptc4xmpCore/1.0/xmlns/"</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPConst.NS_IX"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;java.lang.String</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPConst.html#NS_IX">NS_IX</A></CODE></TD>
+<TD ALIGN="right"><CODE>"http://ns.adobe.com/iX/1.0/"</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPConst.NS_JP2K"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;java.lang.String</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPConst.html#NS_JP2K">NS_JP2K</A></CODE></TD>
+<TD ALIGN="right"><CODE>"http://ns.adobe.com/jp2k/1.0/"</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPConst.NS_JPEG"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;java.lang.String</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPConst.html#NS_JPEG">NS_JPEG</A></CODE></TD>
+<TD ALIGN="right"><CODE>"http://ns.adobe.com/jpeg/1.0/"</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPConst.NS_PDF"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;java.lang.String</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPConst.html#NS_PDF">NS_PDF</A></CODE></TD>
+<TD ALIGN="right"><CODE>"http://ns.adobe.com/pdf/1.3/"</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPConst.NS_PDFA_EXTENSION"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;java.lang.String</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPConst.html#NS_PDFA_EXTENSION">NS_PDFA_EXTENSION</A></CODE></TD>
+<TD ALIGN="right"><CODE>"http://www.aiim.org/pdfa/ns/extension/"</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPConst.NS_PDFA_FIELD"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;java.lang.String</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPConst.html#NS_PDFA_FIELD">NS_PDFA_FIELD</A></CODE></TD>
+<TD ALIGN="right"><CODE>"http://www.aiim.org/pdfa/ns/field#"</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPConst.NS_PDFA_ID"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;java.lang.String</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPConst.html#NS_PDFA_ID">NS_PDFA_ID</A></CODE></TD>
+<TD ALIGN="right"><CODE>"http://www.aiim.org/pdfa/ns/id/"</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPConst.NS_PDFA_PROPERTY"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;java.lang.String</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPConst.html#NS_PDFA_PROPERTY">NS_PDFA_PROPERTY</A></CODE></TD>
+<TD ALIGN="right"><CODE>"http://www.aiim.org/pdfa/ns/property#"</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPConst.NS_PDFA_SCHEMA"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;java.lang.String</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPConst.html#NS_PDFA_SCHEMA">NS_PDFA_SCHEMA</A></CODE></TD>
+<TD ALIGN="right"><CODE>"http://www.aiim.org/pdfa/ns/schema#"</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPConst.NS_PDFA_TYPE"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;java.lang.String</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPConst.html#NS_PDFA_TYPE">NS_PDFA_TYPE</A></CODE></TD>
+<TD ALIGN="right"><CODE>"http://www.aiim.org/pdfa/ns/type#"</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPConst.NS_PDFX"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;java.lang.String</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPConst.html#NS_PDFX">NS_PDFX</A></CODE></TD>
+<TD ALIGN="right"><CODE>"http://ns.adobe.com/pdfx/1.3/"</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPConst.NS_PDFX_ID"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;java.lang.String</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPConst.html#NS_PDFX_ID">NS_PDFX_ID</A></CODE></TD>
+<TD ALIGN="right"><CODE>"http://www.npes.org/pdfx/ns/id/"</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPConst.NS_PHOTOSHOP"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;java.lang.String</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPConst.html#NS_PHOTOSHOP">NS_PHOTOSHOP</A></CODE></TD>
+<TD ALIGN="right"><CODE>"http://ns.adobe.com/photoshop/1.0/"</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPConst.NS_PNG"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;java.lang.String</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPConst.html#NS_PNG">NS_PNG</A></CODE></TD>
+<TD ALIGN="right"><CODE>"http://ns.adobe.com/png/1.0/"</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPConst.NS_PSALBUM"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;java.lang.String</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPConst.html#NS_PSALBUM">NS_PSALBUM</A></CODE></TD>
+<TD ALIGN="right"><CODE>"http://ns.adobe.com/album/1.0/"</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPConst.NS_RDF"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;java.lang.String</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPConst.html#NS_RDF">NS_RDF</A></CODE></TD>
+<TD ALIGN="right"><CODE>"http://www.w3.org/1999/02/22-rdf-syntax-ns#"</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPConst.NS_TIFF"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;java.lang.String</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPConst.html#NS_TIFF">NS_TIFF</A></CODE></TD>
+<TD ALIGN="right"><CODE>"http://ns.adobe.com/tiff/1.0/"</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPConst.NS_TRANSIENT"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;java.lang.String</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPConst.html#NS_TRANSIENT">NS_TRANSIENT</A></CODE></TD>
+<TD ALIGN="right"><CODE>"http://ns.adobe.com/xmp/transient/1.0/"</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPConst.NS_WAV"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;java.lang.String</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPConst.html#NS_WAV">NS_WAV</A></CODE></TD>
+<TD ALIGN="right"><CODE>"http://ns.adobe.com/xmp/wav/1.0/"</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPConst.NS_X"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;java.lang.String</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPConst.html#NS_X">NS_X</A></CODE></TD>
+<TD ALIGN="right"><CODE>"adobe:ns:meta/"</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPConst.NS_XML"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;java.lang.String</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPConst.html#NS_XML">NS_XML</A></CODE></TD>
+<TD ALIGN="right"><CODE>"http://www.w3.org/XML/1998/namespace"</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPConst.NS_XMP"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;java.lang.String</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPConst.html#NS_XMP">NS_XMP</A></CODE></TD>
+<TD ALIGN="right"><CODE>"http://ns.adobe.com/xap/1.0/"</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPConst.NS_XMP_BJ"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;java.lang.String</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPConst.html#NS_XMP_BJ">NS_XMP_BJ</A></CODE></TD>
+<TD ALIGN="right"><CODE>"http://ns.adobe.com/xap/1.0/bj/"</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPConst.NS_XMP_MM"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;java.lang.String</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPConst.html#NS_XMP_MM">NS_XMP_MM</A></CODE></TD>
+<TD ALIGN="right"><CODE>"http://ns.adobe.com/xap/1.0/mm/"</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPConst.NS_XMP_NOTE"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;java.lang.String</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPConst.html#NS_XMP_NOTE">NS_XMP_NOTE</A></CODE></TD>
+<TD ALIGN="right"><CODE>"http://ns.adobe.com/xmp/note/"</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPConst.NS_XMP_RIGHTS"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;java.lang.String</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPConst.html#NS_XMP_RIGHTS">NS_XMP_RIGHTS</A></CODE></TD>
+<TD ALIGN="right"><CODE>"http://ns.adobe.com/xap/1.0/rights/"</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPConst.RDF_TYPE"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;java.lang.String</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPConst.html#RDF_TYPE">RDF_TYPE</A></CODE></TD>
+<TD ALIGN="right"><CODE>"rdf:type"</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPConst.TRUESTR"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;java.lang.String</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPConst.html#TRUESTR">TRUESTR</A></CODE></TD>
+<TD ALIGN="right"><CODE>"True"</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPConst.TYPE_DIMENSIONS"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;java.lang.String</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPConst.html#TYPE_DIMENSIONS">TYPE_DIMENSIONS</A></CODE></TD>
+<TD ALIGN="right"><CODE>"http://ns.adobe.com/xap/1.0/sType/Dimensions#"</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPConst.TYPE_FONT"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;java.lang.String</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPConst.html#TYPE_FONT">TYPE_FONT</A></CODE></TD>
+<TD ALIGN="right"><CODE>"http://ns.adobe.com/xap/1.0/sType/Font#"</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPConst.TYPE_GRAPHICS"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;java.lang.String</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPConst.html#TYPE_GRAPHICS">TYPE_GRAPHICS</A></CODE></TD>
+<TD ALIGN="right"><CODE>"http://ns.adobe.com/xap/1.0/g/"</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPConst.TYPE_IDENTIFIERQUAL"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;java.lang.String</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPConst.html#TYPE_IDENTIFIERQUAL">TYPE_IDENTIFIERQUAL</A></CODE></TD>
+<TD ALIGN="right"><CODE>"http://ns.adobe.com/xmp/Identifier/qual/1.0/"</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPConst.TYPE_IMAGE"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;java.lang.String</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPConst.html#TYPE_IMAGE">TYPE_IMAGE</A></CODE></TD>
+<TD ALIGN="right"><CODE>"http://ns.adobe.com/xap/1.0/g/img/"</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPConst.TYPE_MANIFESTITEM"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;java.lang.String</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPConst.html#TYPE_MANIFESTITEM">TYPE_MANIFESTITEM</A></CODE></TD>
+<TD ALIGN="right"><CODE>"http://ns.adobe.com/xap/1.0/sType/ManifestItem#"</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPConst.TYPE_PAGEDFILE"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;java.lang.String</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPConst.html#TYPE_PAGEDFILE">TYPE_PAGEDFILE</A></CODE></TD>
+<TD ALIGN="right"><CODE>"http://ns.adobe.com/xap/1.0/t/pg/"</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPConst.TYPE_RESOURCEEVENT"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;java.lang.String</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPConst.html#TYPE_RESOURCEEVENT">TYPE_RESOURCEEVENT</A></CODE></TD>
+<TD ALIGN="right"><CODE>"http://ns.adobe.com/xap/1.0/sType/ResourceEvent#"</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPConst.TYPE_RESOURCEREF"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;java.lang.String</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPConst.html#TYPE_RESOURCEREF">TYPE_RESOURCEREF</A></CODE></TD>
+<TD ALIGN="right"><CODE>"http://ns.adobe.com/xap/1.0/sType/ResourceRef#"</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPConst.TYPE_ST_JOB"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;java.lang.String</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPConst.html#TYPE_ST_JOB">TYPE_ST_JOB</A></CODE></TD>
+<TD ALIGN="right"><CODE>"http://ns.adobe.com/xap/1.0/sType/Job#"</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPConst.TYPE_ST_VERSION"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;java.lang.String</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPConst.html#TYPE_ST_VERSION">TYPE_ST_VERSION</A></CODE></TD>
+<TD ALIGN="right"><CODE>"http://ns.adobe.com/xap/1.0/sType/Version#"</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPConst.TYPE_TEXT"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;java.lang.String</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPConst.html#TYPE_TEXT">TYPE_TEXT</A></CODE></TD>
+<TD ALIGN="right"><CODE>"http://ns.adobe.com/xap/1.0/t/"</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPConst.X_DEFAULT"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;java.lang.String</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPConst.html#X_DEFAULT">X_DEFAULT</A></CODE></TD>
+<TD ALIGN="right"><CODE>"x-default"</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPConst.XML_LANG"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;java.lang.String</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPConst.html#XML_LANG">XML_LANG</A></CODE></TD>
+<TD ALIGN="right"><CODE>"xml:lang"</CODE></TD>
+</TR>
+</FONT></TD>
+</TR>
+</TABLE>
+
+<P>
+
+<P>
+
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#EEEEFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="left" COLSPAN="3">com.adobe.xmp.<A HREF="com/adobe/xmp/XMPError.html" title="interface in com.adobe.xmp">XMPError</A></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPError.BADINDEX"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;int</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPError.html#BADINDEX">BADINDEX</A></CODE></TD>
+<TD ALIGN="right"><CODE>104</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPError.BADOPTIONS"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;int</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPError.html#BADOPTIONS">BADOPTIONS</A></CODE></TD>
+<TD ALIGN="right"><CODE>103</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPError.BADPARAM"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;int</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPError.html#BADPARAM">BADPARAM</A></CODE></TD>
+<TD ALIGN="right"><CODE>4</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPError.BADRDF"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;int</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPError.html#BADRDF">BADRDF</A></CODE></TD>
+<TD ALIGN="right"><CODE>202</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPError.BADSCHEMA"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;int</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPError.html#BADSCHEMA">BADSCHEMA</A></CODE></TD>
+<TD ALIGN="right"><CODE>101</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPError.BADSERIALIZE"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;int</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPError.html#BADSERIALIZE">BADSERIALIZE</A></CODE></TD>
+<TD ALIGN="right"><CODE>107</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPError.BADSTREAM"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;int</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPError.html#BADSTREAM">BADSTREAM</A></CODE></TD>
+<TD ALIGN="right"><CODE>204</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPError.BADVALUE"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;int</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPError.html#BADVALUE">BADVALUE</A></CODE></TD>
+<TD ALIGN="right"><CODE>5</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPError.BADXML"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;int</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPError.html#BADXML">BADXML</A></CODE></TD>
+<TD ALIGN="right"><CODE>201</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPError.BADXMP"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;int</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPError.html#BADXMP">BADXMP</A></CODE></TD>
+<TD ALIGN="right"><CODE>203</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPError.BADXPATH"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;int</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPError.html#BADXPATH">BADXPATH</A></CODE></TD>
+<TD ALIGN="right"><CODE>102</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPError.INTERNALFAILURE"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;int</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPError.html#INTERNALFAILURE">INTERNALFAILURE</A></CODE></TD>
+<TD ALIGN="right"><CODE>9</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.XMPError.UNKNOWN"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;int</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/XMPError.html#UNKNOWN">UNKNOWN</A></CODE></TD>
+<TD ALIGN="right"><CODE>0</CODE></TD>
+</TR>
+</FONT></TD>
+</TR>
+</TABLE>
+
+<P>
+
+<P>
+
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#EEEEFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="left" COLSPAN="3">com.adobe.xmp.options.<A HREF="com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options">AliasOptions</A></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.options.AliasOptions.PROP_ARRAY"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;int</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/options/AliasOptions.html#PROP_ARRAY">PROP_ARRAY</A></CODE></TD>
+<TD ALIGN="right"><CODE>512</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.options.AliasOptions.PROP_ARRAY_ALT_TEXT"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;int</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/options/AliasOptions.html#PROP_ARRAY_ALT_TEXT">PROP_ARRAY_ALT_TEXT</A></CODE></TD>
+<TD ALIGN="right"><CODE>4096</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.options.AliasOptions.PROP_ARRAY_ALTERNATE"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;int</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/options/AliasOptions.html#PROP_ARRAY_ALTERNATE">PROP_ARRAY_ALTERNATE</A></CODE></TD>
+<TD ALIGN="right"><CODE>2048</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.options.AliasOptions.PROP_ARRAY_ORDERED"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;int</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/options/AliasOptions.html#PROP_ARRAY_ORDERED">PROP_ARRAY_ORDERED</A></CODE></TD>
+<TD ALIGN="right"><CODE>1024</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.options.AliasOptions.PROP_DIRECT"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;int</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/options/AliasOptions.html#PROP_DIRECT">PROP_DIRECT</A></CODE></TD>
+<TD ALIGN="right"><CODE>0</CODE></TD>
+</TR>
+</FONT></TD>
+</TR>
+</TABLE>
+
+<P>
+
+<P>
+
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#EEEEFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="left" COLSPAN="3">com.adobe.xmp.options.<A HREF="com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options">IteratorOptions</A></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.options.IteratorOptions.INCLUDE_ALIASES"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;int</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/options/IteratorOptions.html#INCLUDE_ALIASES">INCLUDE_ALIASES</A></CODE></TD>
+<TD ALIGN="right"><CODE>2048</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.options.IteratorOptions.JUST_CHILDREN"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;int</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/options/IteratorOptions.html#JUST_CHILDREN">JUST_CHILDREN</A></CODE></TD>
+<TD ALIGN="right"><CODE>256</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.options.IteratorOptions.JUST_LEAFNAME"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;int</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/options/IteratorOptions.html#JUST_LEAFNAME">JUST_LEAFNAME</A></CODE></TD>
+<TD ALIGN="right"><CODE>1024</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.options.IteratorOptions.JUST_LEAFNODES"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;int</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/options/IteratorOptions.html#JUST_LEAFNODES">JUST_LEAFNODES</A></CODE></TD>
+<TD ALIGN="right"><CODE>512</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.options.IteratorOptions.OMIT_QUALIFIERS"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;int</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/options/IteratorOptions.html#OMIT_QUALIFIERS">OMIT_QUALIFIERS</A></CODE></TD>
+<TD ALIGN="right"><CODE>4096</CODE></TD>
+</TR>
+</FONT></TD>
+</TR>
+</TABLE>
+
+<P>
+
+<P>
+
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#EEEEFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="left" COLSPAN="3">com.adobe.xmp.options.<A HREF="com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options">ParseOptions</A></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.options.ParseOptions.ACCEPT_LATIN_1"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;int</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/options/ParseOptions.html#ACCEPT_LATIN_1">ACCEPT_LATIN_1</A></CODE></TD>
+<TD ALIGN="right"><CODE>16</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.options.ParseOptions.FIX_CONTROL_CHARS"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;int</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/options/ParseOptions.html#FIX_CONTROL_CHARS">FIX_CONTROL_CHARS</A></CODE></TD>
+<TD ALIGN="right"><CODE>8</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.options.ParseOptions.REQUIRE_XMP_META"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;int</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/options/ParseOptions.html#REQUIRE_XMP_META">REQUIRE_XMP_META</A></CODE></TD>
+<TD ALIGN="right"><CODE>1</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.options.ParseOptions.STRICT_ALIASING"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;int</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/options/ParseOptions.html#STRICT_ALIASING">STRICT_ALIASING</A></CODE></TD>
+<TD ALIGN="right"><CODE>4</CODE></TD>
+</TR>
+</FONT></TD>
+</TR>
+</TABLE>
+
+<P>
+
+<P>
+
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#EEEEFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="left" COLSPAN="3">com.adobe.xmp.options.<A HREF="com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.options.PropertyOptions.ARRAY"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;int</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/options/PropertyOptions.html#ARRAY">ARRAY</A></CODE></TD>
+<TD ALIGN="right"><CODE>512</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.options.PropertyOptions.ARRAY_ALT_TEXT"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;int</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/options/PropertyOptions.html#ARRAY_ALT_TEXT">ARRAY_ALT_TEXT</A></CODE></TD>
+<TD ALIGN="right"><CODE>4096</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.options.PropertyOptions.ARRAY_ALTERNATE"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;int</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/options/PropertyOptions.html#ARRAY_ALTERNATE">ARRAY_ALTERNATE</A></CODE></TD>
+<TD ALIGN="right"><CODE>2048</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.options.PropertyOptions.ARRAY_ORDERED"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;int</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/options/PropertyOptions.html#ARRAY_ORDERED">ARRAY_ORDERED</A></CODE></TD>
+<TD ALIGN="right"><CODE>1024</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.options.PropertyOptions.COMPACT"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;int</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/options/PropertyOptions.html#COMPACT">COMPACT</A></CODE></TD>
+<TD ALIGN="right"><CODE>8192</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.options.PropertyOptions.DELETE_EXISTING"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;int</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/options/PropertyOptions.html#DELETE_EXISTING">DELETE_EXISTING</A></CODE></TD>
+<TD ALIGN="right"><CODE>536870912</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.options.PropertyOptions.HAS_LANGUAGE"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;int</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/options/PropertyOptions.html#HAS_LANGUAGE">HAS_LANGUAGE</A></CODE></TD>
+<TD ALIGN="right"><CODE>64</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.options.PropertyOptions.HAS_QUALIFIERS"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;int</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/options/PropertyOptions.html#HAS_QUALIFIERS">HAS_QUALIFIERS</A></CODE></TD>
+<TD ALIGN="right"><CODE>16</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.options.PropertyOptions.HAS_TYPE"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;int</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/options/PropertyOptions.html#HAS_TYPE">HAS_TYPE</A></CODE></TD>
+<TD ALIGN="right"><CODE>128</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.options.PropertyOptions.NO_OPTIONS"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;int</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/options/PropertyOptions.html#NO_OPTIONS">NO_OPTIONS</A></CODE></TD>
+<TD ALIGN="right"><CODE>0</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.options.PropertyOptions.QUALIFIER"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;int</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/options/PropertyOptions.html#QUALIFIER">QUALIFIER</A></CODE></TD>
+<TD ALIGN="right"><CODE>32</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.options.PropertyOptions.SCHEMA_NODE"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;int</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/options/PropertyOptions.html#SCHEMA_NODE">SCHEMA_NODE</A></CODE></TD>
+<TD ALIGN="right"><CODE>-2147483648</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.options.PropertyOptions.STRUCT"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;int</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/options/PropertyOptions.html#STRUCT">STRUCT</A></CODE></TD>
+<TD ALIGN="right"><CODE>256</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.options.PropertyOptions.URI"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;int</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/options/PropertyOptions.html#URI">URI</A></CODE></TD>
+<TD ALIGN="right"><CODE>2</CODE></TD>
+</TR>
+</FONT></TD>
+</TR>
+</TABLE>
+
+<P>
+
+<P>
+
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#EEEEFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="left" COLSPAN="3">com.adobe.xmp.options.<A HREF="com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.options.SerializeOptions.ENCODE_UTF16BE"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;int</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/options/SerializeOptions.html#ENCODE_UTF16BE">ENCODE_UTF16BE</A></CODE></TD>
+<TD ALIGN="right"><CODE>2</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.options.SerializeOptions.ENCODE_UTF16LE"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;int</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/options/SerializeOptions.html#ENCODE_UTF16LE">ENCODE_UTF16LE</A></CODE></TD>
+<TD ALIGN="right"><CODE>3</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.options.SerializeOptions.ENCODE_UTF8"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;int</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/options/SerializeOptions.html#ENCODE_UTF8">ENCODE_UTF8</A></CODE></TD>
+<TD ALIGN="right"><CODE>0</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.options.SerializeOptions.EXACT_PACKET_LENGTH"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;int</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/options/SerializeOptions.html#EXACT_PACKET_LENGTH">EXACT_PACKET_LENGTH</A></CODE></TD>
+<TD ALIGN="right"><CODE>512</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.options.SerializeOptions.INCLUDE_THUMBNAIL_PAD"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;int</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/options/SerializeOptions.html#INCLUDE_THUMBNAIL_PAD">INCLUDE_THUMBNAIL_PAD</A></CODE></TD>
+<TD ALIGN="right"><CODE>256</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.options.SerializeOptions.OMIT_PACKET_WRAPPER"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;int</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/options/SerializeOptions.html#OMIT_PACKET_WRAPPER">OMIT_PACKET_WRAPPER</A></CODE></TD>
+<TD ALIGN="right"><CODE>16</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.options.SerializeOptions.READONLY_PACKET"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;int</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/options/SerializeOptions.html#READONLY_PACKET">READONLY_PACKET</A></CODE></TD>
+<TD ALIGN="right"><CODE>32</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.options.SerializeOptions.SORT"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;int</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/options/SerializeOptions.html#SORT">SORT</A></CODE></TD>
+<TD ALIGN="right"><CODE>4096</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.options.SerializeOptions.USE_COMPACT_FORMAT"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;int</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/options/SerializeOptions.html#USE_COMPACT_FORMAT">USE_COMPACT_FORMAT</A></CODE></TD>
+<TD ALIGN="right"><CODE>64</CODE></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<A NAME="com.adobe.xmp.options.SerializeOptions.WRITE_ALIAS_COMMENTS"><!-- --></A><TD ALIGN="right"><FONT SIZE="-1">
+<CODE>public&nbsp;static&nbsp;final&nbsp;int</CODE></FONT></TD>
+<TD ALIGN="left"><CODE><A HREF="com/adobe/xmp/options/SerializeOptions.html#WRITE_ALIAS_COMMENTS">WRITE_ALIAS_COMMENTS</A></CODE></TD>
+<TD ALIGN="right"><CODE>1024</CODE></TD>
+</TR>
+</FONT></TD>
+</TR>
+</TABLE>
+
+<P>
+
+<P>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="index.html?constant-values.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="constant-values.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/deprecated-list.html b/java/XMPCore/docs/deprecated-list.html
new file mode 100644
index 0000000..6ad197c
--- /dev/null
+++ b/java/XMPCore/docs/deprecated-list.html
@@ -0,0 +1,157 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:51 CEST 2007 -->
+<TITLE>
+Deprecated List
+</TITLE>
+
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="Deprecated List";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Deprecated</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="index.html?deprecated-list.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="deprecated-list.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<CENTER>
+<H2>
+<B>Deprecated API</B></H2>
+</CENTER>
+<HR SIZE="4" NOSHADE>
+<B>Contents</B><UL>
+<LI><A HREF="#field">Deprecated Fields</A>
+</UL>
+
+<A NAME="field"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+<B>Deprecated Fields</B></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><A HREF="com/adobe/xmp/options/IteratorOptions.html#INCLUDE_ALIASES">com.adobe.xmp.options.IteratorOptions.INCLUDE_ALIASES</A>
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<I>it is commonly preferred to work with the base properties</I>&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Deprecated</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="index.html?deprecated-list.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="deprecated-list.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/help-doc.html b/java/XMPCore/docs/help-doc.html
new file mode 100644
index 0000000..525fe95
--- /dev/null
+++ b/java/XMPCore/docs/help-doc.html
@@ -0,0 +1,219 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:51 CEST 2007 -->
+<TITLE>
+API Help
+</TITLE>
+
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="API Help";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Help</B></FONT>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="index.html?help-doc.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="help-doc.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<CENTER>
+<H1>
+How This API Document Is Organized</H1>
+</CENTER>
+This API (Application Programming Interface) document has pages corresponding to the items in the navigation bar, described as follows.<H3>
+Overview</H3>
+<BLOCKQUOTE>
+
+<P>
+The <A HREF="overview-summary.html">Overview</A> page is the front page of this API document and provides a list of all packages with a summary for each. This page can also contain an overall description of the set of packages.</BLOCKQUOTE>
+<H3>
+Package</H3>
+<BLOCKQUOTE>
+
+<P>
+Each package has a page that contains a list of its classes and interfaces, with a summary for each. This page can contain four categories:<UL>
+<LI>Interfaces (italic)<LI>Classes<LI>Enums<LI>Exceptions<LI>Errors<LI>Annotation Types</UL>
+</BLOCKQUOTE>
+<H3>
+Class/Interface</H3>
+<BLOCKQUOTE>
+
+<P>
+Each class, interface, nested class and nested interface has its own separate page. Each of these pages has three sections consisting of a class/interface description, summary tables, and detailed member descriptions:<UL>
+<LI>Class inheritance diagram<LI>Direct Subclasses<LI>All Known Subinterfaces<LI>All Known Implementing Classes<LI>Class/interface declaration<LI>Class/interface description
+<P>
+<LI>Nested Class Summary<LI>Field Summary<LI>Constructor Summary<LI>Method Summary
+<P>
+<LI>Field Detail<LI>Constructor Detail<LI>Method Detail</UL>
+Each summary entry contains the first sentence from the detailed description for that item. The summary entries are alphabetical, while the detailed descriptions are in the order they appear in the source code. This preserves the logical groupings established by the programmer.</BLOCKQUOTE>
+</BLOCKQUOTE>
+<H3>
+Annotation Type</H3>
+<BLOCKQUOTE>
+
+<P>
+Each annotation type has its own separate page with the following sections:<UL>
+<LI>Annotation Type declaration<LI>Annotation Type description<LI>Required Element Summary<LI>Optional Element Summary<LI>Element Detail</UL>
+</BLOCKQUOTE>
+</BLOCKQUOTE>
+<H3>
+Enum</H3>
+<BLOCKQUOTE>
+
+<P>
+Each enum has its own separate page with the following sections:<UL>
+<LI>Enum declaration<LI>Enum description<LI>Enum Constant Summary<LI>Enum Constant Detail</UL>
+</BLOCKQUOTE>
+<H3>
+Use</H3>
+<BLOCKQUOTE>
+Each documented package, class and interface has its own Use page. This page describes what packages, classes, methods, constructors and fields use any part of the given class or package. Given a class or interface A, its Use page includes subclasses of A, fields declared as A, methods that return A, and methods and constructors with parameters of type A. You can access this page by first going to the package, class or interface, then clicking on the "Use" link in the navigation bar.</BLOCKQUOTE>
+<H3>
+Tree (Class Hierarchy)</H3>
+<BLOCKQUOTE>
+There is a <A HREF="overview-tree.html">Class Hierarchy</A> page for all packages, plus a hierarchy for each package. Each hierarchy page contains a list of classes and a list of interfaces. The classes are organized by inheritance structure starting with <code>java.lang.Object</code>. The interfaces do not inherit from <code>java.lang.Object</code>.<UL>
+<LI>When viewing the Overview page, clicking on "Tree" displays the hierarchy for all packages.<LI>When viewing a particular package, class or interface page, clicking "Tree" displays the hierarchy for only that package.</UL>
+</BLOCKQUOTE>
+<H3>
+Deprecated API</H3>
+<BLOCKQUOTE>
+The <A HREF="deprecated-list.html">Deprecated API</A> page lists all of the API that have been deprecated. A deprecated API is not recommended for use, generally due to improvements, and a replacement API is usually given. Deprecated APIs may be removed in future implementations.</BLOCKQUOTE>
+<H3>
+Index</H3>
+<BLOCKQUOTE>
+The <A HREF="index-files/index-1.html">Index</A> contains an alphabetic list of all classes, interfaces, constructors, methods, and fields.</BLOCKQUOTE>
+<H3>
+Prev/Next</H3>
+These links take you to the next or previous class, interface, package, or related page.<H3>
+Frames/No Frames</H3>
+These links show and hide the HTML frames. All pages are available with or without frames.
+<P>
+<H3>
+Serialized Form</H3>
+Each serializable or externalizable class has a description of its serialization fields and methods. This information is of interest to re-implementors, not to developers using the API. While there is no link in the navigation bar, you can get to this information by going to any serialized class and clicking "Serialized Form" in the "See also" section of the class description.
+<P>
+<H3>
+Constant Field Values</H3>
+The <a href="constant-values.html">Constant Field Values</a> page lists the static final fields and their values.
+<P>
+<FONT SIZE="-1">
+<EM>
+This help file applies to API documentation generated using the standard doclet.</EM>
+</FONT>
+<BR>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Help</B></FONT>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="index.html?help-doc.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="help-doc.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/index-files/index-1.html b/java/XMPCore/docs/index-files/index-1.html
new file mode 100644
index 0000000..a050b61
--- /dev/null
+++ b/java/XMPCore/docs/index-files/index-1.html
@@ -0,0 +1,182 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:51 CEST 2007 -->
+<TITLE>
+A-Index
+</TITLE>
+
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="A-Index";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Index</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV LETTER&nbsp;
+&nbsp;<A HREF="index-2.html"><B>NEXT LETTER</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../index.html?index-filesindex-1.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="index-1.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<A HREF="index-1.html">A</A> <A HREF="index-2.html">B</A> <A HREF="index-3.html">C</A> <A HREF="index-4.html">D</A> <A HREF="index-5.html">E</A> <A HREF="index-6.html">F</A> <A HREF="index-7.html">G</A> <A HREF="index-8.html">H</A> <A HREF="index-9.html">I</A> <A HREF="index-10.html">J</A> <A HREF="index-11.html">M</A> <A HREF="index-12.html">N</A> <A HREF="index-13.html">O</A> <A HREF="index-14.html">P</A> <A HREF="index-15.html">Q</A> <A HREF="index-16.html">R</A> <A HREF="index-17.html">S</A> <A HREF="index-18.html">T</A> <A HREF="index-19.html">U</A> <A HREF="index-20.html">W</A> <A HREF="index-21.html">X</A> <HR>
+<A NAME="_A_"><!-- --></A><H2>
+<B>A</B></H2>
+<DL>
+<DT><A HREF="../com/adobe/xmp/options/ParseOptions.html#ACCEPT_LATIN_1"><B>ACCEPT_LATIN_1</B></A> -
+Static variable in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options">ParseOptions</A>
+<DD>If the input is not unicode, try to parse it as ISO-8859-1.
+<DT><A HREF="../com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options"><B>AliasOptions</B></A> - Class in <A HREF="../com/adobe/xmp/options/package-summary.html">com.adobe.xmp.options</A><DD>Options for <A HREF="../com/adobe/xmp/XMPSchemaRegistry.html#registerAlias(java.lang.String, java.lang.String, java.lang.String, java.lang.String, com.adobe.xmp.options.AliasOptions)"><CODE>XMPSchemaRegistry.registerAlias( String, String, String, String,
+ AliasOptions)</CODE></A>.<DT><A HREF="../com/adobe/xmp/options/AliasOptions.html#AliasOptions()"><B>AliasOptions()</B></A> -
+Constructor for class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options">AliasOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/AliasOptions.html#AliasOptions(int)"><B>AliasOptions(int)</B></A> -
+Constructor for class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options">AliasOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#appendArrayItem(java.lang.String, java.lang.String, com.adobe.xmp.options.PropertyOptions, java.lang.String, com.adobe.xmp.options.PropertyOptions)"><B>appendArrayItem(String, String, PropertyOptions, String, PropertyOptions)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>Simplifies the construction of an array by not requiring that you pre-create an empty array.
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#appendArrayItem(java.lang.String, java.lang.String, java.lang.String)"><B>appendArrayItem(String, String, String)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPUtils.html#appendProperties(com.adobe.xmp.XMPMeta, com.adobe.xmp.XMPMeta, boolean, boolean)"><B>appendProperties(XMPMeta, XMPMeta, boolean, boolean)</B></A> -
+Static method in class com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPUtils.html" title="class in com.adobe.xmp">XMPUtils</A>
+<DD>Alias without the new option <code>deleteEmptyValues</code>.
+<DT><A HREF="../com/adobe/xmp/XMPUtils.html#appendProperties(com.adobe.xmp.XMPMeta, com.adobe.xmp.XMPMeta, boolean, boolean, boolean)"><B>appendProperties(XMPMeta, XMPMeta, boolean, boolean, boolean)</B></A> -
+Static method in class com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPUtils.html" title="class in com.adobe.xmp">XMPUtils</A>
+<DD>Append properties from one XMP object to another.
+<DT><A HREF="../com/adobe/xmp/options/PropertyOptions.html#ARRAY"><B>ARRAY</B></A> -
+Static variable in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/PropertyOptions.html#ARRAY_ALT_TEXT"><B>ARRAY_ALT_TEXT</B></A> -
+Static variable in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/PropertyOptions.html#ARRAY_ALTERNATE"><B>ARRAY_ALTERNATE</B></A> -
+Static variable in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPConst.html#ARRAY_ITEM_NAME"><B>ARRAY_ITEM_NAME</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A>
+<DD>Node name of an array item.
+<DT><A HREF="../com/adobe/xmp/XMPConst.html#ARRAY_LAST_ITEM"><B>ARRAY_LAST_ITEM</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A>
+<DD>Index that has the meaning to be always the last item in an array.
+<DT><A HREF="../com/adobe/xmp/options/PropertyOptions.html#ARRAY_ORDERED"><B>ARRAY_ORDERED</B></A> -
+Static variable in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/PropertyOptions.html#assertConsistency(int)"><B>assertConsistency(int)</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>
+<DD>Checks that a node not a struct and array at the same time;
+ and URI cannot be a struct.
+</DL>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Index</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV LETTER&nbsp;
+&nbsp;<A HREF="index-2.html"><B>NEXT LETTER</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../index.html?index-filesindex-1.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="index-1.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<A HREF="index-1.html">A</A> <A HREF="index-2.html">B</A> <A HREF="index-3.html">C</A> <A HREF="index-4.html">D</A> <A HREF="index-5.html">E</A> <A HREF="index-6.html">F</A> <A HREF="index-7.html">G</A> <A HREF="index-8.html">H</A> <A HREF="index-9.html">I</A> <A HREF="index-10.html">J</A> <A HREF="index-11.html">M</A> <A HREF="index-12.html">N</A> <A HREF="index-13.html">O</A> <A HREF="index-14.html">P</A> <A HREF="index-15.html">Q</A> <A HREF="index-16.html">R</A> <A HREF="index-17.html">S</A> <A HREF="index-18.html">T</A> <A HREF="index-19.html">U</A> <A HREF="index-20.html">W</A> <A HREF="index-21.html">X</A> <HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/index-files/index-10.html b/java/XMPCore/docs/index-files/index-10.html
new file mode 100644
index 0000000..408ce86
--- /dev/null
+++ b/java/XMPCore/docs/index-files/index-10.html
@@ -0,0 +1,147 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:51 CEST 2007 -->
+<TITLE>
+J-Index
+</TITLE>
+
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="J-Index";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Index</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="index-9.html"><B>PREV LETTER</B></A>&nbsp;
+&nbsp;<A HREF="index-11.html"><B>NEXT LETTER</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../index.html?index-filesindex-10.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="index-10.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<A HREF="index-1.html">A</A> <A HREF="index-2.html">B</A> <A HREF="index-3.html">C</A> <A HREF="index-4.html">D</A> <A HREF="index-5.html">E</A> <A HREF="index-6.html">F</A> <A HREF="index-7.html">G</A> <A HREF="index-8.html">H</A> <A HREF="index-9.html">I</A> <A HREF="index-10.html">J</A> <A HREF="index-11.html">M</A> <A HREF="index-12.html">N</A> <A HREF="index-13.html">O</A> <A HREF="index-14.html">P</A> <A HREF="index-15.html">Q</A> <A HREF="index-16.html">R</A> <A HREF="index-17.html">S</A> <A HREF="index-18.html">T</A> <A HREF="index-19.html">U</A> <A HREF="index-20.html">W</A> <A HREF="index-21.html">X</A> <HR>
+<A NAME="_J_"><!-- --></A><H2>
+<B>J</B></H2>
+<DL>
+<DT><A HREF="../com/adobe/xmp/options/IteratorOptions.html#JUST_CHILDREN"><B>JUST_CHILDREN</B></A> -
+Static variable in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options">IteratorOptions</A>
+<DD>Just do the immediate children of the root, default is subtree.
+<DT><A HREF="../com/adobe/xmp/options/IteratorOptions.html#JUST_LEAFNAME"><B>JUST_LEAFNAME</B></A> -
+Static variable in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options">IteratorOptions</A>
+<DD>Return just the leaf part of the path, default is the full path.
+<DT><A HREF="../com/adobe/xmp/options/IteratorOptions.html#JUST_LEAFNODES"><B>JUST_LEAFNODES</B></A> -
+Static variable in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options">IteratorOptions</A>
+<DD>Just do the leaf nodes, default is all nodes in the subtree.
+</DL>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Index</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="index-9.html"><B>PREV LETTER</B></A>&nbsp;
+&nbsp;<A HREF="index-11.html"><B>NEXT LETTER</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../index.html?index-filesindex-10.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="index-10.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<A HREF="index-1.html">A</A> <A HREF="index-2.html">B</A> <A HREF="index-3.html">C</A> <A HREF="index-4.html">D</A> <A HREF="index-5.html">E</A> <A HREF="index-6.html">F</A> <A HREF="index-7.html">G</A> <A HREF="index-8.html">H</A> <A HREF="index-9.html">I</A> <A HREF="index-10.html">J</A> <A HREF="index-11.html">M</A> <A HREF="index-12.html">N</A> <A HREF="index-13.html">O</A> <A HREF="index-14.html">P</A> <A HREF="index-15.html">Q</A> <A HREF="index-16.html">R</A> <A HREF="index-17.html">S</A> <A HREF="index-18.html">T</A> <A HREF="index-19.html">U</A> <A HREF="index-20.html">W</A> <A HREF="index-21.html">X</A> <HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/index-files/index-11.html b/java/XMPCore/docs/index-files/index-11.html
new file mode 100644
index 0000000..e09de58
--- /dev/null
+++ b/java/XMPCore/docs/index-files/index-11.html
@@ -0,0 +1,141 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:51 CEST 2007 -->
+<TITLE>
+M-Index
+</TITLE>
+
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="M-Index";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Index</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="index-10.html"><B>PREV LETTER</B></A>&nbsp;
+&nbsp;<A HREF="index-12.html"><B>NEXT LETTER</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../index.html?index-filesindex-11.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="index-11.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<A HREF="index-1.html">A</A> <A HREF="index-2.html">B</A> <A HREF="index-3.html">C</A> <A HREF="index-4.html">D</A> <A HREF="index-5.html">E</A> <A HREF="index-6.html">F</A> <A HREF="index-7.html">G</A> <A HREF="index-8.html">H</A> <A HREF="index-9.html">I</A> <A HREF="index-10.html">J</A> <A HREF="index-11.html">M</A> <A HREF="index-12.html">N</A> <A HREF="index-13.html">O</A> <A HREF="index-14.html">P</A> <A HREF="index-15.html">Q</A> <A HREF="index-16.html">R</A> <A HREF="index-17.html">S</A> <A HREF="index-18.html">T</A> <A HREF="index-19.html">U</A> <A HREF="index-20.html">W</A> <A HREF="index-21.html">X</A> <HR>
+<A NAME="_M_"><!-- --></A><H2>
+<B>M</B></H2>
+<DL>
+<DT><A HREF="../com/adobe/xmp/options/PropertyOptions.html#mergeWith(com.adobe.xmp.options.PropertyOptions)"><B>mergeWith(PropertyOptions)</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>
+<DD>Merges the set options of a another options object with this.
+</DL>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Index</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="index-10.html"><B>PREV LETTER</B></A>&nbsp;
+&nbsp;<A HREF="index-12.html"><B>NEXT LETTER</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../index.html?index-filesindex-11.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="index-11.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<A HREF="index-1.html">A</A> <A HREF="index-2.html">B</A> <A HREF="index-3.html">C</A> <A HREF="index-4.html">D</A> <A HREF="index-5.html">E</A> <A HREF="index-6.html">F</A> <A HREF="index-7.html">G</A> <A HREF="index-8.html">H</A> <A HREF="index-9.html">I</A> <A HREF="index-10.html">J</A> <A HREF="index-11.html">M</A> <A HREF="index-12.html">N</A> <A HREF="index-13.html">O</A> <A HREF="index-14.html">P</A> <A HREF="index-15.html">Q</A> <A HREF="index-16.html">R</A> <A HREF="index-17.html">S</A> <A HREF="index-18.html">T</A> <A HREF="index-19.html">U</A> <A HREF="index-20.html">W</A> <A HREF="index-21.html">X</A> <HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/index-files/index-12.html b/java/XMPCore/docs/index-files/index-12.html
new file mode 100644
index 0000000..d67566f
--- /dev/null
+++ b/java/XMPCore/docs/index-files/index-12.html
@@ -0,0 +1,246 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:51 CEST 2007 -->
+<TITLE>
+N-Index
+</TITLE>
+
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="N-Index";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Index</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="index-11.html"><B>PREV LETTER</B></A>&nbsp;
+&nbsp;<A HREF="index-13.html"><B>NEXT LETTER</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../index.html?index-filesindex-12.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="index-12.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<A HREF="index-1.html">A</A> <A HREF="index-2.html">B</A> <A HREF="index-3.html">C</A> <A HREF="index-4.html">D</A> <A HREF="index-5.html">E</A> <A HREF="index-6.html">F</A> <A HREF="index-7.html">G</A> <A HREF="index-8.html">H</A> <A HREF="index-9.html">I</A> <A HREF="index-10.html">J</A> <A HREF="index-11.html">M</A> <A HREF="index-12.html">N</A> <A HREF="index-13.html">O</A> <A HREF="index-14.html">P</A> <A HREF="index-15.html">Q</A> <A HREF="index-16.html">R</A> <A HREF="index-17.html">S</A> <A HREF="index-18.html">T</A> <A HREF="index-19.html">U</A> <A HREF="index-20.html">W</A> <A HREF="index-21.html">X</A> <HR>
+<A NAME="_N_"><!-- --></A><H2>
+<B>N</B></H2>
+<DL>
+<DT><A HREF="../com/adobe/xmp/options/PropertyOptions.html#NO_OPTIONS"><B>NO_OPTIONS</B></A> -
+Static variable in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPConst.html#NS_ADOBESTOCKPHOTO"><B>NS_ADOBESTOCKPHOTO</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPConst.html#NS_ASF"><B>NS_ASF</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPConst.html#NS_CAMERARAW"><B>NS_CAMERARAW</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPConst.html#NS_DC"><B>NS_DC</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A>
+<DD>The XML namespace for the Dublin Core schema.
+<DT><A HREF="../com/adobe/xmp/XMPConst.html#NS_DC_DEPRECATED"><B>NS_DC_DEPRECATED</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A>
+<DD>legaciy dublin core NS, will be converted to NS_DC
+<DT><A HREF="../com/adobe/xmp/XMPConst.html#NS_DM"><B>NS_DM</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPConst.html#NS_EXIF"><B>NS_EXIF</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A>
+<DD>The XML namespace for Adobe's EXIF schema.
+<DT><A HREF="../com/adobe/xmp/XMPConst.html#NS_EXIF_AUX"><B>NS_EXIF_AUX</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPConst.html#NS_IPTCCORE"><B>NS_IPTCCORE</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A>
+<DD>The XML namespace for the IPTC Core schema.
+<DT><A HREF="../com/adobe/xmp/XMPConst.html#NS_IX"><B>NS_IX</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPConst.html#NS_JP2K"><B>NS_JP2K</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPConst.html#NS_JPEG"><B>NS_JPEG</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPConst.html#NS_PDF"><B>NS_PDF</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A>
+<DD>The XML namespace for the PDF schema.
+<DT><A HREF="../com/adobe/xmp/XMPConst.html#NS_PDFA_EXTENSION"><B>NS_PDFA_EXTENSION</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPConst.html#NS_PDFA_FIELD"><B>NS_PDFA_FIELD</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPConst.html#NS_PDFA_ID"><B>NS_PDFA_ID</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPConst.html#NS_PDFA_PROPERTY"><B>NS_PDFA_PROPERTY</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPConst.html#NS_PDFA_SCHEMA"><B>NS_PDFA_SCHEMA</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPConst.html#NS_PDFA_TYPE"><B>NS_PDFA_TYPE</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPConst.html#NS_PDFX"><B>NS_PDFX</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A>
+<DD>The XML namespace for the PDF schema.
+<DT><A HREF="../com/adobe/xmp/XMPConst.html#NS_PDFX_ID"><B>NS_PDFX_ID</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPConst.html#NS_PHOTOSHOP"><B>NS_PHOTOSHOP</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A>
+<DD>The XML namespace for the Photoshop custom schema.
+<DT><A HREF="../com/adobe/xmp/XMPConst.html#NS_PNG"><B>NS_PNG</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPConst.html#NS_PSALBUM"><B>NS_PSALBUM</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A>
+<DD>The XML namespace for the Photoshop Album schema.
+<DT><A HREF="../com/adobe/xmp/XMPConst.html#NS_RDF"><B>NS_RDF</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A>
+<DD>The XML namespace for RDF.
+<DT><A HREF="../com/adobe/xmp/XMPConst.html#NS_TIFF"><B>NS_TIFF</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A>
+<DD>The XML namespace for Adobe's TIFF schema.
+<DT><A HREF="../com/adobe/xmp/XMPConst.html#NS_TRANSIENT"><B>NS_TRANSIENT</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPConst.html#NS_WAV"><B>NS_WAV</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPConst.html#NS_X"><B>NS_X</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A>
+<DD>The XML namespace Adobe XMP Metadata.
+<DT><A HREF="../com/adobe/xmp/XMPConst.html#NS_XML"><B>NS_XML</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A>
+<DD>The XML namespace for XML.
+<DT><A HREF="../com/adobe/xmp/XMPConst.html#NS_XMP"><B>NS_XMP</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A>
+<DD>The XML namespace for the XMP "basic" schema.
+<DT><A HREF="../com/adobe/xmp/XMPConst.html#NS_XMP_BJ"><B>NS_XMP_BJ</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A>
+<DD>The XML namespace for the job management schema.
+<DT><A HREF="../com/adobe/xmp/XMPConst.html#NS_XMP_MM"><B>NS_XMP_MM</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A>
+<DD>The XML namespace for the XMP digital asset management schema.
+<DT><A HREF="../com/adobe/xmp/XMPConst.html#NS_XMP_NOTE"><B>NS_XMP_NOTE</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A>
+<DD>The XML namespace for the job management schema.
+<DT><A HREF="../com/adobe/xmp/XMPConst.html#NS_XMP_RIGHTS"><B>NS_XMP_RIGHTS</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A>
+<DD>The XML namespace for the XMP copyright schema.
+</DL>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Index</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="index-11.html"><B>PREV LETTER</B></A>&nbsp;
+&nbsp;<A HREF="index-13.html"><B>NEXT LETTER</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../index.html?index-filesindex-12.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="index-12.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<A HREF="index-1.html">A</A> <A HREF="index-2.html">B</A> <A HREF="index-3.html">C</A> <A HREF="index-4.html">D</A> <A HREF="index-5.html">E</A> <A HREF="index-6.html">F</A> <A HREF="index-7.html">G</A> <A HREF="index-8.html">H</A> <A HREF="index-9.html">I</A> <A HREF="index-10.html">J</A> <A HREF="index-11.html">M</A> <A HREF="index-12.html">N</A> <A HREF="index-13.html">O</A> <A HREF="index-14.html">P</A> <A HREF="index-15.html">Q</A> <A HREF="index-16.html">R</A> <A HREF="index-17.html">S</A> <A HREF="index-18.html">T</A> <A HREF="index-19.html">U</A> <A HREF="index-20.html">W</A> <A HREF="index-21.html">X</A> <HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/index-files/index-13.html b/java/XMPCore/docs/index-files/index-13.html
new file mode 100644
index 0000000..039c075
--- /dev/null
+++ b/java/XMPCore/docs/index-files/index-13.html
@@ -0,0 +1,150 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:51 CEST 2007 -->
+<TITLE>
+O-Index
+</TITLE>
+
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="O-Index";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Index</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="index-12.html"><B>PREV LETTER</B></A>&nbsp;
+&nbsp;<A HREF="index-14.html"><B>NEXT LETTER</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../index.html?index-filesindex-13.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="index-13.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<A HREF="index-1.html">A</A> <A HREF="index-2.html">B</A> <A HREF="index-3.html">C</A> <A HREF="index-4.html">D</A> <A HREF="index-5.html">E</A> <A HREF="index-6.html">F</A> <A HREF="index-7.html">G</A> <A HREF="index-8.html">H</A> <A HREF="index-9.html">I</A> <A HREF="index-10.html">J</A> <A HREF="index-11.html">M</A> <A HREF="index-12.html">N</A> <A HREF="index-13.html">O</A> <A HREF="index-14.html">P</A> <A HREF="index-15.html">Q</A> <A HREF="index-16.html">R</A> <A HREF="index-17.html">S</A> <A HREF="index-18.html">T</A> <A HREF="index-19.html">U</A> <A HREF="index-20.html">W</A> <A HREF="index-21.html">X</A> <HR>
+<A NAME="_O_"><!-- --></A><H2>
+<B>O</B></H2>
+<DL>
+<DT><A HREF="../com/adobe/xmp/options/SerializeOptions.html#OMIT_PACKET_WRAPPER"><B>OMIT_PACKET_WRAPPER</B></A> -
+Static variable in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>
+<DD>Omit the XML packet wrapper.
+<DT><A HREF="../com/adobe/xmp/options/IteratorOptions.html#OMIT_QUALIFIERS"><B>OMIT_QUALIFIERS</B></A> -
+Static variable in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options">IteratorOptions</A>
+<DD>Omit all qualifiers.
+<DT><A HREF="../com/adobe/xmp/options/Options.html" title="class in com.adobe.xmp.options"><B>Options</B></A> - Class in <A HREF="../com/adobe/xmp/options/package-summary.html">com.adobe.xmp.options</A><DD>The base class for a collection of 32 flag bits.<DT><A HREF="../com/adobe/xmp/options/Options.html#Options()"><B>Options()</B></A> -
+Constructor for class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/Options.html" title="class in com.adobe.xmp.options">Options</A>
+<DD>The default constructor.
+<DT><A HREF="../com/adobe/xmp/options/Options.html#Options(int)"><B>Options(int)</B></A> -
+Constructor for class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/Options.html" title="class in com.adobe.xmp.options">Options</A>
+<DD>Constructor with the options bit mask.
+</DL>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Index</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="index-12.html"><B>PREV LETTER</B></A>&nbsp;
+&nbsp;<A HREF="index-14.html"><B>NEXT LETTER</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../index.html?index-filesindex-13.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="index-13.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<A HREF="index-1.html">A</A> <A HREF="index-2.html">B</A> <A HREF="index-3.html">C</A> <A HREF="index-4.html">D</A> <A HREF="index-5.html">E</A> <A HREF="index-6.html">F</A> <A HREF="index-7.html">G</A> <A HREF="index-8.html">H</A> <A HREF="index-9.html">I</A> <A HREF="index-10.html">J</A> <A HREF="index-11.html">M</A> <A HREF="index-12.html">N</A> <A HREF="index-13.html">O</A> <A HREF="index-14.html">P</A> <A HREF="index-15.html">Q</A> <A HREF="index-16.html">R</A> <A HREF="index-17.html">S</A> <A HREF="index-18.html">T</A> <A HREF="index-19.html">U</A> <A HREF="index-20.html">W</A> <A HREF="index-21.html">X</A> <HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/index-files/index-14.html b/java/XMPCore/docs/index-files/index-14.html
new file mode 100644
index 0000000..968c0b7
--- /dev/null
+++ b/java/XMPCore/docs/index-files/index-14.html
@@ -0,0 +1,182 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:51 CEST 2007 -->
+<TITLE>
+P-Index
+</TITLE>
+
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="P-Index";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Index</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="index-13.html"><B>PREV LETTER</B></A>&nbsp;
+&nbsp;<A HREF="index-15.html"><B>NEXT LETTER</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../index.html?index-filesindex-14.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="index-14.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<A HREF="index-1.html">A</A> <A HREF="index-2.html">B</A> <A HREF="index-3.html">C</A> <A HREF="index-4.html">D</A> <A HREF="index-5.html">E</A> <A HREF="index-6.html">F</A> <A HREF="index-7.html">G</A> <A HREF="index-8.html">H</A> <A HREF="index-9.html">I</A> <A HREF="index-10.html">J</A> <A HREF="index-11.html">M</A> <A HREF="index-12.html">N</A> <A HREF="index-13.html">O</A> <A HREF="index-14.html">P</A> <A HREF="index-15.html">Q</A> <A HREF="index-16.html">R</A> <A HREF="index-17.html">S</A> <A HREF="index-18.html">T</A> <A HREF="index-19.html">U</A> <A HREF="index-20.html">W</A> <A HREF="index-21.html">X</A> <HR>
+<A NAME="_P_"><!-- --></A><H2>
+<B>P</B></H2>
+<DL>
+<DT><A HREF="../com/adobe/xmp/XMPMetaFactory.html#parse(java.io.InputStream)"><B>parse(InputStream)</B></A> -
+Static method in class com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMetaFactory.html" title="class in com.adobe.xmp">XMPMetaFactory</A>
+<DD>Parsing with default options.
+<DT><A HREF="../com/adobe/xmp/XMPMetaFactory.html#parse(java.io.InputStream, com.adobe.xmp.options.ParseOptions)"><B>parse(InputStream, ParseOptions)</B></A> -
+Static method in class com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMetaFactory.html" title="class in com.adobe.xmp">XMPMetaFactory</A>
+<DD>These functions support parsing serialized RDF into an XMP object, and serailizing an XMP
+ object into RDF.
+<DT><A HREF="../com/adobe/xmp/XMPMetaFactory.html#parseFromBuffer(byte[])"><B>parseFromBuffer(byte[])</B></A> -
+Static method in class com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMetaFactory.html" title="class in com.adobe.xmp">XMPMetaFactory</A>
+<DD>Parsing with default options.
+<DT><A HREF="../com/adobe/xmp/XMPMetaFactory.html#parseFromBuffer(byte[], com.adobe.xmp.options.ParseOptions)"><B>parseFromBuffer(byte[], ParseOptions)</B></A> -
+Static method in class com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMetaFactory.html" title="class in com.adobe.xmp">XMPMetaFactory</A>
+<DD>Creates an <code>XMPMeta</code>-object from a byte-buffer.
+<DT><A HREF="../com/adobe/xmp/XMPMetaFactory.html#parseFromString(java.lang.String)"><B>parseFromString(String)</B></A> -
+Static method in class com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMetaFactory.html" title="class in com.adobe.xmp">XMPMetaFactory</A>
+<DD>Parsing with default options.
+<DT><A HREF="../com/adobe/xmp/XMPMetaFactory.html#parseFromString(java.lang.String, com.adobe.xmp.options.ParseOptions)"><B>parseFromString(String, ParseOptions)</B></A> -
+Static method in class com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMetaFactory.html" title="class in com.adobe.xmp">XMPMetaFactory</A>
+<DD>Creates an <code>XMPMeta</code>-object from a string.
+<DT><A HREF="../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options"><B>ParseOptions</B></A> - Class in <A HREF="../com/adobe/xmp/options/package-summary.html">com.adobe.xmp.options</A><DD>Options for <A HREF="../com/adobe/xmp/XMPMetaFactory.html#parse(java.io.InputStream, com.adobe.xmp.options.ParseOptions)"><CODE>XMPMetaFactory.parse(InputStream, ParseOptions)</CODE></A>.<DT><A HREF="../com/adobe/xmp/options/ParseOptions.html#ParseOptions()"><B>ParseOptions()</B></A> -
+Constructor for class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options">ParseOptions</A>
+<DD>Sets the options to the default values.
+<DT><A HREF="../com/adobe/xmp/options/AliasOptions.html#PROP_ARRAY"><B>PROP_ARRAY</B></A> -
+Static variable in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options">AliasOptions</A>
+<DD>The actual is an unordered array, the alias is to the first element of the array.
+<DT><A HREF="../com/adobe/xmp/options/AliasOptions.html#PROP_ARRAY_ALT_TEXT"><B>PROP_ARRAY_ALT_TEXT</B></A> -
+Static variable in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options">AliasOptions</A>
+<DD>The actual is an alternate text array, the alias is to the 'x-default' element of the array.
+<DT><A HREF="../com/adobe/xmp/options/AliasOptions.html#PROP_ARRAY_ALTERNATE"><B>PROP_ARRAY_ALTERNATE</B></A> -
+Static variable in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options">AliasOptions</A>
+<DD>The actual is an alternate array, the alias is to the first element of the array.
+<DT><A HREF="../com/adobe/xmp/options/AliasOptions.html#PROP_ARRAY_ORDERED"><B>PROP_ARRAY_ORDERED</B></A> -
+Static variable in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options">AliasOptions</A>
+<DD>The actual is an ordered array, the alias is to the first element of the array.
+<DT><A HREF="../com/adobe/xmp/options/AliasOptions.html#PROP_DIRECT"><B>PROP_DIRECT</B></A> -
+Static variable in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options">AliasOptions</A>
+<DD>This is a direct mapping.
+<DT><A HREF="../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options"><B>PropertyOptions</B></A> - Class in <A HREF="../com/adobe/xmp/options/package-summary.html">com.adobe.xmp.options</A><DD>The property flags are used when properties are fetched from the <code>XMPMeta</code>-object
+ and provide more detailed information about the property.<DT><A HREF="../com/adobe/xmp/options/PropertyOptions.html#PropertyOptions()"><B>PropertyOptions()</B></A> -
+Constructor for class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>
+<DD>Default constructor
+<DT><A HREF="../com/adobe/xmp/options/PropertyOptions.html#PropertyOptions(int)"><B>PropertyOptions(int)</B></A> -
+Constructor for class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>
+<DD>Intialization constructor
+</DL>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Index</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="index-13.html"><B>PREV LETTER</B></A>&nbsp;
+&nbsp;<A HREF="index-15.html"><B>NEXT LETTER</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../index.html?index-filesindex-14.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="index-14.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<A HREF="index-1.html">A</A> <A HREF="index-2.html">B</A> <A HREF="index-3.html">C</A> <A HREF="index-4.html">D</A> <A HREF="index-5.html">E</A> <A HREF="index-6.html">F</A> <A HREF="index-7.html">G</A> <A HREF="index-8.html">H</A> <A HREF="index-9.html">I</A> <A HREF="index-10.html">J</A> <A HREF="index-11.html">M</A> <A HREF="index-12.html">N</A> <A HREF="index-13.html">O</A> <A HREF="index-14.html">P</A> <A HREF="index-15.html">Q</A> <A HREF="index-16.html">R</A> <A HREF="index-17.html">S</A> <A HREF="index-18.html">T</A> <A HREF="index-19.html">U</A> <A HREF="index-20.html">W</A> <A HREF="index-21.html">X</A> <HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/index-files/index-15.html b/java/XMPCore/docs/index-files/index-15.html
new file mode 100644
index 0000000..32d306c
--- /dev/null
+++ b/java/XMPCore/docs/index-files/index-15.html
@@ -0,0 +1,141 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:51 CEST 2007 -->
+<TITLE>
+Q-Index
+</TITLE>
+
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="Q-Index";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Index</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="index-14.html"><B>PREV LETTER</B></A>&nbsp;
+&nbsp;<A HREF="index-16.html"><B>NEXT LETTER</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../index.html?index-filesindex-15.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="index-15.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<A HREF="index-1.html">A</A> <A HREF="index-2.html">B</A> <A HREF="index-3.html">C</A> <A HREF="index-4.html">D</A> <A HREF="index-5.html">E</A> <A HREF="index-6.html">F</A> <A HREF="index-7.html">G</A> <A HREF="index-8.html">H</A> <A HREF="index-9.html">I</A> <A HREF="index-10.html">J</A> <A HREF="index-11.html">M</A> <A HREF="index-12.html">N</A> <A HREF="index-13.html">O</A> <A HREF="index-14.html">P</A> <A HREF="index-15.html">Q</A> <A HREF="index-16.html">R</A> <A HREF="index-17.html">S</A> <A HREF="index-18.html">T</A> <A HREF="index-19.html">U</A> <A HREF="index-20.html">W</A> <A HREF="index-21.html">X</A> <HR>
+<A NAME="_Q_"><!-- --></A><H2>
+<B>Q</B></H2>
+<DL>
+<DT><A HREF="../com/adobe/xmp/options/PropertyOptions.html#QUALIFIER"><B>QUALIFIER</B></A> -
+Static variable in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>
+<DD>&nbsp;
+</DL>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Index</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="index-14.html"><B>PREV LETTER</B></A>&nbsp;
+&nbsp;<A HREF="index-16.html"><B>NEXT LETTER</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../index.html?index-filesindex-15.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="index-15.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<A HREF="index-1.html">A</A> <A HREF="index-2.html">B</A> <A HREF="index-3.html">C</A> <A HREF="index-4.html">D</A> <A HREF="index-5.html">E</A> <A HREF="index-6.html">F</A> <A HREF="index-7.html">G</A> <A HREF="index-8.html">H</A> <A HREF="index-9.html">I</A> <A HREF="index-10.html">J</A> <A HREF="index-11.html">M</A> <A HREF="index-12.html">N</A> <A HREF="index-13.html">O</A> <A HREF="index-14.html">P</A> <A HREF="index-15.html">Q</A> <A HREF="index-16.html">R</A> <A HREF="index-17.html">S</A> <A HREF="index-18.html">T</A> <A HREF="index-19.html">U</A> <A HREF="index-20.html">W</A> <A HREF="index-21.html">X</A> <HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/index-files/index-16.html b/java/XMPCore/docs/index-files/index-16.html
new file mode 100644
index 0000000..dc8a074
--- /dev/null
+++ b/java/XMPCore/docs/index-files/index-16.html
@@ -0,0 +1,162 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:51 CEST 2007 -->
+<TITLE>
+R-Index
+</TITLE>
+
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="R-Index";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Index</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="index-15.html"><B>PREV LETTER</B></A>&nbsp;
+&nbsp;<A HREF="index-17.html"><B>NEXT LETTER</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../index.html?index-filesindex-16.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="index-16.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<A HREF="index-1.html">A</A> <A HREF="index-2.html">B</A> <A HREF="index-3.html">C</A> <A HREF="index-4.html">D</A> <A HREF="index-5.html">E</A> <A HREF="index-6.html">F</A> <A HREF="index-7.html">G</A> <A HREF="index-8.html">H</A> <A HREF="index-9.html">I</A> <A HREF="index-10.html">J</A> <A HREF="index-11.html">M</A> <A HREF="index-12.html">N</A> <A HREF="index-13.html">O</A> <A HREF="index-14.html">P</A> <A HREF="index-15.html">Q</A> <A HREF="index-16.html">R</A> <A HREF="index-17.html">S</A> <A HREF="index-18.html">T</A> <A HREF="index-19.html">U</A> <A HREF="index-20.html">W</A> <A HREF="index-21.html">X</A> <HR>
+<A NAME="_R_"><!-- --></A><H2>
+<B>R</B></H2>
+<DL>
+<DT><A HREF="../com/adobe/xmp/XMPConst.html#RDF_TYPE"><B>RDF_TYPE</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A>
+<DD>rdf:type qualfifier
+<DT><A HREF="../com/adobe/xmp/options/SerializeOptions.html#READONLY_PACKET"><B>READONLY_PACKET</B></A> -
+Static variable in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>
+<DD>Mark packet as read-only.
+<DT><A HREF="../com/adobe/xmp/XMPSchemaRegistry.html#registerAlias(java.lang.String, java.lang.String, java.lang.String, java.lang.String, com.adobe.xmp.options.AliasOptions)"><B>registerAlias(String, String, String, String, AliasOptions)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPSchemaRegistry.html" title="interface in com.adobe.xmp">XMPSchemaRegistry</A>
+<DD>Associates an alias name with an actual name.
+<DT><A HREF="../com/adobe/xmp/XMPSchemaRegistry.html#registerNamespace(java.lang.String, java.lang.String)"><B>registerNamespace(String, String)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPSchemaRegistry.html" title="interface in com.adobe.xmp">XMPSchemaRegistry</A>
+<DD>Register a namespace URI with a suggested prefix.
+<DT><A HREF="../com/adobe/xmp/XMPUtils.html#removeProperties(com.adobe.xmp.XMPMeta, java.lang.String, java.lang.String, boolean, boolean)"><B>removeProperties(XMPMeta, String, String, boolean, boolean)</B></A> -
+Static method in class com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPUtils.html" title="class in com.adobe.xmp">XMPUtils</A>
+<DD>Remove multiple properties from an XMP object.
+<DT><A HREF="../com/adobe/xmp/options/ParseOptions.html#REQUIRE_XMP_META"><B>REQUIRE_XMP_META</B></A> -
+Static variable in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options">ParseOptions</A>
+<DD>Require a surrounding &quot;x:xmpmeta&quot; element in the xml-document.
+<DT><A HREF="../com/adobe/xmp/XMPMetaFactory.html#reset()"><B>reset()</B></A> -
+Static method in class com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMetaFactory.html" title="class in com.adobe.xmp">XMPMetaFactory</A>
+<DD>Resets the schema registry to its original state (creates a new one).
+<DT><A HREF="../com/adobe/xmp/XMPSchemaRegistry.html#resolveAlias(java.lang.String, java.lang.String)"><B>resolveAlias(String, String)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPSchemaRegistry.html" title="interface in com.adobe.xmp">XMPSchemaRegistry</A>
+<DD>Determines if a name is an alias, and what it is aliased to.
+</DL>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Index</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="index-15.html"><B>PREV LETTER</B></A>&nbsp;
+&nbsp;<A HREF="index-17.html"><B>NEXT LETTER</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../index.html?index-filesindex-16.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="index-16.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<A HREF="index-1.html">A</A> <A HREF="index-2.html">B</A> <A HREF="index-3.html">C</A> <A HREF="index-4.html">D</A> <A HREF="index-5.html">E</A> <A HREF="index-6.html">F</A> <A HREF="index-7.html">G</A> <A HREF="index-8.html">H</A> <A HREF="index-9.html">I</A> <A HREF="index-10.html">J</A> <A HREF="index-11.html">M</A> <A HREF="index-12.html">N</A> <A HREF="index-13.html">O</A> <A HREF="index-14.html">P</A> <A HREF="index-15.html">Q</A> <A HREF="index-16.html">R</A> <A HREF="index-17.html">S</A> <A HREF="index-18.html">T</A> <A HREF="index-19.html">U</A> <A HREF="index-20.html">W</A> <A HREF="index-21.html">X</A> <HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/index-files/index-17.html b/java/XMPCore/docs/index-files/index-17.html
new file mode 100644
index 0000000..f0f15ce
--- /dev/null
+++ b/java/XMPCore/docs/index-files/index-17.html
@@ -0,0 +1,409 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:51 CEST 2007 -->
+<TITLE>
+S-Index
+</TITLE>
+
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="S-Index";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Index</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="index-16.html"><B>PREV LETTER</B></A>&nbsp;
+&nbsp;<A HREF="index-18.html"><B>NEXT LETTER</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../index.html?index-filesindex-17.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="index-17.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<A HREF="index-1.html">A</A> <A HREF="index-2.html">B</A> <A HREF="index-3.html">C</A> <A HREF="index-4.html">D</A> <A HREF="index-5.html">E</A> <A HREF="index-6.html">F</A> <A HREF="index-7.html">G</A> <A HREF="index-8.html">H</A> <A HREF="index-9.html">I</A> <A HREF="index-10.html">J</A> <A HREF="index-11.html">M</A> <A HREF="index-12.html">N</A> <A HREF="index-13.html">O</A> <A HREF="index-14.html">P</A> <A HREF="index-15.html">Q</A> <A HREF="index-16.html">R</A> <A HREF="index-17.html">S</A> <A HREF="index-18.html">T</A> <A HREF="index-19.html">U</A> <A HREF="index-20.html">W</A> <A HREF="index-21.html">X</A> <HR>
+<A NAME="_S_"><!-- --></A><H2>
+<B>S</B></H2>
+<DL>
+<DT><A HREF="../com/adobe/xmp/options/PropertyOptions.html#SCHEMA_NODE"><B>SCHEMA_NODE</B></A> -
+Static variable in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPUtils.html#separateArrayItems(com.adobe.xmp.XMPMeta, java.lang.String, java.lang.String, java.lang.String, com.adobe.xmp.options.PropertyOptions, boolean)"><B>separateArrayItems(XMPMeta, String, String, String, PropertyOptions, boolean)</B></A> -
+Static method in class com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPUtils.html" title="class in com.adobe.xmp">XMPUtils</A>
+<DD>Separate a single edit string into an array of strings.
+<DT><A HREF="../com/adobe/xmp/XMPMetaFactory.html#serialize(com.adobe.xmp.XMPMeta, java.io.OutputStream)"><B>serialize(XMPMeta, OutputStream)</B></A> -
+Static method in class com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMetaFactory.html" title="class in com.adobe.xmp">XMPMetaFactory</A>
+<DD>Serializes an <code>XMPMeta</code>-object as RDF into an <code>OutputStream</code>
+ with default options.
+<DT><A HREF="../com/adobe/xmp/XMPMetaFactory.html#serialize(com.adobe.xmp.XMPMeta, java.io.OutputStream, com.adobe.xmp.options.SerializeOptions)"><B>serialize(XMPMeta, OutputStream, SerializeOptions)</B></A> -
+Static method in class com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMetaFactory.html" title="class in com.adobe.xmp">XMPMetaFactory</A>
+<DD>Serializes an <code>XMPMeta</code>-object as RDF into an <code>OutputStream</code>.
+<DT><A HREF="../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options"><B>SerializeOptions</B></A> - Class in <A HREF="../com/adobe/xmp/options/package-summary.html">com.adobe.xmp.options</A><DD>Options for <A HREF="../com/adobe/xmp/XMPMetaFactory.html#serializeToBuffer(com.adobe.xmp.XMPMeta, com.adobe.xmp.options.SerializeOptions)"><CODE>XMPMetaFactory.serializeToBuffer(XMPMeta, SerializeOptions)</CODE></A>.<DT><A HREF="../com/adobe/xmp/options/SerializeOptions.html#SerializeOptions()"><B>SerializeOptions()</B></A> -
+Constructor for class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>
+<DD>Default constructor.
+<DT><A HREF="../com/adobe/xmp/options/SerializeOptions.html#SerializeOptions(int)"><B>SerializeOptions(int)</B></A> -
+Constructor for class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>
+<DD>Constructor using inital options
+<DT><A HREF="../com/adobe/xmp/XMPMetaFactory.html#serializeToBuffer(com.adobe.xmp.XMPMeta, com.adobe.xmp.options.SerializeOptions)"><B>serializeToBuffer(XMPMeta, SerializeOptions)</B></A> -
+Static method in class com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMetaFactory.html" title="class in com.adobe.xmp">XMPMetaFactory</A>
+<DD>Serializes an <code>XMPMeta</code>-object as RDF into a byte buffer.
+<DT><A HREF="../com/adobe/xmp/XMPMetaFactory.html#serializeToString(com.adobe.xmp.XMPMeta, com.adobe.xmp.options.SerializeOptions)"><B>serializeToString(XMPMeta, SerializeOptions)</B></A> -
+Static method in class com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMetaFactory.html" title="class in com.adobe.xmp">XMPMetaFactory</A>
+<DD>Serializes an <code>XMPMeta</code>-object as RDF into a string.
+<DT><A HREF="../com/adobe/xmp/options/ParseOptions.html#setAcceptLatin1(boolean)"><B>setAcceptLatin1(boolean)</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options">ParseOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/AliasOptions.html#setArray(boolean)"><B>setArray(boolean)</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options">AliasOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/PropertyOptions.html#setArray(boolean)"><B>setArray(boolean)</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/AliasOptions.html#setArrayAlternate(boolean)"><B>setArrayAlternate(boolean)</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options">AliasOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/PropertyOptions.html#setArrayAlternate(boolean)"><B>setArrayAlternate(boolean)</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/AliasOptions.html#setArrayAltText(boolean)"><B>setArrayAltText(boolean)</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options">AliasOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/PropertyOptions.html#setArrayAltText(boolean)"><B>setArrayAltText(boolean)</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#setArrayItem(java.lang.String, java.lang.String, int, java.lang.String, com.adobe.xmp.options.PropertyOptions)"><B>setArrayItem(String, String, int, String, PropertyOptions)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>Replaces an item within an array.
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#setArrayItem(java.lang.String, java.lang.String, int, java.lang.String)"><B>setArrayItem(String, String, int, String)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/AliasOptions.html#setArrayOrdered(boolean)"><B>setArrayOrdered(boolean)</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options">AliasOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/PropertyOptions.html#setArrayOrdered(boolean)"><B>setArrayOrdered(boolean)</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/SerializeOptions.html#setBaseIndent(int)"><B>setBaseIndent(int)</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/PropertyOptions.html#setCompact(boolean)"><B>setCompact(boolean)</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPDateTime.html#setDay(int)"><B>setDay(int)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/SerializeOptions.html#setEncodeUTF16BE(boolean)"><B>setEncodeUTF16BE(boolean)</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/SerializeOptions.html#setEncodeUTF16LE(boolean)"><B>setEncodeUTF16LE(boolean)</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/SerializeOptions.html#setExactPacketLength(boolean)"><B>setExactPacketLength(boolean)</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/ParseOptions.html#setFixControlChars(boolean)"><B>setFixControlChars(boolean)</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options">ParseOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/PropertyOptions.html#setHasLanguage(boolean)"><B>setHasLanguage(boolean)</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/PropertyOptions.html#setHasQualifiers(boolean)"><B>setHasQualifiers(boolean)</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/PropertyOptions.html#setHasType(boolean)"><B>setHasType(boolean)</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPDateTime.html#setHour(int)"><B>setHour(int)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/SerializeOptions.html#setIncludeThumbnailPad(boolean)"><B>setIncludeThumbnailPad(boolean)</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/SerializeOptions.html#setIndent(java.lang.String)"><B>setIndent(String)</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/IteratorOptions.html#setJustChildren(boolean)"><B>setJustChildren(boolean)</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options">IteratorOptions</A>
+<DD>Sets the option and returns the instance.
+<DT><A HREF="../com/adobe/xmp/options/IteratorOptions.html#setJustLeafname(boolean)"><B>setJustLeafname(boolean)</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options">IteratorOptions</A>
+<DD>Sets the option and returns the instance.
+<DT><A HREF="../com/adobe/xmp/options/IteratorOptions.html#setJustLeafnodes(boolean)"><B>setJustLeafnodes(boolean)</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options">IteratorOptions</A>
+<DD>Sets the option and returns the instance.
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#setLocalizedText(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, com.adobe.xmp.options.PropertyOptions)"><B>setLocalizedText(String, String, String, String, String, PropertyOptions)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>Modifies the value of a selected item in an alt-text array.
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#setLocalizedText(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String)"><B>setLocalizedText(String, String, String, String, String)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPDateTimeFactory.html#setLocalTimeZone(com.adobe.xmp.XMPDateTime)"><B>setLocalTimeZone(XMPDateTime)</B></A> -
+Static method in class com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPDateTimeFactory.html" title="class in com.adobe.xmp">XMPDateTimeFactory</A>
+<DD>Sets the local time zone without touching any other Any existing time zone value is replaced,
+ the other date/time fields are not adjusted in any way.
+<DT><A HREF="../com/adobe/xmp/XMPDateTime.html#setMinute(int)"><B>setMinute(int)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPDateTime.html#setMonth(int)"><B>setMonth(int)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPDateTime.html#setNanoSecond(int)"><B>setNanoSecond(int)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/SerializeOptions.html#setNewline(java.lang.String)"><B>setNewline(String)</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#setObjectName(java.lang.String)"><B>setObjectName(String)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/SerializeOptions.html#setOmitPacketWrapper(boolean)"><B>setOmitPacketWrapper(boolean)</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/IteratorOptions.html#setOmitQualifiers(boolean)"><B>setOmitQualifiers(boolean)</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options">IteratorOptions</A>
+<DD>Sets the option and returns the instance.
+<DT><A HREF="../com/adobe/xmp/options/Options.html#setOption(int, boolean)"><B>setOption(int, boolean)</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/Options.html" title="class in com.adobe.xmp.options">Options</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/Options.html#setOptions(int)"><B>setOptions(int)</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/Options.html" title="class in com.adobe.xmp.options">Options</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/SerializeOptions.html#setPadding(int)"><B>setPadding(int)</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#setProperty(java.lang.String, java.lang.String, java.lang.Object, com.adobe.xmp.options.PropertyOptions)"><B>setProperty(String, String, Object, PropertyOptions)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>The property value <code>setters</code> all take a property specification, their
+ differences are in the form of this.
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#setProperty(java.lang.String, java.lang.String, java.lang.Object)"><B>setProperty(String, String, Object)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#setPropertyBase64(java.lang.String, java.lang.String, byte[], com.adobe.xmp.options.PropertyOptions)"><B>setPropertyBase64(String, String, byte[], PropertyOptions)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>Convenience method to set a property from a binary <code>byte[]</code>-array,
+ which is serialized as base64-string.
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#setPropertyBase64(java.lang.String, java.lang.String, byte[])"><B>setPropertyBase64(String, String, byte[])</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#setPropertyBoolean(java.lang.String, java.lang.String, boolean, com.adobe.xmp.options.PropertyOptions)"><B>setPropertyBoolean(String, String, boolean, PropertyOptions)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>Convenience method to set a property to a literal <code>boolean</code> value.
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#setPropertyBoolean(java.lang.String, java.lang.String, boolean)"><B>setPropertyBoolean(String, String, boolean)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#setPropertyCalendar(java.lang.String, java.lang.String, java.util.Calendar, com.adobe.xmp.options.PropertyOptions)"><B>setPropertyCalendar(String, String, Calendar, PropertyOptions)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>Convenience method to set a property with a Java Calendar-object,
+ which is serialized to an ISO8601 date.
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#setPropertyCalendar(java.lang.String, java.lang.String, java.util.Calendar)"><B>setPropertyCalendar(String, String, Calendar)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#setPropertyDate(java.lang.String, java.lang.String, com.adobe.xmp.XMPDateTime, com.adobe.xmp.options.PropertyOptions)"><B>setPropertyDate(String, String, XMPDateTime, PropertyOptions)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>Convenience method to set a property with an XMPDateTime-object,
+ which is serialized to an ISO8601 date.
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#setPropertyDate(java.lang.String, java.lang.String, com.adobe.xmp.XMPDateTime)"><B>setPropertyDate(String, String, XMPDateTime)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#setPropertyDouble(java.lang.String, java.lang.String, double, com.adobe.xmp.options.PropertyOptions)"><B>setPropertyDouble(String, String, double, PropertyOptions)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>Convenience method to set a property to a literal <code>double</code> value.
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#setPropertyDouble(java.lang.String, java.lang.String, double)"><B>setPropertyDouble(String, String, double)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#setPropertyInteger(java.lang.String, java.lang.String, int, com.adobe.xmp.options.PropertyOptions)"><B>setPropertyInteger(String, String, int, PropertyOptions)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>Convenience method to set a property to a literal <code>int</code> value.
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#setPropertyInteger(java.lang.String, java.lang.String, int)"><B>setPropertyInteger(String, String, int)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#setPropertyLong(java.lang.String, java.lang.String, long, com.adobe.xmp.options.PropertyOptions)"><B>setPropertyLong(String, String, long, PropertyOptions)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>Convenience method to set a property to a literal <code>long</code> value.
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#setPropertyLong(java.lang.String, java.lang.String, long)"><B>setPropertyLong(String, String, long)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/PropertyOptions.html#setQualifier(boolean)"><B>setQualifier(boolean)</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#setQualifier(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, com.adobe.xmp.options.PropertyOptions)"><B>setQualifier(String, String, String, String, String, PropertyOptions)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>Provides access to a qualifier attached to a property.
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#setQualifier(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String)"><B>setQualifier(String, String, String, String, String)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/SerializeOptions.html#setReadOnlyPacket(boolean)"><B>setReadOnlyPacket(boolean)</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/ParseOptions.html#setRequireXMPMeta(boolean)"><B>setRequireXMPMeta(boolean)</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options">ParseOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/PropertyOptions.html#setSchemaNode(boolean)"><B>setSchemaNode(boolean)</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPDateTime.html#setSecond(int)"><B>setSecond(int)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/SerializeOptions.html#setSort(boolean)"><B>setSort(boolean)</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/ParseOptions.html#setStrictAliasing(boolean)"><B>setStrictAliasing(boolean)</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options">ParseOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/PropertyOptions.html#setStruct(boolean)"><B>setStruct(boolean)</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#setStructField(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, com.adobe.xmp.options.PropertyOptions)"><B>setStructField(String, String, String, String, String, PropertyOptions)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>Provides access to fields within a nested structure.
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#setStructField(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String)"><B>setStructField(String, String, String, String, String)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPDateTime.html#setTimeZone(java.util.TimeZone)"><B>setTimeZone(TimeZone)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/PropertyOptions.html#setURI(boolean)"><B>setURI(boolean)</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/SerializeOptions.html#setUseCompactFormat(boolean)"><B>setUseCompactFormat(boolean)</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/SerializeOptions.html#setWriteAliasComments(boolean)"><B>setWriteAliasComments(boolean)</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>
+<DD><em>Note:</em> This options is not supported at the moment.
+<DT><A HREF="../com/adobe/xmp/XMPDateTime.html#setYear(int)"><B>setYear(int)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPIterator.html#skipSiblings()"><B>skipSiblings()</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPIterator.html" title="interface in com.adobe.xmp">XMPIterator</A>
+<DD>Skip the subtree below and remaining siblings of the current node when
+ <code>next()</code> is called.
+<DT><A HREF="../com/adobe/xmp/XMPIterator.html#skipSubtree()"><B>skipSubtree()</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPIterator.html" title="interface in com.adobe.xmp">XMPIterator</A>
+<DD>Skip the subtree below the current node when <code>next()</code> is
+ called.
+<DT><A HREF="../com/adobe/xmp/options/SerializeOptions.html#SORT"><B>SORT</B></A> -
+Static variable in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>
+<DD>Sort the struct properties and qualifier before serializing
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#sort()"><B>sort()</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>Sorts the complete datamodel according to the following rules:
+
+ Schema nodes are sorted by prefix.
+<DT><A HREF="../com/adobe/xmp/options/ParseOptions.html#STRICT_ALIASING"><B>STRICT_ALIASING</B></A> -
+Static variable in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options">ParseOptions</A>
+<DD>Do not reconcile alias differences, throw an exception instead.
+<DT><A HREF="../com/adobe/xmp/options/PropertyOptions.html#STRUCT"><B>STRUCT</B></A> -
+Static variable in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>
+<DD>&nbsp;
+</DL>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Index</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="index-16.html"><B>PREV LETTER</B></A>&nbsp;
+&nbsp;<A HREF="index-18.html"><B>NEXT LETTER</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../index.html?index-filesindex-17.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="index-17.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<A HREF="index-1.html">A</A> <A HREF="index-2.html">B</A> <A HREF="index-3.html">C</A> <A HREF="index-4.html">D</A> <A HREF="index-5.html">E</A> <A HREF="index-6.html">F</A> <A HREF="index-7.html">G</A> <A HREF="index-8.html">H</A> <A HREF="index-9.html">I</A> <A HREF="index-10.html">J</A> <A HREF="index-11.html">M</A> <A HREF="index-12.html">N</A> <A HREF="index-13.html">O</A> <A HREF="index-14.html">P</A> <A HREF="index-15.html">Q</A> <A HREF="index-16.html">R</A> <A HREF="index-17.html">S</A> <A HREF="index-18.html">T</A> <A HREF="index-19.html">U</A> <A HREF="index-20.html">W</A> <A HREF="index-21.html">X</A> <HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/index-files/index-18.html b/java/XMPCore/docs/index-files/index-18.html
new file mode 100644
index 0000000..b0906d2
--- /dev/null
+++ b/java/XMPCore/docs/index-files/index-18.html
@@ -0,0 +1,183 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:51 CEST 2007 -->
+<TITLE>
+T-Index
+</TITLE>
+
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="T-Index";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Index</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="index-17.html"><B>PREV LETTER</B></A>&nbsp;
+&nbsp;<A HREF="index-19.html"><B>NEXT LETTER</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../index.html?index-filesindex-18.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="index-18.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<A HREF="index-1.html">A</A> <A HREF="index-2.html">B</A> <A HREF="index-3.html">C</A> <A HREF="index-4.html">D</A> <A HREF="index-5.html">E</A> <A HREF="index-6.html">F</A> <A HREF="index-7.html">G</A> <A HREF="index-8.html">H</A> <A HREF="index-9.html">I</A> <A HREF="index-10.html">J</A> <A HREF="index-11.html">M</A> <A HREF="index-12.html">N</A> <A HREF="index-13.html">O</A> <A HREF="index-14.html">P</A> <A HREF="index-15.html">Q</A> <A HREF="index-16.html">R</A> <A HREF="index-17.html">S</A> <A HREF="index-18.html">T</A> <A HREF="index-19.html">U</A> <A HREF="index-20.html">W</A> <A HREF="index-21.html">X</A> <HR>
+<A NAME="_T_"><!-- --></A><H2>
+<B>T</B></H2>
+<DL>
+<DT><A HREF="../com/adobe/xmp/options/AliasOptions.html#toPropertyOptions()"><B>toPropertyOptions()</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options">AliasOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/Options.html#toString()"><B>toString()</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/Options.html" title="class in com.adobe.xmp.options">Options</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPConst.html#TRUESTR"><B>TRUESTR</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A>
+<DD>The canonical true string value for Booleans in serialized XMP.
+<DT><A HREF="../com/adobe/xmp/XMPConst.html#TYPE_DIMENSIONS"><B>TYPE_DIMENSIONS</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A>
+<DD>The XML namespace for fields of the Dimensions type.
+<DT><A HREF="../com/adobe/xmp/XMPConst.html#TYPE_FONT"><B>TYPE_FONT</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPConst.html#TYPE_GRAPHICS"><B>TYPE_GRAPHICS</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPConst.html#TYPE_IDENTIFIERQUAL"><B>TYPE_IDENTIFIERQUAL</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A>
+<DD>The XML namespace for qualifiers of the xmp:Identifier property.
+<DT><A HREF="../com/adobe/xmp/XMPConst.html#TYPE_IMAGE"><B>TYPE_IMAGE</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A>
+<DD>The XML namespace for fields of a graphical image.
+<DT><A HREF="../com/adobe/xmp/XMPConst.html#TYPE_MANIFESTITEM"><B>TYPE_MANIFESTITEM</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPConst.html#TYPE_PAGEDFILE"><B>TYPE_PAGEDFILE</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPConst.html#TYPE_RESOURCEEVENT"><B>TYPE_RESOURCEEVENT</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A>
+<DD>The XML namespace for fields of the ResourceEvent type.
+<DT><A HREF="../com/adobe/xmp/XMPConst.html#TYPE_RESOURCEREF"><B>TYPE_RESOURCEREF</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A>
+<DD>The XML namespace for fields of the ResourceRef type.
+<DT><A HREF="../com/adobe/xmp/XMPConst.html#TYPE_ST_JOB"><B>TYPE_ST_JOB</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A>
+<DD>The XML namespace for fields of the JobRef type.
+<DT><A HREF="../com/adobe/xmp/XMPConst.html#TYPE_ST_VERSION"><B>TYPE_ST_VERSION</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A>
+<DD>The XML namespace for fields of the Version type.
+<DT><A HREF="../com/adobe/xmp/XMPConst.html#TYPE_TEXT"><B>TYPE_TEXT</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A>
+<DD>&nbsp;
+</DL>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Index</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="index-17.html"><B>PREV LETTER</B></A>&nbsp;
+&nbsp;<A HREF="index-19.html"><B>NEXT LETTER</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../index.html?index-filesindex-18.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="index-18.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<A HREF="index-1.html">A</A> <A HREF="index-2.html">B</A> <A HREF="index-3.html">C</A> <A HREF="index-4.html">D</A> <A HREF="index-5.html">E</A> <A HREF="index-6.html">F</A> <A HREF="index-7.html">G</A> <A HREF="index-8.html">H</A> <A HREF="index-9.html">I</A> <A HREF="index-10.html">J</A> <A HREF="index-11.html">M</A> <A HREF="index-12.html">N</A> <A HREF="index-13.html">O</A> <A HREF="index-14.html">P</A> <A HREF="index-15.html">Q</A> <A HREF="index-16.html">R</A> <A HREF="index-17.html">S</A> <A HREF="index-18.html">T</A> <A HREF="index-19.html">U</A> <A HREF="index-20.html">W</A> <A HREF="index-21.html">X</A> <HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/index-files/index-19.html b/java/XMPCore/docs/index-files/index-19.html
new file mode 100644
index 0000000..879076a
--- /dev/null
+++ b/java/XMPCore/docs/index-files/index-19.html
@@ -0,0 +1,147 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:51 CEST 2007 -->
+<TITLE>
+U-Index
+</TITLE>
+
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="U-Index";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Index</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="index-18.html"><B>PREV LETTER</B></A>&nbsp;
+&nbsp;<A HREF="index-20.html"><B>NEXT LETTER</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../index.html?index-filesindex-19.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="index-19.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<A HREF="index-1.html">A</A> <A HREF="index-2.html">B</A> <A HREF="index-3.html">C</A> <A HREF="index-4.html">D</A> <A HREF="index-5.html">E</A> <A HREF="index-6.html">F</A> <A HREF="index-7.html">G</A> <A HREF="index-8.html">H</A> <A HREF="index-9.html">I</A> <A HREF="index-10.html">J</A> <A HREF="index-11.html">M</A> <A HREF="index-12.html">N</A> <A HREF="index-13.html">O</A> <A HREF="index-14.html">P</A> <A HREF="index-15.html">Q</A> <A HREF="index-16.html">R</A> <A HREF="index-17.html">S</A> <A HREF="index-18.html">T</A> <A HREF="index-19.html">U</A> <A HREF="index-20.html">W</A> <A HREF="index-21.html">X</A> <HR>
+<A NAME="_U_"><!-- --></A><H2>
+<B>U</B></H2>
+<DL>
+<DT><A HREF="../com/adobe/xmp/XMPError.html#UNKNOWN"><B>UNKNOWN</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPError.html" title="interface in com.adobe.xmp">XMPError</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/PropertyOptions.html#URI"><B>URI</B></A> -
+Static variable in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/SerializeOptions.html#USE_COMPACT_FORMAT"><B>USE_COMPACT_FORMAT</B></A> -
+Static variable in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>
+<DD>Use a compact form of RDF.
+</DL>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Index</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="index-18.html"><B>PREV LETTER</B></A>&nbsp;
+&nbsp;<A HREF="index-20.html"><B>NEXT LETTER</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../index.html?index-filesindex-19.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="index-19.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<A HREF="index-1.html">A</A> <A HREF="index-2.html">B</A> <A HREF="index-3.html">C</A> <A HREF="index-4.html">D</A> <A HREF="index-5.html">E</A> <A HREF="index-6.html">F</A> <A HREF="index-7.html">G</A> <A HREF="index-8.html">H</A> <A HREF="index-9.html">I</A> <A HREF="index-10.html">J</A> <A HREF="index-11.html">M</A> <A HREF="index-12.html">N</A> <A HREF="index-13.html">O</A> <A HREF="index-14.html">P</A> <A HREF="index-15.html">Q</A> <A HREF="index-16.html">R</A> <A HREF="index-17.html">S</A> <A HREF="index-18.html">T</A> <A HREF="index-19.html">U</A> <A HREF="index-20.html">W</A> <A HREF="index-21.html">X</A> <HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/index-files/index-2.html b/java/XMPCore/docs/index-files/index-2.html
new file mode 100644
index 0000000..eec918a
--- /dev/null
+++ b/java/XMPCore/docs/index-files/index-2.html
@@ -0,0 +1,171 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:51 CEST 2007 -->
+<TITLE>
+B-Index
+</TITLE>
+
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="B-Index";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Index</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="index-1.html"><B>PREV LETTER</B></A>&nbsp;
+&nbsp;<A HREF="index-3.html"><B>NEXT LETTER</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../index.html?index-filesindex-2.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="index-2.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<A HREF="index-1.html">A</A> <A HREF="index-2.html">B</A> <A HREF="index-3.html">C</A> <A HREF="index-4.html">D</A> <A HREF="index-5.html">E</A> <A HREF="index-6.html">F</A> <A HREF="index-7.html">G</A> <A HREF="index-8.html">H</A> <A HREF="index-9.html">I</A> <A HREF="index-10.html">J</A> <A HREF="index-11.html">M</A> <A HREF="index-12.html">N</A> <A HREF="index-13.html">O</A> <A HREF="index-14.html">P</A> <A HREF="index-15.html">Q</A> <A HREF="index-16.html">R</A> <A HREF="index-17.html">S</A> <A HREF="index-18.html">T</A> <A HREF="index-19.html">U</A> <A HREF="index-20.html">W</A> <A HREF="index-21.html">X</A> <HR>
+<A NAME="_B_"><!-- --></A><H2>
+<B>B</B></H2>
+<DL>
+<DT><A HREF="../com/adobe/xmp/XMPError.html#BADINDEX"><B>BADINDEX</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPError.html" title="interface in com.adobe.xmp">XMPError</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPError.html#BADOPTIONS"><B>BADOPTIONS</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPError.html" title="interface in com.adobe.xmp">XMPError</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPError.html#BADPARAM"><B>BADPARAM</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPError.html" title="interface in com.adobe.xmp">XMPError</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPError.html#BADRDF"><B>BADRDF</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPError.html" title="interface in com.adobe.xmp">XMPError</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPError.html#BADSCHEMA"><B>BADSCHEMA</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPError.html" title="interface in com.adobe.xmp">XMPError</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPError.html#BADSERIALIZE"><B>BADSERIALIZE</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPError.html" title="interface in com.adobe.xmp">XMPError</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPError.html#BADSTREAM"><B>BADSTREAM</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPError.html" title="interface in com.adobe.xmp">XMPError</A>
+<DD><em>Note:</em> This is an error code introduced by Java.
+<DT><A HREF="../com/adobe/xmp/XMPError.html#BADVALUE"><B>BADVALUE</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPError.html" title="interface in com.adobe.xmp">XMPError</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPError.html#BADXML"><B>BADXML</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPError.html" title="interface in com.adobe.xmp">XMPError</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPError.html#BADXMP"><B>BADXMP</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPError.html" title="interface in com.adobe.xmp">XMPError</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPError.html#BADXPATH"><B>BADXPATH</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPError.html" title="interface in com.adobe.xmp">XMPError</A>
+<DD>&nbsp;
+</DL>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Index</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="index-1.html"><B>PREV LETTER</B></A>&nbsp;
+&nbsp;<A HREF="index-3.html"><B>NEXT LETTER</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../index.html?index-filesindex-2.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="index-2.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<A HREF="index-1.html">A</A> <A HREF="index-2.html">B</A> <A HREF="index-3.html">C</A> <A HREF="index-4.html">D</A> <A HREF="index-5.html">E</A> <A HREF="index-6.html">F</A> <A HREF="index-7.html">G</A> <A HREF="index-8.html">H</A> <A HREF="index-9.html">I</A> <A HREF="index-10.html">J</A> <A HREF="index-11.html">M</A> <A HREF="index-12.html">N</A> <A HREF="index-13.html">O</A> <A HREF="index-14.html">P</A> <A HREF="index-15.html">Q</A> <A HREF="index-16.html">R</A> <A HREF="index-17.html">S</A> <A HREF="index-18.html">T</A> <A HREF="index-19.html">U</A> <A HREF="index-20.html">W</A> <A HREF="index-21.html">X</A> <HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/index-files/index-20.html b/java/XMPCore/docs/index-files/index-20.html
new file mode 100644
index 0000000..a6f9950
--- /dev/null
+++ b/java/XMPCore/docs/index-files/index-20.html
@@ -0,0 +1,141 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:51 CEST 2007 -->
+<TITLE>
+W-Index
+</TITLE>
+
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="W-Index";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Index</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="index-19.html"><B>PREV LETTER</B></A>&nbsp;
+&nbsp;<A HREF="index-21.html"><B>NEXT LETTER</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../index.html?index-filesindex-20.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="index-20.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<A HREF="index-1.html">A</A> <A HREF="index-2.html">B</A> <A HREF="index-3.html">C</A> <A HREF="index-4.html">D</A> <A HREF="index-5.html">E</A> <A HREF="index-6.html">F</A> <A HREF="index-7.html">G</A> <A HREF="index-8.html">H</A> <A HREF="index-9.html">I</A> <A HREF="index-10.html">J</A> <A HREF="index-11.html">M</A> <A HREF="index-12.html">N</A> <A HREF="index-13.html">O</A> <A HREF="index-14.html">P</A> <A HREF="index-15.html">Q</A> <A HREF="index-16.html">R</A> <A HREF="index-17.html">S</A> <A HREF="index-18.html">T</A> <A HREF="index-19.html">U</A> <A HREF="index-20.html">W</A> <A HREF="index-21.html">X</A> <HR>
+<A NAME="_W_"><!-- --></A><H2>
+<B>W</B></H2>
+<DL>
+<DT><A HREF="../com/adobe/xmp/options/SerializeOptions.html#WRITE_ALIAS_COMMENTS"><B>WRITE_ALIAS_COMMENTS</B></A> -
+Static variable in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>
+<DD>Show aliases as XML comments.
+</DL>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Index</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="index-19.html"><B>PREV LETTER</B></A>&nbsp;
+&nbsp;<A HREF="index-21.html"><B>NEXT LETTER</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../index.html?index-filesindex-20.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="index-20.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<A HREF="index-1.html">A</A> <A HREF="index-2.html">B</A> <A HREF="index-3.html">C</A> <A HREF="index-4.html">D</A> <A HREF="index-5.html">E</A> <A HREF="index-6.html">F</A> <A HREF="index-7.html">G</A> <A HREF="index-8.html">H</A> <A HREF="index-9.html">I</A> <A HREF="index-10.html">J</A> <A HREF="index-11.html">M</A> <A HREF="index-12.html">N</A> <A HREF="index-13.html">O</A> <A HREF="index-14.html">P</A> <A HREF="index-15.html">Q</A> <A HREF="index-16.html">R</A> <A HREF="index-17.html">S</A> <A HREF="index-18.html">T</A> <A HREF="index-19.html">U</A> <A HREF="index-20.html">W</A> <A HREF="index-21.html">X</A> <HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/index-files/index-21.html b/java/XMPCore/docs/index-files/index-21.html
new file mode 100644
index 0000000..36b9865
--- /dev/null
+++ b/java/XMPCore/docs/index-files/index-21.html
@@ -0,0 +1,157 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:51 CEST 2007 -->
+<TITLE>
+X-Index
+</TITLE>
+
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="X-Index";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Index</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="index-20.html"><B>PREV LETTER</B></A>&nbsp;
+&nbsp;NEXT LETTER</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../index.html?index-filesindex-21.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="index-21.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<A HREF="index-1.html">A</A> <A HREF="index-2.html">B</A> <A HREF="index-3.html">C</A> <A HREF="index-4.html">D</A> <A HREF="index-5.html">E</A> <A HREF="index-6.html">F</A> <A HREF="index-7.html">G</A> <A HREF="index-8.html">H</A> <A HREF="index-9.html">I</A> <A HREF="index-10.html">J</A> <A HREF="index-11.html">M</A> <A HREF="index-12.html">N</A> <A HREF="index-13.html">O</A> <A HREF="index-14.html">P</A> <A HREF="index-15.html">Q</A> <A HREF="index-16.html">R</A> <A HREF="index-17.html">S</A> <A HREF="index-18.html">T</A> <A HREF="index-19.html">U</A> <A HREF="index-20.html">W</A> <A HREF="index-21.html">X</A> <HR>
+<A NAME="_X_"><!-- --></A><H2>
+<B>X</B></H2>
+<DL>
+<DT><A HREF="../com/adobe/xmp/XMPConst.html#X_DEFAULT"><B>X_DEFAULT</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A>
+<DD>The x-default string for localized properties
+<DT><A HREF="../com/adobe/xmp/XMPConst.html#XML_LANG"><B>XML_LANG</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A>
+<DD>xml:lang qualfifier
+<DT><A HREF="../com/adobe/xmp/properties/XMPAliasInfo.html" title="interface in com.adobe.xmp.properties"><B>XMPAliasInfo</B></A> - Interface in <A HREF="../com/adobe/xmp/properties/package-summary.html">com.adobe.xmp.properties</A><DD>This interface is used to return info about an alias.<DT><A HREF="../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp"><B>XMPConst</B></A> - Interface in <A HREF="../com/adobe/xmp/package-summary.html">com.adobe.xmp</A><DD>Common constants for the XMP Toolkit.<DT><A HREF="../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp"><B>XMPDateTime</B></A> - Interface in <A HREF="../com/adobe/xmp/package-summary.html">com.adobe.xmp</A><DD>The <code>XMPDateTime</code>-class represents a point in time up to a resolution of nano
+ seconds.<DT><A HREF="../com/adobe/xmp/XMPDateTimeFactory.html" title="class in com.adobe.xmp"><B>XMPDateTimeFactory</B></A> - Class in <A HREF="../com/adobe/xmp/package-summary.html">com.adobe.xmp</A><DD>A factory to create <code>XMPDateTime</code>-instances from a <code>Calendar</code> or an
+ ISO 8601 string or for the current time.<DT><A HREF="../com/adobe/xmp/XMPError.html" title="interface in com.adobe.xmp"><B>XMPError</B></A> - Interface in <A HREF="../com/adobe/xmp/package-summary.html">com.adobe.xmp</A><DD>&nbsp;<DT><A HREF="../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp"><B>XMPException</B></A> - Exception in <A HREF="../com/adobe/xmp/package-summary.html">com.adobe.xmp</A><DD>This exception wraps all errors that occur in the XMP Toolkit.<DT><A HREF="../com/adobe/xmp/XMPException.html#XMPException(java.lang.String, int)"><B>XMPException(String, int)</B></A> -
+Constructor for exception com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A>
+<DD>Constructs an exception with a message and an error code.
+<DT><A HREF="../com/adobe/xmp/XMPException.html#XMPException(java.lang.String, int, java.lang.Throwable)"><B>XMPException(String, int, Throwable)</B></A> -
+Constructor for exception com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A>
+<DD>Constructs an exception with a message, an error code and a <code>Throwable</code>
+<DT><A HREF="../com/adobe/xmp/XMPIterator.html" title="interface in com.adobe.xmp"><B>XMPIterator</B></A> - Interface in <A HREF="../com/adobe/xmp/package-summary.html">com.adobe.xmp</A><DD>Interface for the <code>XMPMeta</code> iteration services.<DT><A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp"><B>XMPMeta</B></A> - Interface in <A HREF="../com/adobe/xmp/package-summary.html">com.adobe.xmp</A><DD>This class represents the set of XMP metadata as a DOM representation.<DT><A HREF="../com/adobe/xmp/XMPMetaFactory.html" title="class in com.adobe.xmp"><B>XMPMetaFactory</B></A> - Class in <A HREF="../com/adobe/xmp/package-summary.html">com.adobe.xmp</A><DD>Creates <code>XMPMeta</code>-instances from an <code>InputStream</code><DT><A HREF="../com/adobe/xmp/XMPPathFactory.html" title="class in com.adobe.xmp"><B>XMPPathFactory</B></A> - Class in <A HREF="../com/adobe/xmp/package-summary.html">com.adobe.xmp</A><DD>Utility services for the metadata object.<DT><A HREF="../com/adobe/xmp/properties/XMPProperty.html" title="interface in com.adobe.xmp.properties"><B>XMPProperty</B></A> - Interface in <A HREF="../com/adobe/xmp/properties/package-summary.html">com.adobe.xmp.properties</A><DD>This interface is used to return a text property together with its and options.<DT><A HREF="../com/adobe/xmp/properties/XMPPropertyInfo.html" title="interface in com.adobe.xmp.properties"><B>XMPPropertyInfo</B></A> - Interface in <A HREF="../com/adobe/xmp/properties/package-summary.html">com.adobe.xmp.properties</A><DD>This interface is used to return a property together with its path and namespace.<DT><A HREF="../com/adobe/xmp/XMPSchemaRegistry.html" title="interface in com.adobe.xmp"><B>XMPSchemaRegistry</B></A> - Interface in <A HREF="../com/adobe/xmp/package-summary.html">com.adobe.xmp</A><DD>The schema registry keeps track of all namespaces and aliases used in the XMP
+ metadata.<DT><A HREF="../com/adobe/xmp/XMPUtils.html" title="class in com.adobe.xmp"><B>XMPUtils</B></A> - Class in <A HREF="../com/adobe/xmp/package-summary.html">com.adobe.xmp</A><DD>Utility methods for XMP.<DT><A HREF="../com/adobe/xmp/XMPVersionInfo.html" title="interface in com.adobe.xmp"><B>XMPVersionInfo</B></A> - Interface in <A HREF="../com/adobe/xmp/package-summary.html">com.adobe.xmp</A><DD>XMP Toolkit Version Information
+
+ Version information for the XMP toolkit is stored in the jar-library and available through a
+ runtime call, <A HREF="../com/adobe/xmp/XMPMetaFactory.html#getVersionInfo()"><CODE>XMPMetaFactory.getVersionInfo()</CODE></A>, addition static version numbers are
+ defined in "version.properties".</DL>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Index</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="index-20.html"><B>PREV LETTER</B></A>&nbsp;
+&nbsp;NEXT LETTER</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../index.html?index-filesindex-21.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="index-21.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<A HREF="index-1.html">A</A> <A HREF="index-2.html">B</A> <A HREF="index-3.html">C</A> <A HREF="index-4.html">D</A> <A HREF="index-5.html">E</A> <A HREF="index-6.html">F</A> <A HREF="index-7.html">G</A> <A HREF="index-8.html">H</A> <A HREF="index-9.html">I</A> <A HREF="index-10.html">J</A> <A HREF="index-11.html">M</A> <A HREF="index-12.html">N</A> <A HREF="index-13.html">O</A> <A HREF="index-14.html">P</A> <A HREF="index-15.html">Q</A> <A HREF="index-16.html">R</A> <A HREF="index-17.html">S</A> <A HREF="index-18.html">T</A> <A HREF="index-19.html">U</A> <A HREF="index-20.html">W</A> <A HREF="index-21.html">X</A> <HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/index-files/index-3.html b/java/XMPCore/docs/index-files/index-3.html
new file mode 100644
index 0000000..786b84e
--- /dev/null
+++ b/java/XMPCore/docs/index-files/index-3.html
@@ -0,0 +1,225 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:51 CEST 2007 -->
+<TITLE>
+C-Index
+</TITLE>
+
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="C-Index";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Index</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="index-2.html"><B>PREV LETTER</B></A>&nbsp;
+&nbsp;<A HREF="index-4.html"><B>NEXT LETTER</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../index.html?index-filesindex-3.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="index-3.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<A HREF="index-1.html">A</A> <A HREF="index-2.html">B</A> <A HREF="index-3.html">C</A> <A HREF="index-4.html">D</A> <A HREF="index-5.html">E</A> <A HREF="index-6.html">F</A> <A HREF="index-7.html">G</A> <A HREF="index-8.html">H</A> <A HREF="index-9.html">I</A> <A HREF="index-10.html">J</A> <A HREF="index-11.html">M</A> <A HREF="index-12.html">N</A> <A HREF="index-13.html">O</A> <A HREF="index-14.html">P</A> <A HREF="index-15.html">Q</A> <A HREF="index-16.html">R</A> <A HREF="index-17.html">S</A> <A HREF="index-18.html">T</A> <A HREF="index-19.html">U</A> <A HREF="index-20.html">W</A> <A HREF="index-21.html">X</A> <HR>
+<A NAME="_C_"><!-- --></A><H2>
+<B>C</B></H2>
+<DL>
+<DT><A HREF="../com/adobe/xmp/XMPUtils.html#catenateArrayItems(com.adobe.xmp.XMPMeta, java.lang.String, java.lang.String, java.lang.String, java.lang.String, boolean)"><B>catenateArrayItems(XMPMeta, String, String, String, String, boolean)</B></A> -
+Static method in class com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPUtils.html" title="class in com.adobe.xmp">XMPUtils</A>
+<DD>Create a single edit string from an array of strings.
+<DT><A HREF="../com/adobe/xmp/options/Options.html#clear()"><B>clear()</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/Options.html" title="class in com.adobe.xmp.options">Options</A>
+<DD>Resets the options.
+<DT><A HREF="../com/adobe/xmp/options/SerializeOptions.html#clone()"><B>clone()</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#clone()"><B>clone()</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>Clones the complete metadata tree.
+<DT><A HREF="../com/adobe/xmp/package-summary.html"><B>com.adobe.xmp</B></A> - package com.adobe.xmp<DD>Package containing the xmpcore interface.<DT><A HREF="../com/adobe/xmp/options/package-summary.html"><B>com.adobe.xmp.options</B></A> - package com.adobe.xmp.options<DD>Package containing the option classes.<DT><A HREF="../com/adobe/xmp/properties/package-summary.html"><B>com.adobe.xmp.properties</B></A> - package com.adobe.xmp.properties<DD>Package containing the property information classes.<DT><A HREF="../com/adobe/xmp/options/PropertyOptions.html#COMPACT"><B>COMPACT</B></A> -
+Static variable in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPPathFactory.html#composeArrayItemPath(java.lang.String, int)"><B>composeArrayItemPath(String, int)</B></A> -
+Static method in class com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPPathFactory.html" title="class in com.adobe.xmp">XMPPathFactory</A>
+<DD>Compose the path expression for an item in an array.
+<DT><A HREF="../com/adobe/xmp/XMPPathFactory.html#composeFieldSelector(java.lang.String, java.lang.String, java.lang.String, java.lang.String)"><B>composeFieldSelector(String, String, String, String)</B></A> -
+Static method in class com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPPathFactory.html" title="class in com.adobe.xmp">XMPPathFactory</A>
+<DD>Compose the path expression to select an alternate item by a field's value.
+<DT><A HREF="../com/adobe/xmp/XMPPathFactory.html#composeLangSelector(java.lang.String, java.lang.String)"><B>composeLangSelector(String, String)</B></A> -
+Static method in class com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPPathFactory.html" title="class in com.adobe.xmp">XMPPathFactory</A>
+<DD>Compose the path expression to select an alternate item by language.
+<DT><A HREF="../com/adobe/xmp/XMPPathFactory.html#composeQualifierPath(java.lang.String, java.lang.String)"><B>composeQualifierPath(String, String)</B></A> -
+Static method in class com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPPathFactory.html" title="class in com.adobe.xmp">XMPPathFactory</A>
+<DD>Compose the path expression for a qualifier.
+<DT><A HREF="../com/adobe/xmp/XMPPathFactory.html#composeStructFieldPath(java.lang.String, java.lang.String)"><B>composeStructFieldPath(String, String)</B></A> -
+Static method in class com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPPathFactory.html" title="class in com.adobe.xmp">XMPPathFactory</A>
+<DD>Compose the path expression for a field in a struct.
+<DT><A HREF="../com/adobe/xmp/options/Options.html#containsAllOptions(int)"><B>containsAllOptions(int)</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/Options.html" title="class in com.adobe.xmp.options">Options</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/Options.html#containsOneOf(int)"><B>containsOneOf(int)</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/Options.html" title="class in com.adobe.xmp.options">Options</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPUtils.html#convertFromBoolean(boolean)"><B>convertFromBoolean(boolean)</B></A> -
+Static method in class com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPUtils.html" title="class in com.adobe.xmp">XMPUtils</A>
+<DD>Convert from boolean to string.
+<DT><A HREF="../com/adobe/xmp/XMPUtils.html#convertFromDate(com.adobe.xmp.XMPDateTime)"><B>convertFromDate(XMPDateTime)</B></A> -
+Static method in class com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPUtils.html" title="class in com.adobe.xmp">XMPUtils</A>
+<DD>Convert from <code>XMPDateTime</code> to string.
+<DT><A HREF="../com/adobe/xmp/XMPUtils.html#convertFromDouble(double)"><B>convertFromDouble(double)</B></A> -
+Static method in class com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPUtils.html" title="class in com.adobe.xmp">XMPUtils</A>
+<DD>Convert from long to string.
+<DT><A HREF="../com/adobe/xmp/XMPUtils.html#convertFromInteger(int)"><B>convertFromInteger(int)</B></A> -
+Static method in class com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPUtils.html" title="class in com.adobe.xmp">XMPUtils</A>
+<DD>Convert from int to string.
+<DT><A HREF="../com/adobe/xmp/XMPUtils.html#convertFromLong(long)"><B>convertFromLong(long)</B></A> -
+Static method in class com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPUtils.html" title="class in com.adobe.xmp">XMPUtils</A>
+<DD>Convert from long to string.
+<DT><A HREF="../com/adobe/xmp/XMPUtils.html#convertToBoolean(java.lang.String)"><B>convertToBoolean(String)</B></A> -
+Static method in class com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPUtils.html" title="class in com.adobe.xmp">XMPUtils</A>
+<DD>Convert from string to Boolean.
+<DT><A HREF="../com/adobe/xmp/XMPUtils.html#convertToDate(java.lang.String)"><B>convertToDate(String)</B></A> -
+Static method in class com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPUtils.html" title="class in com.adobe.xmp">XMPUtils</A>
+<DD>Converts a string value to an <code>XMPDateTime</code>.
+<DT><A HREF="../com/adobe/xmp/XMPUtils.html#convertToDouble(java.lang.String)"><B>convertToDouble(String)</B></A> -
+Static method in class com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPUtils.html" title="class in com.adobe.xmp">XMPUtils</A>
+<DD>Converts a string value to a <code>double</code>.
+<DT><A HREF="../com/adobe/xmp/XMPUtils.html#convertToInteger(java.lang.String)"><B>convertToInteger(String)</B></A> -
+Static method in class com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPUtils.html" title="class in com.adobe.xmp">XMPUtils</A>
+<DD>Converts a string value to an <code>int</code>.
+<DT><A HREF="../com/adobe/xmp/XMPDateTimeFactory.html#convertToLocalTime(com.adobe.xmp.XMPDateTime)"><B>convertToLocalTime(XMPDateTime)</B></A> -
+Static method in class com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPDateTimeFactory.html" title="class in com.adobe.xmp">XMPDateTimeFactory</A>
+<DD>Make sure a time is local.
+<DT><A HREF="../com/adobe/xmp/XMPUtils.html#convertToLong(java.lang.String)"><B>convertToLong(String)</B></A> -
+Static method in class com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPUtils.html" title="class in com.adobe.xmp">XMPUtils</A>
+<DD>Converts a string value to a <code>long</code>.
+<DT><A HREF="../com/adobe/xmp/XMPDateTimeFactory.html#convertToUTCTime(com.adobe.xmp.XMPDateTime)"><B>convertToUTCTime(XMPDateTime)</B></A> -
+Static method in class com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPDateTimeFactory.html" title="class in com.adobe.xmp">XMPDateTimeFactory</A>
+<DD>Make sure a time is UTC.
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#countArrayItems(java.lang.String, java.lang.String)"><B>countArrayItems(String, String)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>Returns the number of items in the array.
+<DT><A HREF="../com/adobe/xmp/XMPDateTimeFactory.html#create(int, int, int, int, int, int, int)"><B>create(int, int, int, int, int, int, int)</B></A> -
+Static method in class com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPDateTimeFactory.html" title="class in com.adobe.xmp">XMPDateTimeFactory</A>
+<DD>Creates an <code>XMPDateTime</code>-object from initial values.
+<DT><A HREF="../com/adobe/xmp/XMPMetaFactory.html#create()"><B>create()</B></A> -
+Static method in class com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMetaFactory.html" title="class in com.adobe.xmp">XMPMetaFactory</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPDateTimeFactory.html#createFromCalendar(java.util.Calendar)"><B>createFromCalendar(Calendar)</B></A> -
+Static method in class com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPDateTimeFactory.html" title="class in com.adobe.xmp">XMPDateTimeFactory</A>
+<DD>Creates an <code>XMPDateTime</code> from a <code>Calendar</code>-object.
+<DT><A HREF="../com/adobe/xmp/XMPDateTimeFactory.html#createFromISO8601(java.lang.String)"><B>createFromISO8601(String)</B></A> -
+Static method in class com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPDateTimeFactory.html" title="class in com.adobe.xmp">XMPDateTimeFactory</A>
+<DD>Creates an <code>XMPDateTime</code> from an ISO 8601 string.
+</DL>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Index</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="index-2.html"><B>PREV LETTER</B></A>&nbsp;
+&nbsp;<A HREF="index-4.html"><B>NEXT LETTER</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../index.html?index-filesindex-3.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="index-3.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<A HREF="index-1.html">A</A> <A HREF="index-2.html">B</A> <A HREF="index-3.html">C</A> <A HREF="index-4.html">D</A> <A HREF="index-5.html">E</A> <A HREF="index-6.html">F</A> <A HREF="index-7.html">G</A> <A HREF="index-8.html">H</A> <A HREF="index-9.html">I</A> <A HREF="index-10.html">J</A> <A HREF="index-11.html">M</A> <A HREF="index-12.html">N</A> <A HREF="index-13.html">O</A> <A HREF="index-14.html">P</A> <A HREF="index-15.html">Q</A> <A HREF="index-16.html">R</A> <A HREF="index-17.html">S</A> <A HREF="index-18.html">T</A> <A HREF="index-19.html">U</A> <A HREF="index-20.html">W</A> <A HREF="index-21.html">X</A> <HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/index-files/index-4.html b/java/XMPCore/docs/index-files/index-4.html
new file mode 100644
index 0000000..026a681
--- /dev/null
+++ b/java/XMPCore/docs/index-files/index-4.html
@@ -0,0 +1,177 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:51 CEST 2007 -->
+<TITLE>
+D-Index
+</TITLE>
+
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="D-Index";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Index</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="index-3.html"><B>PREV LETTER</B></A>&nbsp;
+&nbsp;<A HREF="index-5.html"><B>NEXT LETTER</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../index.html?index-filesindex-4.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="index-4.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<A HREF="index-1.html">A</A> <A HREF="index-2.html">B</A> <A HREF="index-3.html">C</A> <A HREF="index-4.html">D</A> <A HREF="index-5.html">E</A> <A HREF="index-6.html">F</A> <A HREF="index-7.html">G</A> <A HREF="index-8.html">H</A> <A HREF="index-9.html">I</A> <A HREF="index-10.html">J</A> <A HREF="index-11.html">M</A> <A HREF="index-12.html">N</A> <A HREF="index-13.html">O</A> <A HREF="index-14.html">P</A> <A HREF="index-15.html">Q</A> <A HREF="index-16.html">R</A> <A HREF="index-17.html">S</A> <A HREF="index-18.html">T</A> <A HREF="index-19.html">U</A> <A HREF="index-20.html">W</A> <A HREF="index-21.html">X</A> <HR>
+<A NAME="_D_"><!-- --></A><H2>
+<B>D</B></H2>
+<DL>
+<DT><A HREF="../com/adobe/xmp/XMPUtils.html#decodeBase64(java.lang.String)"><B>decodeBase64(String)</B></A> -
+Static method in class com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPUtils.html" title="class in com.adobe.xmp">XMPUtils</A>
+<DD>Decode from Base64 encoded string to raw data.
+<DT><A HREF="../com/adobe/xmp/options/PropertyOptions.html#DELETE_EXISTING"><B>DELETE_EXISTING</B></A> -
+Static variable in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>
+<DD>may be used in the future
+<DT><A HREF="../com/adobe/xmp/XMPSchemaRegistry.html#deleteAlias(java.lang.String, java.lang.String)"><B>deleteAlias(String, String)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPSchemaRegistry.html" title="interface in com.adobe.xmp">XMPSchemaRegistry</A>
+<DD>Delete an alias.
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#deleteArrayItem(java.lang.String, java.lang.String, int)"><B>deleteArrayItem(String, String, int)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>Deletes the given XMP subtree rooted at the given array item.
+<DT><A HREF="../com/adobe/xmp/XMPSchemaRegistry.html#deleteNamespace(java.lang.String)"><B>deleteNamespace(String)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPSchemaRegistry.html" title="interface in com.adobe.xmp">XMPSchemaRegistry</A>
+<DD>Deletes a namespace from the registry.
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#deleteProperty(java.lang.String, java.lang.String)"><B>deleteProperty(String, String)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>Deletes the given XMP subtree rooted at the given property.
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#deleteQualifier(java.lang.String, java.lang.String, java.lang.String, java.lang.String)"><B>deleteQualifier(String, String, String, String)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>Deletes the given XMP subtree rooted at the given qualifier.
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#deleteStructField(java.lang.String, java.lang.String, java.lang.String, java.lang.String)"><B>deleteStructField(String, String, String, String)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>Deletes the given XMP subtree rooted at the given struct field.
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#doesArrayItemExist(java.lang.String, java.lang.String, int)"><B>doesArrayItemExist(String, String, int)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>Tells if the array item exists.
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#doesPropertyExist(java.lang.String, java.lang.String)"><B>doesPropertyExist(String, String)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>Returns whether the property exists.
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#doesQualifierExist(java.lang.String, java.lang.String, java.lang.String, java.lang.String)"><B>doesQualifierExist(String, String, String, String)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>DoesQualifierExist tells if the qualifier exists.
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#doesStructFieldExist(java.lang.String, java.lang.String, java.lang.String, java.lang.String)"><B>doesStructFieldExist(String, String, String, String)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>DoesStructFieldExist tells if the struct field exists.
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#dumpObject()"><B>dumpObject()</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>Renders this node and the tree unter this node in a human readable form.
+</DL>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Index</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="index-3.html"><B>PREV LETTER</B></A>&nbsp;
+&nbsp;<A HREF="index-5.html"><B>NEXT LETTER</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../index.html?index-filesindex-4.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="index-4.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<A HREF="index-1.html">A</A> <A HREF="index-2.html">B</A> <A HREF="index-3.html">C</A> <A HREF="index-4.html">D</A> <A HREF="index-5.html">E</A> <A HREF="index-6.html">F</A> <A HREF="index-7.html">G</A> <A HREF="index-8.html">H</A> <A HREF="index-9.html">I</A> <A HREF="index-10.html">J</A> <A HREF="index-11.html">M</A> <A HREF="index-12.html">N</A> <A HREF="index-13.html">O</A> <A HREF="index-14.html">P</A> <A HREF="index-15.html">Q</A> <A HREF="index-16.html">R</A> <A HREF="index-17.html">S</A> <A HREF="index-18.html">T</A> <A HREF="index-19.html">U</A> <A HREF="index-20.html">W</A> <A HREF="index-21.html">X</A> <HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/index-files/index-5.html b/java/XMPCore/docs/index-files/index-5.html
new file mode 100644
index 0000000..e1ef8f8
--- /dev/null
+++ b/java/XMPCore/docs/index-files/index-5.html
@@ -0,0 +1,159 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:51 CEST 2007 -->
+<TITLE>
+E-Index
+</TITLE>
+
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="E-Index";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Index</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="index-4.html"><B>PREV LETTER</B></A>&nbsp;
+&nbsp;<A HREF="index-6.html"><B>NEXT LETTER</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../index.html?index-filesindex-5.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="index-5.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<A HREF="index-1.html">A</A> <A HREF="index-2.html">B</A> <A HREF="index-3.html">C</A> <A HREF="index-4.html">D</A> <A HREF="index-5.html">E</A> <A HREF="index-6.html">F</A> <A HREF="index-7.html">G</A> <A HREF="index-8.html">H</A> <A HREF="index-9.html">I</A> <A HREF="index-10.html">J</A> <A HREF="index-11.html">M</A> <A HREF="index-12.html">N</A> <A HREF="index-13.html">O</A> <A HREF="index-14.html">P</A> <A HREF="index-15.html">Q</A> <A HREF="index-16.html">R</A> <A HREF="index-17.html">S</A> <A HREF="index-18.html">T</A> <A HREF="index-19.html">U</A> <A HREF="index-20.html">W</A> <A HREF="index-21.html">X</A> <HR>
+<A NAME="_E_"><!-- --></A><H2>
+<B>E</B></H2>
+<DL>
+<DT><A HREF="../com/adobe/xmp/options/SerializeOptions.html#ENCODE_UTF16BE"><B>ENCODE_UTF16BE</B></A> -
+Static variable in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>
+<DD>UTF16BE encoding
+<DT><A HREF="../com/adobe/xmp/options/SerializeOptions.html#ENCODE_UTF16LE"><B>ENCODE_UTF16LE</B></A> -
+Static variable in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>
+<DD>UTF16LE encoding
+<DT><A HREF="../com/adobe/xmp/options/SerializeOptions.html#ENCODE_UTF8"><B>ENCODE_UTF8</B></A> -
+Static variable in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>
+<DD>UTF8 encoding; this is the default
+<DT><A HREF="../com/adobe/xmp/XMPUtils.html#encodeBase64(byte[])"><B>encodeBase64(byte[])</B></A> -
+Static method in class com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPUtils.html" title="class in com.adobe.xmp">XMPUtils</A>
+<DD>Convert from a byte array to a base64 encoded string.
+<DT><A HREF="../com/adobe/xmp/options/PropertyOptions.html#equalArrayTypes(com.adobe.xmp.options.PropertyOptions)"><B>equalArrayTypes(PropertyOptions)</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>
+<DD>Compares two options set for array compatibility.
+<DT><A HREF="../com/adobe/xmp/options/Options.html#equals(java.lang.Object)"><B>equals(Object)</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/Options.html" title="class in com.adobe.xmp.options">Options</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/SerializeOptions.html#EXACT_PACKET_LENGTH"><B>EXACT_PACKET_LENGTH</B></A> -
+Static variable in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>
+<DD>The padding parameter provides the overall packet length.
+</DL>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Index</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="index-4.html"><B>PREV LETTER</B></A>&nbsp;
+&nbsp;<A HREF="index-6.html"><B>NEXT LETTER</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../index.html?index-filesindex-5.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="index-5.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<A HREF="index-1.html">A</A> <A HREF="index-2.html">B</A> <A HREF="index-3.html">C</A> <A HREF="index-4.html">D</A> <A HREF="index-5.html">E</A> <A HREF="index-6.html">F</A> <A HREF="index-7.html">G</A> <A HREF="index-8.html">H</A> <A HREF="index-9.html">I</A> <A HREF="index-10.html">J</A> <A HREF="index-11.html">M</A> <A HREF="index-12.html">N</A> <A HREF="index-13.html">O</A> <A HREF="index-14.html">P</A> <A HREF="index-15.html">Q</A> <A HREF="index-16.html">R</A> <A HREF="index-17.html">S</A> <A HREF="index-18.html">T</A> <A HREF="index-19.html">U</A> <A HREF="index-20.html">W</A> <A HREF="index-21.html">X</A> <HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/index-files/index-6.html b/java/XMPCore/docs/index-files/index-6.html
new file mode 100644
index 0000000..6c64702
--- /dev/null
+++ b/java/XMPCore/docs/index-files/index-6.html
@@ -0,0 +1,150 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:51 CEST 2007 -->
+<TITLE>
+F-Index
+</TITLE>
+
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="F-Index";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Index</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="index-5.html"><B>PREV LETTER</B></A>&nbsp;
+&nbsp;<A HREF="index-7.html"><B>NEXT LETTER</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../index.html?index-filesindex-6.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="index-6.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<A HREF="index-1.html">A</A> <A HREF="index-2.html">B</A> <A HREF="index-3.html">C</A> <A HREF="index-4.html">D</A> <A HREF="index-5.html">E</A> <A HREF="index-6.html">F</A> <A HREF="index-7.html">G</A> <A HREF="index-8.html">H</A> <A HREF="index-9.html">I</A> <A HREF="index-10.html">J</A> <A HREF="index-11.html">M</A> <A HREF="index-12.html">N</A> <A HREF="index-13.html">O</A> <A HREF="index-14.html">P</A> <A HREF="index-15.html">Q</A> <A HREF="index-16.html">R</A> <A HREF="index-17.html">S</A> <A HREF="index-18.html">T</A> <A HREF="index-19.html">U</A> <A HREF="index-20.html">W</A> <A HREF="index-21.html">X</A> <HR>
+<A NAME="_F_"><!-- --></A><H2>
+<B>F</B></H2>
+<DL>
+<DT><A HREF="../com/adobe/xmp/XMPConst.html#FALSESTR"><B>FALSESTR</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp">XMPConst</A>
+<DD>The canonical false string value for Booleans in serialized XMP.
+<DT><A HREF="../com/adobe/xmp/XMPSchemaRegistry.html#findAlias(java.lang.String)"><B>findAlias(String)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPSchemaRegistry.html" title="interface in com.adobe.xmp">XMPSchemaRegistry</A>
+<DD>Searches for registered aliases.
+<DT><A HREF="../com/adobe/xmp/XMPSchemaRegistry.html#findAliases(java.lang.String)"><B>findAliases(String)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPSchemaRegistry.html" title="interface in com.adobe.xmp">XMPSchemaRegistry</A>
+<DD>Collects all aliases that are contained in the provided namespace.
+<DT><A HREF="../com/adobe/xmp/options/ParseOptions.html#FIX_CONTROL_CHARS"><B>FIX_CONTROL_CHARS</B></A> -
+Static variable in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options">ParseOptions</A>
+<DD>Convert ASCII control characters 0x01 - 0x1F (except tab, cr, and lf) to spaces.
+</DL>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Index</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="index-5.html"><B>PREV LETTER</B></A>&nbsp;
+&nbsp;<A HREF="index-7.html"><B>NEXT LETTER</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../index.html?index-filesindex-6.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="index-6.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<A HREF="index-1.html">A</A> <A HREF="index-2.html">B</A> <A HREF="index-3.html">C</A> <A HREF="index-4.html">D</A> <A HREF="index-5.html">E</A> <A HREF="index-6.html">F</A> <A HREF="index-7.html">G</A> <A HREF="index-8.html">H</A> <A HREF="index-9.html">I</A> <A HREF="index-10.html">J</A> <A HREF="index-11.html">M</A> <A HREF="index-12.html">N</A> <A HREF="index-13.html">O</A> <A HREF="index-14.html">P</A> <A HREF="index-15.html">Q</A> <A HREF="index-16.html">R</A> <A HREF="index-17.html">S</A> <A HREF="index-18.html">T</A> <A HREF="index-19.html">U</A> <A HREF="index-20.html">W</A> <A HREF="index-21.html">X</A> <HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/index-files/index-7.html b/java/XMPCore/docs/index-files/index-7.html
new file mode 100644
index 0000000..ef1e513
--- /dev/null
+++ b/java/XMPCore/docs/index-files/index-7.html
@@ -0,0 +1,362 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:51 CEST 2007 -->
+<TITLE>
+G-Index
+</TITLE>
+
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="G-Index";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Index</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="index-6.html"><B>PREV LETTER</B></A>&nbsp;
+&nbsp;<A HREF="index-8.html"><B>NEXT LETTER</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../index.html?index-filesindex-7.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="index-7.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<A HREF="index-1.html">A</A> <A HREF="index-2.html">B</A> <A HREF="index-3.html">C</A> <A HREF="index-4.html">D</A> <A HREF="index-5.html">E</A> <A HREF="index-6.html">F</A> <A HREF="index-7.html">G</A> <A HREF="index-8.html">H</A> <A HREF="index-9.html">I</A> <A HREF="index-10.html">J</A> <A HREF="index-11.html">M</A> <A HREF="index-12.html">N</A> <A HREF="index-13.html">O</A> <A HREF="index-14.html">P</A> <A HREF="index-15.html">Q</A> <A HREF="index-16.html">R</A> <A HREF="index-17.html">S</A> <A HREF="index-18.html">T</A> <A HREF="index-19.html">U</A> <A HREF="index-20.html">W</A> <A HREF="index-21.html">X</A> <HR>
+<A NAME="_G_"><!-- --></A><H2>
+<B>G</B></H2>
+<DL>
+<DT><A HREF="../com/adobe/xmp/options/ParseOptions.html#getAcceptLatin1()"><B>getAcceptLatin1()</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options">ParseOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPSchemaRegistry.html#getAliases()"><B>getAliases()</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPSchemaRegistry.html" title="interface in com.adobe.xmp">XMPSchemaRegistry</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/properties/XMPAliasInfo.html#getAliasForm()"><B>getAliasForm()</B></A> -
+Method in interface com.adobe.xmp.properties.<A HREF="../com/adobe/xmp/properties/XMPAliasInfo.html" title="interface in com.adobe.xmp.properties">XMPAliasInfo</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#getArrayItem(java.lang.String, java.lang.String, int)"><B>getArrayItem(String, String, int)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>Provides access to items within an array.
+<DT><A HREF="../com/adobe/xmp/options/SerializeOptions.html#getBaseIndent()"><B>getBaseIndent()</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPVersionInfo.html#getBuild()"><B>getBuild()</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPVersionInfo.html" title="interface in com.adobe.xmp">XMPVersionInfo</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPDateTime.html#getCalendar()"><B>getCalendar()</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPDateTimeFactory.html#getCurrentDateTime()"><B>getCurrentDateTime()</B></A> -
+Static method in class com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPDateTimeFactory.html" title="class in com.adobe.xmp">XMPDateTimeFactory</A>
+<DD>Obtain the current date and time.
+<DT><A HREF="../com/adobe/xmp/XMPDateTime.html#getDay()"><B>getDay()</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/SerializeOptions.html#getEncodeUTF16BE()"><B>getEncodeUTF16BE()</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/SerializeOptions.html#getEncodeUTF16LE()"><B>getEncodeUTF16LE()</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/SerializeOptions.html#getEncoding()"><B>getEncoding()</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPException.html#getErrorCode()"><B>getErrorCode()</B></A> -
+Method in exception com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">XMPException</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/SerializeOptions.html#getExactPacketLength()"><B>getExactPacketLength()</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/ParseOptions.html#getFixControlChars()"><B>getFixControlChars()</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options">ParseOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/PropertyOptions.html#getHasLanguage()"><B>getHasLanguage()</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/PropertyOptions.html#getHasQualifiers()"><B>getHasQualifiers()</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/PropertyOptions.html#getHasType()"><B>getHasType()</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPDateTime.html#getHour()"><B>getHour()</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/SerializeOptions.html#getIncludeThumbnailPad()"><B>getIncludeThumbnailPad()</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/SerializeOptions.html#getIndent()"><B>getIndent()</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPDateTime.html#getISO8601String()"><B>getISO8601String()</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/properties/XMPProperty.html#getLanguage()"><B>getLanguage()</B></A> -
+Method in interface com.adobe.xmp.properties.<A HREF="../com/adobe/xmp/properties/XMPProperty.html" title="interface in com.adobe.xmp.properties">XMPProperty</A>
+<DD>Only set by <A HREF="../com/adobe/xmp/XMPMeta.html#getLocalizedText(java.lang.String, java.lang.String, java.lang.String, java.lang.String)"><CODE>XMPMeta.getLocalizedText(String, String, String, String)</CODE></A>.
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#getLocalizedText(java.lang.String, java.lang.String, java.lang.String, java.lang.String)"><B>getLocalizedText(String, String, String, String)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>These functions provide convenient support for localized text properties, including a number
+ of special and obscure aspects.
+<DT><A HREF="../com/adobe/xmp/XMPVersionInfo.html#getMajor()"><B>getMajor()</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPVersionInfo.html" title="interface in com.adobe.xmp">XMPVersionInfo</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPVersionInfo.html#getMessage()"><B>getMessage()</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPVersionInfo.html" title="interface in com.adobe.xmp">XMPVersionInfo</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPVersionInfo.html#getMicro()"><B>getMicro()</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPVersionInfo.html" title="interface in com.adobe.xmp">XMPVersionInfo</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPVersionInfo.html#getMinor()"><B>getMinor()</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPVersionInfo.html" title="interface in com.adobe.xmp">XMPVersionInfo</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPDateTime.html#getMinute()"><B>getMinute()</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPDateTime.html#getMonth()"><B>getMonth()</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/properties/XMPAliasInfo.html#getNamespace()"><B>getNamespace()</B></A> -
+Method in interface com.adobe.xmp.properties.<A HREF="../com/adobe/xmp/properties/XMPAliasInfo.html" title="interface in com.adobe.xmp.properties">XMPAliasInfo</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/properties/XMPPropertyInfo.html#getNamespace()"><B>getNamespace()</B></A> -
+Method in interface com.adobe.xmp.properties.<A HREF="../com/adobe/xmp/properties/XMPPropertyInfo.html" title="interface in com.adobe.xmp.properties">XMPPropertyInfo</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPSchemaRegistry.html#getNamespacePrefix(java.lang.String)"><B>getNamespacePrefix(String)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPSchemaRegistry.html" title="interface in com.adobe.xmp">XMPSchemaRegistry</A>
+<DD>Obtain the prefix for a registered namespace URI.
+<DT><A HREF="../com/adobe/xmp/XMPSchemaRegistry.html#getNamespaces()"><B>getNamespaces()</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPSchemaRegistry.html" title="interface in com.adobe.xmp">XMPSchemaRegistry</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPSchemaRegistry.html#getNamespaceURI(java.lang.String)"><B>getNamespaceURI(String)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPSchemaRegistry.html" title="interface in com.adobe.xmp">XMPSchemaRegistry</A>
+<DD>Obtain the URI for a registered namespace prefix.
+<DT><A HREF="../com/adobe/xmp/XMPDateTime.html#getNanoSecond()"><B>getNanoSecond()</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/SerializeOptions.html#getNewline()"><B>getNewline()</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#getObjectName()"><B>getObjectName()</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>This correlates to the about-attribute,
+ returns the empty String if no name is set.
+<DT><A HREF="../com/adobe/xmp/options/SerializeOptions.html#getOmitPacketWrapper()"><B>getOmitPacketWrapper()</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/SerializeOptions.html#getOmitVersionAttribute()"><B>getOmitVersionAttribute()</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/Options.html#getOptions()"><B>getOptions()</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/Options.html" title="class in com.adobe.xmp.options">Options</A>
+<DD>Is friendly to access it during the tests.
+<DT><A HREF="../com/adobe/xmp/properties/XMPProperty.html#getOptions()"><B>getOptions()</B></A> -
+Method in interface com.adobe.xmp.properties.<A HREF="../com/adobe/xmp/properties/XMPProperty.html" title="interface in com.adobe.xmp.properties">XMPProperty</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/properties/XMPPropertyInfo.html#getOptions()"><B>getOptions()</B></A> -
+Method in interface com.adobe.xmp.properties.<A HREF="../com/adobe/xmp/properties/XMPPropertyInfo.html" title="interface in com.adobe.xmp.properties">XMPPropertyInfo</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/Options.html#getOptionsString()"><B>getOptionsString()</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/Options.html" title="class in com.adobe.xmp.options">Options</A>
+<DD>Creates a human readable string from the set options.
+<DT><A HREF="../com/adobe/xmp/options/SerializeOptions.html#getPadding()"><B>getPadding()</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/properties/XMPPropertyInfo.html#getPath()"><B>getPath()</B></A> -
+Method in interface com.adobe.xmp.properties.<A HREF="../com/adobe/xmp/properties/XMPPropertyInfo.html" title="interface in com.adobe.xmp.properties">XMPPropertyInfo</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/properties/XMPAliasInfo.html#getPrefix()"><B>getPrefix()</B></A> -
+Method in interface com.adobe.xmp.properties.<A HREF="../com/adobe/xmp/properties/XMPAliasInfo.html" title="interface in com.adobe.xmp.properties">XMPAliasInfo</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPSchemaRegistry.html#getPrefixes()"><B>getPrefixes()</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPSchemaRegistry.html" title="interface in com.adobe.xmp">XMPSchemaRegistry</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#getProperty(java.lang.String, java.lang.String)"><B>getProperty(String, String)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>The property value getter-methods all take a property specification: the first two parameters
+ are always the top level namespace URI (the &quot;schema&quot; namespace) and the basic name
+ of the property being referenced.
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#getPropertyBase64(java.lang.String, java.lang.String)"><B>getPropertyBase64(String, String)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>Convenience method to retrieve the literal value of a property.
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#getPropertyBoolean(java.lang.String, java.lang.String)"><B>getPropertyBoolean(String, String)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>These are very similar to <code>getProperty()</code> and <code>SetProperty()</code> above,
+ but the value is returned or provided in a literal form instead of as a UTF-8 string.
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#getPropertyCalendar(java.lang.String, java.lang.String)"><B>getPropertyCalendar(String, String)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>Convenience method to retrieve the literal value of a property.
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#getPropertyDate(java.lang.String, java.lang.String)"><B>getPropertyDate(String, String)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>Convenience method to retrieve the literal value of a property.
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#getPropertyDouble(java.lang.String, java.lang.String)"><B>getPropertyDouble(String, String)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>Convenience method to retrieve the literal value of a property.
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#getPropertyInteger(java.lang.String, java.lang.String)"><B>getPropertyInteger(String, String)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>Convenience method to retrieve the literal value of a property.
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#getPropertyLong(java.lang.String, java.lang.String)"><B>getPropertyLong(String, String)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>Convenience method to retrieve the literal value of a property.
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#getPropertyString(java.lang.String, java.lang.String)"><B>getPropertyString(String, String)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>Convenience method to retrieve the literal value of a property.
+<DT><A HREF="../com/adobe/xmp/properties/XMPAliasInfo.html#getPropName()"><B>getPropName()</B></A> -
+Method in interface com.adobe.xmp.properties.<A HREF="../com/adobe/xmp/properties/XMPAliasInfo.html" title="interface in com.adobe.xmp.properties">XMPAliasInfo</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#getQualifier(java.lang.String, java.lang.String, java.lang.String, java.lang.String)"><B>getQualifier(String, String, String, String)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>Provides access to a qualifier attached to a property.
+<DT><A HREF="../com/adobe/xmp/options/SerializeOptions.html#getReadOnlyPacket()"><B>getReadOnlyPacket()</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/ParseOptions.html#getRequireXMPMeta()"><B>getRequireXMPMeta()</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options">ParseOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPMetaFactory.html#getSchemaRegistry()"><B>getSchemaRegistry()</B></A> -
+Static method in class com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMetaFactory.html" title="class in com.adobe.xmp">XMPMetaFactory</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPDateTime.html#getSecond()"><B>getSecond()</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/SerializeOptions.html#getSort()"><B>getSort()</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/ParseOptions.html#getStrictAliasing()"><B>getStrictAliasing()</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options">ParseOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#getStructField(java.lang.String, java.lang.String, java.lang.String, java.lang.String)"><B>getStructField(String, String, String, String)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>Provides access to fields within a nested structure.
+<DT><A HREF="../com/adobe/xmp/XMPDateTime.html#getTimeZone()"><B>getTimeZone()</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/SerializeOptions.html#getUseCompactFormat()"><B>getUseCompactFormat()</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/properties/XMPProperty.html#getValue()"><B>getValue()</B></A> -
+Method in interface com.adobe.xmp.properties.<A HREF="../com/adobe/xmp/properties/XMPProperty.html" title="interface in com.adobe.xmp.properties">XMPProperty</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/properties/XMPPropertyInfo.html#getValue()"><B>getValue()</B></A> -
+Method in interface com.adobe.xmp.properties.<A HREF="../com/adobe/xmp/properties/XMPPropertyInfo.html" title="interface in com.adobe.xmp.properties">XMPPropertyInfo</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPMetaFactory.html#getVersionInfo()"><B>getVersionInfo()</B></A> -
+Static method in class com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMetaFactory.html" title="class in com.adobe.xmp">XMPMetaFactory</A>
+<DD>Obtain version information.
+<DT><A HREF="../com/adobe/xmp/options/SerializeOptions.html#getWriteAliasComments()"><B>getWriteAliasComments()</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPDateTime.html#getYear()"><B>getYear()</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp">XMPDateTime</A>
+<DD>&nbsp;
+</DL>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Index</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="index-6.html"><B>PREV LETTER</B></A>&nbsp;
+&nbsp;<A HREF="index-8.html"><B>NEXT LETTER</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../index.html?index-filesindex-7.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="index-7.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<A HREF="index-1.html">A</A> <A HREF="index-2.html">B</A> <A HREF="index-3.html">C</A> <A HREF="index-4.html">D</A> <A HREF="index-5.html">E</A> <A HREF="index-6.html">F</A> <A HREF="index-7.html">G</A> <A HREF="index-8.html">H</A> <A HREF="index-9.html">I</A> <A HREF="index-10.html">J</A> <A HREF="index-11.html">M</A> <A HREF="index-12.html">N</A> <A HREF="index-13.html">O</A> <A HREF="index-14.html">P</A> <A HREF="index-15.html">Q</A> <A HREF="index-16.html">R</A> <A HREF="index-17.html">S</A> <A HREF="index-18.html">T</A> <A HREF="index-19.html">U</A> <A HREF="index-20.html">W</A> <A HREF="index-21.html">X</A> <HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/index-files/index-8.html b/java/XMPCore/docs/index-files/index-8.html
new file mode 100644
index 0000000..8fec0b9
--- /dev/null
+++ b/java/XMPCore/docs/index-files/index-8.html
@@ -0,0 +1,150 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:51 CEST 2007 -->
+<TITLE>
+H-Index
+</TITLE>
+
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="H-Index";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Index</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="index-7.html"><B>PREV LETTER</B></A>&nbsp;
+&nbsp;<A HREF="index-9.html"><B>NEXT LETTER</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../index.html?index-filesindex-8.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="index-8.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<A HREF="index-1.html">A</A> <A HREF="index-2.html">B</A> <A HREF="index-3.html">C</A> <A HREF="index-4.html">D</A> <A HREF="index-5.html">E</A> <A HREF="index-6.html">F</A> <A HREF="index-7.html">G</A> <A HREF="index-8.html">H</A> <A HREF="index-9.html">I</A> <A HREF="index-10.html">J</A> <A HREF="index-11.html">M</A> <A HREF="index-12.html">N</A> <A HREF="index-13.html">O</A> <A HREF="index-14.html">P</A> <A HREF="index-15.html">Q</A> <A HREF="index-16.html">R</A> <A HREF="index-17.html">S</A> <A HREF="index-18.html">T</A> <A HREF="index-19.html">U</A> <A HREF="index-20.html">W</A> <A HREF="index-21.html">X</A> <HR>
+<A NAME="_H_"><!-- --></A><H2>
+<B>H</B></H2>
+<DL>
+<DT><A HREF="../com/adobe/xmp/options/PropertyOptions.html#HAS_LANGUAGE"><B>HAS_LANGUAGE</B></A> -
+Static variable in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/PropertyOptions.html#HAS_QUALIFIERS"><B>HAS_QUALIFIERS</B></A> -
+Static variable in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/PropertyOptions.html#HAS_TYPE"><B>HAS_TYPE</B></A> -
+Static variable in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/Options.html#hashCode()"><B>hashCode()</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/Options.html" title="class in com.adobe.xmp.options">Options</A>
+<DD>&nbsp;
+</DL>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Index</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="index-7.html"><B>PREV LETTER</B></A>&nbsp;
+&nbsp;<A HREF="index-9.html"><B>NEXT LETTER</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../index.html?index-filesindex-8.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="index-8.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<A HREF="index-1.html">A</A> <A HREF="index-2.html">B</A> <A HREF="index-3.html">C</A> <A HREF="index-4.html">D</A> <A HREF="index-5.html">E</A> <A HREF="index-6.html">F</A> <A HREF="index-7.html">G</A> <A HREF="index-8.html">H</A> <A HREF="index-9.html">I</A> <A HREF="index-10.html">J</A> <A HREF="index-11.html">M</A> <A HREF="index-12.html">N</A> <A HREF="index-13.html">O</A> <A HREF="index-14.html">P</A> <A HREF="index-15.html">Q</A> <A HREF="index-16.html">R</A> <A HREF="index-17.html">S</A> <A HREF="index-18.html">T</A> <A HREF="index-19.html">U</A> <A HREF="index-20.html">W</A> <A HREF="index-21.html">X</A> <HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/index-files/index-9.html b/java/XMPCore/docs/index-files/index-9.html
new file mode 100644
index 0000000..e23855f
--- /dev/null
+++ b/java/XMPCore/docs/index-files/index-9.html
@@ -0,0 +1,234 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:51 CEST 2007 -->
+<TITLE>
+I-Index
+</TITLE>
+
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="../stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="I-Index";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Index</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="index-8.html"><B>PREV LETTER</B></A>&nbsp;
+&nbsp;<A HREF="index-10.html"><B>NEXT LETTER</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../index.html?index-filesindex-9.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="index-9.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<A HREF="index-1.html">A</A> <A HREF="index-2.html">B</A> <A HREF="index-3.html">C</A> <A HREF="index-4.html">D</A> <A HREF="index-5.html">E</A> <A HREF="index-6.html">F</A> <A HREF="index-7.html">G</A> <A HREF="index-8.html">H</A> <A HREF="index-9.html">I</A> <A HREF="index-10.html">J</A> <A HREF="index-11.html">M</A> <A HREF="index-12.html">N</A> <A HREF="index-13.html">O</A> <A HREF="index-14.html">P</A> <A HREF="index-15.html">Q</A> <A HREF="index-16.html">R</A> <A HREF="index-17.html">S</A> <A HREF="index-18.html">T</A> <A HREF="index-19.html">U</A> <A HREF="index-20.html">W</A> <A HREF="index-21.html">X</A> <HR>
+<A NAME="_I_"><!-- --></A><H2>
+<B>I</B></H2>
+<DL>
+<DT><A HREF="../com/adobe/xmp/options/IteratorOptions.html#INCLUDE_ALIASES"><B>INCLUDE_ALIASES</B></A> -
+Static variable in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options">IteratorOptions</A>
+<DD><B>Deprecated.</B>&nbsp;<I>it is commonly preferred to work with the base properties</I>
+<DT><A HREF="../com/adobe/xmp/options/SerializeOptions.html#INCLUDE_THUMBNAIL_PAD"><B>INCLUDE_THUMBNAIL_PAD</B></A> -
+Static variable in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options">SerializeOptions</A>
+<DD>Include a padding allowance for a thumbnail image.
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#insertArrayItem(java.lang.String, java.lang.String, int, java.lang.String, com.adobe.xmp.options.PropertyOptions)"><B>insertArrayItem(String, String, int, String, PropertyOptions)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>Inserts an item into an array previous to the given index.
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#insertArrayItem(java.lang.String, java.lang.String, int, java.lang.String)"><B>insertArrayItem(String, String, int, String)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPError.html#INTERNALFAILURE"><B>INTERNALFAILURE</B></A> -
+Static variable in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPError.html" title="interface in com.adobe.xmp">XMPError</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/AliasOptions.html#isArray()"><B>isArray()</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options">AliasOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/PropertyOptions.html#isArray()"><B>isArray()</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/AliasOptions.html#isArrayAlternate()"><B>isArrayAlternate()</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options">AliasOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/PropertyOptions.html#isArrayAlternate()"><B>isArrayAlternate()</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/AliasOptions.html#isArrayAltText()"><B>isArrayAltText()</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options">AliasOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/PropertyOptions.html#isArrayAltText()"><B>isArrayAltText()</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/AliasOptions.html#isArrayOrdered()"><B>isArrayOrdered()</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options">AliasOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/PropertyOptions.html#isArrayOrdered()"><B>isArrayOrdered()</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/PropertyOptions.html#isCompact()"><B>isCompact()</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/PropertyOptions.html#isCompositeProperty()"><B>isCompositeProperty()</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPVersionInfo.html#isDebug()"><B>isDebug()</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPVersionInfo.html" title="interface in com.adobe.xmp">XMPVersionInfo</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/Options.html#isExactly(int)"><B>isExactly(int)</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/Options.html" title="class in com.adobe.xmp.options">Options</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/IteratorOptions.html#isJustChildren()"><B>isJustChildren()</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options">IteratorOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/IteratorOptions.html#isJustLeafname()"><B>isJustLeafname()</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options">IteratorOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/IteratorOptions.html#isJustLeafnodes()"><B>isJustLeafnodes()</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options">IteratorOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/IteratorOptions.html#isOmitQualifiers()"><B>isOmitQualifiers()</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options">IteratorOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/PropertyOptions.html#isOnlyArrayOptions()"><B>isOnlyArrayOptions()</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/PropertyOptions.html#isQualifier()"><B>isQualifier()</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/PropertyOptions.html#isSchemaNode()"><B>isSchemaNode()</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/AliasOptions.html#isSimple()"><B>isSimple()</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options">AliasOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/PropertyOptions.html#isSimple()"><B>isSimple()</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/PropertyOptions.html#isStruct()"><B>isStruct()</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/options/PropertyOptions.html#isURI()"><B>isURI()</B></A> -
+Method in class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options">PropertyOptions</A>
+<DD>&nbsp;
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#iterator()"><B>iterator()</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>Constructs an iterator for the properties within this XMP object.
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#iterator(com.adobe.xmp.options.IteratorOptions)"><B>iterator(IteratorOptions)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>Constructs an iterator for the properties within this XMP object using some options.
+<DT><A HREF="../com/adobe/xmp/XMPMeta.html#iterator(java.lang.String, java.lang.String, com.adobe.xmp.options.IteratorOptions)"><B>iterator(String, String, IteratorOptions)</B></A> -
+Method in interface com.adobe.xmp.<A HREF="../com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp">XMPMeta</A>
+<DD>Construct an iterator for the properties within an XMP object.
+<DT><A HREF="../com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options"><B>IteratorOptions</B></A> - Class in <A HREF="../com/adobe/xmp/options/package-summary.html">com.adobe.xmp.options</A><DD>Options for <code>XMPIterator</code> construction.<DT><A HREF="../com/adobe/xmp/options/IteratorOptions.html#IteratorOptions()"><B>IteratorOptions()</B></A> -
+Constructor for class com.adobe.xmp.options.<A HREF="../com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options">IteratorOptions</A>
+<DD>&nbsp;
+</DL>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Index</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="../help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="index-8.html"><B>PREV LETTER</B></A>&nbsp;
+&nbsp;<A HREF="index-10.html"><B>NEXT LETTER</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="../index.html?index-filesindex-9.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="index-9.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="../allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="../allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<A HREF="index-1.html">A</A> <A HREF="index-2.html">B</A> <A HREF="index-3.html">C</A> <A HREF="index-4.html">D</A> <A HREF="index-5.html">E</A> <A HREF="index-6.html">F</A> <A HREF="index-7.html">G</A> <A HREF="index-8.html">H</A> <A HREF="index-9.html">I</A> <A HREF="index-10.html">J</A> <A HREF="index-11.html">M</A> <A HREF="index-12.html">N</A> <A HREF="index-13.html">O</A> <A HREF="index-14.html">P</A> <A HREF="index-15.html">Q</A> <A HREF="index-16.html">R</A> <A HREF="index-17.html">S</A> <A HREF="index-18.html">T</A> <A HREF="index-19.html">U</A> <A HREF="index-20.html">W</A> <A HREF="index-21.html">X</A> <HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/index.html b/java/XMPCore/docs/index.html
new file mode 100644
index 0000000..3693809
--- /dev/null
+++ b/java/XMPCore/docs/index.html
@@ -0,0 +1,37 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc on Thu May 03 14:54:51 CEST 2007-->
+<TITLE>
+Generated Documentation (Untitled)
+</TITLE>
+<SCRIPT type="text/javascript">
+ targetPage = "" + window.location.search;
+ if (targetPage != "" && targetPage != "undefined")
+ targetPage = targetPage.substring(1);
+ function loadFrames() {
+ if (targetPage != "" && targetPage != "undefined")
+ top.classFrame.location = top.targetPage;
+ }
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+</HEAD>
+<FRAMESET cols="20%,80%" title="" onLoad="top.loadFrames()">
+<FRAMESET rows="30%,70%" title="" onLoad="top.loadFrames()">
+<FRAME src="overview-frame.html" name="packageListFrame" title="All Packages">
+<FRAME src="allclasses-frame.html" name="packageFrame" title="All classes and interfaces (except non-static nested types)">
+</FRAMESET>
+<FRAME src="overview-summary.html" name="classFrame" title="Package, class and interface descriptions" scrolling="yes">
+<NOFRAMES>
+<H2>
+Frame Alert</H2>
+
+<P>
+This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client.
+<BR>
+Link to<A HREF="overview-summary.html">Non-frame version.</A>
+</NOFRAMES>
+</FRAMESET>
+</HTML>
diff --git a/java/XMPCore/docs/overview-frame.html b/java/XMPCore/docs/overview-frame.html
new file mode 100644
index 0000000..a40f541
--- /dev/null
+++ b/java/XMPCore/docs/overview-frame.html
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:50 CEST 2007 -->
+<TITLE>
+Overview
+</TITLE>
+
+<META NAME="keywords" CONTENT="Overview, <h1>Adobe XMPCore</h1>">
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="stylesheet.css" TITLE="Style">
+
+
+</HEAD>
+
+<BODY BGCOLOR="white">
+
+<TABLE BORDER="0" WIDTH="100%" SUMMARY="">
+<TR>
+<TH ALIGN="left" NOWRAP><FONT size="+1" CLASS="FrameTitleFont">
+<B></B></FONT></TH>
+</TR>
+</TABLE>
+
+<TABLE BORDER="0" WIDTH="100%" SUMMARY="">
+<TR>
+<TD NOWRAP><FONT CLASS="FrameItemFont"><A HREF="allclasses-frame.html" target="packageFrame">All Classes</A></FONT>
+<P>
+<FONT size="+1" CLASS="FrameHeadingFont">
+Packages</FONT>
+<BR>
+<FONT CLASS="FrameItemFont"><A HREF="com/adobe/xmp/package-frame.html" target="packageFrame">com.adobe.xmp</A></FONT>
+<BR>
+<FONT CLASS="FrameItemFont"><A HREF="com/adobe/xmp/options/package-frame.html" target="packageFrame">com.adobe.xmp.options</A></FONT>
+<BR>
+<FONT CLASS="FrameItemFont"><A HREF="com/adobe/xmp/properties/package-frame.html" target="packageFrame">com.adobe.xmp.properties</A></FONT>
+<BR>
+</TD>
+</TR>
+</TABLE>
+
+<P>
+&nbsp;
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/overview-summary.html b/java/XMPCore/docs/overview-summary.html
new file mode 100644
index 0000000..2938859
--- /dev/null
+++ b/java/XMPCore/docs/overview-summary.html
@@ -0,0 +1,161 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:51 CEST 2007 -->
+<TITLE>
+Overview
+</TITLE>
+
+<META NAME="keywords" CONTENT="Overview, <h1>Adobe XMPCore</h1>">
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="Overview";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Overview</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="index.html?overview-summary.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="overview-summary.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<CENTER>
+<H1>
+<h1>Adobe XMPCore</h1>
+</H1>
+</CENTER>
+
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+<B>Packages</B></FONT></TH>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD WIDTH="20%"><B><A HREF="com/adobe/xmp/package-summary.html">com.adobe.xmp</A></B></TD>
+<TD>Package containing the xmpcore interface.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD WIDTH="20%"><B><A HREF="com/adobe/xmp/options/package-summary.html">com.adobe.xmp.options</A></B></TD>
+<TD>Package containing the option classes.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD WIDTH="20%"><B><A HREF="com/adobe/xmp/properties/package-summary.html">com.adobe.xmp.properties</A></B></TD>
+<TD>Package containing the property information classes.</TD>
+</TR>
+</TABLE>
+
+<P>
+&nbsp;<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Overview</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="index.html?overview-summary.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="overview-summary.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/overview-tree.html b/java/XMPCore/docs/overview-tree.html
new file mode 100644
index 0000000..75afc85
--- /dev/null
+++ b/java/XMPCore/docs/overview-tree.html
@@ -0,0 +1,168 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:51 CEST 2007 -->
+<TITLE>
+Class Hierarchy
+</TITLE>
+
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="Class Hierarchy";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Tree</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="index.html?overview-tree.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="overview-tree.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<CENTER>
+<H2>
+Hierarchy For All Packages</H2>
+</CENTER>
+<DL>
+<DT><B>Package Hierarchies:</B><DD><A HREF="com/adobe/xmp/package-tree.html">com.adobe.xmp</A>, <A HREF="com/adobe/xmp/options/package-tree.html">com.adobe.xmp.options</A>, <A HREF="com/adobe/xmp/properties/package-tree.html">com.adobe.xmp.properties</A></DL>
+<HR>
+<H2>
+Class Hierarchy
+</H2>
+<UL>
+<LI TYPE="circle">java.lang.Object<UL>
+<LI TYPE="circle">com.adobe.xmp.options.<A HREF="com/adobe/xmp/options/Options.html" title="class in com.adobe.xmp.options"><B>Options</B></A><UL>
+<LI TYPE="circle">com.adobe.xmp.options.<A HREF="com/adobe/xmp/options/AliasOptions.html" title="class in com.adobe.xmp.options"><B>AliasOptions</B></A><LI TYPE="circle">com.adobe.xmp.options.<A HREF="com/adobe/xmp/options/IteratorOptions.html" title="class in com.adobe.xmp.options"><B>IteratorOptions</B></A><LI TYPE="circle">com.adobe.xmp.options.<A HREF="com/adobe/xmp/options/ParseOptions.html" title="class in com.adobe.xmp.options"><B>ParseOptions</B></A><LI TYPE="circle">com.adobe.xmp.options.<A HREF="com/adobe/xmp/options/PropertyOptions.html" title="class in com.adobe.xmp.options"><B>PropertyOptions</B></A><LI TYPE="circle">com.adobe.xmp.options.<A HREF="com/adobe/xmp/options/SerializeOptions.html" title="class in com.adobe.xmp.options"><B>SerializeOptions</B></A></UL>
+<LI TYPE="circle">java.lang.Throwable (implements java.io.Serializable)
+<UL>
+<LI TYPE="circle">java.lang.Exception<UL>
+<LI TYPE="circle">com.adobe.xmp.<A HREF="com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp"><B>XMPException</B></A></UL>
+</UL>
+<LI TYPE="circle">com.adobe.xmp.<A HREF="com/adobe/xmp/XMPDateTimeFactory.html" title="class in com.adobe.xmp"><B>XMPDateTimeFactory</B></A><LI TYPE="circle">com.adobe.xmp.<A HREF="com/adobe/xmp/XMPMetaFactory.html" title="class in com.adobe.xmp"><B>XMPMetaFactory</B></A><LI TYPE="circle">com.adobe.xmp.<A HREF="com/adobe/xmp/XMPPathFactory.html" title="class in com.adobe.xmp"><B>XMPPathFactory</B></A><LI TYPE="circle">com.adobe.xmp.<A HREF="com/adobe/xmp/XMPUtils.html" title="class in com.adobe.xmp"><B>XMPUtils</B></A></UL>
+</UL>
+<H2>
+Interface Hierarchy
+</H2>
+<UL>
+<LI TYPE="circle">java.lang.Cloneable<UL>
+<LI TYPE="circle">com.adobe.xmp.<A HREF="com/adobe/xmp/XMPMeta.html" title="interface in com.adobe.xmp"><B>XMPMeta</B></A></UL>
+<LI TYPE="circle">java.lang.Comparable<UL>
+<LI TYPE="circle">com.adobe.xmp.<A HREF="com/adobe/xmp/XMPDateTime.html" title="interface in com.adobe.xmp"><B>XMPDateTime</B></A></UL>
+<LI TYPE="circle">java.util.Iterator<UL>
+<LI TYPE="circle">com.adobe.xmp.<A HREF="com/adobe/xmp/XMPIterator.html" title="interface in com.adobe.xmp"><B>XMPIterator</B></A></UL>
+<LI TYPE="circle">com.adobe.xmp.properties.<A HREF="com/adobe/xmp/properties/XMPAliasInfo.html" title="interface in com.adobe.xmp.properties"><B>XMPAliasInfo</B></A><LI TYPE="circle">com.adobe.xmp.<A HREF="com/adobe/xmp/XMPConst.html" title="interface in com.adobe.xmp"><B>XMPConst</B></A><LI TYPE="circle">com.adobe.xmp.<A HREF="com/adobe/xmp/XMPError.html" title="interface in com.adobe.xmp"><B>XMPError</B></A><LI TYPE="circle">com.adobe.xmp.properties.<A HREF="com/adobe/xmp/properties/XMPProperty.html" title="interface in com.adobe.xmp.properties"><B>XMPProperty</B></A><UL>
+<LI TYPE="circle">com.adobe.xmp.properties.<A HREF="com/adobe/xmp/properties/XMPPropertyInfo.html" title="interface in com.adobe.xmp.properties"><B>XMPPropertyInfo</B></A></UL>
+<LI TYPE="circle">com.adobe.xmp.<A HREF="com/adobe/xmp/XMPSchemaRegistry.html" title="interface in com.adobe.xmp"><B>XMPSchemaRegistry</B></A><LI TYPE="circle">com.adobe.xmp.<A HREF="com/adobe/xmp/XMPVersionInfo.html" title="interface in com.adobe.xmp"><B>XMPVersionInfo</B></A></UL>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Tree</B></FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="index.html?overview-tree.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="overview-tree.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/package-list b/java/XMPCore/docs/package-list
new file mode 100644
index 0000000..bbeec25
--- /dev/null
+++ b/java/XMPCore/docs/package-list
@@ -0,0 +1,3 @@
+com.adobe.xmp
+com.adobe.xmp.options
+com.adobe.xmp.properties
diff --git a/java/XMPCore/docs/resources/inherit.gif b/java/XMPCore/docs/resources/inherit.gif
new file mode 100644
index 0000000..c814867
--- /dev/null
+++ b/java/XMPCore/docs/resources/inherit.gif
Binary files differ
diff --git a/java/XMPCore/docs/serialized-form.html b/java/XMPCore/docs/serialized-form.html
new file mode 100644
index 0000000..720f3e2
--- /dev/null
+++ b/java/XMPCore/docs/serialized-form.html
@@ -0,0 +1,177 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc (build 1.5.0_07) on Thu May 03 14:54:50 CEST 2007 -->
+<TITLE>
+Serialized Form
+</TITLE>
+
+
+<LINK REL ="stylesheet" TYPE="text/css" HREF="stylesheet.css" TITLE="Style">
+
+<SCRIPT type="text/javascript">
+function windowTitle()
+{
+ parent.document.title="Serialized Form";
+}
+</SCRIPT>
+<NOSCRIPT>
+</NOSCRIPT>
+
+</HEAD>
+
+<BODY BGCOLOR="white" onload="windowTitle();">
+
+
+<!-- ========= START OF TOP NAVBAR ======= -->
+<A NAME="navbar_top"><!-- --></A>
+<A HREF="#skip-navbar_top" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="index.html?serialized-form.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="serialized-form.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_top"></A>
+<!-- ========= END OF TOP NAVBAR ========= -->
+
+<HR>
+<CENTER>
+<H1>
+Serialized Form</H1>
+</CENTER>
+<HR SIZE="4" NOSHADE>
+
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="center"><FONT SIZE="+2">
+<B>Package</B> <B>com.adobe.xmp</B></FONT></TH>
+</TR>
+</TABLE>
+
+<P>
+<A NAME="com.adobe.xmp.XMPException"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableSubHeadingColor">
+<TH ALIGN="left" COLSPAN="2"><FONT SIZE="+2">
+<B>Class <A HREF="com/adobe/xmp/XMPException.html" title="class in com.adobe.xmp">com.adobe.xmp.XMPException</A> extends java.lang.Exception implements Serializable</B></FONT></TH>
+</TR>
+</TABLE>
+
+<P>
+<A NAME="serializedForm"><!-- --></A>
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TH ALIGN="left" COLSPAN="1"><FONT SIZE="+2">
+<B>Serialized Fields</B></FONT></TH>
+</TR>
+</TABLE>
+
+<H3>
+errorCode</H3>
+<PRE>
+int <B>errorCode</B></PRE>
+<DL>
+<DD>the errorCode of the XMP toolkit
+<P>
+<DL>
+</DL>
+</DL>
+
+<P>
+<HR>
+
+
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<A HREF="#skip-navbar_bottom" title="Skip navigation links"></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0" SUMMARY="">
+<TR>
+<TD COLSPAN=2 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3" SUMMARY="">
+ <TR ALIGN="center" VALIGN="top">
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="overview-summary.html"><FONT CLASS="NavBarFont1"><B>Overview</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <FONT CLASS="NavBarFont1">Use</FONT>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="index-files/index-1.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+ <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1"> <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+ </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+ <A HREF="index.html?serialized-form.html" target="_top"><B>FRAMES</B></A> &nbsp;
+&nbsp;<A HREF="serialized-form.html" target="_top"><B>NO FRAMES</B></A> &nbsp;
+&nbsp;<SCRIPT type="text/javascript">
+ <!--
+ if(window==top) {
+ document.writeln('<A HREF="allclasses-noframe.html"><B>All Classes</B></A>');
+ }
+ //-->
+</SCRIPT>
+<NOSCRIPT>
+ <A HREF="allclasses-noframe.html"><B>All Classes</B></A>
+</NOSCRIPT>
+
+
+</FONT></TD>
+</TR>
+</TABLE>
+<A NAME="skip-navbar_bottom"></A>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+
+<HR>
+<i>Copyright © 2006-2007 Adobe Systems Inc. All Rights Reserved.</i>
+</BODY>
+</HTML>
diff --git a/java/XMPCore/docs/stylesheet.css b/java/XMPCore/docs/stylesheet.css
new file mode 100644
index 0000000..6d31fdb
--- /dev/null
+++ b/java/XMPCore/docs/stylesheet.css
@@ -0,0 +1,29 @@
+/* Javadoc style sheet */
+
+/* Define colors, fonts and other style attributes here to override the defaults */
+
+/* Page background color */
+body { background-color: #FFFFFF }
+
+/* Headings */
+h1 { font-size: 145% }
+
+/* Table colors */
+.TableHeadingColor { background: #CCCCFF } /* Dark mauve */
+.TableSubHeadingColor { background: #EEEEFF } /* Light mauve */
+.TableRowColor { background: #FFFFFF } /* White */
+
+/* Font used in left-hand frame lists */
+.FrameTitleFont { font-size: 100%; font-family: Helvetica, Arial, sans-serif }
+.FrameHeadingFont { font-size: 90%; font-family: Helvetica, Arial, sans-serif }
+.FrameItemFont { font-size: 90%; font-family: Helvetica, Arial, sans-serif }
+
+/* Navigation bar fonts and colors */
+.NavBarCell1 { background-color:#EEEEFF;} /* Light mauve */
+.NavBarCell1Rev { background-color:#00008B;} /* Dark Blue */
+.NavBarFont1 { font-family: Arial, Helvetica, sans-serif; color:#000000;}
+.NavBarFont1Rev { font-family: Arial, Helvetica, sans-serif; color:#FFFFFF;}
+
+.NavBarCell2 { font-family: Arial, Helvetica, sans-serif; background-color:#FFFFFF;}
+.NavBarCell3 { font-family: Arial, Helvetica, sans-serif; background-color:#FFFFFF;}
+
diff --git a/java/XMPCore/src/com/adobe/xmp/XMPConst.java b/java/XMPCore/src/com/adobe/xmp/XMPConst.java
new file mode 100644
index 0000000..8180633
--- /dev/null
+++ b/java/XMPCore/src/com/adobe/xmp/XMPConst.java
@@ -0,0 +1,159 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+package com.adobe.xmp;
+
+
+/**
+ * Common constants for the XMP Toolkit.
+ *
+ * @since 20.01.2006
+ */
+public interface XMPConst
+{
+ // ---------------------------------------------------------------------------------------------
+ // Standard namespace URI constants
+
+
+ // Standard namespaces
+
+ /** The XML namespace for XML. */
+ String NS_XML = "http://www.w3.org/XML/1998/namespace";
+ /** The XML namespace for RDF. */
+ String NS_RDF = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+ /** The XML namespace for the Dublin Core schema. */
+ String NS_DC = "http://purl.org/dc/elements/1.1/";
+ /** The XML namespace for the IPTC Core schema. */
+ String NS_IPTCCORE = "http://iptc.org/std/Iptc4xmpCore/1.0/xmlns/";
+
+ // Adobe standard namespaces
+
+ /** The XML namespace Adobe XMP Metadata. */
+ String NS_X = "adobe:ns:meta/";
+ /** */
+ String NS_IX = "http://ns.adobe.com/iX/1.0/";
+ /** The XML namespace for the XMP "basic" schema. */
+ String NS_XMP = "http://ns.adobe.com/xap/1.0/";
+ /** The XML namespace for the XMP copyright schema. */
+ String NS_XMP_RIGHTS = "http://ns.adobe.com/xap/1.0/rights/";
+ /** The XML namespace for the XMP digital asset management schema. */
+ String NS_XMP_MM = "http://ns.adobe.com/xap/1.0/mm/";
+ /** The XML namespace for the job management schema. */
+ String NS_XMP_BJ = "http://ns.adobe.com/xap/1.0/bj/";
+ /** The XML namespace for the job management schema. */
+ String NS_XMP_NOTE = "http://ns.adobe.com/xmp/note/";
+
+ /** The XML namespace for the PDF schema. */
+ String NS_PDF = "http://ns.adobe.com/pdf/1.3/";
+ /** The XML namespace for the PDF schema. */
+ String NS_PDFX = "http://ns.adobe.com/pdfx/1.3/";
+ /** */
+ String NS_PDFX_ID = "http://www.npes.org/pdfx/ns/id/";
+ /** */
+ String NS_PDFA_SCHEMA = "http://www.aiim.org/pdfa/ns/schema#";
+ /** */
+ String NS_PDFA_PROPERTY = "http://www.aiim.org/pdfa/ns/property#";
+ /** */
+ String NS_PDFA_TYPE = "http://www.aiim.org/pdfa/ns/type#";
+ /** */
+ String NS_PDFA_FIELD = "http://www.aiim.org/pdfa/ns/field#";
+ /** */
+ String NS_PDFA_ID = "http://www.aiim.org/pdfa/ns/id/";
+ /** */
+ String NS_PDFA_EXTENSION = "http://www.aiim.org/pdfa/ns/extension/";
+ /** The XML namespace for the Photoshop custom schema. */
+ String NS_PHOTOSHOP = "http://ns.adobe.com/photoshop/1.0/";
+ /** The XML namespace for the Photoshop Album schema. */
+ String NS_PSALBUM = "http://ns.adobe.com/album/1.0/";
+ /** The XML namespace for Adobe's EXIF schema. */
+ String NS_EXIF = "http://ns.adobe.com/exif/1.0/";
+ /** */
+ String NS_EXIF_AUX = "http://ns.adobe.com/exif/1.0/aux/";
+ /** The XML namespace for Adobe's TIFF schema. */
+ String NS_TIFF = "http://ns.adobe.com/tiff/1.0/";
+ /** */
+ String NS_PNG = "http://ns.adobe.com/png/1.0/";
+ /** */
+ String NS_JPEG = "http://ns.adobe.com/jpeg/1.0/";
+ /** */
+ String NS_JP2K = "http://ns.adobe.com/jp2k/1.0/";
+ /** */
+ String NS_CAMERARAW = "http://ns.adobe.com/camera-raw-settings/1.0/";
+ /** */
+ String NS_ADOBESTOCKPHOTO = "http://ns.adobe.com/StockPhoto/1.0/";
+ /** */
+ String NS_ASF = "http://ns.adobe.com/asf/1.0/";
+ /** */
+ String NS_WAV = "http://ns.adobe.com/xmp/wav/1.0/";
+
+
+ // XMP namespaces that are Adobe private
+
+ /** */
+ String NS_DM = "http://ns.adobe.com/xmp/1.0/DynamicMedia/";
+ /** */
+ String NS_TRANSIENT = "http://ns.adobe.com/xmp/transient/1.0/";
+
+
+ // XML namespace constants for qualifiers and structured property fields.
+
+ /** The XML namespace for qualifiers of the xmp:Identifier property. */
+ String TYPE_IDENTIFIERQUAL = "http://ns.adobe.com/xmp/Identifier/qual/1.0/";
+ /** The XML namespace for fields of the Dimensions type. */
+ String TYPE_DIMENSIONS = "http://ns.adobe.com/xap/1.0/sType/Dimensions#";
+ /** */
+ String TYPE_TEXT = "http://ns.adobe.com/xap/1.0/t/";
+ /** */
+ String TYPE_PAGEDFILE = "http://ns.adobe.com/xap/1.0/t/pg/";
+ /** */
+ String TYPE_GRAPHICS = "http://ns.adobe.com/xap/1.0/g/";
+ /** The XML namespace for fields of a graphical image. Used for the Thumbnail type. */
+ String TYPE_IMAGE = "http://ns.adobe.com/xap/1.0/g/img/";
+ /** */
+ String TYPE_FONT = "http://ns.adobe.com/xap/1.0/sType/Font#";
+ /** The XML namespace for fields of the ResourceEvent type. */
+ String TYPE_RESOURCEEVENT = "http://ns.adobe.com/xap/1.0/sType/ResourceEvent#";
+ /** The XML namespace for fields of the ResourceRef type. */
+ String TYPE_RESOURCEREF = "http://ns.adobe.com/xap/1.0/sType/ResourceRef#";
+ /** The XML namespace for fields of the Version type. */
+ String TYPE_ST_VERSION = "http://ns.adobe.com/xap/1.0/sType/Version#";
+ /** The XML namespace for fields of the JobRef type. */
+ String TYPE_ST_JOB = "http://ns.adobe.com/xap/1.0/sType/Job#";
+ /** */
+ String TYPE_MANIFESTITEM = "http://ns.adobe.com/xap/1.0/sType/ManifestItem#";
+
+
+
+ // ---------------------------------------------------------------------------------------------
+ // Basic types and constants
+
+ /**
+ * The canonical true string value for Booleans in serialized XMP. Code that converts from the
+ * string to a bool should be case insensitive, and even allow "1".
+ */
+ String TRUESTR = "True";
+ /**
+ * The canonical false string value for Booleans in serialized XMP. Code that converts from the
+ * string to a bool should be case insensitive, and even allow "0".
+ */
+ String FALSESTR = "False";
+ /** Index that has the meaning to be always the last item in an array. */
+ int ARRAY_LAST_ITEM = -1;
+ /** Node name of an array item. */
+ String ARRAY_ITEM_NAME = "[]";
+ /** The x-default string for localized properties */
+ String X_DEFAULT = "x-default";
+ /** xml:lang qualfifier */
+ String XML_LANG = "xml:lang";
+ /** rdf:type qualfifier */
+ String RDF_TYPE = "rdf:type";
+
+ /** legaciy dublin core NS, will be converted to NS_DC */
+ String NS_DC_DEPRECATED = "http://purl.org/dc/1.1/";
+} \ No newline at end of file
diff --git a/java/XMPCore/src/com/adobe/xmp/XMPDateTime.java b/java/XMPCore/src/com/adobe/xmp/XMPDateTime.java
new file mode 100644
index 0000000..ae3a0fc
--- /dev/null
+++ b/java/XMPCore/src/com/adobe/xmp/XMPDateTime.java
@@ -0,0 +1,98 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+package com.adobe.xmp;
+
+import java.util.Calendar;
+import java.util.TimeZone;
+
+
+/**
+ * The <code>XMPDateTime</code>-class represents a point in time up to a resolution of nano
+ * seconds. Dates and time in the serialized XMP are ISO 8601 strings. There are utility functions
+ * to convert to the ISO format, a <code>Calendar</code> or get the Timezone. The fields of
+ * <code>XMPDateTime</code> are:
+ * <ul>
+ * <li> month - The month in the range 1..12.
+ * <li> day - The day of the month in the range 1..31.
+ * <li> minute - The minute in the range 0..59.
+ * <li> hour - The time zone hour in the range 0..23.
+ * <li> minute - The time zone minute in the range 0..59.
+ * <li> nanoSecond - The nano seconds within a second. <em>Note:</em> if the XMPDateTime is
+ * converted into a calendar, the resolution is reduced to milli seconds.
+ * <li> timeZone - a <code>TimeZone</code>-object.
+ * </ul>
+ * DateTime values are occasionally used in cases with only a date or only a time component. A date
+ * without a time has zeros for all the time fields. A time without a date has zeros for all date
+ * fields (year, month, and day).
+ */
+public interface XMPDateTime extends Comparable
+{
+ /** @return Returns the year, can be negative. */
+ int getYear();
+
+ /** @param year Sets the year */
+ void setYear(int year);
+
+ /** @return Returns The month in the range 1..12. */
+ int getMonth();
+
+ /** @param month Sets the month 1..12 */
+ void setMonth(int month);
+
+ /** @return Returns the day of the month in the range 1..31. */
+ int getDay();
+
+ /** @param day Sets the day 1..31 */
+ void setDay(int day);
+
+ /** @return Returns hour - The hour in the range 0..23. */
+ int getHour();
+
+ /** @param hour Sets the hour in the range 0..23. */
+ void setHour(int hour);
+
+ /** @return Returns the minute in the range 0..59. */
+ int getMinute();
+
+ /** @param minute Sets the minute in the range 0..59. */
+ void setMinute(int minute);
+
+ /** @return Returns the second in the range 0..59. */
+ int getSecond();
+
+ /** @param second Sets the second in the range 0..59. */
+ void setSecond(int second);
+
+ /**
+ * @return Returns milli-, micro- and nano seconds.
+ * Nanoseconds within a second, often left as zero?
+ */
+ int getNanoSecond();
+
+ /**
+ * @param nanoSecond Sets the milli-, micro- and nano seconds.
+ * Granularity goes down to milli seconds.
+ */
+ void setNanoSecond(int nanoSecond);
+
+ /** @return Returns the time zone. */
+ TimeZone getTimeZone();
+
+ /** @param tz a time zone to set */
+ void setTimeZone(TimeZone tz);
+
+ /** @return Returns a calendar (only with milli second precision). */
+ Calendar getCalendar();
+
+ /**
+ * @return Returns the ISO 8601 string representation of the date and time.
+ */
+ String getISO8601String();
+} \ No newline at end of file
diff --git a/java/XMPCore/src/com/adobe/xmp/XMPDateTimeFactory.java b/java/XMPCore/src/com/adobe/xmp/XMPDateTimeFactory.java
new file mode 100644
index 0000000..05b6f0f
--- /dev/null
+++ b/java/XMPCore/src/com/adobe/xmp/XMPDateTimeFactory.java
@@ -0,0 +1,142 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+package com.adobe.xmp;
+
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.TimeZone;
+
+import com.adobe.xmp.impl.XMPDateTimeImpl;
+
+
+/**
+ * A factory to create <code>XMPDateTime</code>-instances from a <code>Calendar</code> or an
+ * ISO 8601 string or for the current time.
+ *
+ * @since 16.02.2006
+ */
+public final class XMPDateTimeFactory
+{
+ /** Private constructor */
+ private XMPDateTimeFactory()
+ {
+ // EMPTY
+ }
+
+
+ /**
+ * Creates an <code>XMPDateTime</code> from a <code>Calendar</code>-object.
+ *
+ * @param calendar a <code>Calendar</code>-object.
+ * @return An <code>XMPDateTime</code>-object.
+ */
+ public static XMPDateTime createFromCalendar(Calendar calendar)
+ {
+ return new XMPDateTimeImpl(calendar);
+ }
+
+
+ /**
+ * Creates an <code>XMPDateTime</code>-object from initial values.
+ * @param year years
+ * @param month months
+ * @param day days
+ * @param hour hours
+ * @param minute minutes
+ * @param second seconds
+ * @param nanoSecond nanoseconds
+ * @return Returns an <code>XMPDateTime</code>-object.
+ */
+ public static XMPDateTime create(int year, int month, int day,
+ int hour, int minute, int second, int nanoSecond)
+ {
+ XMPDateTime dt = new XMPDateTimeImpl();
+ dt.setYear(year);
+ dt.setMonth(month);
+ dt.setDay(day);
+ dt.setHour(hour);
+ dt.setMinute(minute);
+ dt.setSecond(second);
+ dt.setNanoSecond(nanoSecond);
+ return dt;
+ }
+
+
+ /**
+ * Creates an <code>XMPDateTime</code> from an ISO 8601 string.
+ *
+ * @param strValue The ISO 8601 string representation of the date/time.
+ * @return An <code>XMPDateTime</code>-object.
+ * @throws XMPException When the ISO 8601 string is non-conform
+ */
+ public static XMPDateTime createFromISO8601(String strValue) throws XMPException
+ {
+ return new XMPDateTimeImpl(strValue);
+ }
+
+
+ /**
+ * Obtain the current date and time.
+ *
+ * @return Returns The returned time is UTC, properly adjusted for the local time zone. The
+ * resolution of the time is not guaranteed to be finer than seconds.
+ */
+ public static XMPDateTime getCurrentDateTime()
+ {
+ return new XMPDateTimeImpl(new GregorianCalendar());
+ }
+
+
+ /**
+ * Sets the local time zone without touching any other Any existing time zone value is replaced,
+ * the other date/time fields are not adjusted in any way.
+ *
+ * @param dateTime the <code>XMPDateTime</code> variable containing the value to be modified.
+ * @return Returns an updated <code>XMPDateTime</code>-object.
+ */
+ public static XMPDateTime setLocalTimeZone(XMPDateTime dateTime)
+ {
+ Calendar cal = dateTime.getCalendar();
+ cal.setTimeZone(TimeZone.getDefault());
+ return new XMPDateTimeImpl(cal);
+ }
+
+
+ /**
+ * Make sure a time is UTC. If the time zone is not UTC, the time is
+ * adjusted and the time zone set to be UTC.
+ *
+ * @param dateTime
+ * the <code>XMPDateTime</code> variable containing the time to
+ * be modified.
+ * @return Returns an updated <code>XMPDateTime</code>-object.
+ */
+ public static XMPDateTime convertToUTCTime(XMPDateTime dateTime)
+ {
+ Calendar cal = dateTime.getCalendar();
+ cal.setTimeZone(TimeZone.getTimeZone("UTC"));
+ return new XMPDateTimeImpl(cal);
+ }
+
+
+ /**
+ * Make sure a time is local. If the time zone is not the local zone, the time is adjusted and
+ * the time zone set to be local.
+ *
+ * @param dateTime the <code>XMPDateTime</code> variable containing the time to be modified.
+ * @return Returns an updated <code>XMPDateTime</code>-object.
+ */
+ public static XMPDateTime convertToLocalTime(XMPDateTime dateTime)
+ {
+ Calendar cal = dateTime.getCalendar();
+ cal.setTimeZone(TimeZone.getDefault());
+ return new XMPDateTimeImpl(cal);
+ }
+} \ No newline at end of file
diff --git a/java/XMPCore/src/com/adobe/xmp/XMPError.java b/java/XMPCore/src/com/adobe/xmp/XMPError.java
new file mode 100644
index 0000000..ebf040d
--- /dev/null
+++ b/java/XMPCore/src/com/adobe/xmp/XMPError.java
@@ -0,0 +1,44 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+package com.adobe.xmp;
+
+
+/**
+ * @since 21.09.2006
+ */
+public interface XMPError
+{
+ /** */
+ int UNKNOWN = 0;
+ /** */
+ int BADPARAM = 4;
+ /** */
+ int BADVALUE = 5;
+ /** */
+ int INTERNALFAILURE = 9;
+ /** */
+ int BADSCHEMA = 101;
+ /** */
+ int BADXPATH = 102;
+ /** */
+ int BADOPTIONS = 103;
+ /** */
+ int BADINDEX = 104;
+ /** */
+ int BADSERIALIZE = 107;
+ /** */
+ int BADXML = 201;
+ /** */
+ int BADRDF = 202;
+ /** */
+ int BADXMP = 203;
+ /** <em>Note:</em> This is an error code introduced by Java. */
+ int BADSTREAM = 204;
+}
diff --git a/java/XMPCore/src/com/adobe/xmp/XMPException.java b/java/XMPCore/src/com/adobe/xmp/XMPException.java
new file mode 100644
index 0000000..0210143
--- /dev/null
+++ b/java/XMPCore/src/com/adobe/xmp/XMPException.java
@@ -0,0 +1,55 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+package com.adobe.xmp;
+
+/**
+ * This exception wraps all errors that occur in the XMP Toolkit.
+ *
+ * @since 16.02.2006
+ */
+public class XMPException extends Exception
+{
+ /** the errorCode of the XMP toolkit */
+ private int errorCode;
+
+
+ /**
+ * Constructs an exception with a message and an error code.
+ * @param message the message
+ * @param errorCode the error code
+ */
+ public XMPException(String message, int errorCode)
+ {
+ super(message);
+ this.errorCode = errorCode;
+ }
+
+
+ /**
+ * Constructs an exception with a message, an error code and a <code>Throwable</code>
+ * @param message the error message.
+ * @param errorCode the error code
+ * @param t the exception source
+ */
+ public XMPException(String message, int errorCode, Throwable t)
+ {
+ super(message, t);
+ this.errorCode = errorCode;
+ }
+
+
+ /**
+ * @return Returns the errorCode.
+ */
+ public int getErrorCode()
+ {
+ return errorCode;
+ }
+} \ No newline at end of file
diff --git a/java/XMPCore/src/com/adobe/xmp/XMPIterator.java b/java/XMPCore/src/com/adobe/xmp/XMPIterator.java
new file mode 100644
index 0000000..b70e0a5
--- /dev/null
+++ b/java/XMPCore/src/com/adobe/xmp/XMPIterator.java
@@ -0,0 +1,82 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+package com.adobe.xmp;
+
+import java.util.Iterator;
+
+
+/**
+ * Interface for the <code>XMPMeta</code> iteration services.
+ * <code>XMPIterator</code> provides a uniform means to iterate over the
+ * schema and properties within an XMP object.
+ * <p>
+ * The iteration over the schema and properties within an XMP object is very
+ * complex. It is helpful to have a thorough understanding of the XMP data tree.
+ * One way to learn this is to create some complex XMP and examine the output of
+ * <code>XMPMeta#toString</code>. This is also described in the XMP
+ * Specification, in the XMP Data Model chapter.
+ * <p>
+ * The top of the XMP data tree is a single root node. This does not explicitly
+ * appear in the dump and is never visited by an iterator (that is, it is never
+ * returned from <code>XMPIterator#next()</code>). Beneath the root are
+ * schema nodes. These are just collectors for top level properties in the same
+ * namespace. They are created and destroyed implicitly. Beneath the schema
+ * nodes are the property nodes. The nodes below a property node depend on its
+ * type (simple, struct, or array) and whether it has qualifiers.
+ * <p>
+ * An <code>XMPIterator</code> is created by XMPMeta#interator() constructor
+ * defines a starting point for the iteration and options that control how it
+ * proceeds. By default the iteration starts at the root and visits all nodes
+ * beneath it in a depth first manner. The root node is not visited, the first
+ * visited node is a schema node. You can provide a schema name or property path
+ * to select a different starting node. By default this visits the named root
+ * node first then all nodes beneath it in a depth first manner.
+ * <p>
+ * The <code>XMPIterator#next()</code> method delivers the schema URI, path,
+ * and option flags for the node being visited. If the node is simple it also
+ * delivers the value. Qualifiers for this node are visited next. The fields of
+ * a struct or items of an array are visited after the qualifiers of the parent.
+ * <p>
+ * The options to control the iteration are:
+ * <ul>
+ * <li>JUST_CHILDREN - Visit just the immediate children of the root. Skip
+ * the root itself and all nodes below the immediate children. This omits the
+ * qualifiers of the immediate children, the qualifier nodes being below what
+ * they qualify, default is to visit the complete subtree.
+ * <li>UST_LEAFNODES - Visit just the leaf property nodes and their
+ * qualifiers.
+ * <li>JUST_LEAFNAME - Return just the leaf component of the node names.
+ * The default is to return the full xmp path.
+ * <li>OMIT_QUALIFIERS - Do not visit the qualifiers.
+ * <li>INCLUDE_ALIASES - Adds known alias properties to the properties in the iteration.
+ * <em>Note:</em> Not supported in Java XMPCore!
+ * </ul>
+ * <p>
+ * <code>next()</code> returns <code>XMPPropertyInfo</code>-objects and throws
+ * a <code>NoSuchElementException</code> if there are no more properties to
+ * return.
+ *
+ * @since 25.01.2006
+ */
+public interface XMPIterator extends Iterator
+{
+ /**
+ * Skip the subtree below the current node when <code>next()</code> is
+ * called.
+ */
+ void skipSubtree();
+
+
+ /**
+ * Skip the subtree below and remaining siblings of the current node when
+ * <code>next()</code> is called.
+ */
+ void skipSiblings();
+} \ No newline at end of file
diff --git a/java/XMPCore/src/com/adobe/xmp/XMPMeta.java b/java/XMPCore/src/com/adobe/xmp/XMPMeta.java
new file mode 100644
index 0000000..085915f
--- /dev/null
+++ b/java/XMPCore/src/com/adobe/xmp/XMPMeta.java
@@ -0,0 +1,1152 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+package com.adobe.xmp;
+
+import java.util.Calendar;
+
+import com.adobe.xmp.options.IteratorOptions;
+import com.adobe.xmp.options.PropertyOptions;
+import com.adobe.xmp.properties.XMPProperty;
+
+
+/**
+ * This class represents the set of XMP metadata as a DOM representation. It has methods to read and
+ * modify all kinds of properties, create an iterator over all properties and serialize the metadata
+ * to a String, byte-array or <code>OutputStream</code>.
+ *
+ * @since 20.01.2006
+ */
+public interface XMPMeta extends Cloneable
+{
+ // ---------------------------------------------------------------------------------------------
+ // Basic property manipulation functions
+
+ /**
+ * The property value getter-methods all take a property specification: the first two parameters
+ * are always the top level namespace URI (the &quot;schema&quot; namespace) and the basic name
+ * of the property being referenced. See the introductory discussion of path expression usage
+ * for more information.
+ * <p>
+ * All of the functions return an object inherited from <code>PropertyBase</code> or
+ * <code>null</code> if the property does not exists. The result object contains the value of
+ * the property and option flags describing the property. Arrays and the non-leaf levels of
+ * nodes do not have values.
+ * <p>
+ * See {@link PropertyOptions} for detailed information about the options.
+ * <p>
+ * This is the simplest property getter, mainly for top level simple properties or after using
+ * the path composition functions in XMPPathFactory.
+ *
+ * @param schemaNS The namespace URI for the property. May be <code>null</code> or the empty
+ * string if the first component of the propName path contains a namespace prefix. The
+ * URI must be for a registered namespace.
+ * @param propName The name of the property. May be a general path expression, must not be
+ * <code>null</code> or the empty string. Using a namespace prefix on the first
+ * component is optional. If present without a schemaNS value then the prefix specifies
+ * the namespace. The prefix must be for a registered namespace. If both a schemaNS URI
+ * and propName prefix are present, they must be corresponding parts of a registered
+ * namespace.
+ * @return Returns a <code>XMPProperty</code> containing the value and the options or
+ * <code>null</code> if the property does not exist.
+ * @throws XMPException Wraps all errors and exceptions that may occur.
+ */
+ XMPProperty getProperty(String schemaNS, String propName) throws XMPException;
+
+
+ /**
+ * Provides access to items within an array. The index is passed as an integer, you need not
+ * worry about the path string syntax for array items, convert a loop index to a string, etc.
+ *
+ * @param schemaNS The namespace URI for the array. Has the same usage as in getProperty.
+ * @param arrayName The name of the array. May be a general path expression, must not be
+ * <code>null</code> or the empty string. Has the same namespace prefix usage as
+ * propName in <code>getProperty()</code>.
+ * @param itemIndex The index of the desired item. Arrays in XMP are indexed from 1. The
+ * constant {@link XMPConst#ARRAY_LAST_ITEM} always refers to the last existing array
+ * item.
+ * @return Returns a <code>XMPProperty</code> containing the value and the options or
+ * <code>null</code> if the property does not exist.
+ * @throws XMPException Wraps all errors and exceptions that may occur.
+ */
+ XMPProperty getArrayItem(String schemaNS, String arrayName, int itemIndex) throws XMPException;
+
+
+ /**
+ * Returns the number of items in the array.
+ *
+ * @param schemaNS The namespace URI for the array. Has the same usage as in getProperty.
+ * @param arrayName The name of the array. May be a general path expression, must not be
+ * <code>null</code> or the empty string. Has the same namespace prefix usage as
+ * propName in <code>getProperty()</code>.
+ * @return Returns the number of items in the array.
+ * @throws XMPException Wraps all errors and exceptions that may occur.
+ */
+ int countArrayItems(String schemaNS, String arrayName) throws XMPException;
+
+
+ /**
+ * Provides access to fields within a nested structure. The namespace for the field is passed as
+ * a URI, you need not worry about the path string syntax.
+ * <p>
+ * The names of fields should be XML qualified names, that is within an XML namespace. The path
+ * syntax for a qualified name uses the namespace prefix. This is unreliable since the prefix is
+ * never guaranteed. The URI is the formal name, the prefix is just a local shorthand in a given
+ * sequence of XML text.
+ *
+ * @param schemaNS The namespace URI for the struct. Has the same usage as in getProperty.
+ * @param structName The name of the struct. May be a general path expression, must not be
+ * <code>null</code> or the empty string. Has the same namespace prefix usage as
+ * propName in <code>getProperty()</code>.
+ * @param fieldNS The namespace URI for the field. Has the same URI and prefix usage as the
+ * schemaNS parameter.
+ * @param fieldName The name of the field. Must be a single XML name, must not be
+ * <code>null</code> or the empty string. Has the same namespace prefix usage as the
+ * structName parameter.
+ * @return Returns a <code>XMPProperty</code> containing the value and the options or
+ * <code>null</code> if the property does not exist. Arrays and non-leaf levels of
+ * structs do not have values.
+ * @throws XMPException Wraps all errors and exceptions that may occur.
+ */
+ XMPProperty getStructField(
+ String schemaNS,
+ String structName,
+ String fieldNS,
+ String fieldName) throws XMPException;
+
+
+ /**
+ * Provides access to a qualifier attached to a property. The namespace for the qualifier is
+ * passed as a URI, you need not worry about the path string syntax. In many regards qualifiers
+ * are like struct fields. See the introductory discussion of qualified properties for more
+ * information.
+ * <p>
+ * The names of qualifiers should be XML qualified names, that is within an XML namespace. The
+ * path syntax for a qualified name uses the namespace prefix. This is unreliable since the
+ * prefix is never guaranteed. The URI is the formal name, the prefix is just a local shorthand
+ * in a given sequence of XML text.
+ * <p>
+ * <em>Note:</em> Qualifiers are only supported for simple leaf properties at this time.
+ *
+ * @param schemaNS The namespace URI for the struct. Has the same usage as in getProperty.
+ * @param propName The name of the property to which the qualifier is attached. May be a general
+ * path expression, must not be <code>null</code> or the empty string. Has the same
+ * namespace prefix usage as in <code>getProperty()</code>.
+ * @param qualNS The namespace URI for the qualifier. Has the same URI and prefix usage as the
+ * schemaNS parameter.
+ * @param qualName The name of the qualifier. Must be a single XML name, must not be
+ * <code>null</code> or the empty string. Has the same namespace prefix usage as the
+ * propName parameter.
+ * @return Returns a <code>XMPProperty</code> containing the value and the options of the
+ * qualifier or <code>null</code> if the property does not exist. The name of the
+ * qualifier must be a single XML name, must not be <code>null</code> or the empty
+ * string. Has the same namespace prefix usage as the propName parameter.
+ * <p>
+ * The value of the qualifier is only set if it has one (Arrays and non-leaf levels of
+ * structs do not have values).
+ * @throws XMPException Wraps all errors and exceptions that may occur.
+ */
+ XMPProperty getQualifier(
+ String schemaNS,
+ String propName,
+ String qualNS,
+ String qualName) throws XMPException;
+
+
+
+ // ---------------------------------------------------------------------------------------------
+ // Functions for setting property values
+
+ /**
+ * The property value <code>setters</code> all take a property specification, their
+ * differences are in the form of this. The first two parameters are always the top level
+ * namespace URI (the <code>schema</code> namespace) and the basic name of the property being
+ * referenced. See the introductory discussion of path expression usage for more information.
+ * <p>
+ * All of the functions take a string value for the property and option flags describing the
+ * property. The value must be Unicode in UTF-8 encoding. Arrays and non-leaf levels of structs
+ * do not have values. Empty arrays and structs may be created using appropriate option flags.
+ * All levels of structs that is assigned implicitly are created if necessary. appendArayItem
+ * implicitly creates the named array if necessary.
+ * <p>
+ * See {@link PropertyOptions} for detailed information about the options.
+ * <p>
+ * This is the simplest property setter, mainly for top level simple properties or after using
+ * the path composition functions in {@link XMPPathFactory}.
+ *
+ * @param schemaNS The namespace URI for the property. Has the same usage as in getProperty.
+ * @param propName The name of the property.
+ * Has the same usage as in <code>getProperty()</code>.
+ * @param propValue the value for the property (only leaf properties have a value).
+ * Arrays and non-leaf levels of structs do not have values.
+ * Must be <code>null</code> if the value is not relevant.<br/>
+ * The value is automatically detected: Boolean, Integer, Long, Double, XMPDateTime and
+ * byte[] are handled, on all other <code>toString()</code> is called.
+ *
+ * @param options Option flags describing the property. See the earlier description.
+ * @throws XMPException Wraps all errors and exceptions that may occur.
+ */
+ void setProperty(
+ String schemaNS,
+ String propName,
+ Object propValue,
+ PropertyOptions options) throws XMPException;
+
+
+ /**
+ * @see XMPMeta#setProperty(String, String, Object, PropertyOptions)
+ *
+ * @param schemaNS The namespace URI
+ * @param propName The name of the property
+ * @param propValue the value for the property
+ * @throws XMPException Wraps all errors and exceptions
+ */
+ void setProperty(
+ String schemaNS,
+ String propName,
+ Object propValue) throws XMPException;
+
+
+ /**
+ * Replaces an item within an array. The index is passed as an integer, you need not worry about
+ * the path string syntax for array items, convert a loop index to a string, etc. The array
+ * passed must already exist. In normal usage the selected array item is modified. A new item is
+ * automatically appended if the index is the array size plus 1.
+ *
+ * @param schemaNS The namespace URI for the array. Has the same usage as in getProperty.
+ * @param arrayName The name of the array. May be a general path expression, must not be
+ * <code>null</code> or the empty string. Has the same namespace prefix usage as
+ * propName in getProperty.
+ * @param itemIndex The index of the desired item. Arrays in XMP are indexed from 1. To address
+ * the last existing item, use {@link XMPMeta#countArrayItems(String, String)} to find
+ * out the length of the array.
+ * @param itemValue the new value of the array item. Has the same usage as propValue in
+ * <code>setProperty()</code>.
+ * @param options the set options for the item.
+ * @throws XMPException Wraps all errors and exceptions that may occur.
+ */
+ void setArrayItem(
+ String schemaNS,
+ String arrayName,
+ int itemIndex,
+ String itemValue,
+ PropertyOptions options) throws XMPException;
+
+
+ /**
+ * @see XMPMeta#setArrayItem(String, String, int, String, PropertyOptions)
+ *
+ * @param schemaNS The namespace URI
+ * @param arrayName The name of the array
+ * @param itemIndex The index to insert the new item
+ * @param itemValue the new value of the array item
+ * @throws XMPException Wraps all errors and exceptions
+ */
+ void setArrayItem(
+ String schemaNS,
+ String arrayName,
+ int itemIndex,
+ String itemValue) throws XMPException;
+
+
+ /**
+ * Inserts an item into an array previous to the given index. The index is passed as an integer,
+ * you need not worry about the path string syntax for array items, convert a loop index to a
+ * string, etc. The array passed must already exist. In normal usage the selected array item is
+ * modified. A new item is automatically appended if the index is the array size plus 1.
+ *
+ * @param schemaNS The namespace URI for the array. Has the same usage as in getProperty.
+ * @param arrayName The name of the array. May be a general path expression, must not be
+ * <code>null</code> or the empty string. Has the same namespace prefix usage as
+ * propName in getProperty.
+ * @param itemIndex The index to insert the new item. Arrays in XMP are indexed from 1. Use
+ * <code>XMPConst.ARRAY_LAST_ITEM</code> to append items.
+ * @param itemValue the new value of the array item. Has the same usage as
+ * propValue in <code>setProperty()</code>.
+ * @param options the set options that decide about the kind of the node.
+ * @throws XMPException Wraps all errors and exceptions that may occur.
+ */
+ void insertArrayItem(
+ String schemaNS,
+ String arrayName,
+ int itemIndex,
+ String itemValue,
+ PropertyOptions options) throws XMPException;
+
+
+ /**
+ * @see XMPMeta#insertArrayItem(String, String, int, String, PropertyOptions)
+ *
+ * @param schemaNS The namespace URI for the array
+ * @param arrayName The name of the array
+ * @param itemIndex The index to insert the new item
+ * @param itemValue the value of the array item
+ * @throws XMPException Wraps all errors and exceptions
+ */
+ void insertArrayItem(
+ String schemaNS,
+ String arrayName,
+ int itemIndex,
+ String itemValue) throws XMPException;
+
+
+ /**
+ * Simplifies the construction of an array by not requiring that you pre-create an empty array.
+ * The array that is assigned is created automatically if it does not yet exist. Each call to
+ * appendArrayItem() appends an item to the array. The corresponding parameters have the same
+ * use as setArrayItem(). The arrayOptions parameter is used to specify what kind of array. If
+ * the array exists, it must have the specified form.
+ *
+ * @param schemaNS The namespace URI for the array. Has the same usage as in getProperty.
+ * @param arrayName The name of the array. May be a general path expression, must not be null or
+ * the empty string. Has the same namespace prefix usage as propPath in getProperty.
+ * @param arrayOptions Option flags describing the array form. The only valid options are
+ * <ul>
+ * <li> {@link PropertyOptions#ARRAY},
+ * <li> {@link PropertyOptions#ARRAY_ORDERED},
+ * <li> {@link PropertyOptions#ARRAY_ALTERNATE} or
+ * <li> {@link PropertyOptions#ARRAY_ALT_TEXT}.
+ * </ul>
+ * <em>Note:</em> the array options only need to be provided if the array is not
+ * already existing, otherwise you can set them to <code>null</code> or use
+ * {@link XMPMeta#appendArrayItem(String, String, String)}.
+ * @param itemValue the value of the array item. Has the same usage as propValue in getProperty.
+ * @param itemOptions Option flags describing the item to append ({@link PropertyOptions})
+ * @throws XMPException Wraps all errors and exceptions that may occur.
+ */
+ void appendArrayItem(
+ String schemaNS,
+ String arrayName,
+ PropertyOptions arrayOptions,
+ String itemValue,
+ PropertyOptions itemOptions) throws XMPException;
+
+
+ /**
+ * @see XMPMeta#appendArrayItem(String, String, PropertyOptions, String, PropertyOptions)
+ *
+ * @param schemaNS The namespace URI for the array
+ * @param arrayName The name of the array
+ * @param itemValue the value of the array item
+ * @throws XMPException Wraps all errors and exceptions
+ */
+ void appendArrayItem(
+ String schemaNS,
+ String arrayName,
+ String itemValue) throws XMPException;
+
+
+ /**
+ * Provides access to fields within a nested structure. The namespace for the field is passed as
+ * a URI, you need not worry about the path string syntax. The names of fields should be XML
+ * qualified names, that is within an XML namespace. The path syntax for a qualified name uses
+ * the namespace prefix, which is unreliable because the prefix is never guaranteed. The URI is
+ * the formal name, the prefix is just a local shorthand in a given sequence of XML text.
+ *
+ * @param schemaNS The namespace URI for the struct. Has the same usage as in getProperty.
+ * @param structName The name of the struct. May be a general path expression, must not be null
+ * or the empty string. Has the same namespace prefix usage as propName in getProperty.
+ * @param fieldNS The namespace URI for the field. Has the same URI and prefix usage as the
+ * schemaNS parameter.
+ * @param fieldName The name of the field. Must be a single XML name, must not be null or the
+ * empty string. Has the same namespace prefix usage as the structName parameter.
+ * @param fieldValue the value of thefield, if the field has a value.
+ * Has the same usage as propValue in getProperty.
+ * @param options Option flags describing the field. See the earlier description.
+ * @throws XMPException Wraps all errors and exceptions that may occur.
+ */
+ void setStructField(
+ String schemaNS,
+ String structName,
+ String fieldNS,
+ String fieldName,
+ String fieldValue,
+ PropertyOptions options) throws XMPException;
+
+
+ /**
+ * @see XMPMeta#setStructField(String, String, String, String, String, PropertyOptions)
+ *
+ * @param schemaNS The namespace URI for the struct
+ * @param structName The name of the struct
+ * @param fieldNS The namespace URI for the field
+ * @param fieldName The name of the field
+ * @param fieldValue the value of the field
+ * @throws XMPException Wraps all errors and exceptions
+ */
+ void setStructField(
+ String schemaNS,
+ String structName,
+ String fieldNS,
+ String fieldName,
+ String fieldValue) throws XMPException;
+
+
+ /**
+ * Provides access to a qualifier attached to a property. The namespace for the qualifier is
+ * passed as a URI, you need not worry about the path string syntax. In many regards qualifiers
+ * are like struct fields. See the introductory discussion of qualified properties for more
+ * information. The names of qualifiers should be XML qualified names, that is within an XML
+ * namespace. The path syntax for a qualified name uses the namespace prefix, which is
+ * unreliable because the prefix is never guaranteed. The URI is the formal name, the prefix is
+ * just a local shorthand in a given sequence of XML text. The property the qualifier
+ * will be attached has to exist.
+ *
+ * @param schemaNS The namespace URI for the struct. Has the same usage as in getProperty.
+ * @param propName The name of the property to which the qualifier is attached. Has the same
+ * usage as in getProperty.
+ * @param qualNS The namespace URI for the qualifier. Has the same URI and prefix usage as the
+ * schemaNS parameter.
+ * @param qualName The name of the qualifier. Must be a single XML name, must not be
+ * <code>null</code> or the empty string. Has the same namespace prefix usage as the
+ * propName parameter.
+ * @param qualValue A pointer to the <code>null</code> terminated UTF-8 string that is the
+ * value of the qualifier, if the qualifier has a value. Has the same usage as propValue
+ * in getProperty.
+ * @param options Option flags describing the qualifier. See the earlier description.
+ * @throws XMPException Wraps all errors and exceptions that may occur.
+ */
+ void setQualifier(
+ String schemaNS,
+ String propName,
+ String qualNS,
+ String qualName,
+ String qualValue,
+ PropertyOptions options) throws XMPException;
+
+
+ /**
+ * @see XMPMeta#setQualifier(String, String, String, String, String, PropertyOptions)
+ *
+ * @param schemaNS The namespace URI for the struct
+ * @param propName The name of the property to which the qualifier is attached
+ * @param qualNS The namespace URI for the qualifier
+ * @param qualName The name of the qualifier
+ * @param qualValue the value of the qualifier
+ * @throws XMPException Wraps all errors and exceptions
+ */
+ void setQualifier(
+ String schemaNS,
+ String propName,
+ String qualNS,
+ String qualName,
+ String qualValue) throws XMPException;
+
+
+
+ // ---------------------------------------------------------------------------------------------
+ // Functions for deleting and detecting properties. These should be obvious from the
+ // descriptions of the getters and setters.
+
+ /**
+ * Deletes the given XMP subtree rooted at the given property. It is not an error if the
+ * property does not exist.
+ *
+ * @param schemaNS The namespace URI for the property. Has the same usage as in
+ * <code>getProperty()</code>.
+ * @param propName The name of the property. Has the same usage as in getProperty.
+ */
+ void deleteProperty(String schemaNS, String propName);
+
+
+ /**
+ * Deletes the given XMP subtree rooted at the given array item. It is not an error if the array
+ * item does not exist.
+ *
+ * @param schemaNS The namespace URI for the array. Has the same usage as in getProperty.
+ * @param arrayName The name of the array. May be a general path expression, must not be
+ * <code>null</code> or the empty string. Has the same namespace prefix usage as
+ * propName in <code>getProperty()</code>.
+ * @param itemIndex The index of the desired item. Arrays in XMP are indexed from 1. The
+ * constant <code>XMPConst.ARRAY_LAST_ITEM</code> always refers to the last
+ * existing array item.
+ */
+ void deleteArrayItem(String schemaNS, String arrayName, int itemIndex);
+
+
+ /**
+ * Deletes the given XMP subtree rooted at the given struct field. It is not an error if the
+ * field does not exist.
+ *
+ * @param schemaNS The namespace URI for the struct. Has the same usage as in
+ * <code>getProperty()</code>.
+ * @param structName The name of the struct. May be a general path expression, must not be
+ * <code>null</code> or the empty string. Has the same namespace prefix usage as
+ * propName in getProperty.
+ * @param fieldNS The namespace URI for the field. Has the same URI and prefix usage as the
+ * schemaNS parameter.
+ * @param fieldName The name of the field. Must be a single XML name, must not be
+ * <code>null</code> or the empty string. Has the same namespace prefix usage as the
+ * structName parameter.
+ */
+ void deleteStructField(String schemaNS, String structName, String fieldNS, String fieldName);
+
+
+ /**
+ * Deletes the given XMP subtree rooted at the given qualifier. It is not an error if the
+ * qualifier does not exist.
+ *
+ * @param schemaNS The namespace URI for the struct. Has the same usage as in
+ * <code>getProperty()</code>.
+ * @param propName The name of the property to which the qualifier is attached. Has the same
+ * usage as in getProperty.
+ * @param qualNS The namespace URI for the qualifier. Has the same URI and prefix usage as the
+ * schemaNS parameter.
+ * @param qualName The name of the qualifier. Must be a single XML name, must not be
+ * <code>null</code> or the empty string. Has the same namespace prefix usage as the
+ * propName parameter.
+ */
+ void deleteQualifier(String schemaNS, String propName, String qualNS, String qualName);
+
+
+ /**
+ * Returns whether the property exists.
+ *
+ * @param schemaNS The namespace URI for the property. Has the same usage as in
+ * <code>getProperty()</code>.
+ * @param propName The name of the property.
+ * Has the same usage as in <code>getProperty()</code>.
+ * @return Returns true if the property exists.
+ */
+ boolean doesPropertyExist(String schemaNS, String propName);
+
+
+ /**
+ * Tells if the array item exists.
+ *
+ * @param schemaNS The namespace URI for the array. Has the same usage as in
+ * <code>getProperty()</code>.
+ * @param arrayName The name of the array. May be a general path expression, must not be
+ * <code>null</code> or the empty string. Has the same namespace prefix usage as
+ * propName in <code>getProperty()</code>.
+ * @param itemIndex The index of the desired item. Arrays in XMP are indexed from 1. The
+ * constant <code>XMPConst.ARRAY_LAST_ITEM</code> always refers to the last
+ * existing array item.
+ * @return Returns <code>true</code> if the array exists, <code>false</code> otherwise.
+ */
+ boolean doesArrayItemExist(String schemaNS, String arrayName, int itemIndex);
+
+
+ /**
+ * DoesStructFieldExist tells if the struct field exists.
+ *
+ * @param schemaNS The namespace URI for the struct. Has the same usage as in
+ * <code>getProperty()</code>.
+ * @param structName The name of the struct. May be a general path expression, must not be
+ * <code>null</code> or the empty string. Has the same namespace prefix usage as
+ * propName in <code>getProperty()</code>.
+ * @param fieldNS The namespace URI for the field. Has the same URI and prefix usage as the
+ * schemaNS parameter.
+ * @param fieldName The name of the field. Must be a single XML name, must not be
+ * <code>null</code> or the empty string. Has the same namespace prefix usage as the
+ * structName parameter.
+ * @return Returns true if the field exists.
+ */
+ boolean doesStructFieldExist(
+ String schemaNS,
+ String structName,
+ String fieldNS,
+ String fieldName);
+
+
+ /**
+ * DoesQualifierExist tells if the qualifier exists.
+ *
+ * @param schemaNS The namespace URI for the struct. Has the same usage as in
+ * <code>getProperty()</code>.
+ * @param propName The name of the property to which the qualifier is attached. Has the same
+ * usage as in <code>getProperty()</code>.
+ * @param qualNS The namespace URI for the qualifier. Has the same URI and prefix usage as the
+ * schemaNS parameter.
+ * @param qualName The name of the qualifier. Must be a single XML name, must not be
+ * <code>null</code> or the empty string. Has the same namespace prefix usage as the
+ * propName parameter.
+ * @return Returns true if the qualifier exists.
+ */
+ boolean doesQualifierExist(String schemaNS, String propName, String qualNS, String qualName);
+
+
+ // ---------------------------------------------------------------------------------------------
+ // Specialized Get and Set functions
+
+ /**
+ * These functions provide convenient support for localized text properties, including a number
+ * of special and obscure aspects. Localized text properties are stored in alt-text arrays. They
+ * allow multiple concurrent localizations of a property value, for example a document title or
+ * copyright in several languages. The most important aspect of these functions is that they
+ * select an appropriate array item based on one or two RFC 3066 language tags. One of these
+ * languages, the "specific" language, is preferred and selected if there is an exact match. For
+ * many languages it is also possible to define a "generic" language that may be used if there
+ * is no specific language match. The generic language must be a valid RFC 3066 primary subtag,
+ * or the empty string. For example, a specific language of "en-US" should be used in the US,
+ * and a specific language of "en-UK" should be used in England. It is also appropriate to use
+ * "en" as the generic language in each case. If a US document goes to England, the "en-US"
+ * title is selected by using the "en" generic language and the "en-UK" specific language. It is
+ * considered poor practice, but allowed, to pass a specific language that is just an RFC 3066
+ * primary tag. For example "en" is not a good specific language, it should only be used as a
+ * generic language. Passing "i" or "x" as the generic language is also considered poor practice
+ * but allowed. Advice from the W3C about the use of RFC 3066 language tags can be found at:
+ * http://www.w3.org/International/articles/language-tags/
+ * <p>
+ * <em>Note:</em> RFC 3066 language tags must be treated in a case insensitive manner. The XMP
+ * Toolkit does this by normalizing their capitalization:
+ * <ul>
+ * <li> The primary subtag is lower case, the suggested practice of ISO 639.
+ * <li> All 2 letter secondary subtags are upper case, the suggested practice of ISO 3166.
+ * <li> All other subtags are lower case. The XMP specification defines an artificial language,
+ * <li>"x-default", that is used to explicitly denote a default item in an alt-text array.
+ * </ul>
+ * The XMP toolkit normalizes alt-text arrays such that the x-default item is the first item.
+ * The SetLocalizedText function has several special features related to the x-default item, see
+ * its description for details. The selection of the array item is the same for GetLocalizedText
+ * and SetLocalizedText:
+ * <ul>
+ * <li> Look for an exact match with the specific language.
+ * <li> If a generic language is given, look for a partial match.
+ * <li> Look for an x-default item.
+ * <li> Choose the first item.
+ * </ul>
+ * A partial match with the generic language is where the start of the item's language matches
+ * the generic string and the next character is '-'. An exact match is also recognized as a
+ * degenerate case. It is fine to pass x-default as the specific language. In this case,
+ * selection of an x-default item is an exact match by the first rule, not a selection by the
+ * 3rd rule. The last 2 rules are fallbacks used when the specific and generic languages fail to
+ * produce a match. <code>getLocalizedText</code> returns information about a selected item in
+ * an alt-text array. The array item is selected according to the rules given above.
+ *
+ * <em>Note:</em> In a future version of this API a method
+ * using Java <code>java.lang.Locale</code> will be added.
+ *
+ * @param schemaNS The namespace URI for the alt-text array. Has the same usage as in
+ * <code>getProperty()</code>.
+ * @param altTextName The name of the alt-text array. May be a general path expression, must not
+ * be <code>null</code> or the empty string. Has the same namespace prefix usage as
+ * propName in <code>getProperty()</code>.
+ * @param genericLang The name of the generic language as an RFC 3066 primary subtag. May be
+ * <code>null</code> or the empty string if no generic language is wanted.
+ * @param specificLang The name of the specific language as an RFC 3066 tag. Must not be
+ * <code>null</code> or the empty string.
+ * @return Returns an <code>XMPProperty</code> containing the value, the actual language and
+ * the options if an appropriate alternate collection item exists, <code>null</code>
+ * if the property.
+ * does not exist.
+ * @throws XMPException Wraps all errors and exceptions that may occur.
+ */
+ XMPProperty getLocalizedText(
+ String schemaNS,
+ String altTextName,
+ String genericLang,
+ String specificLang) throws XMPException;
+
+
+ /**
+ * Modifies the value of a selected item in an alt-text array. Creates an appropriate array item
+ * if necessary, and handles special cases for the x-default item. If the selected item is from
+ * a match with the specific language, the value of that item is modified. If the existing value
+ * of that item matches the existing value of the x-default item, the x-default item is also
+ * modified. If the array only has 1 existing item (which is not x-default), an x-default item
+ * is added with the given value. If the selected item is from a match with the generic language
+ * and there are no other generic matches, the value of that item is modified. If the existing
+ * value of that item matches the existing value of the x-default item, the x-default item is
+ * also modified. If the array only has 1 existing item (which is not x-default), an x-default
+ * item is added with the given value. If the selected item is from a partial match with the
+ * generic language and there are other partial matches, a new item is created for the specific
+ * language. The x-default item is not modified. If the selected item is from the last 2 rules
+ * then a new item is created for the specific language. If the array only had an x-default
+ * item, the x-default item is also modified. If the array was empty, items are created for the
+ * specific language and x-default.
+ *
+ * <em>Note:</em> In a future version of this API a method
+ * using Java <code>java.lang.Locale</code> will be added.
+ *
+ *
+ * @param schemaNS The namespace URI for the alt-text array. Has the same usage as in
+ * <code>getProperty()</code>.
+ * @param altTextName The name of the alt-text array. May be a general path expression, must not
+ * be <code>null</code> or the empty string. Has the same namespace prefix usage as
+ * propName in <code>getProperty()</code>.
+ * @param genericLang The name of the generic language as an RFC 3066 primary subtag. May be
+ * <code>null</code> or the empty string if no generic language is wanted.
+ * @param specificLang The name of the specific language as an RFC 3066 tag. Must not be
+ * <code>null</code> or the empty string.
+ * @param itemValue A pointer to the <code>null</code> terminated UTF-8 string that is the new
+ * value for the appropriate array item.
+ * @param options Option flags, none are defined at present.
+ * @throws XMPException Wraps all errors and exceptions that may occur.
+ */
+ void setLocalizedText(
+ String schemaNS,
+ String altTextName,
+ String genericLang,
+ String specificLang,
+ String itemValue,
+ PropertyOptions options) throws XMPException;
+
+
+ /**
+ * @see XMPMeta#setLocalizedText(String, String, String, String, String, PropertyOptions)
+ *
+ * @param schemaNS The namespace URI for the alt-text array
+ * @param altTextName The name of the alt-text array
+ * @param genericLang The name of the generic language
+ * @param specificLang The name of the specific language
+ * @param itemValue the new value for the appropriate array item
+ * @throws XMPException Wraps all errors and exceptions
+ */
+ void setLocalizedText(
+ String schemaNS,
+ String altTextName,
+ String genericLang,
+ String specificLang,
+ String itemValue) throws XMPException;
+
+
+
+ // ---------------------------------------------------------------------------------------------
+ // Functions accessing properties as binary values.
+
+
+ /**
+ * These are very similar to <code>getProperty()</code> and <code>SetProperty()</code> above,
+ * but the value is returned or provided in a literal form instead of as a UTF-8 string.
+ * The path composition functions in <code>XMPPathFactory</code> may be used to compose an path
+ * expression for fields in nested structures, items in arrays, or qualifiers.
+ *
+ * @param schemaNS The namespace URI for the property. Has the same usage as in
+ * <code>getProperty()</code>.
+ * @param propName The name of the property.
+ * Has the same usage as in <code>getProperty()</code>.
+ * @return Returns a <code>Boolean</code> value or <code>null</code>
+ * if the property does not exist.
+ * @throws XMPException Wraps all exceptions that may occur,
+ * especially conversion errors.
+ */
+ Boolean getPropertyBoolean(String schemaNS, String propName) throws XMPException;
+
+
+ /**
+ * Convenience method to retrieve the literal value of a property.
+ *
+ * @param schemaNS The namespace URI for the property. Has the same usage as in
+ * <code>getProperty()</code>.
+ * @param propName The name of the property.
+ * Has the same usage as in <code>getProperty()</code>.
+ * @return Returns an <code>Integer</code> value or <code>null</code>
+ * if the property does not exist.
+ * @throws XMPException Wraps all exceptions that may occur,
+ * especially conversion errors.
+ */
+ Integer getPropertyInteger(String schemaNS, String propName) throws XMPException;
+
+
+ /**
+ * Convenience method to retrieve the literal value of a property.
+ *
+ * @param schemaNS The namespace URI for the property. Has the same usage as in
+ * <code>getProperty()</code>.
+ * @param propName The name of the property.
+ * Has the same usage as in <code>getProperty()</code>.
+ * @return Returns a <code>Long</code> value or <code>null</code>
+ * if the property does not exist.
+ * @throws XMPException Wraps all exceptions that may occur,
+ * especially conversion errors.
+ */
+ Long getPropertyLong(String schemaNS, String propName) throws XMPException;
+
+
+ /**
+ * Convenience method to retrieve the literal value of a property.
+ *
+ * @param schemaNS The namespace URI for the property. Has the same usage as in
+ * <code>getProperty()</code>.
+ * @param propName The name of the property.
+ * Has the same usage as in <code>getProperty()</code>.
+ * @return Returns a <code>Double</code> value or <code>null</code>
+ * if the property does not exist.
+ * @throws XMPException Wraps all exceptions that may occur,
+ * especially conversion errors.
+ */
+ Double getPropertyDouble(String schemaNS, String propName) throws XMPException;
+
+
+ /**
+ * Convenience method to retrieve the literal value of a property.
+ *
+ * @param schemaNS The namespace URI for the property. Has the same usage as in
+ * <code>getProperty()</code>.
+ * @param propName The name of the property.
+ * Has the same usage as in <code>getProperty()</code>.
+ * @return Returns a <code>XMPDateTime</code>-object or <code>null</code>
+ * if the property does not exist.
+ * @throws XMPException Wraps all exceptions that may occur,
+ * especially conversion errors.
+ */
+ XMPDateTime getPropertyDate(String schemaNS, String propName) throws XMPException;
+
+
+ /**
+ * Convenience method to retrieve the literal value of a property.
+ *
+ * @param schemaNS The namespace URI for the property. Has the same usage as in
+ * <code>getProperty()</code>.
+ * @param propName The name of the property.
+ * Has the same usage as in <code>getProperty()</code>.
+ * @return Returns a Java <code>Calendar</code>-object or <code>null</code>
+ * if the property does not exist.
+ * @throws XMPException Wraps all exceptions that may occur,
+ * especially conversion errors.
+ */
+ Calendar getPropertyCalendar(String schemaNS, String propName) throws XMPException;
+
+
+ /**
+ * Convenience method to retrieve the literal value of a property.
+ *
+ * @param schemaNS The namespace URI for the property. Has the same usage as in
+ * <code>getProperty()</code>.
+ * @param propName The name of the property.
+ * Has the same usage as in <code>getProperty()</code>.
+ * @return Returns a <code>byte[]</code>-array contained the decoded base64 value
+ * or <code>null</code> if the property does not exist.
+ * @throws XMPException Wraps all exceptions that may occur,
+ * especially conversion errors.
+ */
+ byte[] getPropertyBase64(String schemaNS, String propName) throws XMPException;
+
+
+ /**
+ * Convenience method to retrieve the literal value of a property.
+ * <em>Note:</em> There is no <code>setPropertyString()</code>,
+ * because <code>setProperty()</code> sets a string value.
+ *
+ * @param schemaNS The namespace URI for the property. Has the same usage as in
+ * <code>getProperty()</code>.
+ * @param propName The name of the property.
+ * Has the same usage as in <code>getProperty()</code>.
+ * @return Returns a <code>String</code> value or <code>null</code>
+ * if the property does not exist.
+ * @throws XMPException Wraps all exceptions that may occur,
+ * especially conversion errors.
+ */
+ String getPropertyString(String schemaNS, String propName) throws XMPException;
+
+
+ /**
+ * Convenience method to set a property to a literal <code>boolean</code> value.
+ *
+ * @param schemaNS The namespace URI for the property. Has the same usage as in
+ * <code>setProperty()</code>.
+ * @param propName The name of the property.
+ * Has the same usage as in <code>getProperty()</code>.
+ * @param propValue the literal property value as <code>boolean</code>.
+ * @param options options of the property to set (optional).
+ * @throws XMPException Wraps all exceptions that may occur.
+ */
+ void setPropertyBoolean(
+ String schemaNS,
+ String propName,
+ boolean propValue,
+ PropertyOptions options) throws XMPException;
+
+
+ /**
+ * @see XMPMeta#setPropertyBoolean(String, String, boolean, PropertyOptions)
+ *
+ * @param schemaNS The namespace URI for the property
+ * @param propName The name of the property
+ * @param propValue the literal property value as <code>boolean</code>
+ * @throws XMPException Wraps all exceptions
+ */
+ void setPropertyBoolean(
+ String schemaNS,
+ String propName,
+ boolean propValue) throws XMPException;
+
+
+ /**
+ * Convenience method to set a property to a literal <code>int</code> value.
+ *
+ * @param schemaNS The namespace URI for the property. Has the same usage as in
+ * <code>setProperty()</code>.
+ * @param propName The name of the property.
+ * Has the same usage as in <code>getProperty()</code>.
+ * @param propValue the literal property value as <code>int</code>.
+ * @param options options of the property to set (optional).
+ * @throws XMPException Wraps all exceptions that may occur.
+ */
+ void setPropertyInteger(
+ String schemaNS,
+ String propName,
+ int propValue,
+ PropertyOptions options) throws XMPException;
+
+
+ /**
+ * @see XMPMeta#setPropertyInteger(String, String, int, PropertyOptions)
+ *
+ * @param schemaNS The namespace URI for the property
+ * @param propName The name of the property
+ * @param propValue the literal property value as <code>int</code>
+ * @throws XMPException Wraps all exceptions
+ */
+ void setPropertyInteger(
+ String schemaNS,
+ String propName,
+ int propValue) throws XMPException;
+
+
+ /**
+ * Convenience method to set a property to a literal <code>long</code> value.
+ *
+ * @param schemaNS The namespace URI for the property. Has the same usage as in
+ * <code>setProperty()</code>.
+ * @param propName The name of the property.
+ * Has the same usage as in <code>getProperty()</code>.
+ * @param propValue the literal property value as <code>long</code>.
+ * @param options options of the property to set (optional).
+ * @throws XMPException Wraps all exceptions that may occur.
+ */
+ void setPropertyLong(
+ String schemaNS,
+ String propName,
+ long propValue,
+ PropertyOptions options) throws XMPException;
+
+
+ /**
+ * @see XMPMeta#setPropertyLong(String, String, long, PropertyOptions)
+ *
+ * @param schemaNS The namespace URI for the property
+ * @param propName The name of the property
+ * @param propValue the literal property value as <code>long</code>
+ * @throws XMPException Wraps all exceptions
+ */
+ void setPropertyLong(
+ String schemaNS,
+ String propName,
+ long propValue) throws XMPException;
+
+
+ /**
+ * Convenience method to set a property to a literal <code>double</code> value.
+ *
+ * @param schemaNS The namespace URI for the property. Has the same usage as in
+ * <code>setProperty()</code>.
+ * @param propName The name of the property.
+ * Has the same usage as in <code>getProperty()</code>.
+ * @param propValue the literal property value as <code>double</code>.
+ * @param options options of the property to set (optional).
+ * @throws XMPException Wraps all exceptions that may occur.
+ */
+ void setPropertyDouble(
+ String schemaNS,
+ String propName,
+ double propValue,
+ PropertyOptions options) throws XMPException;
+
+
+ /**
+ * @see XMPMeta#setPropertyDouble(String, String, double, PropertyOptions)
+ *
+ * @param schemaNS The namespace URI for the property
+ * @param propName The name of the property
+ * @param propValue the literal property value as <code>double</code>
+ * @throws XMPException Wraps all exceptions
+ */
+ void setPropertyDouble(
+ String schemaNS,
+ String propName,
+ double propValue) throws XMPException;
+
+
+ /**
+ * Convenience method to set a property with an XMPDateTime-object,
+ * which is serialized to an ISO8601 date.
+ *
+ * @param schemaNS The namespace URI for the property. Has the same usage as in
+ * <code>setProperty()</code>.
+ * @param propName The name of the property.
+ * Has the same usage as in <code>getProperty()</code>.
+ * @param propValue the property value as <code>XMPDateTime</code>.
+ * @param options options of the property to set (optional).
+ * @throws XMPException Wraps all exceptions that may occur.
+ */
+ void setPropertyDate(
+ String schemaNS,
+ String propName,
+ XMPDateTime propValue,
+ PropertyOptions options) throws XMPException;
+
+
+ /**
+ * @see XMPMeta#setPropertyDate(String, String, XMPDateTime, PropertyOptions)
+ *
+ * @param schemaNS The namespace URI for the property
+ * @param propName The name of the property
+ * @param propValue the property value as <code>XMPDateTime</code>
+ * @throws XMPException Wraps all exceptions
+ */
+ void setPropertyDate(
+ String schemaNS,
+ String propName,
+ XMPDateTime propValue) throws XMPException;
+
+
+ /**
+ * Convenience method to set a property with a Java Calendar-object,
+ * which is serialized to an ISO8601 date.
+ *
+ * @param schemaNS The namespace URI for the property. Has the same usage as in
+ * <code>setProperty()</code>.
+ * @param propName The name of the property.
+ * Has the same usage as in <code>getProperty()</code>.
+ * @param propValue the property value as Java <code>Calendar</code>.
+ * @param options options of the property to set (optional).
+ * @throws XMPException Wraps all exceptions that may occur.
+ */
+ void setPropertyCalendar(
+ String schemaNS,
+ String propName,
+ Calendar propValue,
+ PropertyOptions options) throws XMPException;
+
+
+ /**
+ * @see XMPMeta#setPropertyCalendar(String, String, Calendar, PropertyOptions)
+ *
+ * @param schemaNS The namespace URI for the property
+ * @param propName The name of the property
+ * @param propValue the property value as <code>Calendar</code>
+ * @throws XMPException Wraps all exceptions
+ */
+ void setPropertyCalendar(
+ String schemaNS,
+ String propName,
+ Calendar propValue) throws XMPException;
+
+
+ /**
+ * Convenience method to set a property from a binary <code>byte[]</code>-array,
+ * which is serialized as base64-string.
+ *
+ * @param schemaNS The namespace URI for the property. Has the same usage as in
+ * <code>setProperty()</code>.
+ * @param propName The name of the property.
+ * Has the same usage as in <code>getProperty()</code>.
+ * @param propValue the literal property value as byte array.
+ * @param options options of the property to set (optional).
+ * @throws XMPException Wraps all exceptions that may occur.
+ */
+ void setPropertyBase64(
+ String schemaNS,
+ String propName,
+ byte[] propValue,
+ PropertyOptions options) throws XMPException;
+
+
+ /**
+ * @see XMPMeta#setPropertyBase64(String, String, byte[], PropertyOptions)
+ *
+ * @param schemaNS The namespace URI for the property
+ * @param propName The name of the property
+ * @param propValue the literal property value as byte array
+ * @throws XMPException Wraps all exceptions
+ */
+ void setPropertyBase64(
+ String schemaNS,
+ String propName,
+ byte[] propValue) throws XMPException;
+
+
+ /**
+ * Constructs an iterator for the properties within this XMP object.
+ *
+ * @return Returns an <code>XMPIterator</code>.
+ * @see XMPMeta#iterator(String, String, IteratorOptions)
+ * @throws XMPException Wraps all errors and exceptions that may occur.
+ */
+ XMPIterator iterator() throws XMPException;
+
+
+ /**
+ * Constructs an iterator for the properties within this XMP object using some options.
+ *
+ * @param options Option flags to control the iteration.
+ * @return Returns an <code>XMPIterator</code>.
+ * @see XMPMeta#iterator(String, String, IteratorOptions)
+ * @throws XMPException Wraps all errors and exceptions that may occur.
+ */
+ XMPIterator iterator(IteratorOptions options) throws XMPException;
+
+
+ /**
+ * Construct an iterator for the properties within an XMP object. The general operation of an
+ * XMP object iterator was. According to the parameters it iterates the entire data tree,
+ * properties within a specific schema, or a subtree rooted at a specific node.
+ *
+ * @param schemaNS Optional schema namespace URI to restrict the iteration. Omitted (visit all
+ * schema) by passing <code>null</code> or empty String.
+ * @param propName Optional property name to restrict the iteration. May be an arbitrary path
+ * expression. Omitted (visit all properties) by passing <code>null</code> or empty
+ * String. If no schema URI is given, it is ignored.
+ * @param options Option flags to control the iteration. See {@link IteratorOptions} for
+ * details.
+ * @return Returns an <code>XMPIterator</code> for this <code>XMPMeta</code>-object
+ * considering the given options.
+ * @throws XMPException Wraps all errors and exceptions that may occur.
+ */
+ XMPIterator iterator(
+ String schemaNS,
+ String propName,
+ IteratorOptions options) throws XMPException;
+
+
+ /**
+ * This correlates to the about-attribute,
+ * returns the empty String if no name is set.
+ *
+ * @return Returns the name of the XMP object.
+ */
+ String getObjectName();
+
+
+ /**
+ * @param name Sets the name of the XMP object.
+ */
+ void setObjectName(String name);
+
+
+ /**
+ * Clones the complete metadata tree.
+ *
+ * @return Returns a deep copy of this instance.
+ */
+ Object clone();
+
+
+ /**
+ * Sorts the complete datamodel according to the following rules:
+ * <ul>
+ * <li>Schema nodes are sorted by prefix.
+ * <li>Properties at top level and within structs are sorted by full name, that is
+ * prefix + local name.
+ * <li>Array items are not sorted, even if they have no certain order such as bags.
+ * <li>Qualifier are sorted, with the exception of "xml:lang" and/or "rdf:type"
+ * that stay at the top of the list in that order.
+ * </ul>
+ */
+ void sort();
+
+
+ /**
+ * Renders this node and the tree unter this node in a human readable form.
+ * @return Returns a multiline string containing the dump.
+ */
+ String dumpObject();
+} \ No newline at end of file
diff --git a/java/XMPCore/src/com/adobe/xmp/XMPMetaFactory.java b/java/XMPCore/src/com/adobe/xmp/XMPMetaFactory.java
new file mode 100644
index 0000000..4b218ec
--- /dev/null
+++ b/java/XMPCore/src/com/adobe/xmp/XMPMetaFactory.java
@@ -0,0 +1,327 @@
+//=================================================================================================
+//ADOBE SYSTEMS INCORPORATED
+//Copyright 2006-2007 Adobe Systems Incorporated
+//All Rights Reserved
+//
+//NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+//of the Adobe license agreement accompanying it.
+//=================================================================================================
+
+package com.adobe.xmp;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Properties;
+
+import com.adobe.xmp.impl.XMPMetaImpl;
+import com.adobe.xmp.impl.XMPMetaParser;
+import com.adobe.xmp.impl.XMPSchemaRegistryImpl;
+import com.adobe.xmp.impl.XMPSerializerHelper;
+import com.adobe.xmp.options.ParseOptions;
+import com.adobe.xmp.options.SerializeOptions;
+
+
+/**
+ * Creates <code>XMPMeta</code>-instances from an <code>InputStream</code>
+ *
+ * @since 30.01.2006
+ */
+public final class XMPMetaFactory
+{
+ /** The singleton instance of the <code>XMPSchemaRegistry</code>. */
+ private static XMPSchemaRegistry schema = new XMPSchemaRegistryImpl();
+ /** cache for version info */
+ private static XMPVersionInfo versionInfo = null;
+
+ /**
+ * Hides public constructor
+ */
+ private XMPMetaFactory()
+ {
+ // EMPTY
+ }
+
+
+ /**
+ * @return Returns the singleton instance of the <code>XMPSchemaRegistry</code>.
+ */
+ public static XMPSchemaRegistry getSchemaRegistry()
+ {
+ return schema;
+ }
+
+
+ /**
+ * @return Returns an empty <code>XMPMeta</code>-object.
+ */
+ public static XMPMeta create()
+ {
+ return new XMPMetaImpl();
+ }
+
+
+ /**
+ * Parsing with default options.
+ * @see XMPMetaFactory#parse(InputStream, ParseOptions)
+ *
+ * @param in an <code>InputStream</code>
+ * @return Returns the <code>XMPMeta</code>-object created from the input.
+ * @throws XMPException If the file is not well-formed XML or if the parsing fails.
+ */
+ public static XMPMeta parse(InputStream in) throws XMPException
+ {
+ return parse(in, null);
+ }
+
+
+ /**
+ * These functions support parsing serialized RDF into an XMP object, and serailizing an XMP
+ * object into RDF. The input for parsing may be any valid Unicode
+ * encoding. ISO Latin-1 is also recognized, but its use is strongly discouraged. Serialization
+ * is always as UTF-8.
+ * <p>
+ * <code>parseFromBuffer()</code> parses RDF from an <code>InputStream</code>. The encoding
+ * is recognized automatically.
+ *
+ * @param in an <code>InputStream</code>
+ * @param options Options controlling the parsing.<br>
+ * The available options are:
+ * <ul>
+ * <li> XMP_REQUIRE_XMPMETA - The &lt;x:xmpmeta&gt; XML element is required around
+ * <tt>&lt;rdf:RDF&gt;</tt>.
+ * <li> XMP_STRICT_ALIASING - Do not reconcile alias differences, throw an exception.
+ * </ul>
+ * <em>Note:</em>The XMP_STRICT_ALIASING option is not yet implemented.
+ * @return Returns the <code>XMPMeta</code>-object created from the input.
+ * @throws XMPException If the file is not well-formed XML or if the parsing fails.
+ */
+ public static XMPMeta parse(InputStream in, ParseOptions options)
+ throws XMPException
+ {
+ return XMPMetaParser.parse(in, options);
+ }
+
+
+ /**
+ * Parsing with default options.
+ * @see XMPMetaFactory#parse(InputStream)
+ *
+ * @param packet a String contain an XMP-file.
+ * @return Returns the <code>XMPMeta</code>-object created from the input.
+ * @throws XMPException If the file is not well-formed XML or if the parsing fails.
+ */
+ public static XMPMeta parseFromString(String packet) throws XMPException
+ {
+ return parseFromString(packet, null);
+ }
+
+
+ /**
+ * Creates an <code>XMPMeta</code>-object from a string.
+ * @see XMPMetaFactory#parseFromString(String, ParseOptions)
+ *
+ * @param packet a String contain an XMP-file.
+ * @param options Options controlling the parsing.
+ * @return Returns the <code>XMPMeta</code>-object created from the input.
+ * @throws XMPException If the file is not well-formed XML or if the parsing fails.
+ */
+ public static XMPMeta parseFromString(String packet, ParseOptions options)
+ throws XMPException
+ {
+ return XMPMetaParser.parse(packet, options);
+ }
+
+
+ /**
+ * Parsing with default options.
+ * @see XMPMetaFactory#parseFromBuffer(byte[], ParseOptions)
+ *
+ * @param buffer a String contain an XMP-file.
+ * @return Returns the <code>XMPMeta</code>-object created from the input.
+ * @throws XMPException If the file is not well-formed XML or if the parsing fails.
+ */
+ public static XMPMeta parseFromBuffer(byte[] buffer) throws XMPException
+ {
+ return parseFromBuffer(buffer, null);
+ }
+
+
+ /**
+ * Creates an <code>XMPMeta</code>-object from a byte-buffer.
+ * @see XMPMetaFactory#parse(InputStream, ParseOptions)
+ *
+ * @param buffer a String contain an XMP-file.
+ * @param options Options controlling the parsing.
+ * @return Returns the <code>XMPMeta</code>-object created from the input.
+ * @throws XMPException If the file is not well-formed XML or if the parsing fails.
+ */
+ public static XMPMeta parseFromBuffer(byte[] buffer,
+ ParseOptions options) throws XMPException
+ {
+ return XMPMetaParser.parse(buffer, options);
+ }
+
+
+ /**
+ * Serializes an <code>XMPMeta</code>-object as RDF into an <code>OutputStream</code>
+ * with default options.
+ *
+ * @param xmp a metadata object
+ * @param out an <code>OutputStream</code> to write the serialized RDF to.
+ * @throws XMPException on serializsation errors.
+ */
+ public static void serialize(XMPMeta xmp, OutputStream out) throws XMPException
+ {
+ serialize(xmp, out, null);
+ }
+
+
+ /**
+ * Serializes an <code>XMPMeta</code>-object as RDF into an <code>OutputStream</code>.
+ *
+ * @param xmp a metadata object
+ * @param options Options to control the serialization (see {@link SerializeOptions}).
+ * @param out an <code>OutputStream</code> to write the serialized RDF to.
+ * @throws XMPException on serializsation errors.
+ */
+ public static void serialize(XMPMeta xmp, OutputStream out, SerializeOptions options)
+ throws XMPException
+ {
+ assertImplementation(xmp);
+ XMPSerializerHelper.serialize((XMPMetaImpl) xmp, out, options);
+ }
+
+
+ /**
+ * Serializes an <code>XMPMeta</code>-object as RDF into a byte buffer.
+ *
+ * @param xmp a metadata object
+ * @param options Options to control the serialization (see {@link SerializeOptions}).
+ * @return Returns a byte buffer containing the serialized RDF.
+ * @throws XMPException on serializsation errors.
+ */
+ public static byte[] serializeToBuffer(XMPMeta xmp, SerializeOptions options)
+ throws XMPException
+ {
+ assertImplementation(xmp);
+ return XMPSerializerHelper.serializeToBuffer((XMPMetaImpl) xmp, options);
+ }
+
+
+ /**
+ * Serializes an <code>XMPMeta</code>-object as RDF into a string. <em>Note:</em> Encoding
+ * is ignored when serializing to a string.
+ *
+ * @param xmp a metadata object
+ * @param options Options to control the serialization (see {@link SerializeOptions}).
+ * @return Returns a string containing the serialized RDF.
+ * @throws XMPException on serializsation errors.
+ */
+ public static String serializeToString(XMPMeta xmp, SerializeOptions options)
+ throws XMPException
+ {
+ assertImplementation(xmp);
+ return XMPSerializerHelper.serializeToString((XMPMetaImpl) xmp, options);
+ }
+
+
+ /**
+ * @param xmp Asserts that xmp is compatible to <code>XMPMetaImpl</code>.s
+ */
+ private static void assertImplementation(XMPMeta xmp)
+ {
+ if (!(xmp instanceof XMPMetaImpl))
+ {
+ throw new UnsupportedOperationException("The serializing service works only" +
+ "with the XMPMeta implementation of this library");
+ }
+ }
+
+
+ /**
+ * Resets the schema registry to its original state (creates a new one).
+ * Be careful this might break all existing XMPMeta-objects and should be used
+ * only for testing purpurses.
+ */
+ public static void reset()
+ {
+ schema = new XMPSchemaRegistryImpl();
+ }
+
+
+ /**
+ * Obtain version information.
+ *
+ * @return Returns the version information.
+ */
+ public static XMPVersionInfo getVersionInfo()
+ {
+ if (versionInfo == null)
+ {
+ try
+ {
+ Properties versProperties = new Properties();
+ versProperties.load(XMPMetaFactory.class.getResourceAsStream("version.properties"));
+
+ final int major = Integer.parseInt(versProperties
+ .getProperty("implementation.version.major"));
+ final int minor = Integer.parseInt(versProperties
+ .getProperty("implementation.version.minor"));
+ final int micro = Integer.parseInt(versProperties
+ .getProperty("implementation.version.micro"));
+ final boolean debug = Boolean.valueOf(
+ versProperties.getProperty("implementation.version.debug")).booleanValue();
+ final String message;
+ final int engBuild;
+
+ message = versProperties.getProperty("implementation.version");
+ engBuild = Integer.parseInt(versProperties
+ .getProperty("implementation.version.engbuild"));
+
+ versionInfo = new XMPVersionInfo()
+ {
+ public int getMajor()
+ {
+ return major;
+ }
+
+ public int getMinor()
+ {
+ return minor;
+ }
+
+ public int getMicro()
+ {
+ return micro;
+ }
+
+ public boolean isDebug()
+ {
+ return debug;
+ }
+
+ public int getBuild()
+ {
+ return engBuild;
+ }
+
+ public String getMessage()
+ {
+ return message;
+ }
+
+ public String toString()
+ {
+ return message;
+ }
+ };
+
+ }
+ catch (Throwable e)
+ {
+ // EMTPY, severe error would be detected during the tests
+ }
+ }
+ return versionInfo;
+ }
+}
diff --git a/java/XMPCore/src/com/adobe/xmp/XMPPathFactory.java b/java/XMPCore/src/com/adobe/xmp/XMPPathFactory.java
new file mode 100644
index 0000000..e8fa6d2
--- /dev/null
+++ b/java/XMPCore/src/com/adobe/xmp/XMPPathFactory.java
@@ -0,0 +1,286 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+package com.adobe.xmp;
+
+import com.adobe.xmp.impl.Utils;
+import com.adobe.xmp.impl.xpath.XMPPath;
+import com.adobe.xmp.impl.xpath.XMPPathParser;
+
+/**
+ * Utility services for the metadata object. It has only public static functions, you cannot create
+ * an object. These are all functions that layer cleanly on top of the core XMP toolkit.
+ * <p>
+ * These functions provide support for composing path expressions to deeply nested properties. The
+ * functions <code>XMPMeta</code> such as <code>getProperty()</code>,
+ * <code>getArrayItem()</code> and <code>getStructField()</code> provide easy access to top
+ * level simple properties, items in top level arrays, and fields of top level structs. They do not
+ * provide convenient access to more complex things like fields several levels deep in a complex
+ * struct, or fields within an array of structs, or items of an array that is a field of a struct.
+ * These functions can also be used to compose paths to top level array items or struct fields so
+ * that you can use the binary accessors like <code>getPropertyAsInteger()</code>.
+ * <p>
+ * You can use these functions is to compose a complete path expression, or all but the last
+ * component. Suppose you have a property that is an array of integers within a struct. You can
+ * access one of the array items like this:
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * String path = XMPPathFactory.composeStructFieldPath (schemaNS, &quot;Struct&quot;, fieldNS,
+ * &quot;Array&quot;);
+ * String path += XMPPathFactory.composeArrayItemPath (schemaNS, &quot;Array&quot; index);
+ * PropertyInteger result = xmpObj.getPropertyAsInteger(schemaNS, path);
+ * </pre>
+ *
+ * </blockquote> You could also use this code if you want the string form of the integer:
+ * <blockquote>
+ *
+ * <pre>
+ * String path = XMPPathFactory.composeStructFieldPath (schemaNS, &quot;Struct&quot;, fieldNS,
+ * &quot;Array&quot;);
+ * PropertyText xmpObj.getArrayItem (schemaNS, path, index);
+ * </pre>
+ *
+ * </blockquote>
+ * <p>
+ * <em>Note:</em> It might look confusing that the schemaNS is passed in all of the calls above.
+ * This is because the XMP toolkit keeps the top level &quot;schema&quot; namespace separate from
+ * the rest of the path expression.
+ * <em>Note:</em> These methods are much simpler than in the C++-API, they don't check the given
+ * path or array indices.
+ *
+ * @since 25.01.2006
+ */
+public final class XMPPathFactory
+{
+ /** Private constructor */
+ private XMPPathFactory()
+ {
+ // EMPTY
+ }
+
+
+ /**
+ * Compose the path expression for an item in an array.
+ *
+ * @param arrayName The name of the array. May be a general path expression, must not be
+ * <code>null</code> or the empty string.
+ * @param itemIndex The index of the desired item. Arrays in XMP are indexed from 1.
+ * 0 and below means last array item and renders as <code>[last()]</code>.
+ *
+ * @return Returns the composed path basing on fullPath. This will be of the form
+ * <tt>ns:arrayName[i]</tt>, where &quot;ns&quot; is the prefix for schemaNS and
+ * &quot;i&quot; is the decimal representation of itemIndex.
+ */
+ public static String composeArrayItemPath(String arrayName, int itemIndex)
+ {
+ if (itemIndex > 0)
+ {
+ return arrayName + '[' + itemIndex + ']';
+ }
+ else
+ {
+ return arrayName + "[last()]";
+ }
+ }
+
+
+ /**
+ * Compose the path expression for a field in a struct. The result can be added to the
+ * path of
+ *
+ *
+ * @param fieldNS The namespace URI for the field. Must not be <code>null</code> or the empty
+ * string.
+ * @param fieldName The name of the field. Must be a simple XML name, must not be
+ * <code>null</code> or the empty string.
+ * @return Returns the composed path. This will be of the form
+ * <tt>ns:structName/fNS:fieldName</tt>, where &quot;ns&quot; is the prefix for
+ * schemaNS and &quot;fNS&quot; is the prefix for fieldNS.
+ * @throws XMPException Thrown if the path to create is not valid.
+ */
+ public static String composeStructFieldPath(String fieldNS,
+ String fieldName) throws XMPException
+ {
+ assertFieldNS(fieldNS);
+ assertFieldName(fieldName);
+
+ XMPPath fieldPath = XMPPathParser.expandXPath(fieldNS, fieldName);
+ if (fieldPath.size() != 2)
+ {
+ throw new XMPException("The field name must be simple", XMPError.BADXPATH);
+ }
+
+ return '/' + fieldPath.getSegment(XMPPath.STEP_ROOT_PROP).getName();
+ }
+
+
+ /**
+ * Compose the path expression for a qualifier.
+ *
+ * @param qualNS The namespace URI for the qualifier. May be <code>null</code> or the empty
+ * string if the qualifier is in the XML empty namespace.
+ * @param qualName The name of the qualifier. Must be a simple XML name, must not be
+ * <code>null</code> or the empty string.
+ * @return Returns the composed path. This will be of the form
+ * <tt>ns:propName/?qNS:qualName</tt>, where &quot;ns&quot; is the prefix for
+ * schemaNS and &quot;qNS&quot; is the prefix for qualNS.
+ * @throws XMPException Thrown if the path to create is not valid.
+ */
+ public static String composeQualifierPath(
+ String qualNS,
+ String qualName) throws XMPException
+ {
+ assertQualNS(qualNS);
+ assertQualName(qualName);
+
+ XMPPath qualPath = XMPPathParser.expandXPath(qualNS, qualName);
+ if (qualPath.size() != 2)
+ {
+ throw new XMPException("The qualifier name must be simple", XMPError.BADXPATH);
+ }
+
+ return "/?" + qualPath.getSegment(XMPPath.STEP_ROOT_PROP).getName();
+ }
+
+
+ /**
+ * Compose the path expression to select an alternate item by language. The
+ * path syntax allows two forms of &quot;content addressing&quot; that may
+ * be used to select an item in an array of alternatives. The form used in
+ * ComposeLangSelector lets you select an item in an alt-text array based on
+ * the value of its <tt>xml:lang</tt> qualifier. The other form of content
+ * addressing is shown in ComposeFieldSelector. \note ComposeLangSelector
+ * does not supplant SetLocalizedText or GetLocalizedText. They should
+ * generally be used, as they provide extra logic to choose the appropriate
+ * language and maintain consistency with the 'x-default' value.
+ * ComposeLangSelector gives you an path expression that is explicitly and
+ * only for the language given in the langName parameter.
+ *
+ * @param arrayName
+ * The name of the array. May be a general path expression, must
+ * not be <code>null</code> or the empty string.
+ * @param langName
+ * The RFC 3066 code for the desired language.
+ * @return Returns the composed path. This will be of the form
+ * <tt>ns:arrayName[@xml:lang='langName']</tt>, where
+ * &quot;ns&quot; is the prefix for schemaNS.
+ */
+ public static String composeLangSelector(String arrayName,
+ String langName)
+ {
+ return arrayName + "[?xml:lang=\"" + Utils.normalizeLangValue(langName) + "\"]";
+ }
+
+
+ /**
+ * Compose the path expression to select an alternate item by a field's value. The path syntax
+ * allows two forms of &quot;content addressing&quot; that may be used to select an item in an
+ * array of alternatives. The form used in ComposeFieldSelector lets you select an item in an
+ * array of structs based on the value of one of the fields in the structs. The other form of
+ * content addressing is shown in ComposeLangSelector. For example, consider a simple struct
+ * that has two fields, the name of a city and the URI of an FTP site in that city. Use this to
+ * create an array of download alternatives. You can show the user a popup built from the values
+ * of the city fields. You can then get the corresponding URI as follows:
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * String path = composeFieldSelector ( schemaNS, &quot;Downloads&quot;, fieldNS,
+ * &quot;City&quot;, chosenCity );
+ * XMPProperty prop = xmpObj.getStructField ( schemaNS, path, fieldNS, &quot;URI&quot; );
+ * </pre>
+ *
+ * </blockquote>
+ *
+ * @param arrayName The name of the array. May be a general path expression, must not be
+ * <code>null</code> or the empty string.
+ * @param fieldNS The namespace URI for the field used as the selector. Must not be
+ * <code>null</code> or the empty string.
+ * @param fieldName The name of the field used as the selector. Must be a simple XML name, must
+ * not be <code>null</code> or the empty string. It must be the name of a field that is
+ * itself simple.
+ * @param fieldValue The desired value of the field.
+ * @return Returns the composed path. This will be of the form
+ * <tt>ns:arrayName[fNS:fieldName='fieldValue']</tt>, where &quot;ns&quot; is the
+ * prefix for schemaNS and &quot;fNS&quot; is the prefix for fieldNS.
+ * @throws XMPException Thrown if the path to create is not valid.
+ */
+ public static String composeFieldSelector(String arrayName, String fieldNS,
+ String fieldName, String fieldValue) throws XMPException
+ {
+ XMPPath fieldPath = XMPPathParser.expandXPath(fieldNS, fieldName);
+ if (fieldPath.size() != 2)
+ {
+ throw new XMPException("The fieldName name must be simple", XMPError.BADXPATH);
+ }
+
+ return arrayName + '[' + fieldPath.getSegment(XMPPath.STEP_ROOT_PROP).getName() +
+ "=\"" + fieldValue + "\"]";
+ }
+
+
+ /**
+ * ParameterAsserts that a qualifier namespace is set.
+ * @param qualNS a qualifier namespace
+ * @throws XMPException Qualifier schema is null or empty
+ */
+ private static void assertQualNS(String qualNS) throws XMPException
+ {
+ if (qualNS == null || qualNS.length() == 0)
+ {
+ throw new XMPException("Empty qualifier namespace URI", XMPError.BADSCHEMA);
+ }
+
+ }
+
+
+ /**
+ * ParameterAsserts that a qualifier name is set.
+ * @param qualName a qualifier name or path
+ * @throws XMPException Qualifier name is null or empty
+ */
+ private static void assertQualName(String qualName) throws XMPException
+ {
+ if (qualName == null || qualName.length() == 0)
+ {
+ throw new XMPException("Empty qualifier name", XMPError.BADXPATH);
+ }
+ }
+
+
+ /**
+ * ParameterAsserts that a struct field namespace is set.
+ * @param fieldNS a struct field namespace
+ * @throws XMPException Struct field schema is null or empty
+ */
+ private static void assertFieldNS(String fieldNS) throws XMPException
+ {
+ if (fieldNS == null || fieldNS.length() == 0)
+ {
+ throw new XMPException("Empty field namespace URI", XMPError.BADSCHEMA);
+ }
+
+ }
+
+
+ /**
+ * ParameterAsserts that a struct field name is set.
+ * @param fieldName a struct field name or path
+ * @throws XMPException Struct field name is null or empty
+ */
+ private static void assertFieldName(String fieldName) throws XMPException
+ {
+ if (fieldName == null || fieldName.length() == 0)
+ {
+ throw new XMPException("Empty f name", XMPError.BADXPATH);
+ }
+ }
+} \ No newline at end of file
diff --git a/java/XMPCore/src/com/adobe/xmp/XMPSchemaRegistry.java b/java/XMPCore/src/com/adobe/xmp/XMPSchemaRegistry.java
new file mode 100644
index 0000000..a523d93
--- /dev/null
+++ b/java/XMPCore/src/com/adobe/xmp/XMPSchemaRegistry.java
@@ -0,0 +1,235 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+package com.adobe.xmp;
+
+import java.util.Map;
+
+import com.adobe.xmp.options.AliasOptions;
+import com.adobe.xmp.properties.XMPAliasInfo;
+
+/**
+ * The schema registry keeps track of all namespaces and aliases used in the XMP
+ * metadata. At initialisation time, the default namespaces and default aliases
+ * are automatically registered. <b>Namespaces</b> must be registered before
+ * used in namespace URI parameters or path expressions. Within the XMP Toolkit
+ * the registered namespace URIs and prefixes must be unique. Additional
+ * namespaces encountered when parsing RDF are automatically registered. The
+ * namespace URI should always end in an XML name separator such as '/' or '#'.
+ * This is because some forms of RDF shorthand catenate a namespace URI with an
+ * element name to form a new URI.
+ * <p>
+ * <b>Aliases</b> in XMP serve the same purpose as Windows file shortcuts,
+ * Macintosh file aliases, or UNIX file symbolic links. The aliases are simply
+ * multiple names for the same property. One distinction of XMP aliases is that
+ * they are ordered, there is an alias name pointing to an actual name. The
+ * primary significance of the actual name is that it is the preferred name for
+ * output, generally the most widely recognized name.
+ * <p>
+ * The names that can be aliased in XMP are restricted. The alias must be a top
+ * level property name, not a field within a structure or an element within an
+ * array. The actual may be a top level property name, the first element within
+ * a top level array, or the default element in an alt-text array. This does not
+ * mean the alias can only be a simple property. It is OK to alias a top level
+ * structure or array to an identical top level structure or array, or to the
+ * first item of an array of structures.
+ *
+ * @since 27.01.2006
+ */
+public interface XMPSchemaRegistry
+{
+ // ---------------------------------------------------------------------------------------------
+ // Namespace Functions
+
+ /**
+ * Register a namespace URI with a suggested prefix. It is not an error if
+ * the URI is already registered, no matter what the prefix is. If the URI
+ * is not registered but the suggested prefix is in use, a unique prefix is
+ * created from the suggested one. The actual registeed prefix is always
+ * returned. The function result tells if the registered prefix is the
+ * suggested one.
+ * <p>
+ * Note: No checking is presently done on either the URI or the prefix.
+ *
+ * @param namespaceURI
+ * The URI for the namespace. Must be a valid XML URI.
+ * @param suggestedPrefix
+ * The suggested prefix to be used if the URI is not yet
+ * registered. Must be a valid XML name.
+ * @return Returns the registered prefix for this URI, is equal to the
+ * suggestedPrefix if the namespace hasn't been registered before,
+ * otherwise the existing prefix.
+ * @throws XMPException If the parameters are not accordingly set
+ */
+ String registerNamespace(String namespaceURI, String suggestedPrefix) throws XMPException;
+
+
+ /**
+ * Obtain the prefix for a registered namespace URI.
+ * <p>
+ * It is not an error if the namespace URI is not registered. The output
+ * namespacePrefix string is not modified if the namespace URI is not
+ * registered.
+ *
+ * @param namespaceURI
+ * The URI for the namespace. Must not be null or the empty
+ * string.
+ * @return Returns true if the namespace URI is registered.
+ */
+ String getNamespacePrefix(String namespaceURI);
+
+
+ /**
+ * Obtain the URI for a registered namespace prefix.
+ * <p>
+ * It is not an error if the namespace prefix is not registered. The output
+ * namespaceURI string is not modified if the namespace prefix is not
+ * registered.
+ *
+ * @param namespacePrefix
+ * The prefix for the namespace. Must not be null or the empty
+ * string.
+ * @return Returns the URI registered for this prefix.
+ */
+ String getNamespaceURI(String namespacePrefix);
+
+
+ /**
+ * @return Returns the registered prefix/namespace-pairs as map, where the keys are the
+ * namespaces and the values are the prefixes.
+ */
+ Map getNamespaces();
+
+
+ /**
+ * @return Returns the registered namespace/prefix-pairs as map, where the keys are the
+ * prefixes and the values are the namespaces.
+ */
+ Map getPrefixes();
+
+
+ /**
+ * Deletes a namespace from the registry.
+ * <p>
+ * Does nothing if the URI is not registered, or if the namespaceURI
+ * parameter is null or the empty string.
+ * <p>
+ * Note: Not yet implemented.
+ *
+ * @param namespaceURI
+ * The URI for the namespace.
+ */
+ void deleteNamespace(String namespaceURI);
+
+
+
+
+
+ // ---------------------------------------------------------------------------------------------
+ // Alias Functions
+
+ /**
+ * Associates an alias name with an actual name.
+ * <p>
+ * Define a alias mapping from one namespace/property to another. Both
+ * property names must be simple names. An alias can be a direct mapping,
+ * where the alias and actual have the same data type. It is also possible
+ * to map a simple alias to an item in an array. This can either be to the
+ * first item in the array, or to the 'x-default' item in an alt-text array.
+ * Multiple alias names may map to the same actual, as long as the forms
+ * match. It is a no-op to reregister an alias in an identical fashion.
+ *
+ * @param aliasNS
+ * The namespace URI for the alias. Must not be null or the empty
+ * string.
+ * @param aliasProp
+ * The name of the alias. Must be a simple name, not null or the
+ * empty string and not a general path expression.
+ * @param actualNS
+ * The namespace URI for the actual. Must not be null or the
+ * empty string.
+ * @param actualProp
+ * The name of the actual. Must be a simple name, not null or the
+ * empty string and not a general path expression.
+ * @param aliasForm
+ * Provides options for aliases for simple aliases to array
+ * items. This is needed to know what kind of array to create if
+ * set for the first time via the simple alias. Pass
+ * <code>XMP_NoOptions</code>, the default value, for all
+ * direct aliases regardless of whether the actual data type is
+ * an array or not (see {@link AliasOptions}).
+ * @throws XMPException
+ * for inconsistant aliases.
+ */
+ void registerAlias(String aliasNS, String aliasProp, String actualNS, String actualProp,
+ AliasOptions aliasForm) throws XMPException;
+
+
+ /**
+ * Determines if a name is an alias, and what it is aliased to.
+ *
+ * @param aliasNS
+ * The namespace URI of the alias. Must not be <code>null</code> or the empty
+ * string.
+ * @param aliasProp
+ * The name of the alias. May be an arbitrary path expression
+ * path, must not be <code>null</code> or the empty string.
+ * @return Returns the <code>XMPAliasInfo</code> for the given alias namespace and property or
+ * <code>null</code> if there is no such alias.
+ */
+ XMPAliasInfo resolveAlias(String aliasNS, String aliasProp);
+
+
+ /**
+ * Collects all aliases that are contained in the provided namespace.
+ * If nothing is found, an empty array is returned.
+ *
+ * @param aliasNS a schema namespace URI
+ * @return Returns all alias infos from aliases that are contained in the provided namespace.
+ */
+ XMPAliasInfo[] findAliases(String aliasNS);
+
+
+ /**
+ * Searches for registered aliases.
+ *
+ * @param qname
+ * an XML conform qname
+ * @return Returns if an alias definition for the given qname to another
+ * schema and property is registered.
+ */
+ XMPAliasInfo findAlias(String qname);
+
+
+ /**
+ * Delete an alias.
+ * <p>
+ * This only deletes the registration of the alias, it does not delete the
+ * actual property. It does delete any view of the property through the
+ * alias name. It is OK to attempt to delete an alias that does not exist,
+ * that is if the alias name is not registered as an alias.
+ *
+ * @param aliasNS
+ * The namespace URI for the alias. Must not be null or the empty
+ * string.
+ * @param aliasProp
+ * The name of the alias. Must be a simple name, not null or the
+ * empty string and not a general path expression.
+ */
+ void deleteAlias(String aliasNS, String aliasProp);
+
+
+ /**
+ * @return Returns the registered aliases as map, where the key is the "qname" (prefix and name)
+ * and the value an <code>XMPAliasInfo</code>-object.
+ */
+ Map getAliases();
+
+
+} \ No newline at end of file
diff --git a/java/XMPCore/src/com/adobe/xmp/XMPUtils.java b/java/XMPCore/src/com/adobe/xmp/XMPUtils.java
new file mode 100644
index 0000000..b54aebb
--- /dev/null
+++ b/java/XMPCore/src/com/adobe/xmp/XMPUtils.java
@@ -0,0 +1,506 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+package com.adobe.xmp;
+
+import com.adobe.xmp.impl.Base64;
+import com.adobe.xmp.impl.ISO8601Converter;
+import com.adobe.xmp.impl.XMPUtilsImpl;
+import com.adobe.xmp.options.PropertyOptions;
+
+
+/**
+ * Utility methods for XMP. I included only those that are different from the
+ * Java default conversion utilities.
+ *
+ * @since 21.02.2006
+ */
+public class XMPUtils
+{
+ /** Private constructor */
+ private XMPUtils()
+ {
+ // EMPTY
+ }
+
+
+ /**
+ * Create a single edit string from an array of strings.
+ *
+ * @param xmp
+ * The XMP object containing the array to be catenated.
+ * @param schemaNS
+ * The schema namespace URI for the array. Must not be null or
+ * the empty string.
+ * @param arrayName
+ * The name of the array. May be a general path expression, must
+ * not be null or the empty string. Each item in the array must
+ * be a simple string value.
+ * @param separator
+ * The string to be used to separate the items in the catenated
+ * string. Defaults to &quot;; &quot;, ASCII semicolon and space
+ * (U+003B, U+0020).
+ * @param quotes
+ * The characters to be used as quotes around array items that
+ * contain a separator. Defaults to &apos;&quot;&apos;
+ * @param allowCommas
+ * Option flag to control the catenation.
+ * @return Returns the string containing the catenated array items.
+ * @throws XMPException Forwards the Exceptions from the metadata processing
+ */
+ public static String catenateArrayItems(XMPMeta xmp, String schemaNS, String arrayName,
+ String separator, String quotes, boolean allowCommas) throws XMPException
+ {
+ return XMPUtilsImpl
+ .catenateArrayItems(xmp, schemaNS, arrayName, separator, quotes, allowCommas);
+ }
+
+
+ /**
+ * Separate a single edit string into an array of strings.
+ *
+ * @param xmp
+ * The XMP object containing the array to be updated.
+ * @param schemaNS
+ * The schema namespace URI for the array. Must not be null or
+ * the empty string.
+ * @param arrayName
+ * The name of the array. May be a general path expression, must
+ * not be null or the empty string. Each item in the array must
+ * be a simple string value.
+ * @param catedStr
+ * The string to be separated into the array items.
+ * @param arrayOptions Option flags to control the separation.
+ * @param preserveCommas Flag if commas shall be preserved
+ * @throws XMPException Forwards the Exceptions from the metadata processing
+ */
+ public static void separateArrayItems(XMPMeta xmp, String schemaNS, String arrayName,
+ String catedStr, PropertyOptions arrayOptions, boolean preserveCommas)
+ throws XMPException
+ {
+ XMPUtilsImpl.separateArrayItems(xmp, schemaNS, arrayName, catedStr, arrayOptions,
+ preserveCommas);
+ }
+
+
+ /**
+ * Remove multiple properties from an XMP object.
+ *
+ * RemoveProperties was created to support the File Info dialog's Delete
+ * button, and has been been generalized somewhat from those specific needs.
+ * It operates in one of three main modes depending on the schemaNS and
+ * propName parameters:
+ *
+ * <ul>
+ * <li> Non-empty <code>schemaNS</code> and <code>propName</code> - The named property is
+ * removed if it is an external property, or if the
+ * flag <code>doAllProperties</code> option is true. It does not matter whether the
+ * named property is an actual property or an alias.
+ *
+ * <li> Non-empty <code>schemaNS</code> and empty <code>propName</code> - The all external
+ * properties in the named schema are removed. Internal properties are also
+ * removed if the flag <code>doAllProperties</code> option is set. In addition,
+ * aliases from the named schema will be removed if the flag <code>includeAliases</code>
+ * option is set.
+ *
+ * <li> Empty <code>schemaNS</code> and empty <code>propName</code> - All external properties in
+ * all schema are removed. Internal properties are also removed if the
+ * flag <code>doAllProperties</code> option is passed. Aliases are implicitly handled
+ * because the associated actuals are internal if the alias is.
+ * </ul>
+ *
+ * It is an error to pass an empty <code>schemaNS</code> and non-empty <code>propName</code>.
+ *
+ * @param xmp
+ * The XMP object containing the properties to be removed.
+ *
+ * @param schemaNS
+ * Optional schema namespace URI for the properties to be
+ * removed.
+ *
+ * @param propName
+ * Optional path expression for the property to be removed.
+ *
+ * @param doAllProperties Option flag to control the deletion: do internal properties in
+ * addition to external properties.
+ *
+ * @param includeAliases Option flag to control the deletion:
+ * Include aliases in the "named schema" case above.
+ * <em>Note:</em> Currently not supported.
+ * @throws XMPException Forwards the Exceptions from the metadata processing
+ */
+ public static void removeProperties(XMPMeta xmp, String schemaNS, String propName,
+ boolean doAllProperties, boolean includeAliases) throws XMPException
+ {
+ XMPUtilsImpl.removeProperties(xmp, schemaNS, propName, doAllProperties, includeAliases);
+ }
+
+
+
+ /**
+ * Alias without the new option <code>deleteEmptyValues</code>.
+ * @param source The source XMP object.
+ * @param dest The destination XMP object.
+ * @param doAllProperties Do internal properties in addition to external properties.
+ * @param replaceOldValues Replace the values of existing properties.
+ * @throws XMPException Forwards the Exceptions from the metadata processing
+ */
+ public static void appendProperties(XMPMeta source, XMPMeta dest, boolean doAllProperties,
+ boolean replaceOldValues) throws XMPException
+ {
+ appendProperties(source, dest, doAllProperties, replaceOldValues, false);
+ }
+
+
+ /**
+ * <p>Append properties from one XMP object to another.
+ *
+ * <p>XMPUtils#appendProperties was created to support the File Info dialog's Append button, and
+ * has been been generalized somewhat from those specific needs. It appends information from one
+ * XMP object (source) to another (dest). The default operation is to append only external
+ * properties that do not already exist in the destination. The flag
+ * <code>doAllProperties</code> can be used to operate on all properties, external and internal.
+ * The flag <code>replaceOldValues</code> option can be used to replace the values
+ * of existing properties. The notion of external
+ * versus internal applies only to top level properties. The keep-or-replace-old notion applies
+ * within structs and arrays as described below.
+ * <ul>
+ * <li>If <code>replaceOldValues</code> is true then the processing is restricted to the top
+ * level properties. The processed properties from the source (according to
+ * <code>doAllProperties</code>) are propagated to the destination,
+ * replacing any existing values.Properties in the destination that are not in the source
+ * are left alone.
+ *
+ * <li>If <code>replaceOldValues</code> is not passed then the processing is more complicated.
+ * Top level properties are added to the destination if they do not already exist.
+ * If they do exist but differ in form (simple/struct/array) then the destination is left alone.
+ * If the forms match, simple properties are left unchanged while structs and arrays are merged.
+ *
+ * <li>If <code>deleteEmptyValues</code> is passed then an empty value in the source XMP causes
+ * the corresponding destination XMP property to be deleted. The default is to treat empty
+ * values the same as non-empty values. An empty value is any of a simple empty string, an array
+ * with no items, or a struct with no fields. Qualifiers are ignored.
+ * </ul>
+ *
+ * <p>The detailed behavior is defined by the following pseudo-code:
+ * <blockquote>
+ * <pre>
+ * appendProperties ( sourceXMP, destXMP, doAllProperties,
+ * replaceOldValues, deleteEmptyValues ):
+ * for all source schema (top level namespaces):
+ * for all top level properties in sourceSchema:
+ * if doAllProperties or prop is external:
+ * appendSubtree ( sourceNode, destSchema, replaceOldValues, deleteEmptyValues )
+ *
+ * appendSubtree ( sourceNode, destParent, replaceOldValues, deleteEmptyValues ):
+ * if deleteEmptyValues and source value is empty:
+ * delete the corresponding child from destParent
+ * else if sourceNode not in destParent (by name):
+ * copy sourceNode's subtree to destParent
+ * else if replaceOld:
+ * delete subtree from destParent
+ * copy sourceNode's subtree to destParent
+ * else:
+ * // Already exists in dest and not replacing, merge structs and arrays
+ * if sourceNode and destNode forms differ:
+ * return, leave the destNode alone
+ * else if form is a struct:
+ * for each field in sourceNode:
+ * AppendSubtree ( sourceNode.field, destNode, replaceOldValues )
+ * else if form is an alt-text array:
+ * copy new items by "xml:lang" value into the destination
+ * else if form is an array:
+ * copy new items by value into the destination, ignoring order and duplicates
+ * </pre>
+ * </blockquote>
+ *
+ * <p><em>Note:</em> appendProperties can be expensive if replaceOldValues is not passed and
+ * the XMP contains large arrays. The array item checking described above is n-squared.
+ * Each source item is checked to see if it already exists in the destination,
+ * without regard to order or duplicates.
+ * <p>Simple items are compared by value and "xml:lang" qualifier, other qualifiers are ignored.
+ * Structs are recursively compared by field names, without regard to field order. Arrays are
+ * compared by recursively comparing all items.
+ *
+ * @param source The source XMP object.
+ * @param dest The destination XMP object.
+ * @param doAllProperties Do internal properties in addition to external properties.
+ * @param replaceOldValues Replace the values of existing properties.
+ * @param deleteEmptyValues Delete destination values if source property is empty.
+ * @throws XMPException Forwards the Exceptions from the metadata processing
+ */
+ public static void appendProperties(XMPMeta source, XMPMeta dest, boolean doAllProperties,
+ boolean replaceOldValues, boolean deleteEmptyValues) throws XMPException
+ {
+ XMPUtilsImpl.appendProperties(source, dest, doAllProperties, replaceOldValues,
+ deleteEmptyValues);
+ }
+
+
+ /**
+ * Convert from string to Boolean.
+ *
+ * @param value
+ * The string representation of the Boolean.
+ * @return The appropriate boolean value for the string. The checked values
+ * for <code>true</code> and <code>false</code> are:
+ * <ul>
+ * <li>{@link XMPConst#TRUESTR} and {@link XMPConst#FALSESTR}
+ * <li>&quot;t&quot; and &quot;f&quot;
+ * <li>&quot;on&quot; and &quot;off&quot;
+ * <li>&quot;yes&quot; and &quot;no&quot;
+ * <li>&quot;value <> 0&quot; and &quot;value == 0&quot;
+ * </ul>
+ * @throws XMPException If an empty string is passed.
+ */
+ public static boolean convertToBoolean(String value) throws XMPException
+ {
+ if (value == null || value.length() == 0)
+ {
+ throw new XMPException("Empty convert-string", XMPError.BADVALUE);
+ }
+ value = value.toLowerCase();
+
+ try
+ {
+ // First try interpretation as Integer (anything not 0 is true)
+ return Integer.parseInt(value) != 0;
+ }
+ catch (NumberFormatException e)
+ {
+ return
+ "true".equals(value) ||
+ "t".equals(value) ||
+ "on".equals(value) ||
+ "yes".equals(value);
+ }
+ }
+
+
+ /**
+ * Convert from boolean to string.
+ *
+ * @param value
+ * a boolean value
+ * @return The XMP string representation of the boolean. The values used are
+ * given by the constnts {@link XMPConst#TRUESTR} and
+ * {@link XMPConst#FALSESTR}.
+ */
+ public static String convertFromBoolean(boolean value)
+ {
+ return value ? XMPConst.TRUESTR : XMPConst.FALSESTR;
+ }
+
+
+ /**
+ * Converts a string value to an <code>int</code>.
+ *
+ * @param rawValue
+ * the string value
+ * @return Returns an int.
+ * @throws XMPException
+ * If the <code>rawValue</code> is <code>null</code> or empty or the
+ * conversion fails.
+ */
+ public static int convertToInteger(String rawValue) throws XMPException
+ {
+ try
+ {
+ if (rawValue == null || rawValue.length() == 0)
+ {
+ throw new XMPException("Empty convert-string", XMPError.BADVALUE);
+ }
+ if (rawValue.startsWith("0x"))
+ {
+ return Integer.parseInt(rawValue.substring(2), 16);
+ }
+ else
+ {
+ return Integer.parseInt(rawValue);
+ }
+ }
+ catch (NumberFormatException e)
+ {
+ throw new XMPException("Invalid integer string", XMPError.BADVALUE);
+ }
+ }
+
+
+ /**
+ * Convert from int to string.
+ *
+ * @param value
+ * an int value
+ * @return The string representation of the int.
+ */
+ public static String convertFromInteger(int value)
+ {
+ return String.valueOf(value);
+ }
+
+
+ /**
+ * Converts a string value to a <code>long</code>.
+ *
+ * @param rawValue
+ * the string value
+ * @return Returns a long.
+ * @throws XMPException
+ * If the <code>rawValue</code> is <code>null</code> or empty or the
+ * conversion fails.
+ */
+ public static long convertToLong(String rawValue) throws XMPException
+ {
+ try
+ {
+ if (rawValue == null || rawValue.length() == 0)
+ {
+ throw new XMPException("Empty convert-string", XMPError.BADVALUE);
+ }
+ if (rawValue.startsWith("0x"))
+ {
+ return Long.parseLong(rawValue.substring(2), 16);
+ }
+ else
+ {
+ return Long.parseLong(rawValue);
+ }
+ }
+ catch (NumberFormatException e)
+ {
+ throw new XMPException("Invalid long string", XMPError.BADVALUE);
+ }
+ }
+
+
+ /**
+ * Convert from long to string.
+ *
+ * @param value
+ * a long value
+ * @return The string representation of the long.
+ */
+ public static String convertFromLong(long value)
+ {
+ return String.valueOf(value);
+ }
+
+
+ /**
+ * Converts a string value to a <code>double</code>.
+ *
+ * @param rawValue
+ * the string value
+ * @return Returns a double.
+ * @throws XMPException
+ * If the <code>rawValue</code> is <code>null</code> or empty or the
+ * conversion fails.
+ */
+ public static double convertToDouble(String rawValue) throws XMPException
+ {
+ try
+ {
+ if (rawValue == null || rawValue.length() == 0)
+ {
+ throw new XMPException("Empty convert-string", XMPError.BADVALUE);
+ }
+ else
+ {
+ return Double.parseDouble(rawValue);
+ }
+ }
+ catch (NumberFormatException e)
+ {
+ throw new XMPException("Invalid double string", XMPError.BADVALUE);
+ }
+ }
+
+
+ /**
+ * Convert from long to string.
+ *
+ * @param value
+ * a long value
+ * @return The string representation of the long.
+ */
+ public static String convertFromDouble(double value)
+ {
+ return String.valueOf(value);
+ }
+
+
+ /**
+ * Converts a string value to an <code>XMPDateTime</code>.
+ *
+ * @param rawValue
+ * the string value
+ * @return Returns an <code>XMPDateTime</code>-object.
+ * @throws XMPException
+ * If the <code>rawValue</code> is <code>null</code> or empty or the
+ * conversion fails.
+ */
+ public static XMPDateTime convertToDate(String rawValue) throws XMPException
+ {
+ if (rawValue == null || rawValue.length() == 0)
+ {
+ throw new XMPException("Empty convert-string", XMPError.BADVALUE);
+ }
+ else
+ {
+ return ISO8601Converter.parse(rawValue);
+ }
+ }
+
+
+ /**
+ * Convert from <code>XMPDateTime</code> to string.
+ *
+ * @param value
+ * an <code>XMPDateTime</code>
+ * @return The string representation of the long.
+ */
+ public static String convertFromDate(XMPDateTime value)
+ {
+ return ISO8601Converter.render(value);
+ }
+
+
+ /**
+ * Convert from a byte array to a base64 encoded string.
+ *
+ * @param buffer
+ * the byte array to be converted
+ * @return Returns the base64 string.
+ */
+ public static String encodeBase64(byte[] buffer)
+ {
+ return new String(Base64.encode(buffer));
+ }
+
+
+ /**
+ * Decode from Base64 encoded string to raw data.
+ *
+ * @param base64String
+ * a base64 encoded string
+ * @return Returns a byte array containg the decoded string.
+ * @throws XMPException Thrown if the given string is not property base64 encoded
+ */
+ public static byte[] decodeBase64(String base64String) throws XMPException
+ {
+ try
+ {
+ return Base64.decode(base64String.getBytes());
+ }
+ catch (Throwable e)
+ {
+ throw new XMPException("Invalid base64 string", XMPError.BADVALUE, e);
+ }
+ }
+} \ No newline at end of file
diff --git a/java/XMPCore/src/com/adobe/xmp/XMPVersionInfo.java b/java/XMPCore/src/com/adobe/xmp/XMPVersionInfo.java
new file mode 100644
index 0000000..ac8fa32
--- /dev/null
+++ b/java/XMPCore/src/com/adobe/xmp/XMPVersionInfo.java
@@ -0,0 +1,45 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+package com.adobe.xmp;
+
+/**
+ * XMP Toolkit Version Information
+ * <p>
+ * Version information for the XMP toolkit is stored in the jar-library and available through a
+ * runtime call, {@link XMPMetaFactory#getVersionInfo()}, addition static version numbers are
+ * defined in "version.properties".
+ *
+ * @since 23.01.2006
+ */
+public interface XMPVersionInfo
+{
+ /** @return Returns the primary release number, the "1" in version "1.2.3". */
+ int getMajor();
+
+
+ /** @return Returns the secondary release number, the "2" in version "1.2.3". */
+ int getMinor();
+
+
+ /** @return Returns the tertiary release number, the "3" in version "1.2.3". */
+ int getMicro();
+
+
+ /** @return Returns true if this is a debug build. */
+ boolean isDebug();
+
+
+ /** @return Returns a rolling build number, monotonically increasing in a release. */
+ int getBuild();
+
+
+ /** @return Returns a comprehensive version information string. */
+ String getMessage();
+} \ No newline at end of file
diff --git a/java/XMPCore/src/com/adobe/xmp/impl/Base64.java b/java/XMPCore/src/com/adobe/xmp/impl/Base64.java
new file mode 100644
index 0000000..c47d08c
--- /dev/null
+++ b/java/XMPCore/src/com/adobe/xmp/impl/Base64.java
@@ -0,0 +1,251 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2001-2005 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+package com.adobe.xmp.impl;
+
+
+
+
+/**
+ * A utility class to perform base64 encoding and decoding as specified
+ * in RFC-1521. See also RFC 1421.
+ *
+ * @version $Revision: 1.4 $
+ */
+public class Base64
+{
+ /** marker for invalid bytes */
+ private static final byte INVALID = -1;
+ /** marker for accepted whitespace bytes */
+ private static final byte WHITESPACE = -2;
+ /** marker for an equal symbol */
+ private static final byte EQUAL = -3;
+
+ /** */
+ private static byte[] base64 = {
+ (byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', // 0 to 3
+ (byte) 'E', (byte) 'F', (byte) 'G', (byte) 'H', // 4 to 7
+ (byte) 'I', (byte) 'J', (byte) 'K', (byte) 'L', // 8 to 11
+ (byte) 'M', (byte) 'N', (byte) 'O', (byte) 'P', // 11 to 15
+ (byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', // 16 to 19
+ (byte) 'U', (byte) 'V', (byte) 'W', (byte) 'X', // 20 to 23
+ (byte) 'Y', (byte) 'Z', (byte) 'a', (byte) 'b', // 24 to 27
+ (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f', // 28 to 31
+ (byte) 'g', (byte) 'h', (byte) 'i', (byte) 'j', // 32 to 35
+ (byte) 'k', (byte) 'l', (byte) 'm', (byte) 'n', // 36 to 39
+ (byte) 'o', (byte) 'p', (byte) 'q', (byte) 'r', // 40 to 43
+ (byte) 's', (byte) 't', (byte) 'u', (byte) 'v', // 44 to 47
+ (byte) 'w', (byte) 'x', (byte) 'y', (byte) 'z', // 48 to 51
+ (byte) '0', (byte) '1', (byte) '2', (byte) '3', // 52 to 55
+ (byte) '4', (byte) '5', (byte) '6', (byte) '7', // 56 to 59
+ (byte) '8', (byte) '9', (byte) '+', (byte) '/' // 60 to 63
+ };
+ /** */
+ private static byte[] ascii = new byte[255];
+ /** */
+ static {
+ // not valid bytes
+ for (int idx = 0; idx < 255; idx++)
+ {
+ ascii[idx] = INVALID;
+ }
+ // valid bytes
+ for (int idx = 0; idx < base64.length; idx++)
+ {
+ ascii[base64[idx]] = (byte) idx;
+ }
+ // whitespaces
+ ascii[0x09] = WHITESPACE;
+ ascii[0x0A] = WHITESPACE;
+ ascii[0x0D] = WHITESPACE;
+ ascii[0x20] = WHITESPACE;
+
+ // trailing equals
+ ascii[0x3d] = EQUAL;
+ }
+
+
+ /**
+ * Encode the given byte[].
+ *
+ * @param src the source string.
+ * @return the base64-encoded data.
+ */
+ public static final byte[] encode(byte[] src)
+ {
+ return encode(src, 0);
+ }
+
+
+ /**
+ * Encode the given byte[].
+ *
+ * @param src the source string.
+ * @param lineFeed a linefeed is added after <code>linefeed</code> characters;
+ * must be dividable by four; 0 means no linefeeds
+ * @return the base64-encoded data.
+ */
+ public static final byte[] encode(byte[] src, int lineFeed)
+ {
+ // linefeed must be dividable by 4
+ lineFeed = lineFeed / 4 * 4;
+ if (lineFeed < 0)
+ {
+ lineFeed = 0;
+ }
+
+ // determine code length
+ int codeLength = ((src.length + 2) / 3) * 4;
+ if (lineFeed > 0)
+ {
+ codeLength += (codeLength - 1) / lineFeed;
+ }
+
+ byte[] dst = new byte[codeLength];
+ int bits24;
+ int bits6;
+ //
+ // Do 3-byte to 4-byte conversion + 0-63 to ascii printable conversion
+ //
+ int didx = 0;
+ int sidx = 0;
+ int lf = 0;
+ while (sidx + 3 <= src.length)
+ {
+ bits24 = (src[sidx++] & 0xFF) << 16;
+ bits24 |= (src[sidx++] & 0xFF) << 8;
+ bits24 |= (src[sidx++] & 0xFF) << 0;
+ bits6 = (bits24 & 0x00FC0000) >> 18;
+ dst[didx++] = base64[bits6];
+ bits6 = (bits24 & 0x0003F000) >> 12;
+ dst[didx++] = base64[bits6];
+ bits6 = (bits24 & 0x00000FC0) >> 6;
+ dst[didx++] = base64[bits6];
+ bits6 = (bits24 & 0x0000003F);
+ dst[didx++] = base64[bits6];
+
+ lf += 4;
+ if (didx < codeLength && lineFeed > 0 && lf % lineFeed == 0)
+ {
+ dst[didx++] = 0x0A;
+ }
+ }
+ if (src.length - sidx == 2)
+ {
+ bits24 = (src[sidx ] & 0xFF) << 16;
+ bits24 |= (src[sidx + 1] & 0xFF) << 8;
+ bits6 = (bits24 & 0x00FC0000) >> 18;
+ dst[didx++] = base64[bits6];
+ bits6 = (bits24 & 0x0003F000) >> 12;
+ dst[didx++] = base64[bits6];
+ bits6 = (bits24 & 0x00000FC0) >> 6;
+ dst[didx++] = base64[bits6];
+ dst[didx++] = (byte) '=';
+ }
+ else if (src.length - sidx == 1)
+ {
+ bits24 = (src[sidx] & 0xFF) << 16;
+ bits6 = (bits24 & 0x00FC0000) >> 18;
+ dst[didx++] = base64[bits6];
+ bits6 = (bits24 & 0x0003F000) >> 12;
+ dst[didx++] = base64[bits6];
+ dst[didx++] = (byte) '=';
+ dst[didx++] = (byte) '=';
+ }
+ return dst;
+ }
+
+
+ /**
+ * Encode the given string.
+ * @param src the source string.
+ * @return the base64-encoded string.
+ */
+ public static final String encode(String src)
+ {
+ return new String(encode(src.getBytes()));
+ }
+
+
+ /**
+ * Decode the given byte[].
+ *
+ * @param src
+ * the base64-encoded data.
+ * @return the decoded data.
+ * @throws IllegalArgumentException Thrown if the base 64 strings contains non-valid characters,
+ * beside the bas64 chars, LF, CR, tab and space are accepted.
+ */
+ public static final byte[] decode(byte[] src) throws IllegalArgumentException
+ {
+ //
+ // Do ascii printable to 0-63 conversion.
+ //
+ int sidx;
+ int srcLen = 0;
+ for (sidx = 0; sidx < src.length; sidx++)
+ {
+ byte val = ascii[src[sidx]];
+ if (val >= 0)
+ {
+ src[srcLen++] = val;
+ }
+ else if (val == INVALID)
+ {
+ throw new IllegalArgumentException("Invalid base 64 string");
+ }
+ }
+
+ //
+ // Trim any padding.
+ //
+ while (srcLen > 0 && src[srcLen - 1] == EQUAL)
+ {
+ srcLen--;
+ }
+ byte[] dst = new byte[srcLen * 3 / 4];
+
+ //
+ // Do 4-byte to 3-byte conversion.
+ //
+ int didx;
+ for (sidx = 0, didx = 0; didx < dst.length - 2; sidx += 4, didx += 3)
+ {
+ dst[didx ] = (byte) (((src[sidx ] << 2) & 0xFF)
+ | ((src[sidx + 1] >>> 4) & 0x03));
+ dst[didx + 1] = (byte) (((src[sidx + 1] << 4) & 0xFF)
+ | ((src[sidx + 2] >>> 2) & 0x0F));
+ dst[didx + 2] = (byte) (((src[sidx + 2] << 6) & 0xFF)
+ | ((src[sidx + 3]) & 0x3F));
+ }
+ if (didx < dst.length)
+ {
+ dst[didx] = (byte) (((src[sidx ] << 2) & 0xFF)
+ | ((src[sidx + 1] >>> 4) & 0x03));
+ }
+ if (++didx < dst.length)
+ {
+ dst[didx] = (byte) (((src[sidx + 1] << 4) & 0xFF)
+ | ((src[sidx + 2] >>> 2) & 0x0F));
+ }
+ return dst;
+ }
+
+
+ /**
+ * Decode the given string.
+ *
+ * @param src the base64-encoded string.
+ * @return the decoded string.
+ */
+ public static final String decode(String src)
+ {
+ return new String(decode(src.getBytes()));
+ }
+}
diff --git a/java/XMPCore/src/com/adobe/xmp/impl/ByteBuffer.java b/java/XMPCore/src/com/adobe/xmp/impl/ByteBuffer.java
new file mode 100644
index 0000000..c8ef03f
--- /dev/null
+++ b/java/XMPCore/src/com/adobe/xmp/impl/ByteBuffer.java
@@ -0,0 +1,326 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+
+
+package com.adobe.xmp.impl;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+
+/**
+ * Byte buffer container including length of valid data.
+ *
+ * @since 11.10.2006
+ */
+public class ByteBuffer
+{
+ /** */
+ private byte[] buffer;
+ /** */
+ private int length;
+ /** */
+ private String encoding = null;
+
+
+ /**
+ * @param initialCapacity the initial capacity for this buffer
+ */
+ public ByteBuffer(int initialCapacity)
+ {
+ this.buffer = new byte[initialCapacity];
+ this.length = 0;
+ }
+
+
+ /**
+ * @param buffer a byte array that will be wrapped with <code>ByteBuffer</code>.
+ */
+ public ByteBuffer(byte[] buffer)
+ {
+ this.buffer = buffer;
+ this.length = buffer.length;
+ }
+
+
+ /**
+ * @param buffer a byte array that will be wrapped with <code>ByteBuffer</code>.
+ * @param length the length of valid bytes in the array
+ */
+ public ByteBuffer(byte[] buffer, int length)
+ {
+ if (length > buffer.length)
+ {
+ throw new ArrayIndexOutOfBoundsException("Valid length exceeds the buffer length.");
+ }
+ this.buffer = buffer;
+ this.length = length;
+ }
+
+
+ /**
+ * Loads the stream into a buffer.
+ *
+ * @param in an InputStream
+ * @throws IOException If the stream cannot be read.
+ */
+ public ByteBuffer(InputStream in) throws IOException
+ {
+ // load stream into buffer
+ int chunk = 16384;
+ this.length = 0;
+ this.buffer = new byte[chunk];
+
+ int read;
+ while ((read = in.read(this.buffer, this.length, chunk)) > 0)
+ {
+ this.length += read;
+ if (read == chunk)
+ {
+ ensureCapacity(length + chunk);
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+
+
+ /**
+ * @param buffer a byte array that will be wrapped with <code>ByteBuffer</code>.
+ * @param offset the offset of the provided buffer.
+ * @param length the length of valid bytes in the array
+ */
+ public ByteBuffer(byte[] buffer, int offset, int length)
+ {
+ if (length > buffer.length - offset)
+ {
+ throw new ArrayIndexOutOfBoundsException("Valid length exceeds the buffer length.");
+ }
+ this.buffer = new byte[length];
+ System.arraycopy(buffer, offset, this.buffer, 0, length);
+ this.length = length;
+ }
+
+
+ /**
+ * @return Returns a byte stream that is limited to the valid amount of bytes.
+ */
+ public InputStream getByteStream()
+ {
+ return new ByteArrayInputStream(buffer, 0, length);
+ }
+
+
+ /**
+ * @return Returns the length, that means the number of valid bytes, of the buffer;
+ * the inner byte array might be bigger than that.
+ */
+ public int length()
+ {
+ return length;
+ }
+
+
+// /**
+// * <em>Note:</em> Only the byte up to length are valid!
+// * @return Returns the inner byte buffer.
+// */
+// public byte[] getBuffer()
+// {
+// return buffer;
+// }
+
+
+ /**
+ * @param index the index to retrieve the byte from
+ * @return Returns a byte from the buffer
+ */
+ public byte byteAt(int index)
+ {
+ if (index < length)
+ {
+ return buffer[index];
+ }
+ else
+ {
+ throw new IndexOutOfBoundsException("The index exceeds the valid buffer area");
+ }
+ }
+
+
+ /**
+ * @param index the index to retrieve a byte as int or char.
+ * @return Returns a byte from the buffer
+ */
+ public int charAt(int index)
+ {
+ if (index < length)
+ {
+ return buffer[index] & 0xFF;
+ }
+ else
+ {
+ throw new IndexOutOfBoundsException("The index exceeds the valid buffer area");
+ }
+ }
+
+
+ /**
+ * Appends a byte to the buffer.
+ * @param b a byte
+ */
+ public void append(byte b)
+ {
+ ensureCapacity(length + 1);
+ buffer[length++] = b;
+ }
+
+
+ /**
+ * Appends a byte array or part of to the buffer.
+ *
+ * @param bytes a byte array
+ * @param offset an offset with
+ * @param len
+ */
+ public void append(byte[] bytes, int offset, int len)
+ {
+ ensureCapacity(length + len);
+ System.arraycopy(bytes, offset, buffer, length, len);
+ length += len;
+ }
+
+
+ /**
+ * Append a byte array to the buffer
+ * @param bytes a byte array
+ */
+ public void append(byte[] bytes)
+ {
+ append(bytes, 0, bytes.length);
+ }
+
+
+ /**
+ * Append another buffer to this buffer.
+ * @param anotherBuffer another <code>ByteBuffer</code>
+ */
+ public void append(ByteBuffer anotherBuffer)
+ {
+ append(anotherBuffer.buffer, 0, anotherBuffer.length);
+ }
+
+
+ /**
+ * Detects the encoding of the byte buffer, stores and returns it.
+ * Only UTF-8, UTF-16LE/BE and UTF-32LE/BE are recognized.
+ * <em>Note:</em> UTF-32 flavors are not supported by Java, the XML-parser will complain.
+ *
+ * @return Returns the encoding string.
+ */
+ public String getEncoding()
+ {
+ if (encoding == null)
+ {
+ // needs four byte at maximum to determine encoding
+ if (length < 2)
+ {
+ // only one byte length must be UTF-8
+ encoding = "UTF-8";
+ }
+ else if (buffer[0] == 0)
+ {
+ // These cases are:
+ // 00 nn -- -- - Big endian UTF-16
+ // 00 00 00 nn - Big endian UTF-32
+ // 00 00 FE FF - Big endian UTF 32
+
+ if (length < 4 || buffer[1] != 0)
+ {
+ encoding = "UTF-16BE";
+ }
+ else if ((buffer[2] & 0xFF) == 0xFE && (buffer[3] & 0xFF) == 0xFF)
+ {
+ encoding = "UTF-32BE";
+ }
+ else
+ {
+ encoding = "UTF-32";
+ }
+ }
+ else if ((buffer[0] & 0xFF) < 0x80)
+ {
+ // These cases are:
+ // nn mm -- -- - UTF-8, includes EF BB BF case
+ // nn 00 -- -- - Little endian UTF-16
+
+ if (buffer[1] != 0)
+ {
+ encoding = "UTF-8";
+ }
+ else if (length < 4 || buffer[2] != 0)
+ {
+ encoding = "UTF-16LE";
+ }
+ else
+ {
+ encoding = "UTF-32LE";
+ }
+ }
+ else
+ {
+ // These cases are:
+ // EF BB BF -- - UTF-8
+ // FE FF -- -- - Big endian UTF-16
+ // FF FE 00 00 - Little endian UTF-32
+ // FF FE -- -- - Little endian UTF-16
+
+ if ((buffer[0] & 0xFF) == 0xEF)
+ {
+ encoding = "UTF-8";
+ }
+ else if ((buffer[0] & 0xFF) == 0xFE)
+ {
+ encoding = "UTF-16"; // in fact BE
+ }
+ else if (length < 4 || buffer[2] != 0)
+ {
+ encoding = "UTF-16"; // in fact LE
+ }
+ else
+ {
+ encoding = "UTF-32"; // in fact LE
+ }
+ }
+ }
+
+ return encoding;
+ }
+
+
+ /**
+ * Ensures the requested capacity by increasing the buffer size when the
+ * current length is exceeded.
+ *
+ * @param requestedLength requested new buffer length
+ */
+ private void ensureCapacity(int requestedLength)
+ {
+ if (requestedLength > buffer.length)
+ {
+ byte[] oldBuf = buffer;
+ buffer = new byte[oldBuf.length * 2];
+ System.arraycopy(oldBuf, 0, buffer, 0, oldBuf.length);
+ }
+ }
+} \ No newline at end of file
diff --git a/java/XMPCore/src/com/adobe/xmp/impl/CountOutputStream.java b/java/XMPCore/src/com/adobe/xmp/impl/CountOutputStream.java
new file mode 100644
index 0000000..c70b653
--- /dev/null
+++ b/java/XMPCore/src/com/adobe/xmp/impl/CountOutputStream.java
@@ -0,0 +1,79 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+package com.adobe.xmp.impl;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+
+/**
+ * An <code>OutputStream</code> that counts the written bytes.
+ *
+ * @since 08.11.2006
+ */
+public final class CountOutputStream extends OutputStream
+{
+ /** the decorated output stream */
+ private final OutputStream out;
+ /** the byte counter */
+ private int bytesWritten = 0;
+
+
+ /**
+ * Constructor with providing the output stream to decorate.
+ * @param out an <code>OutputStream</code>
+ */
+ CountOutputStream(OutputStream out)
+ {
+ this.out = out;
+ }
+
+
+ /**
+ * Counts the written bytes.
+ * @see java.io.OutputStream#write(byte[], int, int)
+ */
+ public void write(byte[] buf, int off, int len) throws IOException
+ {
+ out.write(buf, off, len);
+ bytesWritten += len;
+ }
+
+
+ /**
+ * Counts the written bytes.
+ * @see java.io.OutputStream#write(byte[])
+ */
+ public void write(byte[] buf) throws IOException
+ {
+ out.write(buf);
+ bytesWritten += buf.length;
+ }
+
+
+ /**
+ * Counts the written bytes.
+ * @see java.io.OutputStream#write(int)
+ */
+ public void write(int b) throws IOException
+ {
+ out.write(b);
+ bytesWritten++;
+ }
+
+
+ /**
+ * @return the bytesWritten
+ */
+ public int getBytesWritten()
+ {
+ return bytesWritten;
+ }
+} \ No newline at end of file
diff --git a/java/XMPCore/src/com/adobe/xmp/impl/FixASCIIControlsReader.java b/java/XMPCore/src/com/adobe/xmp/impl/FixASCIIControlsReader.java
new file mode 100644
index 0000000..d248e0d
--- /dev/null
+++ b/java/XMPCore/src/com/adobe/xmp/impl/FixASCIIControlsReader.java
@@ -0,0 +1,214 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+package com.adobe.xmp.impl;
+
+import java.io.IOException;
+import java.io.PushbackReader;
+import java.io.Reader;
+
+
+/**
+ * @since 22.08.2006
+ */
+public class FixASCIIControlsReader extends PushbackReader
+{
+ /** */
+ private static final int STATE_START = 0;
+ /** */
+ private static final int STATE_AMP = 1;
+ /** */
+ private static final int STATE_HASH = 2;
+ /** */
+ private static final int STATE_HEX = 3;
+ /** */
+ private static final int STATE_DIG1 = 4;
+ /** */
+ private static final int STATE_ERROR = 5;
+ /** */
+ private static final int BUFFER_SIZE = 8;
+ /** the state of the automaton */
+ private int state = STATE_START;
+ /** the result of the escaping sequence */
+ private int control = 0;
+ /** count the digits of the sequence */
+ private int digits = 0;
+
+ /**
+ * The look-ahead size is 6 at maximum (&amp;#xAB;)
+ * @see PushbackReader#PushbackReader(Reader, int)
+ * @param in a Reader
+ */
+ public FixASCIIControlsReader(Reader in)
+ {
+ super(in, BUFFER_SIZE);
+ }
+
+
+ /**
+ * @see Reader#read(char[], int, int)
+ */
+ public int read(char[] cbuf, int off, int len) throws IOException
+ {
+ int readAhead = 0;
+ int read = 0;
+ int pos = off;
+ char[] readAheadBuffer = new char[BUFFER_SIZE];
+
+ boolean available = true;
+ while (available && read < len)
+ {
+ available = super.read(readAheadBuffer, readAhead, 1) == 1;
+ if (available)
+ {
+ char c = processChar(readAheadBuffer[readAhead]);
+ if (state == STATE_START)
+ {
+ // replace control chars with space
+ if (Utils.isControlChar(c))
+ {
+ c = ' ';
+ }
+ cbuf[pos++] = c;
+ readAhead = 0;
+ read++;
+ }
+ else if (state == STATE_ERROR)
+ {
+ unread(readAheadBuffer, 0, readAhead + 1);
+ readAhead = 0;
+ }
+ else
+ {
+ readAhead++;
+ }
+ }
+ else if (readAhead > 0)
+ {
+ // handles case when file ends within excaped sequence
+ unread(readAheadBuffer, 0, readAhead);
+ state = STATE_ERROR;
+ readAhead = 0;
+ available = true;
+ }
+ }
+
+
+ return read > 0 || available ? read : -1;
+ }
+
+
+ /**
+ * Processes numeric escaped chars to find out if they are a control character.
+ * @param ch a char
+ * @return Returns the char directly or as replacement for the escaped sequence.
+ */
+ private char processChar(char ch)
+ {
+ switch (state)
+ {
+ case STATE_START:
+ if (ch == '&')
+ {
+ state = STATE_AMP;
+ }
+ return ch;
+
+ case STATE_AMP:
+ if (ch == '#')
+ {
+ state = STATE_HASH;
+ }
+ else
+ {
+ state = STATE_ERROR;
+ }
+ return ch;
+
+ case STATE_HASH:
+ if (ch == 'x')
+ {
+ control = 0;
+ digits = 0;
+ state = STATE_HEX;
+ }
+ else if ('0' <= ch && ch <= '9')
+ {
+ control = Character.digit(ch, 10);
+ digits = 1;
+ state = STATE_DIG1;
+ }
+ else
+ {
+ state = STATE_ERROR;
+ }
+ return ch;
+
+ case STATE_DIG1:
+ if ('0' <= ch && ch <= '9')
+ {
+ control = control * 10 + Character.digit(ch, 10);
+ digits++;
+ if (digits <= 5)
+ {
+ state = STATE_DIG1;
+ }
+ else
+ {
+ state = STATE_ERROR; // sequence too long
+ }
+ }
+ else if (ch == ';' && Utils.isControlChar((char) control))
+ {
+ state = STATE_START;
+ return (char) control;
+ }
+ else
+ {
+ state = STATE_ERROR;
+ }
+ return ch;
+
+ case STATE_HEX:
+ if (('0' <= ch && ch <= '9') ||
+ ('a' <= ch && ch <= 'f') ||
+ ('A' <= ch && ch <= 'F'))
+ {
+ control = control * 16 + Character.digit(ch, 16);
+ digits++;
+ if (digits <= 4)
+ {
+ state = STATE_HEX;
+ }
+ else
+ {
+ state = STATE_ERROR; // sequence too long
+ }
+ }
+ else if (ch == ';' && Utils.isControlChar((char) control))
+ {
+ state = STATE_START;
+ return (char) control;
+ }
+ else
+ {
+ state = STATE_ERROR;
+ }
+ return ch;
+
+ case STATE_ERROR:
+ state = STATE_START;
+ return ch;
+
+ default:
+ // not reachable
+ return ch;
+ }
+ }
+}
diff --git a/java/XMPCore/src/com/adobe/xmp/impl/ISO8601Converter.java b/java/XMPCore/src/com/adobe/xmp/impl/ISO8601Converter.java
new file mode 100644
index 0000000..2d1939d
--- /dev/null
+++ b/java/XMPCore/src/com/adobe/xmp/impl/ISO8601Converter.java
@@ -0,0 +1,503 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+package com.adobe.xmp.impl;
+
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.util.Locale;
+import java.util.SimpleTimeZone;
+
+import com.adobe.xmp.XMPDateTime;
+import com.adobe.xmp.XMPError;
+import com.adobe.xmp.XMPException;
+
+
+/**
+ * Converts between ISO 8601 Strings and <code>Calendar</code> with millisecond resolution.
+ *
+ * @since 16.02.2006
+ */
+public final class ISO8601Converter
+{
+ /** Hides public constructor */
+ private ISO8601Converter()
+ {
+ // EMPTY
+ }
+
+
+ /**
+ * Converts an ISO 8601 string to an <code>XMPDateTime</code>.
+ *
+ * Parse a date according to ISO 8601 and
+ * http://www.w3.org/TR/NOTE-datetime:
+ * <ul>
+ * <li>YYYY
+ * <li>YYYY-MM
+ * <li>YYYY-MM-DD
+ * <li>YYYY-MM-DDThh:mmTZD
+ * <li>YYYY-MM-DDThh:mm:ssTZD
+ * <li>YYYY-MM-DDThh:mm:ss.sTZD
+ * </ul>
+ *
+ * Data fields:
+ * <ul>
+ * <li>YYYY = four-digit year
+ * <li>MM = two-digit month (01=January, etc.)
+ * <li>DD = two-digit day of month (01 through 31)
+ * <li>hh = two digits of hour (00 through 23)
+ * <li>mm = two digits of minute (00 through 59)
+ * <li>ss = two digits of second (00 through 59)
+ * <li>s = one or more digits representing a decimal fraction of a second
+ * <li>TZD = time zone designator (Z or +hh:mm or -hh:mm)
+ * </ul>
+ *
+ * Note that ISO 8601 does not seem to allow years less than 1000 or greater
+ * than 9999. We allow any year, even negative ones. The year is formatted
+ * as "%.4d".
+ * <p>
+ * <em>Note:</em> Tolerate missing TZD, assume is UTC. Photoshop 8 writes
+ * dates like this for exif:GPSTimeStamp.<br>
+ * <em>Note:</em> Tolerate missing date portion, in case someone foolishly
+ * writes a time-only value that way.
+ *
+ * @param iso8601String a date string that is ISO 8601 conform.
+ * @return Returns a <code>Calendar</code>.
+ * @throws XMPException Is thrown when the string is non-conform.
+ */
+ public static XMPDateTime parse(String iso8601String) throws XMPException
+ {
+ return parse(iso8601String, new XMPDateTimeImpl());
+ }
+
+
+ /**
+ * @param iso8601String a date string that is ISO 8601 conform.
+ * @param binValue an existing XMPDateTime to set with the parsed date
+ * @return Returns an XMPDateTime-object containing the ISO8601-date.
+ * @throws XMPException Is thrown when the string is non-conform.
+ */
+ public static XMPDateTime parse(String iso8601String, XMPDateTime binValue) throws XMPException
+ {
+ ParameterAsserts.assertNotNull(iso8601String);
+
+ ParseState input = new ParseState(iso8601String);
+ int value;
+
+ boolean timeOnly =
+ input.ch(0) == 'T' ||
+ (input.length() >= 2 && input.ch(1) == ':' ||
+ (input.length() >= 3 && input.ch(2) == ':'));
+
+ if (!timeOnly)
+ {
+ if (input.ch(0) == '-')
+ {
+ input.skip();
+ }
+
+
+ // Extract the year.
+ value = input.gatherInt("Invalid year in date string", 9999);
+ if (input.hasNext() && input.ch() != '-')
+ {
+ throw new XMPException("Invalid date string, after year", XMPError.BADVALUE);
+ }
+
+ if (input.ch(0) == '-')
+ {
+ value = -value;
+ }
+ binValue.setYear(value);
+ if (!input.hasNext())
+ {
+ return binValue;
+ }
+ input.skip();
+
+
+ // Extract the month.
+ value = input.gatherInt("Invalid month in date string", 12);
+ if (input.hasNext() && input.ch() != '-')
+ {
+ throw new XMPException("Invalid date string, after month", XMPError.BADVALUE);
+ }
+ binValue.setMonth(value);
+ if (!input.hasNext())
+ {
+ return binValue;
+ }
+ input.skip();
+
+
+ // Extract the day.
+ value = input.gatherInt("Invalid day in date string", 31);
+ if (input.hasNext() && input.ch() != 'T')
+ {
+ throw new XMPException("Invalid date string, after day", XMPError.BADVALUE);
+ }
+ binValue.setDay(value);
+ if (!input.hasNext())
+ {
+ return binValue;
+ }
+ }
+ else
+ {
+ // set default day and month in the year 0000
+ binValue.setMonth(1);
+ binValue.setDay(1);
+ }
+
+ if (input.ch() == 'T')
+ {
+ input.skip();
+ }
+ else if (!timeOnly)
+ {
+ throw new XMPException("Invalid date string, missing 'T' after date",
+ XMPError.BADVALUE);
+ }
+
+
+ // Extract the hour.
+ value = input.gatherInt("Invalid hour in date string", 23);
+ if (input.ch() != ':')
+ {
+ throw new XMPException("Invalid date string, after hour", XMPError.BADVALUE);
+ }
+ binValue.setHour(value);
+
+ // Don't check for done, we have to work up to the time zone.
+ input.skip();
+
+
+ // Extract the minute.
+ value = input.gatherInt("Invalid minute in date string", 59);
+ if (input.hasNext() &&
+ input.ch() != ':' && input.ch() != 'Z' && input.ch() != '+' && input.ch() != '-')
+ {
+ throw new XMPException("Invalid date string, after minute", XMPError.BADVALUE);
+ }
+ binValue.setMinute(value);
+
+ if (input.ch() == ':')
+ {
+ input.skip();
+ value = input.gatherInt("Invalid whole seconds in date string", 59);
+ if (input.hasNext() && input.ch() != '.' && input.ch() != 'Z' &&
+ input.ch() != '+' && input.ch() != '-')
+ {
+ throw new XMPException("Invalid date string, after whole seconds",
+ XMPError.BADVALUE);
+ }
+ binValue.setSecond(value);
+ if (input.ch() == '.')
+ {
+ input.skip();
+ int digits = input.pos();
+ value = input.gatherInt("Invalid fractional seconds in date string", 999999999);
+ if (input.ch() != 'Z' && input.ch() != '+' && input.ch() != '-')
+ {
+ throw new XMPException("Invalid date string, after fractional second",
+ XMPError.BADVALUE);
+ }
+ digits = input.pos() - digits;
+ for (; digits > 9; --digits)
+ {
+ value = value / 10;
+ }
+ for (; digits < 9; ++digits)
+ {
+ value = value * 10;
+ }
+ binValue.setNanoSecond(value);
+ }
+ }
+
+ int tzSign = 0;
+ int tzHour = 0;
+ int tzMinute = 0;
+ if (input.ch() == 'Z')
+ {
+ input.skip();
+ }
+ else if (input.hasNext())
+ {
+ if (input.ch() == '+')
+ {
+ tzSign = 1;
+ }
+ else if (input.ch() == '-')
+ {
+ tzSign = -1;
+ }
+ else
+ {
+ throw new XMPException("Time zone must begin with 'Z', '+', or '-'",
+ XMPError.BADVALUE);
+ }
+
+ input.skip();
+ // Extract the time zone hour.
+ tzHour = input.gatherInt("Invalid time zone hour in date string", 23);
+ if (input.ch() != ':')
+ {
+ throw new XMPException("Invalid date string, after time zone hour",
+ XMPError.BADVALUE);
+ }
+ input.skip();
+
+ // Extract the time zone minute.
+ tzMinute = input.gatherInt("Invalid time zone minute in date string", 59);
+ }
+
+ // create a corresponding TZ and set it time zone
+ int offset = (tzHour * 3600 * 1000 + tzMinute * 60 * 1000) * tzSign;
+ binValue.setTimeZone(new SimpleTimeZone(offset, ""));
+
+
+ if (input.hasNext())
+ {
+ throw new XMPException(
+ "Invalid date string, extra chars at end", XMPError.BADVALUE);
+ }
+
+ return binValue;
+ }
+
+
+ /**
+ * Converts a <code>Calendar</code> into an ISO 8601 string.
+ * Format a date according to ISO 8601 and http://www.w3.org/TR/NOTE-datetime:
+ * <ul>
+ * <li>YYYY
+ * <li>YYYY-MM
+ * <li>YYYY-MM-DD
+ * <li>YYYY-MM-DDThh:mmTZD
+ * <li>YYYY-MM-DDThh:mm:ssTZD
+ * <li>YYYY-MM-DDThh:mm:ss.sTZD
+ * </ul>
+ *
+ * Data fields:
+ * <ul>
+ * <li>YYYY = four-digit year
+ * <li>MM = two-digit month (01=January, etc.)
+ * <li>DD = two-digit day of month (01 through 31)
+ * <li>hh = two digits of hour (00 through 23)
+ * <li>mm = two digits of minute (00 through 59)
+ * <li>ss = two digits of second (00 through 59)
+ * <li>s = one or more digits representing a decimal fraction of a second
+ * <li>TZD = time zone designator (Z or +hh:mm or -hh:mm)
+ * </ul>
+ * <p>
+ * <em>Note:</em> ISO 8601 does not seem to allow years less than 1000 or greater than 9999.
+ * We allow any year, even negative ones. The year is formatted as "%.4d".<p>
+ * <em>Note:</em> Fix for bug 1269463 (silently fix out of range values) included in parsing.
+ * The quasi-bogus "time only" values from Photoshop CS are not supported.
+ *
+ * @param dateTime an XMPDateTime-object.
+ * @return Returns an ISO 8601 string.
+ */
+ public static String render(XMPDateTime dateTime)
+ {
+ StringBuffer buffer = new StringBuffer();
+
+ // year is rendered in any case, even 0000
+ DecimalFormat df = new DecimalFormat("0000", new DecimalFormatSymbols(Locale.ENGLISH));
+ buffer.append(df.format(dateTime.getYear()));
+ if (dateTime.getMonth() == 0)
+ {
+ return buffer.toString();
+ }
+
+ // month
+ df.applyPattern("'-'00");
+ buffer.append(df.format(dateTime.getMonth()));
+ if (dateTime.getDay() == 0)
+ {
+ return buffer.toString();
+ }
+
+ // day
+ buffer.append(df.format(dateTime.getDay()));
+
+ // time, rendered if any time field is not zero
+ if (dateTime.getHour() != 0 ||
+ dateTime.getMinute() != 0 ||
+ dateTime.getSecond() != 0 ||
+ dateTime.getNanoSecond() != 0 ||
+ (dateTime.getTimeZone() != null && dateTime.getTimeZone().getRawOffset() != 0))
+ {
+ // hours and minutes
+ buffer.append('T');
+ df.applyPattern("00");
+ buffer.append(df.format(dateTime.getHour()));
+ buffer.append(':');
+ buffer.append(df.format(dateTime.getMinute()));
+
+ // seconds and nanoseconds
+ if (dateTime.getSecond() != 0 || dateTime.getNanoSecond() != 0)
+ {
+ double seconds = dateTime.getSecond() + dateTime.getNanoSecond() / 1e9d;
+
+ df.applyPattern(":00.#########");
+ buffer.append(df.format(seconds));
+ }
+
+ // time zone
+ if (dateTime.getTimeZone() != null)
+ {
+ if (dateTime.getTimeZone().getRawOffset() == 0)
+ {
+ // UTC
+ buffer.append('Z');
+ }
+ else
+ {
+ int offset = dateTime.getTimeZone().getRawOffset();
+ int thours = offset / 3600000;
+ int tminutes = Math.abs(offset % 3600000 / 60000);
+ df.applyPattern("+00;-00");
+ buffer.append(df.format(thours));
+ df.applyPattern(":00");
+ buffer.append(df.format(tminutes));
+ }
+ }
+ }
+ return buffer.toString();
+ }
+
+
+}
+
+
+/**
+ * @since 22.08.2006
+ */
+class ParseState
+{
+ /** */
+ private String str;
+ /** */
+ private int pos = 0;
+
+
+ /**
+ * @param str initializes the parser container
+ */
+ public ParseState(String str)
+ {
+ this.str = str;
+ }
+
+
+ /**
+ * @return Returns the length of the input.
+ */
+ public int length()
+ {
+ return str.length();
+ }
+
+
+ /**
+ * @return Returns whether there are more chars to come.
+ */
+ public boolean hasNext()
+ {
+ return pos < str.length();
+ }
+
+
+ /**
+ * @param index index of char
+ * @return Returns char at a certain index.
+ */
+ public char ch(int index)
+ {
+ return index < str.length() ?
+ str.charAt(index) :
+ 0x0000;
+ }
+
+
+ /**
+ * @return Returns the current char or 0x0000 if there are no more chars.
+ */
+ public char ch()
+ {
+ return pos < str.length() ?
+ str.charAt(pos) :
+ 0x0000;
+ }
+
+
+ /**
+ * Skips the next char.
+ */
+ public void skip()
+ {
+ pos++;
+ }
+
+
+ /**
+ * @return Returns the current position.
+ */
+ public int pos()
+ {
+ return pos;
+ }
+
+
+ /**
+ * Parses a integer from the source and sets the pointer after it.
+ * @param errorMsg Error message to put in the exception if no number can be found
+ * @param maxValue the max value of the number to return
+ * @return Returns the parsed integer.
+ * @throws XMPException Thrown if no integer can be found.
+ */
+ public int gatherInt(String errorMsg, int maxValue) throws XMPException
+ {
+ int value = 0;
+ boolean success = false;
+ char ch = ch(pos);
+ while ('0' <= ch && ch <= '9')
+ {
+ value = (value * 10) + (ch - '0');
+ success = true;
+ pos++;
+ ch = ch(pos);
+ }
+
+ if (success)
+ {
+ if (value > maxValue)
+ {
+ return maxValue;
+ }
+ else if (value < 0)
+ {
+ return 0;
+ }
+ else
+ {
+ return value;
+ }
+ }
+ else
+ {
+ throw new XMPException(errorMsg, XMPError.BADVALUE);
+ }
+ }
+}
+
+
diff --git a/java/XMPCore/src/com/adobe/xmp/impl/Latin1Converter.java b/java/XMPCore/src/com/adobe/xmp/impl/Latin1Converter.java
new file mode 100644
index 0000000..a8707a5
--- /dev/null
+++ b/java/XMPCore/src/com/adobe/xmp/impl/Latin1Converter.java
@@ -0,0 +1,197 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+
+
+package com.adobe.xmp.impl;
+
+import java.io.UnsupportedEncodingException;
+
+
+/**
+ * @since 12.10.2006
+ */
+public class Latin1Converter
+{
+ /** */
+ private static final int STATE_START = 0;
+ /** */
+ private static final int STATE_UTF8CHAR = 11;
+
+
+ /**
+ * Private constructor
+ */
+ private Latin1Converter()
+ {
+ // EMPTY
+ }
+
+
+ /**
+ * A converter that processes a byte buffer containing a mix of UTF8 and Latin-1/Cp1252 chars.
+ * The result is a buffer where those chars have been converted to UTF-8;
+ * that means it contains only valid UTF-8 chars.
+ * <p>
+ * <em>Explanation of the processing:</em> First the encoding of the buffer is detected looking
+ * at the first four bytes (that works only if the buffer starts with an ASCII-char,
+ * like xmls &apos;&lt;&apos;). UTF-16/32 flavours do not require further proccessing.
+ * <p>
+ * In the case, UTF-8 is detected, it assumes wrong UTF8 chars to be a sequence of
+ * Latin-1/Cp1252 encoded bytes and converts the chars to their corresponding UTF-8 byte
+ * sequence.
+ * <p>
+ * The 0x80..0x9F range is undefined in Latin-1, but is defined in Windows code
+ * page 1252. The bytes 0x81, 0x8D, 0x8F, 0x90, and 0x9D are formally undefined
+ * by Windows 1252. These are in XML's RestrictedChar set, so we map them to a
+ * space.
+ * <p>
+ * The official Latin-1 characters in the range 0xA0..0xFF are converted into
+ * the Unicode Latin Supplement range U+00A0 - U+00FF.
+ * <p>
+ * <em>Example:</em> If an Euro-symbol (€) appears in the byte buffer (0xE2, 0x82, 0xAC),
+ * it will be left as is. But if only the first two bytes are appearing,
+ * followed by an ASCII char a (0xE2 - 0x82 - 0x41), it will be converted to
+ * 0xC3, 0xA2 (â) - 0xE2, 0x80, 0x9A (‚) - 0x41 (a).
+ *
+ * @param buffer a byte buffer contain
+ * @return Returns a new buffer containing valid UTF-8
+ */
+ public static ByteBuffer convert(ByteBuffer buffer)
+ {
+ if ("UTF-8".equals(buffer.getEncoding()))
+ {
+ // the buffer containing one UTF-8 char (up to 8 bytes)
+ byte[] readAheadBuffer = new byte[8];
+ // the number of bytes read ahead.
+ int readAhead = 0;
+ // expected UTF8 bytesto come
+ int expectedBytes = 0;
+ // output buffer with estimated length
+ ByteBuffer out = new ByteBuffer(buffer.length() * 4 / 3);
+
+ int state = STATE_START;
+ for (int i = 0; i < buffer.length(); i++)
+ {
+ int b = buffer.charAt(i);
+
+ switch (state)
+ {
+ default:
+ case STATE_START:
+ if (b < 0x7F)
+ {
+ out.append((byte) b);
+ }
+ else if (b >= 0xC0)
+ {
+ // start of UTF8 sequence
+ expectedBytes = -1;
+ int test = b;
+ for (; expectedBytes < 8 && (test & 0x80) == 0x80; test = test << 1)
+ {
+ expectedBytes++;
+ }
+ readAheadBuffer[readAhead++] = (byte) b;
+ state = STATE_UTF8CHAR;
+ }
+ else // implicitly: b >= 0x80 && b < 0xC0
+ {
+ // invalid UTF8 start char, assume to be Latin-1
+ byte[] utf8 = convertToUTF8((byte) b);
+ out.append(utf8);
+ }
+ break;
+
+ case STATE_UTF8CHAR:
+ if (expectedBytes > 0 && (b & 0xC0) == 0x80)
+ {
+ // valid UTF8 char, add to readAheadBuffer
+ readAheadBuffer[readAhead++] = (byte) b;
+ expectedBytes--;
+
+ if (expectedBytes == 0)
+ {
+ out.append(readAheadBuffer, 0, readAhead);
+ readAhead = 0;
+
+ state = STATE_START;
+ }
+ }
+ else
+ {
+ // invalid UTF8 char:
+ // 1. convert first of seq to UTF8
+ byte[] utf8 = convertToUTF8(readAheadBuffer[0]);
+ out.append(utf8);
+
+ // 2. continue processing at second byte of sequence
+ i = i - readAhead;
+ readAhead = 0;
+
+ state = STATE_START;
+ }
+ break;
+ }
+ }
+
+ // loop ends with "half" Utf8 char --> assume that the bytes are Latin-1
+ if (state == STATE_UTF8CHAR)
+ {
+ for (int j = 0; j < readAhead; j++)
+ {
+ byte b = readAheadBuffer[j];
+ byte[] utf8 = convertToUTF8(b);
+ out.append(utf8);
+ }
+ }
+
+ return out;
+ }
+ else
+ {
+ // Latin-1 fixing applies only to UTF-8
+ return buffer;
+ }
+ }
+
+
+ /**
+ * Converts a Cp1252 char (contains all Latin-1 chars above 0x80) into a
+ * UTF-8 byte sequence. The bytes 0x81, 0x8D, 0x8F, 0x90, and 0x9D are
+ * formally undefined by Windows 1252 and therefore replaced by a space
+ * (0x20).
+ *
+ * @param ch
+ * an Cp1252 / Latin-1 byte
+ * @return Returns a byte array containing a UTF-8 byte sequence.
+ */
+ private static byte[] convertToUTF8(byte ch)
+ {
+ int c = ch & 0xFF;
+ try
+ {
+ if (c >= 0x80)
+ {
+ if (c == 0x81 || c == 0x8D || c == 0x8F || c == 0x90 || c == 0x9D)
+ {
+ return new byte[] { 0x20 }; // space for undefined
+ }
+
+ // interpret byte as Windows Cp1252 char
+ return new String(new byte[] { ch }, "cp1252").getBytes("UTF-8");
+ }
+ }
+ catch (UnsupportedEncodingException e)
+ {
+ // EMPTY
+ }
+ return new byte[] { ch };
+ }
+}
diff --git a/java/XMPCore/src/com/adobe/xmp/impl/ParameterAsserts.java b/java/XMPCore/src/com/adobe/xmp/impl/ParameterAsserts.java
new file mode 100644
index 0000000..51c156a
--- /dev/null
+++ b/java/XMPCore/src/com/adobe/xmp/impl/ParameterAsserts.java
@@ -0,0 +1,153 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+package com.adobe.xmp.impl;
+
+import com.adobe.xmp.XMPConst;
+import com.adobe.xmp.XMPError;
+import com.adobe.xmp.XMPException;
+import com.adobe.xmp.XMPMeta;
+
+
+/**
+ * @since 11.08.2006
+ */
+class ParameterAsserts implements XMPConst
+{
+ /**
+ * private constructor
+ */
+ private ParameterAsserts()
+ {
+ // EMPTY
+ }
+
+
+ /**
+ * Asserts that an array name is set.
+ * @param arrayName an array name
+ * @throws XMPException Array name is null or empty
+ */
+ public static void assertArrayName(String arrayName) throws XMPException
+ {
+ if (arrayName == null || arrayName.length() == 0)
+ {
+ throw new XMPException("Empty array name", XMPError.BADPARAM);
+ }
+ }
+
+
+ /**
+ * Asserts that a property name is set.
+ * @param propName a property name or path
+ * @throws XMPException Property name is null or empty
+ */
+ public static void assertPropName(String propName) throws XMPException
+ {
+ if (propName == null || propName.length() == 0)
+ {
+ throw new XMPException("Empty property name", XMPError.BADPARAM);
+ }
+ }
+
+
+ /**
+ * Asserts that a schema namespace is set.
+ * @param schemaNS a schema namespace
+ * @throws XMPException Schema is null or empty
+ */
+ public static void assertSchemaNS(String schemaNS) throws XMPException
+ {
+ if (schemaNS == null || schemaNS.length() == 0)
+ {
+ throw new XMPException("Empty schema namespace URI", XMPError.BADPARAM);
+ }
+ }
+
+
+ /**
+ * Asserts that a prefix is set.
+ * @param prefix a prefix
+ * @throws XMPException Prefix is null or empty
+ */
+ public static void assertPrefix(String prefix) throws XMPException
+ {
+ if (prefix == null || prefix.length() == 0)
+ {
+ throw new XMPException("Empty prefix", XMPError.BADPARAM);
+ }
+ }
+
+
+ /**
+ * Asserts that a specific language is set.
+ * @param specificLang a specific lang
+ * @throws XMPException Specific language is null or empty
+ */
+ public static void assertSpecificLang(String specificLang) throws XMPException
+ {
+ if (specificLang == null || specificLang.length() == 0)
+ {
+ throw new XMPException("Empty specific language", XMPError.BADPARAM);
+ }
+ }
+
+
+ /**
+ * Asserts that a struct name is set.
+ * @param structName a struct name
+ * @throws XMPException Struct name is null or empty
+ */
+ public static void assertStructName(String structName) throws XMPException
+ {
+ if (structName == null || structName.length() == 0)
+ {
+ throw new XMPException("Empty array name", XMPError.BADPARAM);
+ }
+ }
+
+
+ /**
+ * Asserts that any string parameter is set.
+ * @param param any string parameter
+ * @throws XMPException Thrown if the parameter is null or has length 0.
+ */
+ public static void assertNotNull(Object param) throws XMPException
+ {
+ if (param == null)
+ {
+ throw new XMPException("Parameter must not be null", XMPError.BADPARAM);
+ }
+ else if ((param instanceof String) && ((String) param).length() == 0)
+ {
+ throw new XMPException("Parameter must not be null or empty", XMPError.BADPARAM);
+ }
+ }
+
+
+ /**
+ * Asserts that the xmp object is of this implemention
+ * ({@link XMPMetaImpl}).
+ * @param xmp the XMP object
+ * @throws XMPException A wrong implentaion is used.
+ */
+ public static void assertImplementation(XMPMeta xmp) throws XMPException
+ {
+ if (xmp == null)
+ {
+ throw new XMPException("Parameter must not be null",
+ XMPError.BADPARAM);
+ }
+ else if (!(xmp instanceof XMPMetaImpl))
+ {
+ throw new XMPException("The XMPMeta-object is not compatible with this implementation",
+ XMPError.BADPARAM);
+ }
+ }
+} \ No newline at end of file
diff --git a/java/XMPCore/src/com/adobe/xmp/impl/ParseRDF.java b/java/XMPCore/src/com/adobe/xmp/impl/ParseRDF.java
new file mode 100644
index 0000000..1368a01
--- /dev/null
+++ b/java/XMPCore/src/com/adobe/xmp/impl/ParseRDF.java
@@ -0,0 +1,1349 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+package com.adobe.xmp.impl;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import org.w3c.dom.Attr;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+
+import com.adobe.xmp.XMPConst;
+import com.adobe.xmp.XMPError;
+import com.adobe.xmp.XMPException;
+import com.adobe.xmp.XMPMetaFactory;
+import com.adobe.xmp.XMPSchemaRegistry;
+import com.adobe.xmp.options.PropertyOptions;
+
+
+/**
+ * Parser for "normal" XML serialisation of RDF.
+ *
+ * @since 14.07.2006
+ */
+public class ParseRDF implements XMPError, XMPConst
+{
+ /** */
+ public static final int RDFTERM_OTHER = 0;
+ /** Start of coreSyntaxTerms. */
+ public static final int RDFTERM_RDF = 1;
+ /** */
+ public static final int RDFTERM_ID = 2;
+ /** */
+ public static final int RDFTERM_ABOUT = 3;
+ /** */
+ public static final int RDFTERM_PARSE_TYPE = 4;
+ /** */
+ public static final int RDFTERM_RESOURCE = 5;
+ /** */
+ public static final int RDFTERM_NODE_ID = 6;
+ /** End of coreSyntaxTerms */
+ public static final int RDFTERM_DATATYPE = 7;
+ /** Start of additions for syntax Terms. */
+ public static final int RDFTERM_DESCRIPTION = 8;
+ /** End of of additions for syntaxTerms. */
+ public static final int RDFTERM_LI = 9;
+ /** Start of oldTerms. */
+ public static final int RDFTERM_ABOUT_EACH = 10;
+ /** */
+ public static final int RDFTERM_ABOUT_EACH_PREFIX = 11;
+ /** End of oldTerms. */
+ public static final int RDFTERM_BAG_ID = 12;
+ /** */
+ public static final int RDFTERM_FIRST_CORE = RDFTERM_RDF;
+ /** */
+ public static final int RDFTERM_LAST_CORE = RDFTERM_DATATYPE;
+ /** ! Yes, the syntax terms include the core terms. */
+ public static final int RDFTERM_FIRST_SYNTAX = RDFTERM_FIRST_CORE;
+ /** */
+ public static final int RDFTERM_LAST_SYNTAX = RDFTERM_LI;
+ /** */
+ public static final int RDFTERM_FIRST_OLD = RDFTERM_ABOUT_EACH;
+ /** */
+ public static final int RDFTERM_LAST_OLD = RDFTERM_BAG_ID;
+
+ /** this prefix is used for default namespaces */
+ public static final String DEFAULT_PREFIX = "_dflt";
+
+
+
+ /**
+ * The main parsing method. The XML tree is walked through from the root node and and XMP tree
+ * is created. This is a raw parse, the normalisation of the XMP tree happens outside.
+ *
+ * @param xmlRoot the XML root node
+ * @return Returns an XMP metadata object (not normalized)
+ * @throws XMPException Occurs if the parsing fails for any reason.
+ */
+ static XMPMetaImpl parse(Node xmlRoot) throws XMPException
+ {
+ XMPMetaImpl xmp = new XMPMetaImpl();
+ rdf_RDF(xmp, xmlRoot);
+ return xmp;
+ }
+
+
+ /**
+ * 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.
+ *
+ * @param xmp the xmp metadata object that is generated
+ * @param rdfRdfNode the top-level xml node
+ * @throws XMPException thown on parsing errors
+ */
+ static void rdf_RDF(XMPMetaImpl xmp, Node rdfRdfNode) throws XMPException
+ {
+ if (rdfRdfNode.hasAttributes())
+ {
+ rdf_NodeElementList (xmp, xmp.getRoot(), rdfRdfNode);
+ }
+ else
+ {
+ throw new XMPException("Invalid attributes of rdf:RDF element", BADRDF);
+ }
+ }
+
+
+ /**
+ * 7.2.10 nodeElementList<br>
+ * ws* ( nodeElement ws* )*
+ *
+ * Note: this method is only called from the rdf:RDF-node (top level)
+ * @param xmp the xmp metadata object that is generated
+ * @param xmpParent the parent xmp node
+ * @param rdfRdfNode the top-level xml node
+ * @throws XMPException thown on parsing errors
+ */
+ private static void rdf_NodeElementList(XMPMetaImpl xmp, XMPNode xmpParent, Node rdfRdfNode)
+ throws XMPException
+ {
+ for (int i = 0; i < rdfRdfNode.getChildNodes().getLength(); i++)
+ {
+ Node child = rdfRdfNode.getChildNodes().item(i);
+ // filter whitespaces (and all text nodes)
+ if (!isWhitespaceNode(child))
+ {
+ rdf_NodeElement (xmp, xmpParent, child, true);
+ }
+ }
+ }
+
+
+ /**
+ * 7.2.5 nodeElementURIs
+ * anyURI - ( coreSyntaxTerms | rdf:li | oldTerms )
+ *
+ * 7.2.11 nodeElement
+ * start-element ( URI == nodeElementURIs,
+ * attributes == set ( ( idAttr | nodeIdAttr | aboutAttr )?, propertyAttr* ) )
+ * propertyEltList
+ * end-element()
+ *
+ * A node element URI is rdf:Description or anything else that is not an RDF
+ * term.
+ *
+ * @param xmp the xmp metadata object that is generated
+ * @param xmpParent the parent xmp node
+ * @param xmlNode the currently processed XML node
+ * @param isTopLevel Flag if the node is a top-level node
+ * @throws XMPException thown on parsing errors
+ */
+ private static void rdf_NodeElement(XMPMetaImpl xmp, XMPNode xmpParent, Node xmlNode,
+ boolean isTopLevel) throws XMPException
+ {
+ int nodeTerm = getRDFTermKind (xmlNode);
+ if (nodeTerm != RDFTERM_DESCRIPTION && nodeTerm != RDFTERM_OTHER)
+ {
+ throw new XMPException("Node element must be rdf:Description or typed node",
+ BADRDF);
+ }
+ else if (isTopLevel && nodeTerm == RDFTERM_OTHER)
+ {
+ throw new XMPException("Top level typed node not allowed", BADXMP);
+ }
+ else
+ {
+ rdf_NodeElementAttrs (xmp, xmpParent, xmlNode, isTopLevel);
+ rdf_PropertyElementList (xmp, xmpParent, xmlNode, isTopLevel);
+ }
+
+ }
+
+
+ /**
+ *
+ * 7.2.7 propertyAttributeURIs
+ * anyURI - ( coreSyntaxTerms | rdf:Description | rdf:li | oldTerms )
+ *
+ * 7.2.11 nodeElement
+ * start-element ( URI == nodeElementURIs,
+ * attributes == set ( ( idAttr | nodeIdAttr | aboutAttr )?, propertyAttr* ) )
+ * propertyEltList
+ * end-element()
+ *
+ * Process the attribute list for an RDF node element. A property attribute URI is
+ * anything other than an RDF term. The rdf:ID and rdf:nodeID attributes are simply ignored,
+ * as are rdf:about attributes on inner nodes.
+ *
+ * @param xmp the xmp metadata object that is generated
+ * @param xmpParent the parent xmp node
+ * @param xmlNode the currently processed XML node
+ * @param isTopLevel Flag if the node is a top-level node
+ * @throws XMPException thown on parsing errors
+ */
+ private static void rdf_NodeElementAttrs(XMPMetaImpl xmp, XMPNode xmpParent, Node xmlNode,
+ boolean isTopLevel) throws XMPException
+ {
+ // Used to detect attributes that are mutually exclusive.
+ int exclusiveAttrs = 0;
+
+ for (int i = 0; i < xmlNode.getAttributes().getLength(); i++)
+ {
+ Node attribute = xmlNode.getAttributes().item(i);
+
+ // quick hack, ns declarations do not appear in C++
+ // ignore "ID" without namespace
+ if ("xmlns".equals(attribute.getPrefix()) ||
+ (attribute.getPrefix() == null && "xmlns".equals(attribute.getNodeName())))
+ {
+ continue;
+ }
+
+ int attrTerm = getRDFTermKind(attribute);
+
+ switch (attrTerm)
+ {
+ case RDFTERM_ID:
+ case RDFTERM_NODE_ID:
+ case RDFTERM_ABOUT:
+ if (exclusiveAttrs > 0)
+ {
+ throw new XMPException("Mutally exclusive about, ID, nodeID attributes",
+ BADRDF);
+ }
+
+ exclusiveAttrs++;
+
+ if (isTopLevel && (attrTerm == RDFTERM_ABOUT))
+ {
+ // This is the rdf:about attribute on a top level node. Set
+ // the XMP tree name if
+ // it doesn't have a name yet. Make sure this name matches
+ // the XMP tree name.
+ if (xmpParent.getName() != null && xmpParent.getName().length() > 0)
+ {
+ if (!xmpParent.getName().equals(attribute.getNodeValue()))
+ {
+ throw new XMPException("Mismatched top level rdf:about values",
+ BADXMP);
+ }
+ }
+ else
+ {
+ xmpParent.setName(attribute.getNodeValue());
+ }
+ }
+ break;
+
+ case RDFTERM_OTHER:
+ addChildNode(xmp, xmpParent, attribute, attribute.getNodeValue(), isTopLevel);
+ break;
+
+ default:
+ throw new XMPException("Invalid nodeElement attribute", BADRDF);
+ }
+
+ }
+ }
+
+
+ /**
+ * 7.2.13 propertyEltList
+ * ws* ( propertyElt ws* )*
+ *
+ * @param xmp the xmp metadata object that is generated
+ * @param xmpParent the parent xmp node
+ * @param xmlParent the currently processed XML node
+ * @param isTopLevel Flag if the node is a top-level node
+ * @throws XMPException thown on parsing errors
+ */
+ private static void rdf_PropertyElementList(XMPMetaImpl xmp, XMPNode xmpParent, Node xmlParent,
+ boolean isTopLevel) throws XMPException
+ {
+ for (int i = 0; i < xmlParent.getChildNodes().getLength(); i++)
+ {
+ Node currChild = xmlParent.getChildNodes().item(i);
+ if (isWhitespaceNode(currChild))
+ {
+ continue;
+ }
+ else if (currChild.getNodeType() != Node.ELEMENT_NODE)
+ {
+ throw new XMPException("Expected property element node not found", BADRDF);
+ }
+ else
+ {
+ rdf_PropertyElement(xmp, xmpParent, currChild, isTopLevel);
+ }
+ }
+ }
+
+
+ /**
+ * 7.2.14 propertyElt
+ *
+ * resourcePropertyElt | literalPropertyElt | parseTypeLiteralPropertyElt |
+ * parseTypeResourcePropertyElt | parseTypeCollectionPropertyElt |
+ * parseTypeOtherPropertyElt | emptyPropertyElt
+ *
+ * 7.2.15 resourcePropertyElt
+ * start-element ( URI == propertyElementURIs, attributes == set ( idAttr? ) )
+ * ws* nodeElement ws*
+ * end-element()
+ *
+ * 7.2.16 literalPropertyElt
+ * start-element (
+ * URI == propertyElementURIs, attributes == set ( idAttr?, datatypeAttr?) )
+ * text()
+ * end-element()
+ *
+ * 7.2.17 parseTypeLiteralPropertyElt
+ * start-element (
+ * URI == propertyElementURIs, attributes == set ( idAttr?, parseLiteral ) )
+ * literal
+ * end-element()
+ *
+ * 7.2.18 parseTypeResourcePropertyElt
+ * start-element (
+ * URI == propertyElementURIs, attributes == set ( idAttr?, parseResource ) )
+ * propertyEltList
+ * end-element()
+ *
+ * 7.2.19 parseTypeCollectionPropertyElt
+ * start-element (
+ * URI == propertyElementURIs, attributes == set ( idAttr?, parseCollection ) )
+ * nodeElementList
+ * end-element()
+ *
+ * 7.2.20 parseTypeOtherPropertyElt
+ * start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, parseOther ) )
+ * propertyEltList
+ * end-element()
+ *
+ * 7.2.21 emptyPropertyElt
+ * start-element ( URI == propertyElementURIs,
+ * attributes == set ( idAttr?, ( resourceAttr | nodeIdAttr )?, propertyAttr* ) )
+ * end-element()
+ *
+ * The various property element forms are not distinguished by the XML element name,
+ * but by their attributes for the most part. The exceptions are resourcePropertyElt and
+ * literalPropertyElt. They are distinguished by their XML element content.
+ *
+ * NOTE: The RDF syntax does not explicitly include the xml:lang attribute although it can
+ * appear in many of these. We have to allow for it in the attibute counts below.
+ *
+ * @param xmp the xmp metadata object that is generated
+ * @param xmpParent the parent xmp node
+ * @param xmlNode the currently processed XML node
+ * @param isTopLevel Flag if the node is a top-level node
+ * @throws XMPException thown on parsing errors
+ */
+ private static void rdf_PropertyElement(XMPMetaImpl xmp, XMPNode xmpParent, Node xmlNode,
+ boolean isTopLevel) throws XMPException
+ {
+ int nodeTerm = getRDFTermKind (xmlNode);
+ if (!isPropertyElementName(nodeTerm))
+ {
+ throw new XMPException("Invalid property element name", BADRDF);
+ }
+
+ // remove the namespace-definitions from the list
+ NamedNodeMap attributes = xmlNode.getAttributes();
+ List nsAttrs = null;
+ for (int i = 0; i < attributes.getLength(); i++)
+ {
+ Node attribute = attributes.item(i);
+ if ("xmlns".equals(attribute.getPrefix()) ||
+ (attribute.getPrefix() == null && "xmlns".equals(attribute.getNodeName())))
+ {
+ if (nsAttrs == null)
+ {
+ nsAttrs = new ArrayList();
+ }
+ nsAttrs.add(attribute.getNodeName());
+ }
+ }
+ if (nsAttrs != null)
+ {
+ for (Iterator it = nsAttrs.iterator(); it.hasNext();)
+ {
+ String ns = (String) it.next();
+ attributes.removeNamedItem(ns);
+ }
+ }
+
+
+ if (attributes.getLength() > 3)
+ {
+ // Only an emptyPropertyElt can have more than 3 attributes.
+ rdf_EmptyPropertyElement(xmp, xmpParent, xmlNode, isTopLevel);
+ }
+ else
+ {
+ // Look through the attributes for one that isn't rdf:ID or xml:lang,
+ // it will usually tell what we should be dealing with.
+ // The called routines must verify their specific syntax!
+
+ for (int i = 0; i < attributes.getLength(); i++)
+ {
+ Node attribute = attributes.item(i);
+ String attrLocal = attribute.getLocalName();
+ String attrNS = attribute.getNamespaceURI();
+ String attrValue = attribute.getNodeValue();
+ if (!(XML_LANG.equals(attribute.getNodeName()) &&
+ !("ID".equals(attrLocal) && NS_RDF.equals(attrNS))))
+ {
+ if ("datatype".equals(attrLocal) && NS_RDF.equals(attrNS))
+ {
+ rdf_LiteralPropertyElement (xmp, xmpParent, xmlNode, isTopLevel);
+ }
+ else if (!("parseType".equals(attrLocal) && NS_RDF.equals(attrNS)))
+ {
+ rdf_EmptyPropertyElement (xmp, xmpParent, xmlNode, isTopLevel);
+ }
+ else if ("Literal".equals(attrValue))
+ {
+ rdf_ParseTypeLiteralPropertyElement();
+ }
+ else if ("Resource".equals(attrValue))
+ {
+ rdf_ParseTypeResourcePropertyElement(xmp, xmpParent, xmlNode, isTopLevel);
+ }
+ else if ("Collection".equals(attrValue))
+ {
+ rdf_ParseTypeCollectionPropertyElement();
+ }
+ else
+ {
+ rdf_ParseTypeOtherPropertyElement();
+ }
+
+ return;
+ }
+ }
+
+ // Only rdf:ID and xml:lang, could be a resourcePropertyElt, a literalPropertyElt,
+ // or an emptyPropertyElt. Look at the child XML nodes to decide which.
+
+ if (xmlNode.hasChildNodes())
+ {
+ for (int i = 0; i < xmlNode.getChildNodes().getLength(); i++)
+ {
+ Node currChild = xmlNode.getChildNodes().item(i);
+ if (currChild.getNodeType() != Node.TEXT_NODE)
+ {
+ rdf_ResourcePropertyElement (xmp, xmpParent, xmlNode, isTopLevel);
+ return;
+ }
+ }
+
+ rdf_LiteralPropertyElement (xmp, xmpParent, xmlNode, isTopLevel);
+ }
+ else
+ {
+ rdf_EmptyPropertyElement (xmp, xmpParent, xmlNode, isTopLevel);
+ }
+ }
+ }
+
+
+ /**
+ * 7.2.15 resourcePropertyElt
+ * start-element ( URI == propertyElementURIs, attributes == set ( idAttr? ) )
+ * ws* nodeElement ws*
+ * end-element()
+ *
+ * This handles structs using an rdf:Description node,
+ * arrays using rdf:Bag/Seq/Alt, and typedNodes. It also catches and cleans up qualified
+ * properties written with rdf:Description and rdf:value.
+ *
+ * @param xmp the xmp metadata object that is generated
+ * @param xmpParent the parent xmp node
+ * @param xmlNode the currently processed XML node
+ * @param isTopLevel Flag if the node is a top-level node
+ * @throws XMPException thown on parsing errors
+ */
+ private static void rdf_ResourcePropertyElement(XMPMetaImpl xmp, XMPNode xmpParent,
+ Node xmlNode, boolean isTopLevel) throws XMPException
+ {
+ if (isTopLevel && "iX:changes".equals(xmlNode.getNodeName()))
+ {
+ // Strip old "punchcard" chaff which has on the prefix "iX:".
+ return;
+ }
+
+ XMPNode newCompound = addChildNode(xmp, xmpParent, xmlNode, "", isTopLevel);
+
+ // walk through the attributes
+ for (int i = 0; i < xmlNode.getAttributes().getLength(); i++)
+ {
+ Node attribute = xmlNode.getAttributes().item(i);
+ if ("xmlns".equals(attribute.getPrefix()) ||
+ (attribute.getPrefix() == null && "xmlns".equals(attribute.getNodeName())))
+ {
+ continue;
+ }
+
+ String attrLocal = attribute.getLocalName();
+ String attrNS = attribute.getNamespaceURI();
+ if (XML_LANG.equals(attribute.getNodeName()))
+ {
+ addQualifierNode (newCompound, XML_LANG, attribute.getNodeValue());
+ }
+ else if ("ID".equals(attrLocal) && NS_RDF.equals(attrNS))
+ {
+ continue; // Ignore all rdf:ID attributes.
+ }
+ else
+ {
+ throw new XMPException(
+ "Invalid attribute for resource property element", BADRDF);
+ }
+ }
+
+ // walk through the children
+
+ Node currChild = null;
+ boolean found = false;
+ int i;
+ for (i = 0; i < xmlNode.getChildNodes().getLength(); i++)
+ {
+ currChild = xmlNode.getChildNodes().item(i);
+ if (!isWhitespaceNode(currChild))
+ {
+ if (currChild.getNodeType() == Node.ELEMENT_NODE && !found)
+ {
+ boolean isRDF = NS_RDF.equals(currChild.getNamespaceURI());
+ String childLocal = currChild.getLocalName();
+
+ if (isRDF && "Bag".equals(childLocal))
+ {
+ newCompound.getOptions().setArray(true);
+ }
+ else if (isRDF && "Seq".equals(childLocal))
+ {
+ newCompound.getOptions().setArray(true).setArrayOrdered(true);
+ }
+ else if (isRDF && "Alt".equals(childLocal))
+ {
+ newCompound.getOptions().setArray(true).setArrayOrdered(true)
+ .setArrayAlternate(true);
+ }
+ else
+ {
+ newCompound.getOptions().setStruct(true);
+ if (!isRDF && !"Description".equals(childLocal))
+ {
+ String typeName = currChild.getNamespaceURI();
+ if (typeName == null)
+ {
+ throw new XMPException(
+ "All XML elements must be in a namespace", BADXMP);
+ }
+ typeName += ':' + childLocal;
+ addQualifierNode (newCompound, "rdf:type", typeName);
+ }
+ }
+
+ rdf_NodeElement (xmp, newCompound, currChild, false);
+
+ if (newCompound.getHasValueChild())
+ {
+ fixupQualifiedNode (newCompound);
+ }
+ else if (newCompound.getOptions().isArrayAlternate())
+ {
+ XMPNodeUtils.detectAltText(newCompound);
+ }
+
+ found = true;
+ break;
+ }
+ else if (found)
+ {
+ // found second child element
+ throw new XMPException(
+ "Invalid child of resource property element", BADRDF);
+ }
+ else
+ {
+ throw new XMPException(
+ "Children of resource property element must be XML elements", BADRDF);
+ }
+ }
+ }
+
+ if (!found)
+ {
+ // didn't found any child elements
+ throw new XMPException("Missing child of resource property element", BADRDF);
+ }
+ }
+
+
+ /**
+ * 7.2.16 literalPropertyElt
+ * start-element ( URI == propertyElementURIs,
+ * attributes == set ( idAttr?, datatypeAttr?) )
+ * text()
+ * end-element()
+ *
+ * Add a leaf node with the text value and qualifiers for the attributes.
+ * @param xmp the xmp metadata object that is generated
+ * @param xmpParent the parent xmp node
+ * @param xmlNode the currently processed XML node
+ * @param isTopLevel Flag if the node is a top-level node
+ * @throws XMPException thown on parsing errors
+ */
+ private static void rdf_LiteralPropertyElement(XMPMetaImpl xmp, XMPNode xmpParent,
+ Node xmlNode, boolean isTopLevel) throws XMPException
+ {
+ XMPNode newChild = addChildNode (xmp, xmpParent, xmlNode, null, isTopLevel);
+
+ for (int i = 0; i < xmlNode.getAttributes().getLength(); i++)
+ {
+ Node attribute = xmlNode.getAttributes().item(i);
+ if ("xmlns".equals(attribute.getPrefix()) ||
+ (attribute.getPrefix() == null && "xmlns".equals(attribute.getNodeName())))
+ {
+ continue;
+ }
+
+ String attrNS = attribute.getNamespaceURI();
+ String attrLocal = attribute.getLocalName();
+ if (XML_LANG.equals(attribute.getNodeName()))
+ {
+ addQualifierNode(newChild, XML_LANG, attribute.getNodeValue());
+ }
+ else if (NS_RDF.equals(attrNS) &&
+ ("ID".equals(attrLocal) || "datatype".equals(attrLocal)))
+ {
+ continue; // Ignore all rdf:ID and rdf:datatype attributes.
+ }
+ else
+ {
+ throw new XMPException(
+ "Invalid attribute for literal property element", BADRDF);
+ }
+ }
+ String textValue = "";
+ for (int i = 0; i < xmlNode.getChildNodes().getLength(); i++)
+ {
+ Node child = xmlNode.getChildNodes().item(i);
+ if (child.getNodeType() == Node.TEXT_NODE)
+ {
+ textValue += child.getNodeValue();
+ }
+ else
+ {
+ throw new XMPException("Invalid child of literal property element", BADRDF);
+ }
+ }
+ newChild.setValue(textValue);
+ }
+
+
+ /**
+ * 7.2.17 parseTypeLiteralPropertyElt
+ * start-element ( URI == propertyElementURIs,
+ * attributes == set ( idAttr?, parseLiteral ) )
+ * literal
+ * end-element()
+ *
+ * @throws XMPException thown on parsing errors
+ */
+ private static void rdf_ParseTypeLiteralPropertyElement() throws XMPException
+ {
+ throw new XMPException("ParseTypeLiteral property element not allowed", BADXMP);
+ }
+
+
+ /**
+ * 7.2.18 parseTypeResourcePropertyElt
+ * start-element ( URI == propertyElementURIs,
+ * attributes == set ( idAttr?, parseResource ) )
+ * propertyEltList
+ * end-element()
+ *
+ * Add a new struct node with a qualifier for the possible rdf:ID attribute.
+ * Then process the XML child nodes to get the struct fields.
+ *
+ * @param xmp the xmp metadata object that is generated
+ * @param xmpParent the parent xmp node
+ * @param xmlNode the currently processed XML node
+ * @param isTopLevel Flag if the node is a top-level node
+ * @throws XMPException thown on parsing errors
+ */
+ private static void rdf_ParseTypeResourcePropertyElement(XMPMetaImpl xmp, XMPNode xmpParent,
+ Node xmlNode, boolean isTopLevel) throws XMPException
+ {
+ XMPNode newStruct = addChildNode (xmp, xmpParent, xmlNode, "", isTopLevel);
+
+ newStruct.getOptions().setStruct(true);
+
+ for (int i = 0; i < xmlNode.getAttributes().getLength(); i++)
+ {
+ Node attribute = xmlNode.getAttributes().item(i);
+ if ("xmlns".equals(attribute.getPrefix()) ||
+ (attribute.getPrefix() == null && "xmlns".equals(attribute.getNodeName())))
+ {
+ continue;
+ }
+
+ String attrLocal = attribute.getLocalName();
+ String attrNS = attribute.getNamespaceURI();
+ if (XML_LANG.equals(attribute.getNodeName()))
+ {
+ addQualifierNode (newStruct, XML_LANG, attribute.getNodeValue());
+ }
+ else if (NS_RDF.equals(attrNS) &&
+ ("ID".equals(attrLocal) || "parseType".equals(attrLocal)))
+ {
+ continue; // The caller ensured the value is "Resource".
+ // Ignore all rdf:ID attributes.
+ }
+ else
+ {
+ throw new XMPException("Invalid attribute for ParseTypeResource property element",
+ BADRDF);
+ }
+ }
+
+ rdf_PropertyElementList (xmp, newStruct, xmlNode, false);
+
+ if (newStruct.getHasValueChild())
+ {
+ fixupQualifiedNode (newStruct);
+ }
+ }
+
+
+ /**
+ * 7.2.19 parseTypeCollectionPropertyElt
+ * start-element ( URI == propertyElementURIs,
+ * attributes == set ( idAttr?, parseCollection ) )
+ * nodeElementList
+ * end-element()
+ *
+ * @throws XMPException thown on parsing errors
+ */
+ private static void rdf_ParseTypeCollectionPropertyElement() throws XMPException
+ {
+ throw new XMPException("ParseTypeCollection property element not allowed", BADXMP);
+ }
+
+
+ /**
+ * 7.2.20 parseTypeOtherPropertyElt
+ * start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, parseOther ) )
+ * propertyEltList
+ * end-element()
+ *
+ * @throws XMPException thown on parsing errors
+ */
+ private static void rdf_ParseTypeOtherPropertyElement() throws XMPException
+ {
+ throw new XMPException("ParseTypeOther property element not allowed", BADXMP);
+ }
+
+
+ /**
+ * 7.2.21 emptyPropertyElt
+ * start-element ( URI == propertyElementURIs,
+ * attributes == set (
+ * idAttr?, ( resourceAttr | nodeIdAttr )?, propertyAttr* ) )
+ * end-element()
+ *
+ * <ns:Prop1/> <!-- a simple property with an empty value -->
+ * <ns:Prop2 rdf:resource="http: *www.adobe.com/"/> <!-- a URI value -->
+ * <ns:Prop3 rdf:value="..." ns:Qual="..."/> <!-- a simple qualified property -->
+ * <ns:Prop4 ns:Field1="..." ns:Field2="..."/> <!-- a struct with simple fields -->
+ *
+ * An emptyPropertyElt is an element with no contained content, just a possibly empty set of
+ * attributes. An emptyPropertyElt can represent three special cases of simple XMP properties: a
+ * simple property with an empty value (ns:Prop1), a simple property whose value is a URI
+ * (ns:Prop2), or a simple property with simple qualifiers (ns:Prop3).
+ * An emptyPropertyElt can also represent an XMP struct whose fields are all simple and
+ * unqualified (ns:Prop4).
+ *
+ * It is an error to use both rdf:value and rdf:resource - that can lead to invalid RDF in the
+ * verbose form written using a literalPropertyElt.
+ *
+ * The XMP mapping for an emptyPropertyElt is a bit different from generic RDF, partly for
+ * design reasons and partly for historical reasons. The XMP mapping rules are:
+ * <ol>
+ * <li> If there is an rdf:value attribute then this is a simple property
+ * with a text value.
+ * All other attributes are qualifiers.
+ * <li> If there is an rdf:resource attribute then this is a simple property
+ * with a URI value.
+ * All other attributes are qualifiers.
+ * <li> If there are no attributes other than xml:lang, rdf:ID, or rdf:nodeID
+ * then this is a simple
+ * property with an empty value.
+ * <li> Otherwise this is a struct, the attributes other than xml:lang, rdf:ID,
+ * or rdf:nodeID are fields.
+ * </ol>
+ *
+ * @param xmp the xmp metadata object that is generated
+ * @param xmpParent the parent xmp node
+ * @param xmlNode the currently processed XML node
+ * @param isTopLevel Flag if the node is a top-level node
+ * @throws XMPException thown on parsing errors
+ */
+ private static void rdf_EmptyPropertyElement(XMPMetaImpl xmp, XMPNode xmpParent, Node xmlNode,
+ boolean isTopLevel) throws XMPException
+ {
+ boolean hasPropertyAttrs = false;
+ boolean hasResourceAttr = false;
+ boolean hasNodeIDAttr = false;
+ boolean hasValueAttr = false;
+
+ Node valueNode = null; // ! Can come from rdf:value or rdf:resource.
+
+ if (xmlNode.hasChildNodes())
+ {
+ throw new XMPException(
+ "Nested content not allowed with rdf:resource or property attributes",
+ BADRDF);
+ }
+
+ // First figure out what XMP this maps to and remember the XML node for a simple value.
+ for (int i = 0; i < xmlNode.getAttributes().getLength(); i++)
+ {
+ Node attribute = xmlNode.getAttributes().item(i);
+ if ("xmlns".equals(attribute.getPrefix()) ||
+ (attribute.getPrefix() == null && "xmlns".equals(attribute.getNodeName())))
+ {
+ continue;
+ }
+
+ int attrTerm = getRDFTermKind (attribute);
+
+ switch (attrTerm)
+ {
+ case RDFTERM_ID :
+ // Nothing to do.
+ break;
+
+ case RDFTERM_RESOURCE :
+ if (hasNodeIDAttr)
+ {
+ throw new XMPException(
+ "Empty property element can't have both rdf:resource and rdf:nodeID",
+ BADRDF);
+ }
+ else if (hasValueAttr)
+ {
+ throw new XMPException(
+ "Empty property element can't have both rdf:value and rdf:resource",
+ BADXMP);
+ }
+
+ hasResourceAttr = true;
+ if (!hasValueAttr)
+ {
+ valueNode = attribute;
+ }
+ break;
+
+ case RDFTERM_NODE_ID:
+ if (hasResourceAttr)
+ {
+ throw new XMPException(
+ "Empty property element can't have both rdf:resource and rdf:nodeID",
+ BADRDF);
+ }
+ hasNodeIDAttr = true;
+ break;
+
+ case RDFTERM_OTHER:
+ if ("value".equals(attribute.getLocalName())
+ && NS_RDF.equals(attribute.getNamespaceURI()))
+ {
+ if (hasResourceAttr)
+ {
+ throw new XMPException(
+ "Empty property element can't have both rdf:value and rdf:resource",
+ BADXMP);
+ }
+ hasValueAttr = true;
+ valueNode = attribute;
+ }
+ else if (!XML_LANG.equals(attribute.getNodeName()))
+ {
+ hasPropertyAttrs = true;
+ }
+ break;
+
+ default:
+ throw new XMPException("Unrecognized attribute of empty property element",
+ BADRDF);
+ }
+ }
+
+ // Create the right kind of child node and visit the attributes again
+ // to add the fields or qualifiers.
+ // ! Because of implementation vagaries,
+ // the xmpParent is the tree root for top level properties.
+ // ! The schema is found, created if necessary, by addChildNode.
+
+ XMPNode childNode = addChildNode(xmp, xmpParent, xmlNode, "", isTopLevel);
+ boolean childIsStruct = false;
+
+ if (hasValueAttr || hasResourceAttr)
+ {
+ childNode.setValue(valueNode != null ? valueNode.getNodeValue() : "");
+ if (!hasValueAttr)
+ {
+ // ! Might have both rdf:value and rdf:resource.
+ childNode.getOptions().setURI(true);
+ }
+ }
+ else if (hasPropertyAttrs)
+ {
+ childNode.getOptions().setStruct(true);
+ childIsStruct = true;
+ }
+
+ for (int i = 0; i < xmlNode.getAttributes().getLength(); i++)
+ {
+ Node attribute = xmlNode.getAttributes().item(i);
+ if (attribute == valueNode ||
+ "xmlns".equals(attribute.getPrefix()) ||
+ (attribute.getPrefix() == null && "xmlns".equals(attribute.getNodeName())))
+ {
+ continue; // Skip the rdf:value or rdf:resource attribute holding the value.
+ }
+
+ int attrTerm = getRDFTermKind (attribute);
+
+ switch (attrTerm)
+ {
+ case RDFTERM_ID :
+ case RDFTERM_NODE_ID :
+ break; // Ignore all rdf:ID and rdf:nodeID attributes.
+
+ case RDFTERM_RESOURCE :
+ addQualifierNode(childNode, "rdf:resource", attribute.getNodeValue());
+ break;
+
+ case RDFTERM_OTHER :
+ if (!childIsStruct)
+ {
+ addQualifierNode(
+ childNode, attribute.getNodeName(), attribute.getNodeValue());
+ }
+ else if (XML_LANG.equals(attribute.getNodeName()))
+ {
+ addQualifierNode (childNode, XML_LANG, attribute.getNodeValue());
+ }
+ else
+ {
+ addChildNode (xmp, childNode, attribute, attribute.getNodeValue(), false);
+ }
+ break;
+
+ default :
+ throw new XMPException("Unrecognized attribute of empty property element",
+ BADRDF);
+ }
+
+ }
+ }
+
+
+ /**
+ * Adds a child node.
+ *
+ * @param xmp the xmp metadata object that is generated
+ * @param xmpParent the parent xmp node
+ * @param xmlNode the currently processed XML node
+ * @param value Node value
+ * @param isTopLevel Flag if the node is a top-level node
+ * @return Returns the newly created child node.
+ * @throws XMPException thown on parsing errors
+ */
+ private static XMPNode addChildNode(XMPMetaImpl xmp, XMPNode xmpParent, Node xmlNode,
+ String value, boolean isTopLevel) throws XMPException
+ {
+ XMPSchemaRegistry registry = XMPMetaFactory.getSchemaRegistry();
+ String namespace = xmlNode.getNamespaceURI();
+ String childName;
+ if (namespace != null)
+ {
+ if (NS_DC_DEPRECATED.equals(namespace))
+ {
+ // Fix a legacy DC namespace
+ namespace = NS_DC;
+ }
+
+ String prefix = registry.getNamespacePrefix(namespace);
+ if (prefix == null)
+ {
+ prefix = xmlNode.getPrefix() != null ? xmlNode.getPrefix() : DEFAULT_PREFIX;
+ prefix = registry.registerNamespace(namespace, prefix);
+ }
+ childName = prefix + xmlNode.getLocalName();
+ }
+ else
+ {
+ throw new XMPException(
+ "XML namespace required for all elements and attributes", BADRDF);
+ }
+
+
+ // create schema node if not already there
+ PropertyOptions childOptions = new PropertyOptions();
+ boolean isAlias = false;
+ if (isTopLevel)
+ {
+ // Lookup the schema node, adjust the XMP parent pointer.
+ // Incoming parent must be the tree root.
+ XMPNode schemaNode = XMPNodeUtils.findSchemaNode(xmp.getRoot(), namespace,
+ DEFAULT_PREFIX, true);
+ schemaNode.setImplicit(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().setHasAliases(true);
+ schemaNode.setHasAliases(true);
+ }
+ }
+
+
+ // Make sure that this is not a duplicate of a named node.
+ boolean isArrayItem = "rdf:li".equals(childName);
+ boolean isValueNode = "rdf:value".equals(childName);
+
+ // Create XMP node and so some checks
+ XMPNode newChild = new XMPNode(
+ childName, value, childOptions);
+ newChild.setAlias(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.getOptions().isStruct())
+ {
+ throw new XMPException("Misplaced rdf:value element", BADRDF);
+ }
+ xmpParent.setHasValueChild(true);
+ }
+
+ if (isArrayItem)
+ {
+ if (!xmpParent.getOptions().isArray())
+ {
+ throw new XMPException("Misplaced rdf:li element", BADRDF);
+ }
+ newChild.setName(ARRAY_ITEM_NAME);
+ }
+
+ return newChild;
+ }
+
+
+ /**
+ * Adds a qualifier node.
+ *
+ * @param xmpParent the parent xmp node
+ * @param name the name of the qualifier which has to be
+ * QName including the <b>default prefix</b>
+ * @param value the value of the qualifier
+ * @return Returns the newly created child node.
+ * @throws XMPException thown on parsing errors
+ */
+ private static XMPNode addQualifierNode(XMPNode xmpParent, String name, String value)
+ throws XMPException
+ {
+ boolean isLang = XML_LANG.equals(name);
+ boolean isCompact = "pxmp:compact".equals(name);
+
+ XMPNode newQual = null;
+
+ if (isCompact)
+ {
+ if (xmpParent.getOptions().isCompositeProperty())
+ {
+ throw new XMPException("Only structs and arrays can be compact", BADXMP);
+ }
+ xmpParent.getOptions().setCompact(true);
+ }
+ else
+ {
+ // normalize value of language qualifiers
+ newQual = new XMPNode(name, isLang ? Utils.normalizeLangValue(value) : value, null);
+ xmpParent.addQualifier(newQual);
+ }
+
+ return newQual;
+ }
+
+
+ /**
+ * The parent is an RDF pseudo-struct containing an rdf:value field. Fix the
+ * XMP data model. The rdf:value node must be the first child, the other
+ * children are qualifiers. The form, value, and children of the rdf:value
+ * node are the real ones. The rdf:value node's qualifiers must be added to
+ * the others.
+ *
+ * @param xmpParent the parent xmp node
+ * @throws XMPException thown on parsing errors
+ */
+ private static void fixupQualifiedNode(XMPNode xmpParent) throws XMPException
+ {
+ assert xmpParent.getOptions().isStruct() && xmpParent.hasChildren();
+
+ XMPNode valueNode = xmpParent.getChild(1);
+ assert "rdf:value".equals(valueNode.getName());
+
+ // Move the qualifiers on the value node to the parent.
+ // Make sure an xml:lang qualifier stays at the front.
+ // Check for duplicate names between the value node's qualifiers and the parent's children.
+ // The parent's children are about to become qualifiers. Check here, between the groups.
+ // Intra-group duplicates are caught by XMPNode#addChild(...).
+ if (valueNode.getOptions().getHasLanguage())
+ {
+ if (xmpParent.getOptions().getHasLanguage())
+ {
+ throw new XMPException("Redundant xml:lang for rdf:value element",
+ BADXMP);
+ }
+ XMPNode langQual = valueNode.getQualifier(1);
+ valueNode.removeQualifier(langQual);
+ xmpParent.addQualifier(langQual);
+ }
+
+ // Start the remaining copy after the xml:lang qualifier.
+ for (int i = 1; i <= valueNode.getQualifierLength(); i++)
+ {
+ XMPNode qualifier = valueNode.getQualifier(i);
+ xmpParent.addQualifier(qualifier);
+ }
+
+
+ // Change the parent's other children into qualifiers.
+ // This loop starts at 1, child 0 is the rdf:value node.
+ for (int i = 2; i <= xmpParent.getChildrenLength(); i++)
+ {
+ XMPNode qualifier = xmpParent.getChild(i);
+
+ if ("pxmp:compact".equals(qualifier.getName()))
+ {
+ // Compactness is an option bit, not an actual qualifier.
+ if (!xmpParent.getOptions().isCompositeProperty())
+ {
+ throw new XMPException("Only structs and arrays can be compact", BADXMP);
+ }
+ xmpParent.getOptions().setCompact(true);
+ }
+ else
+ {
+ xmpParent.addQualifier(qualifier);
+ }
+ }
+
+ // Move the options and value last, other checks need the parent's original options.
+ // Move the value node's children to be the parent's children.
+ assert xmpParent.getOptions().isStruct() || xmpParent.getHasValueChild();
+
+ xmpParent.setHasValueChild(false);
+ xmpParent.getOptions().setStruct(false);
+ xmpParent.getOptions().mergeWith(valueNode.getOptions());
+ xmpParent.setValue(valueNode.getValue());
+
+ xmpParent.removeChildren();
+ for (Iterator it = valueNode.iterateChildren(); it.hasNext();)
+ {
+ XMPNode child = (XMPNode) it.next();
+ xmpParent.addChild(child);
+ }
+ }
+
+
+ /**
+ * Checks if the node is a white space.
+ * @param node an XML-node
+ * @return Returns whether the node is a whitespace node,
+ * i.e. a text node that contains only whitespaces.
+ */
+ private static boolean isWhitespaceNode(Node node)
+ {
+ if (node.getNodeType() != Node.TEXT_NODE)
+ {
+ return false;
+ }
+
+ String value = node.getNodeValue();
+ for (int i = 0; i < value.length(); i++)
+ {
+ if (!Character.isWhitespace(value.charAt(i)))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+
+ /**
+ * 7.2.6 propertyElementURIs
+ * anyURI - ( coreSyntaxTerms | rdf:Description | oldTerms )
+ *
+ * @param term the term id
+ * @return Return true if the term is a property element name.
+ */
+ private static boolean isPropertyElementName(int term)
+ {
+ if (term == RDFTERM_DESCRIPTION || isOldTerm(term))
+ {
+ return false;
+ }
+ else
+ {
+ return (!isCoreSyntaxTerm(term));
+ }
+ }
+
+
+ /**
+ * 7.2.4 oldTerms<br>
+ * rdf:aboutEach | rdf:aboutEachPrefix | rdf:bagID
+ *
+ * @param term the term id
+ * @return Returns true if the term is an old term.
+ */
+ private static boolean isOldTerm(int term)
+ {
+ return RDFTERM_FIRST_OLD <= term && term <= RDFTERM_LAST_OLD;
+ }
+
+
+ /**
+ * 7.2.2 coreSyntaxTerms<br>
+ * rdf:RDF | rdf:ID | rdf:about | rdf:parseType | rdf:resource | rdf:nodeID |
+ * rdf:datatype
+ *
+ * @param term the term id
+ * @return Return true if the term is a core syntax term
+ */
+ private static boolean isCoreSyntaxTerm(int term)
+ {
+ return RDFTERM_FIRST_CORE <= term && term <= RDFTERM_LAST_CORE;
+ }
+
+
+ /**
+ * Determines the ID for a certain RDF Term.
+ * Arranged to hopefully minimize the parse time for large XMP.
+ *
+ * @param node an XML node
+ * @return Returns the term ID.
+ */
+ private static int getRDFTermKind(Node node)
+ {
+ String localName = node.getLocalName();
+ String namespace = node.getNamespaceURI();
+
+ if (
+ namespace == null &&
+ ("about".equals(localName) || "ID".equals(localName)) &&
+ (node instanceof Attr) &&
+ NS_RDF.equals(((Attr) node).getOwnerElement().getNamespaceURI())
+ )
+ {
+ namespace = NS_RDF;
+ }
+
+ if (NS_RDF.equals(namespace))
+ {
+ if ("li".equals(localName))
+ {
+ return RDFTERM_LI;
+ }
+ else if ("parseType".equals(localName))
+ {
+ return RDFTERM_PARSE_TYPE;
+ }
+ else if ("Description".equals(localName))
+ {
+ return RDFTERM_DESCRIPTION;
+ }
+ else if ("about".equals(localName))
+ {
+ return RDFTERM_ABOUT;
+ }
+ else if ("resource".equals(localName))
+ {
+ return RDFTERM_RESOURCE;
+ }
+ else if ("RDF".equals(localName))
+ {
+ return RDFTERM_RDF;
+ }
+ else if ("ID".equals(localName))
+ {
+ return RDFTERM_ID;
+ }
+ else if ("nodeID".equals(localName))
+ {
+ return RDFTERM_NODE_ID;
+ }
+ else if ("datatype".equals(localName))
+ {
+ return RDFTERM_DATATYPE;
+ }
+ else if ("aboutEach".equals(localName))
+ {
+ return RDFTERM_ABOUT_EACH;
+ }
+ else if ("aboutEachPrefix".equals(localName))
+ {
+ return RDFTERM_ABOUT_EACH_PREFIX;
+ }
+ else if ("bagID".equals(localName))
+ {
+ return RDFTERM_BAG_ID;
+ }
+ }
+
+ return RDFTERM_OTHER;
+ }
+} \ No newline at end of file
diff --git a/java/XMPCore/src/com/adobe/xmp/impl/QName.java b/java/XMPCore/src/com/adobe/xmp/impl/QName.java
new file mode 100644
index 0000000..0e9e868
--- /dev/null
+++ b/java/XMPCore/src/com/adobe/xmp/impl/QName.java
@@ -0,0 +1,80 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+package com.adobe.xmp.impl;
+
+/**
+ * @since 09.11.2006
+ */
+public class QName
+{
+ /** XML namespace prefix */
+ private String prefix;
+ /** XML localname */
+ private String localName;
+
+
+ /**
+ * Splits a qname into prefix and localname.
+ * @param qname a QName
+ */
+ public QName(String qname)
+ {
+ int colon = qname.indexOf(':');
+
+ if (colon >= 0)
+ {
+ prefix = qname.substring(0, colon);
+ localName = qname.substring(colon + 1);
+ }
+ else
+ {
+ prefix = "";
+ localName = qname;
+ }
+ }
+
+
+ /** Constructor that initializes the fields
+ * @param prefix the prefix
+ * @param localName the name
+ */
+ public QName(String prefix, String localName)
+ {
+ this.prefix = prefix;
+ this.localName = localName;
+ }
+
+
+ /**
+ * @return Returns whether the QName has a prefix.
+ */
+ public boolean hasPrefix()
+ {
+ return prefix != null && prefix.length() > 0;
+ }
+
+
+ /**
+ * @return the localName
+ */
+ public String getLocalName()
+ {
+ return localName;
+ }
+
+
+ /**
+ * @return the prefix
+ */
+ public String getPrefix()
+ {
+ return prefix;
+ }
+} \ No newline at end of file
diff --git a/java/XMPCore/src/com/adobe/xmp/impl/Utils.java b/java/XMPCore/src/com/adobe/xmp/impl/Utils.java
new file mode 100644
index 0000000..009dbe7
--- /dev/null
+++ b/java/XMPCore/src/com/adobe/xmp/impl/Utils.java
@@ -0,0 +1,511 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+package com.adobe.xmp.impl;
+
+
+import com.adobe.xmp.XMPConst;
+
+
+/**
+ * Utility functions for the XMPToolkit implementation.
+ *
+ * @since 06.06.2006
+ */
+public class Utils implements XMPConst
+{
+ /** segments of a UUID */
+ public static final int UUID_SEGMENT_COUNT = 4;
+ /** length of a UUID */
+ public static final int UUID_LENGTH = 32 + UUID_SEGMENT_COUNT;
+ /** table of XML name start chars (<= 0xFF) */
+ private static boolean[] xmlNameStartChars;
+ /** table of XML name chars (<= 0xFF) */
+ private static boolean[] xmlNameChars;
+ /** init char tables */
+ static
+ {
+ initCharTables();
+ }
+
+
+ /**
+ * Private constructor
+ */
+ private Utils()
+ {
+ // EMPTY
+ }
+
+
+ /**
+ * Normalize an xml:lang value so that comparisons are effectively case
+ * insensitive as required by RFC 3066 (which superceeds RFC 1766). The
+ * normalization rules:
+ * <ul>
+ * <li> The primary subtag is lower case, the suggested practice of ISO 639.
+ * <li> All 2 letter secondary subtags are upper case, the suggested
+ * practice of ISO 3166.
+ * <li> All other subtags are lower case.
+ * </ul>
+ *
+ * @param value
+ * raw value
+ * @return Returns the normalized value.
+ */
+ public static String normalizeLangValue(String value)
+ {
+ // don't normalize x-default
+ if (XMPConst.X_DEFAULT.equals(value))
+ {
+ return value;
+ }
+
+ int subTag = 1;
+ StringBuffer buffer = new StringBuffer();
+
+ for (int i = 0; i < value.length(); i++)
+ {
+ switch (value.charAt(i))
+ {
+ case '-':
+ case '_':
+ // move to next subtag and convert underscore to hyphen
+ buffer.append('-');
+ subTag++;
+ break;
+ case ' ':
+ // remove spaces
+ break;
+ default:
+ // convert second subtag to uppercase, all other to lowercase
+ if (subTag != 2)
+ {
+ buffer.append(Character.toLowerCase(value.charAt(i)));
+ }
+ else
+ {
+ buffer.append(Character.toUpperCase(value.charAt(i)));
+ }
+ }
+
+ }
+ return buffer.toString();
+ }
+
+
+ /**
+ * Split the name and value parts for field and qualifier selectors:
+ * <ul>
+ * <li>[qualName="value"] - An element in an array of structs, chosen by a
+ * field value.
+ * <li>[?qualName="value"] - An element in an array, chosen by a qualifier
+ * value.
+ * </ul>
+ * The value portion is a string quoted by ''' or '"'. The value may contain
+ * any character including a doubled quoting character. The value may be
+ * empty. <em>Note:</em> It is assumed that the expression is formal
+ * correct
+ *
+ * @param selector
+ * the selector
+ * @return Returns an array where the first entry contains the name and the
+ * second the value.
+ */
+ static String[] splitNameAndValue(String selector)
+ {
+ // get the name
+ int eq = selector.indexOf('=');
+ int pos = 1;
+ if (selector.charAt(pos) == '?')
+ {
+ pos++;
+ }
+ String name = selector.substring(pos, eq);
+
+ // get the value
+ pos = eq + 1;
+ char quote = selector.charAt(pos);
+ pos++;
+ int end = selector.length() - 2; // quote and ]
+ StringBuffer value = new StringBuffer(end - eq);
+ while (pos < end)
+ {
+ value.append(selector.charAt(pos));
+ pos++;
+ if (selector.charAt(pos) == quote)
+ {
+ // skip one quote in value
+ pos++;
+ }
+ }
+ return new String[] { name, value.toString() };
+ }
+
+
+ /**
+ *
+ * @param schema
+ * a schema namespace
+ * @param prop
+ * an XMP Property
+ * @return Returns true if the property is defined as &quot;Internal
+ * Property&quot;, see XMP Specification.
+ */
+ static boolean isInternalProperty(String schema, String prop)
+ {
+ boolean isInternal = false;
+
+ if (NS_DC.equals(schema))
+ {
+ if ("dc:format".equals(prop) || "dc:language".equals(prop))
+ {
+ isInternal = true;
+ }
+ }
+ else if (NS_XMP.equals(schema))
+ {
+ if ("xap:BaseURL".equals(prop) || "xap:CreatorTool".equals(prop)
+ || "xap:Format".equals(prop) || "xap:Locale".equals(prop)
+ || "xap:MetadataDate".equals(prop) || "xap:ModifyDate".equals(prop))
+ {
+ isInternal = true;
+ }
+ }
+ else if (NS_PDF.equals(schema))
+ {
+ if ("pdf:BaseURL".equals(prop) || "pdf:Creator".equals(prop)
+ || "pdf:ModDate".equals(prop) || "pdf:PDFVersion".equals(prop)
+ || "pdf:Producer".equals(prop))
+ {
+ isInternal = true;
+ }
+ }
+ else if (NS_TIFF.equals(schema))
+ {
+ isInternal = true;
+ if ("tiff:ImageDescription".equals(prop) || "tiff:Artist".equals(prop)
+ || "tiff:Copyright".equals(prop))
+ {
+ isInternal = false;
+ }
+ }
+ else if (NS_EXIF.equals(schema))
+ {
+ isInternal = true;
+ if ("exif:UserComment".equals(prop))
+ {
+ isInternal = false;
+ }
+ }
+ else if (NS_EXIF_AUX.equals(schema))
+ {
+ isInternal = true;
+ }
+ else if (NS_PHOTOSHOP.equals(schema))
+ {
+ if ("photoshop:ICCProfile".equals(prop))
+ {
+ isInternal = true;
+ }
+ }
+ else if (NS_CAMERARAW.equals(schema))
+ {
+ if ("crs:Version".equals(prop) || "crs:RawFileName".equals(prop)
+ || "crs:ToneCurveName".equals(prop))
+ {
+ isInternal = true;
+ }
+ }
+ else if (NS_ADOBESTOCKPHOTO.equals(schema))
+ {
+ isInternal = true;
+ }
+ else if (NS_XMP_MM.equals(schema))
+ {
+ isInternal = true;
+ }
+ else if (TYPE_TEXT.equals(schema))
+ {
+ isInternal = true;
+ }
+ else if (TYPE_PAGEDFILE.equals(schema))
+ {
+ isInternal = true;
+ }
+ else if (TYPE_GRAPHICS.equals(schema))
+ {
+ isInternal = true;
+ }
+ else if (TYPE_IMAGE.equals(schema))
+ {
+ isInternal = true;
+ }
+ else if (TYPE_FONT.equals(schema))
+ {
+ isInternal = true;
+ }
+
+ return isInternal;
+ }
+
+
+ /**
+ * Check some requirements for an UUID:
+ * <ul>
+ * <li>Length of the UUID is 32</li>
+ * <li>The Delimiter count is 4 and all the 4 delimiter are on their right
+ * position (8,13,18,23)</li>
+ * </ul>
+ *
+ *
+ * @param uuid uuid to test
+ * @return true - this is a well formed UUID, false - UUID has not the expected format
+ */
+
+ static boolean checkUUIDFormat(String uuid)
+ {
+ boolean result = true;
+ int delimCnt = 0;
+ int delimPos = 0;
+
+ if (uuid == null)
+ {
+ return false;
+ }
+
+ for (delimPos = 0; delimPos < uuid.length(); delimPos++)
+ {
+ if (uuid.charAt(delimPos) == '-')
+ {
+ delimCnt++;
+ result = result &&
+ (delimPos == 8 || delimPos == 13 || delimPos == 18 || delimPos == 23);
+ }
+ }
+
+ return result && UUID_SEGMENT_COUNT == delimCnt && UUID_LENGTH == delimPos;
+ }
+
+
+ /**
+ * Simple check for valid XMLNames. Within ASCII range<br>
+ * ":" | [A-Z] | "_" | [a-z] | [#xC0-#xD6] | [#xD8-#xF6]<br>
+ * are accepted, above all characters (which is not entirely
+ * correct according to the XML Spec.
+ *
+ * @param name an XML Name
+ * @return Return <code>true</code> if the name is correct.
+ */
+ public static boolean isXMLName(String name)
+ {
+ if (name.length() > 0 && !isNameStartChar(name.charAt(0)))
+ {
+ return false;
+ }
+ for (int i = 1; i < name.length(); i++)
+ {
+ if (!isNameChar(name.charAt(i)))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+
+ /**
+ * Checks if the value is a legal "unqualified" XML name, as
+ * defined in the XML Namespaces proposed recommendation.
+ * These are XML names, except that they must not contain a colon.
+ * @param name the value to check
+ * @return Returns true if the name is a valid "unqualified" XML name.
+ */
+ public static boolean isXMLNameNS(String name)
+ {
+ if (name.length() > 0 && (!isNameStartChar(name.charAt(0)) || name.charAt(0) == ':'))
+ {
+ return false;
+ }
+ for (int i = 1; i < name.length(); i++)
+ {
+ if (!isNameChar(name.charAt(i)) || name.charAt(i) == ':')
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+
+ /**
+ * @param c a char
+ * @return Returns true if the char is an ASCII control char.
+ */
+ static boolean isControlChar(char c)
+ {
+ return (c <= 0x1F || c == 0x7F) &&
+ c != 0x09 && c != 0x0A && c != 0x0D;
+ }
+
+
+ /**
+ * Serializes the node value in XML encoding. Its used for tag bodies and
+ * attributes.<br>
+ * <em>Note:</em> The attribute is always limited by quotes,
+ * thats why <code>&amp;apos;</code> is never serialized.<br>
+ * <em>Note:</em> Control chars are written unescaped, but if the user uses others than tab, LF
+ * and CR the resulting XML will become invalid.
+ * @param value a string
+ * @param forAttribute flag if string is attribute value (need to additional escape quotes)
+ * @param escapeWhitespaces Decides if LF, CR and TAB are escaped.
+ * @return Returns the value ready for XML output.
+ */
+ public static String escapeXML(String value, boolean forAttribute, boolean escapeWhitespaces)
+ {
+ // quick check if character are contained that need special treatment
+ boolean needsEscaping = false;
+ for (int i = 0; i < value.length (); i++)
+ {
+ char c = value.charAt (i);
+ if (
+ c == '<' || c == '>' || c == '&' || // XML chars
+ (escapeWhitespaces && (c == '\t' || c == '\n' || c == '\r')) ||
+ (forAttribute && c == '"'))
+ {
+ needsEscaping = true;
+ break;
+ }
+ }
+
+ if (!needsEscaping)
+ {
+ // fast path
+ return value;
+ }
+ else
+ {
+ // slow path with escaping
+ StringBuffer buffer = new StringBuffer(value.length() * 4 / 3);
+ for (int i = 0; i < value.length (); i++)
+ {
+ char c = value.charAt (i);
+ if (!(escapeWhitespaces && (c == '\t' || c == '\n' || c == '\r')))
+ {
+ switch (c)
+ {
+ // we do what "Canonical XML" expects
+ // AUDIT: &apos; not serialized as only outer qoutes are used
+ case '<': buffer.append("&lt;"); continue;
+ case '>': buffer.append("&gt;"); continue;
+ case '&': buffer.append("&amp;"); continue;
+ case '"': buffer.append(forAttribute ? "&quot;" : "\""); continue;
+ default: buffer.append(c); continue;
+ }
+ }
+ else
+ {
+ // write control chars escaped,
+ // if there are others than tab, LF and CR the xml will become invalid.
+ buffer.append("&#x");
+ buffer.append(Integer.toHexString(c).toUpperCase());
+ buffer.append(';');
+ }
+ }
+ return buffer.toString();
+ }
+ }
+
+
+ /**
+ * Replaces the ASCII control chars with a space.
+ *
+ * @param value
+ * a node value
+ * @return Returns the cleaned up value
+ */
+ static String removeControlChars(String value)
+ {
+ StringBuffer buffer = new StringBuffer(value);
+ for (int i = 0; i < buffer.length(); i++)
+ {
+ if (isControlChar(buffer.charAt(i)))
+ {
+ buffer.setCharAt(i, ' ');
+ }
+ }
+ return buffer.toString();
+ }
+
+
+ /**
+ * Simple check if a character is a valid XML start name char.
+ * Within ASCII range<br>
+ * ":" | [A-Z] | "_" | [a-z] | [#xC0-#xD6] | [#xD8-#xF6]<br>
+ * are accepted, above all characters (which is not entirely
+ * correct according to the XML Spec)
+ *
+ * @param ch a character
+ * @return Returns true if the character is a valid first char of an XML name.
+ */
+ private static boolean isNameStartChar(char ch)
+ {
+ return ch > 0xFF || xmlNameStartChars[ch];
+ }
+
+
+ /**
+ * Simple check if a character is a valid XML name char
+ * (every char except the first one).
+ * Within ASCII range<br>
+ * ":" | [A-Z] | "_" | [a-z] | [#xC0-#xD6] | [#xD8-#xF6]<br>
+ * are accepted, above all characters (which is not entirely
+ * correct according to the XML Spec)
+ *
+ * @param ch a character
+ * @return Returns true if the character is a valid char of an XML name.
+ */
+ private static boolean isNameChar(char ch)
+ {
+ return ch > 0xFF || xmlNameChars[ch];
+ }
+
+
+ /**
+ * Initializes the char tables for later use.
+ */
+ private static void initCharTables()
+ {
+ xmlNameChars = new boolean[0x0100];
+ xmlNameStartChars = new boolean[0x0100];
+
+ for (char ch = 0; ch < xmlNameChars.length; ch++)
+ {
+ xmlNameStartChars[ch] =
+ ('a' <= ch && ch <= 'z') ||
+ ('A' <= ch && ch <= 'Z') ||
+ ch == ':' ||
+ ch == '_' ||
+ (0xC0 <= ch && ch <= 0xD6) ||
+ (0xD8 <= ch && ch <= 0xF6);
+
+ xmlNameChars[ch] =
+ ('a' <= ch && ch <= 'z') ||
+ ('A' <= ch && ch <= 'Z') ||
+ ('0' <= ch && ch <= '9') ||
+ ch == ':' ||
+ ch == '_' ||
+ ch == '-' ||
+ ch == '.' ||
+ ch == 0xB7 ||
+ (0xC0 <= ch && ch <= 0xD6) ||
+ (0xD8 <= ch && ch <= 0xF6);
+ }
+ }
+} \ No newline at end of file
diff --git a/java/XMPCore/src/com/adobe/xmp/impl/XMPDateTimeImpl.java b/java/XMPCore/src/com/adobe/xmp/impl/XMPDateTimeImpl.java
new file mode 100644
index 0000000..e0d0573
--- /dev/null
+++ b/java/XMPCore/src/com/adobe/xmp/impl/XMPDateTimeImpl.java
@@ -0,0 +1,303 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+package com.adobe.xmp.impl;
+
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.TimeZone;
+
+import com.adobe.xmp.XMPDateTime;
+import com.adobe.xmp.XMPException;
+
+
+/**
+ * The implementation of <code>XMPDateTime</code>. Internally a <code>calendar</code> is used
+ * plus an additional nano seconds field, because <code>Calendar</code> supports only milli
+ * seconds. The <code>nanoSeconds</code> convers only the resolution beyond a milli second.
+ *
+ * @since 16.02.2006
+ */
+public class XMPDateTimeImpl implements XMPDateTime
+{
+ /** */
+ private int year = 0;
+ /** */
+ private int month = 0;
+ /** */
+ private int day = 0;
+ /** */
+ private int hour = 0;
+ /** */
+ private int minute = 0;
+ /** */
+ private int second = 0;
+ /** Use the unversal time as default */
+ private TimeZone timeZone = TimeZone.getTimeZone("UTC");
+ /**
+ * The nano seconds take micro and nano seconds, while the milli seconds are in the calendar.
+ */
+ private int nanoSeconds;
+
+
+ /**
+ * Creates an <code>XMPDateTime</code>-instance with the current time in the default time
+ * zone.
+ */
+ public XMPDateTimeImpl()
+ {
+ // EMPTY
+ }
+
+
+ /**
+ * Creates an <code>XMPDateTime</code>-instance from a calendar.
+ *
+ * @param calendar a <code>Calendar</code>
+ */
+ public XMPDateTimeImpl(Calendar calendar)
+ {
+ year = calendar.get(Calendar.YEAR);
+ month = calendar.get(Calendar.MONTH) + 1; // cal is from 0..12
+ day = calendar.get(Calendar.DAY_OF_MONTH);
+ hour = calendar.get(Calendar.HOUR_OF_DAY);
+ minute = calendar.get(Calendar.MINUTE);
+ second = calendar.get(Calendar.SECOND);
+ nanoSeconds = calendar.get(Calendar.MILLISECOND) * 1000000;
+ timeZone = calendar.getTimeZone();
+ }
+
+
+ /**
+ * Creates an <code>XMPDateTime</code>-instance from an ISO 8601 string.
+ *
+ * @param strValue an ISO 8601 string
+ * @throws XMPException If the string is a non-conform ISO 8601 string, an exception is thrown
+ */
+ public XMPDateTimeImpl(String strValue) throws XMPException
+ {
+ ISO8601Converter.parse(strValue, this);
+ }
+
+
+ /**
+ * @see XMPDateTime#getYear()
+ */
+ public int getYear()
+ {
+ return year;
+ }
+
+
+ /**
+ * @see XMPDateTime#setYear(int)
+ */
+ public void setYear(int year)
+ {
+ this.year = Math.min(Math.abs(year), 9999);
+ }
+
+
+ /**
+ * @see XMPDateTime#getMonth()
+ */
+ public int getMonth()
+ {
+ return month;
+ }
+
+
+ /**
+ * @see XMPDateTime#setMonth(int)
+ */
+ public void setMonth(int month)
+ {
+ if (month < 1)
+ {
+ this.month = 1;
+ }
+ else if (month > 12)
+ {
+ this.month = 12;
+ }
+ else
+ {
+ this.month = month;
+ }
+ }
+
+
+ /**
+ * @see XMPDateTime#getDay()
+ */
+ public int getDay()
+ {
+ return day;
+ }
+
+
+ /**
+ * @see XMPDateTime#setDay(int)
+ */
+ public void setDay(int day)
+ {
+ if (day < 1)
+ {
+ this.day = 1;
+ }
+ else if (day > 31)
+ {
+ this.day = 31;
+ }
+ else
+ {
+ this.day = day;
+ }
+ }
+
+
+ /**
+ * @see XMPDateTime#getHour()
+ */
+ public int getHour()
+ {
+ return hour;
+ }
+
+
+ /**
+ * @see XMPDateTime#setHour(int)
+ */
+ public void setHour(int hour)
+ {
+ this.hour = Math.min(Math.abs(hour), 23);
+ }
+
+
+ /**
+ * @see XMPDateTime#getMinute()
+ */
+ public int getMinute()
+ {
+ return minute;
+ }
+
+
+ /**
+ * @see XMPDateTime#setMinute(int)
+ */
+ public void setMinute(int minute)
+ {
+ this.minute = Math.min(Math.abs(minute), 59);
+ }
+
+
+ /**
+ * @see XMPDateTime#getSecond()
+ */
+ public int getSecond()
+ {
+ return second;
+ }
+
+
+ /**
+ * @see XMPDateTime#setSecond(int)
+ */
+ public void setSecond(int second)
+ {
+ this.second = Math.min(Math.abs(second), 59);
+ }
+
+
+ /**
+ * @see XMPDateTime#getNanoSecond()
+ */
+ public int getNanoSecond()
+ {
+ return nanoSeconds;
+ }
+
+
+ /**
+ * @see XMPDateTime#setNanoSecond(int)
+ */
+ public void setNanoSecond(int nanoSecond)
+ {
+ this.nanoSeconds = nanoSecond;
+ }
+
+
+ /**
+ * @see Comparable#compareTo(Object)
+ */
+ public int compareTo(Object dt)
+ {
+ long d = getCalendar().getTimeInMillis()
+ - ((XMPDateTime) dt).getCalendar().getTimeInMillis();
+ if (d != 0)
+ {
+ return (int) (d % 2);
+ }
+ else
+ {
+ // if millis are equal, compare nanoseconds
+ d = nanoSeconds - ((XMPDateTime) dt).getNanoSecond();
+ return (int) (d % 2);
+ }
+ }
+
+
+ /**
+ * @see XMPDateTime#getTimeZone()
+ */
+ public TimeZone getTimeZone()
+ {
+ return timeZone;
+ }
+
+
+ /**
+ * @see XMPDateTime#setTimeZone(TimeZone)
+ */
+ public void setTimeZone(TimeZone timeZone)
+ {
+ this.timeZone = timeZone;
+ }
+
+
+ /**
+ * @see XMPDateTime#getCalendar()
+ */
+ public Calendar getCalendar()
+ {
+ Calendar calendar = new GregorianCalendar(year, month - 1, day, hour, minute, second);
+ calendar.set(Calendar.MILLISECOND, nanoSeconds / 1000000);
+ calendar.setTimeZone(timeZone);
+ return calendar;
+ }
+
+
+ /**
+ * @see XMPDateTime#getISO8601String()
+ */
+ public String getISO8601String()
+ {
+ return ISO8601Converter.render(this);
+ }
+
+
+ /**
+ * @return Returns the ISO string representation.
+ */
+ public String toString()
+ {
+ return getISO8601String();
+ }
+} \ No newline at end of file
diff --git a/java/XMPCore/src/com/adobe/xmp/impl/XMPIteratorImpl.java b/java/XMPCore/src/com/adobe/xmp/impl/XMPIteratorImpl.java
new file mode 100644
index 0000000..53ea83e
--- /dev/null
+++ b/java/XMPCore/src/com/adobe/xmp/impl/XMPIteratorImpl.java
@@ -0,0 +1,598 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+package com.adobe.xmp.impl;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+import com.adobe.xmp.XMPError;
+import com.adobe.xmp.XMPException;
+import com.adobe.xmp.XMPIterator;
+import com.adobe.xmp.impl.xpath.XMPPath;
+import com.adobe.xmp.impl.xpath.XMPPathParser;
+import com.adobe.xmp.options.IteratorOptions;
+import com.adobe.xmp.options.PropertyOptions;
+import com.adobe.xmp.properties.XMPPropertyInfo;
+
+
+/**
+ * The <code>XMPIterator</code> implementation.
+ * Iterates the XMP Tree according to a set of options.
+ * During the iteration the XMPMeta-object must not be changed.
+ * Calls to <code>skipSubtree()</code> / <code>skipSiblings()</code> will affect the iteration.
+ *
+ * @since 29.06.2006
+ */
+public class XMPIteratorImpl implements XMPIterator
+{
+ /** stores the iterator options */
+ private IteratorOptions options;
+ /** the base namespace of the property path, will be changed during the iteration */
+ private String baseNS = null;
+ /** flag to indicate that skipSiblings() has been called. */
+ protected boolean skipSiblings = false;
+ /** flag to indicate that skipSiblings() has been called. */
+ protected boolean skipSubtree = false;
+ /** the node iterator doing the work */
+ private Iterator nodeIterator = null;
+
+
+ /**
+ * Constructor with optionsl initial values. If <code>propName</code> is provided,
+ * <code>schemaNS</code> has also be provided.
+ * @param xmp the iterated metadata object.
+ * @param schemaNS the iteration is reduced to this schema (optional)
+ * @param propPath the iteration is redurce to this property within the <code>schemaNS</code>
+ * @param options advanced iteration options, see {@link IteratorOptions}
+ * @throws XMPException If the node defined by the paramters is not existing.
+ */
+ public XMPIteratorImpl(XMPMetaImpl xmp, String schemaNS, String propPath,
+ IteratorOptions options) throws XMPException
+ {
+ // make sure that options is defined at least with defaults
+ this.options = options != null ? options : new IteratorOptions();
+
+ // the start node of the iteration depending on the schema and property filter
+ XMPNode startNode = null;
+ String initialPath = null;
+ boolean baseSchema = schemaNS != null && schemaNS.length() > 0;
+ boolean baseProperty = propPath != null && propPath.length() > 0;
+
+ 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);
+ 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)
+ {
+ if (!this.options.isJustChildren())
+ {
+ nodeIterator = new NodeIterator(startNode, initialPath, 1);
+ }
+ else
+ {
+ nodeIterator = new NodeIteratorChildren(startNode, initialPath);
+ }
+ }
+ else
+ {
+ // create null iterator
+ nodeIterator = Collections.EMPTY_LIST.iterator();
+ }
+ }
+
+
+ /**
+ * @see XMPIterator#skipSubtree()
+ */
+ public void skipSubtree()
+ {
+ this.skipSubtree = true;
+ }
+
+
+ /**
+ * @see XMPIterator#skipSiblings()
+ */
+ public void skipSiblings()
+ {
+ skipSubtree();
+ this.skipSiblings = true;
+ }
+
+
+ /**
+ * @see java.util.Iterator#hasNext()
+ */
+ public boolean hasNext()
+ {
+ return nodeIterator.hasNext();
+ }
+
+
+ /**
+ * @see java.util.Iterator#next()
+ */
+ public Object next()
+ {
+ return nodeIterator.next();
+ }
+
+
+ /**
+ * @see java.util.Iterator#remove()
+ */
+ public void remove()
+ {
+ throw new UnsupportedOperationException("The XMPIterator does not support remove().");
+ }
+
+
+ /**
+ * @return Exposes the options for inner class.
+ */
+ protected IteratorOptions getOptions()
+ {
+ return options;
+ }
+
+
+ /**
+ * @return Exposes the options for inner class.
+ */
+ protected String getBaseNS()
+ {
+ return baseNS;
+ }
+
+
+ /**
+ * @param baseNS sets the baseNS from the inner class.
+ */
+ protected void setBaseNS(String baseNS)
+ {
+ this.baseNS = baseNS;
+ }
+
+
+
+
+
+
+ /**
+ * The <code>XMPIterator</code> implementation.
+ * It first returns the node itself, then recursivly the children and qualifier of the node.
+ *
+ * @since 29.06.2006
+ */
+ private class NodeIterator implements Iterator
+ {
+ /** iteration state */
+ protected static final int ITERATE_NODE = 0;
+ /** iteration state */
+ protected static final int ITERATE_CHILDREN = 1;
+ /** iteration state */
+ protected static final int ITERATE_QUALIFIER = 2;
+
+ /** the state of the iteration */
+ private int state = ITERATE_NODE;
+ /** the currently visited node */
+ private XMPNode visitedNode;
+ /** the recursively accumulated path */
+ private String path;
+ /** the iterator that goes through the children and qualifier list */
+ private Iterator childrenIterator = null;
+ /** index of node with parent, only interesting for arrays */
+ private int index = 0;
+ /** the iterator for each child */
+ private Iterator subIterator = Collections.EMPTY_LIST.iterator();
+ /** the cached <code>PropertyInfo</code> to return */
+ private XMPPropertyInfo returnProperty = null;
+
+
+ /**
+ * Default constructor
+ */
+ public NodeIterator()
+ {
+ // EMPTY
+ }
+
+
+ /**
+ * Constructor for the node iterator.
+ * @param visitedNode the currently visited node
+ * @param parentPath the accumulated path of the node
+ * @param index the index within the parent node (only for arrays)
+ */
+ public NodeIterator(XMPNode visitedNode, String parentPath, int index)
+ {
+ this.visitedNode = visitedNode;
+ this.state = NodeIterator.ITERATE_NODE;
+ if (visitedNode.getOptions().isSchemaNode())
+ {
+ setBaseNS(visitedNode.getName());
+ }
+
+ // for all but the root node and schema nodes
+ path = accumulatePath(visitedNode, parentPath, index);
+ }
+
+
+ /**
+ * Prepares the next node to return if not already done.
+ *
+ * @see Iterator#hasNext()
+ */
+ public boolean hasNext()
+ {
+ if (returnProperty != null)
+ {
+ // hasNext has been called before
+ return true;
+ }
+
+ // find next node
+ if (state == ITERATE_NODE)
+ {
+ return reportNode();
+ }
+ else if (state == ITERATE_CHILDREN)
+ {
+ if (childrenIterator == null)
+ {
+ childrenIterator = visitedNode.iterateChildren();
+ }
+
+ boolean hasNext = iterateChildren(childrenIterator);
+
+ if (!hasNext && visitedNode.hasQualifier() && !getOptions().isOmitQualifiers())
+ {
+ state = ITERATE_QUALIFIER;
+ childrenIterator = null;
+ hasNext = hasNext();
+ }
+ return hasNext;
+ }
+ else
+ {
+ if (childrenIterator == null)
+ {
+ childrenIterator = visitedNode.iterateQualifier();
+ }
+
+ return iterateChildren(childrenIterator);
+ }
+ }
+
+
+ /**
+ * Sets the returnProperty as next item or recurses into <code>hasNext()</code>.
+ * @return Returns if there is a next item to return.
+ */
+ protected boolean reportNode()
+ {
+ state = ITERATE_CHILDREN;
+ if (visitedNode.getParent() != null &&
+ (!getOptions().isJustLeafnodes() || !visitedNode.hasChildren()))
+ {
+ returnProperty = createPropertyInfo(visitedNode, getBaseNS(), path);
+ return true;
+ }
+ else
+ {
+ return hasNext();
+ }
+ }
+
+
+ /**
+ * Handles the iteration of the children or qualfier
+ * @param iterator an iterator
+ * @return Returns if there are more elements available.
+ */
+ private boolean iterateChildren(Iterator iterator)
+ {
+ if (skipSiblings)
+ {
+ // setSkipSiblings(false);
+ skipSiblings = false;
+ subIterator = Collections.EMPTY_LIST.iterator();
+ }
+
+ // create sub iterator for every child,
+ // if its the first child visited or the former child is finished
+ if ((!subIterator.hasNext()) && iterator.hasNext())
+ {
+ XMPNode child = (XMPNode) iterator.next();
+ index++;
+ subIterator = new NodeIterator(child, path, index);
+ }
+
+ if (subIterator.hasNext())
+ {
+ returnProperty = (XMPPropertyInfo) subIterator.next();
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+
+ /**
+ * Calls hasNext() and returnes the prepared node. Afterwards its set to null.
+ * The existance of returnProperty indicates if there is a next node, otherwise
+ * an exceptio is thrown.
+ *
+ * @see Iterator#next()
+ */
+ public Object next()
+ {
+ if (hasNext())
+ {
+ XMPPropertyInfo result = returnProperty;
+ returnProperty = null;
+ return result;
+ }
+ else
+ {
+ throw new NoSuchElementException("There are no more nodes to return");
+ }
+ }
+
+
+ /**
+ * Not supported.
+ * @see Iterator#remove()
+ */
+ public void remove()
+ {
+ throw new UnsupportedOperationException();
+ }
+
+
+ /**
+ * @param currNode the node that will be added to the path.
+ * @param parentPath the path up to this node.
+ * @param currentIndex the current array index if an arrey is traversed
+ * @return Returns the updated path.
+ */
+ protected String accumulatePath(XMPNode currNode, String parentPath, int currentIndex)
+ {
+ String separator;
+ String segmentName;
+ if (currNode.getParent() == null || currNode.getOptions().isSchemaNode())
+ {
+ return null;
+ }
+ else if (currNode.getParent().getOptions().isArray())
+ {
+ separator = "";
+ segmentName = "[" + String.valueOf(currentIndex) + "]";
+ }
+ else
+ {
+ separator = "/";
+ segmentName = currNode.getName();
+ }
+
+
+ if (parentPath == null || parentPath.length() == 0)
+ {
+ return segmentName;
+ }
+ else if (getOptions().isJustLeafname())
+ {
+ return !segmentName.startsWith("?") ?
+ segmentName :
+ segmentName.substring(1); // qualifier
+ }
+ else
+ {
+ return parentPath + separator + segmentName;
+ }
+ }
+
+
+ /**
+ * Creates a property info object from an <code>XMPNode</code>.
+ * @param node an <code>XMPNode</code>
+ * @param baseNS the base namespace to report
+ * @param path the full property path
+ * @return Returns a <code>XMPProperty</code>-object that serves representation of the node.
+ */
+ protected XMPPropertyInfo createPropertyInfo(final XMPNode node, final String baseNS,
+ final String path)
+ {
+ final Object value = node.getOptions().isSchemaNode() ? null : node.getValue();
+
+ return new XMPPropertyInfo()
+ {
+ public String getNamespace()
+ {
+ return baseNS;
+ }
+
+ public String getPath()
+ {
+ return path;
+ }
+
+ public Object getValue()
+ {
+ return value;
+ }
+
+ public PropertyOptions getOptions()
+ {
+ return node.getOptions();
+ }
+
+ public String getLanguage()
+ {
+ // the language is not reported
+ return null;
+ }
+ };
+ }
+
+
+ /**
+ * @return the childrenIterator
+ */
+ protected Iterator getChildrenIterator()
+ {
+ return childrenIterator;
+ }
+
+
+ /**
+ * @param childrenIterator the childrenIterator to set
+ */
+ protected void setChildrenIterator(Iterator childrenIterator)
+ {
+ this.childrenIterator = childrenIterator;
+ }
+
+
+ /**
+ * @return Returns the returnProperty.
+ */
+ protected XMPPropertyInfo getReturnProperty()
+ {
+ return returnProperty;
+ }
+
+
+ /**
+ * @param returnProperty the returnProperty to set
+ */
+ protected void setReturnProperty(XMPPropertyInfo returnProperty)
+ {
+ this.returnProperty = returnProperty;
+ }
+ }
+
+
+ /**
+ * This iterator is derived from the default <code>NodeIterator</code>,
+ * and is only used for the option {@link IteratorOptions#JUST_CHILDREN}.
+ *
+ * @since 02.10.2006
+ */
+ private class NodeIteratorChildren extends NodeIterator
+ {
+ /** */
+ private String parentPath;
+ /** */
+ private Iterator childrenIterator;
+ /** */
+ private int index = 0;
+
+
+ /**
+ * Constructor
+ * @param parentNode the node which children shall be iterated.
+ * @param parentPath the full path of the former node without the leaf node.
+ */
+ public NodeIteratorChildren(XMPNode parentNode, String parentPath)
+ {
+ if (parentNode.getOptions().isSchemaNode())
+ {
+ setBaseNS(parentNode.getName());
+ }
+ this.parentPath = accumulatePath(parentNode, parentPath, 1);
+
+ childrenIterator = parentNode.iterateChildren();
+ }
+
+
+ /**
+ * Prepares the next node to return if not already done.
+ *
+ * @see Iterator#hasNext()
+ */
+ public boolean hasNext()
+ {
+ if (getReturnProperty() != null)
+ {
+ // hasNext has been called before
+ return true;
+ }
+ else if (skipSiblings)
+ {
+ return false;
+ }
+ else if (childrenIterator.hasNext())
+ {
+ XMPNode child = (XMPNode) childrenIterator.next();
+ index++;
+
+ String path = null;
+ if (child.getOptions().isSchemaNode())
+ {
+ setBaseNS(child.getName());
+ }
+ else if (child.getParent() != null)
+ {
+ // for all but the root node and schema nodes
+ path = accumulatePath(child, parentPath, index);
+ }
+
+ // report next property, skip not-leaf nodes in case options is set
+ if (!getOptions().isJustLeafnodes() || !child.hasChildren())
+ {
+ setReturnProperty(createPropertyInfo(child, getBaseNS(), path));
+ return true;
+ }
+ else
+ {
+ return hasNext();
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/java/XMPCore/src/com/adobe/xmp/impl/XMPMetaImpl.java b/java/XMPCore/src/com/adobe/xmp/impl/XMPMetaImpl.java
new file mode 100644
index 0000000..251154d
--- /dev/null
+++ b/java/XMPCore/src/com/adobe/xmp/impl/XMPMetaImpl.java
@@ -0,0 +1,1389 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+package com.adobe.xmp.impl;
+
+import java.util.Calendar;
+import java.util.Iterator;
+
+import com.adobe.xmp.XMPConst;
+import com.adobe.xmp.XMPDateTime;
+import com.adobe.xmp.XMPError;
+import com.adobe.xmp.XMPException;
+import com.adobe.xmp.XMPIterator;
+import com.adobe.xmp.XMPMeta;
+import com.adobe.xmp.XMPPathFactory;
+import com.adobe.xmp.XMPUtils;
+import com.adobe.xmp.impl.xpath.XMPPath;
+import com.adobe.xmp.impl.xpath.XMPPathParser;
+import com.adobe.xmp.options.IteratorOptions;
+import com.adobe.xmp.options.PropertyOptions;
+import com.adobe.xmp.properties.XMPProperty;
+
+
+/**
+ * Implementation for {@link XMPMeta}.
+ *
+ * @since 17.02.2006
+ */
+public class XMPMetaImpl implements XMPMeta, XMPConst
+{
+ /** Property values are Strings by default */
+ private static final int VALUE_STRING = 0;
+ /** */
+ private static final int VALUE_BOOLEAN = 1;
+ /** */
+ private static final int VALUE_INTEGER = 2;
+ /** */
+ private static final int VALUE_LONG = 3;
+ /** */
+ private static final int VALUE_DOUBLE = 4;
+ /** */
+ private static final int VALUE_DATE = 5;
+ /** */
+ private static final int VALUE_CALENDAR = 6;
+ /** */
+ private static final int VALUE_BASE64 = 7;
+
+ /** root of the metadata tree */
+ private XMPNode tree;
+
+
+ /**
+ * Constructor for an empty metadata object.
+ */
+ public XMPMetaImpl()
+ {
+ // create root node
+ tree = new XMPNode(null, null, null);
+ }
+
+
+ /**
+ * Constructor for a cloned metadata tree.
+ *
+ * @param tree
+ * an prefilled metadata tree which fulfills all
+ * <code>XMPNode</code> contracts.
+ */
+ public XMPMetaImpl(XMPNode tree)
+ {
+ this.tree = tree;
+ }
+
+
+ /**
+ * @see XMPMeta#appendArrayItem(String, String, PropertyOptions, String,
+ * PropertyOptions)
+ */
+ public void appendArrayItem(String schemaNS, String arrayName, PropertyOptions arrayOptions,
+ String itemValue, PropertyOptions itemOptions) throws XMPException
+ {
+ ParameterAsserts.assertSchemaNS(schemaNS);
+ ParameterAsserts.assertArrayName(arrayName);
+
+ if (arrayOptions == null)
+ {
+ arrayOptions = new PropertyOptions();
+ }
+ if (!arrayOptions.isOnlyArrayOptions())
+ {
+ throw new XMPException("Only array form flags allowed for arrayOptions",
+ XMPError.BADOPTIONS);
+ }
+
+ // Check if array options are set correctly.
+ arrayOptions = XMPNodeUtils.verifySetOptions(arrayOptions, null);
+
+
+ // Locate or create the array. If it already exists, make sure the array
+ // form from the options
+ // parameter is compatible with the current state.
+ XMPPath arrayPath = XMPPathParser.expandXPath(schemaNS, arrayName);
+
+
+ // Just lookup, don't try to create.
+ XMPNode arrayNode = XMPNodeUtils.findNode(tree, arrayPath, false, null);
+
+ if (arrayNode != null)
+ {
+ // The array exists, make sure the form is compatible. Zero
+ // arrayForm means take what exists.
+ if (!arrayNode.getOptions().isArray())
+ {
+ throw new XMPException("The named property is not an array", XMPError.BADXPATH);
+ }
+ // if (arrayOptions != null && !arrayOptions.equalArrayTypes(arrayNode.getOptions()))
+ // {
+ // throw new XMPException("Mismatch of existing and specified array form", BADOPTIONS);
+ // }
+ }
+ else
+ {
+ // The array does not exist, try to create it.
+ if (arrayOptions.isArray())
+ {
+ arrayNode = XMPNodeUtils.findNode(tree, arrayPath, true, arrayOptions);
+ if (arrayNode == null)
+ {
+ throw new XMPException("Failure creating array node", XMPError.BADXPATH);
+ }
+ }
+ else
+ {
+ // array options missing
+ throw new XMPException("Explicit arrayOptions required to create new array",
+ XMPError.BADOPTIONS);
+ }
+ }
+
+ doSetArrayItem(arrayNode, ARRAY_LAST_ITEM, itemValue, itemOptions, true);
+ }
+
+
+ /**
+ * @see XMPMeta#appendArrayItem(String, String, String)
+ */
+ public void appendArrayItem(String schemaNS, String arrayName, String itemValue)
+ throws XMPException
+ {
+ appendArrayItem(schemaNS, arrayName, null, itemValue, null);
+ }
+
+
+ /**
+ * @throws XMPException
+ * @see XMPMeta#countArrayItems(String, String)
+ */
+ public int countArrayItems(String schemaNS, String arrayName) throws XMPException
+ {
+ ParameterAsserts.assertSchemaNS(schemaNS);
+ ParameterAsserts.assertArrayName(arrayName);
+
+ XMPPath arrayPath = XMPPathParser.expandXPath(schemaNS, arrayName);
+ XMPNode arrayNode = XMPNodeUtils.findNode(tree, arrayPath, false, null);
+
+ if (arrayNode == null)
+ {
+ return 0;
+ }
+
+ if (arrayNode.getOptions().isArray())
+ {
+ return arrayNode.getChildrenLength();
+ }
+ else
+ {
+ throw new XMPException("The named property is not an array", XMPError.BADXPATH);
+ }
+ }
+
+
+ /**
+ * @see XMPMeta#deleteArrayItem(String, String, int)
+ */
+ public void deleteArrayItem(String schemaNS, String arrayName, int itemIndex)
+ {
+ try
+ {
+ ParameterAsserts.assertSchemaNS(schemaNS);
+ ParameterAsserts.assertArrayName(arrayName);
+
+ String itemPath = XMPPathFactory.composeArrayItemPath(arrayName, itemIndex);
+ deleteProperty(schemaNS, itemPath);
+ }
+ catch (XMPException e)
+ {
+ // EMPTY, exceptions are ignored within delete
+ }
+ }
+
+
+ /**
+ * @see XMPMeta#deleteProperty(String, String)
+ */
+ public void deleteProperty(String schemaNS, String propName)
+ {
+ try
+ {
+ ParameterAsserts.assertSchemaNS(schemaNS);
+ ParameterAsserts.assertPropName(propName);
+
+ XMPPath expPath = XMPPathParser.expandXPath(schemaNS, propName);
+
+ XMPNode propNode = XMPNodeUtils.findNode(tree, expPath, false, null);
+ if (propNode != null)
+ {
+ XMPNodeUtils.deleteNode(propNode);
+ }
+ }
+ catch (XMPException e)
+ {
+ // EMPTY, exceptions are ignored within delete
+ }
+ }
+
+
+ /**
+ * @see XMPMeta#deleteQualifier(String, String, String, String)
+ */
+ public void deleteQualifier(String schemaNS, String propName, String qualNS, String qualName)
+ {
+ try
+ {
+ // Note: qualNS and qualName are checked inside composeQualfierPath
+ ParameterAsserts.assertSchemaNS(schemaNS);
+ ParameterAsserts.assertPropName(propName);
+
+ String qualPath = propName + XMPPathFactory.composeQualifierPath(qualNS, qualName);
+ deleteProperty(schemaNS, qualPath);
+ }
+ catch (XMPException e)
+ {
+ // EMPTY, exceptions within delete are ignored
+ }
+ }
+
+
+ /**
+ * @see XMPMeta#deleteStructField(String, String, String, String)
+ */
+ public void deleteStructField(String schemaNS, String structName, String fieldNS,
+ String fieldName)
+ {
+ try
+ {
+ // fieldNS and fieldName are checked inside composeStructFieldPath
+ ParameterAsserts.assertSchemaNS(schemaNS);
+ ParameterAsserts.assertStructName(structName);
+
+ String fieldPath = structName
+ + XMPPathFactory.composeStructFieldPath(fieldNS, fieldName);
+ deleteProperty(schemaNS, fieldPath);
+ }
+ catch (XMPException e)
+ {
+ // EMPTY, exceptions within delete are ignored
+ }
+ }
+
+
+ /**
+ * @see XMPMeta#doesPropertyExist(String, String)
+ */
+ public boolean doesPropertyExist(String schemaNS, String propName)
+ {
+ try
+ {
+ ParameterAsserts.assertSchemaNS(schemaNS);
+ ParameterAsserts.assertPropName(propName);
+
+ XMPPath expPath = XMPPathParser.expandXPath(schemaNS, propName);
+ final XMPNode propNode = XMPNodeUtils.findNode(tree, expPath, false, null);
+ return propNode != null;
+ }
+ catch (XMPException e)
+ {
+ return false;
+ }
+ }
+
+
+ /**
+ * @see XMPMeta#doesArrayItemExist(String, String, int)
+ */
+ public boolean doesArrayItemExist(String schemaNS, String arrayName, int itemIndex)
+ {
+ try
+ {
+ ParameterAsserts.assertSchemaNS(schemaNS);
+ ParameterAsserts.assertArrayName(arrayName);
+
+ String path = XMPPathFactory.composeArrayItemPath(arrayName, itemIndex);
+ return doesPropertyExist(schemaNS, path);
+ }
+ catch (XMPException e)
+ {
+ return false;
+ }
+ }
+
+
+ /**
+ * @see XMPMeta#doesStructFieldExist(String, String, String, String)
+ */
+ public boolean doesStructFieldExist(String schemaNS, String structName, String fieldNS,
+ String fieldName)
+ {
+ try
+ {
+ // fieldNS and fieldName are checked inside composeStructFieldPath()
+ ParameterAsserts.assertSchemaNS(schemaNS);
+ ParameterAsserts.assertStructName(structName);
+
+ String path = XMPPathFactory.composeStructFieldPath(fieldNS, fieldName);
+ return doesPropertyExist(schemaNS, structName + path);
+ }
+ catch (XMPException e)
+ {
+ return false;
+ }
+ }
+
+
+ /**
+ * @see XMPMeta#doesQualifierExist(String, String, String, String)
+ */
+ public boolean doesQualifierExist(String schemaNS, String propName, String qualNS,
+ String qualName)
+ {
+ try
+ {
+ // qualNS and qualName are checked inside composeQualifierPath()
+ ParameterAsserts.assertSchemaNS(schemaNS);
+ ParameterAsserts.assertPropName(propName);
+
+ String path = XMPPathFactory.composeQualifierPath(qualNS, qualName);
+ return doesPropertyExist(schemaNS, propName + path);
+ }
+ catch (XMPException e)
+ {
+ return false;
+ }
+ }
+
+
+ /**
+ * @see XMPMeta#getArrayItem(String, String, int)
+ */
+ public XMPProperty getArrayItem(String schemaNS, String arrayName, int itemIndex)
+ throws XMPException
+ {
+ ParameterAsserts.assertSchemaNS(schemaNS);
+ ParameterAsserts.assertArrayName(arrayName);
+
+ String itemPath = XMPPathFactory.composeArrayItemPath(arrayName, itemIndex);
+ return getProperty(schemaNS, itemPath);
+ }
+
+
+ /**
+ * @throws XMPException
+ * @see XMPMeta#getLocalizedText(String, String, String, String)
+ */
+ public XMPProperty getLocalizedText(String schemaNS, String altTextName, String genericLang,
+ String specificLang) throws XMPException
+ {
+ ParameterAsserts.assertSchemaNS(schemaNS);
+ ParameterAsserts.assertArrayName(altTextName);
+ ParameterAsserts.assertSpecificLang(specificLang);
+
+ genericLang = genericLang != null ? Utils.normalizeLangValue(genericLang) : null;
+ specificLang = Utils.normalizeLangValue(specificLang);
+
+ XMPPath arrayPath = XMPPathParser.expandXPath(schemaNS, altTextName);
+ XMPNode arrayNode = XMPNodeUtils.findNode(tree, arrayPath, false, null);
+ if (arrayNode == null)
+ {
+ return null;
+ }
+
+ Object[] result = XMPNodeUtils.chooseLocalizedText(arrayNode, genericLang, specificLang);
+ int match = ((Integer) result[0]).intValue();
+ final XMPNode itemNode = (XMPNode) result[1];
+
+ if (match != XMPNodeUtils.CLT_NO_VALUES)
+ {
+ return new XMPProperty()
+ {
+ public Object getValue()
+ {
+ return itemNode.getValue();
+ }
+
+
+ public PropertyOptions getOptions()
+ {
+ return itemNode.getOptions();
+ }
+
+
+ public String getLanguage()
+ {
+ return itemNode.getQualifier(1).getValue();
+ }
+
+
+ public String toString()
+ {
+ return itemNode.getValue().toString();
+ }
+ };
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+
+ /**
+ * @see XMPMeta#setLocalizedText(String, String, String, String, String,
+ * PropertyOptions)
+ */
+ public void setLocalizedText(String schemaNS, String altTextName, String genericLang,
+ String specificLang, String itemValue, PropertyOptions options) throws XMPException
+ {
+ ParameterAsserts.assertSchemaNS(schemaNS);
+ ParameterAsserts.assertArrayName(altTextName);
+ ParameterAsserts.assertSpecificLang(specificLang);
+
+ genericLang = genericLang != null ? Utils.normalizeLangValue(genericLang) : null;
+ specificLang = Utils.normalizeLangValue(specificLang);
+
+ XMPPath arrayPath = XMPPathParser.expandXPath(schemaNS, altTextName);
+
+ // Find the array node and set the options if it was just created.
+ XMPNode arrayNode = XMPNodeUtils.findNode(tree, arrayPath, true, new PropertyOptions(
+ PropertyOptions.ARRAY | PropertyOptions.ARRAY_ORDERED
+ | PropertyOptions.ARRAY_ALTERNATE | PropertyOptions.ARRAY_ALT_TEXT));
+
+ if (arrayNode == null)
+ {
+ throw new XMPException("Failed to find or create array node", XMPError.BADXPATH);
+ }
+ else if (!arrayNode.getOptions().isArrayAltText())
+ {
+ if (!arrayNode.hasChildren() && arrayNode.getOptions().isArrayAlternate())
+ {
+ arrayNode.getOptions().setArrayAltText(true);
+ }
+ else
+ {
+ throw new XMPException(
+ "Specified property is no alt-text array", XMPError.BADXPATH);
+ }
+ }
+
+ // Make sure the x-default item, if any, is first.
+ boolean haveXDefault = false;
+ XMPNode xdItem = null;
+
+ for (Iterator it = arrayNode.iterateChildren(); it.hasNext();)
+ {
+ XMPNode currItem = (XMPNode) it.next();
+ if (!currItem.hasQualifier()
+ || !XMPConst.XML_LANG.equals(currItem.getQualifier(1).getName()))
+ {
+ throw new XMPException("Language qualifier must be first", XMPError.BADXPATH);
+ }
+ else if (XMPConst.X_DEFAULT.equals(currItem.getQualifier(1).getValue()))
+ {
+ xdItem = currItem;
+ haveXDefault = true;
+ break;
+ }
+ }
+
+ // Moves x-default to the beginning of the array
+ if (xdItem != null && arrayNode.getChildrenLength() > 1)
+ {
+ arrayNode.removeChild(xdItem);
+ arrayNode.addChild(1, xdItem);
+ }
+
+ // Find the appropriate item.
+ // chooseLocalizedText will make sure the array is a language
+ // alternative.
+ Object[] result = XMPNodeUtils.chooseLocalizedText(arrayNode, genericLang, specificLang);
+ int match = ((Integer) result[0]).intValue();
+ XMPNode itemNode = (XMPNode) result[1];
+
+ boolean specificXDefault = XMPConst.X_DEFAULT.equals(specificLang);
+
+ switch (match)
+ {
+ case XMPNodeUtils.CLT_NO_VALUES:
+
+ // Create the array items for the specificLang and x-default, with
+ // x-default first.
+ XMPNodeUtils.appendLangItem(arrayNode, XMPConst.X_DEFAULT, itemValue);
+ haveXDefault = true;
+ if (!specificXDefault)
+ {
+ XMPNodeUtils.appendLangItem(arrayNode, specificLang, itemValue);
+ }
+ break;
+
+ case XMPNodeUtils.CLT_SPECIFIC_MATCH:
+
+ if (!specificXDefault)
+ {
+ // Update the specific item, update x-default if it matches the
+ // old value.
+ if (haveXDefault && xdItem != itemNode && xdItem != null
+ && xdItem.getValue().equals(itemNode.getValue()))
+ {
+ xdItem.setValue(itemValue);
+ }
+ // ! Do this after the x-default check!
+ itemNode.setValue(itemValue);
+ }
+ else
+ {
+ // Update all items whose values match the old x-default value.
+ assert haveXDefault && xdItem == itemNode;
+ for (Iterator it = arrayNode.iterateChildren(); it.hasNext();)
+ {
+ XMPNode currItem = (XMPNode) it.next();
+ if (currItem == xdItem
+ || !currItem.getValue().equals(
+ xdItem != null ? xdItem.getValue() : null))
+ {
+ continue;
+ }
+ currItem.setValue(itemValue);
+ }
+ // And finally do the x-default item.
+ if (xdItem != null)
+ {
+ xdItem.setValue(itemValue);
+ }
+ }
+ break;
+
+ case XMPNodeUtils.CLT_SINGLE_GENERIC:
+
+ // Update the generic item, update x-default if it matches the old
+ // value.
+ if (haveXDefault && xdItem != itemNode && xdItem != null
+ && xdItem.getValue().equals(itemNode.getValue()))
+ {
+ xdItem.setValue(itemValue);
+ }
+ itemNode.setValue(itemValue); // ! Do this after
+ // the x-default
+ // check!
+ break;
+
+ case XMPNodeUtils.CLT_MULTIPLE_GENERIC:
+
+ // Create the specific language, ignore x-default.
+ XMPNodeUtils.appendLangItem(arrayNode, specificLang, itemValue);
+ if (specificXDefault)
+ {
+ haveXDefault = true;
+ }
+ break;
+
+ case XMPNodeUtils.CLT_XDEFAULT:
+
+ // Create the specific language, update x-default if it was the only
+ // item.
+ if (xdItem != null && arrayNode.getChildrenLength() == 1)
+ {
+ xdItem.setValue(itemValue);
+ }
+ XMPNodeUtils.appendLangItem(arrayNode, specificLang, itemValue);
+ break;
+
+ case XMPNodeUtils.CLT_FIRST_ITEM:
+
+ // Create the specific language, don't add an x-default item.
+ XMPNodeUtils.appendLangItem(arrayNode, specificLang, itemValue);
+ if (specificXDefault)
+ {
+ haveXDefault = true;
+ }
+ break;
+
+ default:
+ // does not happen under normal circumstances
+ throw new XMPException("Unexpected result from ChooseLocalizedText",
+ XMPError.INTERNALFAILURE);
+
+ }
+
+ // Add an x-default at the front if needed.
+ if (!haveXDefault && arrayNode.getChildrenLength() == 1)
+ {
+ XMPNodeUtils.appendLangItem(arrayNode, XMPConst.X_DEFAULT, itemValue);
+ }
+ }
+
+
+ /**
+ * @see XMPMeta#setLocalizedText(String, String, String, String, String)
+ */
+ public void setLocalizedText(String schemaNS, String altTextName, String genericLang,
+ String specificLang, String itemValue) throws XMPException
+ {
+ setLocalizedText(schemaNS, altTextName, genericLang, specificLang, itemValue, null);
+ }
+
+
+ /**
+ * @throws XMPException
+ * @see XMPMeta#getProperty(String, String)
+ */
+ public XMPProperty getProperty(String schemaNS, String propName) throws XMPException
+ {
+ return getProperty(schemaNS, propName, VALUE_STRING);
+ }
+
+
+ /**
+ * Returns a property, but the result value can be requested. It can be one
+ * of {@link XMPMetaImpl#VALUE_STRING}, {@link XMPMetaImpl#VALUE_BOOLEAN},
+ * {@link XMPMetaImpl#VALUE_INTEGER}, {@link XMPMetaImpl#VALUE_LONG},
+ * {@link XMPMetaImpl#VALUE_DOUBLE}, {@link XMPMetaImpl#VALUE_DATE},
+ * {@link XMPMetaImpl#VALUE_CALENDAR}, {@link XMPMetaImpl#VALUE_BASE64}.
+ *
+ * @see XMPMeta#getProperty(String, String)
+ * @param schemaNS
+ * a schema namespace
+ * @param propName
+ * a property name or path
+ * @param valueType
+ * the type of the value, see VALUE_...
+ * @return Returns an <code>XMPProperty</code>
+ * @throws XMPException
+ * Collects any exception that occurs.
+ */
+ protected XMPProperty getProperty(String schemaNS, String propName, int valueType)
+ throws XMPException
+ {
+ ParameterAsserts.assertSchemaNS(schemaNS);
+ ParameterAsserts.assertPropName(propName);
+
+ final XMPPath expPath = XMPPathParser.expandXPath(schemaNS, propName);
+ final XMPNode propNode = XMPNodeUtils.findNode(tree, expPath, false, null);
+
+ if (propNode != null)
+ {
+ if (valueType != VALUE_STRING && propNode.getOptions().isCompositeProperty())
+ {
+ throw new XMPException("Property must be simple when a value type is requested",
+ XMPError.BADXPATH);
+ }
+
+ final Object value = evaluateNodeValue(valueType, propNode);
+
+ return new XMPProperty()
+ {
+ public Object getValue()
+ {
+ return value;
+ }
+
+
+ public PropertyOptions getOptions()
+ {
+ return propNode.getOptions();
+ }
+
+
+ public String getLanguage()
+ {
+ return null;
+ }
+
+
+ public String toString()
+ {
+ return value.toString();
+ }
+ };
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+
+ /**
+ * Returns a property, but the result value can be requested.
+ *
+ * @see XMPMeta#getProperty(String, String)
+ * @param schemaNS
+ * a schema namespace
+ * @param propName
+ * a property name or path
+ * @param valueType
+ * the type of the value, see VALUE_...
+ * @return Returns the node value as an object according to the
+ * <code>valueType</code>.
+ * @throws XMPException
+ * Collects any exception that occurs.
+ */
+ protected Object getPropertyObject(String schemaNS, String propName, int valueType)
+ throws XMPException
+ {
+ ParameterAsserts.assertSchemaNS(schemaNS);
+ ParameterAsserts.assertPropName(propName);
+
+ final XMPPath expPath = XMPPathParser.expandXPath(schemaNS, propName);
+ final XMPNode propNode = XMPNodeUtils.findNode(tree, expPath, false, null);
+
+ if (propNode != null)
+ {
+ if (valueType != VALUE_STRING && propNode.getOptions().isCompositeProperty())
+ {
+ throw new XMPException("Property must be simple when a value type is requested",
+ XMPError.BADXPATH);
+ }
+
+ return evaluateNodeValue(valueType, propNode);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+
+ /**
+ * @see XMPMeta#getPropertyBoolean(String, String)
+ */
+ public Boolean getPropertyBoolean(String schemaNS, String propName) throws XMPException
+ {
+ return (Boolean) getPropertyObject(schemaNS, propName, VALUE_BOOLEAN);
+ }
+
+
+ /**
+ * @throws XMPException
+ * @see XMPMeta#setPropertyBoolean(String, String, boolean, PropertyOptions)
+ */
+ public void setPropertyBoolean(String schemaNS, String propName, boolean propValue,
+ PropertyOptions options) throws XMPException
+ {
+ setProperty(schemaNS, propName, propValue ? TRUESTR : FALSESTR, options);
+ }
+
+
+ /**
+ * @see XMPMeta#setPropertyBoolean(String, String, boolean)
+ */
+ public void setPropertyBoolean(String schemaNS, String propName, boolean propValue)
+ throws XMPException
+ {
+ setProperty(schemaNS, propName, propValue ? TRUESTR : FALSESTR, null);
+ }
+
+
+ /**
+ * @see XMPMeta#getPropertyInteger(String, String)
+ */
+ public Integer getPropertyInteger(String schemaNS, String propName) throws XMPException
+ {
+ return (Integer) getPropertyObject(schemaNS, propName, VALUE_INTEGER);
+ }
+
+
+ /**
+ * @see XMPMeta#setPropertyInteger(String, String, int, PropertyOptions)
+ */
+ public void setPropertyInteger(String schemaNS, String propName, int propValue,
+ PropertyOptions options) throws XMPException
+ {
+ setProperty(schemaNS, propName, new Integer(propValue), options);
+ }
+
+
+ /**
+ * @see XMPMeta#setPropertyInteger(String, String, int)
+ */
+ public void setPropertyInteger(String schemaNS, String propName, int propValue)
+ throws XMPException
+ {
+ setProperty(schemaNS, propName, new Integer(propValue), null);
+ }
+
+
+ /**
+ * @see XMPMeta#getPropertyLong(String, String)
+ */
+ public Long getPropertyLong(String schemaNS, String propName) throws XMPException
+ {
+ return (Long) getPropertyObject(schemaNS, propName, VALUE_LONG);
+ }
+
+
+ /**
+ * @see XMPMeta#setPropertyLong(String, String, long, PropertyOptions)
+ */
+ public void setPropertyLong(String schemaNS, String propName, long propValue,
+ PropertyOptions options) throws XMPException
+ {
+ setProperty(schemaNS, propName, new Long(propValue), options);
+ }
+
+
+ /**
+ * @see XMPMeta#setPropertyLong(String, String, long)
+ */
+ public void setPropertyLong(String schemaNS, String propName, long propValue)
+ throws XMPException
+ {
+ setProperty(schemaNS, propName, new Long(propValue), null);
+ }
+
+
+ /**
+ * @see XMPMeta#getPropertyDouble(String, String)
+ */
+ public Double getPropertyDouble(String schemaNS, String propName) throws XMPException
+ {
+ return (Double) getPropertyObject(schemaNS, propName, VALUE_DOUBLE);
+ }
+
+
+ /**
+ * @see XMPMeta#setPropertyDouble(String, String, double, PropertyOptions)
+ */
+ public void setPropertyDouble(String schemaNS, String propName, double propValue,
+ PropertyOptions options) throws XMPException
+ {
+ setProperty(schemaNS, propName, new Double(propValue), options);
+ }
+
+
+ /**
+ * @see XMPMeta#setPropertyDouble(String, String, double)
+ */
+ public void setPropertyDouble(String schemaNS, String propName, double propValue)
+ throws XMPException
+ {
+ setProperty(schemaNS, propName, new Double(propValue), null);
+ }
+
+
+ /**
+ * @see XMPMeta#getPropertyDate(String, String)
+ */
+ public XMPDateTime getPropertyDate(String schemaNS, String propName) throws XMPException
+ {
+ return (XMPDateTime) getPropertyObject(schemaNS, propName, VALUE_DATE);
+ }
+
+
+ /**
+ * @see XMPMeta#setPropertyDate(String, String, XMPDateTime,
+ * PropertyOptions)
+ */
+ public void setPropertyDate(String schemaNS, String propName, XMPDateTime propValue,
+ PropertyOptions options) throws XMPException
+ {
+ setProperty(schemaNS, propName, propValue, options);
+ }
+
+
+ /**
+ * @see XMPMeta#setPropertyDate(String, String, XMPDateTime)
+ */
+ public void setPropertyDate(String schemaNS, String propName, XMPDateTime propValue)
+ throws XMPException
+ {
+ setProperty(schemaNS, propName, propValue, null);
+ }
+
+
+ /**
+ * @see XMPMeta#getPropertyCalendar(String, String)
+ */
+ public Calendar getPropertyCalendar(String schemaNS, String propName) throws XMPException
+ {
+ return (Calendar) getPropertyObject(schemaNS, propName, VALUE_CALENDAR);
+ }
+
+
+ /**
+ * @see XMPMeta#setPropertyCalendar(String, String, Calendar,
+ * PropertyOptions)
+ */
+ public void setPropertyCalendar(String schemaNS, String propName, Calendar propValue,
+ PropertyOptions options) throws XMPException
+ {
+ setProperty(schemaNS, propName, propValue, options);
+ }
+
+
+ /**
+ * @see XMPMeta#setPropertyCalendar(String, String, Calendar)
+ */
+ public void setPropertyCalendar(String schemaNS, String propName, Calendar propValue)
+ throws XMPException
+ {
+ setProperty(schemaNS, propName, propValue, null);
+ }
+
+
+ /**
+ * @see XMPMeta#getPropertyBase64(String, String)
+ */
+ public byte[] getPropertyBase64(String schemaNS, String propName) throws XMPException
+ {
+ return (byte[]) getPropertyObject(schemaNS, propName, VALUE_BASE64);
+ }
+
+
+ /**
+ * @see XMPMeta#getPropertyString(String, String)
+ */
+ public String getPropertyString(String schemaNS, String propName) throws XMPException
+ {
+ return (String) getPropertyObject(schemaNS, propName, VALUE_STRING);
+ }
+
+
+ /**
+ * @see XMPMeta#setPropertyBase64(String, String, byte[], PropertyOptions)
+ */
+ public void setPropertyBase64(String schemaNS, String propName, byte[] propValue,
+ PropertyOptions options) throws XMPException
+ {
+ setProperty(schemaNS, propName, propValue, options);
+ }
+
+
+ /**
+ * @see XMPMeta#setPropertyBase64(String, String, byte[])
+ */
+ public void setPropertyBase64(String schemaNS, String propName, byte[] propValue)
+ throws XMPException
+ {
+ setProperty(schemaNS, propName, propValue, null);
+ }
+
+
+ /**
+ * @throws XMPException
+ * @see XMPMeta#getQualifier(String, String, String, String)
+ */
+ public XMPProperty getQualifier(String schemaNS, String propName, String qualNS,
+ String qualName) throws XMPException
+ {
+ // qualNS and qualName are checked inside composeQualfierPath
+ ParameterAsserts.assertSchemaNS(schemaNS);
+ ParameterAsserts.assertPropName(propName);
+
+ String qualPath = propName + XMPPathFactory.composeQualifierPath(qualNS, qualName);
+ return getProperty(schemaNS, qualPath);
+ }
+
+
+ /**
+ * @see XMPMeta#getStructField(String, String, String, String)
+ */
+ public XMPProperty getStructField(String schemaNS, String structName, String fieldNS,
+ String fieldName) throws XMPException
+ {
+ // fieldNS and fieldName are checked inside composeStructFieldPath
+ ParameterAsserts.assertSchemaNS(schemaNS);
+ ParameterAsserts.assertStructName(structName);
+
+ String fieldPath = structName + XMPPathFactory.composeStructFieldPath(fieldNS, fieldName);
+ return getProperty(schemaNS, fieldPath);
+ }
+
+
+ /**
+ * @throws XMPException
+ * @see XMPMeta#iterator()
+ */
+ public XMPIterator iterator() throws XMPException
+ {
+ return iterator(null, null, null);
+ }
+
+
+ /**
+ * @see XMPMeta#iterator(IteratorOptions)
+ */
+ public XMPIterator iterator(IteratorOptions options) throws XMPException
+ {
+ return iterator(null, null, options);
+ }
+
+
+ /**
+ * @see XMPMeta#iterator(String, String, IteratorOptions)
+ */
+ public XMPIterator iterator(String schemaNS, String propName, IteratorOptions options)
+ throws XMPException
+ {
+ return new XMPIteratorImpl(this, schemaNS, propName, options);
+ }
+
+
+ /**
+ * @throws XMPException
+ * @see XMPMeta#setArrayItem(String, String, int, String, PropertyOptions)
+ */
+ public void setArrayItem(String schemaNS, String arrayName, int itemIndex, String itemValue,
+ PropertyOptions options) throws XMPException
+ {
+ ParameterAsserts.assertSchemaNS(schemaNS);
+ ParameterAsserts.assertArrayName(arrayName);
+
+ // Just lookup, don't try to create.
+ XMPPath arrayPath = XMPPathParser.expandXPath(schemaNS, arrayName);
+ XMPNode arrayNode = XMPNodeUtils.findNode(tree, arrayPath, false, null);
+
+ if (arrayNode != null)
+ {
+ doSetArrayItem(arrayNode, itemIndex, itemValue, options, false);
+ }
+ else
+ {
+ throw new XMPException("Specified array does not exist", XMPError.BADXPATH);
+ }
+ }
+
+
+ /**
+ * @see XMPMeta#setArrayItem(String, String, int, String)
+ */
+ public void setArrayItem(String schemaNS, String arrayName, int itemIndex, String itemValue)
+ throws XMPException
+ {
+ setArrayItem(schemaNS, arrayName, itemIndex, itemValue, null);
+ }
+
+
+ /**
+ * @throws XMPException
+ * @see XMPMeta#insertArrayItem(String, String, int, String,
+ * PropertyOptions)
+ */
+ public void insertArrayItem(String schemaNS, String arrayName, int itemIndex, String itemValue,
+ PropertyOptions options) throws XMPException
+ {
+ ParameterAsserts.assertSchemaNS(schemaNS);
+ ParameterAsserts.assertArrayName(arrayName);
+
+ // Just lookup, don't try to create.
+ XMPPath arrayPath = XMPPathParser.expandXPath(schemaNS, arrayName);
+ XMPNode arrayNode = XMPNodeUtils.findNode(tree, arrayPath, false, null);
+
+ if (arrayNode != null)
+ {
+ doSetArrayItem(arrayNode, itemIndex, itemValue, options, true);
+ }
+ else
+ {
+ throw new XMPException("Specified array does not exist", XMPError.BADXPATH);
+ }
+ }
+
+
+ /**
+ * @see XMPMeta#insertArrayItem(String, String, int, String)
+ */
+ public void insertArrayItem(String schemaNS, String arrayName, int itemIndex, String itemValue)
+ throws XMPException
+ {
+ insertArrayItem(schemaNS, arrayName, itemIndex, itemValue, null);
+ }
+
+
+ /**
+ * @throws XMPException
+ * @see XMPMeta#setProperty(String, String, Object, PropertyOptions)
+ */
+ public void setProperty(String schemaNS, String propName, Object propValue,
+ PropertyOptions options) throws XMPException
+ {
+ ParameterAsserts.assertSchemaNS(schemaNS);
+ ParameterAsserts.assertPropName(propName);
+
+ options = XMPNodeUtils.verifySetOptions(options, propValue);
+
+ XMPPath expPath = XMPPathParser.expandXPath(schemaNS, propName);
+
+ XMPNode propNode = XMPNodeUtils.findNode(tree, expPath, true, options);
+ if (propNode != null)
+ {
+ setNode(propNode, propValue, options, false);
+ }
+ else
+ {
+ throw new XMPException("Specified property does not exist", XMPError.BADXPATH);
+ }
+ }
+
+
+ /**
+ * @see XMPMeta#setProperty(String, String, Object)
+ */
+ public void setProperty(String schemaNS, String propName, Object propValue) throws XMPException
+ {
+ setProperty(schemaNS, propName, propValue, null);
+ }
+
+
+ /**
+ * @throws XMPException
+ * @see XMPMeta#setQualifier(String, String, String, String, String,
+ * PropertyOptions)
+ */
+ public void setQualifier(String schemaNS, String propName, String qualNS, String qualName,
+ String qualValue, PropertyOptions options) throws XMPException
+ {
+ ParameterAsserts.assertSchemaNS(schemaNS);
+ ParameterAsserts.assertPropName(propName);
+
+ if (!doesPropertyExist(schemaNS, propName))
+ {
+ throw new XMPException("Specified property does not exist!", XMPError.BADXPATH);
+ }
+
+ String qualPath = propName + XMPPathFactory.composeQualifierPath(qualNS, qualName);
+ setProperty(schemaNS, qualPath, qualValue, options);
+ }
+
+
+ /**
+ * @see XMPMeta#setQualifier(String, String, String, String, String)
+ */
+ public void setQualifier(String schemaNS, String propName, String qualNS, String qualName,
+ String qualValue) throws XMPException
+ {
+ setQualifier(schemaNS, propName, qualNS, qualName, qualValue, null);
+
+ }
+
+
+ /**
+ * @see XMPMeta#setStructField(String, String, String, String, String,
+ * PropertyOptions)
+ */
+ public void setStructField(String schemaNS, String structName, String fieldNS,
+ String fieldName, String fieldValue, PropertyOptions options) throws XMPException
+ {
+ ParameterAsserts.assertSchemaNS(schemaNS);
+ ParameterAsserts.assertStructName(structName);
+
+ String fieldPath = structName + XMPPathFactory.composeStructFieldPath(fieldNS, fieldName);
+ setProperty(schemaNS, fieldPath, fieldValue, options);
+ }
+
+
+ /**
+ * @see XMPMeta#setStructField(String, String, String, String, String)
+ */
+ public void setStructField(String schemaNS, String structName, String fieldNS,
+ String fieldName, String fieldValue) throws XMPException
+ {
+ setStructField(schemaNS, structName, fieldNS, fieldName, fieldValue, null);
+ }
+
+
+ /**
+ * @see XMPMeta#getObjectName()
+ */
+ public String getObjectName()
+ {
+ return tree.getName() != null ? tree.getName() : "";
+ }
+
+
+ /**
+ * @see XMPMeta#setObjectName(String)
+ */
+ public void setObjectName(String name)
+ {
+ tree.setName(name);
+ }
+
+
+ /**
+ * Performs a deep clone of the XMPMeta-object
+ *
+ * @see java.lang.Object#clone()
+ */
+ public Object clone()
+ {
+ XMPNode clonedTree = (XMPNode) tree.clone();
+ return new XMPMetaImpl(clonedTree);
+ }
+
+
+ /**
+ * @see XMPMeta#dumpObject()
+ */
+ public String dumpObject()
+ {
+ // renders tree recursively
+ return getRoot().dumpNode(true);
+ }
+
+
+ /**
+ * @see XMPMeta#sort()
+ */
+ public void sort()
+ {
+ this.tree.sort();
+ }
+
+
+ /**
+ * @return Returns the root node of the XMP tree.
+ */
+ public XMPNode getRoot()
+ {
+ return tree;
+ }
+
+
+
+ // -------------------------------------------------------------------------------------
+ // private
+
+
+ /**
+ * Locate or create the item node and set the value. Note the index
+ * parameter is one-based! The index can be in the range [1..size + 1] or
+ * "last()", normalize it and check the insert flags. The order of the
+ * normalization checks is important. If the array is empty we end up with
+ * an index and location to set item size + 1.
+ *
+ * @param arrayNode an array node
+ * @param itemIndex the index where to insert the item
+ * @param itemValue the item value
+ * @param itemOptions the options for the new item
+ * @param insert insert oder overwrite at index position?
+ * @throws XMPException
+ */
+ private void doSetArrayItem(XMPNode arrayNode, int itemIndex, String itemValue,
+ PropertyOptions itemOptions, boolean insert) throws XMPException
+ {
+ XMPNode itemNode = new XMPNode(ARRAY_ITEM_NAME, null);
+ itemOptions = XMPNodeUtils.verifySetOptions(itemOptions, itemValue);
+
+ // in insert mode the index after the last is allowed,
+ // even ARRAY_LAST_ITEM points to the index *after* the last.
+ int maxIndex = insert ? arrayNode.getChildrenLength() + 1 : arrayNode.getChildrenLength();
+ if (itemIndex == ARRAY_LAST_ITEM)
+ {
+ itemIndex = maxIndex;
+ }
+
+ if (1 <= itemIndex && itemIndex <= maxIndex)
+ {
+ if (!insert)
+ {
+ arrayNode.removeChild(itemIndex);
+ }
+ arrayNode.addChild(itemIndex, itemNode);
+ setNode(itemNode, itemValue, itemOptions, false);
+ }
+ else
+ {
+ throw new XMPException("Array index out of bounds", XMPError.BADINDEX);
+ }
+ }
+
+
+ /**
+ * The internals for setProperty() and related calls, used after the node is
+ * found or created.
+ *
+ * @param node
+ * the newly created node
+ * @param value
+ * the node value, can be <code>null</code>
+ * @param newOptions
+ * options for the new node, must not be <code>null</code>.
+ * @param deleteExisting flag if the existing value is to be overwritten
+ * @throws XMPException thrown if options and value do not correspond
+ */
+ void setNode(XMPNode node, Object value, PropertyOptions newOptions, boolean deleteExisting)
+ throws XMPException
+ {
+ if (deleteExisting)
+ {
+ node.clear();
+ }
+
+ // its checked by setOptions(), if the merged result is a valid options set
+ node.getOptions().mergeWith(newOptions);
+
+ if (!node.getOptions().isCompositeProperty())
+ {
+ // This is setting the value of a leaf node.
+ XMPNodeUtils.setNodeValue(node, value);
+ }
+ else
+ {
+ if (value != null && value.toString().length() > 0)
+ {
+ throw new XMPException("Composite nodes can't have values", XMPError.BADXPATH);
+ }
+
+ node.removeChildren();
+ }
+
+ }
+
+
+ /**
+ * Evaluates a raw node value to the given value type, apply special
+ * conversions for defined types in XMP.
+ *
+ * @param valueType
+ * an int indicating the value type
+ * @param propNode
+ * the node containing the value
+ * @return Returns a literal value for the node.
+ * @throws XMPException
+ */
+ private Object evaluateNodeValue(int valueType, final XMPNode propNode) throws XMPException
+ {
+ final Object value;
+ String rawValue = propNode.getValue();
+ switch (valueType)
+ {
+ case VALUE_BOOLEAN:
+ value = new Boolean(XMPUtils.convertToBoolean(rawValue));
+ break;
+ case VALUE_INTEGER:
+ value = new Integer(XMPUtils.convertToInteger(rawValue));
+ break;
+ case VALUE_LONG:
+ value = new Long(XMPUtils.convertToLong(rawValue));
+ break;
+ case VALUE_DOUBLE:
+ value = new Double(XMPUtils.convertToDouble(rawValue));
+ break;
+ case VALUE_DATE:
+ value = XMPUtils.convertToDate(rawValue);
+ break;
+ case VALUE_CALENDAR:
+ XMPDateTime dt = XMPUtils.convertToDate(rawValue);
+ value = dt.getCalendar();
+ break;
+ case VALUE_BASE64:
+ value = XMPUtils.decodeBase64(rawValue);
+ break;
+ case VALUE_STRING:
+ default:
+ // leaf values return empty string instead of null
+ // for the other cases the converter methods provides a "null"
+ // value.
+ // a default value can only occur if this method is made public.
+ value = rawValue != null || propNode.getOptions().isCompositeProperty() ? rawValue : "";
+ break;
+ }
+ return value;
+ }
+}
diff --git a/java/XMPCore/src/com/adobe/xmp/impl/XMPMetaParser.java b/java/XMPCore/src/com/adobe/xmp/impl/XMPMetaParser.java
new file mode 100644
index 0000000..35d929e
--- /dev/null
+++ b/java/XMPCore/src/com/adobe/xmp/impl/XMPMetaParser.java
@@ -0,0 +1,361 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+package com.adobe.xmp.impl;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.UnsupportedEncodingException;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+import com.adobe.xmp.XMPConst;
+import com.adobe.xmp.XMPError;
+import com.adobe.xmp.XMPException;
+import com.adobe.xmp.XMPMeta;
+import com.adobe.xmp.options.ParseOptions;
+
+
+/**
+ * This class replaces the <code>ExpatAdapter.cpp</code> and does the
+ * XML-parsing and fixes the prefix. After the parsing several normalisations
+ * are applied to the XMPTree.
+ *
+ * @since 01.02.2006
+ */
+public class XMPMetaParser
+{
+ /** */
+ private static final Object XMP_RDF = new Object();
+ /** the DOM Parser Factory, options are set */
+ private static DocumentBuilderFactory factory = createDocumentBuilderFactory();
+
+
+ /**
+ * Hidden constructor, initialises the SAX parser handler.
+ */
+ private XMPMetaParser()
+ {
+ // EMPTY
+ }
+
+
+
+ /**
+ * Parses the input source into an XMP metadata object, including
+ * de-aliasing and normalisation.
+ *
+ * @param input the input can be an <code>InputStream</code>, a <code>String</code> or
+ * a byte buffer containing the XMP packet.
+ * @param options the parse options
+ * @return Returns the resulting XMP metadata object
+ * @throws XMPException Thrown if parsing or normalisation fails.
+ */
+ public static XMPMeta parse(Object input, ParseOptions options) throws XMPException
+ {
+ ParameterAsserts.assertNotNull(input);
+ options = options != null ? options : new ParseOptions();
+
+ Document document = parseXml(input, options);
+
+ boolean xmpmetaRequired = options.getRequireXMPMeta();
+ Object[] result = findRootNode(document, xmpmetaRequired);
+
+ if (result != null && result[1] == XMP_RDF)
+ {
+ XMPMetaImpl xmp = ParseRDF.parse((Node) result[0]);
+ return XMPNormalizer.process(xmp, options);
+ }
+ else
+ {
+ // no appropriate root node found, return empty metadata object
+ return new XMPMetaImpl();
+ }
+ }
+
+
+ /**
+ * Parses the raw XML metadata packet considering the parsing options.
+ * Latin-1/ISO-8859-1 can be accepted when the input is a byte stream
+ * (some old toolkits versions such packets). The stream is
+ * then wrapped in another stream that converts Latin-1 to UTF-8.
+ * <p>
+ * If control characters shall be fixed, a reader is used that fixes the chars to spaces
+ * (if the input is a byte stream is has to be read as character stream).
+ * <p>
+ * Both options reduce the performance of the parser.
+ *
+ * @param input the input can be an <code>InputStream</code>, a <code>String</code> or
+ * a byte buffer containing the XMP packet.
+ * @param options the parsing options
+ * @return Returns the parsed XML document or an exception.
+ * @throws XMPException Thrown if the parsing fails for different reasons
+ */
+ private static Document parseXml(Object input, ParseOptions options)
+ throws XMPException
+ {
+ if (input instanceof InputStream)
+ {
+ return parseXmlFromInputStream((InputStream) input, options);
+ }
+ else if (input instanceof byte[])
+ {
+ return parseXmlFromBytebuffer(new ByteBuffer((byte[]) input), options);
+ }
+ else
+ {
+ return parseXmlFromString((String) input, options);
+ }
+ }
+
+
+ /**
+ * Parses XML from an {@link InputStream},
+ * fixing the encoding (Latin-1 to UTF-8) and illegal control character optionally.
+ *
+ * @param stream an <code>InputStream</code>
+ * @param options the parsing options
+ * @return Returns an XML DOM-Document.
+ * @throws XMPException Thrown when the parsing fails.
+ */
+ private static Document parseXmlFromInputStream(InputStream stream, ParseOptions options)
+ throws XMPException
+ {
+ if (!options.getAcceptLatin1() && !options.getFixControlChars())
+ {
+ return parseInputSource(new InputSource(stream));
+ }
+ else
+ {
+ // load stream into bytebuffer
+ try
+ {
+ ByteBuffer buffer = new ByteBuffer(stream);
+ return parseXmlFromBytebuffer(buffer, options);
+ }
+ catch (IOException e)
+ {
+ throw new XMPException("Error reading the XML-file",
+ XMPError.BADSTREAM, e);
+ }
+ }
+ }
+
+
+ /**
+ * Parses XML from a byte buffer,
+ * fixing the encoding (Latin-1 to UTF-8) and illegal control character optionally.
+ *
+ * @param buffer a byte buffer containing the XMP packet
+ * @param options the parsing options
+ * @return Returns an XML DOM-Document.
+ * @throws XMPException Thrown when the parsing fails.
+ */
+ private static Document parseXmlFromBytebuffer(ByteBuffer buffer, ParseOptions options)
+ throws XMPException
+ {
+ InputSource source = new InputSource(buffer.getByteStream());
+ try
+ {
+ return parseInputSource(source);
+ }
+ catch (XMPException e)
+ {
+ if (e.getErrorCode() == XMPError.BADXML)
+ {
+ if (options.getAcceptLatin1())
+ {
+ buffer = Latin1Converter.convert(buffer);
+ }
+
+ if (options.getFixControlChars())
+ {
+ try
+ {
+ String encoding = buffer.getEncoding();
+ Reader fixReader = new FixASCIIControlsReader(
+ new InputStreamReader(
+ buffer.getByteStream(), encoding));
+ return parseInputSource(new InputSource(fixReader));
+ }
+ catch (UnsupportedEncodingException e1)
+ {
+ // can normally not happen as the encoding is provided by a util function
+ throw new XMPException("Unsupported Encoding",
+ XMPError.INTERNALFAILURE, e);
+ }
+ }
+ source = new InputSource(buffer.getByteStream());
+ return parseInputSource(source);
+ }
+ else
+ {
+ throw e;
+ }
+ }
+ }
+
+
+ /**
+ * Parses XML from a {@link String},
+ * fixing the illegal control character optionally.
+ *
+ * @param input a <code>String</code> containing the XMP packet
+ * @param options the parsing options
+ * @return Returns an XML DOM-Document.
+ * @throws XMPException Thrown when the parsing fails.
+ */
+ private static Document parseXmlFromString(String input, ParseOptions options)
+ throws XMPException
+ {
+ InputSource source = new InputSource(new StringReader(input));
+ try
+ {
+ return parseInputSource(source);
+ }
+ catch (XMPException e)
+ {
+ if (e.getErrorCode() == XMPError.BADXML && options.getFixControlChars())
+ {
+ source = new InputSource(new FixASCIIControlsReader(new StringReader(input)));
+ return parseInputSource(source);
+ }
+ else
+ {
+ throw e;
+ }
+ }
+ }
+
+
+ /**
+ * Runs the XML-Parser.
+ * @param source an <code>InputSource</code>
+ * @return Returns an XML DOM-Document.
+ * @throws XMPException Wraps parsing and I/O-exceptions into an XMPException.
+ */
+ private static Document parseInputSource(InputSource source) throws XMPException
+ {
+ try
+ {
+ DocumentBuilder builder = factory.newDocumentBuilder();
+ builder.setErrorHandler(null);
+ return builder.parse(source);
+ }
+ catch (SAXException e)
+ {
+ throw new XMPException("XML parsing failure", XMPError.BADXML, e);
+ }
+ catch (ParserConfigurationException e)
+ {
+ throw new XMPException("XML Parser not correctly configured",
+ XMPError.UNKNOWN, e);
+ }
+ catch (IOException e)
+ {
+ throw new XMPException("Error reading the XML-file", XMPError.BADSTREAM, e);
+ }
+ }
+
+
+ /**
+ * Find the XML node that is the root of the XMP data tree. Generally this
+ * will be an outer node, but it could be anywhere if a general XML document
+ * is parsed (e.g. SVG). The XML parser counted all rdf:RDF and
+ * pxmp:XMP_Packet nodes, and kept a pointer to the last one. If there is
+ * more than one possible root use PickBestRoot to choose among them.
+ * <p>
+ * If there is a root node, try to extract the version of the previous XMP
+ * toolkit.
+ * <p>
+ * Pick the first x:xmpmeta among multiple root candidates. If there aren't
+ * any, pick the first bare rdf:RDF if that is allowed. The returned root is
+ * the rdf:RDF child if an x:xmpmeta element was chosen. The search is
+ * breadth first, so a higher level candiate is chosen over a lower level
+ * one that was textually earlier in the serialized XML.
+ *
+ * @param root the root of the xml document
+ * @param xmpmetaRequired flag if the xmpmeta-tag is still required, might be set
+ * initially to <code>true</code>, if the parse option "REQUIRE_XMP_META" is set
+ * @return Returns the rdf:RDF-node or <code>null</code>.
+ */
+ private static Object[] findRootNode(Node root, boolean xmpmetaRequired)
+ {
+ // Look among this parent's content for x:xapmeta or x:xmpmeta.
+ // The recursion for x:xmpmeta is broader than the strictly defined choice,
+ // but gives us smaller code.
+ NodeList children = root.getChildNodes();
+ for (int i = 0; i < children.getLength(); i++)
+ {
+ root = children.item(i);
+ if (Node.TEXT_NODE != root.getNodeType() &&
+ Node.PROCESSING_INSTRUCTION_NODE != root.getNodeType())
+ {
+ String rootNS = root.getNamespaceURI();
+ String rootLocal = root.getLocalName();
+ if (
+ ("xmpmeta".equals(rootLocal) || "xapmeta".equals(rootLocal)) &&
+ XMPConst.NS_X.equals(rootNS)
+ )
+ {
+ // by not passing the RequireXMPMeta-option, the rdf-Node will be valid
+ return findRootNode(root, false);
+ }
+ else if (!xmpmetaRequired &&
+ "RDF".equals(rootLocal) &&
+ XMPConst.NS_RDF.equals(rootNS))
+ {
+ return new Object[] {root, XMP_RDF};
+ }
+ else
+ {
+ // continue searching
+ Object[] result = findRootNode(root, xmpmetaRequired);
+ if (result != null)
+ {
+ return result;
+ }
+ else
+ {
+ continue;
+ }
+ }
+ }
+ }
+
+ // no appropriate node has been found
+ return null;
+ // is extracted here in the C++ Toolkit
+ }
+
+
+ /**
+ * @return Creates, configures and returnes the document builder factory for
+ * the Metadata Parser.
+ */
+ private static DocumentBuilderFactory createDocumentBuilderFactory()
+ {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ factory.setNamespaceAware(true);
+ factory.setIgnoringComments(true);
+ factory.setExpandEntityReferences(true);
+ return factory;
+ }
+} \ No newline at end of file
diff --git a/java/XMPCore/src/com/adobe/xmp/impl/XMPNode.java b/java/XMPCore/src/com/adobe/xmp/impl/XMPNode.java
new file mode 100644
index 0000000..3342514
--- /dev/null
+++ b/java/XMPCore/src/com/adobe/xmp/impl/XMPNode.java
@@ -0,0 +1,921 @@
+//=================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+package com.adobe.xmp.impl;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+
+import com.adobe.xmp.XMPConst;
+import com.adobe.xmp.XMPError;
+import com.adobe.xmp.XMPException;
+import com.adobe.xmp.options.PropertyOptions;
+
+
+/**
+ * A node in the internally XMP tree, which can be a schema node, a property node, an array node,
+ * an array item, a struct node or a qualifier node (without '?').
+ *
+ * Possible improvements:
+ *
+ * 1. The kind Node of node might be better represented by a class-hierarchy of different nodes.
+ * 2. The array type should be an enum
+ * 3. isImplicitNode should be removed completely and replaced by return values of fi.
+ * 4. hasLanguage, hasType should be automatically maintained by XMPNode
+ *
+ * @since 21.02.2006
+ */
+class XMPNode implements Comparable
+{
+ /** name of the node, contains different information depending of the node kind */
+ private String name;
+ /** value of the node, contains different information depending of the node kind */
+ private String value;
+ /** link to the parent node */
+ private XMPNode parent;
+ /** list of child nodes, lazy initialized */
+ private List children = null;
+ /** list of qualifier of the node, lazy initialized */
+ private List qualifier = null;
+ /** options describing the kind of the node */
+ private PropertyOptions options = null;
+
+ // internal processing options
+
+ /** flag if the node is implicitly created */
+ private boolean implicit;
+ /** flag if the node has aliases */
+ private boolean hasAliases;
+ /** flag if the node is an alias */
+ private boolean alias;
+ /** flag if the node has an "rdf:value" child node. */
+ private boolean hasValueChild;
+
+
+
+ /**
+ * Creates an <code>XMPNode</code> with initial values.
+ *
+ * @param name the name of the node
+ * @param value the value of the node
+ * @param options the options of the node
+ */
+ public XMPNode(String name, String value, PropertyOptions options)
+ {
+ this.name = name;
+ this.value = value;
+ this.options = options;
+ }
+
+
+ /**
+ * Constructor for the node without value.
+ *
+ * @param name the name of the node
+ * @param options the options of the node
+ */
+ public XMPNode(String name, PropertyOptions options)
+ {
+ this(name, null, options);
+ }
+
+
+ /**
+ * Resets the node.
+ */
+ public void clear()
+ {
+ options = null;
+ name = null;
+ value = null;
+ children = null;
+ qualifier = null;
+ }
+
+
+ /**
+ * @return Returns the parent node.
+ */
+ public XMPNode getParent()
+ {
+ return parent;
+ }
+
+
+ /**
+ * @param index an index [1..size]
+ * @return Returns the child with the requested index.
+ */
+ public XMPNode getChild(int index)
+ {
+ return (XMPNode) getChildren().get(index - 1);
+ }
+
+
+ /**
+ * Adds a node as child to this node.
+ * @param node an XMPNode
+ * @throws XMPException
+ */
+ public void addChild(XMPNode node) throws XMPException
+ {
+ // check for duplicate properties
+ assertChildNotExisting(node.getName());
+ node.setParent(this);
+ getChildren().add(node);
+ }
+
+
+ /**
+ * Adds a node as child to this node.
+ * @param index the index of the node <em>before</em> which the new one is inserted.
+ * <em>Note:</em> The node children are indexed from [1..size]!
+ * An index of size + 1 appends a node.
+ * @param node an XMPNode
+ * @throws XMPException
+ */
+ public void addChild(int index, XMPNode node) throws XMPException
+ {
+ assertChildNotExisting(node.getName());
+ node.setParent(this);
+ getChildren().add(index - 1, node);
+ }
+
+
+ /**
+ * Replaces a node with another one.
+ * @param index the index of the node that will be replaced.
+ * <em>Note:</em> The node children are indexed from [1..size]!
+ * @param node the replacement XMPNode
+ */
+ public void replaceChild(int index, XMPNode node)
+ {
+ node.setParent(this);
+ getChildren().set(index - 1, node);
+ }
+
+
+ /**
+ * Removes a child at the requested index.
+ * @param itemIndex the index to remove [1..size]
+ */
+ public void removeChild(int itemIndex)
+ {
+ getChildren().remove(itemIndex - 1);
+ cleanupChildren();
+ }
+
+
+ /**
+ * Removes a child node.
+ * If its a schema node and doesn't have any children anymore, its deleted.
+ *
+ * @param node the child node to delete.
+ */
+ public void removeChild(XMPNode node)
+ {
+ getChildren().remove(node);
+ cleanupChildren();
+ }
+
+
+ /**
+ * Removes the children list if this node has no children anymore;
+ * checks if the provided node is a schema node and doesn't have any children anymore,
+ * its deleted.
+ */
+ protected void cleanupChildren()
+ {
+ if (children.isEmpty())
+ {
+ children = null;
+ }
+ }
+
+
+ /**
+ * Removes all children from the node.
+ */
+ public void removeChildren()
+ {
+ children = null;
+ }
+
+
+ /**
+ * @return Returns the number of children without neccessarily creating a list.
+ */
+ public int getChildrenLength()
+ {
+ return children != null ?
+ children.size() :
+ 0;
+ }
+
+
+ /**
+ * @param expr child node name to look for
+ * @return Returns an <code>XMPNode</code> if node has been found, <code>null</code> otherwise.
+ */
+ public XMPNode findChildByName(String expr)
+ {
+ return find(getChildren(), expr);
+ }
+
+
+ /**
+ * @param index an index [1..size]
+ * @return Returns the qualifier with the requested index.
+ */
+ public XMPNode getQualifier(int index)
+ {
+ return (XMPNode) getQualifier().get(index - 1);
+ }
+
+
+ /**
+ * @return Returns the number of qualifier without neccessarily creating a list.
+ */
+ public int getQualifierLength()
+ {
+ return qualifier != null ?
+ qualifier.size() :
+ 0;
+ }
+
+
+ /**
+ * Appends a qualifier to the qualifier list and sets respective options.
+ * @param qualNode a qualifier node.
+ * @throws XMPException
+ */
+ public void addQualifier(XMPNode qualNode) throws XMPException
+ {
+ assertQualifierNotExisting(qualNode.getName());
+ qualNode.setParent(this);
+ qualNode.getOptions().setQualifier(true);
+ getOptions().setHasQualifiers(true);
+
+ // contraints
+ if (qualNode.isLanguageNode())
+ {
+ // "xml:lang" is always first and the option "hasLanguage" is set
+ options.setHasLanguage(true);
+ getQualifier().add(0, qualNode);
+ }
+ else if (qualNode.isTypeNode())
+ {
+ // "rdf:type" must be first or second after "xml:lang" and the option "hasType" is set
+ options.setHasType(true);
+ getQualifier().add(
+ !options.getHasLanguage() ? 0 : 1,
+ qualNode);
+ }
+ else
+ {
+ // other qualifiers are appended
+ getQualifier().add(qualNode);
+ }
+ }
+
+
+ /**
+ * Removes one qualifier node and fixes the options.
+ * @param qualNode qualifier to remove
+ */
+ public void removeQualifier(XMPNode qualNode)
+ {
+ PropertyOptions opts = getOptions();
+ if (qualNode.isLanguageNode())
+ {
+ // if "xml:lang" is removed, remove hasLanguage-flag too
+ opts.setHasLanguage(false);
+ }
+ else if (qualNode.isTypeNode())
+ {
+ // if "rdf:type" is removed, remove hasType-flag too
+ opts.setHasType(false);
+ }
+
+ getQualifier().remove(qualNode);
+ if (qualifier.isEmpty())
+ {
+ opts.setHasQualifiers(false);
+ qualifier = null;
+ }
+
+ }
+
+
+ /**
+ * Removes all qualifiers from the node and sets the options appropriate.
+ */
+ public void removeQualifiers()
+ {
+ PropertyOptions opts = getOptions();
+ // clear qualifier related options
+ opts.setHasQualifiers(false);
+ opts.setHasLanguage(false);
+ opts.setHasType(false);
+ qualifier = null;
+ }
+
+
+ /**
+ * @param expr qualifier node name to look for
+ * @return Returns a qualifier <code>XMPNode</code> if node has been found,
+ * <code>null</code> otherwise.
+ */
+ public XMPNode findQualifierByName(String expr)
+ {
+ return find(qualifier, expr);
+ }
+
+
+ /**
+ * @return Returns whether the node has children.
+ */
+ public boolean hasChildren()
+ {
+ return children != null && children.size() > 0;
+ }
+
+
+ /**
+ * @return Returns an iterator for the children.
+ * <em>Note:</em> take care to use it.remove(), as the flag are not adjusted in that case.
+ */
+ public Iterator iterateChildren()
+ {
+ if (children != null)
+ {
+ return getChildren().iterator();
+ }
+ else
+ {
+ return Collections.EMPTY_LIST.listIterator();
+ }
+ }
+
+
+ /**
+ * @return Returns whether the node has qualifier attached.
+ */
+ public boolean hasQualifier()
+ {
+ return qualifier != null && qualifier.size() > 0;
+ }
+
+
+ /**
+ * @return Returns an iterator for the qualifier.
+ * <em>Note:</em> take care to use it.remove(), as the flag are not adjusted in that case.
+ */
+ public Iterator iterateQualifier()
+ {
+ if (qualifier != null)
+ {
+ final Iterator it = getQualifier().iterator();
+
+ return new Iterator()
+ {
+ public boolean hasNext()
+ {
+ return it.hasNext();
+ }
+
+ public Object next()
+ {
+ return it.next();
+ }
+
+ public void remove()
+ {
+ throw new UnsupportedOperationException(
+ "remove() is not allowed due to the internal contraints");
+ }
+
+ };
+ }
+ else
+ {
+ return Collections.EMPTY_LIST.iterator();
+ }
+ }
+
+
+ /**
+ * Performs a <b>deep clone</b> of the node and the complete subtree.
+ *
+ * @see java.lang.Object#clone()
+ */
+ public Object clone()
+ {
+ PropertyOptions newOptions;
+ try
+ {
+ newOptions = new PropertyOptions(getOptions().getOptions());
+ }
+ catch (XMPException e)
+ {
+ // cannot happen
+ newOptions = new PropertyOptions();
+ }
+
+ XMPNode newNode = new XMPNode(name, value, newOptions);
+ cloneSubtree(newNode);
+
+ return newNode;
+ }
+
+
+ /**
+ * Performs a <b>deep clone</b> of the complete subtree (children and
+ * qualifier )into and add it to the destination node.
+ *
+ * @param destination the node to add the cloned subtree
+ */
+ public void cloneSubtree(XMPNode destination)
+ {
+ try
+ {
+ for (Iterator it = iterateChildren(); it.hasNext();)
+ {
+ XMPNode child = (XMPNode) it.next();
+ destination.addChild((XMPNode) child.clone());
+ }
+
+ for (Iterator it = iterateQualifier(); it.hasNext();)
+ {
+ XMPNode qualifier = (XMPNode) it.next();
+ destination.addQualifier((XMPNode) qualifier.clone());
+ }
+ }
+ catch (XMPException e)
+ {
+ // cannot happen (duplicate childs/quals do not exist in this node)
+ assert false;
+ }
+
+ }
+
+
+ /**
+ * Renders this node and the tree unter this node in a human readable form.
+ * @param recursive Flag is qualifier and child nodes shall be rendered too
+ * @return Returns a multiline string containing the dump.
+ */
+ public String dumpNode(boolean recursive)
+ {
+ StringBuffer result = new StringBuffer(512);
+ this.dumpNode(result, recursive, 0, 0);
+ return result.toString();
+ }
+
+
+ /**
+ * @see Comparable#compareTo(Object)
+ */
+ public int compareTo(Object xmpNode)
+ {
+ if (getOptions().isSchemaNode())
+ {
+ return this.value.compareTo(((XMPNode) xmpNode).getValue());
+ }
+ else
+ {
+ return this.name.compareTo(((XMPNode) xmpNode).getName());
+ }
+ }
+
+
+ /**
+ * @return Returns the name.
+ */
+ public String getName()
+ {
+ return name;
+ }
+
+
+ /**
+ * @param name The name to set.
+ */
+ public void setName(String name)
+ {
+ this.name = name;
+ }
+
+
+ /**
+ * @return Returns the value.
+ */
+ public String getValue()
+ {
+ return value;
+ }
+
+
+ /**
+ * @param value The value to set.
+ */
+ public void setValue(String value)
+ {
+ this.value = value;
+ }
+
+
+ /**
+ * @return Returns the options.
+ */
+ public PropertyOptions getOptions()
+ {
+ if (options == null)
+ {
+ options = new PropertyOptions();
+ }
+ return options;
+ }
+
+
+ /**
+ * Updates the options of the node.
+ * @param options the options to set.
+ */
+ public void setOptions(PropertyOptions options)
+ {
+ this.options = options;
+ }
+
+
+ /**
+ * @return Returns the implicit flag
+ */
+ public boolean isImplicit()
+ {
+ return implicit;
+ }
+
+
+ /**
+ * @param implicit Sets the implicit node flag
+ */
+ public void setImplicit(boolean implicit)
+ {
+ this.implicit = implicit;
+ }
+
+
+ /**
+ * @return Returns if the node contains aliases (applies only to schema nodes)
+ */
+ public boolean getHasAliases()
+ {
+ return hasAliases;
+ }
+
+
+ /**
+ * @param hasAliases sets the flag that the node contains aliases
+ */
+ public void setHasAliases(boolean hasAliases)
+ {
+ this.hasAliases = hasAliases;
+ }
+
+
+ /**
+ * @return Returns if the node contains aliases (applies only to schema nodes)
+ */
+ public boolean isAlias()
+ {
+ return alias;
+ }
+
+
+ /**
+ * @param alias sets the flag that the node is an alias
+ */
+ public void setAlias(boolean alias)
+ {
+ this.alias = alias;
+ }
+
+
+ /**
+ * @return the hasValueChild
+ */
+ public boolean getHasValueChild()
+ {
+ return hasValueChild;
+ }
+
+
+ /**
+ * @param hasValueChild the hasValueChild to set
+ */
+ public void setHasValueChild(boolean hasValueChild)
+ {
+ this.hasValueChild = hasValueChild;
+ }
+
+
+
+ /**
+ * Sorts the complete datamodel according to the following rules:
+ * <ul>
+ * <li>Nodes at one level are sorted by name, that is prefix + local name
+ * <li>Starting at the root node the children and qualifier are sorted recursively,
+ * which the following exceptions.
+ * <li>Sorting will not be used for arrays.
+ * <li>Within qualifier "xml:lang" and/or "rdf:type" stay at the top in that order,
+ * all others are sorted.
+ * </ul>
+ */
+ public void sort()
+ {
+ // sort qualifier
+ if (hasQualifier())
+ {
+ XMPNode[] quals = (XMPNode[]) getQualifier()
+ .toArray(new XMPNode[getQualifierLength()]);
+ int sortFrom = 0;
+ while (
+ quals.length > sortFrom &&
+ (XMPConst.XML_LANG.equals(quals[sortFrom].getName()) ||
+ "rdf:type".equals(quals[sortFrom].getName()))
+ )
+ {
+ quals[sortFrom].sort();
+ sortFrom++;
+ }
+
+ Arrays.sort(quals, sortFrom, quals.length);
+ ListIterator it = qualifier.listIterator();
+ for (int j = 0; j < quals.length; j++)
+ {
+ it.next();
+ it.set(quals[j]);
+ quals[j].sort();
+ }
+ }
+
+ // sort children
+ if (hasChildren())
+ {
+ if (!getOptions().isArray())
+ {
+ Collections.sort(children);
+ }
+ for (Iterator it = iterateChildren(); it.hasNext();)
+ {
+ ((XMPNode) it.next()).sort();
+
+ }
+ }
+ }
+
+
+
+ //------------------------------------------------------------------------------ private methods
+
+
+ /**
+ * Dumps this node and its qualifier and children recursively.
+ * <em>Note:</em> It creats empty options on every node.
+ *
+ * @param result the buffer to append the dump.
+ * @param recursive Flag is qualifier and child nodes shall be rendered too
+ * @param indent the current indent level.
+ * @param index the index within the parent node (important for arrays)
+ */
+ private void dumpNode(StringBuffer result, boolean recursive, int indent, int index)
+ {
+ // write indent
+ for (int i = 0; i < indent; i++)
+ {
+ result.append('\t');
+ }
+
+ // render Node
+ if (parent != null)
+ {
+ if (getOptions().isQualifier())
+ {
+ result.append('?');
+ result.append(name);
+ }
+ else if (getParent().getOptions().isArray())
+ {
+ result.append('[');
+ result.append(index);
+ result.append(']');
+ }
+ else
+ {
+ result.append(name);
+ }
+ }
+ else
+ {
+ // applies only to the root node
+ result.append("ROOT NODE");
+ if (name != null && name.length() > 0)
+ {
+ // the "about" attribute
+ result.append(" (");
+ result.append(name);
+ result.append(')');
+ }
+ }
+
+ if (value != null && value.length() > 0)
+ {
+ result.append(" = \"");
+ result.append(value);
+ result.append('"');
+ }
+
+ // render options if at least one is set
+ if (getOptions().containsOneOf(0xffffffff))
+ {
+ result.append("\t(");
+ result.append(getOptions().toString());
+ result.append(" : ");
+ result.append(getOptions().getOptionsString());
+ result.append(')');
+ }
+
+ result.append('\n');
+
+ // render qualifier
+ if (recursive && hasQualifier())
+ {
+ XMPNode[] quals = (XMPNode[]) getQualifier()
+ .toArray(new XMPNode[getQualifierLength()]);
+ int i = 0;
+ while (quals.length > i &&
+ (XMPConst.XML_LANG.equals(quals[i].getName()) ||
+ "rdf:type".equals(quals[i].getName()))
+ )
+ {
+ i++;
+ }
+ Arrays.sort(quals, i, quals.length);
+ for (i = 0; i < quals.length; i++)
+ {
+ XMPNode qualifier = quals[i];
+ qualifier.dumpNode(result, recursive, indent + 2, i + 1);
+ }
+ }
+
+ // render children
+ if (recursive && hasChildren())
+ {
+ XMPNode[] children = (XMPNode[]) getChildren()
+ .toArray(new XMPNode[getChildrenLength()]);
+ if (!getOptions().isArray())
+ {
+ Arrays.sort(children);
+ }
+ for (int i = 0; i < children.length; i++)
+ {
+ XMPNode child = children[i];
+ child.dumpNode(result, recursive, indent + 1, i + 1);
+ }
+ }
+ }
+
+
+ /**
+ * @return Returns whether this node is a language qualifier.
+ */
+ private boolean isLanguageNode()
+ {
+ return XMPConst.XML_LANG.equals(name);
+ }
+
+
+ /**
+ * @return Returns whether this node is a type qualifier.
+ */
+ private boolean isTypeNode()
+ {
+ return "rdf:type".equals(name);
+ }
+
+
+ /**
+ * <em>Note:</em> This method should always be called when accessing 'children' to be sure
+ * that its initialized.
+ * @return Returns list of children that is lazy initialized.
+ */
+ private List getChildren()
+ {
+ if (children == null)
+ {
+ children = new ArrayList(0);
+ }
+ return children;
+ }
+
+
+ /**
+ * @return Returns a read-only copy of child nodes list.
+ */
+ public List getUnmodifiableChildren()
+ {
+ return Collections.unmodifiableList(new ArrayList(getChildren()));
+ }
+
+
+ /**
+ * @return Returns list of qualifier that is lazy initialized.
+ */
+ private List getQualifier()
+ {
+ if (qualifier == null)
+ {
+ qualifier = new ArrayList(0);
+ }
+ return qualifier;
+ }
+
+
+ /**
+ * Sets the parent node, this is solely done by <code>addChild(...)</code>
+ * and <code>addQualifier()</code>.
+ *
+ * @param parent
+ * Sets the parent node.
+ */
+ protected void setParent(XMPNode parent)
+ {
+ this.parent = parent;
+ }
+
+
+ /**
+ * Internal find.
+ * @param list the list to search in
+ * @param expr the search expression
+ * @return Returns the found node or <code>nulls</code>.
+ */
+ private XMPNode find(List list, String expr)
+ {
+
+ if (list != null)
+ {
+ for (Iterator it = list.iterator(); it.hasNext();)
+ {
+ XMPNode child = (XMPNode) it.next();
+ if (child.getName().equals(expr))
+ {
+ return child;
+ }
+ }
+ }
+ return null;
+ }
+
+
+ /**
+ * Checks that a node name is not existing on the same level, except for array items.
+ * @param childName the node name to check
+ * @throws XMPException Thrown if a node with the same name is existing.
+ */
+ private void assertChildNotExisting(String childName) throws XMPException
+ {
+ if (!XMPConst.ARRAY_ITEM_NAME.equals(childName) &&
+ findChildByName(childName) != null)
+ {
+ throw new XMPException("Duplicate property or field node '" + childName + "'",
+ XMPError.BADXMP);
+ }
+ }
+
+
+ /**
+ * Checks that a qualifier name is not existing on the same level.
+ * @param qualifierName the new qualifier name
+ * @throws XMPException Thrown if a node with the same name is existing.
+ */
+ private void assertQualifierNotExisting(String qualifierName) throws XMPException
+ {
+ if (!XMPConst.ARRAY_ITEM_NAME.equals(qualifierName) &&
+ findQualifierByName(qualifierName) != null)
+ {
+ throw new XMPException("Duplicate '" + qualifierName + "' qualifier", XMPError.BADXMP);
+ }
+ }
+} \ No newline at end of file
diff --git a/java/XMPCore/src/com/adobe/xmp/impl/XMPNodeUtils.java b/java/XMPCore/src/com/adobe/xmp/impl/XMPNodeUtils.java
new file mode 100644
index 0000000..283db03
--- /dev/null
+++ b/java/XMPCore/src/com/adobe/xmp/impl/XMPNodeUtils.java
@@ -0,0 +1,930 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+package com.adobe.xmp.impl;
+
+import java.util.Calendar;
+import java.util.Iterator;
+
+import com.adobe.xmp.XMPConst;
+import com.adobe.xmp.XMPDateTime;
+import com.adobe.xmp.XMPDateTimeFactory;
+import com.adobe.xmp.XMPError;
+import com.adobe.xmp.XMPException;
+import com.adobe.xmp.XMPMetaFactory;
+import com.adobe.xmp.XMPUtils;
+import com.adobe.xmp.impl.xpath.XMPPath;
+import com.adobe.xmp.impl.xpath.XMPPathSegment;
+import com.adobe.xmp.options.AliasOptions;
+import com.adobe.xmp.options.PropertyOptions;
+
+
+/**
+ * Utilities for <code>XMPNode</code>.
+ *
+ * @since Aug 28, 2006
+ */
+public class XMPNodeUtils implements XMPConst
+{
+ /** */
+ static final int CLT_NO_VALUES = 0;
+ /** */
+ static final int CLT_SPECIFIC_MATCH = 1;
+ /** */
+ static final int CLT_SINGLE_GENERIC = 2;
+ /** */
+ static final int CLT_MULTIPLE_GENERIC = 3;
+ /** */
+ static final int CLT_XDEFAULT = 4;
+ /** */
+ static final int CLT_FIRST_ITEM = 5;
+
+
+ /**
+ * Private Constructor
+ */
+ private XMPNodeUtils()
+ {
+ // EMPTY
+ }
+
+
+ /**
+ * Find or create a schema node if <code>createNodes</code> is false and
+ *
+ * @param tree the root of the xmp tree.
+ * @param namespaceURI a namespace
+ * @param createNodes a flag indicating if the node shall be created if not found.
+ * <em>Note:</em> The namespace must be registered prior to this call.
+ *
+ * @return Returns the schema node if found, <code>null</code> otherwise.
+ * Note: If <code>createNodes</code> is <code>true</code>, it is <b>always</b>
+ * returned a valid node.
+ * @throws XMPException An exception is only thrown if an error occurred, not if a
+ * node was not found.
+ */
+ static XMPNode findSchemaNode(XMPNode tree, String namespaceURI,
+ boolean createNodes)
+ throws XMPException
+ {
+ return findSchemaNode(tree, namespaceURI, null, createNodes);
+ }
+
+
+ /**
+ * Find or create a schema node if <code>createNodes</code> is true.
+ *
+ * @param tree the root of the xmp tree.
+ * @param namespaceURI a namespace
+ * @param suggestedPrefix If a prefix is suggested, the namespace is allowed to be registered.
+ * @param createNodes a flag indicating if the node shall be created if not found.
+ * <em>Note:</em> The namespace must be registered prior to this call.
+ *
+ * @return Returns the schema node if found, <code>null</code> otherwise.
+ * Note: If <code>createNodes</code> is <code>true</code>, it is <b>always</b>
+ * returned a valid node.
+ * @throws XMPException An exception is only thrown if an error occurred, not if a
+ * node was not found.
+ */
+ static XMPNode findSchemaNode(XMPNode tree, String namespaceURI, String suggestedPrefix,
+ boolean createNodes)
+ throws XMPException
+ {
+ assert tree.getParent() == null; // make sure that its the root
+ XMPNode schemaNode = tree.findChildByName(namespaceURI);
+
+ if (schemaNode == null && createNodes)
+ {
+ schemaNode = new XMPNode(namespaceURI,
+ new PropertyOptions()
+ .setSchemaNode(true));
+ schemaNode.setImplicit(true);
+
+ // only previously registered schema namespaces are allowed in the XMP tree.
+ String prefix = XMPMetaFactory.getSchemaRegistry().getNamespacePrefix(namespaceURI);
+ if (prefix == null)
+ {
+ if (suggestedPrefix != null && suggestedPrefix.length() != 0)
+ {
+ prefix = XMPMetaFactory.getSchemaRegistry().registerNamespace(namespaceURI,
+ suggestedPrefix);
+ }
+ else
+ {
+ throw new XMPException("Unregistered schema namespace URI",
+ XMPError.BADSCHEMA);
+ }
+ }
+
+ schemaNode.setValue(prefix);
+
+ tree.addChild(schemaNode);
+ }
+
+ return schemaNode;
+ }
+
+
+ /**
+ * Find or create a child node under a given parent node. If the parent node is no
+ * Returns the found or created child node.
+ *
+ * @param parent
+ * the parent node
+ * @param childName
+ * the node name to find
+ * @param createNodes
+ * flag, if new nodes shall be created.
+ * @return Returns the found or created node or <code>null</code>.
+ * @throws XMPException Thrown if
+ */
+ static XMPNode findChildNode(XMPNode parent, String childName, boolean createNodes)
+ throws XMPException
+ {
+ if (!parent.getOptions().isSchemaNode() && !parent.getOptions().isStruct())
+ {
+ if (!parent.isImplicit())
+ {
+ throw new XMPException("Named children only allowed for schemas and structs",
+ XMPError.BADXPATH);
+ }
+ else if (parent.getOptions().isArray())
+ {
+ throw new XMPException("Named children not allowed for arrays",
+ XMPError.BADXPATH);
+ }
+ else if (createNodes)
+ {
+ parent.getOptions().setStruct(true);
+ }
+ }
+
+ XMPNode childNode = parent.findChildByName(childName);
+
+ if (childNode == null && createNodes)
+ {
+ PropertyOptions options = new PropertyOptions();
+ childNode = new XMPNode(childName, options);
+ childNode.setImplicit(true);
+ parent.addChild(childNode);
+ }
+
+ assert childNode != null || !createNodes;
+
+ return childNode;
+ }
+
+
+ /**
+ * Follow an expanded path expression to find or create a node.
+ *
+ * @param xmpTree the node to begin the search.
+ * @param xpath the complete xpath
+ * @param createNodes flag if nodes shall be created
+ * (when called by <code>setProperty()</code>)
+ * @param leafOptions the options for the created leaf nodes (only when
+ * <code>createNodes == true</code>).
+ * @return Returns the node if found or created or <code>null</code>.
+ * @throws XMPException An exception is only thrown if an error occurred,
+ * not if a node was not found.
+ */
+ static XMPNode findNode(XMPNode xmpTree, XMPPath xpath, boolean createNodes,
+ PropertyOptions leafOptions) throws XMPException
+ {
+ // check if xpath is set.
+ if (xpath == null || xpath.size() == 0)
+ {
+ throw new XMPException("Empty XMPPath", XMPError.BADXPATH);
+ }
+
+ // Root of implicitly created subtree to possible delete it later.
+ // Valid only if leaf is new.
+ XMPNode rootImplicitNode = null;
+ XMPNode currNode = null;
+
+ // resolve schema step
+ currNode = findSchemaNode(xmpTree,
+ xpath.getSegment(XMPPath.STEP_SCHEMA).getName(), createNodes);
+ if (currNode == null)
+ {
+ return null;
+ }
+ else if (currNode.isImplicit())
+ {
+ currNode.setImplicit(false); // Clear the implicit node bit.
+ rootImplicitNode = currNode; // Save the top most implicit node.
+ }
+
+
+ // Now follow the remaining steps of the original XMPPath.
+ try
+ {
+ for (int i = 1; i < xpath.size(); i++)
+ {
+ currNode = followXPathStep(currNode, xpath.getSegment(i), createNodes);
+ if (currNode == null)
+ {
+ if (createNodes)
+ {
+ // delete implicitly created nodes
+ deleteNode(rootImplicitNode);
+ }
+ return null;
+ }
+ else if (currNode.isImplicit())
+ {
+ // clear the implicit node flag
+ currNode.setImplicit(false);
+
+ // if node is an ALIAS (can be only in root step, auto-create array
+ // when the path has been resolved from a not simple alias type
+ if (i == 1 &&
+ xpath.getSegment(i).isAlias() &&
+ xpath.getSegment(i).getAliasForm() != 0)
+ {
+ currNode.getOptions().setOption(xpath.getSegment(i).getAliasForm(), true);
+ }
+ // "CheckImplicitStruct" in C++
+ else if (i < xpath.size() - 1 &&
+ xpath.getSegment(i).getKind() == XMPPath.STRUCT_FIELD_STEP &&
+ !currNode.getOptions().isCompositeProperty())
+ {
+ currNode.getOptions().setStruct(true);
+ }
+
+ if (rootImplicitNode == null)
+ {
+ rootImplicitNode = currNode; // Save the top most implicit node.
+ }
+ }
+ }
+ }
+ catch (XMPException e)
+ {
+ // if new notes have been created prior to the error, delete them
+ if (rootImplicitNode != null)
+ {
+ deleteNode(rootImplicitNode);
+ }
+ throw e;
+ }
+
+
+ if (rootImplicitNode != null)
+ {
+ // set options only if a node has been successful created
+ currNode.getOptions().mergeWith(leafOptions);
+ currNode.setOptions(currNode.getOptions());
+ }
+
+ return currNode;
+ }
+
+
+ /**
+ * Deletes the the given node and its children from its parent.
+ * Takes care about adjusting the flags.
+ * @param node the top-most node to delete.
+ */
+ static void deleteNode(XMPNode node)
+ {
+ XMPNode parent = node.getParent();
+
+ if (node.getOptions().isQualifier())
+ {
+ // root is qualifier
+ parent.removeQualifier(node);
+ }
+ else
+ {
+ // root is NO qualifier
+ parent.removeChild(node);
+ }
+
+ // delete empty Schema nodes
+ if (!parent.hasChildren() && parent.getOptions().isSchemaNode())
+ {
+ parent.getParent().removeChild(parent);
+ }
+ }
+
+
+ /**
+ * This is setting the value of a leaf node.
+ *
+ * @param node an XMPNode
+ * @param value a value
+ */
+ static void setNodeValue(XMPNode node, Object value)
+ {
+ String strValue = serializeNodeValue(value);
+ if (!(node.getOptions().isQualifier() && XML_LANG.equals(node.getName())))
+ {
+ node.setValue(strValue);
+ }
+ else
+ {
+ node.setValue(Utils.normalizeLangValue(strValue));
+ }
+ }
+
+
+ /**
+ * Verifies the PropertyOptions for consistancy and updates them as needed.
+ * If options are <code>null</code> they are created with default values.
+ *
+ * @param options the <code>PropertyOptions</code>
+ * @param itemValue the node value to set
+ * @return Returns the updated options.
+ * @throws XMPException If the options are not consistant.
+ */
+ static PropertyOptions verifySetOptions(PropertyOptions options, Object itemValue)
+ throws XMPException
+ {
+ // create empty and fix existing options
+ if (options == null)
+ {
+ // set default options
+ options = new PropertyOptions();
+ }
+
+ if (options.isArrayAltText())
+ {
+ options.setArrayAlternate(true);
+ }
+
+ if (options.isArrayAlternate())
+ {
+ options.setArrayOrdered(true);
+ }
+
+ if (options.isArrayOrdered())
+ {
+ options.setArray(true);
+ }
+
+ if (options.isCompositeProperty() && itemValue != null && itemValue.toString().length() > 0)
+ {
+ throw new XMPException("Structs and arrays can't have values",
+ XMPError.BADOPTIONS);
+ }
+
+ options.assertConsistency(options.getOptions());
+
+ return options;
+ }
+
+
+ /**
+ * Converts the node value to String, apply special conversions for defined
+ * types in XMP.
+ *
+ * @param value
+ * the node value to set
+ * @return Returns the String representation of the node value.
+ */
+ static String serializeNodeValue(Object value)
+ {
+ String strValue;
+ if (value == null)
+ {
+ strValue = null;
+ }
+ else if (value instanceof Boolean)
+ {
+ strValue = XMPUtils.convertFromBoolean(((Boolean) value).booleanValue());
+ }
+ else if (value instanceof Integer)
+ {
+ strValue = XMPUtils.convertFromInteger(((Integer) value).intValue());
+ }
+ else if (value instanceof Long)
+ {
+ strValue = XMPUtils.convertFromLong(((Long) value).longValue());
+ }
+ else if (value instanceof Double)
+ {
+ strValue = XMPUtils.convertFromDouble(((Double) value).doubleValue());
+ }
+ else if (value instanceof XMPDateTime)
+ {
+ strValue = XMPUtils.convertFromDate((XMPDateTime) value);
+ }
+ else if (value instanceof Calendar)
+ {
+ XMPDateTime dt = XMPDateTimeFactory.createFromCalendar((Calendar) value);
+ strValue = XMPUtils.convertFromDate(dt);
+ }
+ else if (value instanceof byte[])
+ {
+ strValue = XMPUtils.encodeBase64((byte[]) value);
+ }
+ else
+ {
+ strValue = value.toString();
+ }
+
+ return strValue != null ? Utils.removeControlChars(strValue) : null;
+ }
+
+
+ /**
+ * After processing by ExpandXPath, a step can be of these forms:
+ * <ul>
+ * <li>qualName - A top level property or struct field.
+ * <li>[index] - An element of an array.
+ * <li>[last()] - The last element of an array.
+ * <li>[qualName="value"] - An element in an array of structs, chosen by a field value.
+ * <li>[?qualName="value"] - An element in an array, chosen by a qualifier value.
+ * <li>?qualName - A general qualifier.
+ * </ul>
+ * Find the appropriate child node, resolving aliases, and optionally creating nodes.
+ *
+ * @param parentNode the node to start to start from
+ * @param nextStep the xpath segment
+ * @param createNodes
+ * @return returns the found or created XMPPath node
+ * @throws XMPException
+ */
+ private static XMPNode followXPathStep(
+ XMPNode parentNode,
+ XMPPathSegment nextStep,
+ boolean createNodes) throws XMPException
+ {
+ XMPNode nextNode = null;
+ int index = 0;
+ int stepKind = nextStep.getKind();
+
+ if (stepKind == XMPPath.STRUCT_FIELD_STEP)
+ {
+ nextNode = findChildNode(parentNode, nextStep.getName(), createNodes);
+ }
+ else if (stepKind == XMPPath.QUALIFIER_STEP)
+ {
+ nextNode = findQualifierNode(
+ parentNode, nextStep.getName().substring(1), createNodes);
+ }
+ else
+ {
+ // This is an array indexing step. First get the index, then get the node.
+
+ if (!parentNode.getOptions().isArray())
+ {
+ throw new XMPException("Indexing applied to non-array", XMPError.BADXPATH);
+ }
+
+ if (stepKind == XMPPath.ARRAY_INDEX_STEP)
+ {
+ index = findIndexedItem(parentNode, nextStep.getName(), createNodes);
+ }
+ else if (stepKind == XMPPath.ARRAY_LAST_STEP)
+ {
+ index = parentNode.getChildrenLength();
+ }
+ else if (stepKind == XMPPath.FIELD_SELECTOR_STEP)
+ {
+ String[] result = Utils.splitNameAndValue(nextStep.getName());
+ String fieldName = result[0];
+ String fieldValue = result[1];
+ index = lookupFieldSelector(parentNode, fieldName, fieldValue);
+ }
+ else if (stepKind == XMPPath.QUAL_SELECTOR_STEP)
+ {
+ String[] result = Utils.splitNameAndValue(nextStep.getName());
+ String qualName = result[0];
+ String qualValue = result[1];
+ index = lookupQualSelector(
+ parentNode, qualName, qualValue, nextStep.getAliasForm());
+ }
+ else
+ {
+ throw new XMPException("Unknown array indexing step in FollowXPathStep",
+ XMPError.INTERNALFAILURE);
+ }
+
+ if (1 <= index && index <= parentNode.getChildrenLength())
+ {
+ nextNode = parentNode.getChild(index);
+ }
+ }
+
+ return nextNode;
+ }
+
+
+ /**
+ * Find or create a qualifier node under a given parent node. Returns a pointer to the
+ * qualifier node, and optionally an iterator for the node's position in
+ * the parent's vector of qualifiers. The iterator is unchanged if no qualifier node (null)
+ * is returned.
+ * <em>Note:</em> On entry, the qualName parameter must not have the leading '?' from the
+ * XMPPath step.
+ *
+ * @param parent the parent XMPNode
+ * @param qualName the qualifier name
+ * @param createNodes flag if nodes shall be created
+ * @return Returns the qualifier node if found or created, <code>null</code> otherwise.
+ * @throws XMPException
+ */
+ private static XMPNode findQualifierNode(XMPNode parent, String qualName, boolean createNodes)
+ throws XMPException
+ {
+ assert !qualName.startsWith("?");
+
+ XMPNode qualNode = parent.findQualifierByName(qualName);
+
+ if (qualNode == null && createNodes)
+ {
+ qualNode = new XMPNode(qualName, null);
+ qualNode.setImplicit(true);
+
+ parent.addQualifier(qualNode);
+ }
+
+ return qualNode;
+ }
+
+
+ /**
+ * @param arrayNode an array node
+ * @param segment the segment containing the array index
+ * @param createNodes flag if new nodes are allowed to be created.
+ * @return Returns the index or index = -1 if not found
+ * @throws XMPException Throws Exceptions
+ */
+ private static int findIndexedItem(XMPNode arrayNode, String segment, boolean createNodes)
+ throws XMPException
+ {
+ int index = 0;
+
+ try
+ {
+ segment = segment.substring(1, segment.length() - 1);
+ index = Integer.parseInt(segment);
+ if (index < 1)
+ {
+ throw new XMPException("Array index must be larger than zero",
+ XMPError.BADXPATH);
+ }
+ }
+ catch (NumberFormatException e)
+ {
+ throw new XMPException("Array index not digits.", XMPError.BADXPATH);
+ }
+
+ if (index == arrayNode.getChildrenLength() + 1 && createNodes)
+ {
+ // Append a new last + 1 node.
+ XMPNode newItem = new XMPNode(ARRAY_ITEM_NAME, null);
+ newItem.setImplicit(true);
+ arrayNode.addChild(newItem);
+ }
+
+ // Don't throw here for a too large index. setProperty() will throw,
+ // getProperty() will not.
+ if (index > arrayNode.getChildrenLength())
+ {
+ index = -1;
+ }
+ return index;
+ }
+
+
+ /**
+ * 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.
+ *
+ * @param arrayNode
+ * @param fieldName
+ * @param fieldValue
+ * @return Returns the index of the field if found, otherwise -1.
+ * @throws XMPException
+ */
+ private static int lookupFieldSelector(XMPNode arrayNode, String fieldName, String fieldValue)
+ throws XMPException
+ {
+ int result = -1;
+
+ for (int index = 1; index <= arrayNode.getChildrenLength() && result < 0; index++)
+ {
+ XMPNode currItem = arrayNode.getChild(index);
+
+ if (!currItem.getOptions().isStruct())
+ {
+ throw new XMPException("Field selector must be used on array of struct",
+ XMPError.BADXPATH);
+ }
+
+ for (int f = 1; f <= currItem.getChildrenLength(); f++)
+ {
+ XMPNode currField = currItem.getChild(f);
+ if (!fieldName.equals(currField.getName()))
+ {
+ continue;
+ }
+ if (fieldValue.equals(currField.getValue()))
+ {
+ result = index;
+ break;
+ }
+ }
+ }
+
+ return result;
+ }
+
+
+ /**
+ * 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.
+ *
+ * @param arrayNode an array node
+ * @param qualName the qualifier name
+ * @param qualValue the qualifier value
+ * @param aliasForm in case the qual selector results from an alias,
+ * an x-default node is created if there has not been one.
+ * @return Returns the index of th
+ * @throws XMPException
+ */
+ private static int lookupQualSelector(XMPNode arrayNode, String qualName,
+ String qualValue, int aliasForm) throws XMPException
+ {
+ if (XML_LANG.equals(qualName))
+ {
+ qualValue = Utils.normalizeLangValue(qualValue);
+ int index = XMPNodeUtils.lookupLanguageItem(arrayNode, qualValue);
+ if (index < 0 && (aliasForm & AliasOptions.PROP_ARRAY_ALT_TEXT) > 0)
+ {
+ XMPNode langNode = new XMPNode(ARRAY_ITEM_NAME, null);
+ XMPNode xdefault = new XMPNode(XML_LANG, X_DEFAULT, null);
+ langNode.addQualifier(xdefault);
+ arrayNode.addChild(1, langNode);
+ return 1;
+ }
+ else
+ {
+ return index;
+ }
+ }
+ else
+ {
+ for (int index = 1; index < arrayNode.getChildrenLength(); index++)
+ {
+ XMPNode currItem = arrayNode.getChild(index);
+
+ for (Iterator it = currItem.iterateQualifier(); it.hasNext();)
+ {
+ XMPNode qualifier = (XMPNode) it.next();
+ if (qualName.equals(qualifier.getName()) &&
+ qualValue.equals(qualifier.getValue()))
+ {
+ return index;
+ }
+ }
+ }
+ return -1;
+ }
+ }
+
+
+ /**
+ * 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.
+ *
+ * @param arrayNode
+ * an alt text array node
+ */
+ static void normalizeLangArray(XMPNode arrayNode)
+ {
+ if (!arrayNode.getOptions().isArrayAltText())
+ {
+ return;
+ }
+
+ // check if node with x-default qual is first place
+ for (int i = 2; i <= arrayNode.getChildrenLength(); i++)
+ {
+ XMPNode child = arrayNode.getChild(i);
+ if (child.hasQualifier() && X_DEFAULT.equals(child.getQualifier(1).getValue()))
+ {
+ // move node to first place
+ try
+ {
+ arrayNode.removeChild(i);
+ arrayNode.addChild(1, child);
+ }
+ catch (XMPException e)
+ {
+ // cannot occur, because same child is removed before
+ assert false;
+ }
+
+ if (i == 2)
+ {
+ arrayNode.getChild(2).setValue(child.getValue());
+ }
+ break;
+ }
+ }
+ }
+
+
+ /**
+ * See if an array is an alt-text array. If so, make sure the x-default item
+ * is first.
+ *
+ * @param arrayNode
+ * the array node to check if its an alt-text array
+ */
+ static void detectAltText(XMPNode arrayNode)
+ {
+ if (arrayNode.getOptions().isArrayAlternate() && arrayNode.hasChildren())
+ {
+ boolean isAltText = false;
+ for (Iterator it = arrayNode.iterateChildren(); it.hasNext();)
+ {
+ XMPNode child = (XMPNode) it.next();
+ if (child.getOptions().getHasLanguage())
+ {
+ isAltText = true;
+ break;
+ }
+ }
+
+ if (isAltText)
+ {
+ arrayNode.getOptions().setArrayAltText(true);
+ normalizeLangArray(arrayNode);
+ }
+ }
+ }
+
+
+ /**
+ * Appends a language item to an alt text array.
+ *
+ * @param arrayNode the language array
+ * @param itemLang the language of the item
+ * @param itemValue the content of the item
+ * @throws XMPException Thrown if a duplicate property is added
+ */
+ static void appendLangItem(XMPNode arrayNode, String itemLang, String itemValue)
+ throws XMPException
+ {
+ XMPNode newItem = new XMPNode(ARRAY_ITEM_NAME, itemValue, null);
+ XMPNode langQual = new XMPNode(XML_LANG, itemLang, null);
+ newItem.addQualifier(langQual);
+
+ if (!X_DEFAULT.equals(langQual.getValue()))
+ {
+ arrayNode.addChild(newItem);
+ }
+ else
+ {
+ arrayNode.addChild(1, newItem);
+ }
+ }
+
+
+ /**
+ * <ol>
+ * <li>Look for an exact match with the specific language.
+ * <li>If a generic language is given, look for partial matches.
+ * <li>Look for an "x-default"-item.
+ * <li>Choose the first item.
+ * </ol>
+ *
+ * @param arrayNode
+ * the alt text array node
+ * @param genericLang
+ * the generic language
+ * @param specificLang
+ * the specific language
+ * @return Returns the kind of match as an Integer and the found node in an
+ * array.
+ *
+ * @throws XMPException
+ */
+ static Object[] chooseLocalizedText(XMPNode arrayNode, String genericLang, String specificLang)
+ throws XMPException
+ {
+ // See if the array has the right form. Allow empty alt arrays,
+ // that is what parsing returns.
+ if (!arrayNode.getOptions().isArrayAltText())
+ {
+ throw new XMPException("Localized text array is not alt-text", XMPError.BADXPATH);
+ }
+ else if (!arrayNode.hasChildren())
+ {
+ return new Object[] { new Integer(XMPNodeUtils.CLT_NO_VALUES), null };
+ }
+
+ int foundGenericMatches = 0;
+ XMPNode resultNode = null;
+ XMPNode xDefault = null;
+
+ // Look for the first partial match with the generic language.
+ for (Iterator it = arrayNode.iterateChildren(); it.hasNext();)
+ {
+ XMPNode currItem = (XMPNode) it.next();
+
+ // perform some checks on the current item
+ if (currItem.getOptions().isCompositeProperty())
+ {
+ throw new XMPException("Alt-text array item is not simple", XMPError.BADXPATH);
+ }
+ else if (!currItem.hasQualifier()
+ || !XML_LANG.equals(currItem.getQualifier(1).getName()))
+ {
+ throw new XMPException("Alt-text array item has no language qualifier",
+ XMPError.BADXPATH);
+ }
+
+ String currLang = currItem.getQualifier(1).getValue();
+
+ // Look for an exact match with the specific language.
+ if (specificLang.equals(currLang))
+ {
+ return new Object[] { new Integer(XMPNodeUtils.CLT_SPECIFIC_MATCH), currItem };
+ }
+ else if (genericLang != null && currLang.startsWith(genericLang))
+ {
+ if (resultNode == null)
+ {
+ resultNode = currItem;
+ }
+ // ! Don't return/break, need to look for other matches.
+ foundGenericMatches++;
+ }
+ else if (X_DEFAULT.equals(currLang))
+ {
+ xDefault = currItem;
+ }
+ }
+
+ // evaluate loop
+ if (foundGenericMatches == 1)
+ {
+ return new Object[] { new Integer(XMPNodeUtils.CLT_SINGLE_GENERIC), resultNode };
+ }
+ else if (foundGenericMatches > 1)
+ {
+ return new Object[] { new Integer(XMPNodeUtils.CLT_MULTIPLE_GENERIC), resultNode };
+ }
+ else if (xDefault != null)
+ {
+ return new Object[] { new Integer(XMPNodeUtils.CLT_XDEFAULT), xDefault };
+ }
+ else
+ {
+ // Everything failed, choose the first item.
+ return new Object[] { new Integer(XMPNodeUtils.CLT_FIRST_ITEM), arrayNode.getChild(1) };
+ }
+ }
+
+
+ /**
+ * Looks for the appropriate language item in a text alternative array.item
+ *
+ * @param arrayNode
+ * an array node
+ * @param language
+ * the requested language
+ * @return Returns the index if the language has been found, -1 otherwise.
+ * @throws XMPException
+ */
+ static int lookupLanguageItem(XMPNode arrayNode, String language) throws XMPException
+ {
+ if (!arrayNode.getOptions().isArray())
+ {
+ throw new XMPException("Language item must be used on array", XMPError.BADXPATH);
+ }
+
+ for (int index = 1; index <= arrayNode.getChildrenLength(); index++)
+ {
+ XMPNode child = arrayNode.getChild(index);
+ if (!child.hasQualifier() || !XML_LANG.equals(child.getQualifier(1).getName()))
+ {
+ continue;
+ }
+ else if (language.equals(child.getQualifier(1).getValue()))
+ {
+ return index;
+ }
+ }
+
+ return -1;
+ }
+}
diff --git a/java/XMPCore/src/com/adobe/xmp/impl/XMPNormalizer.java b/java/XMPCore/src/com/adobe/xmp/impl/XMPNormalizer.java
new file mode 100644
index 0000000..b812324
--- /dev/null
+++ b/java/XMPCore/src/com/adobe/xmp/impl/XMPNormalizer.java
@@ -0,0 +1,696 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+package com.adobe.xmp.impl;
+
+import java.util.Calendar;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import com.adobe.xmp.XMPConst;
+import com.adobe.xmp.XMPDateTime;
+import com.adobe.xmp.XMPError;
+import com.adobe.xmp.XMPException;
+import com.adobe.xmp.XMPMeta;
+import com.adobe.xmp.XMPMetaFactory;
+import com.adobe.xmp.XMPUtils;
+import com.adobe.xmp.impl.xpath.XMPPath;
+import com.adobe.xmp.impl.xpath.XMPPathParser;
+import com.adobe.xmp.options.ParseOptions;
+import com.adobe.xmp.options.PropertyOptions;
+import com.adobe.xmp.properties.XMPAliasInfo;
+
+/**
+ * @since Aug 18, 2006
+ */
+public class XMPNormalizer
+{
+ /** caches the correct dc-property array forms */
+ private static Map dcArrayForms;
+ /** init char tables */
+ static
+ {
+ initDCArrays();
+ }
+
+
+ /**
+ * Hidden constructor
+ */
+ private XMPNormalizer()
+ {
+ // EMPTY
+ }
+
+
+ /**
+ * Normalizes a raw parsed XMPMeta-Object
+ * @param xmp the raw metadata object
+ * @param options the parsing options
+ * @return Returns the normalized metadata object
+ * @throws XMPException Collects all severe processing errors.
+ */
+ static XMPMeta process(XMPMetaImpl xmp, ParseOptions options) throws XMPException
+ {
+ XMPNode tree = xmp.getRoot();
+
+ touchUpDataModel(xmp);
+ moveExplicitAliases(tree, options);
+
+ tweakOldXMP(tree);
+
+ deleteEmptySchemas(tree);
+
+ return xmp;
+ }
+
+
+ /**
+ * Tweak old XMP: Move an instance ID from rdf:about to the
+ * <em>xmpMM:InstanceID</em> property. An old instance ID usually looks
+ * like &quot;uuid:bac965c4-9d87-11d9-9a30-000d936b79c4&quot;, plus InDesign
+ * 3.0 wrote them like &quot;bac965c4-9d87-11d9-9a30-000d936b79c4&quot;. If
+ * the name looks like a UUID simply move it to <em>xmpMM:InstanceID</em>,
+ * don't worry about any existing <em>xmpMM:InstanceID</em>. Both will
+ * only be present when a newer file with the <em>xmpMM:InstanceID</em>
+ * property is updated by an old app that uses <em>rdf:about</em>.
+ *
+ * @param tree the root of the metadata tree
+ * @throws XMPException Thrown if tweaking fails.
+ */
+ private static void tweakOldXMP(XMPNode tree) throws XMPException
+ {
+ if (tree.getName() != null && tree.getName().length() >= Utils.UUID_LENGTH)
+ {
+ String nameStr = tree.getName().toLowerCase();
+ if (nameStr.startsWith("uuid:"))
+ {
+ nameStr = nameStr.substring(5);
+ }
+
+ if (Utils.checkUUIDFormat(nameStr))
+ {
+ // move UUID to xmpMM:InstanceID and remove it from the root node
+ XMPPath path = XMPPathParser.expandXPath(XMPConst.NS_XMP_MM, "InstanceID");
+ XMPNode idNode = XMPNodeUtils.findNode (tree, path, true, null);
+ if (idNode != null)
+ {
+ idNode.setOptions(null); // Clobber any existing xmpMM:InstanceID.
+ idNode.setValue("uuid:" + nameStr);
+ idNode.removeChildren();
+ idNode.removeQualifiers();
+ tree.setName(null);
+ }
+ else
+ {
+ throw new XMPException("Failure creating xmpMM:InstanceID",
+ XMPError.INTERNALFAILURE);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Visit all schemas to do general fixes and handle special cases.
+ *
+ * @param xmp the metadata object implementation
+ * @throws XMPException Thrown if the normalisation fails.
+ */
+ private static void touchUpDataModel(XMPMetaImpl xmp) throws XMPException
+ {
+ // 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 (Iterator it = xmp.getRoot().iterateChildren(); it.hasNext();)
+ {
+ XMPNode currSchema = (XMPNode) it.next();
+ 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, "xapRights:UsageTerms",
+ false);
+ if (arrayNode != null)
+ {
+ repairAltText(arrayNode);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * 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 <code>xml:lang</code> attribute was dropped from an
+ * <code>alt-text</code> item if the language was <code>x-default</code>.
+ *
+ * @param dcSchema the DC schema node
+ * @throws XMPException Thrown if normalization fails
+ */
+ private static void normalizeDCArrays(XMPNode dcSchema) throws XMPException
+ {
+ for (int i = 1; i <= dcSchema.getChildrenLength(); i++)
+ {
+ XMPNode currProp = dcSchema.getChild(i);
+
+ PropertyOptions arrayForm = (PropertyOptions) dcArrayForms.get(currProp.getName());
+ if (arrayForm == null)
+ {
+ continue;
+ }
+ else if (currProp.getOptions().isSimple())
+ {
+ // create a new array and add the current property as child,
+ // if it was formerly simple
+ XMPNode newArray = new XMPNode(currProp.getName(), arrayForm);
+ currProp.setName(XMPConst.ARRAY_ITEM_NAME);
+ newArray.addChild(currProp);
+ dcSchema.replaceChild(i, newArray);
+
+ // fix language alternatives
+ if (arrayForm.isArrayAltText() && !currProp.getOptions().getHasLanguage())
+ {
+ XMPNode newLang = new XMPNode(XMPConst.XML_LANG, XMPConst.X_DEFAULT, null);
+ currProp.addQualifier(newLang);
+ }
+ }
+ else
+ {
+ // clear array options and add corrected array form if it has been an array before
+ currProp.getOptions().setOption(
+ PropertyOptions.ARRAY |
+ PropertyOptions.ARRAY_ORDERED |
+ PropertyOptions.ARRAY_ALTERNATE |
+ PropertyOptions.ARRAY_ALT_TEXT,
+ false);
+ currProp.getOptions().mergeWith(arrayForm);
+
+ if (arrayForm.isArrayAltText())
+ {
+ // applying for "dc:description", "dc:rights", "dc:title"
+ repairAltText(currProp);
+ }
+ }
+
+ }
+ }
+
+
+ /**
+ * Make sure that the array is well-formed AltText. Each item must be simple
+ * and have an "xml:lang" qualifier. If repairs are needed, keep simple
+ * non-empty items by adding the "xml:lang" with value "x-repair".
+ * @param arrayNode the property node of the array to repair.
+ * @throws XMPException Forwards unexpected exceptions.
+ */
+ private static void repairAltText(XMPNode arrayNode) throws XMPException
+ {
+ if (arrayNode == null ||
+ !arrayNode.getOptions().isArray())
+ {
+ // Already OK or not even an array.
+ return;
+ }
+
+ // fix options
+ arrayNode.getOptions().setArrayOrdered(true).setArrayAlternate(true).setArrayAltText(true);
+
+ for (Iterator it = arrayNode.iterateChildren(); it.hasNext();)
+ {
+ XMPNode currChild = (XMPNode) it.next();
+ if (currChild.getOptions().isCompositeProperty())
+ {
+ // Delete non-simple children.
+ it.remove();
+ }
+ else if (!currChild.getOptions().getHasLanguage())
+ {
+ String childValue = currChild.getValue();
+ if (childValue == null || childValue.length() == 0)
+ {
+ // Delete empty valued children that have no xml:lang.
+ it.remove();
+ }
+ else
+ {
+ // Add an xml:lang qualifier with the value "x-repair".
+ XMPNode repairLang = new XMPNode(XMPConst.XML_LANG, "x-repair", null);
+ currChild.addQualifier(repairLang);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * 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.
+ *
+ * @param tree the root of the metadata tree
+ * @param options th parsing options
+ * @throws XMPException Forwards XMP errors
+ */
+ private static void moveExplicitAliases(XMPNode tree, ParseOptions options)
+ throws XMPException
+ {
+ if (!tree.getHasAliases())
+ {
+ return;
+ }
+ tree.setHasAliases(false);
+
+ boolean strictAliasing = options.getStrictAliasing();
+
+ for (Iterator schemaIt = tree.getUnmodifiableChildren().iterator(); schemaIt.hasNext();)
+ {
+ XMPNode currSchema = (XMPNode) schemaIt.next();
+ if (!currSchema.getHasAliases())
+ {
+ continue;
+ }
+
+ for (Iterator propertyIt = currSchema.iterateChildren(); propertyIt.hasNext();)
+ {
+ XMPNode currProp = (XMPNode) propertyIt.next();
+
+ 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);
+ // remove the alias property
+ propertyIt.remove();
+ }
+ 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 (propertyIt, currProp, baseNode);
+ }
+
+ }
+ 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);
+ }
+
+ propertyIt.remove();
+ }
+ 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 (propertyIt, currProp, baseNode);
+ }
+ else
+ {
+ if (strictAliasing)
+ {
+ compareAliasedSubtrees (currProp, itemNode, true);
+ }
+
+ propertyIt.remove();
+ }
+ }
+ }
+ }
+ currSchema.setHasAliases(false);
+ }
+ }
+
+
+ /**
+ * Moves an alias node of array form to another schema into an array
+ * @param propertyIt the property iterator of the old schema (used to delete the property)
+ * @param childNode the node to be moved
+ * @param baseArray the base array for the array item
+ * @throws XMPException Forwards XMP errors
+ */
+ private static void transplantArrayItemAlias(Iterator propertyIt, XMPNode childNode,
+ XMPNode baseArray) throws XMPException
+ {
+ if (baseArray.getOptions().isArrayAltText())
+ {
+ if (childNode.getOptions().getHasLanguage())
+ {
+ throw new XMPException("Alias to x-default already has a language qualifier",
+ XMPError.BADXMP);
+ }
+
+ XMPNode langQual = new XMPNode(XMPConst.XML_LANG, XMPConst.X_DEFAULT, null);
+ childNode.addQualifier(langQual);
+ }
+
+ propertyIt.remove();
+ childNode.setName(XMPConst.ARRAY_ITEM_NAME);
+ baseArray.addChild(childNode);
+ }
+
+
+ /**
+ * Fixes the GPS Timestamp in EXIF.
+ * @param exifSchema the EXIF schema node
+ * @throws XMPException Thrown if the date conversion fails.
+ */
+ private static void fixGPSTimeStamp(XMPNode exifSchema)
+ throws XMPException
+ {
+ // Note: if dates are not found the convert-methods throws an exceptions,
+ // and this methods returns.
+ XMPNode gpsDateTime = XMPNodeUtils.findChildNode(exifSchema, "exif:GPSTimeStamp", false);
+ if (gpsDateTime == null)
+ {
+ return;
+ }
+
+ try
+ {
+ XMPDateTime binGPSStamp;
+ XMPDateTime binOtherDate;
+
+ binGPSStamp = XMPUtils.convertToDate(gpsDateTime.getValue());
+ if (binGPSStamp.getYear() != 0 ||
+ binGPSStamp.getMonth() != 0 ||
+ binGPSStamp.getDay() != 0)
+ {
+ return;
+ }
+
+ XMPNode otherDate = XMPNodeUtils.findChildNode(exifSchema, "exif:DateTimeOriginal",
+ false);
+ if (otherDate == null)
+ {
+ otherDate = XMPNodeUtils.findChildNode(exifSchema, "exif:DateTimeDigitized", false);
+ }
+
+ binOtherDate = XMPUtils.convertToDate(otherDate.getValue());
+ Calendar cal = binGPSStamp.getCalendar();
+ cal.set(Calendar.YEAR, binOtherDate.getYear());
+ cal.set(Calendar.MONTH, binOtherDate.getMonth());
+ cal.set(Calendar.DAY_OF_MONTH, binOtherDate.getDay());
+ binGPSStamp = new XMPDateTimeImpl(cal);
+
+ gpsDateTime.setValue(XMPUtils.convertFromDate (binGPSStamp));
+ }
+ catch (XMPException e)
+ {
+ // Don't let a missing or bad date stop other things.
+ return;
+ }
+ }
+
+
+
+ /**
+ * Remove all empty schemas from the metadata tree that were generated during the rdf parsing.
+ * @param tree the root of the metadata tree
+ */
+ private static void deleteEmptySchemas(XMPNode tree)
+ {
+ // Delete empty schema nodes. Do this last, other cleanup can make empty
+ // schema.
+
+ for (Iterator it = tree.iterateChildren(); it.hasNext();)
+ {
+ XMPNode schema = (XMPNode) it.next();
+ if (!schema.hasChildren())
+ {
+ it.remove();
+ }
+ }
+ }
+
+
+ /**
+ * The outermost call is special. The names almost certainly differ. The
+ * qualifiers (and hence options) will differ for an alias to the x-default
+ * item of a langAlt array.
+ *
+ * @param aliasNode the alias node
+ * @param baseNode the base node of the alias
+ * @param outerCall marks the outer call of the recursion
+ * @throws XMPException Forwards XMP errors
+ */
+ private static void compareAliasedSubtrees(XMPNode aliasNode, XMPNode baseNode,
+ boolean outerCall) throws XMPException
+ {
+ if (!aliasNode.getValue().equals(baseNode.getValue()) ||
+ aliasNode.getChildrenLength() != baseNode.getChildrenLength())
+ {
+ throw new XMPException("Mismatch between alias and base nodes", XMPError.BADXMP);
+ }
+
+ if (
+ !outerCall &&
+ (!aliasNode.getName().equals(baseNode.getName()) ||
+ !aliasNode.getOptions().equals(baseNode.getOptions()) ||
+ aliasNode.getQualifierLength() != baseNode.getQualifierLength())
+ )
+ {
+ throw new XMPException("Mismatch between alias and base nodes",
+ XMPError.BADXMP);
+ }
+
+ for (Iterator an = aliasNode.iterateChildren(),
+ bn = baseNode.iterateChildren();
+ an.hasNext() && bn.hasNext();)
+ {
+ XMPNode aliasChild = (XMPNode) an.next();
+ XMPNode baseChild = (XMPNode) bn.next();
+ compareAliasedSubtrees (aliasChild, baseChild, false);
+ }
+
+
+ for (Iterator an = aliasNode.iterateQualifier(),
+ bn = baseNode.iterateQualifier();
+ an.hasNext() && bn.hasNext();)
+ {
+ XMPNode aliasQual = (XMPNode) an.next();
+ XMPNode baseQual = (XMPNode) bn.next();
+ compareAliasedSubtrees (aliasQual, baseQual, false);
+ }
+ }
+
+
+ /**
+ * 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>
+ *
+ * @param xmp the metadata object
+ * @param dmCopyright the "dm:copyright"-property
+ */
+ 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.substring(0, lfPos + 2) + dmValue);
+ }
+ }
+
+ }
+
+ // 4. Get rid of the xmpDM:copyright.
+ dmCopyright.getParent().removeChild(dmCopyright);
+ }
+ catch (XMPException e)
+ {
+ // Don't let failures (like a bad dc:rights form) stop other
+ // cleanup.
+ }
+ }
+
+
+ /**
+ * Initializes the map that contains the known arrays, that are fixed by
+ * {@link XMPNormalizer#normalizeDCArrays(XMPNode)}.
+ */
+ private static void initDCArrays()
+ {
+ dcArrayForms = new HashMap();
+
+ // Properties supposed to be a "Bag".
+ PropertyOptions bagForm = new PropertyOptions();
+ bagForm.setArray(true);
+ dcArrayForms.put("dc:contributor", bagForm);
+ dcArrayForms.put("dc:language", bagForm);
+ dcArrayForms.put("dc:publisher", bagForm);
+ dcArrayForms.put("dc:relation", bagForm);
+ dcArrayForms.put("dc:subject", bagForm);
+ dcArrayForms.put("dc:type", bagForm);
+
+ // Properties supposed to be a "Seq".
+ PropertyOptions seqForm = new PropertyOptions();
+ seqForm.setArray(true);
+ seqForm.setArrayOrdered(true);
+ dcArrayForms.put("dc:creator", seqForm);
+ dcArrayForms.put("dc:date", seqForm);
+
+ // Properties supposed to be an "Alt" in alternative-text form.
+ PropertyOptions altTextForm = new PropertyOptions();
+ altTextForm.setArray(true);
+ altTextForm.setArrayOrdered(true);
+ altTextForm.setArrayAlternate(true);
+ altTextForm.setArrayAltText(true);
+ dcArrayForms.put("dc:description", altTextForm);
+ dcArrayForms.put("dc:rights", altTextForm);
+ dcArrayForms.put("dc:title", altTextForm);
+ }
+}
diff --git a/java/XMPCore/src/com/adobe/xmp/impl/XMPSchemaRegistryImpl.java b/java/XMPCore/src/com/adobe/xmp/impl/XMPSchemaRegistryImpl.java
new file mode 100644
index 0000000..c6135ca
--- /dev/null
+++ b/java/XMPCore/src/com/adobe/xmp/impl/XMPSchemaRegistryImpl.java
@@ -0,0 +1,467 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+package com.adobe.xmp.impl;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.regex.Pattern;
+
+import com.adobe.xmp.XMPConst;
+import com.adobe.xmp.XMPError;
+import com.adobe.xmp.XMPException;
+import com.adobe.xmp.XMPSchemaRegistry;
+import com.adobe.xmp.options.AliasOptions;
+import com.adobe.xmp.properties.XMPAliasInfo;
+
+
+/**
+ * The schema registry handles the namespaces, aliases and global options for the XMP Toolkit. There
+ * is only one single instance used by the toolkit.
+ *
+ * @since 27.01.2006
+ */
+public final class XMPSchemaRegistryImpl implements XMPSchemaRegistry, XMPConst
+{
+ /** a map from a namespace URI to its registered prefix */
+ private Map namespaceToPrefixMap = new HashMap();
+
+ /** a map from a prefix to the associated namespace URI */
+ private Map prefixToNamespaceMap = new HashMap();
+
+ /** a map of all registered aliases.
+ * The map is a relationship from a qname to an <code>XMPAliasInfo</code>-object. */
+ private Map aliasMap = new HashMap();
+ /** The pattern that must not be contained in simple properties */
+ private Pattern p = Pattern.compile("[/*?\\[\\]]");
+
+
+ /**
+ * Performs the initialisation of the registry with the default namespaces, aliases and global
+ * options.
+ */
+ public XMPSchemaRegistryImpl()
+ {
+ try
+ {
+ registerStandardNamespaces();
+ registerStandardAliases();
+ }
+ catch (XMPException e)
+ {
+ throw new RuntimeException("The XMPSchemaRegistry cannot be initialized!");
+ }
+ }
+
+
+ // ---------------------------------------------------------------------------------------------
+ // Namespace Functions
+
+
+ /**
+ * @see XMPSchemaRegistry#registerNamespace(String, String)
+ */
+ public synchronized String registerNamespace(String namespaceURI, String suggestedPrefix)
+ throws XMPException
+ {
+ ParameterAsserts.assertSchemaNS(namespaceURI);
+ ParameterAsserts.assertPrefix(suggestedPrefix);
+
+ if (suggestedPrefix.charAt(suggestedPrefix.length() - 1) != ':')
+ {
+ suggestedPrefix += ':';
+ }
+
+ if (!Utils.isXMLNameNS(suggestedPrefix.substring(0,
+ suggestedPrefix.length() - 1)))
+ {
+ throw new XMPException("The prefix is a bad XML name", XMPError.BADXML);
+ }
+
+ String registeredPrefix = (String) namespaceToPrefixMap.get(namespaceURI);
+ String registeredNS = (String) prefixToNamespaceMap.get(suggestedPrefix);
+ if (registeredPrefix != null)
+ {
+ // Return the actual prefix
+ return registeredPrefix;
+ }
+ else
+ {
+ if (registeredNS != null)
+ {
+ // the namespace is new, but the prefix is already engaged,
+ // we generate a new prefix out of the suggested
+ String generatedPrefix = suggestedPrefix;
+ for (int i = 1; prefixToNamespaceMap.containsKey(generatedPrefix); i++)
+ {
+ generatedPrefix = suggestedPrefix
+ .substring(0, suggestedPrefix.length() - 1)
+ + "_" + i + "_:";
+ }
+ suggestedPrefix = generatedPrefix;
+ }
+ prefixToNamespaceMap.put(suggestedPrefix, namespaceURI);
+ namespaceToPrefixMap.put(namespaceURI, suggestedPrefix);
+
+ // Return the suggested prefix
+ return suggestedPrefix;
+ }
+ }
+
+
+ /**
+ * @see XMPSchemaRegistry#deleteNamespace(String)
+ */
+ public synchronized void deleteNamespace(String namespaceURI)
+ {
+ String prefixToDelete = getNamespacePrefix(namespaceURI);
+ if (prefixToDelete != null)
+ {
+ namespaceToPrefixMap.remove(namespaceURI);
+ prefixToNamespaceMap.remove(prefixToDelete);
+ }
+ }
+
+
+ /**
+ * @see XMPSchemaRegistry#getNamespacePrefix(String)
+ */
+ public synchronized String getNamespacePrefix(String namespaceURI)
+ {
+ return (String) namespaceToPrefixMap.get(namespaceURI);
+ }
+
+
+ /**
+ * @see XMPSchemaRegistry#getNamespaceURI(String)
+ */
+ public synchronized String getNamespaceURI(String namespacePrefix)
+ {
+ if (namespacePrefix != null && !namespacePrefix.endsWith(":"))
+ {
+ namespacePrefix += ":";
+ }
+ return (String) prefixToNamespaceMap.get(namespacePrefix);
+ }
+
+
+ /**
+ * @see XMPSchemaRegistry#getNamespaces()
+ */
+ public synchronized Map getNamespaces()
+ {
+ return Collections.unmodifiableMap(new TreeMap(namespaceToPrefixMap));
+ }
+
+
+ /**
+ * @see XMPSchemaRegistry#getPrefixes()
+ */
+ public synchronized Map getPrefixes()
+ {
+ return Collections.unmodifiableMap(new TreeMap(prefixToNamespaceMap));
+ }
+
+
+ /**
+ * Register the standard namespaces of schemas and types that are included in the XMP
+ * Specification and some other Adobe private namespaces.
+ * Note: This method is not lock because only called by the constructor.
+ *
+ * @throws XMPException Forwards processing exceptions
+ */
+ private void registerStandardNamespaces() throws XMPException
+ {
+ // register standard namespaces
+ registerNamespace(NS_XML, "xml");
+ registerNamespace(NS_RDF, "rdf");
+ registerNamespace(NS_DC, "dc");
+ registerNamespace(NS_IPTCCORE, "Iptc4xmpCore");
+
+ // register Adobe standard namespaces
+ registerNamespace(NS_X, "x");
+ registerNamespace(NS_IX, "iX");
+
+ registerNamespace(NS_XMP, "xap");
+ registerNamespace(NS_XMP_RIGHTS, "xapRights");
+ registerNamespace(NS_XMP_MM, "xapMM");
+ registerNamespace(NS_XMP_BJ, "xapBJ");
+ registerNamespace(NS_XMP_NOTE, "xmpNote");
+
+ registerNamespace(NS_PDF, "pdf");
+ registerNamespace(NS_PDFX, "pdfx");
+ registerNamespace(NS_PDFX_ID, "pdfxid");
+ registerNamespace(NS_PDFA_SCHEMA, "pdfaSchema");
+ registerNamespace(NS_PDFA_PROPERTY, "pdfaProperty");
+ registerNamespace(NS_PDFA_TYPE, "pdfaType");
+ registerNamespace(NS_PDFA_FIELD, "pdfaField");
+ registerNamespace(NS_PDFA_ID, "pdfaid");
+ registerNamespace(NS_PDFA_EXTENSION, "pdfaExtension");
+ registerNamespace(NS_PHOTOSHOP, "photoshop");
+ registerNamespace(NS_PSALBUM, "album");
+ registerNamespace(NS_EXIF, "exif");
+ registerNamespace(NS_EXIF_AUX, "aux");
+ registerNamespace(NS_TIFF, "tiff");
+ registerNamespace(NS_PNG, "png");
+ registerNamespace(NS_JPEG, "jpeg");
+ registerNamespace(NS_JP2K, "jp2k");
+ registerNamespace(NS_CAMERARAW, "crs");
+ registerNamespace(NS_ADOBESTOCKPHOTO, "bmsp");
+ registerNamespace(NS_ASF, "asf");
+ registerNamespace(NS_WAV, "wav");
+
+ // register Adobe private namespaces
+ registerNamespace(NS_DM, "xmpDM");
+ registerNamespace(NS_TRANSIENT, "xmpx");
+
+ // register Adobe standard type namespaces
+ registerNamespace(TYPE_TEXT, "xapT");
+ registerNamespace(TYPE_PAGEDFILE, "xapTPg");
+ registerNamespace(TYPE_GRAPHICS, "xapG");
+ registerNamespace(TYPE_IMAGE, "xapGImg");
+ registerNamespace(TYPE_FONT, "stFNT");
+ registerNamespace(TYPE_DIMENSIONS, "stDim");
+ registerNamespace(TYPE_RESOURCEEVENT, "stEvt");
+ registerNamespace(TYPE_RESOURCEREF, "stRef");
+ registerNamespace(TYPE_ST_VERSION, "stVer");
+ registerNamespace(TYPE_ST_JOB, "stJob");
+ registerNamespace(TYPE_MANIFESTITEM, "stMfs");
+ registerNamespace(TYPE_IDENTIFIERQUAL, "xmpidq");
+ }
+
+
+
+ // ---------------------------------------------------------------------------------------------
+ // Alias Functions
+
+
+ /**
+ * @see XMPSchemaRegistry#resolveAlias(String, String)
+ */
+ public synchronized XMPAliasInfo resolveAlias(String aliasNS, String aliasProp)
+ {
+ String aliasPrefix = getNamespacePrefix(aliasNS);
+ if (aliasPrefix == null)
+ {
+ return null;
+ }
+
+ return (XMPAliasInfo) aliasMap.get(aliasPrefix + aliasProp);
+ }
+
+
+ /**
+ * @see XMPSchemaRegistry#findAlias(java.lang.String)
+ */
+ public synchronized XMPAliasInfo findAlias(String qname)
+ {
+ return (XMPAliasInfo) aliasMap.get(qname);
+ }
+
+
+ /**
+ * @see XMPSchemaRegistry#findAliases(String)
+ */
+ public synchronized XMPAliasInfo[] findAliases(String aliasNS)
+ {
+ String prefix = getNamespacePrefix(aliasNS);
+ List result = new ArrayList();
+ if (prefix != null)
+ {
+ for (Iterator it = aliasMap.keySet().iterator(); it.hasNext();)
+ {
+ String qname = (String) it.next();
+ if (qname.startsWith(prefix))
+ {
+ result.add(findAlias(qname));
+ }
+ }
+
+ }
+ return (XMPAliasInfo[]) result.toArray(new XMPAliasInfo[result.size()]);
+ }
+
+
+ /**
+ * @see XMPSchemaRegistry#registerAlias(String, String, String, String,
+ * AliasOptions)
+ */
+ public synchronized void registerAlias(String aliasNS, String aliasProp, final String actualNS,
+ final String actualProp, final AliasOptions aliasForm) throws XMPException
+ {
+ ParameterAsserts.assertSchemaNS(aliasNS);
+ ParameterAsserts.assertPropName(aliasProp);
+ ParameterAsserts.assertSchemaNS(actualNS);
+ ParameterAsserts.assertPropName(actualProp);
+
+ // Fix the alias options
+ final AliasOptions aliasOpts = aliasForm != null ?
+ new AliasOptions(XMPNodeUtils.verifySetOptions(
+ aliasForm.toPropertyOptions(), null).getOptions()) :
+ new AliasOptions();
+
+ if (p.matcher(aliasProp).find() || p.matcher(actualProp).find())
+ {
+ throw new XMPException("Alias and actual property names must be simple",
+ XMPError.BADXPATH);
+ }
+
+ // check if both namespaces are registered
+ final String aliasPrefix = getNamespacePrefix(aliasNS);
+ final String actualPrefix = getNamespacePrefix(actualNS);
+ if (aliasPrefix == null)
+ {
+ throw new XMPException("Alias namespace is not registered", XMPError.BADSCHEMA);
+ }
+ else if (actualPrefix == null)
+ {
+ throw new XMPException("Actual namespace is not registered",
+ XMPError.BADSCHEMA);
+ }
+
+ String key = aliasPrefix + aliasProp;
+
+ // check if alias is already existing
+ if (aliasMap.containsKey(key))
+ {
+ throw new XMPException("Alias is already existing", XMPError.BADPARAM);
+ }
+ else if (aliasMap.containsKey(actualPrefix + actualProp))
+ {
+ throw new XMPException(
+ "Actual property is already an alias, use the base property",
+ XMPError.BADPARAM);
+ }
+
+ XMPAliasInfo aliasInfo = new XMPAliasInfo()
+ {
+ /**
+ * @see XMPAliasInfo#getNamespace()
+ */
+ public String getNamespace()
+ {
+ return actualNS;
+ }
+
+ /**
+ * @see XMPAliasInfo#getPrefix()
+ */
+ public String getPrefix()
+ {
+ return actualPrefix;
+ }
+
+ /**
+ * @see XMPAliasInfo#getPropName()
+ */
+ public String getPropName()
+ {
+ return actualProp;
+ }
+
+ /**
+ * @see XMPAliasInfo#getAliasForm()
+ */
+ public AliasOptions getAliasForm()
+ {
+ return aliasOpts;
+ }
+
+ public String toString()
+ {
+ return actualPrefix + actualProp + " NS(" + actualNS + "), FORM ("
+ + getAliasForm() + ")";
+ }
+ };
+
+ aliasMap.put(key, aliasInfo);
+ }
+
+
+ /**
+ * @see XMPSchemaRegistry#deleteAlias(String, String)
+ */
+ public synchronized void deleteAlias(String aliasNS, String aliasProp)
+ {
+ String aliasPrefix = getNamespacePrefix(aliasNS);
+ aliasMap.remove(aliasPrefix + aliasProp);
+ }
+
+
+ /**
+ * @see XMPSchemaRegistry#getAliases()
+ */
+ public synchronized Map getAliases()
+ {
+ return Collections.unmodifiableMap(new TreeMap(aliasMap));
+ }
+
+
+ /**
+ * Register the standard aliases.
+ * Note: This method is not lock because only called by the constructor.
+ *
+ * @throws XMPException If the registrations of at least one alias fails.
+ */
+ private void registerStandardAliases() throws XMPException
+ {
+ AliasOptions aliasToArrayOrdered = new AliasOptions().setArrayOrdered(true);
+ AliasOptions aliasToArrayAltText = new AliasOptions().setArrayAltText(true);
+
+
+ // Aliases from XMP to DC.
+ registerAlias(NS_XMP, "Author", NS_DC, "creator", aliasToArrayOrdered);
+ registerAlias(NS_XMP, "Authors", NS_DC, "creator", null);
+ registerAlias(NS_XMP, "Description", NS_DC, "description", null);
+ registerAlias(NS_XMP, "Format", NS_DC, "format", null);
+ registerAlias(NS_XMP, "Keywords", NS_DC, "subject", null);
+ registerAlias(NS_XMP, "Locale", NS_DC, "language", null);
+ registerAlias(NS_XMP, "Title", NS_DC, "title", null);
+ registerAlias(NS_XMP_RIGHTS, "Copyright", NS_DC, "rights", null);
+
+ // Aliases from PDF to DC and XMP.
+ registerAlias(NS_PDF, "Author", NS_DC, "creator", aliasToArrayOrdered);
+ registerAlias(NS_PDF, "BaseURL", NS_XMP, "BaseURL", null);
+ registerAlias(NS_PDF, "CreationDate", NS_XMP, "CreateDate", null);
+ registerAlias(NS_PDF, "Creator", NS_XMP, "CreatorTool", null);
+ registerAlias(NS_PDF, "ModDate", NS_XMP, "ModifyDate", null);
+ registerAlias(NS_PDF, "Subject", NS_DC, "description", aliasToArrayAltText);
+ registerAlias(NS_PDF, "Title", NS_DC, "title", aliasToArrayAltText);
+
+ // Aliases from PHOTOSHOP to DC and XMP.
+ registerAlias(NS_PHOTOSHOP, "Author", NS_DC, "creator", aliasToArrayOrdered);
+ registerAlias(NS_PHOTOSHOP, "Caption", NS_DC, "description", aliasToArrayAltText);
+ registerAlias(NS_PHOTOSHOP, "Copyright", NS_DC, "rights", aliasToArrayAltText);
+ registerAlias(NS_PHOTOSHOP, "Keywords", NS_DC, "subject", null);
+ registerAlias(NS_PHOTOSHOP, "Marked", NS_XMP_RIGHTS, "Marked", null);
+ registerAlias(NS_PHOTOSHOP, "Title", NS_DC, "title", aliasToArrayAltText);
+ registerAlias(NS_PHOTOSHOP, "WebStatement", NS_XMP_RIGHTS, "WebStatement", null);
+
+ // Aliases from TIFF and EXIF to DC and XMP.
+ registerAlias(NS_TIFF, "Artist", NS_DC, "creator", aliasToArrayOrdered);
+ registerAlias(NS_TIFF, "Copyright", NS_DC, "rights", null);
+ registerAlias(NS_TIFF, "DateTime", NS_XMP, "ModifyDate", null);
+ registerAlias(NS_TIFF, "ImageDescription", NS_DC, "description", null);
+ registerAlias(NS_TIFF, "Software", NS_XMP, "CreatorTool", null);
+
+ // Aliases from PNG (Acrobat ImageCapture) to DC and XMP.
+ registerAlias(NS_PNG, "Author", NS_DC, "creator", aliasToArrayOrdered);
+ registerAlias(NS_PNG, "Copyright", NS_DC, "rights", aliasToArrayAltText);
+ registerAlias(NS_PNG, "CreationTime", NS_XMP, "CreateDate", null);
+ registerAlias(NS_PNG, "Description", NS_DC, "description", aliasToArrayAltText);
+ registerAlias(NS_PNG, "ModificationTime", NS_XMP, "ModifyDate", null);
+ registerAlias(NS_PNG, "Software", NS_XMP, "CreatorTool", null);
+ registerAlias(NS_PNG, "Title", NS_DC, "title", aliasToArrayAltText);
+ }
+} \ No newline at end of file
diff --git a/java/XMPCore/src/com/adobe/xmp/impl/XMPSerializerHelper.java b/java/XMPCore/src/com/adobe/xmp/impl/XMPSerializerHelper.java
new file mode 100644
index 0000000..9b6c7af
--- /dev/null
+++ b/java/XMPCore/src/com/adobe/xmp/impl/XMPSerializerHelper.java
@@ -0,0 +1,102 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+package com.adobe.xmp.impl;
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+
+import com.adobe.xmp.XMPException;
+import com.adobe.xmp.options.SerializeOptions;
+
+
+/**
+ * Serializes the <code>XMPMeta</code>-object to an <code>OutputStream</code> according to the
+ * <code>SerializeOptions</code>.
+ *
+ * @since 11.07.2006
+ */
+public class XMPSerializerHelper
+{
+ /**
+ * Static method to serialize the metadata object. For each serialisation, a new XMPSerializer
+ * instance is created, either XMPSerializerRDF or XMPSerializerPlain so thats its possible to
+ * serialialize the same XMPMeta objects in two threads.
+ *
+ * @param xmp a metadata implementation object
+ * @param out the output stream to serialize to
+ * @param options serialization options, can be <code>null</code> for default.
+ * @throws XMPException
+ */
+ public static void serialize(XMPMetaImpl xmp, OutputStream out,
+ SerializeOptions options)
+ throws XMPException
+ {
+ options = options != null ? options : new SerializeOptions();
+
+ // sort the internal data model on demand
+ if (options.getSort())
+ {
+ xmp.sort();
+ }
+ new XMPSerializerRDF().serialize(xmp, out, options);
+ }
+
+
+ /**
+ * Serializes an <code>XMPMeta</code>-object as RDF into a string.
+ * <em>Note:</em> Encoding is forced to UTF-16 when serializing to a
+ * string to ensure the correctness of &quot;exact packet size&quot;.
+ *
+ * @param xmp a metadata implementation object
+ * @param options Options to control the serialization (see
+ * {@link SerializeOptions}).
+ * @return Returns a string containing the serialized RDF.
+ * @throws XMPException on serializsation errors.
+ */
+ public static String serializeToString(XMPMetaImpl xmp, SerializeOptions options)
+ throws XMPException
+ {
+ // forces the encoding to be UTF-16 to get the correct string length
+ options = options != null ? options : new SerializeOptions();
+ options.setEncodeUTF16BE(true);
+
+ ByteArrayOutputStream out = new ByteArrayOutputStream(2048);
+ serialize(xmp, out, options);
+
+ try
+ {
+ return out.toString(options.getEncoding());
+ }
+ catch (UnsupportedEncodingException e)
+ {
+ // cannot happen as UTF-8/16LE/BE is required to be implemented in
+ // Java
+ return out.toString();
+ }
+ }
+
+
+ /**
+ * Serializes an <code>XMPMeta</code>-object as RDF into a byte buffer.
+ *
+ * @param xmp a metadata implementation object
+ * @param options Options to control the serialization (see {@link SerializeOptions}).
+ * @return Returns a byte buffer containing the serialized RDF.
+ * @throws XMPException on serializsation errors.
+ */
+ public static byte[] serializeToBuffer(XMPMetaImpl xmp, SerializeOptions options)
+ throws XMPException
+ {
+ ByteArrayOutputStream out = new ByteArrayOutputStream(2048);
+ serialize(xmp, out, options);
+ return out.toByteArray();
+ }
+} \ No newline at end of file
diff --git a/java/XMPCore/src/com/adobe/xmp/impl/XMPSerializerRDF.java b/java/XMPCore/src/com/adobe/xmp/impl/XMPSerializerRDF.java
new file mode 100644
index 0000000..24cafd3
--- /dev/null
+++ b/java/XMPCore/src/com/adobe/xmp/impl/XMPSerializerRDF.java
@@ -0,0 +1,1295 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+package com.adobe.xmp.impl;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import com.adobe.xmp.XMPConst;
+import com.adobe.xmp.XMPError;
+import com.adobe.xmp.XMPException;
+import com.adobe.xmp.XMPMeta;
+import com.adobe.xmp.XMPMetaFactory;
+import com.adobe.xmp.options.SerializeOptions;
+
+
+/**
+ * Serializes the <code>XMPMeta</code>-object using the standard RDF serialization format.
+ * The output is written to an <code>OutputStream</code>
+ * according to the <code>SerializeOptions</code>.
+ *
+ * @since 11.07.2006
+ */
+public class XMPSerializerRDF
+{
+ /** default padding */
+ private static final int DEFAULT_PAD = 2048;
+ /** */
+ private static final String PACKET_HEADER =
+ "<?xpacket begin=\"\uFEFF\" id=\"W5M0MpCehiHzreSzNTczkc9d\"?>";
+ /** The w/r is missing inbetween */
+ private static final String PACKET_TRAILER = "<?xpacket end=\"";
+ /** */
+ private static final String PACKET_TRAILER2 = "\"?>";
+ /** */
+ private static final String RDF_XMPMETA_START =
+ "<x:xmpmeta xmlns:x=\"adobe:ns:meta/\" x:xmptk=\"";
+ /** */
+ private static final String RDF_XMPMETA_END = "</x:xmpmeta>";
+ /** */
+ private static final String RDF_RDF_START =
+ "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">";
+ /** */
+ private static final String RDF_RDF_END = "</rdf:RDF>";
+
+ /** */
+ private static final String RDF_SCHEMA_START = "<rdf:Description rdf:about=";
+ /** */
+ private static final String RDF_SCHEMA_END = "</rdf:Description>";
+ /** */
+ private static final String RDF_STRUCT_START = "<rdf:Description";
+ /** */
+ private static final String RDF_STRUCT_END = "</rdf:Description>";
+ /** a set of all rdf attribute qualifier */
+ static final Set RDF_ATTR_QUALIFIER = new HashSet(Arrays.asList(new String[] {
+ XMPConst.XML_LANG, "rdf:resource", "rdf:ID", "rdf:bagID", "rdf:nodeID" }));
+
+ /** the metadata object to be serialized. */
+ private XMPMetaImpl xmp;
+ /** the output stream to serialize to */
+ private CountOutputStream outputStream;
+ /** this writer is used to do the actual serialisation */
+ private OutputStreamWriter writer;
+ /** the stored serialisation options */
+ private SerializeOptions options;
+ /** the size of one unicode char, for UTF-8 set to 1
+ * (Note: only valid for ASCII chars lower than 0x80),
+ * set to 2 in case of UTF-16 */
+ private int unicodeSize = 1; // UTF-8
+ /** the padding in the XMP Packet, or the length of the complete packet in
+ * case of option <em>exactPacketLength</em>. */
+ private int padding;
+
+
+ /**
+ * The actual serialisation.
+ *
+ * @param xmp the metadata object to be serialized
+ * @param out outputStream the output stream to serialize to
+ * @param options the serialization options
+ *
+ * @throws XMPException If case of wrong options or any other serialisaton error.
+ */
+ public void serialize(XMPMeta xmp, OutputStream out,
+ SerializeOptions options) throws XMPException
+ {
+ try
+ {
+ outputStream = new CountOutputStream(out);
+ writer = new OutputStreamWriter(outputStream, options.getEncoding());
+
+ this.xmp = (XMPMetaImpl) xmp;
+ this.options = options;
+ this.padding = options.getPadding();
+
+ writer = new OutputStreamWriter(outputStream, options.getEncoding());
+
+ checkOptionsConsistence();
+
+ // serializes the whole packet, but don't write the tail yet
+ // and flush to make sure that the written bytes are calculated correctly
+ String tailStr = serializeAsRDF();
+ writer.flush();
+
+ // adds padding
+ addPadding(tailStr.length());
+
+ // writes the tail
+ write(tailStr);
+ writer.flush();
+
+ outputStream.close();
+ }
+ catch (IOException e)
+ {
+ throw new XMPException("Error writing to the OutputStream", XMPError.UNKNOWN);
+ }
+ }
+
+
+ /**
+ * Calulates the padding according to the options and write it to the stream.
+ * @param tailLength the length of the tail string
+ * @throws XMPException thrown if packet size is to small to fit the padding
+ * @throws IOException forwards writer errors
+ */
+ private void addPadding(int tailLength) throws XMPException, IOException
+ {
+ if (options.getExactPacketLength())
+ {
+ // the string length is equal to the length of the UTF-8 encoding
+ int minSize = outputStream.getBytesWritten() + tailLength * unicodeSize;
+ if (minSize > padding)
+ {
+ throw new XMPException("Can't fit into specified packet size",
+ XMPError.BADSERIALIZE);
+ }
+ padding -= minSize; // Now the actual amount of padding to add.
+ }
+
+ // fix rest of the padding according to Unicode unit size.
+ padding /= unicodeSize;
+
+ int newlineLen = options.getNewline().length();
+ if (padding >= newlineLen)
+ {
+ padding -= newlineLen; // Write this newline last.
+ while (padding >= (100 + newlineLen))
+ {
+ writeChars(100, ' ');
+ writeNewline();
+ padding -= (100 + newlineLen);
+ }
+ writeChars(padding, ' ');
+ writeNewline();
+ }
+ else
+ {
+ writeChars(padding, ' ');
+ }
+ }
+
+
+ /**
+ * Checks if the supplied options are consistent.
+ * @throws XMPException Thrown if options are conflicting
+ */
+ protected void checkOptionsConsistence() throws XMPException
+ {
+ if (options.getEncodeUTF16BE() | options.getEncodeUTF16LE())
+ {
+ unicodeSize = 2;
+ }
+
+ if (options.getExactPacketLength())
+ {
+ if (options.getOmitPacketWrapper() | options.getIncludeThumbnailPad())
+ {
+ throw new XMPException("Inconsistent options for exact size serialize",
+ XMPError.BADOPTIONS);
+ }
+ if ((options.getPadding() & (unicodeSize - 1)) != 0)
+ {
+ throw new XMPException("Exact size must be a multiple of the Unicode element",
+ XMPError.BADOPTIONS);
+ }
+ }
+ else if (options.getReadOnlyPacket())
+ {
+ if (options.getOmitPacketWrapper() | options.getIncludeThumbnailPad())
+ {
+ throw new XMPException("Inconsistent options for read-only packet",
+ XMPError.BADOPTIONS);
+ }
+ padding = 0;
+ }
+ else if (options.getOmitPacketWrapper())
+ {
+ if (options.getIncludeThumbnailPad())
+ {
+ throw new XMPException("Inconsistent options for non-packet serialize",
+ XMPError.BADOPTIONS);
+ }
+ padding = 0;
+ }
+ else
+ {
+ if (padding == 0)
+ {
+ padding = DEFAULT_PAD * unicodeSize;
+ }
+
+ if (options.getIncludeThumbnailPad())
+ {
+ if (!xmp.doesPropertyExist(XMPConst.NS_XMP, "Thumbnails"))
+ {
+ padding += 10000 * unicodeSize;
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Writes the (optional) packet header and the outer rdf-tags.
+ * @return Returns the packet end processing instraction to be written after the padding.
+ * @throws IOException Forwarded writer exceptions.
+ * @throws XMPException
+ */
+ private String serializeAsRDF() throws IOException, XMPException
+ {
+ // Write the packet header PI.
+ if (!options.getOmitPacketWrapper())
+ {
+ writeIndent(0);
+ write(PACKET_HEADER);
+ writeNewline();
+ }
+
+ // Write the xmpmeta element's start tag.
+ writeIndent(0);
+ write(RDF_XMPMETA_START);
+ // Note: this flag can only be set by unit tests
+ if (!options.getOmitVersionAttribute())
+ {
+ write(XMPMetaFactory.getVersionInfo().getMessage());
+ }
+ write("\">");
+ writeNewline();
+
+ // Write the rdf:RDF start tag.
+ writeIndent(1);
+ write(RDF_RDF_START);
+ writeNewline();
+
+ // Write all of the properties.
+ if (options.getUseCompactFormat())
+ {
+ serializeCompactRDFSchemas();
+ }
+ else
+ {
+ serializePrettyRDFSchemas();
+ }
+
+ // Write the rdf:RDF end tag.
+ writeIndent(1);
+ write(RDF_RDF_END);
+ writeNewline();
+
+ // Write the xmpmeta end tag.
+ writeIndent(0);
+ write(RDF_XMPMETA_END);
+ writeNewline();
+
+ // Write the packet trailer PI into the tail string as UTF-8.
+ String tailStr = "";
+ if (!options.getOmitPacketWrapper())
+ {
+ for (int level = options.getBaseIndent(); level > 0; level--)
+ {
+ tailStr += options.getIndent();
+ }
+
+ tailStr += PACKET_TRAILER;
+ tailStr += options.getReadOnlyPacket() ? 'r' : 'w';
+ tailStr += PACKET_TRAILER2;
+ }
+
+ return tailStr;
+ }
+
+
+ /**
+ * Serializes the metadata in pretty-printed manner.
+ * @throws IOException Forwarded writer exceptions
+ * @throws XMPException
+ */
+ private void serializePrettyRDFSchemas() throws IOException, XMPException
+ {
+ if (xmp.getRoot().getChildrenLength() > 0)
+ {
+ for (Iterator it = xmp.getRoot().iterateChildren(); it.hasNext(); )
+ {
+ XMPNode currSchema = (XMPNode) it.next();
+ serializePrettyRDFSchema(currSchema);
+ }
+ }
+ else
+ {
+ writeIndent(2);
+ write(RDF_SCHEMA_START); // Special case an empty XMP object.
+ writeTreeName();
+ write("/>");
+ writeNewline();
+ }
+ }
+
+
+ /**
+ * @throws IOException
+ */
+ private void writeTreeName() throws IOException
+ {
+ write('"');
+ String name = xmp.getRoot().getName();
+ if (name != null)
+ {
+ appendNodeValue(name, true);
+ }
+ write('"');
+ }
+
+
+ /**
+ * Serializes the metadata in compact manner.
+ * @throws IOException Forwarded writer exceptions
+ * @throws XMPException
+ */
+ private void serializeCompactRDFSchemas() throws IOException, XMPException
+ {
+ // Begin the rdf:Description start tag.
+ writeIndent(2);
+ write(RDF_SCHEMA_START);
+ writeTreeName();
+
+ // Write all necessary xmlns attributes.
+ Set usedPrefixes = new HashSet();
+ usedPrefixes.add("xml");
+ usedPrefixes.add("rdf");
+
+ for (Iterator it = xmp.getRoot().iterateChildren(); it.hasNext();)
+ {
+ XMPNode schema = (XMPNode) it.next();
+ declareUsedNamespaces(schema, usedPrefixes, 4);
+ }
+
+ // Write the top level "attrProps" and close the rdf:Description start tag.
+ boolean allAreAttrs = true;
+ for (Iterator it = xmp.getRoot().iterateChildren(); it.hasNext();)
+ {
+ XMPNode schema = (XMPNode) it.next();
+ allAreAttrs &= serializeCompactRDFAttrProps (schema, 3);
+ }
+
+ if (!allAreAttrs)
+ {
+ write('>');
+ writeNewline();
+ }
+ else
+ {
+ write("/>");
+ writeNewline();
+ return; // ! Done if all properties in all schema are written as attributes.
+ }
+
+ // Write the remaining properties for each schema.
+ for (Iterator it = xmp.getRoot().iterateChildren(); it.hasNext();)
+ {
+ XMPNode schema = (XMPNode) it.next();
+ serializeCompactRDFElementProps (schema, 3);
+ }
+
+ // Write the rdf:Description end tag.
+ writeIndent(2);
+ write(RDF_SCHEMA_END);
+ writeNewline();
+ }
+
+
+
+ /**
+ * Write each of the parent's simple unqualified properties as an attribute. Returns true if all
+ * of the properties are written as attributes.
+ *
+ * @param parentNode the parent property node
+ * @param indent the current indent level
+ * @return Returns true if all properties can be rendered as RDF attribute.
+ * @throws IOException
+ */
+ private boolean serializeCompactRDFAttrProps(XMPNode parentNode, int indent) throws IOException
+ {
+ boolean allAreAttrs = true;
+
+ for (Iterator it = parentNode.iterateChildren(); it.hasNext();)
+ {
+ XMPNode prop = (XMPNode) it.next();
+
+ if (canBeRDFAttrProp(prop))
+ {
+ writeNewline();
+ writeIndent(indent);
+ write(prop.getName());
+ write("=\"");
+ appendNodeValue(prop.getValue(), true);
+ write('"');
+ }
+ else
+ {
+ allAreAttrs = false;
+ }
+ }
+ return allAreAttrs;
+ }
+
+
+ /**
+ * Recursively handles the "value" for a node that must be written as an RDF
+ * property element. It does not matter if it is a top level property, a
+ * field of a struct, or an item of an array. The indent is that for the
+ * property element. The patterns bwlow ignore attribute qualifiers such as
+ * xml:lang, they don't affect the output form.
+ *
+ * <blockquote>
+ *
+ * <pre>
+ * &lt;ns:UnqualifiedStructProperty-1
+ * ... The fields as attributes, if all are simple and unqualified
+ * /&gt;
+ *
+ * &lt;ns:UnqualifiedStructProperty-2 rdf:parseType=&quot;Resource&quot;&gt;
+ * ... The fields as elements, if none are simple and unqualified
+ * &lt;/ns:UnqualifiedStructProperty-2&gt;
+ *
+ * &lt;ns:UnqualifiedStructProperty-3&gt;
+ * &lt;rdf:Description
+ * ... The simple and unqualified fields as attributes
+ * &gt;
+ * ... The compound or qualified fields as elements
+ * &lt;/rdf:Description&gt;
+ * &lt;/ns:UnqualifiedStructProperty-3&gt;
+ *
+ * &lt;ns:UnqualifiedArrayProperty&gt;
+ * &lt;rdf:Bag&gt; or Seq or Alt
+ * ... Array items as rdf:li elements, same forms as top level properties
+ * &lt;/rdf:Bag&gt;
+ * &lt;/ns:UnqualifiedArrayProperty&gt;
+ *
+ * &lt;ns:QualifiedProperty rdf:parseType=&quot;Resource&quot;&gt;
+ * &lt;rdf:value&gt; ... Property &quot;value&quot;
+ * following the unqualified forms ... &lt;/rdf:value&gt;
+ * ... Qualifiers looking like named struct fields
+ * &lt;/ns:QualifiedProperty&gt;
+ * </pre>
+ *
+ * </blockquote>
+ *
+ * *** Consider numbered array items, but has compatibility problems. ***
+ * Consider qualified form with rdf:Description and attributes.
+ *
+ * @param parentNode the parent node
+ * @param indent the current indent level
+ * @throws IOException Forwards writer exceptions
+ * @throws XMPException If qualifier and element fields are mixed.
+ */
+ private void serializeCompactRDFElementProps(XMPNode parentNode, int indent)
+ throws IOException, XMPException
+ {
+ for (Iterator it = parentNode.iterateChildren(); it.hasNext();)
+ {
+ XMPNode node = (XMPNode) it.next();
+ if (canBeRDFAttrProp (node))
+ {
+ continue;
+ }
+
+ boolean emitEndTag = true;
+ boolean indentEndTag = true;
+
+ // Determine the XML element name, write the name part of the start tag. Look over the
+ // qualifiers to decide on "normal" versus "rdf:value" form. Emit the attribute
+ // qualifiers at the same time.
+ String elemName = node.getName();
+ if (XMPConst.ARRAY_ITEM_NAME.equals(elemName))
+ {
+ elemName = "rdf:li";
+ }
+
+ writeIndent(indent);
+ write('<');
+ write(elemName);
+
+ boolean isCompact = node.getOptions().isCompact();
+ boolean hasGeneralQualifiers = isCompact; // Might also become true later.
+ boolean hasRDFResourceQual = false;
+
+ for (Iterator iq = node.iterateQualifier(); iq.hasNext();)
+ {
+ XMPNode qualifier = (XMPNode) iq.next();
+ if (!RDF_ATTR_QUALIFIER.contains(qualifier.getName()))
+ {
+ hasGeneralQualifiers = true;
+ }
+ else
+ {
+ hasRDFResourceQual = "rdf:resource".equals(qualifier.getName());
+ write(' ');
+ write(qualifier.getName());
+ write("=\"");
+ appendNodeValue(qualifier.getValue(), true);
+ write('"');
+ }
+ }
+
+
+ // Process the property according to the standard patterns.
+ if (hasGeneralQualifiers)
+ {
+ serializeCompactRDFGeneralQualifier(indent, node, isCompact);
+ }
+ else
+ {
+ // This node has only attribute qualifiers. Emit as a property element.
+ if (!node.getOptions().isCompositeProperty())
+ {
+ Object[] result = serializeCompactRDFSimpleProp(node);
+ emitEndTag = ((Boolean) result[0]).booleanValue();
+ indentEndTag = ((Boolean) result[1]).booleanValue();
+ }
+ else if (node.getOptions().isArray())
+ {
+ serializeCompactRDFArrayProp(node, indent);
+ }
+ else
+ {
+ emitEndTag = serializeCompactRDFStructProp(
+ node, indent, hasRDFResourceQual);
+ }
+
+ }
+
+ // Emit the property element end tag.
+ if (emitEndTag)
+ {
+ if (indentEndTag)
+ {
+ writeIndent(indent);
+ }
+ write("</");
+ write(elemName);
+ write('>');
+ writeNewline();
+ }
+
+ }
+ }
+
+
+ /**
+ * Serializes a simple property.
+ *
+ * @param node an XMPNode
+ * @return Returns an array containing the flags emitEndTag and indentEndTag.
+ * @throws IOException Forwards the writer exceptions.
+ */
+ private Object[] serializeCompactRDFSimpleProp(XMPNode node) throws IOException
+ {
+ // This is a simple property.
+ Boolean emitEndTag = Boolean.TRUE;
+ Boolean indentEndTag = Boolean.TRUE;
+
+ if (node.getOptions().isURI())
+ {
+ write(" rdf:resource=\"");
+ appendNodeValue(node.getValue(), true);
+ write("\"/>");
+ writeNewline();
+ emitEndTag = Boolean.FALSE;
+ }
+ else if (node.getValue() == null || node.getValue().length() == 0)
+ {
+ write("/>");
+ writeNewline();
+ emitEndTag = Boolean.FALSE;
+ }
+ else
+ {
+ write('>');
+ appendNodeValue (node.getValue(), false);
+ indentEndTag = Boolean.FALSE;
+ }
+
+ return new Object[] {emitEndTag, indentEndTag};
+ }
+
+
+ /**
+ * Serializes an array property.
+ *
+ * @param node an XMPNode
+ * @param indent the current indent level
+ * @throws IOException Forwards the writer exceptions.
+ * @throws XMPException If qualifier and element fields are mixed.
+ */
+ private void serializeCompactRDFArrayProp(XMPNode node, int indent) throws IOException,
+ XMPException
+ {
+ // This is an array.
+ write('>');
+ writeNewline();
+ emitRDFArrayTag (node, true, indent + 1);
+
+ if (node.getOptions().isArrayAltText())
+ {
+ XMPNodeUtils.normalizeLangArray (node);
+ }
+
+ serializeCompactRDFElementProps(node, indent + 2);
+
+ emitRDFArrayTag(node, false, indent + 1);
+ }
+
+
+ /**
+ * Serializes a struct property.
+ *
+ * @param node an XMPNode
+ * @param indent the current indent level
+ * @param hasRDFResourceQual Flag if the element has resource qualifier
+ * @return Returns true if an end flag shall be emitted.
+ * @throws IOException Forwards the writer exceptions.
+ * @throws XMPException If qualifier and element fields are mixed.
+ */
+ private boolean serializeCompactRDFStructProp(XMPNode node, int indent,
+ boolean hasRDFResourceQual) throws XMPException, IOException
+ {
+ // This must be a struct.
+ boolean hasAttrFields = false;
+ boolean hasElemFields = false;
+ boolean emitEndTag = true;
+
+ for (Iterator ic = node.iterateChildren(); ic.hasNext(); )
+ {
+ XMPNode field = (XMPNode) ic.next();
+ if (canBeRDFAttrProp(field))
+ {
+ hasAttrFields = true;
+ }
+ else
+ {
+ hasElemFields = true;
+ }
+
+ if (hasAttrFields && hasElemFields)
+ {
+ break; // No sense looking further.
+ }
+ }
+
+ if (hasRDFResourceQual && hasElemFields)
+ {
+ throw new XMPException(
+ "Can't mix rdf:resource qualifier and element fields",
+ XMPError.BADRDF);
+ }
+
+ if (!node.hasChildren())
+ {
+ // Catch an empty struct as a special case. The case
+ // below would emit an empty
+ // XML element, which gets reparsed as a simple property
+ // with an empty value.
+ write(" rdf:parseType=\"Resource\"/>");
+ writeNewline();
+ emitEndTag = false;
+
+ }
+ else if (!hasElemFields)
+ {
+ // All fields can be attributes, use the
+ // emptyPropertyElt form.
+ serializeCompactRDFAttrProps(node, indent + 1);
+ write("/>");
+ writeNewline();
+ emitEndTag = false;
+
+ }
+ else if (!hasAttrFields)
+ {
+ // All fields must be elements, use the
+ // parseTypeResourcePropertyElt form.
+ write(" rdf:parseType=\"Resource\">");
+ writeNewline();
+ serializeCompactRDFElementProps(node, indent + 1);
+
+ }
+ else
+ {
+ // Have a mix of attributes and elements, use an inner rdf:Description.
+ write('>');
+ writeNewline();
+ writeIndent(indent + 1);
+ write(RDF_STRUCT_START);
+ serializeCompactRDFAttrProps(node, indent + 2);
+ write(">");
+ writeNewline();
+ serializeCompactRDFElementProps(node, indent + 1);
+ writeIndent(indent + 1);
+ write(RDF_STRUCT_END);
+ writeNewline();
+ }
+ return emitEndTag;
+ }
+
+
+ /**
+ * Serializes the general qualifier.
+ * @param node the root node of the subtree
+ * @param indent the current indent level
+ * @param isCompact flag if qual shall be renderen in compact form.
+ * @throws IOException Forwards all writer exceptions.
+ * @throws XMPException If qualifier and element fields are mixed.
+ */
+ private void serializeCompactRDFGeneralQualifier(int indent, XMPNode node, boolean isCompact)
+ throws IOException, XMPException
+ {
+ // The node has general qualifiers, ones that can't be
+ // attributes on a property element.
+ // Emit using the qualified property pseudo-struct form. The
+ // value is output by a call
+ // to SerializePrettyRDFProperty with emitAsRDFValue set.
+ write(" rdf:parseType=\"Resource\">");
+ writeNewline();
+
+ serializePrettyRDFProperty(node, true, indent + 1);
+
+ if (isCompact)
+ {
+ // Emit a "pxmp:compact" fake qualifier.
+ writeIndent(1);
+ write("<pxmp:compact/>");
+ writeNewline();
+ }
+
+ for (Iterator iq = node.iterateQualifier(); iq.hasNext();)
+ {
+ XMPNode qualifier = (XMPNode) iq.next();
+ serializePrettyRDFProperty(qualifier, false, indent + 1);
+ }
+ }
+
+
+ /**
+ * Serializes one schema with all contained properties in pretty-printed
+ * manner.<br>
+ * Each schema's properties are written in a separate
+ * rdf:Description element. All of the necessary namespaces are declared in
+ * the rdf:Description element. The baseIndent is the base level for the
+ * entire serialization, that of the x:xmpmeta element. An xml:lang
+ * qualifier is written as an attribute of the property start tag, not by
+ * itself forcing the qualified property form.
+ *
+ * <blockquote>
+ *
+ * <pre>
+ * &lt;rdf:Description rdf:about=&quot;TreeName&quot; xmlns:ns=&quot;URI&quot; ... &gt;
+ *
+ * ... The actual properties of the schema, see SerializePrettyRDFProperty
+ *
+ * &lt;!-- ns1:Alias is aliased to ns2:Actual --&gt; ... If alias comments are wanted
+ *
+ * &lt;/rdf:Description&gt;
+ * </pre>
+ *
+ * </blockquote>
+ *
+ * @param schemaNode a schema node
+ * @throws IOException Forwarded writer exceptions
+ * @throws XMPException
+ */
+ private void serializePrettyRDFSchema(XMPNode schemaNode) throws IOException, XMPException
+ {
+ writeIndent(2);
+ write(RDF_SCHEMA_START);
+ writeTreeName();
+
+ Set usedPrefixes = new HashSet();
+ usedPrefixes.add("xml");
+ usedPrefixes.add("rdf");
+
+ declareUsedNamespaces(schemaNode, usedPrefixes, 4);
+
+ write('>');
+ writeNewline();
+
+ // Write each of the schema's actual properties.
+ for (Iterator it = schemaNode.iterateChildren(); it.hasNext();)
+ {
+ XMPNode propNode = (XMPNode) it.next();
+ serializePrettyRDFProperty(propNode, false, 3);
+ }
+
+ // Write the rdf:Description end tag.
+ writeIndent(2);
+ write(RDF_SCHEMA_END);
+ writeNewline();
+ }
+
+
+ /**
+ * Writes all used namespaces of the subtree in node to the output.
+ * The subtree is recursivly traversed.
+ * @param node the root node of the subtree
+ * @param usedPrefixes a set containing currently used prefixes
+ * @param indent the current indent level
+ * @throws IOException Forwards all writer exceptions.
+ */
+ private void declareUsedNamespaces(XMPNode node, Set usedPrefixes, int indent)
+ throws IOException
+ {
+ if (node.getOptions().isSchemaNode())
+ {
+ // The schema node name is the URI, the value is the prefix.
+ String prefix = node.getValue().substring(0, node.getValue().length() - 1);
+ declareNamespace(prefix, node.getName(), usedPrefixes, indent);
+ }
+ else if (node.getOptions().isStruct())
+ {
+ for (Iterator it = node.iterateChildren(); it.hasNext();)
+ {
+ XMPNode field = (XMPNode) it.next();
+ declareNamespace(field.getName(), null, usedPrefixes, indent);
+ }
+ }
+
+ for (Iterator it = node.iterateChildren(); it.hasNext();)
+ {
+ XMPNode child = (XMPNode) it.next();
+ declareUsedNamespaces(child, usedPrefixes, indent);
+ }
+
+ for (Iterator it = node.iterateQualifier(); it.hasNext();)
+ {
+ XMPNode qualifier = (XMPNode) it.next();
+ declareNamespace(qualifier.getName(), null, usedPrefixes, indent);
+ declareUsedNamespaces(qualifier, usedPrefixes, indent);
+ }
+ }
+
+
+ /**
+ * Writes one namespace declaration to the output.
+ * @param prefix a namespace prefix (without colon) or a complete qname (when namespace == null)
+ * @param namespace the a namespace
+ * @param usedPrefixes a set containing currently used prefixes
+ * @param indent the current indent level
+ * @throws IOException Forwards all writer exceptions.
+ */
+ private void declareNamespace(String prefix, String namespace, Set usedPrefixes, int indent)
+ throws IOException
+ {
+ if (namespace == null)
+ {
+ // prefix contains qname, extract prefix and lookup namespace with prefix
+ QName qname = new QName(prefix);
+ if (qname.hasPrefix())
+ {
+ prefix = qname.getPrefix();
+ // add colon for lookup
+ namespace = XMPMetaFactory.getSchemaRegistry().getNamespaceURI(prefix + ":");
+ // prefix w/o colon
+ declareNamespace(prefix, namespace, usedPrefixes, indent);
+ }
+ else
+ {
+ return;
+ }
+ }
+
+ if (!usedPrefixes.contains(prefix))
+ {
+ writeNewline();
+ writeIndent(indent);
+ write("xmlns:");
+ write(prefix);
+ write("=\"");
+ write(namespace);
+ write('"');
+ usedPrefixes.add(prefix);
+ }
+ }
+
+
+ /**
+ * Recursively handles the "value" for a node. It does not matter if it is a
+ * top level property, a field of a struct, or an item of an array. The
+ * indent is that for the property element. An xml:lang qualifier is written
+ * as an attribute of the property start tag, not by itself forcing the
+ * qualified property form. The patterns below mostly ignore attribute
+ * qualifiers like xml:lang. Except for the one struct case, attribute
+ * qualifiers don't affect the output form.
+ *
+ * <blockquote>
+ *
+ * <pre>
+ * &lt;ns:UnqualifiedSimpleProperty&gt;value&lt;/ns:UnqualifiedSimpleProperty&gt;
+ *
+ * &lt;ns:UnqualifiedStructProperty rdf:parseType=&quot;Resource&quot;&gt;
+ * (If no rdf:resource qualifier)
+ * ... Fields, same forms as top level properties
+ * &lt;/ns:UnqualifiedStructProperty&gt;
+ *
+ * &lt;ns:ResourceStructProperty rdf:resource=&quot;URI&quot;
+ * ... Fields as attributes
+ * &gt;
+ *
+ * &lt;ns:UnqualifiedArrayProperty&gt;
+ * &lt;rdf:Bag&gt; or Seq or Alt
+ * ... Array items as rdf:li elements, same forms as top level properties
+ * &lt;/rdf:Bag&gt;
+ * &lt;/ns:UnqualifiedArrayProperty&gt;
+ *
+ * &lt;ns:QualifiedProperty rdf:parseType=&quot;Resource&quot;&gt;
+ * &lt;rdf:value&gt; ... Property &quot;value&quot; following the unqualified
+ * forms ... &lt;/rdf:value&gt;
+ * ... Qualifiers looking like named struct fields
+ * &lt;/ns:QualifiedProperty&gt;
+ * </pre>
+ *
+ * </blockquote>
+ *
+ * @param node the property node
+ * @param emitAsRDFValue property shall be renderes as attribute rather than tag
+ * @param indent the current indent level
+ * @throws IOException Forwards all writer exceptions.
+ * @throws XMPException If &quot;rdf:resource&quot; and general qualifiers are mixed.
+ */
+ private void serializePrettyRDFProperty(XMPNode node, boolean emitAsRDFValue, int indent)
+ throws IOException, XMPException
+ {
+ boolean emitEndTag = true;
+ boolean indentEndTag = true;
+
+ // Determine the XML element name. Open the start tag with the name and
+ // attribute qualifiers.
+
+ String elemName = node.getName();
+ if (emitAsRDFValue)
+ {
+ elemName = "rdf:value";
+ }
+ else if (XMPConst.ARRAY_ITEM_NAME.equals(elemName))
+ {
+ elemName = "rdf:li";
+ }
+
+ writeIndent(indent);
+ write('<');
+ write(elemName);
+
+ boolean isCompact = node.getOptions().isCompact();
+ boolean hasGeneralQualifiers = isCompact; // Might also become true later.
+ boolean hasRDFResourceQual = false;
+
+ for (Iterator it = node.iterateQualifier(); it.hasNext();)
+ {
+ XMPNode qualifier = (XMPNode) it.next();
+ if (!RDF_ATTR_QUALIFIER.contains(qualifier.getName()))
+ {
+ hasGeneralQualifiers = true;
+ }
+ else
+ {
+ hasRDFResourceQual = "rdf:resource".equals(qualifier.getName());
+ if (!emitAsRDFValue)
+ {
+ write(' ');
+ write(qualifier.getName());
+ write("=\"");
+ appendNodeValue(qualifier.getValue(), true);
+ write('"');
+ }
+ }
+ }
+
+ // Process the property according to the standard patterns.
+
+ if (hasGeneralQualifiers && !emitAsRDFValue)
+ {
+ // This node has general, non-attribute, qualifiers. Emit using the
+ // qualified property form.
+ // ! The value is output by a recursive call ON THE SAME NODE with
+ // emitAsRDFValue set.
+
+ if (hasRDFResourceQual)
+ {
+ throw new XMPException("Can't mix rdf:resource and general qualifiers",
+ XMPError.BADRDF);
+ }
+
+ write(" rdf:parseType=\"Resource\">");
+ writeNewline();
+
+ serializePrettyRDFProperty(node, true, indent + 1);
+
+ if (isCompact)
+ {
+ // Emit a "pxmp:compact" fake qualifier.
+ writeIndent(indent);
+ write("<pxmp:compact/>");
+ writeNewline();
+ }
+
+ for (Iterator it = node.iterateQualifier(); it.hasNext();)
+ {
+ XMPNode qualifier = (XMPNode) it.next();
+ if (!RDF_ATTR_QUALIFIER.contains(qualifier.getName()))
+ {
+ serializePrettyRDFProperty(qualifier, false, indent + 1);
+ }
+ }
+ }
+ else
+ {
+ // This node has no general qualifiers. Emit using an unqualified form.
+
+ if (!node.getOptions().isCompositeProperty())
+ {
+ // This is a simple property.
+
+ if (node.getOptions().isURI())
+ {
+ write(" rdf:resource=\"");
+ appendNodeValue(node.getValue(), true);
+ write("\"/>");
+ writeNewline();
+ emitEndTag = false;
+ }
+ else if (node.getValue() == null || "".equals(node.getValue()))
+ {
+ write("/>");
+ writeNewline();
+ emitEndTag = false;
+ }
+ else
+ {
+ write('>');
+ appendNodeValue(node.getValue(), false);
+ indentEndTag = false;
+ }
+ }
+ else if (node.getOptions().isArray())
+ {
+ // This is an array.
+ write('>');
+ writeNewline();
+ emitRDFArrayTag(node, true, indent + 1);
+ if (node.getOptions().isArrayAltText())
+ {
+ XMPNodeUtils.normalizeLangArray(node);
+ }
+ for (Iterator it = node.iterateChildren(); it.hasNext();)
+ {
+ XMPNode child = (XMPNode) it.next();
+ serializePrettyRDFProperty(child, false, indent + 2);
+ }
+ emitRDFArrayTag(node, false, indent + 1);
+
+
+ }
+ else if (!hasRDFResourceQual)
+ {
+ // This is a "normal" struct, use the rdf:parseType="Resource" form.
+ if (!node.hasChildren())
+ {
+ write(" rdf:parseType=\"Resource\"/>");
+ writeNewline();
+ emitEndTag = false;
+ }
+ else
+ {
+ write(" rdf:parseType=\"Resource\">");
+ writeNewline();
+ for (Iterator it = node.iterateChildren(); it.hasNext();)
+ {
+ XMPNode child = (XMPNode) it.next();
+ serializePrettyRDFProperty(child, false, indent + 1);
+ }
+ }
+ }
+ else
+ {
+ // This is a struct with an rdf:resource attribute, use the
+ // "empty property element" form.
+ for (Iterator it = node.iterateChildren(); it.hasNext();)
+ {
+ XMPNode child = (XMPNode) it.next();
+ if (!canBeRDFAttrProp(child))
+ {
+ throw new XMPException("Can't mix rdf:resource and complex fields",
+ XMPError.BADRDF);
+ }
+ writeNewline();
+ writeIndent(indent + 1);
+ write(' ');
+ write(child.getName());
+ write("=\"");
+ appendNodeValue(child.getValue(), true);
+ write('"');
+ }
+ write("/>");
+ writeNewline();
+ emitEndTag = false;
+ }
+ }
+
+ // Emit the property element end tag.
+ if (emitEndTag)
+ {
+ if (indentEndTag)
+ {
+ writeIndent(indent);
+ }
+ write("</");
+ write(elemName);
+ write('>');
+ writeNewline();
+ }
+ }
+
+
+ /**
+ * Writes the array start and end tags.
+ *
+ * @param arrayNode an array node
+ * @param isStartTag flag if its the start or end tag
+ * @param indent the current indent level
+ * @throws IOException forwards writer exceptions
+ */
+ private void emitRDFArrayTag(XMPNode arrayNode, boolean isStartTag, int indent)
+ throws IOException
+ {
+ if (isStartTag || arrayNode.hasChildren())
+ {
+ writeIndent(indent);
+ write(isStartTag ? "<rdf:" : "</rdf:");
+
+ if (arrayNode.getOptions().isArrayAlternate())
+ {
+ write("Alt");
+ }
+ else if (arrayNode.getOptions().isArrayOrdered())
+ {
+ write("Seq");
+ }
+ else
+ {
+ write("Bag");
+ }
+
+ if (isStartTag && !arrayNode.hasChildren())
+ {
+ write("/>");
+ }
+ else
+ {
+ write(">");
+ }
+
+ writeNewline();
+ }
+ }
+
+
+ /**
+ * Serializes the node value in XML encoding. Its used for tag bodies and
+ * attributes. <em>Note:</em> The attribute is always limited by quotes,
+ * thats why <code>&amp;apos;</code> is never serialized. <em>Note:</em>
+ * Control chars are written unescaped, but if the user uses others than tab, LF
+ * and CR the resulting XML will become invalid.
+ *
+ * @param value the value of the node
+ * @param forAttribute flag if value is an attribute value
+ * @throws IOException
+ */
+ private void appendNodeValue(String value, boolean forAttribute) throws IOException
+ {
+ write (Utils.escapeXML(value, forAttribute, true));
+ }
+
+
+ /**
+ * A node can be serialized as RDF-Attribute, if it meets the following conditions:
+ * <ul>
+ * <li>is not array item
+ * <li>don't has qualifier
+ * <li>is no URI
+ * <li>is no composite property
+ * </ul>
+ *
+ * @param node an XMPNode
+ * @return Returns true if the node serialized as RDF-Attribute
+ */
+ private boolean canBeRDFAttrProp(XMPNode node)
+ {
+ return
+ !node.hasQualifier() &&
+ !node.getOptions().isURI() &&
+ !node.getOptions().isCompositeProperty() &&
+ !XMPConst.ARRAY_ITEM_NAME.equals(node.getName());
+ }
+
+
+ /**
+ * Writes indents and automatically includes the baseindend from the options.
+ * @param times number of indents to write
+ * @throws IOException forwards exception
+ */
+ private void writeIndent(int times) throws IOException
+ {
+ for (int i = options.getBaseIndent() + times; i > 0; i--)
+ {
+ writer.write(options.getIndent());
+ }
+ }
+
+
+ /**
+ * Writes a char to the output.
+ * @param c a char
+ * @throws IOException forwards writer exceptions
+ */
+ private void write(int c) throws IOException
+ {
+ writer.write(c);
+ }
+
+
+ /**
+ * Writes a String to the output.
+ * @param str a String
+ * @throws IOException forwards writer exceptions
+ */
+ private void write(String str) throws IOException
+ {
+ writer.write(str);
+ }
+
+
+ /**
+ * Writes an amount of chars, mostly spaces
+ * @param number number of chars
+ * @param c a char
+ * @throws IOException
+ */
+ private void writeChars(int number, char c) throws IOException
+ {
+ for (; number > 0; number--)
+ {
+ writer.write(c);
+ }
+ }
+
+
+ /**
+ * Writes a newline according to the options.
+ * @throws IOException Forwards exception
+ */
+ private void writeNewline() throws IOException
+ {
+ writer.write(options.getNewline());
+ }
+} \ No newline at end of file
diff --git a/java/XMPCore/src/com/adobe/xmp/impl/XMPUtilsImpl.java b/java/XMPCore/src/com/adobe/xmp/impl/XMPUtilsImpl.java
new file mode 100644
index 0000000..4af9564
--- /dev/null
+++ b/java/XMPCore/src/com/adobe/xmp/impl/XMPUtilsImpl.java
@@ -0,0 +1,1167 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+
+
+package com.adobe.xmp.impl;
+
+import java.util.Iterator;
+
+import com.adobe.xmp.XMPConst;
+import com.adobe.xmp.XMPError;
+import com.adobe.xmp.XMPException;
+import com.adobe.xmp.XMPMeta;
+import com.adobe.xmp.XMPMetaFactory;
+import com.adobe.xmp.XMPUtils;
+import com.adobe.xmp.impl.xpath.XMPPath;
+import com.adobe.xmp.impl.xpath.XMPPathParser;
+import com.adobe.xmp.options.PropertyOptions;
+import com.adobe.xmp.properties.XMPAliasInfo;
+
+
+
+/**
+ * @since 11.08.2006
+ */
+public class XMPUtilsImpl implements XMPConst
+{
+ /** */
+ private static final int UCK_NORMAL = 0;
+ /** */
+ private static final int UCK_SPACE = 1;
+ /** */
+ private static final int UCK_COMMA = 2;
+ /** */
+ private static final int UCK_SEMICOLON = 3;
+ /** */
+ private static final int UCK_QUOTE = 4;
+ /** */
+ private static final int UCK_CONTROL = 5;
+
+
+ /**
+ * Private constructor, as
+ */
+ private XMPUtilsImpl()
+ {
+ // EMPTY
+ }
+
+
+ /**
+ * @see XMPUtils#catenateArrayItems(XMPMeta, String, String, String, String,
+ * boolean)
+ *
+ * @param xmp
+ * The XMP object containing the array to be catenated.
+ * @param schemaNS
+ * The schema namespace URI for the array. Must not be null or
+ * the empty string.
+ * @param arrayName
+ * The name of the array. May be a general path expression, must
+ * not be null or the empty string. Each item in the array must
+ * be a simple string value.
+ * @param separator
+ * The string to be used to separate the items in the catenated
+ * string. Defaults to &quot;; &quot;, ASCII semicolon and space
+ * (U+003B, U+0020).
+ * @param quotes
+ * The characters to be used as quotes around array items that
+ * contain a separator. Defaults to &apos;&quot;&apos;
+ * @param allowCommas
+ * Option flag to control the catenation.
+ * @return Returns the string containing the catenated array items.
+ * @throws XMPException
+ * Forwards the Exceptions from the metadata processing
+ */
+ public static String catenateArrayItems(XMPMeta xmp, String schemaNS, String arrayName,
+ String separator, String quotes, boolean allowCommas) throws XMPException
+ {
+ ParameterAsserts.assertSchemaNS(schemaNS);
+ ParameterAsserts.assertArrayName(arrayName);
+ ParameterAsserts.assertImplementation(xmp);
+ if (separator == null || separator.length() == 0)
+ {
+ separator = "; ";
+ }
+ if (quotes == null || quotes.length() == 0)
+ {
+ quotes = "\"";
+ }
+
+ XMPMetaImpl xmpImpl = (XMPMetaImpl) xmp;
+ XMPNode arrayNode = null;
+ XMPNode currItem = null;
+
+ // Return an empty result if the array does not exist,
+ // hurl if it isn't the right form.
+ XMPPath arrayPath = XMPPathParser.expandXPath(schemaNS, arrayName);
+ arrayNode = XMPNodeUtils.findNode(xmpImpl.getRoot(), arrayPath, false, null);
+ if (arrayNode == null)
+ {
+ return "";
+ }
+ else if (!arrayNode.getOptions().isArray() || arrayNode.getOptions().isArrayAlternate())
+ {
+ throw new XMPException("Named property must be non-alternate array", XMPError.BADPARAM);
+ }
+
+ // Make sure the separator is OK.
+ checkSeparator(separator);
+ // Make sure the open and close quotes are a legitimate pair.
+ char openQuote = quotes.charAt(0);
+ char closeQuote = checkQuotes(quotes, openQuote);
+
+ // Build the result, quoting the array items, adding separators.
+ // Hurl if any item isn't simple.
+
+ StringBuffer catinatedString = new StringBuffer();
+
+ for (Iterator it = arrayNode.iterateChildren(); it.hasNext();)
+ {
+ currItem = (XMPNode) it.next();
+ if (currItem.getOptions().isCompositeProperty())
+ {
+ throw new XMPException("Array items must be simple", XMPError.BADPARAM);
+ }
+ String str = applyQuotes(currItem.getValue(), openQuote, closeQuote, allowCommas);
+
+ catinatedString.append(str);
+ if (it.hasNext())
+ {
+ catinatedString.append(separator);
+ }
+ }
+
+ return catinatedString.toString();
+ }
+
+
+ /**
+ * see {@link XMPUtils#separateArrayItems(XMPMeta, String, String, String,
+ * PropertyOptions, boolean)}
+ *
+ * @param xmp
+ * The XMP object containing the array to be updated.
+ * @param schemaNS
+ * The schema namespace URI for the array. Must not be null or
+ * the empty string.
+ * @param arrayName
+ * The name of the array. May be a general path expression, must
+ * not be null or the empty string. Each item in the array must
+ * be a simple string value.
+ * @param catedStr
+ * The string to be separated into the array items.
+ * @param arrayOptions
+ * Option flags to control the separation.
+ * @param preserveCommas
+ * Flag if commas shall be preserved
+ *
+ * @throws XMPException
+ * Forwards the Exceptions from the metadata processing
+ */
+ public static void separateArrayItems(XMPMeta xmp, String schemaNS, String arrayName,
+ String catedStr, PropertyOptions arrayOptions, boolean preserveCommas)
+ throws XMPException
+ {
+ ParameterAsserts.assertSchemaNS(schemaNS);
+ ParameterAsserts.assertArrayName(arrayName);
+ ParameterAsserts.assertNotNull(catedStr);
+ ParameterAsserts.assertImplementation(xmp);
+ XMPMetaImpl xmpImpl = (XMPMetaImpl) xmp;
+
+ // Keep a zero value, has special meaning below.
+ XMPNode arrayNode = separateFindCreateArray(schemaNS, arrayName, arrayOptions, xmpImpl);
+
+ // Extract the item values one at a time, until the whole input string is done.
+ String itemValue;
+ int itemStart, itemEnd;
+ int nextKind = UCK_NORMAL, charKind = UCK_NORMAL;
+ char ch = 0, nextChar = 0;
+
+ itemEnd = 0;
+ int endPos = catedStr.length();
+ while (itemEnd < endPos)
+ {
+ // Skip any leading spaces and separation characters. Always skip commas here.
+ // They can be kept when within a value, but not when alone between values.
+ for (itemStart = itemEnd; itemStart < endPos; itemStart++)
+ {
+ ch = catedStr.charAt(itemStart);
+ charKind = classifyCharacter(ch);
+ if (charKind == UCK_NORMAL || charKind == UCK_QUOTE)
+ {
+ break;
+ }
+ }
+ if (itemStart >= endPos)
+ {
+ break;
+ }
+
+ if (charKind != UCK_QUOTE)
+ {
+ // This is not a quoted value. Scan for the end, create an array
+ // item from the substring.
+ for (itemEnd = itemStart; itemEnd < endPos; itemEnd++)
+ {
+ ch = catedStr.charAt(itemEnd);
+ charKind = classifyCharacter(ch);
+
+ if (charKind == UCK_NORMAL || charKind == UCK_QUOTE ||
+ (charKind == UCK_COMMA && preserveCommas))
+ {
+ continue;
+ }
+ else if (charKind != UCK_SPACE)
+ {
+ break;
+ }
+ else if ((itemEnd + 1) < endPos)
+ {
+ ch = catedStr.charAt(itemEnd + 1);
+ nextKind = classifyCharacter(ch);
+ if (nextKind == UCK_NORMAL || nextKind == UCK_QUOTE ||
+ (nextKind == UCK_COMMA && preserveCommas))
+ {
+ continue;
+ }
+ }
+
+ // Anything left?
+ break; // Have multiple spaces, or a space followed by a
+ // separator.
+ }
+ itemValue = catedStr.substring(itemStart, itemEnd);
+ }
+ else
+ {
+ // Accumulate quoted values into a local string, undoubling
+ // internal quotes that
+ // match the surrounding quotes. Do not undouble "unmatching"
+ // quotes.
+
+ char openQuote = ch;
+ char closeQuote = getClosingQuote(openQuote);
+
+ itemStart++; // Skip the opening quote;
+ itemValue = "";
+
+ for (itemEnd = itemStart; itemEnd < endPos; itemEnd++)
+ {
+ ch = catedStr.charAt(itemEnd);
+ charKind = classifyCharacter(ch);
+
+ if (charKind != UCK_QUOTE || !isSurroundingQuote(ch, openQuote, closeQuote))
+ {
+ // This is not a matching quote, just append it to the
+ // item value.
+ itemValue += ch;
+ }
+ else
+ {
+ // This is a "matching" quote. Is it doubled, or the
+ // final closing quote?
+ // Tolerate various edge cases like undoubled opening
+ // (non-closing) quotes,
+ // or end of input.
+
+ if ((itemEnd + 1) < endPos)
+ {
+ nextChar = catedStr.charAt(itemEnd + 1);
+ nextKind = classifyCharacter(nextChar);
+ }
+ else
+ {
+ nextKind = UCK_SEMICOLON;
+ nextChar = 0x3B;
+ }
+
+ if (ch == nextChar)
+ {
+ // This is doubled, copy it and skip the double.
+ itemValue += ch;
+ // Loop will add in charSize.
+ itemEnd++;
+ }
+ else if (!isClosingingQuote(ch, openQuote, closeQuote))
+ {
+ // This is an undoubled, non-closing quote, copy it.
+ itemValue += ch;
+ }
+ else
+ {
+ // This is an undoubled closing quote, skip it and
+ // exit the loop.
+ itemEnd++;
+ break;
+ }
+ }
+ }
+ }
+
+ // Add the separated item to the array.
+ // Keep a matching old value in case it had separators.
+ int foundIndex = -1;
+ for (int oldChild = 1; oldChild <= arrayNode.getChildrenLength(); oldChild++)
+ {
+ if (itemValue.equals(arrayNode.getChild(oldChild).getValue()))
+ {
+ foundIndex = oldChild;
+ break;
+ }
+ }
+
+ XMPNode newItem = null;
+ if (foundIndex < 0)
+ {
+ newItem = new XMPNode(ARRAY_ITEM_NAME, itemValue, null);
+ arrayNode.addChild(newItem);
+ }
+ }
+ }
+
+
+ /**
+ * Utility to find or create the array used by <code>separateArrayItems()</code>.
+ * @param schemaNS a the namespace fo the array
+ * @param arrayName the name of the array
+ * @param arrayOptions the options for the array if newly created
+ * @param xmp the xmp object
+ * @return Returns the array node.
+ * @throws XMPException Forwards exceptions
+ */
+ private static XMPNode separateFindCreateArray(String schemaNS, String arrayName,
+ PropertyOptions arrayOptions, XMPMetaImpl xmp) throws XMPException
+ {
+ arrayOptions = XMPNodeUtils.verifySetOptions(arrayOptions, null);
+ if (!arrayOptions.isOnlyArrayOptions())
+ {
+ throw new XMPException("Options can only provide array form", XMPError.BADOPTIONS);
+ }
+
+ // Find the array node, make sure it is OK. Move the current children
+ // aside, to be readded later if kept.
+ XMPPath arrayPath = XMPPathParser.expandXPath(schemaNS, arrayName);
+ XMPNode 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.
+ PropertyOptions arrayForm = arrayNode.getOptions();
+ if (!arrayForm.isArray() || arrayForm.isArrayAlternate())
+ {
+ throw new XMPException("Named property must be non-alternate array",
+ XMPError.BADXPATH);
+ }
+ if (arrayOptions.equalArrayTypes(arrayForm))
+ {
+ throw new XMPException("Mismatch of specified and existing array form",
+ XMPError.BADXPATH); // *** Right error?
+ }
+ }
+ else
+ {
+ // The array does not exist, try to create it.
+ // don't modify the options handed into the method
+ arrayNode = XMPNodeUtils.findNode(xmp.getRoot(), arrayPath, true, arrayOptions
+ .setArray(true));
+ if (arrayNode == null)
+ {
+ throw new XMPException("Failed to create named array", XMPError.BADXPATH);
+ }
+ }
+ return arrayNode;
+ }
+
+
+ /**
+ * @see XMPUtils#removeProperties(XMPMeta, String, String, boolean, boolean)
+ *
+ * @param xmp
+ * The XMP object containing the properties to be removed.
+ *
+ * @param schemaNS
+ * Optional schema namespace URI for the properties to be
+ * removed.
+ *
+ * @param propName
+ * Optional path expression for the property to be removed.
+ *
+ * @param doAllProperties
+ * Option flag to control the deletion: do internal properties in
+ * addition to external properties.
+ * @param includeAliases
+ * Option flag to control the deletion: Include aliases in the
+ * "named schema" case above.
+ * @throws XMPException If metadata processing fails
+ */
+ public static void removeProperties(XMPMeta xmp, String schemaNS, String propName,
+ boolean doAllProperties, boolean includeAliases) throws XMPException
+ {
+ ParameterAsserts.assertImplementation(xmp);
+ XMPMetaImpl xmpImpl = (XMPMetaImpl) xmp;
+
+ if (propName != null && propName.length() > 0)
+ {
+ // Remove just the one indicated property. This might be an alias,
+ // the named schema might not actually exist. So don't lookup the
+ // schema node.
+
+ if (schemaNS == null || schemaNS.length() == 0)
+ {
+ throw new XMPException("Property name requires schema namespace",
+ XMPError.BADPARAM);
+ }
+
+ XMPPath expPath = XMPPathParser.expandXPath(schemaNS, propName);
+
+ XMPNode propNode = XMPNodeUtils.findNode(xmpImpl.getRoot(), expPath, false, null);
+ if (propNode != null)
+ {
+ if (doAllProperties
+ || !Utils.isInternalProperty(expPath.getSegment(XMPPath.STEP_SCHEMA)
+ .getName(), expPath.getSegment(XMPPath.STEP_ROOT_PROP).getName()))
+ {
+ XMPNode parent = propNode.getParent();
+ parent.removeChild(propNode);
+ if (parent.getOptions().isSchemaNode() && !parent.hasChildren())
+ {
+ // remove empty schema node
+ parent.getParent().removeChild(parent);
+ }
+
+ }
+ }
+ }
+ else if (schemaNS != null && schemaNS.length() > 0)
+ {
+
+ // Remove all properties from the named schema. Optionally include
+ // aliases, in which case
+ // there might not be an actual schema node.
+
+ // XMP_NodePtrPos schemaPos;
+ XMPNode schemaNode = XMPNodeUtils.findSchemaNode(xmpImpl.getRoot(), schemaNS, false);
+ if (schemaNode != null)
+ {
+ if (removeSchemaChildren(schemaNode, doAllProperties))
+ {
+ xmpImpl.getRoot().removeChild(schemaNode);
+ }
+ }
+
+ if (includeAliases)
+ {
+ // We're removing the aliases also. Look them up by their
+ // namespace prefix.
+ // But that takes more code and the extra speed isn't worth it.
+ // Lookup the XMP node
+ // from the alias, to make sure the actual exists.
+
+ XMPAliasInfo[] aliases = XMPMetaFactory.getSchemaRegistry().findAliases(schemaNS);
+ for (int i = 0; i < aliases.length; i++)
+ {
+ XMPAliasInfo info = aliases[i];
+ XMPPath path = XMPPathParser.expandXPath(info.getNamespace(), info
+ .getPropName());
+ XMPNode actualProp = XMPNodeUtils
+ .findNode(xmpImpl.getRoot(), path, false, null);
+ if (actualProp != null)
+ {
+ XMPNode parent = actualProp.getParent();
+ parent.removeChild(actualProp);
+ }
+ }
+ }
+ }
+ else
+ {
+ // Remove all appropriate properties from all schema. In this case
+ // we don't have to be
+ // concerned with aliases, they are handled implicitly from the
+ // actual properties.
+ for (Iterator it = xmpImpl.getRoot().iterateChildren(); it.hasNext();)
+ {
+ XMPNode schema = (XMPNode) it.next();
+ if (removeSchemaChildren(schema, doAllProperties))
+ {
+ it.remove();
+ }
+ }
+ }
+ }
+
+
+ /**
+ * @see XMPUtils#appendProperties(XMPMeta, XMPMeta, boolean, boolean)
+ * @param source The source XMP object.
+ * @param destination The destination XMP object.
+ * @param doAllProperties Do internal properties in addition to external properties.
+ * @param replaceOldValues Replace the values of existing properties.
+ * @param deleteEmptyValues Delete destination values if source property is empty.
+ * @throws XMPException Forwards the Exceptions from the metadata processing
+ */
+ public static void appendProperties(XMPMeta source, XMPMeta destination,
+ boolean doAllProperties, boolean replaceOldValues, boolean deleteEmptyValues)
+ throws XMPException
+ {
+ ParameterAsserts.assertImplementation(source);
+ ParameterAsserts.assertImplementation(destination);
+
+ XMPMetaImpl src = (XMPMetaImpl) source;
+ XMPMetaImpl dest = (XMPMetaImpl) destination;
+
+ for (Iterator it = src.getRoot().iterateChildren(); it.hasNext();)
+ {
+ XMPNode sourceSchema = (XMPNode) it.next();
+
+ // Make sure we have a destination schema node
+ XMPNode destSchema = XMPNodeUtils.findSchemaNode(dest.getRoot(),
+ sourceSchema.getName(), false);
+ boolean createdSchema = false;
+ if (destSchema == null)
+ {
+ destSchema = new XMPNode(sourceSchema.getName(), sourceSchema.getValue(),
+ new PropertyOptions().setSchemaNode(true));
+ dest.getRoot().addChild(destSchema);
+ createdSchema = true;
+ }
+
+ // Process the source schema's children.
+ for (Iterator ic = sourceSchema.iterateChildren(); ic.hasNext();)
+ {
+ XMPNode sourceProp = (XMPNode) ic.next();
+ if (doAllProperties
+ || !Utils.isInternalProperty(sourceSchema.getName(), sourceProp.getName()))
+ {
+ appendSubtree(
+ dest, sourceProp, destSchema, replaceOldValues, deleteEmptyValues);
+ }
+ }
+
+ if (!destSchema.hasChildren() && (createdSchema || deleteEmptyValues))
+ {
+ // Don't create an empty schema / remove empty schema.
+ dest.getRoot().removeChild(destSchema);
+ }
+ }
+ }
+
+
+ /**
+ * Remove all schema children according to the flag
+ * <code>doAllProperties</code>. Empty schemas are automatically remove
+ * by <code>XMPNode</code>
+ *
+ * @param schemaNode
+ * a schema node
+ * @param doAllProperties
+ * flag if all properties or only externals shall be removed.
+ * @return Returns true if the schema is empty after the operation.
+ */
+ private static boolean removeSchemaChildren(XMPNode schemaNode, boolean doAllProperties)
+ {
+ for (Iterator it = schemaNode.iterateChildren(); it.hasNext();)
+ {
+ XMPNode currProp = (XMPNode) it.next();
+ if (doAllProperties
+ || !Utils.isInternalProperty(schemaNode.getName(), currProp.getName()))
+ {
+ it.remove();
+ }
+ }
+
+ return !schemaNode.hasChildren();
+ }
+
+
+ /**
+ * @see XMPUtilsImpl#appendProperties(XMPMeta, XMPMeta, boolean, boolean, boolean)
+ * @param destXMP The destination XMP object.
+ * @param sourceNode the source node
+ * @param destParent the parent of the destination node
+ * @param replaceOldValues Replace the values of existing properties.
+ * @param deleteEmptyValues flag if properties with empty values should be deleted
+ * in the destination object.
+ * @throws XMPException
+ */
+ private static void appendSubtree(XMPMetaImpl destXMP, XMPNode sourceNode, XMPNode destParent,
+ boolean replaceOldValues, boolean deleteEmptyValues) throws XMPException
+ {
+ XMPNode destNode = XMPNodeUtils.findChildNode(destParent, sourceNode.getName(), false);
+
+ boolean valueIsEmpty = false;
+ if (deleteEmptyValues)
+ {
+ valueIsEmpty = sourceNode.getOptions().isSimple() ?
+ sourceNode.getValue() == null || sourceNode.getValue().length() == 0 :
+ !sourceNode.hasChildren();
+ }
+
+ if (deleteEmptyValues && valueIsEmpty)
+ {
+ if (destNode != null)
+ {
+ destParent.removeChild(destNode);
+ }
+ }
+ else if (destNode == null)
+ {
+ // The one easy case, the destination does not exist.
+ destParent.addChild((XMPNode) sourceNode.clone());
+ }
+ else if (replaceOldValues)
+ {
+ // The destination exists and should be replaced.
+ destXMP.setNode(destNode, sourceNode.getValue(), sourceNode.getOptions(), true);
+ destParent.removeChild(destNode);
+ destNode = (XMPNode) sourceNode.clone();
+ destParent.addChild(destNode);
+ }
+ else
+ {
+ // The destination exists and is not totally replaced. Structs and
+ // arrays are merged.
+
+ PropertyOptions sourceForm = sourceNode.getOptions();
+ PropertyOptions destForm = destNode.getOptions();
+ if (sourceForm != destForm)
+ {
+ return;
+ }
+ if (sourceForm.isStruct())
+ {
+ // To merge a struct process the fields recursively. E.g. add simple missing fields.
+ // The recursive call to AppendSubtree will handle deletion for fields with empty
+ // values.
+ for (Iterator it = sourceNode.iterateChildren(); it.hasNext();)
+ {
+ XMPNode sourceField = (XMPNode) it.next();
+ appendSubtree(destXMP, sourceField, destNode,
+ replaceOldValues, deleteEmptyValues);
+ if (deleteEmptyValues && !destNode.hasChildren())
+ {
+ destParent.removeChild(destNode);
+ }
+ }
+ }
+ else if (sourceForm.isArrayAltText())
+ {
+ // Merge AltText arrays by the "xml:lang" qualifiers. Make sure x-default is first.
+ // Make a special check for deletion of empty values. Meaningful in AltText arrays
+ // because the "xml:lang" qualifier provides unambiguous source/dest correspondence.
+ for (Iterator it = sourceNode.iterateChildren(); it.hasNext();)
+ {
+ XMPNode sourceItem = (XMPNode) it.next();
+ if (!sourceItem.hasQualifier()
+ || !XMPConst.XML_LANG.equals(sourceItem.getQualifier(1).getName()))
+ {
+ continue;
+ }
+
+ int destIndex = XMPNodeUtils.lookupLanguageItem(destNode,
+ sourceItem.getQualifier(1).getValue());
+ if (deleteEmptyValues &&
+ (sourceItem.getValue() == null ||
+ sourceItem.getValue().length() == 0))
+ {
+ if (destIndex != -1)
+ {
+ destNode.removeChild(destIndex);
+ if (!destNode.hasChildren())
+ {
+ destParent.removeChild(destNode);
+ }
+ }
+ }
+ else if (destIndex == -1)
+ {
+ // Not replacing, keep the existing item.
+ if (!XMPConst.X_DEFAULT.equals(sourceItem.getQualifier(1).getValue())
+ || !destNode.hasChildren())
+ {
+ sourceItem.cloneSubtree(destNode);
+ }
+ else
+ {
+ XMPNode destItem = new XMPNode(
+ sourceItem.getName(),
+ sourceItem.getValue(),
+ sourceItem.getOptions());
+ sourceItem.cloneSubtree(destItem);
+ destNode.addChild(1, destItem);
+ }
+ }
+ }
+ }
+ else if (sourceForm.isArray())
+ {
+ // Merge other arrays by item values. Don't worry about order or duplicates. Source
+ // items with empty values do not cause deletion, that conflicts horribly with
+ // merging.
+
+ for (Iterator is = sourceNode.iterateChildren(); is.hasNext();)
+ {
+ XMPNode sourceItem = (XMPNode) is.next();
+
+ boolean match = false;
+ for (Iterator id = sourceNode.iterateChildren(); id.hasNext();)
+ {
+ XMPNode destItem = (XMPNode) id.next();
+ if (itemValuesMatch(sourceItem, destItem))
+ {
+ match = true;
+ }
+ }
+ if (!match)
+ {
+ destNode = (XMPNode) sourceItem.clone();
+ destParent.addChild(destNode);
+ }
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Compares two nodes including its children and qualifier.
+ * @param leftNode an <code>XMPNode</code>
+ * @param rightNode an <code>XMPNode</code>
+ * @return Returns true if the nodes are equal, false otherwise.
+ * @throws XMPException Forwards exceptions to the calling method.
+ */
+ private static boolean itemValuesMatch(XMPNode leftNode, XMPNode rightNode) throws XMPException
+ {
+ PropertyOptions leftForm = leftNode.getOptions();
+ PropertyOptions rightForm = rightNode.getOptions();
+
+ if (leftForm.equals(rightForm))
+ {
+ return false;
+ }
+
+ if (leftForm.getOptions() == 0)
+ {
+ // Simple nodes, check the values and xml:lang qualifiers.
+ if (!leftNode.getValue().equals(rightNode.getValue()))
+ {
+ return false;
+ }
+ if (leftNode.getOptions().getHasLanguage() != rightNode.getOptions().getHasLanguage())
+ {
+ return false;
+ }
+ if (leftNode.getOptions().getHasLanguage()
+ && !leftNode.getQualifier(1).getValue().equals(
+ rightNode.getQualifier(1).getValue()))
+ {
+ return false;
+ }
+ }
+ else if (leftForm.isStruct())
+ {
+ // Struct nodes, see if all fields match, ignoring order.
+
+ if (leftNode.getChildrenLength() != rightNode.getChildrenLength())
+ {
+ return false;
+ }
+
+ for (Iterator it = leftNode.iterateChildren(); it.hasNext();)
+ {
+ XMPNode leftField = (XMPNode) it.next();
+ XMPNode rightField = XMPNodeUtils.findChildNode(rightNode, leftField.getName(),
+ false);
+ if (rightField == null || !itemValuesMatch(leftField, rightField))
+ {
+ return false;
+ }
+ }
+ }
+ else
+ {
+ // Array nodes, see if the "leftNode" values are present in the
+ // "rightNode", ignoring order, duplicates,
+ // and extra values in the rightNode-> The rightNode is the
+ // destination for AppendProperties.
+
+ assert leftForm.isArray();
+
+ for (Iterator il = leftNode.iterateChildren(); il.hasNext();)
+ {
+ XMPNode leftItem = (XMPNode) il.next();
+
+ boolean match = false;
+ for (Iterator ir = leftNode.iterateChildren(); ir.hasNext();)
+ {
+ XMPNode rightItem = (XMPNode) ir.next();
+ if (itemValuesMatch(leftItem, rightItem))
+ {
+ match = true;
+ break;
+ }
+ }
+ if (!match)
+ {
+ return false;
+ }
+ }
+ }
+ return true; // All of the checks passed.
+ }
+
+
+ /**
+ * Make sure the separator is OK. It must be one semicolon surrounded by
+ * zero or more spaces. Any of the recognized semicolons or spaces are
+ * allowed.
+ *
+ * @param separator
+ * @throws XMPException
+ */
+ private static void checkSeparator(String separator) throws XMPException
+ {
+ boolean haveSemicolon = false;
+ for (int i = 0; i < separator.length(); i++)
+ {
+ int charKind = classifyCharacter(separator.charAt(i));
+ if (charKind == UCK_SEMICOLON)
+ {
+ if (haveSemicolon)
+ {
+ throw new XMPException("Separator can have only one semicolon",
+ XMPError.BADPARAM);
+ }
+ haveSemicolon = true;
+ }
+ else if (charKind != UCK_SPACE)
+ {
+ throw new XMPException("Separator can have only spaces and one semicolon",
+ XMPError.BADPARAM);
+ }
+ }
+ if (!haveSemicolon)
+ {
+ throw new XMPException("Separator must have one semicolon", XMPError.BADPARAM);
+ }
+ }
+
+
+ /**
+ * Make sure the open and close quotes are a legitimate pair and return the
+ * correct closing quote or an exception.
+ *
+ * @param quotes
+ * opened and closing quote in a string
+ * @param openQuote
+ * the open quote
+ * @return Returns a corresponding closing quote.
+ * @throws XMPException
+ */
+ private static char checkQuotes(String quotes, char openQuote) throws XMPException
+ {
+ char closeQuote;
+
+ int charKind = classifyCharacter(openQuote);
+ if (charKind != UCK_QUOTE)
+ {
+ throw new XMPException("Invalid quoting character", XMPError.BADPARAM);
+ }
+
+ if (quotes.length() == 1)
+ {
+ closeQuote = openQuote;
+ }
+ else
+ {
+ closeQuote = quotes.charAt(1);
+ charKind = classifyCharacter(closeQuote);
+ if (charKind != UCK_QUOTE)
+ {
+ throw new XMPException("Invalid quoting character", XMPError.BADPARAM);
+ }
+ }
+
+ if (closeQuote != getClosingQuote(openQuote))
+ {
+ throw new XMPException("Mismatched quote pair", XMPError.BADPARAM);
+ }
+ return closeQuote;
+ }
+
+
+ /**
+ * Classifies the character into normal chars, spaces, semicola, quotes,
+ * control chars.
+ *
+ * @param ch
+ * a char
+ * @return Return the character kind.
+ */
+ private static int classifyCharacter(char ch)
+ {
+ if (SPACES.indexOf(ch) >= 0 || (0x2000 <= ch && ch <= 0x200B))
+ {
+ return UCK_SPACE;
+ }
+ else if (COMMAS.indexOf(ch) >= 0)
+ {
+ return UCK_COMMA;
+ }
+ else if (SEMICOLA.indexOf(ch) >= 0)
+ {
+ return UCK_SEMICOLON;
+ }
+ else if (QUOTES.indexOf(ch) >= 0 || (0x3008 <= ch && ch <= 0x300F)
+ || (0x2018 <= ch && ch <= 0x201F))
+ {
+ return UCK_QUOTE;
+ }
+ else if (ch < 0x0020 || CONTROLS.indexOf(ch) >= 0)
+ {
+ return UCK_CONTROL;
+ }
+ else
+ {
+ // Assume typical case.
+ return UCK_NORMAL;
+ }
+ }
+
+
+ /**
+ * @param openQuote
+ * the open quote char
+ * @return Returns the matching closing quote for an open quote.
+ */
+ private static char getClosingQuote(char openQuote)
+ {
+ switch (openQuote)
+ {
+ case 0x0022:
+ return 0x0022; // ! U+0022 is both opening and closing.
+ case 0x005B:
+ return 0x005D;
+ case 0x00AB:
+ return 0x00BB; // ! U+00AB and U+00BB are reversible.
+ case 0x00BB:
+ return 0x00AB;
+ case 0x2015:
+ return 0x2015; // ! U+2015 is both opening and closing.
+ case 0x2018:
+ return 0x2019;
+ case 0x201A:
+ return 0x201B;
+ case 0x201C:
+ return 0x201D;
+ case 0x201E:
+ return 0x201F;
+ case 0x2039:
+ return 0x203A; // ! U+2039 and U+203A are reversible.
+ case 0x203A:
+ return 0x2039;
+ case 0x3008:
+ return 0x3009;
+ case 0x300A:
+ return 0x300B;
+ case 0x300C:
+ return 0x300D;
+ case 0x300E:
+ return 0x300F;
+ case 0x301D:
+ return 0x301F; // ! U+301E also closes U+301D.
+ default:
+ return 0;
+ }
+ }
+
+
+ /**
+ * Add quotes to the item.
+ *
+ * @param item
+ * the array item
+ * @param openQuote
+ * the open quote character
+ * @param closeQuote
+ * the closing quote character
+ * @param allowCommas
+ * flag if commas are allowed
+ * @return Returns the value in quotes.
+ */
+ private static String applyQuotes(String item, char openQuote, char closeQuote,
+ boolean allowCommas)
+ {
+ if (item == null)
+ {
+ item = "";
+ }
+
+ boolean prevSpace = false;
+ int charOffset;
+ int charKind;
+
+ // See if there are any separators in the value. Stop at the first
+ // occurrance. This is a bit
+ // tricky in order to make typical typing work conveniently. The purpose
+ // of applying quotes
+ // is to preserve the values when splitting them back apart. That is
+ // CatenateContainerItems
+ // and SeparateContainerItems must round trip properly. For the most
+ // part we only look for
+ // separators here. Internal quotes, as in -- Irving "Bud" Jones --
+ // won't cause problems in
+ // the separation. An initial quote will though, it will make the value
+ // look quoted.
+
+ int i;
+ for (i = 0; i < item.length(); i++)
+ {
+ char ch = item.charAt(i);
+ charKind = classifyCharacter(ch);
+ if (i == 0 && charKind == UCK_QUOTE)
+ {
+ break;
+ }
+
+ if (charKind == UCK_SPACE)
+ {
+ // Multiple spaces are a separator.
+ if (prevSpace)
+ {
+ break;
+ }
+ prevSpace = true;
+ }
+ else
+ {
+ prevSpace = false;
+ if ((charKind == UCK_SEMICOLON || charKind == UCK_CONTROL)
+ || (charKind == UCK_COMMA && !allowCommas))
+ {
+ break;
+ }
+ }
+ }
+
+
+ if (i < item.length())
+ {
+ // Create a quoted copy, doubling any internal quotes that match the
+ // outer ones. Internal quotes did not stop the "needs quoting"
+ // search, but they do need
+ // doubling. So we have to rescan the front of the string for
+ // quotes. Handle the special
+ // case of U+301D being closed by either U+301E or U+301F.
+
+ StringBuffer newItem = new StringBuffer(item.length() + 2);
+ int splitPoint;
+ for (splitPoint = 0; splitPoint <= i; splitPoint++)
+ {
+ if (classifyCharacter(item.charAt(i)) == UCK_QUOTE)
+ {
+ break;
+ }
+ }
+
+ // Copy the leading "normal" portion.
+ newItem.append(openQuote).append(item.substring(0, splitPoint));
+
+ for (charOffset = splitPoint; charOffset < item.length(); charOffset++)
+ {
+ newItem.append(item.charAt(charOffset));
+ if (classifyCharacter(item.charAt(charOffset)) == UCK_QUOTE
+ && isSurroundingQuote(item.charAt(charOffset), openQuote, closeQuote))
+ {
+ newItem.append(item.charAt(charOffset));
+ }
+ }
+
+ newItem.append(closeQuote);
+
+ item = newItem.toString();
+ }
+
+ return item;
+ }
+
+
+ /**
+ * @param ch a character
+ * @param openQuote the opening quote char
+ * @param closeQuote the closing quote char
+ * @return Return it the character is a surrounding quote.
+ */
+ private static boolean isSurroundingQuote(char ch, char openQuote, char closeQuote)
+ {
+ return ch == openQuote || isClosingingQuote(ch, openQuote, closeQuote);
+ }
+
+
+ /**
+ * @param ch a character
+ * @param openQuote the opening quote char
+ * @param closeQuote the closing quote char
+ * @return Returns true if the character is a closing quote.
+ */
+ private static boolean isClosingingQuote(char ch, char openQuote, char closeQuote)
+ {
+ return ch == closeQuote || (openQuote == 0x301D && ch == 0x301E || ch == 0x301F);
+ }
+
+
+
+ /**
+ * U+0022 ASCII space<br>
+ * U+3000, ideographic space<br>
+ * U+303F, ideographic half fill space<br>
+ * U+2000..U+200B, en quad through zero width space
+ */
+ private static final String SPACES = "\u0020\u3000\u303F";
+ /**
+ * U+002C, ASCII comma<br>
+ * U+FF0C, full width comma<br>
+ * U+FF64, half width ideographic comma<br>
+ * U+FE50, small comma<br>
+ * U+FE51, small ideographic comma<br>
+ * U+3001, ideographic comma<br>
+ * U+060C, Arabic comma<br>
+ * U+055D, Armenian comma
+ */
+ private static final String COMMAS = "\u002C\uFF0C\uFF64\uFE50\uFE51\u3001\u060C\u055D";
+ /**
+ * U+003B, ASCII semicolon<br>
+ * U+FF1B, full width semicolon<br>
+ * U+FE54, small semicolon<br>
+ * U+061B, Arabic semicolon<br>
+ * U+037E, Greek "semicolon" (really a question mark)
+ */
+ private static final String SEMICOLA = "\u003B\uFF1B\uFE54\u061B\u037E";
+ /**
+ * U+0022 ASCII quote<br>
+ * ASCII '[' (0x5B) and ']' (0x5D) are used as quotes in Chinese and
+ * Korean.<br>
+ * U+00AB and U+00BB, guillemet quotes<br>
+ * U+3008..U+300F, various quotes.<br>
+ * U+301D..U+301F, double prime quotes.<br>
+ * U+2015, dash quote.<br>
+ * U+2018..U+201F, various quotes.<br>
+ * U+2039 and U+203A, guillemet quotes.
+ */
+ private static final String QUOTES =
+ "\"\u005B\u005D\u00AB\u00BB\u301D\u301E\u301F\u2015\u2039\u203A";
+ /**
+ * U+0000..U+001F ASCII controls<br>
+ * U+2028, line separator.<br>
+ * U+2029, paragraph separator.
+ */
+ private static final String CONTROLS = "\u2028\u2029";
+}
diff --git a/java/XMPCore/src/com/adobe/xmp/impl/package.html b/java/XMPCore/src/com/adobe/xmp/impl/package.html
new file mode 100644
index 0000000..aea0dfa
--- /dev/null
+++ b/java/XMPCore/src/com/adobe/xmp/impl/package.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+ <title>Package overview</title>
+</head>
+
+<body>
+ <p>Package containing the xmpcore implementation.</p>
+</body>
+</html>
diff --git a/java/XMPCore/src/com/adobe/xmp/impl/xpath/XMPPath.java b/java/XMPCore/src/com/adobe/xmp/impl/xpath/XMPPath.java
new file mode 100644
index 0000000..d6979a5
--- /dev/null
+++ b/java/XMPCore/src/com/adobe/xmp/impl/xpath/XMPPath.java
@@ -0,0 +1,106 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+package com.adobe.xmp.impl.xpath;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ * Representates an XMP XMPPath with segment accessor methods.
+ *
+ * @since 28.02.2006
+ */
+public class XMPPath
+{
+ // Bits for XPathStepInfo options.
+
+ /** Marks a struct field step , also for top level nodes (schema "fields"). */
+ public static final int STRUCT_FIELD_STEP = 0x01;
+ /** Marks a qualifier step.
+ * Note: Order is significant to separate struct/qual from array kinds! */
+ public static final int QUALIFIER_STEP = 0x02; //
+ /** Marks an array index step */
+ public static final int ARRAY_INDEX_STEP = 0x03;
+ /** */
+ public static final int ARRAY_LAST_STEP = 0x04;
+ /** */
+ public static final int QUAL_SELECTOR_STEP = 0x05;
+ /** */
+ public static final int FIELD_SELECTOR_STEP = 0x06;
+ /** */
+ public static final int SCHEMA_NODE = 0x80000000;
+ /** */
+ public static final int STEP_SCHEMA = 0;
+ /** */
+ public static final int STEP_ROOT_PROP = 1;
+
+
+ /** stores the segments of an XMPPath */
+ private List segments = new ArrayList(5);
+
+
+ /**
+ * Append a path segment
+ *
+ * @param segment the segment to add
+ */
+ public void add(XMPPathSegment segment)
+ {
+ segments.add(segment);
+ }
+
+
+ /**
+ * @param index the index of the segment to return
+ * @return Returns a path segment.
+ */
+ public XMPPathSegment getSegment(int index)
+ {
+ return (XMPPathSegment) segments.get(index);
+ }
+
+
+ /**
+ * @return Returns the size of the xmp path.
+ */
+ public int size()
+ {
+ return segments.size();
+ }
+
+
+ /**
+ * Serializes the normalized XMP-path.
+ * @see Object#toString()
+ */
+ public String toString()
+ {
+ StringBuffer result = new StringBuffer();
+ int index = 1;
+ while (index < size())
+ {
+ result.append(getSegment(index));
+ if (index < size() - 1)
+ {
+ int kind = getSegment(index + 1).getKind();
+ if (kind == STRUCT_FIELD_STEP ||
+ kind == QUALIFIER_STEP)
+ {
+ // all but last and array indices
+ result.append('/');
+ }
+ }
+ index++;
+ }
+
+ return result.toString();
+ }
+} \ No newline at end of file
diff --git a/java/XMPCore/src/com/adobe/xmp/impl/xpath/XMPPathParser.java b/java/XMPCore/src/com/adobe/xmp/impl/xpath/XMPPathParser.java
new file mode 100644
index 0000000..2f01ad3
--- /dev/null
+++ b/java/XMPCore/src/com/adobe/xmp/impl/xpath/XMPPathParser.java
@@ -0,0 +1,529 @@
+
+package com.adobe.xmp.impl.xpath;
+
+import com.adobe.xmp.XMPError;
+import com.adobe.xmp.XMPException;
+import com.adobe.xmp.XMPMetaFactory;
+import com.adobe.xmp.impl.Utils;
+import com.adobe.xmp.properties.XMPAliasInfo;
+
+
+/**
+ * Parser for XMP XPaths.
+ *
+ * @since 01.03.2006
+ */
+public final class XMPPathParser
+{
+ /**
+ * Private constructor
+ */
+ private XMPPathParser()
+ {
+ // empty
+ }
+
+
+ /**
+ * Split an XMPPath expression apart at the conceptual steps, adding the
+ * root namespace prefix to the first property component. The schema URI is
+ * put in the first (0th) slot in the expanded XMPPath. Check if the top
+ * level component is an alias, but don't resolve it.
+ * <p>
+ * In the most verbose case steps are separated by '/', and each step can be
+ * of these forms:
+ * <dl>
+ * <dt>prefix:name
+ * <dd> A top level property or struct field.
+ * <dt>[index]
+ * <dd> An element of an array.
+ * <dt>[last()]
+ * <dd> The last element of an array.
+ * <dt>[fieldName=&quot;value&quot;]
+ * <dd> An element in an array of structs, chosen by a field value.
+ * <dt>[@xml:lang=&quot;value&quot;]
+ * <dd> An element in an alt-text array, chosen by the xml:lang qualifier.
+ * <dt>[?qualName=&quot;value&quot;]
+ * <dd> An element in an array, chosen by a qualifier value.
+ * <dt>@xml:lang
+ * <dd> An xml:lang qualifier.
+ * <dt>?qualName
+ * <dd> A general qualifier.
+ * </dl>
+ * <p>
+ * The logic is complicated though by shorthand for arrays, the separating
+ * '/' and leading '*' are optional. These are all equivalent: array/*[2]
+ * array/[2] array*[2] array[2] All of these are broken into the 2 steps
+ * "array" and "[2]".
+ * <p>
+ * The value portion in the array selector forms is a string quoted by '''
+ * or '"'. The value may contain any character including a doubled quoting
+ * character. The value may be empty.
+ * <p>
+ * The syntax isn't checked, but an XML name begins with a letter or '_',
+ * and contains letters, digits, '.', '-', '_', and a bunch of special
+ * non-ASCII Unicode characters. An XML qualified name is a pair of names
+ * separated by a colon.
+ * @param schemaNS
+ * schema namespace
+ * @param path
+ * property name
+ * @return Returns the expandet XMPPath.
+ * @throws XMPException
+ * Thrown if the format is not correct somehow.
+ *
+ */
+ public static XMPPath expandXPath(String schemaNS, String path) throws XMPException
+ {
+ if (schemaNS == null || path == null)
+ {
+ throw new XMPException("Parameter must not be null", XMPError.BADPARAM);
+ }
+
+ XMPPath expandedXPath = new XMPPath();
+ PathPosition pos = new PathPosition();
+ pos.path = path;
+
+ // Pull out the first component and do some special processing on it: add the schema
+ // namespace prefix and and see if it is an alias. The start must be a "qualName".
+ parseRootNode(schemaNS, pos, expandedXPath);
+
+ // Now continue to process the rest of the XMPPath string.
+ while (pos.stepEnd < path.length())
+ {
+ pos.stepBegin = pos.stepEnd;
+
+ skipPathDelimiter(path, pos);
+
+ pos.stepEnd = pos.stepBegin;
+
+
+ XMPPathSegment segment;
+ if (path.charAt(pos.stepBegin) != '[')
+ {
+ // A struct field or qualifier.
+ segment = parseStructSegment(pos);
+ }
+ else
+ {
+ // One of the array forms.
+ segment = parseIndexSegment(pos);
+ }
+
+
+ if (segment.getKind() == XMPPath.STRUCT_FIELD_STEP)
+ {
+ if (segment.getName().charAt(0) == '@')
+ {
+ segment.setName("?" + segment.getName().substring(1));
+ if (!"?xml:lang".equals(segment.getName()))
+ {
+ throw new XMPException("Only xml:lang allowed with '@'",
+ XMPError.BADXPATH);
+ }
+ }
+ if (segment.getName().charAt(0) == '?')
+ {
+ pos.nameStart++;
+ segment.setKind(XMPPath.QUALIFIER_STEP);
+ }
+
+ verifyQualName(pos.path.substring(pos.nameStart, pos.nameEnd));
+ }
+ else if (segment.getKind() == XMPPath.FIELD_SELECTOR_STEP)
+ {
+ if (segment.getName().charAt(1) == '@')
+ {
+ segment.setName("[?" + segment.getName().substring(2));
+ if (!segment.getName().startsWith("[?xml:lang="))
+ {
+ throw new XMPException("Only xml:lang allowed with '@'",
+ XMPError.BADXPATH);
+ }
+ }
+
+ if (segment.getName().charAt(1) == '?')
+ {
+ pos.nameStart++;
+ segment.setKind(XMPPath.QUAL_SELECTOR_STEP);
+ verifyQualName(pos.path.substring(pos.nameStart, pos.nameEnd));
+ }
+ }
+
+ expandedXPath.add(segment);
+ }
+ return expandedXPath;
+ }
+
+
+ /**
+ * @param path
+ * @param pos
+ * @throws XMPException
+ */
+ private static void skipPathDelimiter(String path, PathPosition pos) throws XMPException
+ {
+ if (path.charAt(pos.stepBegin) == '/')
+ {
+ // skip slash
+
+ pos.stepBegin++;
+
+ // added for Java
+ if (pos.stepBegin >= path.length())
+ {
+ throw new XMPException("Empty XMPPath segment", XMPError.BADXPATH);
+ }
+ }
+
+ if (path.charAt(pos.stepBegin) == '*')
+ {
+ // skip asterisk
+
+ pos.stepBegin++;
+ if (pos.stepBegin >= path.length() || path.charAt(pos.stepBegin) != '[')
+ {
+ throw new XMPException("Missing '[' after '*'", XMPError.BADXPATH);
+ }
+ }
+ }
+
+
+ /**
+ * Parses a struct segment
+ * @param pos the current position in the path
+ * @return Retusn the segment or an errror
+ * @throws XMPException If the sement is empty
+ */
+ private static XMPPathSegment parseStructSegment(PathPosition pos) throws XMPException
+ {
+ pos.nameStart = pos.stepBegin;
+ while (pos.stepEnd < pos.path.length() && "/[*".indexOf(pos.path.charAt(pos.stepEnd)) < 0)
+ {
+ pos.stepEnd++;
+ }
+ pos.nameEnd = pos.stepEnd;
+
+ if (pos.stepEnd == pos.stepBegin)
+ {
+ throw new XMPException("Empty XMPPath segment", XMPError.BADXPATH);
+ }
+
+ // ! Touch up later, also changing '@' to '?'.
+ XMPPathSegment segment = new XMPPathSegment(pos.path.substring(pos.stepBegin, pos.stepEnd),
+ XMPPath.STRUCT_FIELD_STEP);
+ return segment;
+ }
+
+
+ /**
+ * Parses an array index segment.
+ *
+ * @param pos the xmp path
+ * @return Returns the segment or an error
+ * @throws XMPException thrown on xmp path errors
+ *
+ */
+ private static XMPPathSegment parseIndexSegment(PathPosition pos) throws XMPException
+ {
+ XMPPathSegment segment;
+ pos.stepEnd++; // Look at the character after the leading '['.
+
+ if ('0' <= pos.path.charAt(pos.stepEnd) && pos.path.charAt(pos.stepEnd) <= '9')
+ {
+ // A numeric (decimal integer) array index.
+ while (pos.stepEnd < pos.path.length() && '0' <= pos.path.charAt(pos.stepEnd)
+ && pos.path.charAt(pos.stepEnd) <= '9')
+ {
+ pos.stepEnd++;
+ }
+
+ segment = new XMPPathSegment(null, XMPPath.ARRAY_INDEX_STEP);
+ }
+ else
+ {
+ // Could be "[last()]" or one of the selector forms. Find the ']' or '='.
+
+ while (pos.stepEnd < pos.path.length() && pos.path.charAt(pos.stepEnd) != ']'
+ && pos.path.charAt(pos.stepEnd) != '=')
+ {
+ pos.stepEnd++;
+ }
+
+ if (pos.stepEnd >= pos.path.length())
+ {
+ throw new XMPException("Missing ']' or '=' for array index", XMPError.BADXPATH);
+ }
+
+ if (pos.path.charAt(pos.stepEnd) == ']')
+ {
+ if (!"[last()".equals(pos.path.substring(pos.stepBegin, pos.stepEnd)))
+ {
+ throw new XMPException(
+ "Invalid non-numeric array index", XMPError.BADXPATH);
+ }
+ segment = new XMPPathSegment(null, XMPPath.ARRAY_LAST_STEP);
+ }
+ else
+ {
+ pos.nameStart = pos.stepBegin + 1;
+ pos.nameEnd = pos.stepEnd;
+ pos.stepEnd++; // Absorb the '=', remember the quote.
+ char quote = pos.path.charAt(pos.stepEnd);
+ if (quote != '\'' && quote != '"')
+ {
+ throw new XMPException(
+ "Invalid quote in array selector", XMPError.BADXPATH);
+ }
+
+ pos.stepEnd++; // Absorb the leading quote.
+ while (pos.stepEnd < pos.path.length())
+ {
+ if (pos.path.charAt(pos.stepEnd) == quote)
+ {
+ // check for escaped quote
+ if (pos.stepEnd + 1 >= pos.path.length()
+ || pos.path.charAt(pos.stepEnd + 1) != quote)
+ {
+ break;
+ }
+ pos.stepEnd++;
+ }
+ pos.stepEnd++;
+ }
+
+ if (pos.stepEnd >= pos.path.length())
+ {
+ throw new XMPException("No terminating quote for array selector",
+ XMPError.BADXPATH);
+ }
+ pos.stepEnd++; // Absorb the trailing quote.
+
+ // ! Touch up later, also changing '@' to '?'.
+ segment = new XMPPathSegment(null, XMPPath.FIELD_SELECTOR_STEP);
+ }
+ }
+
+
+ if (pos.stepEnd >= pos.path.length() || pos.path.charAt(pos.stepEnd) != ']')
+ {
+ throw new XMPException("Missing ']' for array index", XMPError.BADXPATH);
+ }
+ pos.stepEnd++;
+ segment.setName(pos.path.substring(pos.stepBegin, pos.stepEnd));
+
+ return segment;
+ }
+
+
+ /**
+ * Parses the root node of an XMP Path, checks if namespace and prefix fit together
+ * and resolve the property to the base property if it is an alias.
+ * @param schemaNS the root namespace
+ * @param pos the parsing position helper
+ * @param expandedXPath the path to contribute to
+ * @throws XMPException If the path is not valid.
+ */
+ private static void parseRootNode(String schemaNS, PathPosition pos, XMPPath expandedXPath)
+ throws XMPException
+ {
+ while (pos.stepEnd < pos.path.length() && "/[*".indexOf(pos.path.charAt(pos.stepEnd)) < 0)
+ {
+ pos.stepEnd++;
+ }
+
+ if (pos.stepEnd == pos.stepBegin)
+ {
+ throw new XMPException("Empty initial XMPPath step", XMPError.BADXPATH);
+ }
+
+ String rootProp = verifyXPathRoot(schemaNS, pos.path.substring(pos.stepBegin, pos.stepEnd));
+ XMPAliasInfo aliasInfo = XMPMetaFactory.getSchemaRegistry().findAlias(rootProp);
+ if (aliasInfo == null)
+ {
+ // add schema xpath step
+ expandedXPath.add(new XMPPathSegment(schemaNS, XMPPath.SCHEMA_NODE));
+ XMPPathSegment rootStep = new XMPPathSegment(rootProp, XMPPath.STRUCT_FIELD_STEP);
+ expandedXPath.add(rootStep);
+ }
+ else
+ {
+ // add schema xpath step and base step of alias
+ expandedXPath.add(new XMPPathSegment(aliasInfo.getNamespace(), XMPPath.SCHEMA_NODE));
+ XMPPathSegment rootStep = new XMPPathSegment(verifyXPathRoot(aliasInfo.getNamespace(),
+ aliasInfo.getPropName()),
+ XMPPath.STRUCT_FIELD_STEP);
+ rootStep.setAlias(true);
+ rootStep.setAliasForm(aliasInfo.getAliasForm().getOptions());
+ expandedXPath.add(rootStep);
+
+ if (aliasInfo.getAliasForm().isArrayAltText())
+ {
+ XMPPathSegment qualSelectorStep = new XMPPathSegment("[?xml:lang='x-default']",
+ XMPPath.QUAL_SELECTOR_STEP);
+ qualSelectorStep.setAlias(true);
+ qualSelectorStep.setAliasForm(aliasInfo.getAliasForm().getOptions());
+ expandedXPath.add(qualSelectorStep);
+ }
+ else if (aliasInfo.getAliasForm().isArray())
+ {
+ XMPPathSegment indexStep = new XMPPathSegment("[1]",
+ XMPPath.ARRAY_INDEX_STEP);
+ indexStep.setAlias(true);
+ indexStep.setAliasForm(aliasInfo.getAliasForm().getOptions());
+ expandedXPath.add(indexStep);
+ }
+ }
+ }
+
+
+ /**
+ * Verifies whether the qualifier name is not XML conformant or the
+ * namespace prefix has not been registered.
+ *
+ * @param qualName
+ * a qualifier name
+ * @throws XMPException
+ * If the name is not conformant
+ */
+ private static void verifyQualName(String qualName) throws XMPException
+ {
+ int colonPos = qualName.indexOf(':');
+ if (colonPos > 0)
+ {
+ String prefix = qualName.substring(0, colonPos);
+ if (Utils.isXMLNameNS(prefix))
+ {
+ String regURI = XMPMetaFactory.getSchemaRegistry().getNamespaceURI(
+ prefix);
+ if (regURI != null)
+ {
+ return;
+ }
+
+ throw new XMPException("Unknown namespace prefix for qualified name",
+ XMPError.BADXPATH);
+ }
+ }
+
+ throw new XMPException("Ill-formed qualified name", XMPError.BADXPATH);
+ }
+
+
+ /**
+ * Verify if an XML name is conformant.
+ *
+ * @param name
+ * an XML name
+ * @throws XMPException
+ * When the name is not XML conformant
+ */
+ private static void verifySimpleXMLName(String name) throws XMPException
+ {
+ if (!Utils.isXMLName(name))
+ {
+ throw new XMPException("Bad XML name", XMPError.BADXPATH);
+ }
+ }
+
+
+ /**
+ * Set up the first 2 components of the expanded XMPPath. Normalizes the various cases of using
+ * the full schema URI and/or a qualified root property name. Returns true for normal
+ * processing. If allowUnknownSchemaNS is true and the schema namespace is not registered, false
+ * is returned. If allowUnknownSchemaNS is false and the schema namespace is not registered, an
+ * exception is thrown
+ * <P>
+ * (Should someday check the full syntax:)
+ *
+ * @param schemaNS schema namespace
+ * @param rootProp the root xpath segment
+ * @return Returns root QName.
+ * @throws XMPException Thrown if the format is not correct somehow.
+ */
+ private static String verifyXPathRoot(String schemaNS, String rootProp)
+ throws XMPException
+ {
+ // Do some basic checks on the URI and name. Try to lookup the URI. See if the name is
+ // qualified.
+
+ if (schemaNS == null || schemaNS.length() == 0)
+ {
+ throw new XMPException(
+ "Schema namespace URI is required", XMPError.BADSCHEMA);
+ }
+
+ if ((rootProp.charAt(0) == '?') || (rootProp.charAt(0) == '@'))
+ {
+ throw new XMPException("Top level name must not be a qualifier", XMPError.BADXPATH);
+ }
+
+ if (rootProp.indexOf('/') >= 0 || rootProp.indexOf('[') >= 0)
+ {
+ throw new XMPException("Top level name must be simple", XMPError.BADXPATH);
+ }
+
+ String prefix = XMPMetaFactory.getSchemaRegistry().getNamespacePrefix(schemaNS);
+ if (prefix == null)
+ {
+ throw new XMPException("Unregistered schema namespace URI", XMPError.BADSCHEMA);
+ }
+
+ // Verify the various URI and prefix combinations. Initialize the
+ // expanded XMPPath.
+ int colonPos = rootProp.indexOf(':');
+ if (colonPos < 0)
+ {
+ // The propName is unqualified, use the schemaURI and associated
+ // prefix.
+ verifySimpleXMLName(rootProp); // Verify the part before any colon
+ return prefix + rootProp;
+ }
+ else
+ {
+ // The propName is qualified. Make sure the prefix is legit. Use the associated URI and
+ // qualified name.
+
+ // Verify the part before any colon
+ verifySimpleXMLName(rootProp.substring(0, colonPos));
+ verifySimpleXMLName(rootProp.substring(colonPos));
+
+ prefix = rootProp.substring(0, colonPos + 1);
+
+ String regPrefix = XMPMetaFactory.getSchemaRegistry().getNamespacePrefix(schemaNS);
+ if (regPrefix == null)
+ {
+ throw new XMPException("Unknown schema namespace prefix", XMPError.BADSCHEMA);
+ }
+ if (!prefix.equals(regPrefix))
+ {
+ throw new XMPException("Schema namespace URI and prefix mismatch",
+ XMPError.BADSCHEMA);
+ }
+
+ return rootProp;
+ }
+ }
+}
+
+
+
+
+
+/**
+ * This objects contains all needed char positions to parse.
+ */
+class PathPosition
+{
+ /** the complete path */
+ public String path = null;
+ /** the start of a segment name */
+ int nameStart = 0;
+ /** the end of a segment name */
+ int nameEnd = 0;
+ /** the begin of a step */
+ int stepBegin = 0;
+ /** the end of a step */
+ int stepEnd = 0;
+}
+
diff --git a/java/XMPCore/src/com/adobe/xmp/impl/xpath/XMPPathSegment.java b/java/XMPCore/src/com/adobe/xmp/impl/xpath/XMPPathSegment.java
new file mode 100644
index 0000000..b025170
--- /dev/null
+++ b/java/XMPCore/src/com/adobe/xmp/impl/xpath/XMPPathSegment.java
@@ -0,0 +1,147 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+package com.adobe.xmp.impl.xpath;
+
+
+/**
+ * A segment of a parsed <code>XMPPath</code>.
+ *
+ * @since 23.06.2006
+ */
+public class XMPPathSegment
+{
+ /** name of the path segment */
+ private String name;
+ /** kind of the path segment */
+ private int kind;
+ /** flag if segment is an alias */
+ private boolean alias;
+ /** alias form if applicable */
+ private int aliasForm;
+
+
+ /**
+ * Constructor with initial values.
+ *
+ * @param name the name of the segment
+ */
+ public XMPPathSegment(String name)
+ {
+ this.name = name;
+ }
+
+
+ /**
+ * Constructor with initial values.
+ *
+ * @param name the name of the segment
+ * @param kind the kind of the segment
+ */
+ public XMPPathSegment(String name, int kind)
+ {
+ this.name = name;
+ this.kind = kind;
+ }
+
+
+ /**
+ * @return Returns the kind.
+ */
+ public int getKind()
+ {
+ return kind;
+ }
+
+
+ /**
+ * @param kind The kind to set.
+ */
+ public void setKind(int kind)
+ {
+ this.kind = kind;
+ }
+
+
+ /**
+ * @return Returns the name.
+ */
+ public String getName()
+ {
+ return name;
+ }
+
+
+ /**
+ * @param name The name to set.
+ */
+ public void setName(String name)
+ {
+ this.name = name;
+ }
+
+
+ /**
+ * @param alias the flag to set
+ */
+ public void setAlias(boolean alias)
+ {
+ this.alias = alias;
+ }
+
+
+ /**
+ * @return Returns the alias.
+ */
+ public boolean isAlias()
+ {
+ return alias;
+ }
+
+
+ /**
+ * @return Returns the aliasForm if this segment has been created by an alias.
+ */
+ public int getAliasForm()
+ {
+ return aliasForm;
+ }
+
+
+ /**
+ * @param aliasForm the aliasForm to set
+ */
+ public void setAliasForm(int aliasForm)
+ {
+ this.aliasForm = aliasForm;
+ }
+
+
+ /**
+ * @see Object#toString()
+ */
+ public String toString()
+ {
+ switch (kind)
+ {
+ case XMPPath.STRUCT_FIELD_STEP:
+ case XMPPath.ARRAY_INDEX_STEP:
+ case XMPPath.QUALIFIER_STEP:
+ case XMPPath.ARRAY_LAST_STEP:
+ return name;
+ case XMPPath.QUAL_SELECTOR_STEP:
+ case XMPPath.FIELD_SELECTOR_STEP:
+ return name;
+
+ default:
+ // no defined step
+ return name;
+ }
+ }
+}
diff --git a/java/XMPCore/src/com/adobe/xmp/impl/xpath/package.html b/java/XMPCore/src/com/adobe/xmp/impl/xpath/package.html
new file mode 100644
index 0000000..e444a87
--- /dev/null
+++ b/java/XMPCore/src/com/adobe/xmp/impl/xpath/package.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+ <title>Package overview</title>
+</head>
+
+<body>
+ <p>Package containing the XMPPath handling.</p>
+ <p>An XMPPath a simplified form of an XPath, used only to create or retrieve properties in an XMPMeta object.<p>
+</body>
+</html>
diff --git a/java/XMPCore/src/com/adobe/xmp/options/AliasOptions.java b/java/XMPCore/src/com/adobe/xmp/options/AliasOptions.java
new file mode 100644
index 0000000..ccd3921
--- /dev/null
+++ b/java/XMPCore/src/com/adobe/xmp/options/AliasOptions.java
@@ -0,0 +1,186 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+package com.adobe.xmp.options;
+
+import com.adobe.xmp.XMPException;
+import com.adobe.xmp.XMPSchemaRegistry;
+
+
+/**
+ * Options for {@link XMPSchemaRegistry#registerAlias( String, String, String, String,
+ * AliasOptions)}.
+ *
+ * @since 20.02.2006
+ */
+public final class AliasOptions extends Options
+{
+ /** This is a direct mapping. The actual data type does not matter. */
+ public static final int PROP_DIRECT = 0;
+ /** The actual is an unordered array, the alias is to the first element of the array. */
+ public static final int PROP_ARRAY = PropertyOptions.ARRAY;
+ /** The actual is an ordered array, the alias is to the first element of the array. */
+ public static final int PROP_ARRAY_ORDERED = PropertyOptions.ARRAY_ORDERED;
+ /** The actual is an alternate array, the alias is to the first element of the array. */
+ public static final int PROP_ARRAY_ALTERNATE = PropertyOptions.ARRAY_ALTERNATE;
+ /**
+ * The actual is an alternate text array, the alias is to the 'x-default' element of the array.
+ */
+ public static final int PROP_ARRAY_ALT_TEXT = PropertyOptions.ARRAY_ALT_TEXT;
+
+
+ /**
+ * @see Options#Options()
+ */
+ public AliasOptions()
+ {
+ // EMPTY
+ }
+
+
+ /**
+ * @param options the options to init with
+ * @throws XMPException If options are not consistant
+ */
+ public AliasOptions(int options) throws XMPException
+ {
+ super(options);
+ }
+
+
+ /**
+ * @return Returns if the alias is of the simple form.
+ */
+ public boolean isSimple()
+ {
+ return getOptions() == PROP_DIRECT;
+ }
+
+
+ /**
+ * @return Returns the option.
+ */
+ public boolean isArray()
+ {
+ return getOption(PROP_ARRAY);
+ }
+
+
+ /**
+ * @param value the value to set
+ * @return Returns the instance to call more set-methods.
+ */
+ public AliasOptions setArray(boolean value)
+ {
+ setOption(PROP_ARRAY, value);
+ return this;
+ }
+
+
+ /**
+ * @return Returns the option.
+ */
+ public boolean isArrayOrdered()
+ {
+ return getOption(PROP_ARRAY_ORDERED);
+ }
+
+
+ /**
+ * @param value the value to set
+ * @return Returns the instance to call more set-methods.
+ */
+ public AliasOptions setArrayOrdered(boolean value)
+ {
+ setOption(PROP_ARRAY | PROP_ARRAY_ORDERED, value);
+ return this;
+ }
+
+
+ /**
+ * @return Returns the option.
+ */
+ public boolean isArrayAlternate()
+ {
+ return getOption(PROP_ARRAY_ALTERNATE);
+ }
+
+
+ /**
+ * @param value the value to set
+ * @return Returns the instance to call more set-methods.
+ */
+ public AliasOptions setArrayAlternate(boolean value)
+ {
+ setOption(PROP_ARRAY | PROP_ARRAY_ORDERED | PROP_ARRAY_ALTERNATE, value);
+ return this;
+ }
+
+
+ /**
+ * @return Returns the option.
+ */
+ public boolean isArrayAltText()
+ {
+ return getOption(PROP_ARRAY_ALT_TEXT);
+ }
+
+
+ /**
+ * @param value the value to set
+ * @return Returns the instance to call more set-methods.
+ */
+ public AliasOptions setArrayAltText(boolean value)
+ {
+ setOption(PROP_ARRAY | PROP_ARRAY_ORDERED |
+ PROP_ARRAY_ALTERNATE | PROP_ARRAY_ALT_TEXT, value);
+ return this;
+ }
+
+
+ /**
+ * @return returns a {@link PropertyOptions}s object
+ * @throws XMPException If the options are not consistant.
+ */
+ public PropertyOptions toPropertyOptions() throws XMPException
+ {
+ return new PropertyOptions(getOptions());
+ }
+
+
+ /**
+ * @see Options#defineOptionName(int)
+ */
+ protected String defineOptionName(int option)
+ {
+ switch (option)
+ {
+ case PROP_DIRECT : return "PROP_DIRECT";
+ case PROP_ARRAY : return "ARRAY";
+ case PROP_ARRAY_ORDERED : return "ARRAY_ORDERED";
+ case PROP_ARRAY_ALTERNATE : return "ARRAY_ALTERNATE";
+ case PROP_ARRAY_ALT_TEXT : return "ARRAY_ALT_TEXT";
+ default: return null;
+ }
+ }
+
+
+ /**
+ * @see Options#getValidOptions()
+ */
+ protected int getValidOptions()
+ {
+ return
+ PROP_DIRECT |
+ PROP_ARRAY |
+ PROP_ARRAY_ORDERED |
+ PROP_ARRAY_ALTERNATE |
+ PROP_ARRAY_ALT_TEXT;
+ }
+} \ No newline at end of file
diff --git a/java/XMPCore/src/com/adobe/xmp/options/IteratorOptions.java b/java/XMPCore/src/com/adobe/xmp/options/IteratorOptions.java
new file mode 100644
index 0000000..5affb05
--- /dev/null
+++ b/java/XMPCore/src/com/adobe/xmp/options/IteratorOptions.java
@@ -0,0 +1,148 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+package com.adobe.xmp.options;
+
+
+/**
+ * Options for <code>XMPIterator</code> construction.
+ *
+ * @since 24.01.2006
+ */
+public final class IteratorOptions extends Options
+{
+ /** Just do the immediate children of the root, default is subtree. */
+ public static final int JUST_CHILDREN = 0x0100;
+ /** Just do the leaf nodes, default is all nodes in the subtree. */
+ public static final int JUST_LEAFNODES = 0x0200;
+ /** Return just the leaf part of the path, default is the full path. */
+ public static final int JUST_LEAFNAME = 0x0400;
+ /** Include aliases, default is just actual properties. <em>Note:</em> Not supported.
+ * @deprecated it is commonly preferred to work with the base properties */
+ public static final int INCLUDE_ALIASES = 0x0800;
+ /** Omit all qualifiers. */
+ public static final int OMIT_QUALIFIERS = 0x1000;
+
+
+ /**
+ * @return Returns whether the option is set.
+ */
+ public boolean isJustChildren()
+ {
+ return getOption(JUST_CHILDREN);
+ }
+
+
+ /**
+ * @return Returns whether the option is set.
+ */
+ public boolean isJustLeafname()
+ {
+ return getOption(JUST_LEAFNAME);
+ }
+
+
+ /**
+ * @return Returns whether the option is set.
+ */
+ public boolean isJustLeafnodes()
+ {
+ return getOption(JUST_LEAFNODES);
+ }
+
+
+ /**
+ * @return Returns whether the option is set.
+ */
+ public boolean isOmitQualifiers()
+ {
+ return getOption(OMIT_QUALIFIERS);
+ }
+
+
+ /**
+ * Sets the option and returns the instance.
+ *
+ * @param value the value to set
+ * @return Returns the instance to call more set-methods.
+ */
+ public IteratorOptions setJustChildren(boolean value)
+ {
+ setOption(JUST_CHILDREN, value);
+ return this;
+ }
+
+
+ /**
+ * Sets the option and returns the instance.
+ *
+ * @param value the value to set
+ * @return Returns the instance to call more set-methods.
+ */
+ public IteratorOptions setJustLeafname(boolean value)
+ {
+ setOption(JUST_LEAFNAME, value);
+ return this;
+ }
+
+
+ /**
+ * Sets the option and returns the instance.
+ *
+ * @param value the value to set
+ * @return Returns the instance to call more set-methods.
+ */
+ public IteratorOptions setJustLeafnodes(boolean value)
+ {
+ setOption(JUST_LEAFNODES, value);
+ return this;
+ }
+
+
+ /**
+ * Sets the option and returns the instance.
+ *
+ * @param value the value to set
+ * @return Returns the instance to call more set-methods.
+ */
+ public IteratorOptions setOmitQualifiers(boolean value)
+ {
+ setOption(OMIT_QUALIFIERS, value);
+ return this;
+ }
+
+
+ /**
+ * @see Options#defineOptionName(int)
+ */
+ protected String defineOptionName(int option)
+ {
+ switch (option)
+ {
+ case JUST_CHILDREN : return "JUST_CHILDREN";
+ case JUST_LEAFNODES : return "JUST_LEAFNODES";
+ case JUST_LEAFNAME : return "JUST_LEAFNAME";
+ case OMIT_QUALIFIERS : return "OMIT_QUALIFIERS";
+ default: return null;
+ }
+ }
+
+
+ /**
+ * @see Options#getValidOptions()
+ */
+ protected int getValidOptions()
+ {
+ return
+ JUST_CHILDREN |
+ JUST_LEAFNODES |
+ JUST_LEAFNAME |
+ OMIT_QUALIFIERS;
+ }
+} \ No newline at end of file
diff --git a/java/XMPCore/src/com/adobe/xmp/options/Options.java b/java/XMPCore/src/com/adobe/xmp/options/Options.java
new file mode 100644
index 0000000..278db73
--- /dev/null
+++ b/java/XMPCore/src/com/adobe/xmp/options/Options.java
@@ -0,0 +1,290 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+package com.adobe.xmp.options;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.adobe.xmp.XMPError;
+import com.adobe.xmp.XMPException;
+
+/**
+ * The base class for a collection of 32 flag bits. Individual flags are defined as enum value bit
+ * masks. Inheriting classes add convenience accessor methods.
+ *
+ * @since 24.01.2006
+ */
+public abstract class Options
+{
+ /** the internal int containing all options */
+ private int options = 0;
+ /** a map containing the bit names */
+ private Map optionNames = null;
+
+
+ /**
+ * The default constructor.
+ */
+ public Options()
+ {
+ // EMTPY
+ }
+
+
+ /**
+ * Constructor with the options bit mask.
+ *
+ * @param options the options bit mask
+ * @throws XMPException If the options are not correct
+ */
+ public Options(int options) throws XMPException
+ {
+ assertOptionsValid(options);
+ setOptions(options);
+ }
+
+
+ /**
+ * Resets the options.
+ */
+ public void clear()
+ {
+ options = 0;
+ }
+
+
+ /**
+ * @param optionBits an option bitmask
+ * @return Returns true, if this object is equal to the given options.
+ */
+ public boolean isExactly(int optionBits)
+ {
+ return getOptions() == optionBits;
+ }
+
+
+ /**
+ * @param optionBits an option bitmask
+ * @return Returns true, if this object contains all given options.
+ */
+ public boolean containsAllOptions(int optionBits)
+ {
+ return (getOptions() & optionBits) == optionBits;
+ }
+
+
+ /**
+ * @param optionBits an option bitmask
+ * @return Returns true, if this object contain at least one of the given options.
+ */
+ public boolean containsOneOf(int optionBits)
+ {
+ return ((getOptions()) & optionBits) != 0;
+ }
+
+
+ /**
+ * @param optionBit the binary bit or bits that are requested
+ * @return Returns if <emp>all</emp> of the requested bits are set or not.
+ */
+ protected boolean getOption(int optionBit)
+ {
+ return (options & optionBit) != 0;
+ }
+
+
+ /**
+ * @param optionBits the binary bit or bits that shall be set to the given value
+ * @param value the boolean value to set
+ */
+ public void setOption(int optionBits, boolean value)
+ {
+ options = value ? options | optionBits : options & ~optionBits;
+ }
+
+
+ /**
+ * Is friendly to access it during the tests.
+ * @return Returns the options.
+ */
+ public int getOptions()
+ {
+ return options;
+ }
+
+
+ /**
+ * @param options The options to set.
+ * @throws XMPException
+ */
+ public void setOptions(int options) throws XMPException
+ {
+ assertOptionsValid(options);
+ this.options = options;
+ }
+
+
+ /**
+ * @see Object#equals(Object)
+ */
+ public boolean equals(Object obj)
+ {
+ return getOptions() == ((Options) obj).getOptions();
+ }
+
+
+ /**
+ * @see java.lang.Object#hashCode()
+ */
+ public int hashCode()
+ {
+ return getOptions();
+ }
+
+
+ /**
+ * Creates a human readable string from the set options. <em>Note:</em> This method is quite
+ * expensive and should only be used within tests or as
+ * @return Returns a String listing all options that are set to <code>true</code> by their name,
+ * like &quot;option1 | option4&quot;.
+ */
+ public String getOptionsString()
+ {
+ if (options != 0)
+ {
+ StringBuffer sb = new StringBuffer();
+ int theBits = options;
+ while (theBits != 0)
+ {
+ int oneLessBit = theBits & (theBits - 1); // clear rightmost one bit
+ int singleBit = theBits ^ oneLessBit;
+ String bitName = getOptionName(singleBit);
+ sb.append(bitName);
+ if (oneLessBit != 0)
+ {
+ sb.append(" | ");
+ }
+ theBits = oneLessBit;
+ }
+ return sb.toString();
+ }
+ else
+ {
+ return "<none>";
+ }
+ }
+
+
+ /**
+ * @return Returns the options as hex bitmask.
+ */
+ public String toString()
+ {
+ return "0x" + Integer.toHexString(options);
+ }
+
+
+ /**
+ * To be implemeted by inheritants.
+ * @return Returns a bit mask where all valid option bits are set.
+ */
+ protected abstract int getValidOptions();
+
+
+ /**
+ * To be implemeted by inheritants.
+ * @param option a single, valid option bit.
+ * @return Returns a human readable name for an option bit.
+ */
+ protected abstract String defineOptionName(int option);
+
+
+ /**
+ * The inheriting option class can do additional checks on the options.
+ * <em>Note:</em> For performance reasons this method is only called
+ * when setting bitmasks directly.
+ * When get- and set-methods are used, this method must be called manually,
+ * normally only when the Options-object has been created from a client
+ * (it has to be made public therefore).
+ *
+ * @param options the bitmask to check.
+ * @throws XMPException Thrown if the options are not consistent.
+ */
+ protected void assertConsistency(int options) throws XMPException
+ {
+ // empty, no checks
+ }
+
+
+ /**
+ * Checks options before they are set.
+ * First it is checked if only defined options are used,
+ * second the additional {@link Options#assertConsistency(int)}-method is called.
+ *
+ * @param options the options to check
+ * @throws XMPException Thrown if the options are invalid.
+ */
+ private void assertOptionsValid(int options) throws XMPException
+ {
+ int invalidOptions = options & ~getValidOptions();
+ if (invalidOptions == 0)
+ {
+ assertConsistency(options);
+ }
+ else
+ {
+ throw new XMPException("The option bit(s) 0x" + Integer.toHexString(invalidOptions)
+ + " are invalid!", XMPError.BADOPTIONS);
+ }
+ }
+
+
+
+ /**
+ * Looks up or asks the inherited class for the name of an option bit.
+ * Its save that there is only one valid option handed into the method.
+ * @param option a single option bit
+ * @return Returns the option name or undefined.
+ */
+ private String getOptionName(int option)
+ {
+ Map optionsNames = procureOptionNames();
+
+ Integer key = new Integer(option);
+ String result = (String) optionsNames.get(key);
+ if (result == null)
+ {
+ result = defineOptionName(option);
+ if (result != null)
+ {
+ optionsNames.put(key, result);
+ }
+ else
+ {
+ result = "<option name not defined>";
+ }
+ }
+
+ return result;
+ }
+
+
+ /**
+ * @return Returns the optionNames map and creates it if required.
+ */
+ private Map procureOptionNames()
+ {
+ if (optionNames == null)
+ {
+ optionNames = new HashMap();
+ }
+ return optionNames;
+ }
+}
diff --git a/java/XMPCore/src/com/adobe/xmp/options/ParseOptions.java b/java/XMPCore/src/com/adobe/xmp/options/ParseOptions.java
new file mode 100644
index 0000000..04d831d
--- /dev/null
+++ b/java/XMPCore/src/com/adobe/xmp/options/ParseOptions.java
@@ -0,0 +1,150 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+package com.adobe.xmp.options;
+
+import java.io.InputStream;
+
+import com.adobe.xmp.XMPMetaFactory;
+
+
+/**
+ * Options for {@link XMPMetaFactory#parse(InputStream, ParseOptions)}.
+ *
+ * @since 24.01.2006
+ */
+public final class ParseOptions extends Options
+{
+ /** Require a surrounding &quot;x:xmpmeta&quot; element in the xml-document. */
+ public static final int REQUIRE_XMP_META = 0x0001;
+ /** Do not reconcile alias differences, throw an exception instead. */
+ public static final int STRICT_ALIASING = 0x0004;
+ /** Convert ASCII control characters 0x01 - 0x1F (except tab, cr, and lf) to spaces. */
+ public static final int FIX_CONTROL_CHARS = 0x0008;
+ /** If the input is not unicode, try to parse it as ISO-8859-1. */
+ public static final int ACCEPT_LATIN_1 = 0x0010;
+
+
+ /**
+ * Sets the options to the default values.
+ */
+ public ParseOptions()
+ {
+ setOption(FIX_CONTROL_CHARS | ACCEPT_LATIN_1, true);
+ }
+
+
+ /**
+ * @return Returns the requireXMPMeta.
+ */
+ public boolean getRequireXMPMeta()
+ {
+ return getOption(REQUIRE_XMP_META);
+ }
+
+
+ /**
+ * @param value the value to set
+ * @return Returns the instance to call more set-methods.
+ */
+ public ParseOptions setRequireXMPMeta(boolean value)
+ {
+ setOption(REQUIRE_XMP_META, value);
+ return this;
+ }
+
+
+ /**
+ * @return Returns the strictAliasing.
+ */
+ public boolean getStrictAliasing()
+ {
+ return getOption(STRICT_ALIASING);
+ }
+
+
+ /**
+ * @param value the value to set
+ * @return Returns the instance to call more set-methods.
+ */
+ public ParseOptions setStrictAliasing(boolean value)
+ {
+ setOption(STRICT_ALIASING, value);
+ return this;
+ }
+
+
+ /**
+ * @return Returns the strictAliasing.
+ */
+ public boolean getFixControlChars()
+ {
+ return getOption(FIX_CONTROL_CHARS);
+ }
+
+
+ /**
+ * @param value the value to set
+ * @return Returns the instance to call more set-methods.
+ */
+ public ParseOptions setFixControlChars(boolean value)
+ {
+ setOption(FIX_CONTROL_CHARS, value);
+ return this;
+ }
+
+
+ /**
+ * @return Returns the strictAliasing.
+ */
+ public boolean getAcceptLatin1()
+ {
+ return getOption(ACCEPT_LATIN_1);
+ }
+
+
+ /**
+ * @param value the value to set
+ * @return Returns the instance to call more set-methods.
+ */
+ public ParseOptions setAcceptLatin1(boolean value)
+ {
+ setOption(ACCEPT_LATIN_1, value);
+ return this;
+ }
+
+
+ /**
+ * @see Options#defineOptionName(int)
+ */
+ protected String defineOptionName(int option)
+ {
+ switch (option)
+ {
+ case REQUIRE_XMP_META : return "REQUIRE_XMP_META";
+ case STRICT_ALIASING : return "STRICT_ALIASING";
+ case FIX_CONTROL_CHARS: return "FIX_CONTROL_CHARS";
+ case ACCEPT_LATIN_1: return "ACCEPT_LATIN_1";
+ default: return null;
+ }
+ }
+
+
+ /**
+ * @see Options#getValidOptions()
+ */
+ protected int getValidOptions()
+ {
+ return
+ REQUIRE_XMP_META |
+ STRICT_ALIASING |
+ FIX_CONTROL_CHARS |
+ ACCEPT_LATIN_1;
+ }
+} \ No newline at end of file
diff --git a/java/XMPCore/src/com/adobe/xmp/options/PropertyOptions.java b/java/XMPCore/src/com/adobe/xmp/options/PropertyOptions.java
new file mode 100644
index 0000000..53d2cb1
--- /dev/null
+++ b/java/XMPCore/src/com/adobe/xmp/options/PropertyOptions.java
@@ -0,0 +1,453 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+package com.adobe.xmp.options;
+
+import com.adobe.xmp.XMPError;
+import com.adobe.xmp.XMPException;
+
+
+/**
+ * The property flags are used when properties are fetched from the <code>XMPMeta</code>-object
+ * and provide more detailed information about the property.
+ *
+ * @since 03.07.2006
+ */
+public final class PropertyOptions extends Options
+{
+ /** */
+ public static final int NO_OPTIONS = 0x00000000;
+ /** */
+ public static final int URI = 0x00000002;
+ /** */
+ public static final int HAS_QUALIFIERS = 0x00000010;
+ /** */
+ public static final int QUALIFIER = 0x00000020;
+ /** */
+ public static final int HAS_LANGUAGE = 0x00000040;
+ /** */
+ public static final int HAS_TYPE = 0x00000080;
+ /** */
+ public static final int STRUCT = 0x00000100;
+ /** */
+ public static final int ARRAY = 0x00000200;
+ /** */
+ public static final int ARRAY_ORDERED = 0x00000400;
+ /** */
+ public static final int ARRAY_ALTERNATE = 0x00000800;
+ /** */
+ public static final int ARRAY_ALT_TEXT = 0x00001000;
+ /** */
+ public static final int COMPACT = 0x00002000;
+ /** */
+ public static final int SCHEMA_NODE = 0x80000000;
+ /** may be used in the future */
+ public static final int DELETE_EXISTING = 0x20000000;
+
+
+ /**
+ * Default constructor
+ */
+ public PropertyOptions()
+ {
+ // reveal default constructor
+ }
+
+
+ /**
+ * Intialization constructor
+ *
+ * @param options the initialization options
+ * @throws XMPException If the options are not valid
+ */
+ public PropertyOptions(int options) throws XMPException
+ {
+ super(options);
+ }
+
+
+ /**
+ * @return Return whether the property value is a URI. It is serialized to RDF using the
+ * <tt>rdf:resource</tt> attribute. Not mandatory for URIs, but considered RDF-savvy.
+ */
+ public boolean isURI()
+ {
+ return getOption(URI);
+ }
+
+
+ /**
+ * @param value the value to set
+ * @return Returns this to enable cascaded options.
+ */
+ public PropertyOptions setURI(boolean value)
+ {
+ setOption(URI, value);
+ return this;
+ }
+
+
+ /**
+ * @return Return whether the property has qualifiers. These could be an <tt>xml:lang</tt>
+ * attribute, an <tt>rdf:type</tt> property, or a general qualifier. See the
+ * introductory discussion of qualified properties for more information.
+ */
+ public boolean getHasQualifiers()
+ {
+ return getOption(HAS_QUALIFIERS);
+ }
+
+
+ /**
+ * @param value the value to set
+ * @return Returns this to enable cascaded options.
+ */
+ public PropertyOptions setHasQualifiers(boolean value)
+ {
+ setOption(HAS_QUALIFIERS, value);
+ return this;
+ }
+
+
+ /**
+ * @return Return whether this property is a qualifier for some other property. Note that if the
+ * qualifier itself has a structured value, this flag is only set for the top node of
+ * the qualifier's subtree. Qualifiers may have arbitrary structure, and may even have
+ * qualifiers.
+ */
+ public boolean isQualifier()
+ {
+ return getOption(QUALIFIER);
+ }
+
+
+ /**
+ * @param value the value to set
+ * @return Returns this to enable cascaded options.
+ */
+ public PropertyOptions setQualifier(boolean value)
+ {
+ setOption(QUALIFIER, value);
+ return this;
+ }
+
+
+ /** @return Return whether this property has an <tt>xml:lang</tt> qualifier. */
+ public boolean getHasLanguage()
+ {
+ return getOption(HAS_LANGUAGE);
+ }
+
+
+ /**
+ * @param value the value to set
+ * @return Returns this to enable cascaded options.
+ */
+ public PropertyOptions setHasLanguage(boolean value)
+ {
+ setOption(HAS_LANGUAGE, value);
+ return this;
+ }
+
+
+ /** @return Return whether this property has an <tt>rdf:type</tt> qualifier. */
+ public boolean getHasType()
+ {
+ return getOption(HAS_TYPE);
+ }
+
+
+ /**
+ * @param value the value to set
+ * @return Returns this to enable cascaded options.
+ */
+ public PropertyOptions setHasType(boolean value)
+ {
+ setOption(HAS_TYPE, value);
+ return this;
+ }
+
+
+ /** @return Return whether this property contains nested fields. */
+ public boolean isStruct()
+ {
+ return getOption(STRUCT);
+ }
+
+
+ /**
+ * @param value the value to set
+ * @return Returns this to enable cascaded options.
+ */
+ public PropertyOptions setStruct(boolean value)
+ {
+ setOption(STRUCT, value);
+ return this;
+ }
+
+
+ /**
+ * @return Return whether this property is an array. By itself this indicates a general
+ * unordered array. It is serialized using an <tt>rdf:Bag</tt> container.
+ */
+ public boolean isArray()
+ {
+ return getOption(ARRAY);
+ }
+
+
+ /**
+ * @param value the value to set
+ * @return Returns this to enable cascaded options.
+ */
+ public PropertyOptions setArray(boolean value)
+ {
+ setOption(ARRAY, value);
+ return this;
+ }
+
+
+ /**
+ * @return Return whether this property is an ordered array. Appears in conjunction with
+ * getPropValueIsArray(). It is serialized using an <tt>rdf:Seq</tt> container.
+ */
+ public boolean isArrayOrdered()
+ {
+ return getOption(ARRAY_ORDERED);
+ }
+
+
+ /**
+ * @param value the value to set
+ * @return Returns this to enable cascaded options.
+ */
+ public PropertyOptions setArrayOrdered(boolean value)
+ {
+ setOption(ARRAY_ORDERED, value);
+ return this;
+ }
+
+
+ /**
+ * @return Return whether this property is an alternative array. Appears in conjunction with
+ * getPropValueIsArray(). It is serialized using an <tt>rdf:Alt</tt> container.
+ */
+ public boolean isArrayAlternate()
+ {
+ return getOption(ARRAY_ALTERNATE);
+ }
+
+
+ /**
+ * @param value the value to set
+ * @return Returns this to enable cascaded options.
+ */
+ public PropertyOptions setArrayAlternate(boolean value)
+ {
+ setOption(ARRAY_ALTERNATE, value);
+ return this;
+ }
+
+
+ /**
+ * @return Return whether this property is an alt-text array. Appears in conjunction with
+ * getPropArrayIsAlternate(). It is serialized using an <tt>rdf:Alt</tt> container.
+ * Each array element is a simple property with an <tt>xml:lang</tt> attribute.
+ */
+ public boolean isArrayAltText()
+ {
+ return getOption(ARRAY_ALT_TEXT);
+ }
+
+
+ /**
+ * @param value the value to set
+ * @return Returns this to enable cascaded options.
+ */
+ public PropertyOptions setArrayAltText(boolean value)
+ {
+ setOption(ARRAY_ALT_TEXT, value);
+ return this;
+ }
+
+
+ /**
+ * @return Return whether the value is a compact struct or array.
+ */
+ public boolean isCompact()
+ {
+ return getOption(COMPACT);
+ }
+
+
+ /**
+ * @param value the value to set
+ * @return Returns this to enable cascaded options.
+ */
+ public PropertyOptions setCompact(boolean value)
+ {
+ setOption(COMPACT, value);
+ return this;
+ }
+
+
+ /**
+ * @param value the value to set
+ * @return Returns this to enable cascaded options.
+ */
+
+
+ /**
+ * @return Returns whether the SCHEMA_NODE option is set.
+ */
+ public boolean isSchemaNode()
+ {
+ return getOption(SCHEMA_NODE);
+ }
+
+
+ /**
+ * @param value the option DELETE_EXISTING to set
+ * @return Returns this to enable cascaded options.
+ */
+ public PropertyOptions setSchemaNode(boolean value)
+ {
+ setOption(SCHEMA_NODE, value);
+ return this;
+ }
+
+
+ //-------------------------------------------------------------------------- convenience methods
+
+ /**
+ * @return Returns whether the property is of composite type - an array or a struct.
+ */
+ public boolean isCompositeProperty()
+ {
+ return (getOptions() & (ARRAY | STRUCT)) > 0;
+ }
+
+
+ /**
+ * @return Returns whether the property is of composite type - an array or a struct.
+ */
+ public boolean isSimple()
+ {
+ return (getOptions() & (ARRAY | STRUCT)) == 0;
+ }
+
+
+ /**
+ * Compares two options set for array compatibility.
+ *
+ * @param options other options
+ * @return Returns true if the array options of the sets are equal.
+ */
+ public boolean equalArrayTypes(PropertyOptions options)
+ {
+ return
+ isArray() == options.isArray() &&
+ isArrayOrdered() == options.isArrayOrdered() &&
+ isArrayAlternate() == options.isArrayAlternate() &&
+ isArrayAltText() == options.isArrayAltText();
+ }
+
+
+
+ /**
+ * Merges the set options of a another options object with this.
+ * If the other options set is null, this objects stays the same.
+ * @param options other options
+ * @throws XMPException If illegal options are provided
+ */
+ public void mergeWith(PropertyOptions options) throws XMPException
+ {
+ if (options != null)
+ {
+ setOptions(getOptions() | options.getOptions());
+ }
+ }
+
+
+ /**
+ * @return Returns true if only array options are set.
+ */
+ public boolean isOnlyArrayOptions()
+ {
+ return (getOptions() &
+ ~(ARRAY | ARRAY_ORDERED | ARRAY_ALTERNATE | ARRAY_ALT_TEXT)) == 0;
+ }
+
+
+ /**
+ * @see Options#getValidOptions()
+ */
+ protected int getValidOptions()
+ {
+ return
+ URI |
+ HAS_QUALIFIERS |
+ QUALIFIER |
+ HAS_LANGUAGE |
+ HAS_TYPE |
+ STRUCT |
+ ARRAY |
+ ARRAY_ORDERED |
+ ARRAY_ALTERNATE |
+ ARRAY_ALT_TEXT |
+ COMPACT |
+ SCHEMA_NODE;
+ }
+
+
+ /**
+ * @see Options#defineOptionName(int)
+ */
+ protected String defineOptionName(int option)
+ {
+ switch (option)
+ {
+ case URI : return "URI";
+ case HAS_QUALIFIERS : return "HAS_QUALIFIER";
+ case QUALIFIER : return "QUALIFIER";
+ case HAS_LANGUAGE : return "HAS_LANGUAGE";
+ case HAS_TYPE: return "HAS_TYPE";
+ case STRUCT : return "STRUCT";
+ case ARRAY : return "ARRAY";
+ case ARRAY_ORDERED : return "ARRAY_ORDERED";
+ case ARRAY_ALTERNATE : return "ARRAY_ALTERNATE";
+ case ARRAY_ALT_TEXT : return "ARRAY_ALT_TEXT";
+ case COMPACT : return "COMPACT";
+ case SCHEMA_NODE : return "SCHEMA_NODE";
+ default: return null;
+ }
+ }
+
+
+ /**
+ * Checks that a node not a struct and array at the same time;
+ * and URI cannot be a struct.
+ *
+ * @param options the bitmask to check.
+ * @throws XMPException Thrown if the options are not consistent.
+ */
+ public void assertConsistency(int options) throws XMPException
+ {
+ if ((options & STRUCT) > 0 && (options & ARRAY) > 0)
+ {
+ throw new XMPException("IsStruct and IsArray options are mutually exclusive",
+ XMPError.BADOPTIONS);
+ }
+ else if ((options & URI) > 0 && (options & (ARRAY | STRUCT)) > 0)
+ {
+ throw new XMPException("Structs and arrays can't have \"value\" options",
+ XMPError.BADOPTIONS);
+ }
+ }
+} \ No newline at end of file
diff --git a/java/XMPCore/src/com/adobe/xmp/options/SerializeOptions.java b/java/XMPCore/src/com/adobe/xmp/options/SerializeOptions.java
new file mode 100644
index 0000000..c4d4f94
--- /dev/null
+++ b/java/XMPCore/src/com/adobe/xmp/options/SerializeOptions.java
@@ -0,0 +1,461 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+package com.adobe.xmp.options;
+
+import com.adobe.xmp.XMPException;
+import com.adobe.xmp.XMPMeta;
+import com.adobe.xmp.XMPMetaFactory;
+
+
+/**
+ * Options for {@link XMPMetaFactory#serializeToBuffer(XMPMeta, SerializeOptions)}.
+ *
+ * @since 24.01.2006
+ */
+public final class SerializeOptions extends Options
+{
+ /** Omit the XML packet wrapper. */
+ public static final int OMIT_PACKET_WRAPPER = 0x0010;
+ /** Mark packet as read-only. Default is a writeable packet. */
+ public static final int READONLY_PACKET = 0x0020;
+ /** Use a compact form of RDF. */
+ public static final int USE_COMPACT_FORMAT = 0x0040;
+ /**
+ * Include a padding allowance for a thumbnail image. If no <tt>xmp:Thumbnails</tt> property
+ * is present, the typical space for a JPEG thumbnail is used.
+ */
+ public static final int INCLUDE_THUMBNAIL_PAD = 0x0100;
+ /**
+ * The padding parameter provides the overall packet length. The actual amount of padding is
+ * computed. An exception is thrown if the packet exceeds this length with no padding.
+ */
+ public static final int EXACT_PACKET_LENGTH = 0x0200;
+ /** Show aliases as XML comments. <em>Note:</em> This option is currently not supported. */
+ public static final int WRITE_ALIAS_COMMENTS = 0x0400;
+ /** Sort the struct properties and qualifier before serializing */
+ public static final int SORT = 0x1000;
+
+ // ---------------------------------------------------------------------------------------------
+ // encoding bit constants
+
+ /** Bit indicating little endian encoding, unset is big endian */
+ private static final int LITTLEENDIAN_BIT = 0x0001;
+ /** Bit indication UTF16 encoding. */
+ private static final int UTF16_BIT = 0x0002;
+ /** UTF8 encoding; this is the default */
+ public static final int ENCODE_UTF8 = 0;
+ /** UTF16BE encoding */
+ public static final int ENCODE_UTF16BE = UTF16_BIT;
+ /** UTF16LE encoding */
+ public static final int ENCODE_UTF16LE = UTF16_BIT | LITTLEENDIAN_BIT;
+ /** */
+ private static final int ENCODING_MASK = UTF16_BIT | LITTLEENDIAN_BIT;
+
+ /**
+ * The amount of padding to be added if a writeable XML packet is created. If zero is passed
+ * (the default) an appropriate amount of padding is computed.
+ */
+ private int padding = 2048;
+ /**
+ * The string to be used as a line terminator. If empty it defaults to; linefeed, U+000A, the
+ * standard XML newline.
+ */
+ private String newline = "\n";
+ /**
+ * The string to be used for each level of indentation in the serialized
+ * RDF. If empty it defaults to two ASCII spaces, U+0020.
+ */
+ private String indent = " ";
+ /**
+ * The number of levels of indentation to be used for the outermost XML element in the
+ * serialized RDF. This is convenient when embedding the RDF in other text, defaults to 0.
+ */
+ private int baseIndent = 0;
+ /** Omits the Toolkit version attribute, not published, only used for Unit tests. */
+ private boolean omitVersionAttribute = false;
+
+
+ /**
+ * Default constructor.
+ */
+ public SerializeOptions()
+ {
+ // reveal default constructor
+ }
+
+
+ /**
+ * Constructor using inital options
+ * @param options the inital options
+ * @throws XMPException Thrown if options are not consistant.
+ */
+ public SerializeOptions(int options) throws XMPException
+ {
+ super(options);
+ }
+
+
+ /**
+ * @return Returns the option.
+ */
+ public boolean getOmitPacketWrapper()
+ {
+ return getOption(OMIT_PACKET_WRAPPER);
+ }
+
+
+ /**
+ * @param value the value to set
+ * @return Returns the instance to call more set-methods.
+ */
+ public SerializeOptions setOmitPacketWrapper(boolean value)
+ {
+ setOption(OMIT_PACKET_WRAPPER, value);
+ return this;
+ }
+
+
+ /**
+ * @return Returns the option.
+ */
+ public boolean getReadOnlyPacket()
+ {
+ return getOption(READONLY_PACKET);
+ }
+
+
+ /**
+ * @param value the value to set
+ * @return Returns the instance to call more set-methods.
+ */
+ public SerializeOptions setReadOnlyPacket(boolean value)
+ {
+ setOption(READONLY_PACKET, value);
+ return this;
+ }
+
+
+ /**
+ * @return Returns the option.
+ */
+ public boolean getUseCompactFormat()
+ {
+ return getOption(USE_COMPACT_FORMAT);
+ }
+
+
+ /**
+ * @param value the value to set
+ * @return Returns the instance to call more set-methods.
+ */
+ public SerializeOptions setUseCompactFormat(boolean value)
+ {
+ setOption(USE_COMPACT_FORMAT, value);
+ return this;
+ }
+
+ /**
+ * @return Returns the option.
+ */
+ public boolean getIncludeThumbnailPad()
+ {
+ return getOption(INCLUDE_THUMBNAIL_PAD);
+ }
+
+
+ /**
+ * @param value the value to set
+ * @return Returns the instance to call more set-methods.
+ */
+ public SerializeOptions setIncludeThumbnailPad(boolean value)
+ {
+ setOption(INCLUDE_THUMBNAIL_PAD, value);
+ return this;
+ }
+
+
+ /**
+ * @return Returns the option.
+ */
+ public boolean getExactPacketLength()
+ {
+ return getOption(EXACT_PACKET_LENGTH);
+ }
+
+
+ /**
+ * @param value the value to set
+ * @return Returns the instance to call more set-methods.
+ */
+ public SerializeOptions setExactPacketLength(boolean value)
+ {
+ setOption(EXACT_PACKET_LENGTH, value);
+ return this;
+ }
+
+
+ /**
+ * @return Returns the option.
+ */
+ public boolean getWriteAliasComments()
+ {
+ return getOption(WRITE_ALIAS_COMMENTS);
+ }
+
+
+ /**
+ * <em>Note:</em> This options is not supported at the moment.
+ * @param value the value to set
+ * @return Returns the instance to call more set-methods.
+ */
+ public SerializeOptions setWriteAliasComments(boolean value)
+ {
+ setOption(WRITE_ALIAS_COMMENTS, value);
+ return this;
+ }
+
+
+ /**
+ * @return Returns the option.
+ */
+ public boolean getSort()
+ {
+ return getOption(SORT);
+ }
+
+
+ /**
+ * @param value the value to set
+ * @return Returns the instance to call more set-methods.
+ */
+ public SerializeOptions setSort(boolean value)
+ {
+ setOption(SORT, value);
+ return this;
+ }
+
+
+ /**
+ * @return Returns the option.
+ */
+ public boolean getEncodeUTF16BE()
+ {
+ return (getOptions() & ENCODING_MASK) == ENCODE_UTF16BE;
+ }
+
+
+ /**
+ * @param value the value to set
+ * @return Returns the instance to call more set-methods.
+ */
+ public SerializeOptions setEncodeUTF16BE(boolean value)
+ {
+ // clear unicode bits
+ setOption(UTF16_BIT | LITTLEENDIAN_BIT, false);
+ setOption(ENCODE_UTF16BE, value);
+ return this;
+ }
+
+
+ /**
+ * @return Returns the option.
+ */
+ public boolean getEncodeUTF16LE()
+ {
+ return (getOptions() & ENCODING_MASK) == ENCODE_UTF16LE;
+ }
+
+
+ /**
+ * @param value the value to set
+ * @return Returns the instance to call more set-methods.
+ */
+ public SerializeOptions setEncodeUTF16LE(boolean value)
+ {
+ // clear unicode bits
+ setOption(UTF16_BIT | LITTLEENDIAN_BIT, false);
+ setOption(ENCODE_UTF16LE, value);
+ return this;
+ }
+
+
+ /**
+ * @return Returns the baseIndent.
+ */
+ public int getBaseIndent()
+ {
+ return baseIndent;
+ }
+
+
+ /**
+ * @param baseIndent
+ * The baseIndent to set.
+ * @return Returns the instance to call more set-methods.
+ */
+ public SerializeOptions setBaseIndent(int baseIndent)
+ {
+ this.baseIndent = baseIndent;
+ return this;
+ }
+
+
+ /**
+ * @return Returns the indent.
+ */
+ public String getIndent()
+ {
+ return indent;
+ }
+
+
+ /**
+ * @param indent
+ * The indent to set.
+ * @return Returns the instance to call more set-methods.
+ */
+ public SerializeOptions setIndent(String indent)
+ {
+ this.indent = indent;
+ return this;
+ }
+
+
+ /**
+ * @return Returns the newline.
+ */
+ public String getNewline()
+ {
+ return newline;
+ }
+
+
+ /**
+ * @param newline
+ * The newline to set.
+ * @return Returns the instance to call more set-methods.
+ */
+ public SerializeOptions setNewline(String newline)
+ {
+ this.newline = newline;
+ return this;
+ }
+
+
+ /**
+ * @return Returns the padding.
+ */
+ public int getPadding()
+ {
+ return padding;
+ }
+
+
+ /**
+ * @param padding
+ * The padding to set.
+ * @return Returns the instance to call more set-methods.
+ */
+ public SerializeOptions setPadding(int padding)
+ {
+ this.padding = padding;
+ return this;
+ }
+
+
+ /**
+ * @return Returns whether the Toolkit version attribute shall be omitted.
+ * <em>Note:</em> This options can only be set by unit tests.
+ */
+ public boolean getOmitVersionAttribute()
+ {
+ return omitVersionAttribute;
+ }
+
+
+ /**
+ * @return Returns the encoding as Java encoding String.
+ */
+ public String getEncoding()
+ {
+ if (getEncodeUTF16BE())
+ {
+ return "UTF-16BE";
+ }
+ else if (getEncodeUTF16LE())
+ {
+ return "UTF-16LE";
+ }
+ else
+ {
+ return "UTF-8";
+ }
+ }
+
+
+ /**
+ *
+ * @return Returns clone of this SerializeOptions-object with the same options set.
+ * @throws CloneNotSupportedException Cannot happen in this place.
+ */
+ public Object clone() throws CloneNotSupportedException
+ {
+ SerializeOptions clone;
+ try
+ {
+ clone = new SerializeOptions(getOptions());
+ clone.setBaseIndent(baseIndent);
+ clone.setIndent(indent);
+ clone.setNewline(newline);
+ clone.setPadding(padding);
+ return clone;
+ }
+ catch (XMPException e)
+ {
+ // This cannot happen, the options are already checked in "this" object.
+ return null;
+ }
+ }
+
+
+ /**
+ * @see Options#defineOptionName(int)
+ */
+ protected String defineOptionName(int option)
+ {
+ switch (option)
+ {
+ case OMIT_PACKET_WRAPPER : return "OMIT_PACKET_WRAPPER";
+ case READONLY_PACKET : return "READONLY_PACKET";
+ case USE_COMPACT_FORMAT : return "USE_COMPACT_FORMAT";
+ case INCLUDE_THUMBNAIL_PAD : return "INCLUDE_THUMBNAIL_PAD";
+ case EXACT_PACKET_LENGTH : return "EXACT_PACKET_LENGTH";
+ case WRITE_ALIAS_COMMENTS : return "WRITE_ALIAS_COMMENTS";
+ case SORT : return "NORMALIZED";
+ default: return null;
+ }
+ }
+
+
+ /**
+ * @see Options#getValidOptions()
+ */
+ protected int getValidOptions()
+ {
+ return
+ OMIT_PACKET_WRAPPER |
+ READONLY_PACKET |
+ USE_COMPACT_FORMAT |
+ INCLUDE_THUMBNAIL_PAD |
+ EXACT_PACKET_LENGTH |
+ WRITE_ALIAS_COMMENTS |
+ SORT;
+ }
+} \ No newline at end of file
diff --git a/java/XMPCore/src/com/adobe/xmp/options/package.html b/java/XMPCore/src/com/adobe/xmp/options/package.html
new file mode 100644
index 0000000..d2e56d0
--- /dev/null
+++ b/java/XMPCore/src/com/adobe/xmp/options/package.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+ <title>Package overview</title>
+</head>
+
+<body>
+ <p>Package containing the option classes.</p>
+ <p>These are used to configure diverse function calls of xmpcore:<p>
+ <ul>
+ <li>PropertyOptions - these are used to create properties and also to retrieve information about simple, array or struct properties, as well as qualifiers
+ <li>ParseOptions - used to configure the parsing of xmp metadata packets
+ <li>SerializationOptions - used to control the serialization of xmp metadata packets
+ <li>AliasOptions - used by XMPSchemaRegistry#registerAlias()
+ <li>IteratorOptions - used to set up an XMPIterator
+ <li>Options - the base class of all option classes
+ </ul>
+</body>
+</html>
diff --git a/java/XMPCore/src/com/adobe/xmp/package.html b/java/XMPCore/src/com/adobe/xmp/package.html
new file mode 100644
index 0000000..8afb896
--- /dev/null
+++ b/java/XMPCore/src/com/adobe/xmp/package.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+ <title>Package overview</title>
+</head>
+
+<body>
+ <p>Package containing the xmpcore interface.</p>
+</body>
+</html>
diff --git a/java/XMPCore/src/com/adobe/xmp/properties/XMPAliasInfo.java b/java/XMPCore/src/com/adobe/xmp/properties/XMPAliasInfo.java
new file mode 100644
index 0000000..5eb707e
--- /dev/null
+++ b/java/XMPCore/src/com/adobe/xmp/properties/XMPAliasInfo.java
@@ -0,0 +1,39 @@
+package com.adobe.xmp.properties;
+
+import com.adobe.xmp.options.AliasOptions;
+
+
+/**
+ * This interface is used to return info about an alias.
+ *
+ * @since 27.01.2006
+ */
+public interface XMPAliasInfo
+{
+ /**
+ * @return Returns Returns the namespace URI for the base property.
+ */
+ String getNamespace();
+
+
+ /**
+ * @return Returns the default prefix for the given base property.
+ */
+ String getPrefix();
+
+
+ /**
+ * @return Returns the path of the base property.
+ */
+ String getPropName();
+
+
+ /**
+ * @return Returns the kind of the alias. This can be a direct alias
+ * (ARRAY), a simple property to an ordered array
+ * (ARRAY_ORDERED), to an alternate array
+ * (ARRAY_ALTERNATE) or to an alternate text array
+ * (ARRAY_ALT_TEXT).
+ */
+ AliasOptions getAliasForm();
+} \ No newline at end of file
diff --git a/java/XMPCore/src/com/adobe/xmp/properties/XMPProperty.java b/java/XMPCore/src/com/adobe/xmp/properties/XMPProperty.java
new file mode 100644
index 0000000..ad0c075
--- /dev/null
+++ b/java/XMPCore/src/com/adobe/xmp/properties/XMPProperty.java
@@ -0,0 +1,40 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+package com.adobe.xmp.properties;
+
+import com.adobe.xmp.XMPMeta;
+import com.adobe.xmp.options.PropertyOptions;
+
+
+/**
+ * This interface is used to return a text property together with its and options.
+ *
+ * @since 23.01.2006
+ */
+public interface XMPProperty
+{
+ /**
+ * @return Returns the value of the property.
+ */
+ Object getValue();
+
+
+ /**
+ * @return Returns the options of the property.
+ */
+ PropertyOptions getOptions();
+
+
+ /**
+ * Only set by {@link XMPMeta#getLocalizedText(String, String, String, String)}.
+ * @return Returns the language of the alt-text item.
+ */
+ String getLanguage();
+}
diff --git a/java/XMPCore/src/com/adobe/xmp/properties/XMPPropertyInfo.java b/java/XMPCore/src/com/adobe/xmp/properties/XMPPropertyInfo.java
new file mode 100644
index 0000000..bf1150b
--- /dev/null
+++ b/java/XMPCore/src/com/adobe/xmp/properties/XMPPropertyInfo.java
@@ -0,0 +1,45 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+package com.adobe.xmp.properties;
+
+import com.adobe.xmp.options.PropertyOptions;
+
+
+/**
+ * This interface is used to return a property together with its path and namespace.
+ * It is returned when properties are iterated with the <code>XMPIterator</code>.
+ *
+ * @since 06.07.2006
+ */
+public interface XMPPropertyInfo extends XMPProperty
+{
+ /**
+ * @return Returns the namespace of the property
+ */
+ String getNamespace();
+
+
+ /**
+ * @return Returns the path of the property, but only if returned by the iterator.
+ */
+ String getPath();
+
+
+ /**
+ * @return Returns the value of the property.
+ */
+ Object getValue();
+
+
+ /**
+ * @return Returns the options of the property.
+ */
+ PropertyOptions getOptions();
+}
diff --git a/java/XMPCore/src/com/adobe/xmp/properties/package.html b/java/XMPCore/src/com/adobe/xmp/properties/package.html
new file mode 100644
index 0000000..19e7427
--- /dev/null
+++ b/java/XMPCore/src/com/adobe/xmp/properties/package.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+ <title>Package overview</title>
+</head>
+
+<body>
+ <p>Package containing the property information classes.</p>
+ <p>XMPProperty and XMPPropertyInfo are used to report properties when they are retrieved by get-methods or by the iterator.
+ XMPAliasInfo informs about a certain property-to-property alias.<p>
+</body>
+</html>
diff --git a/java/XMPCore/src/com/adobe/xmp/version.properties b/java/XMPCore/src/com/adobe/xmp/version.properties
new file mode 100644
index 0000000..0bc14bc
--- /dev/null
+++ b/java/XMPCore/src/com/adobe/xmp/version.properties
@@ -0,0 +1,15 @@
+# ==================================================================================================
+# ADOBE SYSTEMS INCORPORATED
+# Copyright 2006-2007 Adobe Systems Incorporated
+# All Rights Reserved
+#
+# NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+# of the Adobe license agreement accompanying it.
+# ==================================================================================================
+
+implementation.version Adobe XMP Core 4.1.1
+implementation.version.major 4
+implementation.version.minor 1
+implementation.version.micro 1
+implementation.version.engbuild 0
+implementation.version.debug true \ No newline at end of file
diff --git a/java/XMPCoreCoverage/.classpath b/java/XMPCoreCoverage/.classpath
new file mode 100644
index 0000000..d0eb651
--- /dev/null
+++ b/java/XMPCoreCoverage/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry combineaccessrules="false" kind="src" path="/XMPCore"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/java/XMPCoreCoverage/.project b/java/XMPCoreCoverage/.project
new file mode 100644
index 0000000..a494e1e
--- /dev/null
+++ b/java/XMPCoreCoverage/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>XMPCoreCoverage</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/java/XMPCoreCoverage/src/samples/XMPCoreCoverage.java b/java/XMPCoreCoverage/src/samples/XMPCoreCoverage.java
new file mode 100644
index 0000000..1f43833
--- /dev/null
+++ b/java/XMPCoreCoverage/src/samples/XMPCoreCoverage.java
@@ -0,0 +1,1073 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+package samples;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.PrintStream;
+import java.net.URI;
+import java.net.URL;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.SimpleTimeZone;
+import java.util.TimeZone;
+
+import com.adobe.xmp.XMPConst;
+import com.adobe.xmp.XMPDateTime;
+import com.adobe.xmp.XMPDateTimeFactory;
+import com.adobe.xmp.XMPException;
+import com.adobe.xmp.XMPIterator;
+import com.adobe.xmp.XMPMeta;
+import com.adobe.xmp.XMPMetaFactory;
+import com.adobe.xmp.XMPPathFactory;
+import com.adobe.xmp.XMPSchemaRegistry;
+import com.adobe.xmp.options.AliasOptions;
+import com.adobe.xmp.options.IteratorOptions;
+import com.adobe.xmp.options.ParseOptions;
+import com.adobe.xmp.options.PropertyOptions;
+import com.adobe.xmp.options.SerializeOptions;
+import com.adobe.xmp.properties.XMPAliasInfo;
+import com.adobe.xmp.properties.XMPProperty;
+import com.adobe.xmp.properties.XMPPropertyInfo;
+
+
+/**
+ * An example for XMPCore.
+ * It covers most of the functionality of XMPCore,
+ * but does not provide any meaningful workflow.
+ *
+ * @author smakswit
+ * @since 11.02.2007
+ */
+public class XMPCoreCoverage implements XMPCoreCoverageConst
+{
+ /** the log stream for all outputs */
+ private static PrintStream log;
+ /** shortcut for the schema registry */
+ private static XMPSchemaRegistry registry = XMPMetaFactory.getSchemaRegistry();
+
+
+ /**
+ * Runs the example
+ * @param args not used
+ */
+ public static void main(String[] args)
+ {
+ try
+ {
+ URL url = XMPCoreCoverage.class.getResource(".");
+ String filePath = "file:" + url.getPath().replaceFirst("/bin/", "/src/")
+ + "XMPCoreCoverage.log";
+ File file = new File (new URI(filePath));
+ file.createNewFile();
+ FileOutputStream out = new FileOutputStream(file);
+ log = new PrintStream(out);
+
+ println("XMPCoreCoverage starting " + new Date());
+ println("XMPCore Version: " + XMPMetaFactory.getVersionInfo());
+ println();
+
+
+ doCoreCoverage();
+
+
+ println(); println();
+ println("XMPCoreCoverage ending " + new Date());
+ }
+ catch (XMPException e)
+ {
+ println("Caught XMPException " + e.getErrorCode() + " : " +e.getMessage());
+ }
+ catch (Throwable e)
+ {
+ println("Caught Throwable '" + e.getMessage() + "'");
+ }
+ finally
+ {
+ if (log != null)
+ {
+ log.close();
+ }
+ }
+ }
+
+
+ /**
+ * Runs example functions that explain some features of XMPCore.
+ * @throws Exception Forwards exceptions
+ */
+ private static void doCoreCoverage() throws Exception
+ {
+ coverNamespaceRegistry();
+
+ coverAliasRegistry();
+
+ coverCreatingXMP();
+
+ XMPMeta meta = coverSetPropertyMethods();
+
+ coverGetPropertyMethods(meta);
+
+ coverExistingProperties(meta);
+
+ coverDeleteProperties(meta);
+
+ coverLocalisedProperties();
+
+ coverLiteralProperties();
+
+ coverParsing();
+
+ coverLinefeedValues();
+
+ coverSerialization();
+
+ coverIterator();
+
+ coverPathCreation();
+
+ coverDateTime();
+ }
+
+
+ /**
+ * List predefined namespaces and aliases;
+ * register new namespaces and aliases.
+ * @throws XMPException Forward exceptions
+ */
+ private static void coverNamespaceRegistry() throws XMPException
+ {
+ writeMajorLabel ("Test of namespace registry");
+
+ // Lists of predefined namespaces
+ writeMinorLabel ("List predefined namespaces");
+ Map namespaces = registry.getNamespaces();
+ for (Iterator it = namespaces.keySet().iterator(); it.hasNext();)
+ {
+ String prefix = (String) it.next();
+ String namespace = (String) namespaces.get(prefix);
+ println(prefix + " ---> " + namespace);
+ }
+ println();
+
+
+ // Registry namespace functions
+ writeMinorLabel ("Test namespace registry functions");
+
+ String prefix = registry.registerNamespace(NS1, "ns1");
+ println ("registerNamespace ns1: " + prefix + " ---> " +
+ registry.getNamespaceURI(prefix));
+
+ prefix = registry.registerNamespace(NS2, "ns2");
+ println ("registerNamespace ns2: " + prefix + " ---> " +
+ registry.getNamespaceURI(prefix));
+
+ prefix = registry.getNamespacePrefix(NS1);
+ println ("getNamespacePrefix ns1: " + prefix);
+
+ String ns = registry.getNamespaceURI("ns1");
+ println ("getNamespaceURI ns1: " + ns);
+
+ prefix = registry.getNamespacePrefix("bogus");
+ println ("getNamespacePrefix bogus: " + prefix);
+
+ ns = registry.getNamespaceURI("bogus");
+ println ("getNamespaceURI ns1: " + ns);
+ }
+
+
+ /**
+ * List predefined aliases, register new aliases and resolve aliases.
+ * @throws XMPException Forward exceptions
+ */
+ private static void coverAliasRegistry() throws XMPException
+ {
+ writeMajorLabel ("Test alias registry and functions");
+ dumpAliases();
+
+ // Register new aliases
+ writeMinorLabel ("Add ns2: to ns1: aliases");
+
+ registry.registerAlias (NS2, "SimpleAlias", NS1, "SimpleActual", null);
+
+ registry.registerAlias (NS2, "BagAlias", NS1, "BagActual", null);
+ registry.registerAlias (NS2, "SeqAlias", NS1, "SeqActual", null);
+ registry.registerAlias (NS2, "AltAlias", NS1, "AltActual", null);
+ registry.registerAlias (NS2, "AltTextAlias", NS1, "AltTextActual", null);
+
+ registry.registerAlias (NS2, "BagItemAlias", NS1, "BagActual",
+ new AliasOptions().setArray(true));
+ registry.registerAlias (NS2, "SeqItemAlias", NS1, "SeqActual",
+ new AliasOptions().setArrayOrdered(true));
+ registry.registerAlias (NS2, "AltItemAlias", NS1, "AltActual",
+ new AliasOptions().setArrayAlternate(true));
+ registry.registerAlias (NS2, "AltTextItemAlias", NS1, "AltTextActual",
+ new AliasOptions().setArrayAltText(true));
+
+ dumpAliases();
+
+
+ // Resolve aliases
+ writeMinorLabel ("Resolve ns2: to ns1: aliases");
+
+ XMPAliasInfo aliasInfo = registry.resolveAlias (NS1, "SimpleActual");
+ println ("resolveAlias ns1:SimpleActual: " + aliasInfo + " (wrong way!)");
+
+ aliasInfo = registry.resolveAlias (NS2, "SimpleAlias");
+ println ("resolveAlias ns2:SimpleAlias: " + aliasInfo);
+ println();
+
+
+ aliasInfo = registry.resolveAlias (NS2, "BagAlias");
+ println ("resolveAlias ns2:BagAlias: " + aliasInfo);
+
+ aliasInfo = registry.resolveAlias (NS2, "SeqAlias");
+ println ("resolveAlias ns2:SeqAlias: " + aliasInfo);
+
+ aliasInfo = registry.resolveAlias (NS2, "AltAlias");
+ println ("resolveAlias ns2:AltAlias: " + aliasInfo);
+
+ aliasInfo = registry.resolveAlias (NS2, "AltTextAlias");
+ println ("resolveAlias ns2:AltTextAlias: " + aliasInfo);
+ println();
+
+
+ aliasInfo = registry.resolveAlias (NS2, "BagItemAlias");
+ println ("resolveAlias ns2:BagItemAlias: " + aliasInfo);
+
+ aliasInfo = registry.resolveAlias (NS2, "SeqItemAlias");
+ println ("resolveAlias ns2:SeqItemAlias: " + aliasInfo);
+
+ aliasInfo = registry.resolveAlias (NS2, "AltItemAlias");
+ println ("resolveAlias ns2:AltItemAlias: " + aliasInfo);
+
+ aliasInfo = registry.resolveAlias (NS2, "AltTextItemAlias");
+ println ("resolveAlias ns2:AltTextItemAlias: " + aliasInfo);
+ println();
+
+
+ // set alias properties
+ writeMinorLabel ("Test setProperty through ns2: simple aliases");
+
+ XMPMeta meta = XMPMetaFactory.create();
+ meta.setProperty (NS2, "SimpleAlias", "Simple value");
+ meta.setProperty (NS2, "ns2:BagItemAlias", "BagItem value");
+ meta.setProperty (NS2, "SeqItemAlias", "SeqItem value");
+ meta.setProperty (NS2, "AltItemAlias", "AltItem value");
+ meta.setProperty (NS2, "AltTextItemAlias", "AltTextItem value");
+ printXMPMeta(meta, "Check for aliases and bases");
+
+
+ // delete aliases
+ writeMinorLabel ("Delete some ns2: to ns1: aliases");
+
+ registry.deleteAlias (NS2, "ns2:SimpleAlias");
+ registry.deleteAlias (NS2, "SeqAlias");
+ registry.deleteAlias (NS2, "AltAlias");
+ registry.deleteAlias (NS2, "SeqItemAlias");
+ registry.deleteAlias (NS2, "AltItemAlias");
+
+ dumpAliases();
+ }
+
+
+ /**
+ * Test simple constructors and parsing, setting the instance ID
+ * @throws XMPException Forwards exceptions
+ */
+ private static void coverCreatingXMP() throws XMPException
+ {
+ writeMajorLabel ("Test simple constructors and parsing, setting the instance ID");
+
+ XMPMeta meta1 = XMPMetaFactory.create();
+ printXMPMeta(meta1, "Empty XMP object");
+
+ XMPMeta meta2 = XMPMetaFactory.create();
+ meta2.setObjectName("New object name");
+ printXMPMeta(meta2, "XMP object with name");
+
+ XMPMeta meta3 = XMPMetaFactory.parseFromString(RDF_COVERAGE);
+ printXMPMeta(meta3, "Construct and parse from buffer");
+
+ meta3.setProperty (XMPConst.NS_XMP_MM, "InstanceID", "meta2:Original");
+ printXMPMeta(meta3, "Add instance ID");
+
+ XMPMeta meta4 = (XMPMeta) meta3.clone();
+ meta4.setProperty (XMPConst.NS_XMP_MM, "InstanceID", "meta2:Clone");
+ printXMPMeta(meta3, "Clone and add instance ID");
+ }
+
+
+ /**
+ * Cover some basid set calls (including arrays and structs).
+ * @return Returns an <code>XMPMeta</code> object that is reused in the next examples.
+ * @throws XMPException Forwards Exceptions
+ */
+ private static XMPMeta coverSetPropertyMethods() throws XMPException
+ {
+ // Basic set/get methods
+ writeMajorLabel ("Test setProperty and related methods");
+
+ XMPMeta meta = XMPMetaFactory.create();
+ meta.setProperty (NS1, "Prop", "Prop value");
+ meta.setProperty (NS1, "ns1:XMLProp", "<PropValue/>");
+ meta.setProperty (NS1, "ns1:URIProp", "URI:value/", new PropertyOptions().setURI(true));
+
+ meta.appendArrayItem(NS1, "Bag", new PropertyOptions().setArray(true), "BagItem value",
+ null);
+ meta.appendArrayItem(NS1, "ns1:Seq", new PropertyOptions().setArrayOrdered(true),
+ "SeqItem value", null);
+ meta.appendArrayItem(NS1, "ns1:Alt", new PropertyOptions().setArrayAlternate(true),
+ "AltItem value", null);
+
+ meta.setArrayItem (NS1, "Bag", 1, "BagItem 3");
+ meta.insertArrayItem (NS1, "ns1:Bag", 1, "BagItem 1");
+ meta.insertArrayItem (NS1, "ns1:Bag", 2, "BagItem 2");
+ meta.appendArrayItem (NS1, "Bag", "BagItem 4");
+
+ meta.setStructField (NS1, "Struct", NS2, "Field1", "Field1 value");
+ meta.setStructField (NS1, "ns1:Struct", NS2, "Field2", "Field2 value");
+ meta.setStructField (NS1, "ns1:Struct", NS2, "Field3", "Field3 value");
+
+ printXMPMeta(meta, "A few basic set property calls");
+
+ // -----------------------------------------------------------------------------------------
+
+ // Add some properties with qualifier
+ writeMinorLabel ("Add some properties with qualifier");
+ println ("CountArrayItems Bag = " + meta.countArrayItems(NS1, "Bag"));
+
+ meta.setProperty (NS1, "QualProp1", "Prop value");
+ meta.setQualifier (NS1, "QualProp1", NS2, "Qual1", "Qual1 value");
+ meta.setProperty (NS1, "QualProp1/?ns2:Qual3", "Qual3 value");
+ meta.setProperty (NS1, "QualProp1/?xml:lang", "x-qual");
+
+ meta.setProperty (NS1, "QualProp2", "Prop value");
+ meta.setQualifier (NS1, "QualProp2", XMPConst.NS_XML, "lang", "en-us");
+ meta.setProperty (NS1, "QualProp2/@xml:lang", "x-attr");
+
+ meta.setProperty (NS1, "QualProp3", "Prop value");
+ meta.setQualifier (NS1, "ns1:QualProp3", XMPConst.NS_XML, "xml:lang", "en-us");
+ meta.setQualifier (NS1, "ns1:QualProp3", NS2, "ns2:Qual", "Qual value");
+
+ meta.setProperty (NS1, "QualProp4", "Prop value");
+ meta.setQualifier (NS1, "QualProp4", NS2, "Qual", "Qual value");
+ meta.setQualifier (NS1, "QualProp4", XMPConst.NS_XML, "lang", "en-us");
+ printXMPMeta(meta, "Add some qualifiers");
+
+ meta.setProperty (NS1, "QualProp1", "new value");
+ meta.setProperty (NS1, "QualProp2", "new value");
+ meta.setProperty (NS1, "QualProp3", "new value");
+ meta.setProperty (NS1, "QualProp4", "new value");
+ printXMPMeta (meta, "Change values and keep qualifiers");
+
+ return meta;
+ }
+
+
+ /**
+ * Test getProperty, deleteProperty and related methods.
+ * @param meta a predefined <code>XMPMeta</code> object.
+ * @throws XMPException Forwards exceptions
+ */
+ private static void coverGetPropertyMethods(XMPMeta meta) throws XMPException
+ {
+ writeMajorLabel ("Test getProperty, deleteProperty and related methods");
+
+ meta.deleteProperty (NS1, "QualProp1"); // ! Start with fresh qualifiers.
+ meta.deleteProperty (NS1, "ns1:QualProp2");
+ meta.deleteProperty (NS1, "ns1:QualProp3");
+ meta.deleteProperty (NS1, "QualProp4");
+
+
+ writeMinorLabel("Set properties with qualifier");
+
+ meta.setProperty (NS1, "QualProp1", "Prop value");
+ meta.setQualifier (NS1, "QualProp1", NS2, "Qual1", "Qual1 value");
+
+ meta.setProperty (NS1, "QualProp2", "Prop value");
+ meta.setQualifier (NS1, "QualProp2", XMPConst.NS_XML, "lang", "en-us");
+
+ meta.setProperty (NS1, "QualProp3", "Prop value");
+ meta.setQualifier (NS1, "QualProp3", XMPConst.NS_XML, "lang", "en-us");
+ meta.setQualifier (NS1, "QualProp3", NS2, "Qual", "Qual value");
+
+ meta.setProperty (NS1, "QualProp4", "Prop value");
+ meta.setQualifier (NS1, "QualProp4", NS2, "Qual", "Qual value");
+ meta.setQualifier (NS1, "QualProp4", XMPConst.NS_XML, "lang", "en-us");
+
+ printXMPMeta (meta, "XMP object");
+
+
+ writeMinorLabel("Get simple properties");
+
+ XMPProperty property = meta.getProperty(NS1, "Prop");
+ println("getProperty ns1:Prop = " + property.getValue() + " (" + property.getOptions().getOptionsString() + ")");
+
+ property = meta.getProperty(NS1, "ns1:XMLProp");
+ println("getProperty ns1:XMLProp = " + property.getValue() + " (" + property.getOptions().getOptionsString() + ")");
+
+ property = meta.getProperty(NS1, "ns1:URIProp");
+ println("getProperty ns1:URIProp = " + property.getValue() + " (" + property.getOptions().getOptionsString() + ")");
+
+ property = meta.getArrayItem(NS1, "Bag", 2);
+ println("getArrayItem ns1:Bag[2] = " + property.getValue() + " (" + property.getOptions().getOptionsString() + ")");
+
+ try
+ {
+ meta.getArrayItem(null, "ns1:Bag", 1);
+ }
+ catch (XMPException e)
+ {
+ println("getArrayItem with no schema URI - threw XMPException #" + e.getErrorCode() +" : " + e.getMessage() + ")");
+ }
+
+
+ writeMinorLabel("Get array items and struct fields");
+
+ property = meta.getArrayItem(NS1, "ns1:Seq", 1);
+ println("getArrayItem ns1:Seq[1] = " + property.getValue() + " (" + property.getOptions().getOptionsString() + ")");
+
+ property = meta.getArrayItem(NS1, "ns1:Alt", 1);
+ println("getArrayItem ns1:Alt[1] = " + property.getValue() + " (" + property.getOptions().getOptionsString() + ")");
+ println();
+
+ property = meta.getStructField(NS1, "Struct", NS2, "Field1");
+ println("getStructField ns1:Struct/ns2:Field1 = " + property.getValue() + " (" + property.getOptions().getOptionsString() + ")");
+
+ property = meta.getStructField(NS1, "ns1:Struct", NS2, "Field2");
+ println("getStructField ns1:Struct/ns2:Field2 = " + property.getValue() + " (" + property.getOptions().getOptionsString() + ")");
+
+ property = meta.getStructField(NS1, "ns1:Struct", NS2, "ns2:Field3");
+ println("getStructField ns1:Struct/ns2:Field3 = " + property.getValue() + " (" + property.getOptions().getOptionsString() + ")");
+
+ property = meta.getStructField(NS1, "ns1:Struct", NS2, "ns2:Field3");
+ println("getStructField ns1:Struct/ns2:Field3 = " + property.getValue() + " (" + property.getOptions().getOptionsString() + ")");
+
+ property = meta.getStructField(NS1, "ns1:Struct", NS2, "ns2:Field3");
+ println("getStructField ns1:Struct/ns2:Field3 = " + property.getValue() + " (" + property.getOptions().getOptionsString() + ")");
+ println();
+
+
+ writeMinorLabel("Get qualifier");
+
+ property = meta.getQualifier(NS1, "QualProp1", NS2, "Qual1");
+ println("getQualifier ns1:QualProp1/?ns2:Qual1 = " + property.getValue() + " (" + property.getOptions().getOptionsString() + ")");
+
+ try
+ {
+ meta.getQualifier(null, "ns1:QualProp1", NS2, "Qual1");
+ }
+ catch (XMPException e)
+ {
+ println("getQualifier with no schema URI - threw XMPException #" + e.getErrorCode() + " : " + e.getMessage());
+ }
+
+ property = meta.getQualifier(NS1, "QualProp3", XMPConst.NS_XML, "xml:lang");
+ println("getQualifier ns1:QualProp3/@xml-lang = " + property.getValue() + " (" + property.getOptions().getOptionsString() + ")");
+
+ property = meta.getQualifier(NS1, "QualProp3", NS2, "ns2:Qual");
+ println("getQualifier ns1:QualProp3/?ns2:Qual = " + property.getValue() + " (" + property.getOptions().getOptionsString() + ")");
+ println();
+
+
+ writeMinorLabel("Get non-simple properties");
+
+ property = meta.getProperty(NS1, "Bag");
+ println("getProperty ns1:Bag = " + property.getValue() + " ("
+ + property.getOptions().getOptionsString() + ")");
+
+ property = meta.getProperty(NS1, "Seq");
+ println("getProperty ns1:Seq = " + property.getValue() + " ("
+ + property.getOptions().getOptionsString() + ")");
+
+ property = meta.getProperty(NS1, "Alt");
+ println("getProperty ns1:Alt = " + property.getValue() + " ("
+ + property.getOptions().getOptionsString() + ")");
+
+ property = meta.getProperty(NS1, "Struct");
+ println("getProperty ns1:Struct = " + property.getValue() + " ("
+ + property.getOptions().getOptionsString() + ")");
+ println();
+
+
+ writeMinorLabel("Get not existing properties");
+
+ try
+ {
+ meta.getProperty("ns:bogus/", "Bogus");
+ }
+ catch (XMPException e)
+ {
+ println("getProperty with bogus schema URI - threw XMPException #" + e.getErrorCode() + " : " + e.getMessage());
+ }
+
+ property = meta.getProperty (NS1, "Bogus");
+ println ("getProperty ns1:Bogus (not existing) = " + property);
+
+ property = meta.getArrayItem(NS1, "Bag", 99);
+ println ("ArrayItem ns1:Bag[99] (not existing) = " + property);
+
+ property = meta.getStructField(NS1, "Struct", NS2, "Bogus");
+ println ("getStructField ns1:Struct/ns2:Bogus (not existing) = " + property);
+
+ property = meta.getQualifier (NS1, "Prop", NS2, "Bogus");
+ println ("getQualifier ns1:Prop/?ns2:Bogus (not existing) = " + property);
+ }
+
+
+ /**
+ * Test doesPropertyExist, deleteProperty, and related methods.
+ * @param meta a predefined <code>XMPMeta</code> object.
+ */
+ private static void coverExistingProperties(XMPMeta meta)
+ {
+ writeMajorLabel ("Test doesPropertyExist, deleteProperty, and related methods");
+
+ printXMPMeta (meta, "XMP object");
+
+ println("doesPropertyExist ns1:Prop = " + meta.doesPropertyExist(NS1, "Prop"));
+ println("doesPropertyExist ns1:Struct = " + meta.doesPropertyExist(NS1, "ns1:Struct"));
+ println("doesArrayItemExist ns1:Bag[2] = " + meta.doesArrayItemExist(NS1, "Bag", 2));
+ println("doesArrayItemExist ns1:Seq[last()] = "
+ + meta.doesArrayItemExist(NS1, "ns1:Seq", XMPConst.ARRAY_LAST_ITEM));
+ println("doesStructFieldExist ns1:Struct/ns2:Field1 = "
+ + meta.doesStructFieldExist(NS1, "Struct", NS2, "Field1"));
+ println("doesQualifierExist ns1:QualProp1/?ns2:Qual1 = "
+ + meta.doesQualifierExist(NS1, "QualProp1", NS2, "Qual1"));
+ println("doesQualifierExist ns1:QualProp2/?xml:lang = "
+ + meta.doesQualifierExist(NS1, "QualProp2", XMPConst.NS_XML, "lang"));
+ println();
+ println("doesPropertyExist (namespace is null) = "
+ + meta.doesPropertyExist(null, "ns1:Bag"));
+ println("doesArrayItemExist (namespace is null) = "
+ + meta.doesArrayItemExist(null, "ns1:Bag", XMPConst.ARRAY_LAST_ITEM));
+ println("doesQualifierExist ns:Bogus (namespace not existing) = "
+ + meta.doesPropertyExist("ns:bogus/", "Bogus"));
+ println("doesPropertyExist ns1:Bogus = " + meta.doesPropertyExist(NS1, "Bogus"));
+ println("doesArrayItemExist ns1:Bag[99] = " + meta.doesArrayItemExist(NS1, "Bag", 99));
+ println("doesStructFieldExist ns1:Struct/ns2:Bogus = "
+ + meta.doesStructFieldExist(NS1, "Struct", NS2, "Bogus"));
+ println("doesQualifierExist ns1:Prop/?ns2:Bogus = "
+ + meta.doesQualifierExist(NS1, "Prop", NS2, "Bogus"));
+ }
+
+
+ /**
+ * Tests deletion of properties, array items, struct fields and qualifer.
+ * @param meta a predefined <code>XMPMeta</code> object.
+ */
+ private static void coverDeleteProperties(XMPMeta meta)
+ {
+ writeMajorLabel("Test deleteProperty");
+
+ meta.deleteProperty (NS1, "Prop");
+ meta.deleteArrayItem (NS1, "Bag", 2);
+ meta.deleteStructField (NS1, "Struct", NS2, "Field1");
+
+ printXMPMeta (meta, "Delete Prop, Bag[2], and Struct1/Field1");
+
+ meta.deleteQualifier (NS1, "QualProp1", NS2, "Qual1");
+ meta.deleteQualifier (NS1, "QualProp2", XMPConst.NS_XML, "lang");
+ meta.deleteQualifier (NS1, "QualProp3", NS2, "Qual");
+ meta.deleteQualifier (NS1, "QualProp4", XMPConst.NS_XML, "lang");
+
+ printXMPMeta(meta,
+ "Delete QualProp1/?ns2:Qual1, QualProp2/?xml:lang, " +
+ "QualProp3:/ns2:Qual, and QualProp4/?xml:lang");
+
+ meta.deleteProperty (NS1, "Bag");
+ meta.deleteProperty (NS1, "Struct");
+
+ printXMPMeta (meta, "Delete all of Bag and Struct");
+ }
+
+
+ /**
+ * Localized text set/get methods.
+ * @throws XMPException Forwards exceptions
+ */
+ private static void coverLocalisedProperties() throws XMPException
+ {
+ writeMajorLabel ("Test setLocalizedText and getLocalizedText");
+
+ XMPMeta meta = XMPMetaFactory.create();
+ meta.setLocalizedText (NS1, "AltText", "", "x-default", "default value");
+ printXMPMeta (meta, "Set x-default value");
+
+ meta.setLocalizedText (NS1, "AltText", "en", "en-us", "en-us value");
+ printXMPMeta (meta, "Set en/en-us value");
+
+ meta.setLocalizedText (NS1, "AltText", "en", "en-uk", "en-uk value");
+ printXMPMeta (meta, "Set en/en-uk value");
+ println();
+
+ XMPProperty property = meta.getLocalizedText(NS1, "AltText", "en", "en-ca");
+ println("getLocalizedText en/en-ca = " + property.getValue() + " (lang: " + property.getLanguage() + ", opt: " + property.getOptions().getOptionsString() + ")");
+
+ property = meta.getProperty(NS1, "AltText");
+ println("getProperty ns1:AltText = " + property.getValue() + " (lang: " + property.getLanguage() + ", opt: " + property.getOptions().getOptionsString() + ")");
+ }
+
+
+ /**
+ * Literal value set/get methods
+ * @throws XMPException
+ */
+ private static void coverLiteralProperties() throws XMPException
+ {
+ writeMajorLabel("Test setProperty... and getProperty... methods " +
+ "(set/get with literal values)");
+
+ XMPMeta meta = XMPMetaFactory.parseFromString(DATETIME_RDF);
+ XMPDateTime dateValue = XMPDateTimeFactory.create(2000, 1, 2, 3, 4, 5, 0);
+
+ meta.setPropertyBoolean (NS1, "Bool0", false);
+ meta.setPropertyBoolean (NS1, "Bool1", true);
+ meta.setPropertyInteger (NS1, "Int", 42);
+ meta.setPropertyDouble (NS1, "Double", 4.2);
+
+ meta.setPropertyDate (NS1, "Date10", dateValue);
+ int offset = (/* hour */ 06 * 3600 * 1000 + /* minute */ 07 * 60 * 1000) * /* sign */ 1;
+ dateValue.setTimeZone(new SimpleTimeZone(offset, "test"));
+ meta.setPropertyDate (NS1, "Date11", dateValue);
+ offset *= -1;
+ dateValue.setTimeZone(new SimpleTimeZone(offset, "test"));
+ meta.setPropertyDate (NS1, "Date12", dateValue);
+ dateValue.setNanoSecond(9);
+ meta.setPropertyDate (NS1, "Date13", dateValue);
+
+ printXMPMeta (meta, "A few basic binary Set... calls");
+ println();
+
+ Boolean bool = meta.getPropertyBoolean(NS1, "Bool0");
+ println ("getPropertyBoolean ns1:Bool0 = " + bool);
+
+ bool = meta.getPropertyBoolean(NS1, "Bool1");
+ println ("getPropertyBoolean ns1:Bool1 = " + bool);
+
+ Integer integer = meta.getPropertyInteger(NS1, "Int");
+ println ("getPropertyBoolean ns1:Int = " + integer);
+
+ Double d = meta.getPropertyDouble(NS1, "Double");
+ println ("getPropertyBoolean ns1:Int = " + d);
+ println();
+
+ for (int i = 1; i <= 13; i++)
+ {
+ String dateName = "Date" + i;
+ XMPDateTime dt = meta.getPropertyDate (NS1, dateName);
+ println ("getPropertyDate (" + i + ") = " + dt);
+ meta.setPropertyDate (NS2, dateName, dateValue);
+ }
+
+ printXMPMeta (meta, "Get and re-set the dates in NS2");
+ }
+
+
+ /**
+ * Parse and serialize methods.
+ * @throws XMPException Forwards exceptions
+ */
+ private static void coverParsing() throws XMPException
+ {
+ writeMajorLabel ("Test parsing with multiple buffers and various options");
+
+ XMPMeta meta = XMPMetaFactory.parseFromString(SIMPLE_RDF);
+ printXMPMeta (meta, "Parse from String");
+
+ meta = XMPMetaFactory.parseFromString(SIMPLE_RDF, new ParseOptions()
+ .setRequireXMPMeta(true));
+ printXMPMeta(meta, "Parse and require xmpmeta element, which is missing");
+
+ meta = XMPMetaFactory.parseFromString(NAMESPACE_RDF);
+ printXMPMeta(meta, "Parse RDF with multiple nested namespaces");
+
+ meta = XMPMetaFactory.parseFromString(XMPMETA_RDF, new ParseOptions()
+ .setRequireXMPMeta(true));
+ printXMPMeta(meta, "Parse and require xmpmeta element, which is present");
+
+ meta = XMPMetaFactory.parseFromString(INCONSISTENT_RDF);
+ printXMPMeta(meta, "Parse and reconcile inconsistent aliases");
+
+ try
+ {
+ XMPMetaFactory.parseFromString(INCONSISTENT_RDF, new ParseOptions()
+ .setStrictAliasing(true));
+ }
+ catch (XMPException e)
+ {
+ println("Parse and do not reconcile inconsistent aliases - threw XMPException #" + e.getErrorCode() + " : " + e.getMessage());
+ }
+ }
+
+
+ /**
+ * Test CR and LF in values.
+ * @throws XMPException Forwards exceptions
+ */
+ private static void coverLinefeedValues() throws XMPException
+ {
+ writeMajorLabel ("Test CR and LF in values");
+
+ String valueWithCR = "ASCII \r CR";
+ String valueWithLF = "ASCII \n LF";
+ String valueWithCRLF = "ASCII \r\n CRLF";
+
+ XMPMeta meta = XMPMetaFactory.parseFromString(NEWLINE_RDF);
+
+ meta.setProperty (NS2, "HasCR", valueWithCR);
+ meta.setProperty (NS2, "HasLF", valueWithLF);
+ meta.setProperty (NS2, "HasCRLF", valueWithCRLF);
+
+ String result = XMPMetaFactory.serializeToString(meta, new SerializeOptions()
+ .setOmitPacketWrapper(true));
+ println(result);
+
+ String hasCR = meta.getPropertyString (NS1, "HasCR");
+ String hasCR2 = meta.getPropertyString (NS2, "HasCR");
+ String hasLF = meta.getPropertyString (NS1, "HasLF");
+ String hasLF2 = meta.getPropertyString (NS2, "HasLF");
+ String hasCRLF = meta.getPropertyString (NS1, "HasCRLF");
+ String hasCRLF2 = meta.getPropertyString (NS2, "HasCRLF");
+ if (hasCR.equals(valueWithCR) && hasCR2.equals(valueWithCR) &&
+ hasLF.equals(valueWithLF) && hasLF2.equals(valueWithLF) &&
+ hasCRLF.equals(valueWithCRLF) && hasCRLF2.equals(valueWithCRLF))
+ {
+ println();
+ println("\n## HasCR and HasLF and HasCRLF correctly retrieved\n");
+ }
+ }
+
+
+ /**
+ * Covers the serialization of an <code>XMPMeta</code> object with different options.
+ * @throws Exception Forwards exceptions
+ */
+ private static void coverSerialization() throws Exception
+ {
+ writeMajorLabel ("Test serialization with various options");
+
+ XMPMeta meta = XMPMetaFactory.parseFromString(SIMPLE_RDF);
+ meta.setProperty (NS2, "Another", "Something in another schema");
+ meta.setProperty (NS2, "Yet/pdf:More", "Yet more in another schema");
+
+ printXMPMeta (meta, "Parse simple RDF, serialize with various options");
+
+ writeMinorLabel ("Default serialize");
+ println(XMPMetaFactory.serializeToString(meta, null));
+
+ writeMinorLabel ("Compact RDF, no packet serialize");
+ println(XMPMetaFactory.serializeToString(meta, new SerializeOptions().setUseCompactFormat(
+ true).setOmitPacketWrapper(true)));
+
+ writeMinorLabel ("Read-only serialize");
+ println(XMPMetaFactory.serializeToString(meta, new SerializeOptions()
+ .setReadOnlyPacket(true)));
+
+ writeMinorLabel ("Alternate newline serialize");
+ println(XMPMetaFactory.serializeToString(meta, new SerializeOptions().setNewline(
+ "<--newline-->\n").setOmitPacketWrapper(true)));
+
+ writeMinorLabel ("Alternate indent serialize");
+ println(XMPMetaFactory.serializeToString(meta, new SerializeOptions().setIndent("-->")
+ .setBaseIndent(5).setOmitPacketWrapper(true)));
+
+ writeMinorLabel ("Small padding serialize");
+ println(XMPMetaFactory.serializeToString(meta, new SerializeOptions().setPadding(10)));
+
+ writeMinorLabel ("Serialize with exact packet size");
+ int s = XMPMetaFactory.serializeToBuffer(meta, new SerializeOptions()
+ .setReadOnlyPacket(true)).length;
+ println ("Minimum packet size is " + s + " bytes\n");
+
+ // with the flag "exact packet size" the padding becomes the overall length of the packet
+ byte[] buffer = XMPMetaFactory.serializeToBuffer(meta, new SerializeOptions()
+ .setExactPacketLength(true).setPadding(s));
+ println(new String(buffer, "UTF-8"));
+
+ try
+ {
+ XMPMetaFactory.parseFromString(XMPMetaFactory.serializeToString(meta,
+ new SerializeOptions().setExactPacketLength(true).setPadding(s - 1)));
+ }
+ catch (XMPException e)
+ {
+ println("\nExact packet size smaller than minimal packet length - " +
+ "threw XMPException #" + e.getErrorCode() + " : " + e.getMessage());
+ }
+ }
+
+
+ /**
+ * Cover different use cases of the <code>XMPIterator</code>.
+ * @throws XMPException Forwards exceptions
+ */
+ private static void coverIterator() throws XMPException
+ {
+ writeMajorLabel ("Test iteration methods");
+
+ XMPMeta meta = XMPMetaFactory.parseFromString(RDF_COVERAGE);
+ meta.setProperty (NS2, "Prop", "Prop value");
+ meta.appendArrayItem (NS2, "Bag", new PropertyOptions().setArray(true),
+ "BagItem 2", null);
+ meta.appendArrayItem(NS2, "Bag", "BagItem 1");
+ meta.appendArrayItem(NS2, "Bag", "BagItem 3");
+
+ printXMPMeta (meta, "Parse \"coverage\" RDF, add Bag items out of order");
+
+ writeMinorLabel ("Default iteration");
+ for (XMPIterator it = meta.iterator(); it.hasNext();)
+ {
+ XMPPropertyInfo prop = (XMPPropertyInfo) it.next();
+ printPropertyInfo(prop);
+ }
+
+ writeMinorLabel ("Iterate omitting qualifiers");
+ for (XMPIterator it = meta.iterator(new IteratorOptions().setOmitQualifiers(true)); it
+ .hasNext();)
+ {
+ XMPPropertyInfo prop = (XMPPropertyInfo) it.next();
+ printPropertyInfo(prop);
+ }
+
+ writeMinorLabel("Iterate with just leaf names");
+ for (XMPIterator it = meta.iterator(new IteratorOptions().setJustLeafname(true)); it
+ .hasNext();)
+ {
+ XMPPropertyInfo prop = (XMPPropertyInfo) it.next();
+ printPropertyInfo(prop);
+ }
+
+ writeMinorLabel("Iterate with just leaf nodes");
+ for (XMPIterator it = meta.iterator(new IteratorOptions().setJustLeafnodes(true)); it
+ .hasNext();)
+ {
+ XMPPropertyInfo prop = (XMPPropertyInfo) it.next();
+ printPropertyInfo(prop);
+ }
+
+ writeMinorLabel("Iterate just the schema nodes");
+ for (XMPIterator it = meta.iterator(new IteratorOptions().setJustChildren(true)); it
+ .hasNext();)
+ {
+ XMPPropertyInfo prop = (XMPPropertyInfo) it.next();
+ printPropertyInfo(prop);
+ }
+
+ writeMinorLabel("Iterate the ns2: namespace");
+ for (XMPIterator it = meta.iterator(NS2, null, null); it.hasNext();)
+ {
+ XMPPropertyInfo prop = (XMPPropertyInfo) it.next();
+ printPropertyInfo(prop);
+ }
+
+ writeMinorLabel("Start at ns2:Bag");
+ for (XMPIterator it = meta.iterator(NS2, "Bag", null); it.hasNext();)
+ {
+ XMPPropertyInfo prop = (XMPPropertyInfo) it.next();
+ printPropertyInfo(prop);
+ }
+
+ writeMinorLabel("Start at ns2:NestedStructProp/ns1:Outer");
+ for (XMPIterator it = meta.iterator(NS2, "NestedStructProp/ns1:Outer", null); it.hasNext();)
+ {
+ XMPPropertyInfo prop = (XMPPropertyInfo) it.next();
+ printPropertyInfo(prop);
+ }
+
+ writeMinorLabel("Iterate an empty namespace");
+ for (XMPIterator it = meta.iterator("ns:Empty", null, null); it.hasNext();)
+ {
+ XMPPropertyInfo prop = (XMPPropertyInfo) it.next();
+ printPropertyInfo(prop);
+ }
+
+ writeMinorLabel("Iterate the top of the ns2: namespace with just leaf names");
+ for (XMPIterator it = meta.iterator(NS2, null, new IteratorOptions().setJustChildren(true)
+ .setJustLeafname(true)); it.hasNext();)
+ {
+ XMPPropertyInfo prop = (XMPPropertyInfo) it.next();
+ printPropertyInfo(prop);
+ }
+
+ writeMinorLabel("Iterate the top of the ns2: namespace with just leaf nodes");
+ for (XMPIterator it = meta.iterator(NS2, null, new IteratorOptions().setJustChildren(true)
+ .setJustLeafnodes(true)); it.hasNext();)
+ {
+ XMPPropertyInfo prop = (XMPPropertyInfo) it.next();
+ printPropertyInfo(prop);
+ }
+ }
+
+
+ /**
+ * XPath composition utilities using the <code>XMPPathFactory</code>.
+ * @throws XMPException Forwards exceptions
+ */
+ private static void coverPathCreation() throws XMPException
+ {
+ writeMajorLabel ("XPath composition utilities");
+
+ XMPMeta meta = XMPMetaFactory.create();
+
+ meta.appendArrayItem(NS1, "ArrayProp", new PropertyOptions().setArray(true),
+ "Item 1", null);
+
+ String path = XMPPathFactory.composeArrayItemPath("ArrayProp", 2);
+ println ("composeArrayItemPath ArrayProp[2] = " + path);
+ meta.setProperty (NS1, path, "new ns1:ArrayProp[2] value");
+
+ path = "StructProperty";
+ path += XMPPathFactory.composeStructFieldPath(NS2, "Field3");
+ println ("composeStructFieldPath StructProperty/ns2:Field3 = " + path);
+ meta.setProperty (NS1, path, "new ns1:StructProp/ns2:Field3 value");
+
+ path = "QualProp";
+ path += XMPPathFactory.composeQualifierPath(NS2, "Qual");
+ println ("composeStructFieldPath QualProp/?ns2:Qual = " + path);
+ meta.setProperty (NS1, path, "new ns1:QualProp/?ns2:Qual value");
+
+ meta.setLocalizedText(NS1, "AltTextProp", null, "en-US", "initival value");
+ path = "AltTextProp";
+ path += XMPPathFactory.composeQualifierPath(XMPConst.NS_XML, "lang");
+ println ("composeQualifierPath ns1:AltTextProp/?xml:lang = " + path);
+ meta.setProperty (NS1, path, "new ns1:AltTextProp/?xml:lang value");
+
+ printXMPMeta (meta, "Modified simple RDF");
+ }
+
+
+ /**
+ * Date/Time utilities
+ */
+ private static void coverDateTime()
+ {
+ writeMajorLabel ("Test date/time utilities and special values");
+
+ XMPDateTime date1 = XMPDateTimeFactory.create(2000, 1, 31, 12, 34, 56, -1);
+ date1.setTimeZone(TimeZone.getTimeZone("PST"));
+ XMPDateTime date2 = XMPDateTimeFactory.create(0, 0, 0, 0, 0, 0, 0);
+ Calendar cal = new GregorianCalendar(2007, 1, 28);
+ XMPDateTime date3 = XMPDateTimeFactory.createFromCalendar(cal);
+ XMPDateTime currentDateTime = XMPDateTimeFactory.getCurrentDateTime();
+
+ println("Print date 2000 Jan 31 12:34:56 PST = " + date1.toString());
+ println("Print zero date = " + date2.toString());
+ println("Print date created by a calendar = " + date3.toString());
+ println("Print current date = " + currentDateTime);
+ println();
+ }
+
+
+
+
+ // ---------------------------------------------------------------------------------------------
+ // Utilities for this example
+ // ---------------------------------------------------------------------------------------------
+
+ /**
+ * Print the content of an XMPMeta object a headline and its name.
+ * @param meta an <code>XMPMeta</code> object
+ * @param title the headline
+ */
+ private static void printXMPMeta(XMPMeta meta, String title)
+ {
+ String name = meta.getObjectName();
+ if (name != null && name.length() > 0)
+ {
+ println(title + " (Name: '" + name + "'):");
+ }
+ else
+ {
+ println(title + ":");
+ }
+ println(meta.dumpObject());
+ println();
+ }
+
+
+ /**
+ * @param prop an <code>XMPPropertyInfo</code> from the <code>XMPIterator</code>.
+ */
+ private static void printPropertyInfo(XMPPropertyInfo prop)
+ {
+ println("NS (" + prop.getNamespace() + ") PATH (" + prop.getPath() + ") VALUE ("
+ + prop.getValue() + ") OPTIONS (" + prop.getOptions().getOptionsString() + ")");
+ }
+
+
+ /**
+ * Dump the alias list to the output.
+ */
+ private static void dumpAliases()
+ {
+ Map aliases;
+ aliases = registry.getAliases();
+ for (Iterator it = aliases.keySet().iterator(); it.hasNext();)
+ {
+ String qname = (String) it.next();
+ XMPAliasInfo aliasInfo = (XMPAliasInfo) aliases.get(qname);
+ println("" + qname + " ---> " + aliasInfo);
+ }
+ println();
+ }
+
+
+ /**
+ * Writes a major headline to the output.
+ * @param title the headline
+ */
+ private static void writeMajorLabel (String title)
+ {
+ println();
+ println("// =============================================================================");
+ println("// " + title);
+ println("// =============================================================================");
+ println();
+ }
+
+
+ /**
+ * Writes a minor headline to the output.
+ * @param title the headline
+ */
+ private static void writeMinorLabel (String title)
+ {
+ println();
+ println ("// -----------------------------------------------------------------------------"
+ .substring(0, title.length() + 3));
+ println ("// " + title);
+ println();
+ }
+
+
+ /**
+ * Prints a string message to both log file and system out.
+ * @param message the message
+ */
+ private static void println(String message)
+ {
+ System.out.println(message);
+ log.println(message);
+ }
+
+
+ /**
+ * Prints a newline to both log file and system out.
+ */
+ private static void println()
+ {
+ println("");
+ }
+} \ No newline at end of file
diff --git a/java/XMPCoreCoverage/src/samples/XMPCoreCoverageConst.java b/java/XMPCoreCoverage/src/samples/XMPCoreCoverageConst.java
new file mode 100644
index 0000000..2ae2169
--- /dev/null
+++ b/java/XMPCoreCoverage/src/samples/XMPCoreCoverageConst.java
@@ -0,0 +1,280 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+package samples;
+
+
+/**
+ * Constants for the XMPCoreCoverage example.
+ *
+ * @author smakswit
+ * @since 21.02.2007
+ */
+public interface XMPCoreCoverageConst
+{
+ /** */
+ String NS1 = "ns:test1/";
+ /** */
+ String NS2 = "ns:test2/";
+ /** RDF metadata that covers most variants of XMP data structures */
+ String RDF_COVERAGE =
+ "<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>" +
+ " <rdf:Description rdf:about='Test:XMPCoreCoverage/kRDFCoverage' xmlns:ns1='ns:test1/' " +
+ " xmlns:ns2='ns:test2/'>" +
+ "" +
+ " <ns1:SimpleProp1>Simple1 value</ns1:SimpleProp1>" +
+ " <ns1:SimpleProp2 xml:lang='x-default'>Simple2 value</ns1:SimpleProp2>" +
+ "" +
+ " <ns1:ArrayProp1>" +
+ " <rdf:Bag>" +
+ " <rdf:li>Item1.1 value</rdf:li>" +
+ " <rdf:li>Item1.2 value</rdf:li>" +
+ " </rdf:Bag>" +
+ " </ns1:ArrayProp1>" +
+ "" +
+ " <ns1:ArrayProp2>" +
+ " <rdf:Alt>" +
+ " <rdf:li xml:lang='x-one'>Item2.1 value</rdf:li>" +
+ " <rdf:li xml:lang='x-two'>Item2.2 value</rdf:li>" +
+ " </rdf:Alt>" +
+ " </ns1:ArrayProp2>" +
+ "" +
+ " <ns1:ArrayProp3>" +
+ " <rdf:Alt>" +
+ " <rdf:li xml:lang='x-one'>Item3.1 value</rdf:li>" +
+ " <rdf:li>Item3.2 value</rdf:li>" +
+ " </rdf:Alt>" +
+ " </ns1:ArrayProp3>" +
+ "" +
+ " <ns1:ArrayProp4>" +
+ " <rdf:Alt>" +
+ " <rdf:li>Item4.1 value</rdf:li>" +
+ " <rdf:li xml:lang='x-two'>Item4.2 value</rdf:li>" +
+ " </rdf:Alt>" +
+ " </ns1:ArrayProp4>" +
+ "" +
+ " <ns1:ArrayProp5>" +
+ " <rdf:Alt>" +
+ " <rdf:li xml:lang='x-xxx'>Item5.1 value</rdf:li>" +
+ " <rdf:li xml:lang='x-xxx'>Item5.2 value</rdf:li>" +
+ " </rdf:Alt>" +
+ " </ns1:ArrayProp5>" +
+ "" +
+ " <ns1:StructProp rdf:parseType='Resource'>" +
+ " <ns2:Field1>Field1 value</ns2:Field1>" +
+ " <ns2:Field2>Field2 value</ns2:Field2>" +
+ " </ns1:StructProp>" +
+ "" +
+ " <ns1:QualProp1 rdf:parseType='Resource'>" +
+ " <rdf:value>Prop value</rdf:value>" +
+ " <ns2:Qual>Qual value</ns2:Qual>" +
+ " </ns1:QualProp1>" +
+ "" +
+ " <ns1:QualProp2 rdf:parseType='Resource'>" +
+ " <rdf:value xml:lang='x-default'>Prop value</rdf:value>" +
+ " <ns2:Qual>Qual value</ns2:Qual>" +
+ " </ns1:QualProp2>" +
+ "" +
+ " <!-- " +
+ " NOTE: QualProp3 is not quite kosher. Normally a qualifier on a struct is attached " +
+ " to the struct node in the XMP tree, and the same for an array. See QualProp4 and " +
+ " QualProp5. But for the pseudo-struct of a qualified simple property there is no " +
+ " struct node that can own the qualifier. Instead the qualifier is attached to the " +
+ " value. The alternative of attaching the qualifier to the value and all other " +
+ " qualifiers is not compelling. This issue only arises for xml:lang, it is the only " +
+ " qualifier that RDF has as an attribute." +
+ " -->" +
+ "" +
+ " <ns1:QualProp3 xml:lang='x-default' rdf:parseType='Resource'>" +
+ " <rdf:value>Prop value</rdf:value>" +
+ " <ns2:Qual>Qual value</ns2:Qual>" +
+ " </ns1:QualProp3>" +
+ "" +
+ " <ns1:QualProp4 xml:lang='x-default' rdf:parseType='Resource'>" +
+ " <ns2:Field1>Field1 value</ns2:Field1>" +
+ " <ns2:Field2>Field2 value</ns2:Field2>" +
+ " </ns1:QualProp4>" +
+ "" +
+ " <ns1:QualProp5 xml:lang='x-default'>" +
+ " <rdf:Bag>" +
+ " <rdf:li>Item1.1 value</rdf:li>" +
+ " <rdf:li>Item1.2 value</rdf:li>" +
+ " </rdf:Bag>" +
+ " </ns1:QualProp5>" +
+ "" +
+ " <ns2:NestedStructProp rdf:parseType='Resource'>" +
+ " <ns1:Outer rdf:parseType='Resource'>" +
+ " <ns1:Middle rdf:parseType='Resource'>" +
+ " <ns1:Inner rdf:parseType='Resource'>" +
+ " <ns1:Field1>Field1 value</ns1:Field1>" +
+ " <ns2:Field2>Field2 value</ns2:Field2>" +
+ " </ns1:Inner>" +
+ " </ns1:Middle>" +
+ " </ns1:Outer>" +
+ " </ns2:NestedStructProp>" +
+ "" +
+ " </rdf:Description>" +
+ "</rdf:RDF>";
+
+ /** */
+ String SIMPLE_RDF =
+ "<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>" +
+ " <rdf:Description rdf:about='Test:XMPCoreCoverage/kSimpleRDF' xmlns:ns1='ns:test1/' " +
+ " xmlns:ns2='ns:test2/'>" +
+ "" +
+ " <ns1:SimpleProp>Simple value</ns1:SimpleProp>" +
+ "" +
+ " <ns1:ArrayProp>" +
+ " <rdf:Bag>" +
+ " <rdf:li>Item1 value</rdf:li>" +
+ " <rdf:li>Item2 value</rdf:li>" +
+ " </rdf:Bag>" +
+ " </ns1:ArrayProp>" +
+ "" +
+ " <ns1:StructProp rdf:parseType='Resource'>" +
+ " <ns2:Field1>Field1 value</ns2:Field1>" +
+ " <ns2:Field2>Field2 value</ns2:Field2>" +
+ " </ns1:StructProp>" +
+ "" +
+ " <ns1:QualProp rdf:parseType='Resource'>" +
+ " <rdf:value>Prop value</rdf:value>" +
+ " <ns2:Qual>Qual value</ns2:Qual>" +
+ " </ns1:QualProp>" +
+ "" +
+ " <ns1:AltTextProp>" +
+ " <rdf:Alt>" +
+ " <rdf:li xml:lang='x-one'>x-one value</rdf:li>" +
+ " <rdf:li xml:lang='x-two'>x-two value</rdf:li>" +
+ " </rdf:Alt>" +
+ " </ns1:AltTextProp>" +
+ "" +
+ " <ns1:ArrayOfStructProp>" +
+ " <rdf:Bag>" +
+ " <rdf:li rdf:parseType='Resource'>" +
+ " <ns2:Field1>Item-1</ns2:Field1>" +
+ " <ns2:Field2>Field 1.2 value</ns2:Field2>" +
+ " </rdf:li>" +
+ " <rdf:li rdf:parseType='Resource'>" +
+ " <ns2:Field1>Item-2</ns2:Field1>" +
+ " <ns2:Field2>Field 2.2 value</ns2:Field2>" +
+ " </rdf:li>" +
+ " </rdf:Bag>" +
+ " </ns1:ArrayOfStructProp>" +
+ "" +
+ " </rdf:Description>" +
+ "</rdf:RDF>";
+
+ /** RDF metadata introducing new namespaces */
+ String NAMESPACE_RDF =
+ "<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>" +
+ " <rdf:Description rdf:about='Test:XMPCoreCoverage/kNamespaceRDF' " +
+ " xmlns:ns1='ns:test1/'>" +
+ "" +
+ " <ns1:NestedStructProp rdf:parseType='Resource'>" +
+ " <ns2:Outer rdf:parseType='Resource' xmlns:ns2='ns:test2/' xmlns:ns3='ns:test3/'>" +
+ " <ns3:Middle rdf:parseType='Resource' xmlns:ns4='ns:test4/'>" +
+ " <ns4:Inner rdf:parseType='Resource' xmlns:ns5='ns:test5/' " +
+ " xmlns:ns6='ns:test6/'>" +
+ " <ns5:Field1>Field1 value</ns5:Field1>" +
+ " <ns6:Field2>Field2 value</ns6:Field2>" +
+ " </ns4:Inner>" +
+ " </ns3:Middle>" +
+ " </ns2:Outer>" +
+ " </ns1:NestedStructProp>" +
+ "" +
+ " </rdf:Description>" +
+ "</rdf:RDF>";
+
+ /** RDF metadata embedded in XML tag. */
+ String XMPMETA_RDF =
+ "<x:Outermost xmlns:x='adobe:ns:meta/'>" +
+ "" +
+ "<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>" +
+ " <rdf:Description rdf:about='Test:XMPCoreCoverage/kBogusLeadingRDF' " +
+ " xmlns:ns1='ns:test1/'>" +
+ " <ns1:BogusLeadingProp>bogus packet</ns1:BogusLeadingProp>" +
+ " </rdf:Description>" +
+ "</rdf:RDF>" +
+ "" +
+ "<x:xmpmeta>" +
+ "<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>" +
+ " <rdf:Description rdf:about='Test:XMPCoreCoverage/kXMPMetaRDF' xmlns:ns1='ns:test1/'>" +
+ " <ns1:XMPMetaProp>xmpmeta packet</ns1:XMPMetaProp>" +
+ " </rdf:Description>" +
+ "</rdf:RDF>" +
+ "</x:xmpmeta>" +
+ "" +
+ "<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>" +
+ " <rdf:Description rdf:about='Test:XMPCoreCoverage/kBogusTrailingRDF'" +
+ " xmlns:ns1='ns:test1/'>" +
+ " <ns1:BogusTrailingProp>bogus packet</ns1:BogusTrailingProp>" +
+ " </rdf:Description>" +
+ "</rdf:RDF>" +
+ "" +
+ "</x:Outermost>";
+
+ /** RDF metadata with properties that contain whitespaces */
+ String NEWLINE_RDF =
+ "<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>" +
+ " <rdf:Description rdf:about='Test:XMPCoreCoverage/kNewlineRDF' xmlns:ns1='ns:test1/'>" +
+ "" +
+ " <ns1:HasCR>ASCII &#xD; CR</ns1:HasCR>" +
+ " <ns1:HasLF>ASCII &#xA; LF</ns1:HasLF>" +
+ " <ns1:HasCRLF>ASCII &#xD;&#xA; CRLF</ns1:HasCRLF>" +
+ "" +
+ " </rdf:Description>" +
+ "</rdf:RDF>";
+
+ /** Inconsistant RDF metadata */
+ String INCONSISTENT_RDF =
+ "<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>" +
+ " <rdf:Description rdf:about='Test:XMPCoreCoverage/kInconsistentRDF'" +
+ " xmlns:pdf='http://ns.adobe.com/pdf/1.3/'" +
+ " xmlns:xmp='http://ns.adobe.com/xap/1.0/'" +
+ " xmlns:dc='http://purl.org/dc/elements/1.1/'>" +
+ "" +
+ " <pdf:Author>PDF Author</pdf:Author>" +
+ " <xmp:Author>XMP Author</xmp:Author>" +
+ "" +
+ " <xmp:Authors>" +
+ " <rdf:Seq>" +
+ " <rdf:li>XMP Authors [1]</rdf:li>" +
+ " </rdf:Seq>" +
+ " </xmp:Authors>" +
+ "" +
+ " <dc:creator>" +
+ " <rdf:Seq>" +
+ " <rdf:li>DC Creator [1]</rdf:li>" +
+ " </rdf:Seq>" +
+ " </dc:creator>" +
+ "" +
+ " </rdf:Description>" +
+ "</rdf:RDF>";
+
+ /** Example for the usage of date and time properties */
+ String DATETIME_RDF =
+ "<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>" +
+ " <rdf:Description rdf:about='Test:XMPCoreCoverage/kDateTimeRDF' xmlns:ns1='ns:test1/'>" +
+ "" +
+ " <ns1:Date1>2003</ns1:Date1>" +
+ " <ns1:Date2>2003-12</ns1:Date2>" +
+ " <ns1:Date3>2003-12-31</ns1:Date3>" +
+ "" +
+ " <ns1:Date4>2003-12-31T12:34Z</ns1:Date4>" +
+ " <ns1:Date5>2003-12-31T12:34:56Z</ns1:Date5>" +
+ "" +
+ " <ns1:Date6>2003-12-31T12:34:56.001Z</ns1:Date6>" +
+ " <ns1:Date7>2003-12-31T12:34:56.000000001Z</ns1:Date7>" +
+ "" +
+ " <ns1:Date8>2003-12-31T10:04:56-02:30</ns1:Date8>" +
+ " <ns1:Date9>2003-12-31T15:49:56+03:15</ns1:Date9>" +
+ "" +
+ " </rdf:Description>" +
+ "</rdf:RDF>";
+}
diff --git a/java/readme.txt b/java/readme.txt
new file mode 100644
index 0000000..6c7dca0
--- /dev/null
+++ b/java/readme.txt
@@ -0,0 +1,39 @@
+Adobe XMP Toolkit for Java Version 4.1.1
+========================================
+
+It contains the XMPCore part of the toolkit and NOT XMPFiles.
+To get more information about the "Extensible Metadata Platform" (XMP),
+please visit the XMP product page on the Adobe website (http://www.adobe.com/xmp).
+
+This readme.txt covers the setup of the XMPCore and the example project
+for the Eclipse Java IDE 3.0 and above and Java SDK 1.4.2 and above.
+
+
+Setup the projects in Eclipse 3.2 and above:
+
+1. Start Eclipse with an empty workspace
+2. In the menu select File --> Import...
+ --> Existing Projects into Workspace --> Next
+3. Select "Select root directory" and browse for this directory (XMP-SDK/java)
+4. Press <Finish>
+
+
+Setup the projects in Eclipse 3.0.x:
+
+1. Start Eclipse with an empty workspace
+2. In the menu select File --> New --> Project --> Java Project
+3. Enter Project Name "XMPCore"
+4. Select "Create project at external location" and select the folder "XMPCore"
+ which you find as sibling of this readme.txt file.
+5. Press <Finish>
+6. To install the example please repeat steps 2. to 5. replacing "XMPCore" by "XMPCoreCoverage"
+
+
+To build debug and release libraries of XMPCore, run the ANT script "build.xml"
+that is contained in the XMPCore project.
+
+Note: If you use Java 1.4.2, please ensure that the class file compliance is set to 1.4
+(default is 1.2). Otherwise the assert statements do not compile.
+To change this setting, open the Preferences dialog and select --> Java --> Compiler:
+Uncheck "Use default compliance settings" and set "Generated .class files compatibility"
+and "Source compatibility" both to 1.4. \ No newline at end of file
diff --git a/public/include/TXMPFiles.hpp b/public/include/TXMPFiles.hpp
new file mode 100644
index 0000000..499dfb9
--- /dev/null
+++ b/public/include/TXMPFiles.hpp
@@ -0,0 +1,418 @@
+#ifndef __TXMPFiles_hpp__
+#define __TXMPFiles_hpp__ 1
+
+#if ( ! __XMP_hpp__ )
+ #error "Do not directly include, use XMP.hpp"
+#endif
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+// ================================================================================================
+/// \file TXMPFiles.hpp
+/// \brief API for access to the "main" metadata in a file.
+///
+/// \c TXMPFiles provides the API for the Adobe XMP Toolkit's File Handler component. This provides
+/// convenient access to the main, or document level, XMP for a file. The File Handler supports file
+/// I/O, the XMP Toolkit Core supports manipulation of the XMP properties. The File Handler is
+/// intended to eventually have smart, efficient support for all file formats for which the means to
+/// embed XMP is defined in the XMP Specification. Where possible this support will allow injection
+/// of XMP where none currently exists, expansion of XMP without regard to existing padding, and
+/// reconciliation of the XMP and other legacy forms of metadata.
+///
+///\c TXMPFiles is designed for use by clients interested in the metadata and not in the primary file
+/// content. The Adobe Bridge application is a typical example. \c TXMPFiles is not intended to be
+/// particulary appropriate for files authored by an application. I.e. those files for which the
+/// application has explicit knowledge of the file format.
+// ================================================================================================
+
+// ================================================================================================
+/// \class TXMPFiles TXMPFiles.hpp
+/// \brief API for access to the "main" metadata in a file.
+///
+/// \c TXMPFiles provides the API for the Adobe XMP Toolkit's File Handler component. This provides
+/// convenient access to the main, or document level, XMP for a file. The general model is to open
+/// a file, read and write the metadata, then close the file. While open, portions of the file
+/// might be maintained in RAM data structures. Memory usage can vary considerably depending on
+/// file format and access options. The file may be opened for read-only or read-write access, with
+/// typical exclusion for both modes.
+///
+/// Errors result in the throw of an \c XMPError exception.
+///
+/// The template is instantiated with a string object class. This allows a clean implementation
+/// that provides two major benefits: output string storage is fully owned by the client and access
+/// is fully thread safe. The template parameter, class \c tStringObj, is described in the XMP.hpp
+/// umbrella header.
+///
+/// To use TXMPFiles define TXMP_STRING_TYPE and XMP_INCLUDE_XMPFILES, then include the XMP.hpp
+/// umbrella header:
+/// \code
+/// #define TXMP_STRING_TYPE std::string
+/// #define XMP_INCLUDE_XMPFILES 1
+/// #include "XMP.hpp"
+/// \endcode
+// ================================================================================================
+
+template <class tStringObj>
+class TXMPFiles {
+
+public:
+
+ // ============================================================================================
+ /// \name Initialization and termination
+ /// @{
+ /// \c SXMPFiles must be initialized before use and may be terminated when done.
+
+ static void GetVersionInfo ( XMP_VersionInfo * versionInfo );
+
+ /// \brief \c Initialize must be called before using \c SXMPFiles. It returns a Boolean
+ /// success/failure value.
+
+ static bool Initialize();
+ static bool Initialize ( XMP_OptionBits options );
+
+ /// \brief \c Terminate may be called when done using \c SXMPFiles. It deallocates global data
+ /// structures created by \c Initialize.
+
+ static void Terminate();
+
+ /// @}
+
+ // ============================================================================================
+ /// \name Constructors and destructor
+ /// @{
+ /// The default constructor initializes an object that is associated with no file. The alternate
+ /// constructors call OpenFile. The destructor automatically calls CloseFile if necessary.
+
+ /// \brief The default constructor initializes an object that is associated with no file.
+
+ TXMPFiles();
+ virtual ~TXMPFiles() throw();
+
+ /// \brief These alternate constructors call \c OpenFile. The second form is a trivial overload
+ /// that calls the first form passing \c filePath.c_str().
+
+ TXMPFiles ( XMP_StringPtr filePath,
+ XMP_FileFormat format = kXMP_UnknownFile,
+ XMP_OptionBits openFlags = 0 );
+
+ TXMPFiles ( const tStringObj & filePath,
+ XMP_FileFormat format = kXMP_UnknownFile,
+ XMP_OptionBits openFlags = 0 );
+
+ /// \brief The copy constructor and assignment operator increment an internal reference count,
+ /// they do not perform a deep copy.
+
+ TXMPFiles ( const TXMPFiles<tStringObj> & original );
+
+ void operator= ( const TXMPFiles<tStringObj> & rhs );
+
+ /// \brief The "ref" constructor and \c GetInternalRef serve the same purpose as their analogs
+ /// in SXMPMeta, safely passing \c SXMPFiles references across DLL boundaries where the clients
+ /// might have used different string types when instantiating \c TXMPFiles.
+
+ TXMPFiles ( XMPFilesRef xmpFilesObj );
+
+ XMPFilesRef GetInternalRef();
+
+ /// @}
+
+ // ============================================================================================
+ /// \name Static Functions
+ /// @{
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Determine the supported features for a given file format.
+ ///
+ /// The supported features can vary quite a bit among file formats, depending on both the
+ /// general capabilities of the format and the implementation of the handler for that format.
+ ///
+ /// \param format The format whose support flags are desired.
+ ///
+ /// \param handlerFlags A set of option bits showing the support for this format:
+ ///
+ /// \li kXMPFiles_CanInjectXMP - Can inject first-time XMP into an existing file.
+ /// \li kXMPFiles_CanExpand - Can expand XMP or other metadata in an existing file.
+ /// \li kXMPFiles_CanRewrite - Can copy one file to another, writing new metadata.
+ /// \li kXMPFiles_CanReconcile - Supports reconciliation between XMP and other forms.
+ /// \li kXMPFiles_AllowsOnlyXMP - Allows access to just the XMP, ignoring other forms.
+ /// \li kXMPFiles_ReturnsRawPacket - File handler returns raw XMP packet information and string.
+ /// \li kXMPFiles_ReturnsTNail - File handler returns native thumbnail information.
+ ///
+ /// The kXMPFiles_AllowsOnlyXMP flag is only meaningful if kXMPFiles_CanReconcile is set.
+ ///
+ /// If kXMPFiles_ReturnsRawPacket is set, the returned packet information might have an offset
+ /// of -1 to indicate an unknown offset. While all file handlers should be able to return the
+ /// raw packet, some might not know the offset of the packet within the file. This is typical
+ /// in cases where external libraries are used. These cases might not even allow return of the
+ /// raw packet.
+ ///
+ /// \result Returns true if the format has explicit "smart" support. Returns false if the format
+ /// is handled by the default packet scanning plus heuristics.
+
+ static bool GetFormatInfo ( XMP_FileFormat format,
+ XMP_OptionBits * handlerFlags = 0 );
+
+ /// @}
+
+ // ============================================================================================
+ /// \name OpenFile, CloseFile, and related file-oriented operations
+ /// @{
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Open a file for metadata access.
+ ///
+ /// Opens a file for the requested forms of metadata access. Opening the file at a minimum
+ /// causes the raw XMP packet to be read from the file. If the file handler supports legacy
+ /// metadata reconciliation then legacy metadata will also be read, unless kXMPFiles_OpenOnlyXMP
+ /// is passed. If the file handler supports native thumbnails and kXMPFiles_OpenCacheTNail is
+ /// passed then the native thumbnail will also be cached.
+ ///
+ /// If the file is opened for read-only access (passing kXMPFiles_OpenForRead), then the disk
+ /// file itself will be closed after reading the data from it. The XMPFiles object will not be
+ /// "closed" though, it is still necessary to call CloseFile when finished using it. Other
+ /// methods (GetXMP, etc.) can only be used between the OpenFile and CloseFile calls. The XMPFiles
+ /// destructor will not call CloseFile, any pending updates will be lost.
+ ///
+ /// If the file is opened for update (passing kXMPFiles_OpenForUpdate), then the disk file remains
+ /// open until CloseFile is called. The disk file is only updated once, when Close file is called,
+ /// no matter how many calls are made to PutXMP.
+ ///
+ /// Ideally the XMP is not parsed and legacy reconciliation is not performed until GetXMP is
+ /// called. This is not guaranteed though, specific file handlers might do earlier parsing of
+ /// the XMP. This delayed parsing and the early disk file close for read-only access are
+ /// optimizations to help clients implementing file browsers. They can access the file briefly
+ /// and possibly display a thumbnail, then postpone more expensive XMP processing until later.
+ ///
+ /// \param filePath The UTF-8 path for the file, appropriate for the local OS. Overloads are
+ /// declared to pass the path as either a "const char *" or a string object.
+ ///
+ /// \param format The format of the file. If the format is unknown pass \c kXMP_UnknownFile and
+ /// the format will be determined from the file content. The first handler to check will be
+ /// guessed from the file's extension. Passing any other format value is generally just a hint
+ /// about what file handler to try first (instead of the one based on the extension). If the
+ /// kXMPFiles_OpenStrictly is set, then any format other than kXMP_UnknownFile requires that the
+ /// file actually be that format, an exception is thrown if not.
+ ///
+ /// \param openFlags A set of option bits describing the desired access. By default (zero) the
+ /// file is opened for read-only access and the format handler decides on the level of
+ /// reconciliation that will be performed. By default a best effort will be made to locate the
+ /// correct XMP and to reconcile XMP with other forms (if reconciliation is done). The option
+ /// \c kXMPFiles_OpenStrictly may be used to force more strict rules, resulting is exceptions for
+ /// errors. The definition of strictness is specific to each handler, there may be no difference.
+ ///
+ /// The defined openFlag bits are:
+ ///
+ /// \li kXMPFiles_OpenForRead - Open for read-only access.
+ /// \li kXMPFiles_OpenForUpdate - Open for reading and writing.
+ /// \li kXMPFiles_OpenOnlyXMP - Only the XMP is wanted, no reconciliation.
+ /// \li kXMPFiles_OpenCacheTNail - Cache thumbnail if possible, GetThumbnail will be called.
+ /// \li kXMPFiles_OpenStrictly - Be strict about locating XMP and reconciling with other forms.
+ /// \li kXMPFiles_OpenUseSmartHandler - Require the use of a smart handler.
+ /// \li kXMPFiles_OpenUsePacketScanning - Force packet scanning, don't use a smart handler.
+ ///
+ /// \result Returns true if the file is succesfully opened and attached to a file handler.
+ /// Returns false for "anticipated" problems, e.g. passing kXMPFiles_OpenUseSmartHandler but not
+ /// having an appropriate smart handler. Throws an exception for serious problems.
+
+ bool OpenFile ( XMP_StringPtr filePath,
+ XMP_FileFormat format = kXMP_UnknownFile,
+ XMP_OptionBits openFlags = 0 );
+
+ bool OpenFile ( const tStringObj & filePath,
+ XMP_FileFormat format = kXMP_UnknownFile,
+ XMP_OptionBits openFlags = 0 );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Close an opened file.
+ ///
+ /// Performs any necessary output to the file and closes it. Files that are opened for update
+ /// are written to only when closing.
+ ///
+ /// \param closeFlags A set of bit flags for optional closing actions.
+ ///
+ /// The defined closeFlags bits are:
+ ///
+ /// \li kXMPFiles_UpdateSafely - Write into a temporary file then swap for crash safety.
+
+ void CloseFile ( XMP_OptionBits closeFlags = 0 );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Get basic information about an opened file.
+ ///
+ /// \param filePath If not null, returns the path passed to OpenFile.
+ ///
+ /// \param openFlags If not null, returns the flags passed to OpenFile.
+ ///
+ /// \param format If not null, returns the format of the file.
+ ///
+ /// \param handlerFlags If not null, returns the handler's capability flags.
+ ///
+ /// \result Returns true if a file is opened, false otherwise. This notion of "open" really means
+ /// that OpenFile has been called but CloseFile has not. The actual disk file might be closed in
+ /// the host file system sense, as explained for OpenFile.
+
+ bool GetFileInfo ( tStringObj * filePath = 0,
+ XMP_OptionBits * openFlags = 0,
+ XMP_FileFormat * format = 0,
+ XMP_OptionBits * handlerFlags = 0 );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Set the callback function used to check for a user signaled abort.
+ ///
+ /// \param abortProc The callback function used to check for a user signaled abort. It will be
+ /// called periodically to allow an abort of time consuming operations. The abort results in an
+ /// exception being thrown. The callback function should return true to signal an abort.
+ ///
+ /// \param abortArg An argument passed to the callback function.
+
+ void SetAbortProc ( XMP_AbortProc abortProc,
+ void * abortArg );
+
+ /// @}
+
+ // ============================================================================================
+ /// \name Metadata Access Functions
+ /// @{
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Obtain the XMP.
+ ///
+ /// \c GetXMP is used to obtain the parsed XMP, and/or the raw XMP packet, and/or information
+ /// about the raw XMP packet. If all parameters are null it simply tells if XMP is present or
+ /// not. The options provided when the file was opened determine if reconciliation is done with
+ /// other forms of metadata.
+ ///
+ /// \param xmpObj If not null, returns the parsed XMP.
+ ///
+ /// \param xmpPacket If not null, returns the raw XMP packet as stored in the file. The encoding
+ /// of the packet is given in the packetInfo. The string will be empty if the low level file
+ /// handler does not provide the raw packet.
+ ///
+ /// \param packetInfo If not null, returns the location and form of the raw XMP in the file. The
+ /// charForm and writeable flag reflect the raw XMP in the file. The parsed XMP property values
+ /// are always UTF-8. The writeable flag is taken from the packet trailer, it is only relevant
+ /// for "format ignorant" writing.
+ ///
+ /// \note The packetInfo struct always reflects the state of the XMP in the file. The offset,
+ /// length, and character form will not change as a result of calling \c PutXMP unless the file
+ /// is also written.
+ ///
+ /// \note Some file handlers might not return location or contents of the raw packet string.
+ /// Check the \c kXMPFiles_ReturnsRawPacket bit returned by GetFormatInfo if you depend on this.
+ /// If the low level file handler does not provide the raw packet location then the offset and
+ /// length will both be 0, the charForm will be UTF-8, and the writeable flag will be false.
+ ///
+ /// \result Returns true if the file has XMP, false otherwise.
+
+ bool GetXMP ( SXMPMeta * xmpObj = 0,
+ tStringObj * xmpPacket = 0,
+ XMP_PacketInfo * packetInfo = 0 );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Obtain the native thumbnail.
+ ///
+ /// \c GetThumbnail is used to obtain native thumbnail information, if the associated file
+ /// handler supports that and the thumbnail was cached by OpenFile. This requires that
+ /// kXMPFiles_OpenCacheTNail be passed to OpenFile. The tnailInfo output pointer can be null,
+ /// in which case GetThumbnail will simply tell if a recognized native thumbnail is present.
+ ///
+ /// \param tnailInfo If not null, returns information about a recognized native thumbnail, and
+ /// some related information about the primary image if appropriate.
+ ///
+ /// \note The returned thumbnail information can be incomplete. What gets returned can depend on
+ /// the file format, the file handler's capabilities, and the specific file content.
+ ///
+ /// \li The fullHeight, fullWIdth, and fullOrientation fields are only meaningful for image files.
+ /// They are not meaningful for multi-page files such as PDF or InDesign, for dynamic audio or
+ /// video files, etc. The fields will be zero if not meaningful or not determined.
+ ///
+ /// \li The tnailImage and tnailSize fields might be zero even if a "recognized" thumbnail is
+ /// present. Being recognized means only that the handler has determined that the file does
+ /// contain a native thumbnail. The thumbnail data might be of a format that the file handler
+ /// cannot (or does not) return a single contiguous block of thumbnail data. A possible case of
+ /// this is a TIFF uncompressed thumbnail, the handler might not have logic to gather the various
+ /// disjoint pieces of the thumbnail from the overall TIFF stream.
+ ///
+ /// \result Returns true if a recognized native thumbnail is presentand the thumbnail was
+ /// cached by OpenFile. This requires that kXMPFiles_OpenCacheTNail be passed to OpenFile. Note
+ /// that GetThumbnail can return true but still not return an actual thumbnail image, see the
+ /// above note.
+
+ bool GetThumbnail ( XMP_ThumbnailInfo * tnailInfo );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Update the XMP.
+ ///
+ /// \c PutXMP supplies new XMP for the file. However, the file is not actully written until
+ /// closed. The options provided when the file was opened determine if reconciliation is done
+ /// with other forms of metadata. Overloads are provided to pass the XMP as an XMP
+ /// object, a string object, or a "const char *" plus length.
+
+ void PutXMP ( const SXMPMeta & xmpObj );
+
+ void PutXMP ( const tStringObj & xmpPacket );
+
+ void PutXMP ( XMP_StringPtr xmpPacket,
+ XMP_StringLen xmpLength = kXMP_UseNullTermination );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Determine if the XMP can be updated.
+ ///
+ /// \c CanPutXMP determines if the XMP can (probably) be updated. The provided XMP is only used
+ /// to obtain the length of the serialized packet. The new XMP is not kept, calling this will
+ /// not cause the file to be written when closed. Overloads are provided to pass the XMP as an
+ /// XMP object, a string object, or a "const char *" plus length. This is implemented roughly
+ /// as:
+ ///
+ /// \code
+ /// bool CanPutXMP ( XMP_StringPtr xmpPacket )
+ /// {
+ /// XMP_FileFormat format;
+ /// this->GetFileInfo ( 0, &format, 0 );
+ ///
+ /// XMP_OptionBits formatFlags;
+ /// GetFormatInfo ( format, &formatFlags );
+ ///
+ /// if ( (formatFlags & kXMPFiles_CanInjectXMP) && (formatFlags & kXMPFiles_CanExpand) ) return true;
+ ///
+ /// XMP_PacketInfo packetInfo;
+ /// bool hasXMP = this->GetXMP ( 0, 0, &packetInfo );
+ ///
+ /// if ( ! hasXMP ) {
+ /// if ( formatFlags & kXMPFiles_CanInjectXMP ) return true;
+ /// } else {
+ /// if ( (formatFlags & kXMPFiles_CanExpand) ||
+ /// (packetInfo.length >= strlen(xmpPacket)) ) return true;
+ /// }
+ ///
+ /// return false;
+ ///
+ /// }
+ /// \endcode
+
+ bool CanPutXMP ( const SXMPMeta & xmpObj );
+
+ bool CanPutXMP ( const tStringObj & xmpPacket );
+
+ bool CanPutXMP ( XMP_StringPtr xmpPacket,
+ XMP_StringLen xmpLength = kXMP_UseNullTermination );
+
+ /// @}
+
+ // =============================================================================================
+
+private:
+ XMPFilesRef xmpFilesRef;
+
+}; // class TXMPFiles
+
+// =================================================================================================
+
+#endif // __TXMPFiles_hpp__
diff --git a/public/include/TXMPIterator.hpp b/public/include/TXMPIterator.hpp
new file mode 100644
index 0000000..26bb141
--- /dev/null
+++ b/public/include/TXMPIterator.hpp
@@ -0,0 +1,205 @@
+#ifndef __TXMPIterator_hpp__
+#define __TXMPIterator_hpp__ 1
+
+#if ( ! __XMP_hpp__ )
+ #error "Do not directly include, use XMP.hpp"
+#endif
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+// ================================================================================================
+/// \file TXMPIterator.hpp
+/// \brief Template class for the XMP Toolkit iteration services.
+///
+/// This template class provides iteration services for the XMP Toolkit. It should be instantiated
+/// with a string class such as <tt>std::string</tt>. Please read the general usage notes for
+/// information on the overall architecture of the XMP API.
+// ================================================================================================
+
+// ================================================================================================
+/// \class TXMPIterator TXMPIterator.hpp
+/// \brief Template class for the XMP Toolkit iteration services.
+///
+/// This template class provides iteration services for the XMP Toolkit. It should be instantiated
+/// with a string class such as <tt>std::string</tt>. Please read the general usage notes for
+/// information on the overall architecture of the XMP API.
+///
+/// \c TXMPIterator provides a uniform means to iterate over several XMP data structures, including
+/// the schema and properties within an XMP object plus global tables such as registered
+/// namespaces. The template wraps a string class around the raw XMP API, so that output strings
+/// are automatically copied and access is fully thread safe. String objects are only necessary
+/// for output strings. Input string are literals and passed as typical C <tt>const char *</tt>.
+///
+/// The template parameter, class \c TtStringObj, is described in the XMP.hpp umbrella header.
+///
+/// \note Only XMP object iteration is implemented at this time. There are no table iterators yet.
+///
+/// Iteration over the schema and properties within an XMP object is the most important and complex
+/// use of \c TTXMPIterator. It is helpful to have a thorough understanding of the XMP data tree.
+/// One way to learn this is to create some complex XMP and examine the output of
+/// <tt>TXMPMeta::DumpObject</tt>. This is also described in the XMP Specification, in the XMP Data
+/// Model chapter.
+///
+/// The top of the XMP data tree is a single root node. This does not explicitly appear in the dump
+/// and is never visited by an iterator (that is, it is never returned from
+/// <tt>TXMPIterator::Next</tt>). Beneath the root are schema nodes. These are just collectors for
+/// top level properties in the same namespace. They are created and destroyed implicitly. Beneath
+/// the schema nodes are the property nodes. The nodes below a property node depend on its type
+/// (simple, struct, or array) and whether it has qualifiers.
+///
+/// A \c TXMPIterator constructor defines a starting point for the iteration and options that control
+/// how it proceeds. By default the iteration starts at the root and visits all nodes beneath it in
+/// a depth first manner. The root node is not visited, the first visited node is a schema node. You
+/// can provide a schema name or property path to select a different starting node. By default this
+/// visits the named root node first then all nodes beneath it in a depth first manner.
+///
+/// The <tt>TXMPIterator::Next</tt> method delivers the schema URI, path, and option flags for the
+/// node being visited. If the node is simple it also delivers the value. Qualifiers for this node
+/// are visited next. The fields of a struct or items of an array are visited after the qualifiers
+/// of the parent.
+///
+/// The options to control the iteration are:
+///
+/// \li \c kXMP_IterJustChildren - Visit just the immediate children of the root. Skip the root
+/// itself and all nodes below the immediate children. This omits the qualifiers of the immediate
+/// children, the qualifier nodes being below what they qualify.
+///
+/// \li \c kXMP_IterJustLeafNodes - Visit just the leaf property nodes and their qualifiers.
+///
+/// \li \c kXMP_IterJustLeafName - Return just the leaf component of the node names. The default is
+/// to return the full path name.
+///
+/// \li \c kXMP_IterIncludeAliases - Include aliases as part of the iteration. Since aliases are not
+/// actual nodes the default iteration does not visit them.
+///
+/// \li \c kXMP_IterOmitQualifiers - Do not visit the qualifiers of a node.
+///
+// ================================================================================================
+
+#include "client-glue/WXMPIterator.hpp"
+
+template <class tStringObj>
+class TXMPIterator {
+
+public:
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Assignment operator, assigns the internal ref and increments the ref count.
+ ///
+ /// The assignment operator assigns the internal ref from the rhs object and increments the
+ /// reference count on the underlying internal XMP iterator.
+
+ void operator= ( const TXMPIterator<tStringObj> & rhs );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Copy constructor, creates a client object refering to the same internal object.
+ ///
+ /// The copy constructor creates a new client iterator that refers to the same underlying iterator.
+
+ TXMPIterator ( const TXMPIterator<tStringObj> & original );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Construct an iterator for the properties within an XMP object.
+ ///
+ /// Construct an iterator for the properties within an XMP object. The general operation of an
+ /// XMP object iterator was described above. Overloaded forms are provided to iterate the entire
+ /// data tree, properties within a specific schema, or a subtree rooted at a specific node.
+ ///
+ /// \param xmpObj The XMP object over which to iterate.
+ ///
+ /// \param schemaNS Optional schema namespace URI to restrict the iteration. Omitted (visit all
+ /// schema) by passing 0 or "".
+ ///
+ /// \param propName Optional property name to restrict the iteration. May be an arbitrary path
+ /// expression. Omitted (visit all properties) by passing 0 or "". If not null/empty a schema
+ /// URI must also be provided.
+ ///
+ /// \param options Option flags to control the iteration.
+ ///
+ /// The available option flags are:
+ ///
+ /// \li \c kXMP_IterJustChildren - Just visit the immediate children of the root, default is subtree.
+ /// \li \c kXMP_IterJustLeafNodes - Just visit the leaf nodes, default visits all nodes.
+ /// \li \c kXMP_IterJustLeafName - Return just the leaf part of the path, default is the full path.
+ /// \li \c kXMP_IterOmitQualifiers - Omit all qualifiers.
+
+ TXMPIterator ( const TXMPMeta<tStringObj> & xmpObj,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_OptionBits options = 0 );
+
+ TXMPIterator ( const TXMPMeta<tStringObj> & xmpObj,
+ XMP_StringPtr schemaNS,
+ XMP_OptionBits options = 0 );
+
+ TXMPIterator ( const TXMPMeta<tStringObj> & xmpObj,
+ XMP_OptionBits options = 0 );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Construct an iterator for the global tables of the XMP toolkit.
+ ///
+ /// \note <b>Not yet implemented.</b> File a bug if you need this.
+
+ TXMPIterator ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_OptionBits options );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Destructor, typical virtual destructor.
+
+ virtual ~TXMPIterator() throw();
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Visit the next node in the iteration.
+ ///
+ /// \result Returns true if there was another node to visit, false if the iteration is done.
+ ///
+ /// \param schemaNS A pointer to the string that is assigned the schema namespace URI of
+ /// the current property. May be null if the value is not wanted.
+ ///
+ /// \param propPath A pointer to the string that is assigned the XPath name of the current
+ /// property. May be null if the value is not wanted.
+ ///
+ /// \param propValue A pointer to the string that is assigned the value of the current
+ /// property. May be null if the value is not wanted.
+ ///
+ /// \param options A pointer to the XMP_OptionBits variable that is assigned the flags
+ /// describing the current property.
+
+ bool
+ Next ( tStringObj * schemaNS = 0,
+ tStringObj * propPath = 0,
+ tStringObj * propValue = 0,
+ XMP_OptionBits * options = 0 );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Skip some portion of the remaining iterations.
+ ///
+ /// \param options Option flags to control the iteration.
+ ///
+ /// The available option flags are:
+ ///
+ /// \li \c kXMP_IterSkipSubtree - Skip the subtree below the current node.
+ /// \li \c kXMP_IterSkipSiblings - Skip the subtree below and remaining siblings of the current node.
+
+ void
+ Skip ( XMP_OptionBits options );
+
+private:
+
+ XMPIteratorRef iterRef;
+
+ TXMPIterator(); // ! Hidden, must choose property or table iteration.
+
+}; // class TXMPIterator
+
+// =================================================================================================
+
+#endif // __TXMPIterator_hpp__
diff --git a/public/include/TXMPMeta.hpp b/public/include/TXMPMeta.hpp
new file mode 100644
index 0000000..ef1a5fc
--- /dev/null
+++ b/public/include/TXMPMeta.hpp
@@ -0,0 +1,1599 @@
+#ifndef __TXMPMeta_hpp__
+#define __TXMPMeta_hpp__ 1
+
+#if ( ! __XMP_hpp__ )
+ #error "Do not directly include, use XMP.hpp"
+#endif
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+// ================================================================================================
+/// \file TXMPMeta.hpp
+/// \brief Template class for the XMP Toolkit core services.
+///
+/// TXMPMeta is the template class providing the core services of the XMP Toolkit. It should be
+/// instantiated with a string class such as <tt>std::string</tt>. Please read the general toolkit
+/// usage notes for information about the overall architecture of the XMP API.
+// ================================================================================================
+
+// ================================================================================================
+/// \class TXMPMeta TXMPMeta.hpp
+/// \brief Template class for the XMP Toolkit core services.
+///
+/// \c TXMPMeta is the template class providing the core services of the XMP Toolkit. It should be
+/// instantiated with a string class such as std::string. Please read the general toolkit usage notes
+/// for information about the overall architecture of the XMP API.
+///
+/// This template wraps a string object class around the raw XMP API. This provides two significant
+/// benefits, output strings are automatically copied and access is fully thread safe. The
+/// umbrella header, \c XMP.hpp, provides an \c SXMPMeta typedef for the instantiated template. String
+/// objects are only necessary for output strings. Input string are literals and passed as typical
+/// C <tt>const char *</tt>.
+///
+/// The template parameter, class \c TtStringObj, is described in the XMP.hpp umbrella header.
+///
+/// <b>Be aware that the \c TXMPMeta class is a normal C++ template, it is instantiated and local to
+/// each client executable. As are the other TXMP* classes. Different clients might not even use the
+/// same string type to instantiate \c TXMPMeta.</b>
+///
+/// Because of this you should not pass \c SXMPMeta objects, or pointers to \c SXMPMeta objects,
+/// across DLL boundaries. There is a safe internal reference that you can pass, then construct a
+/// local object on the callee side. This construction does not create a cloned XMP tree, it is the
+/// same underlying XMP object safely wrapped in each client's \c SXMPMeta object.
+///
+/// Use GetInternalRef and the associated constructor like this:
+/// \code
+/// --- The callee's header contains:
+/// CalleeMethod ( XMPMetaRef xmpRef );
+///
+/// --- The caller's code contains:
+/// SXMPMeta callerXMP;
+/// CalleeMethod ( callerXMP.GetInternalRef() );
+///
+/// --- The callee's code contains:
+/// SXMPMeta calleeXMP ( xmpRef );
+/// \endcode
+// ================================================================================================
+
+template <class tStringObj> class TXMPIterator;
+template <class tStringObj> class TXMPUtils;
+
+// -------------------------------------------------------------------------------------------------
+
+template <class tStringObj>
+class TXMPMeta {
+
+public:
+
+ // =============================================================================================
+ // Initialization and termination
+ // ==============================
+
+ // --------------------------------------------------------------------------------------------
+ /// \name Initialization and termination
+ /// @{
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Obtain version information.
+
+ static void
+ GetVersionInfo ( XMP_VersionInfo * info );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Initialize the XMP Toolkit.
+ ///
+ /// The XMP Toolkit may be explicitly initialized before use. The allocate/delete parameters must
+ /// be either both null (0), or both non-null.
+
+ static bool
+ Initialize();
+ // --------------------------------------------------------------------------------------------
+ /// \brief Terminate the XMP Toolkit.
+
+ static void
+ Terminate();
+
+ /// @}
+
+ // =============================================================================================
+ // Constuctors and destructor
+ // =========================
+
+ // --------------------------------------------------------------------------------------------
+ /// \name Constructors and destructor
+ /// @{
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Default constructor, creates an empty object.
+ ///
+ /// The default constructor creates a new empty \c TXMPMeta object.
+
+ TXMPMeta();
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Copy constructor, creates a client object refering to the same internal object.
+ ///
+ /// The copy constructor creates a new \c TXMPMeta object that refers to the same internal XMP object.
+
+ TXMPMeta ( const TXMPMeta<tStringObj> & original );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Assignment operator, assigns the internal ref and increments the ref count.
+ ///
+ /// The assignment operator assigns the internal ref from the rhs object and increments the
+ /// reference count on the underlying internal XMP object.
+
+ void operator= ( const TXMPMeta<tStringObj> & rhs );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Reconstruct an XMP object from an internal ref.
+ ///
+ /// This constructor creates a new \c TXMPMeta object that refers to the underlying \c xmpRef,
+ /// which was obtained from some other XMP object by the \c GetInternalRef method. This is used
+ /// to safely pass XMP objects across DLL boundaries.
+
+ TXMPMeta ( XMPMetaRef xmpRef );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Construct an object and parse one buffer of RDF into it.
+ ///
+ /// This constructor creates a new \c TXMPMeta object and populates it with metadata from a
+ /// buffer containing serialized RDF. This buffer must be a complete RDF parse stream. Pass
+ /// (0,0) to construct an empty \c TXMPMeta object. The result of an actual parse is identical
+ /// to creating an empty object then calling <tt>TXMPMeta::ParseFromBuffer</tt>. The RDF must be
+ /// complete. If you need to parse with multiple buffers, create an empty object and use
+ /// \c TXMPMeta::ParseFromBuffer.
+ ///
+ /// \param buffer A pointer to the buffer of RDF to be parsed. May be null if the length is 0.
+ ///
+ /// \param xmpSize The length in bytes of the buffer.
+
+ TXMPMeta ( XMP_StringPtr buffer,
+ XMP_StringLen xmpSize );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Destructor, typical virtual destructor.
+
+ virtual ~TXMPMeta() throw();
+
+ /// @}
+
+ // =============================================================================================
+ // Global state functions
+ // ======================
+
+ // --------------------------------------------------------------------------------------------
+ /// \name Global option flags
+ /// @{
+ /// The global option flags affect the overall behavior of the XMP Toolkit. The available options
+ /// are declared in <tt>XMP_Const.h</tt>. <b>(There are none at present.)</b>
+
+ /// \brief GetGlobalOptions returns the set of global option flags.
+
+ static XMP_OptionBits
+ GetGlobalOptions();
+
+ /// \brief \c SetGlobalOptions updates the set of global option flags. The entire set is
+ /// replaced with the new values. If only one flag is to be modified, use \c GetGlobalOptions
+ /// to obtain the current set, modify the desired flag, then use \c SetGlobalOptions.
+ ///
+ /// \note There are no options to set yet.
+
+ static void
+ SetGlobalOptions ( XMP_OptionBits options );
+
+ /// @}
+
+ // --------------------------------------------------------------------------------------------
+ /// \name Internal data structure dump utilities
+ /// @{
+ /// These are debugging utilities that dump internal data structures. The output callback is
+ /// described in <tt>XMP_Const.h</tt>.
+
+ /// \brief \c DumpNamespaces dumps the list of registered namespace URIs and prefixes.
+
+ static XMP_Status
+ DumpNamespaces ( XMP_TextOutputProc outProc,
+ void * refCon );
+
+ /// \brief \c DumpAliases dumps the list of registered aliases and corresponding actuals.
+
+ static XMP_Status
+ DumpAliases ( XMP_TextOutputProc outProc,
+ void * refCon );
+
+ /// @}
+
+ // --------------------------------------------------------------------------------------------
+ /// \name Namespace Functions
+ /// @{
+ /// Namespaces must be registered before use in namespace URI parameters or path expressions.
+ /// Within the XMP Toolkit the registered namespace URIs and prefixes must be unique. Additional
+ /// namespaces encountered when parsing RDF are automatically registered.
+ ///
+ /// The namespace URI should always end in an XML name separator such as '/' or '#'. This is
+ /// because some forms of RDF shorthand catenate a namespace URI with an element name to form a
+ /// new URI.
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Register a namespace URI with a suggested prefix.
+ ///
+ /// It is not an error if the URI is already registered, no matter what the prefix is. If the
+ /// URI is not registered but the suggested prefix is in use, a unique prefix is created from
+ /// the suggested one. The actual registeed prefix is always returned. The function result
+ /// tells if the registered prefix is the suggested one.
+ ///
+ /// \param namespaceURI The URI for the namespace. Must be a valid XML URI.
+ ///
+ /// \param suggestedPrefix The suggested prefix to be used if the URI is not yet registered.
+ /// Must be a valid XML name.
+ ///
+ /// \param registeredPrefix Returns the prefix actually registered for this URI.
+ ///
+ /// \result Returns true if the registered prefix matches the suggested prefix.
+ ///
+ /// \note No checking is presently done on either the URI or the prefix.
+
+ static bool
+ RegisterNamespace ( XMP_StringPtr namespaceURI,
+ XMP_StringPtr suggestedPrefix,
+ tStringObj * registeredPrefix );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Obtain the prefix for a registered namespace URI.
+ ///
+ /// It is not an error if the namespace URI is not registered. The output \c namespacePrefix
+ /// string is not modified if the namespace URI is not registered.
+ ///
+ /// \param namespaceURI The URI for the namespace. Must not be null or the empty string.
+ ///
+ /// \param namespacePrefix Returns the prefix registered for this URI, with a terminating ':'.
+ ///
+ /// \result Returns true if the namespace URI is registered.
+
+ static bool
+ GetNamespacePrefix ( XMP_StringPtr namespaceURI,
+ tStringObj * namespacePrefix );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Obtain the URI for a registered namespace prefix.
+ ///
+ /// It is not an error if the namespace prefix is not registered. The output \c namespaceURI
+ /// string is not modified if the namespace prefix is not registered.
+ ///
+ /// \param namespacePrefix The prefix for the namespace. Must not be null or the empty string.
+ ///
+ /// \param namespaceURI Returns the URI registered for this prefix.
+ ///
+ /// \result Returns true if the namespace prefix is registered.
+
+ static bool
+ GetNamespaceURI ( XMP_StringPtr namespacePrefix,
+ tStringObj * namespaceURI );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Delete a namespace from the registry.
+ ///
+ /// Does nothing if the URI is not registered, or if the \c namespaceURI parameter is null or the
+ /// empty string.
+ ///
+ /// \param namespaceURI The URI for the namespace.
+ ///
+ /// \note <b>Not yet implemented.</b>
+
+ static void
+ DeleteNamespace ( XMP_StringPtr namespaceURI );
+
+ /// @}
+
+ // --------------------------------------------------------------------------------------------
+ /// \name Alias Functions
+ /// @{
+ /// Aliases in XMP serve the same purpose as Windows file shortcuts, Macintosh file aliases, or
+ /// UNIX file symbolic links. The aliases are simply multiple names for the same property. One
+ /// distinction of XMP aliases is that they are ordered, there is an alias name pointing to an
+ /// actual name. The primary significance of the actual name is that it is the preferred name
+ /// for output, generally the most widely recognized name.
+ ///
+ /// The names that can be aliased in XMP are restricted. The alias must be a top level property
+ /// name, not a field within a structure or an element within an array. The actual may be a top
+ /// level property name, the first element within a top level array, or the default element in
+ /// an alt-text array. This does not mean the alias can only be a simple property. It is OK to
+ /// alias a top level structure or array to an identical top level structure or array, or to the
+ /// first item of an array of structures.
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Associates an alias name with an actual name.
+ ///
+ /// Define a alias mapping from one namespace/property to another. Both property names must be
+ /// simple names. An alias can be a direct mapping, where the alias and actual have the same
+ /// data type. It is also possible to map a simple alias to an item in an array. This can either
+ /// be to the first item in the array, or to the 'x-default' item in an alt-text array. Multiple
+ /// alias names may map to the same actual, as long as the forms match. It is a no-op to
+ /// reregister an alias in an identical fashion.
+ ///
+ /// \param aliasNS The namespace URI for the alias. Must not be null or the empty string.
+ ///
+ /// \param aliasProp The name of the alias. Must be a simple name, not null or the empty string
+ /// and not a general path expression.
+ ///
+ /// \param actualNS The namespace URI for the actual. Must not be null or the empty string.
+ ///
+ /// \param actualProp The name of the actual. Must be a simple name, not null or the empty string
+ /// and not a general path expression.
+ ///
+ /// \param arrayForm Provides the array form for simple aliases to an array item. This is needed
+ /// to know what kind of array to create if set for the first time via the simple alias. Pass
+ /// \c kXMP_NoOptions, the default value, for all direct aliases regardless of whether the actual
+ /// data type is an array or not.
+ ///
+ /// Constants for the arrayForm parameter:
+ ///
+ /// \li \c kXMP_NoOptions - This is a direct mapping. The actual data type does not matter.
+ /// \li \c kXMP_PropValueIsArray - The actual is an unordered array, the alias is to the first
+ /// element of the array.
+ /// \li \c kXMP_PropArrayIsOrdered - The actual is an ordered array, the alias is to the first
+ /// element of the array.
+ /// \li \c kXMP_PropArrayIsAlternate - The actual is an alternate array, the alias is to the first
+ /// element of the array.
+ /// \li \c kXMP_PropArrayIsAltText - The actual is an alternate text array, the alias is to the
+ /// 'x-default' element of the array.
+
+ static void
+ RegisterAlias ( XMP_StringPtr aliasNS,
+ XMP_StringPtr aliasProp,
+ XMP_StringPtr actualNS,
+ XMP_StringPtr actualProp,
+ XMP_OptionBits arrayForm = kXMP_NoOptions );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Determines if a name is an alias, and what it is aliased to.
+ ///
+ /// \param aliasNS The namespace URI for the alias. Must not be null or the empty string.
+ ///
+ /// \param aliasProp The name of the alias. May be an arbitrary path expression path, must not
+ /// null or the empty string.
+ ///
+ /// \param actualNS Untouched if <tt>aliasNS:aliasProp</tt> is not an alias. Otherwise returns
+ /// the namespace URI for the actual. May be null if the namespace URI is not wanted.
+ ///
+ /// \param actualProp Untouched if <tt>aliasNS:aliasProp</tt> is not an alias. Otherwise
+ /// returns the path of the actual. May be null if the actual's path is not wanted.
+ ///
+ /// \param arrayForm Untouched if <tt>aliasNS:aliasProp</tt> is not an alias. Otherwise returns
+ /// the form of the actual. This is 0 (\c kXMP_NoOptions) if the alias and actual forms match,
+ /// otherwise it is the options passed to <tt>TXMPMeta::RegisterAlias</tt>. May be null if the
+ /// actual's form is not wanted.
+ ///
+ /// \result Returns true if the input is an alias.
+ ///
+ /// \note The client output strings are not written until return, so a call like the following
+ /// may be used to "reduce" a path to the base form:
+ /// \code
+ /// isAlias = SXMPMeta::ResolveAlias ( ns.c_str(), path.c_str(), &ns, &path, 0 );
+ /// \endcode
+
+ static bool
+ ResolveAlias ( XMP_StringPtr aliasNS,
+ XMP_StringPtr aliasProp,
+ tStringObj * actualNS,
+ tStringObj * actualProp,
+ XMP_OptionBits * arrayForm );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Delete an alias.
+ ///
+ /// This only deletes the registration of the alias, it does not delete the actual property. It
+ /// does delete any view of the property through the alias name. It is OK to attempt to delete
+ /// an alias that does not exist, that is if the alias name is not registered as an alias.
+ ///
+ /// \param aliasNS The namespace URI for the alias. Must not be null or the empty string.
+ ///
+ /// \param aliasProp The name of the alias. Must be a simple name, not null or the empty string
+ /// and not a general path expression.
+
+ static void
+ DeleteAlias ( XMP_StringPtr aliasNS,
+ XMP_StringPtr aliasProp );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Registers all of the built-in aliases for a standard namespace.
+ ///
+ /// The built-in aliases are documented in the XMP Specification. This registers the aliases in
+ /// the given namespace, that is the aliases from this namespace to actuals in other namespaces.
+ ///
+ /// \param schemaNS The namespace URI for the aliases. Must not be null or the empty string.
+
+ static void
+ RegisterStandardAliases ( XMP_StringPtr schemaNS );
+
+ /// @}
+
+ // =============================================================================================
+ // Basic property manipulation functions
+ // =====================================
+
+ // *** Should add discussion of schemaNS and propName prefix usage.
+
+ // --------------------------------------------------------------------------------------------
+ /// \name Functions for getting property values
+ /// @{
+ /// The property value "getters" all take a property specification, The first two parameters
+ /// are always the top level namespace URI (the "schema" namespace) and the basic name of the
+ /// property being referenced. See the introductory discussion of path expression usage for
+ /// more information.
+ ///
+ /// All of the functions return a Boolean result telling if the property exists, and if it does
+ /// they also return option flags describing the property. If the property exists and has a
+ /// value, the string value is also returned. The string is Unicode in UTF-8 encoding. Arrays
+ /// and the non-leaf levels of structs do not have values. The possible option flags that
+ /// describe properties are:
+ ///
+ /// \li \c kXMP_PropValueIsURI - The property value is a URI. It is serialized to RDF using the
+ /// <tt>rdf:resource</tt> attribute. Not mandatory for URIs, but considered RDF-savvy.
+ ///
+ /// \li \c kXMP_PropHasQualifiers - The property has qualifiers. These could be an
+ /// <tt>xml:lang</tt> attribute, an <tt>rdf:type</tt> property, or a general qualifier. See the
+ /// introductory discussion of qualified properties for more information.
+ ///
+ /// \li \c kXMP_PropIsQualifier - This property is a qualifier for some other property. Note
+ /// that if the qualifier itself has a structured value, this flag is only set for the top node
+ /// of the qualifier's subtree. Qualifiers may have arbitrary structure, and may even have
+ /// qualifiers.
+ ///
+ /// \li \c kXMP_PropHasLang - This property has an <tt>xml:lang</tt> qualifier.
+ ///
+ /// \li \c kXMP_PropHasType - This property has an <tt>rdf:type</tt> qualifier.
+ ///
+ /// \li \c kXMP_PropValueIsStruct - This property contains nested fields (models a C struct).
+ ///
+ /// \li \c kXMP_PropValueIsArray - This property is an array. By itself (no ...ArrayIs... flags),
+ /// this indicates a general unordered array. It is serialized using an <tt>rdf:Bag</tt> container.
+ ///
+ /// \li \c kXMP_PropArrayIsOrdered - This property is an ordered array. Appears in conjunction
+ /// with \c kXMP_PropValueIsArray. It is serialized using an <tt>rdf:Seq</tt> container.
+ ///
+ /// \li \c kXMP_PropArrayIsAlternate - This property is an alternative array. Appears in
+ /// conjunction with \c kXMP_PropValueIsArray. It is serialized using an <tt>rdf:Alt</tt> container.
+ ///
+ /// \li \c kXMP_PropArrayIsAltText - This property is an alt-text array. Appears in conjunction
+ /// with \c kXMP_PropArrayIsAlternate. It is serialized using an <tt>rdf:Alt</tt> container. Each
+ /// array element is a simple property with an <tt>xml:lang</tt> attribute.
+ ///
+ /// \li \c kXMP_PropIsAlias - The given property name is an alias. This is only returned by
+ /// \c GetProperty and then only if the property name is simple, not an path expression.
+ ///
+ /// \li \c kXMP_PropHasAliases - The given property name has aliases. This is only returned by
+ /// \c GetProperty and then only if the property name is simple, not an path expression.
+ ///
+ /// \li \c kXMP_PropIsStable - The value of this property is not related to the document
+ /// content.
+ ///
+ /// \li \c kXMP_PropIsDerived - The value of this property is derived from the document
+ /// content.
+ ///
+ /// \li \c kXMP_PropIsInternal - The value of this property is "owned" by the application, it
+ /// should not generally be editable in a UI.
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief \c GetProperty is the simplest property getter, mainly for top level simple
+ /// properties or after using the path composition functions in \c TXMPUtils.
+ ///
+ /// \result Returns true if the property exists.
+ ///
+ /// \param schemaNS The namespace URI for the property. May be null or the empty string if the
+ /// first component of the propName path contains a namespace prefix. The URI must be for a
+ /// registered namespace.
+ ///
+ /// \param propName The name of the property. May be a general path expression, must not be
+ /// null or the empty string. Using a namespace prefix on the first component is optional. If
+ /// present without a \c schemaNS value then the prefix specifies the namespace. The prefix
+ /// must be for a registered namespace. If both a \c schemaNS URI and \c propName prefix are
+ /// present, they must be corresponding parts of a registered namespace.
+ ///
+ /// \param propValue A pointer to the string that is assigned the value of the property, if
+ /// the property has a value. Arrays and non-leaf levels of structs do not have values. May be
+ /// null if the value is not wanted.
+ ///
+ /// \param options A pointer to the \c XMP_OptionBits variable that is assigned option flags
+ /// describing the property. May be null if the flags are not wanted.
+
+ bool
+ GetProperty ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ tStringObj * propValue,
+ XMP_OptionBits * options ) const;
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief \c GetArrayItem provides access to items within an array. The index is passed as an
+ /// integer, you need not worry about the path string syntax for array items, convert a loop
+ /// index to a string, etc.
+ ///
+ /// \result Returns true if the array item exists.
+ ///
+ /// \param schemaNS The namespace URI for the array. Has the same usage as in \c GetProperty.
+ ///
+ /// \param arrayName The name of the array. May be a general path expression, must not be null
+ /// or the empty string. Has the same namespace prefix usage as \c propName in \c GeProperty.
+ ///
+ /// \param itemIndex The index of the desired item. Arrays in XMP are indexed from 1. The constant
+ /// \c kXMP_ArrayLastItem always refers to the last existing array item.
+ ///
+ /// \param itemValue A pointer to the string that is assigned the value of the array item, if
+ /// the array item has a value. Arrays and non-leaf levels of structs do not have values. May be
+ /// null if the value is not wanted.
+ ///
+ /// \param options A pointer to the \c XMP_OptionBits variable that is assigned option flags
+ /// describing the array item. May be null if the flags are not wanted.
+
+ bool
+ GetArrayItem ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex,
+ tStringObj * itemValue,
+ XMP_OptionBits * options ) const;
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief \c GetStructField provides access to fields within a nested structure. The namespace
+ /// for the field is passed as a URI, you need not worry about the path string syntax.
+ ///
+ /// The names of fields should be XML qualified names, that is within an XML namespace. The path
+ /// syntax for a qualified name uses the namespace prefix. This is unreliable since the prefix
+ /// is never guaranteed. The URI is the formal name, the prefix is just a local shorthand in a
+ /// given sequence of XML text.
+ ///
+ /// \result Returns true if the field exists.
+ ///
+ /// \param schemaNS The namespace URI for the struct. Has the same usage as in \c GetProperty.
+ ///
+ /// \param structName The name of the struct. May be a general path expression, must not be null
+ /// or the empty string. Has the same namespace prefix usage as \c propName in \c GetProperty.
+ ///
+ /// \param fieldNS The namespace URI for the field. Has the same URI and prefix usage as the
+ /// \c schemaNS parameter.
+ ///
+ /// \param fieldName The name of the field. Must be a single XML name, must not be null or the
+ /// empty string. Has the same namespace prefix usage as the \c structName parameter.
+ ///
+ /// \param fieldValue A pointer to the string that is assigned the value of the field, if
+ /// the field has a value. Arrays and non-leaf levels of structs do not have values. May be
+ /// null if the value is not wanted.
+ ///
+ /// \param options A pointer to the \c XMP_OptionBits variable that is assigned option flags
+ /// describing the field. May be null if the flags are not wanted.
+
+ bool
+ GetStructField ( XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ tStringObj * fieldValue,
+ XMP_OptionBits * options ) const;
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief \c GetQualifier provides access to a qualifier attached to a property. The namespace
+ /// for the qualifier is passed as a URI, you need not worry about the path string syntax. In
+ /// many regards qualifiers are like struct fields. See the introductory discussion of
+ /// qualified properties for more information.
+ ///
+ /// The names of qualifiers should be XML qualified names, that is within an XML namespace. The
+ /// path syntax for a qualified name uses the namespace prefix. This is unreliable since the
+ /// prefix is never guaranteed. The URI is the formal name, the prefix is just a local shorthand
+ /// in a given sequence of XML text.
+ ///
+ /// \note Qualifiers are only supported for simple leaf properties at this time.
+ ///
+ /// \result Returns true if the qualifier exists.
+ ///
+ /// \param schemaNS The namespace URI for the struct. Has the same usage as in \c GetProperty.
+ ///
+ /// \param propName The name of the property to which the qualifier is attached. May be a general
+ /// path expression, must not be null or the empty string. Has the same namespace prefix usage
+ /// as in \c GetProperty.
+ ///
+ /// \param qualNS The namespace URI for the qualifier. Has the same URI and prefix usage as the
+ /// \c schemaNS parameter.
+ ///
+ /// \param qualName The name of the qualifier. Must be a single XML name, must not be null or the
+ /// empty string. Has the same namespace prefix usage as the \c propName parameter.
+ ///
+ /// \param qualValue A pointer to the string that is assigned the value of the qualifier, if
+ /// the qualifier has a value. Arrays and non-leaf levels of structs do not have values. May be
+ /// null if the value is not wanted.
+ ///
+ /// \param options A pointer to the \c XMP_OptionBits variable that is assigned option flags
+ /// describing the qualifier. May be null if the flags are not wanted.
+
+ bool
+ GetQualifier ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName,
+ tStringObj * qualValue,
+ XMP_OptionBits * options ) const;
+
+ /// @}
+
+ // =============================================================================================
+
+ // --------------------------------------------------------------------------------------------
+ /// \name Functions for setting property values
+ /// @{
+ /// The property value "setters" all take a property specification, their differences are in
+ /// the form of this. The first two parameters are always the top level namespace URI (the
+ /// "schema" namespace) and the basic name of the property being referenced. See the
+ /// introductory discussion of path expression usage for more information.
+ ///
+ /// All of the functions take a string value for the property and option flags describing the
+ /// property. The value must be Unicode in UTF-8 encoding. Arrays and non-leaf levels of
+ /// structs do not have values. Empty arrays and structs may be created using appropriate
+ /// option flags. All levels of structs that is assigned implicitly are created if necessary.
+ /// \c AppendArayItem implicitly creates the named array if necessary.
+ ///
+ /// The canonical form of these functions take the value as an \c XMP_StringPtr, a pointer to a
+ /// null terminated string. (\c XMP_StringPtr is a typedef for <tt>const char *</tt>.) They
+ /// also have overloaded forms that take a string object. These are implemented in the template
+ /// instantiation as a call to the canonical form, using <tt>value.c_str()</tt> to obtain the
+ /// \c XMP_StringPtr.
+ ///
+ /// The possible option flags are:
+ ///
+ /// \li \c kXMP_PropValueIsURI - The property value is a URI. It is serialized to RDF using the
+ /// <tt>rdf:resource</tt> attribute. Not mandatory for URIs, but considered RDF-savvy.
+ ///
+ /// \li \c kXMP_PropValueIsStruct - This property contains nested fields (models a C struct).
+ /// Not necessary, may be used to create an empty struct. A struct is implicitly created when
+ /// first field is set.
+ ///
+ /// \li \c kXMP_PropValueIsArray - This property is an array. By itself (no ...ArrayIs...
+ /// flags), this indicates a general unordered array. It is serialized using an
+ /// <tt>rdf:Bag</tt> container.
+ ///
+ /// \li \c kXMP_PropArrayIsOrdered - This property is an ordered array. Implies \c
+ /// kXMP_PropValueIsArray, may be used together. It is serialized using an <tt>rdf:Seq</tt>
+ /// container.
+ ///
+ /// \li \c kXMP_PropArrayIsAlternate - This property is an alternative array. Implies \c
+ /// kXMP_PropArrayIsOrdered, may be used together. It is serialized using an <tt>rdf:Alt</tt>
+ /// container.
+ ///
+ /// \li \c kXMP_PropArrayIsAltText - This property is an alt-text array. Implies \c
+ /// kXMP_PropArrayIsAlternate, may be used together. It is serialized using an <tt>rdf:Alt</tt>
+ /// container. Each array element must be a simple property with an <tt>xml:lang</tt> attribute.
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief \c SetProperty is the simplest property setter, mainly for top level simple
+ /// properties or after using the path composition functions in \c TXMPUtils.
+ ///
+ /// \param schemaNS The namespace URI for the property. Has the same usage as in \c GetProperty.
+ ///
+ /// \param propName The name of the property. Has the same usage as in \c GetProperty.
+ ///
+ /// \param propValue A pointer to the null terminated UTF-8 string that is the value of the
+ /// property, if the property has a value. Arrays and non-leaf levels of structs do not have
+ /// values. Must be null if the value is not relevant.
+ ///
+ /// \param options Option flags describing the property. See the earlier description.
+
+ void
+ SetProperty ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr propValue,
+ XMP_OptionBits options = 0 );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief This form of \c SetProperty is a simple overload in the template that calls the above
+ /// form passing <tt>propValue.c_str()</tt>.
+
+ void
+ SetProperty ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ const tStringObj & propValue,
+ XMP_OptionBits options = 0 );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief \c SetArrayItem provides access to items within an array. The index is passed as an
+ /// integer, you need not worry about the path string syntax for array items, convert a loop
+ /// index to a string, etc. The array passed to \c SetArrayItem must already exist. See also
+ /// \c AppendArrayItem.
+ ///
+ /// In normal usage the selected array item is modified. A new item is automatically
+ /// appended if the index is the array size plus 1. A new item may be inserted before or after
+ /// any item by using one of the following option flags:
+ ///
+ /// \li \c kXMP_InsertBeforeItem - Insert a new array item before the selected one.
+ /// \li \c kXMP_InsertAfterItem - Insert a new array item after the selected one.
+ ///
+ /// \param schemaNS The namespace URI for the array. Has the same usage as in \c GetProperty.
+ ///
+ /// \param arrayName The name of the array. May be a general path expression, must not be null
+ /// or the empty string. Has the same namespace prefix usage as \c propName in \c GetProperty.
+ ///
+ /// \param itemIndex The index of the desired item. Arrays in XMP are indexed from 1. The
+ /// constant \c kXMP_ArrayLastItem always refers to the last existing array item.
+ ///
+ /// \param itemValue A pointer to the null terminated UTF-8 string that is the value of the array
+ /// item, if the array item has a value. Has the same usage as \c propValue in \c GetProperty.
+ ///
+ /// \param options Option flags describing the item. See the earlier description.
+
+ void
+ SetArrayItem ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex,
+ XMP_StringPtr itemValue,
+ XMP_OptionBits options = 0 );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief This form of \c SetArrayItem is a simple overload in the template that calls the above
+ /// form passing <tt>itemValue.c_str()</tt>.
+
+ void
+ SetArrayItem ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex,
+ const tStringObj & itemValue,
+ XMP_OptionBits options = 0 );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief \c AppendArrayItem simplifies construction of an array by not requiring that you
+ /// pre-create an empty array. The array that is assigned is created automatically if it does
+ /// not yet exist. Each call to \c AppendArrayItem appends an item to the array. The
+ /// corresponding parameters have the same use as \c SetArrayItem. The \c arrayOptions
+ /// parameter is used to specify what kind of array. If the array exists, it must have the
+ /// specified form.
+ ///
+ /// \param schemaNS The namespace URI for the array. Has the same usage as in \c GetProperty.
+ ///
+ /// \param arrayName The name of the array. May be a general path expression, must not be null
+ /// or the empty string. Has the same namespace prefix usage as \c propPath in \c GetProperty.
+ ///
+ /// \param arrayOptions Option flags describing the array form. The only valid bits are those
+ /// that are part of \c kXMP_PropArrayFormMask: \c kXMP_PropValueIsArray, \c
+ /// kXMP_PropArrayIsOrdered, \c kXMP_PropArrayIsAlternate, or \c kXMP_PropArrayIsAltText.
+ ///
+ /// \param itemValue A pointer to the null terminated UTF-8 string that is the value of the
+ /// array item, if the array item has a value. Has the same usage as \c propValue in \c
+ /// GetProperty.
+ ///
+ /// \param itemOptions Option flags describing the item. See the earlier description.
+
+ void
+ AppendArrayItem ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_OptionBits arrayOptions,
+ XMP_StringPtr itemValue,
+ XMP_OptionBits itemOptions = 0 );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief This form of \c AppendArrayItem is a simple overload in the template that calls the
+ /// above form passing <tt>itemValue.c_str()</tt>.
+
+ void
+ AppendArrayItem ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_OptionBits arrayOptions,
+ const tStringObj & itemValue,
+ XMP_OptionBits itemOptions = 0 );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief \c SetStructField provides access to fields within a nested structure. The namespace
+ /// for the field is passed as a URI, you need not worry about the path string syntax.
+ ///
+ /// The names of fields should be XML qualified names, that is within an XML namespace. The
+ /// path syntax for a qualified name uses the namespace prefix, which is unreliable because
+ /// the prefix is never guaranteed. The URI is the formal name, the prefix is just a local
+ /// shorthand in a given sequence of XML text.
+ ///
+ /// \param schemaNS The namespace URI for the struct. Has the same usage as in \c GetProperty.
+ ///
+ /// \param structName The name of the struct. May be a general path expression, must not be
+ /// null or the empty string. Has the same namespace prefix usage as \c propName in \c
+ /// GetProperty.
+ ///
+ /// \param fieldNS The namespace URI for the field. Has the same URI and prefix usage as the \c
+ /// schemaNS parameter.
+ ///
+ /// \param fieldName The name of the field. Must be a single XML name, must not be null or the
+ /// empty string. Has the same namespace prefix usage as the \c structName parameter.
+ ///
+ /// \param fieldValue A pointer to the null terminated UTF-8 string that is the value of the
+ /// field, if the field has a value. Has the same usage as \c propValue in \c GetProperty.
+ ///
+ /// \param options Option flags describing the field. See the earlier description.
+
+ void
+ SetStructField ( XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ XMP_StringPtr fieldValue,
+ XMP_OptionBits options = 0 );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief This form of \c SetStructField is a simple overload in the template that calls the
+ /// above form passing <tt>fieldValue.c_str()</tt>.
+
+ void
+ SetStructField ( XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ const tStringObj & fieldValue,
+ XMP_OptionBits options = 0 );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief \c SetQualifier provides access to a qualifier attached to a property. The namespace
+ /// for the qualifier is passed as a URI, you need not worry about the path string syntax. In
+ /// many regards qualifiers are like struct fields. See the introductory discussion of
+ /// qualified properties for more information.
+ ///
+ /// The names of qualifiers should be XML qualified names, that is within an XML namespace. The
+ /// path syntax for a qualified name uses the namespace prefix, which is unreliable because
+ /// the prefix is never guaranteed. The URI is the formal name, the prefix is just a local
+ /// shorthand in a given sequence of XML text.
+ ///
+ /// \param schemaNS The namespace URI for the struct. Has the same usage as in \c GetProperty.
+ ///
+ /// \param propName The name of the property to which the qualifier is attached. Has the same
+ /// usage as in \c GetProperty.
+ ///
+ /// \param qualNS The namespace URI for the qualifier. Has the same URI and prefix usage as the
+ /// \c schemaNS parameter.
+ ///
+ /// \param qualName The name of the qualifier. Must be a single XML name, must not be null or
+ /// the empty string. Has the same namespace prefix usage as the \c propName parameter.
+ ///
+ /// \param qualValue A pointer to the null terminated UTF-8 string that is the value of the
+ /// qualifier, if the qualifier has a value. Has the same usage as \c propValue in \c
+ /// GetProperty.
+ ///
+ /// \param options Option flags describing the qualifier. See the earlier description.
+
+ void
+ SetQualifier ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName,
+ XMP_StringPtr qualValue,
+ XMP_OptionBits options = 0 );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief This form of \c SetQualifier is a simple overload in the template that calls the above
+ /// form passing <tt>qualValue.c_str()</tt>.
+
+ void
+ SetQualifier ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName,
+ const tStringObj & qualValue,
+ XMP_OptionBits options = 0 );
+
+ /// @}
+
+ // =============================================================================================
+
+ // --------------------------------------------------------------------------------------------
+ /// \name Functions for deleting and detecting properties.
+ /// @{
+ /// These should be obvious from the descriptions of the getters and setters.
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief \c DeleteProperty deletes the given XMP subtree rooted at the given property. It is
+ /// not an error if the property does not exist.
+ ///
+ /// \param schemaNS The namespace URI for the property. Has the same usage as in \c GetProperty.
+ ///
+ /// \param propName The name of the property. Has the same usage as in \c GetProperty.
+
+ void
+ DeleteProperty ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief \c DeleteArrayItem deletes the given XMP subtree rooted at the given array item. It
+ /// is not an error if the array item does not exist.
+ ///
+ /// \param schemaNS The namespace URI for the array. Has the same usage as in \c GetProperty.
+ ///
+ /// \param arrayName The name of the array. May be a general path expression, must not be null
+ /// or the empty string. Has the same namespace prefix usage as \c propName in \c GetProperty.
+ ///
+ /// \param itemIndex The index of the desired item. Arrays in XMP are indexed from 1. The
+ /// constant \c kXMP_ArrayLastItem always refers to the last existing array item.
+
+ void
+ DeleteArrayItem ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief \c DeleteStructField deletes the given XMP subtree rooted at the given struct field.
+ /// It is not an error if the field does not exist.
+ ///
+ /// \param schemaNS The namespace URI for the struct. Has the same usage as in \c GetProperty.
+ ///
+ /// \param structName The name of the struct. May be a general path expression, must not be null
+ /// or the empty string. Has the same namespace prefix usage as \c propName in \c GetProperty.
+ ///
+ /// \param fieldNS The namespace URI for the field. Has the same URI and prefix usage as the
+ /// \c schemaNS parameter.
+ ///
+ /// \param fieldName The name of the field. Must be a single XML name, must not be null or the
+ /// empty string. Has the same namespace prefix usage as the \c structName parameter.
+
+ void
+ DeleteStructField ( XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief \c DeleteQualifier deletes the given XMP subtree rooted at the given qualifier. It
+ /// is not an error if the qualifier does not exist.
+ ///
+ /// \param schemaNS The namespace URI for the struct. Has the same usage as in \c GetProperty.
+ ///
+ /// \param propName The name of the property to which the qualifier is attached. Has the same
+ /// usage as in \c GetProperty.
+ ///
+ /// \param qualNS The namespace URI for the qualifier. Has the same URI and prefix usage as the
+ /// \c schemaNS parameter.
+ ///
+ /// \param qualName The name of the qualifier. Must be a single XML name, must not be null or the
+ /// empty string. Has the same namespace prefix usage as the \c propName parameter.
+
+ void
+ DeleteQualifier ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief \c DoesPropertyExist tells if the property exists.
+ ///
+ /// \result Returns true if the property exists.
+ ///
+ /// \param schemaNS The namespace URI for the property. Has the same usage as in \c GetProperty.
+ ///
+ /// \param propName The name of the property. Has the same usage as in \c GetProperty.
+
+ bool
+ DoesPropertyExist ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName ) const;
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief \c DoesArrayItemExist tells if the array item exists.
+ ///
+ /// \result Returns true if the array item exists.
+ ///
+ /// \param schemaNS The namespace URI for the array. Has the same usage as in \c GetProperty.
+ ///
+ /// \param arrayName The name of the array. May be a general path expression, must not be null
+ /// or the empty string. Has the same namespace prefix usage as \c propName in \c GetProperty.
+ ///
+ /// \param itemIndex The index of the desired item. Arrays in XMP are indexed from 1. The
+ /// constant \c kXMP_ArrayLastItem always refers to the last existing array item.
+
+ bool
+ DoesArrayItemExist ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex ) const;
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief \c DoesStructFieldExist tells if the struct field exists.
+ ///
+ /// \result Returns true if the field exists.
+ ///
+ /// \param schemaNS The namespace URI for the struct. Has the same usage as in \c GetProperty.
+ ///
+ /// \param structName The name of the struct. May be a general path expression, must not be null
+ /// or the empty string. Has the same namespace prefix usage as \c propName in \c GetProperty.
+ ///
+ /// \param fieldNS The namespace URI for the field. Has the same URI and prefix usage as the
+ /// \c schemaNS parameter.
+ ///
+ /// \param fieldName The name of the field. Must be a single XML name, must not be null or the
+ /// empty string. Has the same namespace prefix usage as the \c structName parameter.
+
+ bool
+ DoesStructFieldExist ( XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName ) const;
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief \c DoesQualifierExist tells if the qualifier exists.
+ ///
+ /// \result Returns true if the qualifier exists.
+ ///
+ /// \param schemaNS The namespace URI for the struct. Has the same usage as in \c GetProperty.
+ ///
+ /// \param propName The name of the property to which the qualifier is attached. Has the same
+ /// usage as in \c GetProperty.
+ ///
+ /// \param qualNS The namespace URI for the qualifier. Has the same URI and prefix usage as the
+ /// \c schemaNS parameter.
+ ///
+ /// \param qualName The name of the qualifier. Must be a single XML name, must not be null or the
+ /// empty string. Has the same namespace prefix usage as the \c propName parameter.
+
+ bool
+ DoesQualifierExist ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName ) const;
+
+ /// @}
+
+ // =============================================================================================
+ // Specialized Get and Set functions
+ // =================================
+
+ // --------------------------------------------------------------------------------------------
+ /// \name Functions for accessing localized text (alt-text) properties.
+ /// @{
+ /// These functions provide convenient support for localized text properties, including a number
+ /// of special and obscure aspects. Localized text properties are stored in alt-text arrays.
+ /// They allow multiple concurrent localizations of a property value, for example a document
+ /// title or copyright in several languages.
+ ///
+ /// The most important aspect of these functions is that they select an appropriate array item
+ /// based on one or two RFC 3066 language tags. One of these languages, the "specific" language,
+ /// is preferred and selected if there is an exact match. For many languages it is also possible
+ /// to define a "generic" language that may be used if there is no specific language match. The
+ /// generic language must be a valid RFC 3066 primary subtag, or the empty string.
+ ///
+ /// For example, a specific language of "en-US" should be used in the US, and a specific language
+ /// of "en-UK" should be used in England. It is also appropriate to use "en" as the generic
+ /// language in each case. If a US document goes to England, the "en-US" title is selected
+ /// by using the "en" generic language and the "en-UK" specific language.
+ ///
+ /// It is considered poor practice, but allowed, to pass a specific language that is just an
+ /// RFC 3066 primary tag. For example "en" is not a good specific language, it should only be
+ /// used as a generic language. Passing "i" or "x" as the generic language is also considered
+ /// poor practice but allowed.
+ ///
+ /// Advice from the W3C about the use of RFC 3066 language tags can be found at:
+ /// \li http://www.w3.org/International/articles/language-tags/
+ ///
+ /// \note RFC 3066 language tags must be treated in a case insensitive manner. The XMP toolkit
+ /// does this by normalizing their capitalization:
+ ///
+ /// \li The primary subtag is lower case, the suggested practice of ISO 639.
+ /// \li All 2 letter secondary subtags are upper case, the suggested practice of ISO 3166.
+ /// \li All other subtags are lower case.
+ ///
+ /// The XMP specification defines an artificial language, "x-default", that is used to
+ /// explicitly denote a default item in an alt-text array. The XMP toolkit normalizes alt-text
+ /// arrays such that the x-default item is the first item. The \c SetLocalizedText function has
+ /// several special features related to the x-default item, see its description for details.
+ ///
+ /// The selection of the array item is the same for \c GetLocalizedText and \c SetLocalizedText:
+ ///
+ /// \li Look for an exact match with the specific language.
+ /// \li If a generic language is given, look for a partial match.
+ /// \li Look for an x-default item.
+ /// \li Choose the first item.
+ ///
+ /// A partial match with the generic language is where the start of the item's language matches
+ /// the generic string and the next character is '-'. An exact match is also recognized as a
+ /// degenerate case.
+ ///
+ /// It is fine to pass x-default as the specific language. In this case, selection of an x-default
+ /// item is an exact match by the first rule, not a selection by the 3rd rule. The last 2 rules
+ /// are fallbacks used when the specific and generic languages fail to produce a match.
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief \c GetLocalizedText returns information about a selected item in an alt-text array.
+ /// The array item is selected according to the rules given above.
+ ///
+ /// \result Returns true if an appropriate array item exists.
+ ///
+ /// \param schemaNS The namespace URI for the alt-text array. Has the same usage as in \c
+ /// GetProperty.
+ ///
+ /// \param altTextName The name of the alt-text array. May be a general path expression, must
+ /// not be null or the empty string. Has the same namespace prefix usage as \c propName in \c
+ /// GetProperty.
+ ///
+ /// \param genericLang The name of the generic language as an RFC 3066 primary subtag. May be
+ /// null or the empty string if no generic language is wanted.
+ ///
+ /// \param specificLang The name of the specific language as an RFC 3066 tag. Must not be null
+ /// or the empty string.
+ ///
+ /// \param actualLang A pointer to the string that is assigned the language of the selected
+ /// array item, if an appropriate array item is found. May be null if the language is not
+ /// wanted.
+ ///
+ /// \param itemValue A pointer to the string that is assigned the value of the array item, if
+ /// an appropriate array item is found. May be null if the value is not wanted.
+ ///
+ /// \param options A pointer to the \c XMP_OptionBits variable that is assigned option flags
+ /// describing the array item. May be null if the flags are not wanted.
+
+ bool
+ GetLocalizedText ( XMP_StringPtr schemaNS,
+ XMP_StringPtr altTextName,
+ XMP_StringPtr genericLang,
+ XMP_StringPtr specificLang,
+ tStringObj * actualLang,
+ tStringObj * itemValue,
+ XMP_OptionBits * options ) const;
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief \c SetLocalizedText modifies the value of a selected item in an alt-text array.
+ /// Creates an appropriate array item if necessary, and handles special cases for the x-default
+ /// item.
+ ///
+ /// If the selected item is from a match with the specific language, the value of that item is
+ /// modified. If the existing value of that item matches the existing value of the x-default
+ /// item, the x-default item is also modified. If the array only has 1 existing item (which is
+ /// not x-default), an x-default item is added with the given value.
+ ///
+ /// If the selected item is from a match with the generic language and there are no other
+ /// generic matches, the value of that item is modified. If the existing value of that item
+ /// matches the existing value of the x-default item, the x-default item is also modified. If
+ /// the array only has 1 existing item (which is not x-default), an x-default item is added
+ /// with the given value.
+ ///
+ /// If the selected item is from a partial match with the generic language and there are other
+ /// partial matches, a new item is created for the specific language. The x-default item is not
+ /// modified.
+ ///
+ /// If the selected item is from the last 2 rules then a new item is created for the specific
+ /// language. If the array only had an x-default item, the x-default item is also modified. If
+ /// the array was empty, items are created for the specific language and x-default.
+ ///
+ /// \param schemaNS The namespace URI for the alt-text array. Has the same usage as in \c
+ /// GetProperty.
+ ///
+ /// \param altTextName The name of the alt-text array. May be a general path expression, must
+ /// not be null or the empty string. Has the same namespace prefix usage as \c propName in \c
+ /// GetProperty.
+ ///
+ /// \param genericLang The name of the generic language as an RFC 3066 primary subtag. May be
+ /// null or the empty string if no generic language is wanted.
+ ///
+ /// \param specificLang The name of the specific language as an RFC 3066 tag. Must not be null
+ /// or the empty string.
+ ///
+ /// \param itemValue A pointer to the null terminated UTF-8 string that is the new value for
+ /// the appropriate array item.
+ ///
+ /// \param options Option flags, none are defined at present.
+
+ void
+ SetLocalizedText ( XMP_StringPtr schemaNS,
+ XMP_StringPtr altTextName,
+ XMP_StringPtr genericLang,
+ XMP_StringPtr specificLang,
+ XMP_StringPtr itemValue,
+ XMP_OptionBits options = 0 );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief This form of \c SetLocalizedText is a simple overload in the template that calls the
+ /// above form passing <tt>itemValue.c_str()</tt>.
+
+ void
+ SetLocalizedText ( XMP_StringPtr schemaNS,
+ XMP_StringPtr altTextName,
+ XMP_StringPtr genericLang,
+ XMP_StringPtr specificLang,
+ const tStringObj & itemValue,
+ XMP_OptionBits options = 0 );
+
+ /// @}
+
+ // =============================================================================================
+
+ // --------------------------------------------------------------------------------------------
+ /// \name Functions accessing properties as binary values.
+ /// @{
+ /// These are very similar to \c GetProperty and \c SetProperty above, but the value is
+ /// returned or
+ /// provided in binary form instead of as a UTF-8 string. The path composition functions in
+ /// \c TXMPUtils may be used to compose an path expression for fields in nested structures, items
+ /// in arrays, or qualifiers.
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief \c GetProperty_Bool returns the value of a Boolean property as a C++ bool.
+ ///
+ /// \result Returns true if the property exists.
+ ///
+ /// \param schemaNS The namespace URI for the property. Has the same usage as in \c GetProperty.
+ ///
+ /// \param propName The name of the property. Has the same usage as in \c GetProperty.
+ ///
+ /// \param propValue A pointer to the bool variable that is assigned the value of the property.
+ /// May be null if the value is not wanted.
+ ///
+ /// \param options A pointer to the \c XMP_OptionBits variable that is assigned option flags
+ /// describing the property. May be null if the flags are not wanted.
+
+ bool
+ GetProperty_Bool ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ bool * propValue,
+ XMP_OptionBits * options ) const;
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief \c GetProperty_Int returns the value of an integer property as a C long integer.
+ ///
+ /// \result Returns true if the property exists.
+ ///
+ /// \param schemaNS The namespace URI for the property. Has the same usage as in \c GetProperty.
+ ///
+ /// \param propName The name of the property. Has the same usage as in \c GetProperty.
+ ///
+ /// \param propValue A pointer to the long integer variable that is assigned the value of
+ /// the property. May be null if the value is not wanted.
+ ///
+ /// \param options A pointer to the \c XMP_OptionBits variable that is assigned option flags
+ /// describing the property. May be null if the flags are not wanted.
+
+ bool
+ GetProperty_Int ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ long * propValue,
+ XMP_OptionBits * options ) const;
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief \c GetProperty_Int64 returns the value of an integer property as a C long long integer.
+ ///
+ /// \result Returns true if the property exists.
+ ///
+ /// \param schemaNS The namespace URI for the property. Has the same usage as in \c GetProperty.
+ ///
+ /// \param propName The name of the property. Has the same usage as in \c GetProperty.
+ ///
+ /// \param propValue A pointer to the long long integer variable that is assigned the value of
+ /// the property. May be null if the value is not wanted.
+ ///
+ /// \param options A pointer to the \c XMP_OptionBits variable that is assigned option flags
+ /// describing the property. May be null if the flags are not wanted.
+
+ bool
+ GetProperty_Int64 ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ long long * propValue,
+ XMP_OptionBits * options ) const;
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief \c GetProperty_Float returns the value of a flaoting point property as a C double float.
+ ///
+ /// \result Returns true if the property exists.
+ ///
+ /// \param schemaNS The namespace URI for the property. Has the same usage as in \c GetProperty.
+ ///
+ /// \param propName The name of the property. Has the same usage as in \c GetProperty.
+ ///
+ /// \param propValue A pointer to the double float variable that is assigned the value of
+ /// the property. May be null if the value is not wanted.
+ ///
+ /// \param options A pointer to the \c XMP_OptionBits variable that is assigned option flags
+ /// describing the property. May be null if the flags are not wanted.
+
+ bool
+ GetProperty_Float ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ double * propValue,
+ XMP_OptionBits * options ) const;
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief \c GetProperty_Date returns the value of a date/time property as an \c XMP_DateTime struct.
+ ///
+ /// \result Returns true if the property exists.
+ ///
+ /// \param schemaNS The namespace URI for the property. Has the same usage as in \c GetProperty.
+ ///
+ /// \param propName The name of the property. Has the same usage as in \c GetProperty.
+ ///
+ /// \param propValue A pointer to the \c XMP_DateTime variable that is assigned the value of
+ /// the property. May be null if the value is not wanted.
+ ///
+ /// \param options A pointer to the \c XMP_OptionBits variable that is assigned option flags
+ /// describing the property. May be null if the flags are not wanted.
+
+ bool
+ GetProperty_Date ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_DateTime * propValue,
+ XMP_OptionBits * options ) const;
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief \c SetProperty_Bool sets the value of a Boolean property from a C++ bool.
+ ///
+ /// \param schemaNS The namespace URI for the property. Has the same usage as in \c GetProperty.
+ ///
+ /// \param propName The name of the property. Has the same usage as in \c GetProperty.
+ ///
+ /// \param propValue The bool value to be assigned to the property.
+ ///
+ /// \param options A pointer to the \c XMP_OptionBits variable that is assigned option flags
+ /// describing the property. May be null if the flags are not wanted.
+
+ void
+ SetProperty_Bool ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ bool propValue,
+ XMP_OptionBits options = 0 );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief \c SetProperty_Int sets the value of an integer property from a C long integer.
+ ///
+ /// \param schemaNS The namespace URI for the property. Has the same usage as in \c GetProperty.
+ ///
+ /// \param propName The name of the property. Has the same usage as in \c GetProperty.
+ ///
+ /// \param propValue The long integer value to be assigned to the property.
+ ///
+ /// \param options Option flags describing the property.
+
+ void
+ SetProperty_Int ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ long propValue,
+ XMP_OptionBits options = 0 );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief \c SetProperty_Int64 sets the value of an integer property from a C long long integer.
+ ///
+ /// \param schemaNS The namespace URI for the property. Has the same usage as in \c GetProperty.
+ ///
+ /// \param propName The name of the property. Has the same usage as in \c GetProperty.
+ ///
+ /// \param propValue The long long integer value to be assigned to the property.
+ ///
+ /// \param options Option flags describing the property.
+
+ void
+ SetProperty_Int64 ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ long long propValue,
+ XMP_OptionBits options = 0 );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief \c SetProperty_Float sets the value of a floating point property from a C double float.
+ ///
+ /// \param schemaNS The namespace URI for the property. Has the same usage as in \c GetProperty.
+ ///
+ /// \param propName The name of the property. Has the same usage as in \c GetProperty.
+ ///
+ /// \param propValue The double float value to be assigned to the property.
+ ///
+ /// \param options Option flags describing the property.
+
+ void
+ SetProperty_Float ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ double propValue,
+ XMP_OptionBits options = 0 );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief \c SetProperty_Date sets the value of a date/time property from an \c XMP_DateTime struct.
+ ///
+ /// \param schemaNS The namespace URI for the property. Has the same usage as in \c GetProperty.
+ ///
+ /// \param propName The name of the property. Has the same usage as in \c GetProperty.
+ ///
+ /// \param propValue The \c XMP_DateTime value to be assigned to the property.
+ ///
+ /// \param options Option flags describing the property.
+
+ void
+ SetProperty_Date ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ const XMP_DateTime & propValue,
+ XMP_OptionBits options = 0 );
+
+ /// @}
+
+ // =============================================================================================
+ // Miscellaneous Member Functions
+ // ==============================
+
+ // --------------------------------------------------------------------------------------------
+ /// \name Misceallaneous functions.
+ /// @{
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief GetInternalRef Returns an internal reference that may be safely passed across DLL
+ /// boundaries and reconstructed.
+
+ XMPMetaRef
+ GetInternalRef() const;
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief GetObjectName --TBD--
+
+ void
+ GetObjectName ( tStringObj * name ) const;
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief SetObjectName --TBD--
+
+ void
+ SetObjectName ( XMP_StringPtr name );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief SetObjectName --TBD--
+
+ void
+ SetObjectName ( tStringObj name );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief GetObjectOptions --TBD--
+
+ XMP_OptionBits
+ GetObjectOptions() const;
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief SetObjectOptions --TBD--
+ ///
+ /// \note <b>Not yet implemented.</b> File a bug if you need this.
+
+ void
+ SetObjectOptions ( XMP_OptionBits options );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief \c Clone creates a deep clone of the XMP object.
+ ///
+ /// This function creates a deep clone of the XMP object. Assignment and copy constructors do
+ /// not, they just increment a reference count. Note that \c Clone returns an object, not a
+ /// pointer. This is easy to misuse:
+ ///
+ /// \code
+ /// SXMPMeta * clone1 = &sourceXMP.Clone(); // ! This does not work!
+ /// SXMPMeta * clone2 = new SXMPMeta ( sourceXMP.Clone() ); // This works.
+ /// SXMPMeta clone3 ( sourceXMP.Clone ); // This works also. (Not a pointer.)
+ /// \endcode
+ ///
+ /// In the code above, the assignment to \c clone1 creates a temporary object, initializes it
+ /// with the clone, assigns the address of the temporary to \c clone1, then deletes the
+ /// temporary. The \c clone3 example also works, you do not have to use an explicit pointer.
+ /// This is good for local usage, you don't have to worry about memory leaks.
+ ///
+ /// \param options Option flags, not are defined at present.
+ ///
+ /// \result An XMP object cloned from the original.
+
+ TXMPMeta
+ Clone ( XMP_OptionBits options = 0 ) const;
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief CountArrayItems --TBD--
+
+ XMP_Index
+ CountArrayItems ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName ) const;
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief \c DumpObject dumps the content of an XMP object.
+
+ XMP_Status
+ DumpObject ( XMP_TextOutputProc outProc,
+ void * refCon ) const;
+
+ /// @}
+
+ // =============================================================================================
+
+ // --------------------------------------------------------------------------------------------
+ /// \name Functions for parsing and serializing.
+ /// @{
+ /// These functions support parsing serialized RDF into an XMP object, and serailizing an XMP
+ /// object into RDF. The input for parsing may be any valid Unicode encoding. ISO Latin-1 is
+ /// also recognized, but its use is strongly discouraged. Serialization is always as UTF-8.
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief \c ParseFromBuffer parses RDF from a series of input buffers. The buffers may be any
+ /// length. The buffer boundaries need not respect XML tokens or even Unicode characters.
+ ///
+ /// \param buffer A pointer to a buffer of input. May be null if \c bufferSize is 0.
+ ///
+ /// \param bufferSize The length of this buffer in bytes. Zero is a valid value. Termination of
+ /// an input loop is convenient by passing \c kXMP_ParseMoreBuffers for all real input, then
+ /// having a final call with a zero length and \c kXMP_NoOptions.
+ ///
+ /// \param options Options controlling the parsing.
+ ///
+ /// The available options are:
+ ///
+ /// \li \c kXMP_ParseMoreBuffers - This is not the last buffer of input, more calls follow.
+ /// \li \c kXMP_RequireXMPMeta - The x:xmpmeta XML element is required around <tt>rdf:RDF</tt>.
+ /// \li \c kXMP_StrictAliasing - Do not reconcile alias differences, throw an exception.
+ ///
+ /// \note The \c kXMP_StrictAliasing option is not yet implemented.
+
+ void
+ ParseFromBuffer ( XMP_StringPtr buffer,
+ XMP_StringLen bufferSize,
+ XMP_OptionBits options = 0 );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief \c SerializeToBuffer serializes an XMP object into a string as RDF.
+ ///
+ /// \param rdfString A pointer to the string to receive the serialized RDF. Must not be null.
+ ///
+ /// \param options Option flags to control the serialization.
+ ///
+ /// \param padding The amount of padding to be added if a writeable XML packet is created. If
+ /// zero is passed (the default) an appropriate amount of padding is computed.
+ ///
+ /// \param newline The string to be used as a line terminator. If empty it defaults to
+ /// linefeed, U+000A, the standard XML newline.
+ ///
+ /// \param indent The string to be used for each level of indentation in the serialized RDF. If
+ /// empty it defaults to two ASCII spaces, U+0020.
+ ///
+ /// \param baseIndent The number of levels of indentation to be used for the outermost XML
+ /// element in the serialized RDF. This is convenient when embedding the RDF in other text.
+ ///
+ /// The available option flags are:
+ ///
+ /// \li \c kXMP_OmitPacketWrapper - Do not include an XML packet wrapper.
+ /// \li \c kXMP_ReadOnlyPacket - Create a read-only XML packet wapper.
+ /// \li \c kXMP_UseCompactFormat - Use a highly compact RDF syntax and layout.
+ /// \li \c kXMP_WriteAliasComments - Include XML comments for aliases.
+ /// \li \c kXMP_IncludeThumbnailPad - Include typical space for a JPEG thumbnail in the padding
+ /// if no <tt>xmp:Thumbnails</tt> property is present.
+ /// \li \c kXMP_ExactPacketLength - The padding parameter provides the overall packet length.
+ /// The actual amount of padding is computed. An exception is thrown if the packet exceeds this
+ /// length with no padding.
+ ///
+ /// The specified options must be logically consistent, an exception is thrown if not. You
+ /// cannot specify both \c kXMP_OmitPacketWrapper along with \c kXMP_ReadOnlyPacket, \c
+ /// kXMP_IncludeThumbnailPad, or \c kXMP_ExactPacketLength.
+ ///
+ /// In addition, one of the following encoding options may be included:
+ ///
+ /// \li \c kXMP_EncodeUTF8 - Encode as UTF-8, the default.
+ /// \li \c kXMP_EncodeUTF16Big - Encode as big-endian UTF-16.
+ /// \li \c kXMP_EncodeUTF16Little - Encode as little-endian UTF-16.
+ /// \li \c kXMP_EncodeUTF32Big - Encode as big-endian UTF-32.
+ /// \li \c kXMP_EncodeUTF32Little - Encode as little-endian UTF-32.
+
+ void
+ SerializeToBuffer ( tStringObj * rdfString,
+ XMP_OptionBits options,
+ XMP_StringLen padding,
+ XMP_StringPtr newline,
+ XMP_StringPtr indent = "",
+ XMP_Index baseIndent = 0 ) const;
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief This form of \c SerializeToBuffer is a simple overload in the template that calls the
+ /// above form passing default values for the \c newline, \c indent, and \c baseIndent
+ /// parameters.
+
+ void
+ SerializeToBuffer ( tStringObj * rdfString,
+ XMP_OptionBits options = 0,
+ XMP_StringLen padding = 0 ) const;
+
+ /// @}
+
+ // =============================================================================================
+
+ XMPMetaRef xmpRef; // *** Should be private, see below.
+
+private:
+
+#if 0 // *** VS.Net and gcc seem to not handle the friend declarations properly.
+ friend class TXMPIterator <class tStringObj>;
+ friend class TXMPUtils <class tStringObj>;
+#endif
+
+}; // class TXMPMeta
+
+#endif // __TXMPMeta_hpp__
diff --git a/public/include/TXMPUtils.hpp b/public/include/TXMPUtils.hpp
new file mode 100644
index 0000000..95cdc9c
--- /dev/null
+++ b/public/include/TXMPUtils.hpp
@@ -0,0 +1,845 @@
+#ifndef __TXMPUtils_hpp__
+#define __TXMPUtils_hpp__ 1
+
+#if ( ! __XMP_hpp__ )
+ #error "Do not directly include, use XMP.hpp"
+#endif
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+// ================================================================================================
+/// \file TXMPUtils.hpp
+/// \brief Template class for the XMP Toolkit utility services.
+///
+/// \c TXMPUtils is the template class providing utility services for the XMP Toolkit. It should be
+/// instantiated with a string class such as <tt>std::string</tt>. Please read the general toolkit
+/// usage notes for information about the overall architecture of the XMP API.
+// ================================================================================================
+
+// ================================================================================================
+/// \class TXMPUtils TXMPUtils.hpp
+/// \brief Template class for the XMP Toolkit utility services.
+///
+/// \c TXMPUtils is the template class providing utility services for the XMP Toolkit. It should be
+/// instantiated with a string class such as <tt>std::string</tt>. Please read the general toolkit
+/// usage notes for information about the overall architecture of the XMP API.
+///
+/// This is a class for C++ scoping purposes only. It has only static functions, you cannot create
+/// an object. These are all functions that layer cleanly on top of the core XMP toolkit. The
+/// template wraps a string class around the raw XMP API, so that output strings are automatically
+/// copied and access is fully thread safe. String objects are only necessary for output strings.
+/// Input strings are literals and passed as typical C <tt>const char *</tt>.
+///
+/// The template parameter, class \c TtStringObj, is described in the XMP.hpp umbrella header.
+// ================================================================================================
+
+template <class tStringObj>
+class TXMPUtils {
+
+public:
+
+ // =============================================================================================
+ // No constructors or destructor declared or needed
+ // ================================================
+
+ // =============================================================================================
+ // =============================================================================================
+
+ // ============================================================================================
+ /// \name Path composition functions
+ /// @{
+ /// These functions provide support for composing path expressions to deeply nested properties.
+ /// The functions in \c TXMPMeta such as \c GetProperty, \c GetArrayItem, and \c GetStructField
+ /// provide easy access to top level simple properties, items in top level arrays, and fields
+ /// of top level structs. They do not provide convenient access to more complex things like
+ /// fields several levels deep in a complex struct, or fields within an array of structs, or
+ /// items of an array that is a field of a struct. These functions can also be used to compose
+ /// paths to top level array items or struct fields so that you can use the binary accessors
+ /// like \c GetProperty_Int.
+ ///
+ /// You can use these functions is to compose a complete path expression, or all but the last
+ /// component. Suppose you have a property that is an array of integers within a struct. You can
+ /// access one of the array items like this:
+ ///
+ /// \verbatim
+ /// SXMPUtils::ComposeStructFieldPath ( schemaNS, "Struct", fieldNS, "Array", &path );
+ /// SXMPUtils::ComposeArrayItemPath ( schemaNS, path, index, &path );
+ /// exists = xmpObj.GetProperty_Int ( schemaNS, path, &value, &options );
+ /// \endverbatim
+ ///
+ /// You could also use this code if you want the string form of the integer:
+ ///
+ /// \verbatim
+ /// SXMPUtils::ComposeStructFieldPath ( schemaNS, "Struct", fieldNS, "Array", &path );
+ /// xmpObj.GetArrayItem ( schemaNS, path, index, &value, &options );
+ /// \endverbatim
+ ///
+ /// \note It might look confusing that the \c schemaNS is passed in all of the calls above. This
+ /// is because the XMP toolkit keeps the top level "schema" namespace separate from the rest
+ /// of the path expression.
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Compose the path expression for an item in an array.
+ ///
+ /// \param schemaNS The namespace URI for the array. Must not be null or the empty string.
+ ///
+ /// \param arrayName The name of the array. May be a general path expression, must not be null
+ /// or the empty string.
+ ///
+ /// \param itemIndex The index of the desired item. Arrays in XMP are indexed from 1. The
+ /// constant \c kXMP_ArrayLastItem always refers to the last existing array item.
+ ///
+ /// \param fullPath A pointer to the string that will be assigned the composed path. This will
+ /// be of the form <tt>ns:arrayName[i]</tt>, where "ns" is the prefix for \c schemaNS and "i"
+ /// is the decimal representation of \c itemIndex. If the value of \c itemIndex is
+ /// \c kXMP_ArrayLastItem, the path is <tt>ns:arrayName[last()]</tt>.
+
+ static void
+ ComposeArrayItemPath ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex,
+ tStringObj * fullPath );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Compose the path expression for a field in a struct.
+ ///
+ /// \param schemaNS The namespace URI for the struct. Must not be null or the empty string.
+ ///
+ /// \param structName The name of the struct. May be a general path expression, must not be null
+ /// or the empty string.
+ ///
+ /// \param fieldNS The namespace URI for the field. Must not be null or the empty string.
+ ///
+ /// \param fieldName The name of the field. Must be a simple XML name, must not be null or the
+ /// empty string.
+ ///
+ /// \param fullPath A pointer to the string that will be assigned the composed path. This will
+ /// be of the form <tt>ns:structName/fNS:fieldName</tt>, where "ns" is the prefix for
+ /// \c schemaNS and "fNS" is the prefix for \c fieldNS.
+
+ static void
+ ComposeStructFieldPath ( XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ tStringObj * fullPath );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Compose the path expression for a qualifier.
+ ///
+ /// \param schemaNS The namespace URI for the property to which the qualifier is attached. Must
+ /// not be null or the empty string.
+ ///
+ /// \param propName The name of the property to which the qualifier is attached. May be a general
+ /// path expression, must not be null or the empty string.
+ ///
+ /// \param qualNS The namespace URI for the qualifier. May be null or the empty string if the
+ /// qualifier is in the XML empty namespace.
+ ///
+ /// \param qualName The name of the qualifier. Must be a simple XML name, must not be null or the
+ /// empty string.
+ ///
+ /// \param fullPath A pointer to the string that will be assigned the composed path. This will
+ /// be of the form <tt>ns:propName/?qNS:qualName</tt>, where "ns" is the prefix for \c schemaNS
+ /// and "qNS" is the prefix for \c qualNS.
+
+ static void
+ ComposeQualifierPath ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName,
+ tStringObj * fullPath );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Compose the path expression to select an alternate item by language.
+ ///
+ /// The path syntax allows two forms of "content addressing" that may be used to select an item
+ /// in an array of alternatives. The form used in \c ComposeLangSelector lets you select an
+ /// item in an alt-text array based on the value of its <tt>xml:lang</tt> qualifier. The other
+ /// form of content addressing is shown in \c ComposeFieldSelector.
+ ///
+ /// \note \c ComposeLangSelector does not supplant \c SetLocalizedText or \c GetLocalizedText.
+ /// They should generally be used, as they provide extra logic to choose the appropriate
+ /// language and maintain consistency with the 'x-default' value. \c ComposeLangSelector gives
+ /// you an path expression that is explicitly and only for the language given in the
+ /// \c langName parameter.
+ ///
+ /// \param schemaNS The namespace URI for the array. Must not be null or the empty string.
+ ///
+ /// \param arrayName The name of the array. May be a general path expression, must not be null
+ /// or the empty string.
+ ///
+ /// \param langName The RFC 3066 code for the desired language.
+ ///
+ /// \param fullPath A pointer to the string that will be assigned the composed path. This will
+ /// be of the form <tt>ns:arrayName[\@xml:lang='langName']</tt>,
+ /// where "ns" is the prefix for \c schemaNS.
+
+ static void
+ ComposeLangSelector ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_StringPtr langName,
+ tStringObj * fullPath );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief This form of \c ComposeLangSelector is a simple overload in the template that calls
+ /// the above form passing <tt>langName.c_str()</tt>.
+
+ static void
+ ComposeLangSelector ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ const tStringObj & langName,
+ tStringObj * fullPath );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Compose the path expression to select an alternate item by a field's value.
+ ///
+ /// The path syntax allows two forms of "content addressing" that may be used to select an item
+ /// in an array of alternatives. The form used in \c ComposeFieldSelector lets you select an
+ /// item in an array of structs based on the value of one of the fields in the structs. The
+ /// other form of content addressing is shown in \c ComposeLangSelector.
+ ///
+ /// For example, consider a simple struct that has two fields, the name of a city and the URI
+ /// of an FTP site in that city. Use this to create an array of download alternatives. You can
+ /// show the user a popup built from the values of the city fields. You can then get the
+ /// corresponding URI as follows:
+ ///
+ /// \verbatim
+ /// ComposeFieldSelector ( schemaNS, "Downloads", fieldNS, "City", chosenCity, &path );
+ /// exists = GetStructField ( schemaNS, path, fieldNS, "URI", &uri );
+ /// \endverbatim
+ ///
+ /// \param schemaNS The namespace URI for the array. Must not be null or the empty string.
+ ///
+ /// \param arrayName The name of the array. May be a general path expression, must not be null
+ /// or the empty string.
+ ///
+ /// \param fieldNS The namespace URI for the field used as the selector. Must not be null or the
+ /// empty string.
+ ///
+ /// \param fieldName The name of the field used as the selector. Must be a simple XML name, must
+ /// not be null or the empty string. It must be the name of a field that is itself simple.
+ ///
+ /// \param fieldValue The desired value of the field.
+ ///
+ /// \param fullPath A pointer to the string that will be assigned the composed path. This will
+ /// be of the form <tt>ns:arrayName[fNS:fieldName='fieldValue']</tt>, where "ns" is the prefix
+ /// for \c schemaNS and "fNS" is the prefix for \c fieldNS.
+
+ static void
+ ComposeFieldSelector ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ XMP_StringPtr fieldValue,
+ tStringObj * fullPath );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief This form of ComposeFieldSelector is a simple overload in the template that calls the
+ /// above form passing <tt>fieldValue.c_str()</tt>.
+
+ static void
+ ComposeFieldSelector ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ const tStringObj & fieldValue,
+ tStringObj * fullPath );
+
+ /// @}
+
+ // =============================================================================================
+ // =============================================================================================
+
+ // ============================================================================================
+ /// \name Binary-String conversion functions
+ /// @{
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Convert from Boolean to string.
+ ///
+ /// \param binValue The Boolean value to be converted.
+ ///
+ /// \param strValue The string representation of the Boolean. The values used are given by the
+ /// macros \c kXMP_TrueStr and \c kXMP_FalseStr found in \c XMP_Const.h.
+
+ static void
+ ConvertFromBool ( bool binValue,
+ tStringObj * strValue );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Convert from integer to string.
+ ///
+ /// \param binValue The integer value to be converted.
+ ///
+ /// \param format Optional C sprintf format for the conversion. Defaults to "%d".
+ ///
+ /// \param strValue The string representation of the integer.
+
+ static void
+ ConvertFromInt ( long binValue,
+ XMP_StringPtr format,
+ tStringObj * strValue );
+
+ static void
+ ConvertFromInt64 ( long long binValue,
+ XMP_StringPtr format,
+ tStringObj * strValue );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Convert from floating point to string.
+ ///
+ /// \param binValue The floating point value to be converted.
+ ///
+ /// \param format Optional C sprintf format for the conversion. Defaults to "%f".
+ ///
+ /// \param strValue The string representation of the floating point value.
+
+ static void
+ ConvertFromFloat ( double binValue,
+ XMP_StringPtr format,
+ tStringObj * strValue );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Convert from date/time to string.
+ ///
+ /// Format a date according to the ISO 8601 profile in http://www.w3.org/TR/NOTE-datetime:
+ /// YYYY
+ /// YYYY-MM
+ /// YYYY-MM-DD
+ /// YYYY-MM-DDThh:mmTZD
+ /// YYYY-MM-DDThh:mm:ssTZD
+ /// YYYY-MM-DDThh:mm:ss.sTZD
+ ///
+ /// YYYY = four-digit year
+ /// MM = two-digit month (01=January, etc.)
+ /// DD = two-digit day of month (01 through 31)
+ /// hh = two digits of hour (00 through 23)
+ /// mm = two digits of minute (00 through 59)
+ /// ss = two digits of second (00 through 59)
+ /// s = one or more digits representing a decimal fraction of a second
+ /// TZD = time zone designator (Z or +hh:mm or -hh:mm)
+ ///
+ /// \note ISO 8601 does not seem to allow years less than 1000 or greater than 9999. We allow
+ /// any year, even negative ones. The year is formatted as "%.4d".
+ ///
+ /// \note As a compatibility "tactic" (OK, a hack), so-called time-only input is allowed where
+ /// the year, month, and day are all zero. This is output as "0000-00-00...".
+ ///
+ /// \param binValue The \c XMP_DateTime value to be converted.
+ ///
+ /// \param strValue The ISO 8601 string representation of the date/time.
+
+ static void
+ ConvertFromDate ( const XMP_DateTime & binValue,
+ tStringObj * strValue );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Convert from string to Boolean.
+ ///
+ /// \param strValue The string representation of the Boolean.
+ ///
+ /// \result The appropriate C++ bool value for the string. The preferred strings are
+ /// \c kXMP_TrueStr and \c kXMP_FalseStr. If these do not match, a case insensitive comparison is
+ /// tried, then simply 't' or 'f', and finally non-zero and zero integer representations.
+
+ static bool
+ ConvertToBool ( XMP_StringPtr strValue );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief This form of \c ConvertToBool is a simple overload in the template that calls the
+ /// above form passing <tt>strValue.c_str()</tt>.
+
+ static bool
+ ConvertToBool ( const tStringObj & strValue );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Convert from string to integer.
+ ///
+ /// \param strValue The string representation of the integer.
+ ///
+ /// \result The integer value as a C long.
+
+ static long
+ ConvertToInt ( XMP_StringPtr strValue );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief This form of \c ConvertToInt is a simple overload in the template that calls the above
+ /// form passing <tt>strValue.c_str()</tt>.
+
+ static long
+ ConvertToInt ( const tStringObj & strValue );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Convert from string to 64 bit integer.
+ ///
+ /// \param strValue The string representation of the integer.
+ ///
+ /// \result The integer value as a C long long.
+
+ static long long
+ ConvertToInt64 ( XMP_StringPtr strValue );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief This form of ConvertToInt64 is a simple overload in the template that calls the above
+ /// form passing <tt>strValue.c_str()</tt>.
+
+ static long long
+ ConvertToInt64 ( const tStringObj & strValue );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Convert from string to floating point.
+ ///
+ /// \param strValue The string representation of the floating point value.
+ ///
+ /// \result The floating point value.
+
+ static double
+ ConvertToFloat ( XMP_StringPtr strValue );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief This form of \c ConvertToFloat is a simple overload in the template that calls the
+ /// above form passing <tt>strValue.c_str()</tt>.
+
+ static double
+ ConvertToFloat ( const tStringObj & strValue );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Convert from string to date/time.
+ ///
+ /// Parse a date according to the ISO 8601 profile in http://www.w3.org/TR/NOTE-datetime:
+ /// YYYY
+ /// YYYY-MM
+ /// YYYY-MM-DD
+ /// YYYY-MM-DDThh:mmTZD
+ /// YYYY-MM-DDThh:mm:ssTZD
+ /// YYYY-MM-DDThh:mm:ss.sTZD
+ ///
+ /// YYYY = four-digit year
+ /// MM = two-digit month (01=January, etc.)
+ /// DD = two-digit day of month (01 through 31)
+ /// hh = two digits of hour (00 through 23)
+ /// mm = two digits of minute (00 through 59)
+ /// ss = two digits of second (00 through 59)
+ /// s = one or more digits representing a decimal fraction of a second
+ /// TZD = time zone designator (Z or +hh:mm or -hh:mm)
+ ///
+ /// \note ISO 8601 does not seem to allow years less than 1000 or greater than 9999. We allow
+ /// any year, even negative ones. The year is assumed to be formatted as "%.4d".
+ ///
+ /// \note As compatibility "tactics" (OK, hacks), a missing date portion or missing TZD are
+ /// tolerated. A missing date value may begin with "Thh:" or "hh:"; the year, month, and day are
+ /// all set to zero in the XMP_DateTime value. A missing TZD is assumed to be UTC.
+ ///
+ /// \param strValue The ISO 8601 string representation of the date/time.
+ ///
+ /// \param binValue A pointer to the \c XMP_DateTime variable to be assigned the date/time components.
+
+ static void
+ ConvertToDate ( XMP_StringPtr strValue,
+ XMP_DateTime * binValue );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief This form of \c ConvertToDate is a simple overload in the template that calls the above
+ /// form passing s<tt>strValue.c_str()</tt>.
+
+ static void
+ ConvertToDate ( const tStringObj & strValue,
+ XMP_DateTime * binValue );
+
+ /// @}
+
+ // =============================================================================================
+ // =============================================================================================
+
+ // ============================================================================================
+ /// \name Date/Time functions
+ /// @{
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Obtain the current date and time.
+ ///
+ /// \param time A pointer to the \c XMP_DateTime variable to be assigned the current date
+ /// and time. The returned time is UTC, properly adjusted for the local time zone. The
+ /// resolution of the time is not guaranteed to be finer than seconds.
+
+ static void
+ CurrentDateTime ( XMP_DateTime * time );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Set the local time zone.
+ ///
+ /// \param time A pointer to the \c XMP_DateTime variable containing the value to be modified. Any
+ /// existing time zone value is replaced, the other date/time fields are not adjusted in any way.
+
+ static void
+ SetTimeZone ( XMP_DateTime * time );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Make sure a time is UTC.
+ ///
+ /// \param time A pointer to the \c XMP_DateTime variable containing the time to be modified. If
+ /// the time zone is not UTC, the time is adjusted and the time zone set to be UTC.
+
+ static void
+ ConvertToUTCTime ( XMP_DateTime * time );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Make sure a time is local.
+ ///
+ /// \param time A pointer to the \c XMP_DateTime variable containing the time to be modified. If
+ /// the time zone is not the local zone, the time is adjusted and the time zone set to be local.
+
+ static void
+ ConvertToLocalTime ( XMP_DateTime * time );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Compare the order of two date/time values.
+ ///
+ /// \param left The "lefthand" date/time.
+ ///
+ /// \param right The "righthand" date/time.
+ ///
+ /// \result
+ /// \li -1 if left is before right
+ /// \li 0 if left matches right
+ /// \li +1 if left is after right
+
+ static int
+ CompareDateTime ( const XMP_DateTime & left,
+ const XMP_DateTime & right );
+
+ /// @}
+
+ // =============================================================================================
+ // =============================================================================================
+
+ // ============================================================================================
+ /// \name Base 64 Encoding and Decoding
+ /// @{
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Convert from raw data to Base64 encoded string.
+ ///
+ /// \param rawStr The pointer to raw data to be converted.
+ ///
+ /// \param rawLen The length of raw data to be converted.
+ ///
+ /// \param encodedStr The XMP object to contain the encoded string.
+
+ static void
+ EncodeToBase64 ( XMP_StringPtr rawStr,
+ XMP_StringLen rawLen,
+ tStringObj * encodedStr );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief This form of \c EncodeToBase64 is a simple overload in the template that calls the
+ /// above form passing <tt>rawStr.c_str()</tt>, and <tt>rawStr.size()</tt>.
+
+ static void
+ EncodeToBase64 ( const tStringObj & rawStr,
+ tStringObj * encodedStr );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Decode from Base64 encoded string to raw data.
+ ///
+ /// \param encodedStr The pointer to encoded data to be converted.
+ ///
+ /// \param encodedLen The length of encoded datavto be converted.
+ ///
+ /// \param rawStr The XMP object to contain the decoded string.
+
+ static void
+ DecodeFromBase64 ( XMP_StringPtr encodedStr,
+ XMP_StringLen encodedLen,
+ tStringObj * rawStr );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief This form of \c DecodeFromBase64 is a simple overload in the template that calls the
+ /// above form passing <tt>encodedStr.c_str()</tt>, and <tt>encodedStr.size()</tt>.
+
+ static void
+ DecodeFromBase64 ( const tStringObj & encodedStr,
+ tStringObj * rawStr );
+
+ /// @}
+
+ // =============================================================================================
+ // =============================================================================================
+
+ // ============================================================================================
+ /// \name JPEG file handling
+ /// @{
+ /// These functions support the partitioning of XMP in JPEG files into standard and extended
+ /// portions in order to work around the 64KB size limit of JPEG marker segments.
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Create XMP serializations appropriate for a JPEG file. The standard XMP in a JPEG
+ /// file is limited to about 65500 bytes. \c PackageForJPEG attempts to fit the serialization
+ /// within that limit. If necessary it will partition the XMP into 2 serializations.
+ ///
+ /// \param xmpObj The XMP for the JPEG file.
+ ///
+ /// \param standardXMP The full standard XMP packet.
+ ///
+ /// \param extendedXMP The serialized extended XMP, empty if not needed.
+ ///
+ /// \param extendedDigest An MD5 digest of the serialized extended XMP, empty if not needed.
+
+ static void
+ PackageForJPEG ( const TXMPMeta<tStringObj> & xmpObj,
+ tStringObj * standardXMP,
+ tStringObj * extendedXMP,
+ tStringObj * extendedDigest );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Put the extended XMP properties back into the full XMP.
+ ///
+ /// \param fullXMP The full XMP, presumed to be initialized from the standard XMP packet.
+ ///
+ /// \param extendedXMP The properties that were partitioned into the extended XMP.
+
+ static void
+ MergeFromJPEG ( TXMPMeta<tStringObj> * fullXMP,
+ const TXMPMeta<tStringObj> & extendedXMP );
+
+ /// @}
+
+ // =============================================================================================
+ // =============================================================================================
+
+ // ============================================================================================
+ /// \name UI helper functions
+ /// @{
+ /// These functions are mainly of interest in implementing a user interface for editing XMP.
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Create a single edit string from an array of strings.
+ ///
+ /// TBD - needs more description
+ ///
+ /// \param xmpObj The XMP object containing the array to be catenated.
+ ///
+ /// \param schemaNS The schema namespace URI for the array. Must not be null or the empty string.
+ ///
+ /// \param arrayName The name of the array. May be a general path expression, must not be null
+ /// or the empty string. Each item in the array must be a simple string value.
+ ///
+ /// \param separator The string to be used to separate the items in the catenated string.
+ /// Defaults to "; ", ASCII semicolon and space (U+003B, U+0020).
+ ///
+ /// \param quotes The characters to be used as quotes around array items that contain a separator.
+ /// Defaults to '"', ASCII quote (U+0022).
+ ///
+ /// \param options Option flags to control the catenation.
+ ///
+ /// \param catedStr A pointer to the string to be assigned the catenated array items.
+
+ static void
+ CatenateArrayItems ( const TXMPMeta<tStringObj> & xmpObj,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_StringPtr separator,
+ XMP_StringPtr quotes,
+ XMP_OptionBits options,
+ tStringObj * catedStr );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Separate a single edit string into an array of strings.
+ ///
+ /// TBD - needs more description
+ ///
+ /// \param xmpObj The XMP object containing the array to be updated.
+ ///
+ /// \param schemaNS The schema namespace URI for the array. Must not be null or the empty string.
+ ///
+ /// \param arrayName The name of the array. May be a general path expression, must not be null
+ /// or the empty string. Each item in the array must be a simple string value.
+ ///
+ /// \param options Option flags to control the separation.
+ ///
+ /// \param catedStr The string to be separated into the array items.
+
+ static void
+ SeparateArrayItems ( TXMPMeta<tStringObj> * xmpObj,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_OptionBits options,
+ XMP_StringPtr catedStr );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief This form of \c SeparateArrayItems is a simple overload in the template that calls
+ /// the aboveform passing <tt>catedStr.c_str()</tt>.
+
+ static void
+ SeparateArrayItems ( TXMPMeta<tStringObj> * xmpObj,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_OptionBits options,
+ const tStringObj & catedStr );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Remove multiple properties from an XMP object.
+ ///
+ /// \c RemoveProperties was created to support the File Info dialog's Delete button, and has
+ /// been been generalized somewhat from those specific needs. It operates in one of three main
+ /// modes depending on the schemaNS and propName parameters:
+ ///
+ /// \li Non-empty \c schemaNS and \c propName - The named property is removed if it is an
+ /// external property, or if the \c kXMPUtil_DoAllProperties option is passed. It does not
+ /// matter whether the named property is an actual property or an alias.
+ ///
+ /// \li Non-empty \c schemaNS and empty \c propName - The all external properties in the named
+ /// schema are removed. Internal properties are also removed if the \c kXMPUtil_DoAllProperties
+ /// option is passed. In addition, aliases from the named schema will be removed if the \c
+ /// kXMPUtil_IncludeAliases option is passed.
+ ///
+ /// \li Empty \c schemaNS and empty \c propName - All external properties in all schema are
+ /// removed. Internal properties are also removed if the \c kXMPUtil_DoAllProperties option is
+ /// passed. Aliases are implicitly handled because the associated actuals are.
+ ///
+ /// It is an error to pass and empty schemaNS and non-empty propName.
+ ///
+ /// \param xmpObj The XMP object containing the properties to be removed.
+ ///
+ /// \param schemaNS Optional schema namespace URI for the properties to be removed.
+ ///
+ /// \param propName Optional path expression for the property to be removed.
+ ///
+ /// \param options Option flags to control the deletion. The defined flags are:
+ /// \li \c kXMPUtil_DoAllProperties - Do internal properties in addition to external properties.
+ /// \li \c kXMPUtil_IncludeAliases - Include aliases in the "named schema" case above.
+
+ static void
+ RemoveProperties ( TXMPMeta<tStringObj> * xmpObj,
+ XMP_StringPtr schemaNS = 0,
+ XMP_StringPtr propName = 0,
+ XMP_OptionBits options = 0 );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Append properties from one XMP object to another.
+ ///
+ /// \c AppendProperties was created to support the File Info dialog's Append button, and has
+ /// been been generalized somewhat from those specific needs. It appends information from one
+ /// XMP object (\c source) to another (\c dest). The default operation is to append only external
+ /// properties that do not already exist in the destination. The kXMPUtil_DoAllProperties option
+ /// can be used to operate on all properties, external and internal. The kXMPUtil_ReplaceOldValues
+ /// option can be used to replace the values of existing properties. The notion of external
+ /// versus internal applies only to top level properties. The keep-or-replace-old notion applies
+ /// within structs and arrays as described below.
+ ///
+ /// If kXMPUtil_ReplaceOldValues is passed then the processing is restricted to the top level
+ /// properties. The processed properties from the source (according to kXMPUtil_DoAllProperties)
+ /// are propagated to the destination, replacing any existing values. Properties in the destination
+ /// that are not in the source are left alone.
+ ///
+ /// If kXMPUtil_ReplaceOldValues is not passed then the processing is more complicated. Top level
+ /// properties are added to the destination if they do not already exist. If they do exist but
+ /// differ in form (simple/struct/array) then the destination is left alone. If the forms match,
+ /// simple properties are left unchanged while structs and arrays are merged.
+ ///
+ /// If kXMPUtil_DeleteEmptyValues is passed then an empty value in the source XMP causes the
+ /// corresponding Dest XMP property to be deleted. The default is to treat empty values the same
+ /// as non-empty values. An empty value is any of a simple empty string, an array with no items,
+ /// or a struct with no fields. Qualifiers are ignored.
+ ///
+ /// The detailed behavior is defined by the following pseudo-code:
+ /// \verbatim
+ /// AppendProperties ( sourceXMP, destXMP, options ):
+ /// doAll = options & kXMPUtil_DoAllProperties
+ /// replaceOld = options & kXMPUtil_ReplaceOldValues
+ /// deleteEmpty = options & kXMPUtil_DeleteEmptyValues
+ /// for all source schema (top level namespaces):
+ /// for all top level properties in sourceSchema:
+ /// if doAll or prop is external:
+ /// AppendSubtree ( sourceNode, destSchema, replaceOld, deleteEmpty )
+ ///
+ /// AppendSubtree ( sourceNode, destParent, replaceOld, deleteEmpty ):
+ /// if deleteEmpty and source value is empty:
+ /// delete the corresponding child from destParent
+ /// else if sourceNode not in destParent (by name):
+ /// copy sourceNode's subtree to destParent
+ /// else if replaceOld:
+ /// delete subtree from destParent
+ /// copy sourceNode's subtree to destParent
+ /// else:
+ /// // Already exists in dest and not replacing, merge structs and arrays
+ /// if sourceNode and destNode forms differ:
+ /// return, leave the destNode alone
+ /// else if form is a struct:
+ /// for each field in sourceNode:
+ /// AppendSubtree ( sourceNode.field, destNode, replaceOld )
+ /// else if form is an alt-text array:
+ /// copy new items by xml:lang value into the destination
+ /// else if form is an array:
+ /// copy new items by value into the destination, ignoring order and duplicates
+ /// \endverbatim
+ ///
+ /// \note \c AppendProperties can be expensive if replaceOld is not passed and the XMP contains
+ /// large arrays. The array item checking described above is n-squared. Each source item is
+ /// checked to see if it already exists in the destination, without regard to order or duplicates.
+ /// Simple items are compared by value and xml:lang qualifier, other qualifiers are ignored.
+ /// Structs are recursively compared by field names, without regard to field order. Arrays are
+ /// compared by recursively comparing all items.
+ ///
+ /// \param source The source XMP object.
+ ///
+ /// \param dest The destination XMP object.
+ ///
+ /// \param options Option flags to control the copying.
+ /// \li \c kXMPUtil_DoAllProperties - Do internal properties in addition to external properties.
+ /// \li \c kXMPUtil_ReplaceOldValues - Replace the values of existing properties.
+ /// \li \c kXMPUtil_DeleteEmptyValues - Delete properties if the new value is empty.
+
+ static void
+ AppendProperties ( const TXMPMeta<tStringObj> & source,
+ TXMPMeta<tStringObj> * dest,
+ XMP_OptionBits options = 0 );
+
+ // --------------------------------------------------------------------------------------------
+ /// \brief Replicate a subtree from one XMP object into another, possibly at a different location.
+ ///
+ /// TBD - needs more description
+ ///
+ /// \param source The source XMP object.
+ ///
+ /// \param dest The destination XMP object.
+ ///
+ /// \param sourceNS The schema namespace URI for the source subtree.
+ ///
+ /// \param sourceRoot The root location for the source subtree. May be a general path expression,
+ /// must not be null or the empty string.
+ ///
+ /// \param destNS The schema namespace URI for the destination. Defaults to the source namespace.
+ ///
+ /// \param destRoot The root location for the destination. May be a general path expression.
+ /// Defaults to the source location.
+ ///
+ /// \param options Option flags to control the separation.
+
+ static void
+ DuplicateSubtree ( const TXMPMeta<tStringObj> & source,
+ TXMPMeta<tStringObj> * dest,
+ XMP_StringPtr sourceNS,
+ XMP_StringPtr sourceRoot,
+ XMP_StringPtr destNS = 0,
+ XMP_StringPtr destRoot = 0,
+ XMP_OptionBits options = 0 );
+
+
+ /// @}
+
+ // =============================================================================================
+
+}; // class TXMPUtils
+
+// =================================================================================================
+
+#endif // __TXMPUtils_hpp__
diff --git a/public/include/XMP.hpp b/public/include/XMP.hpp
new file mode 100644
index 0000000..2ceb936
--- /dev/null
+++ b/public/include/XMP.hpp
@@ -0,0 +1,98 @@
+#ifndef __XMP_hpp__
+#define __XMP_hpp__ 1
+
+// =================================================================================================
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+// ================================================================================================
+/// \file XMP.hpp
+/// \brief Overall header file for the XMP toolkit.
+///
+/// This is an overall header file, the only one that C++ clients should #include. The full client
+/// API is in the \c TXMPMeta.hpp, \c TXMPIterator.hpp, \c TXMPUtils.hpp headers. Read these for
+/// information, but do not #include them directly. The \c TXMP... classes are C++ template classes
+/// that must be instantiated with a string class such as <tt>std::string<\tt>. The string class is
+/// used to return text strings for property values, serialized XMP, etc.
+///
+/// Clients must also compile <tt>XMP.incl_cpp<\tt> to ensure that all client-side glue code is
+/// generated. This should be done by #including it in exactly one client source file.
+///
+/// There are two C preprocessor macros that simplify use of the templates:
+///
+/// \li \c TXMP_STRING_TYPE - Define this as the string class to use with the template. You will get
+/// the template headers included and typedefs (\c SXMPMeta, and so on) to use in your code.
+///
+/// \li \c TXMP_EXPAND_INLINE - Define this as 1 if you want to have the template functions expanded
+/// inline in your code. Leave it undefined, or defined as 0, to use out-of-line instantiations of
+/// the template functions. Compiling <tt>XMP.incl_cpp<\tt> generates explicit out-of-line
+/// instantiations if \c TXMP_EXPAND_INLINE is off.
+///
+/// The template parameter, class \c tStringObj, must have the following member functions (which match
+/// those for <tt>std::string<\tt>):
+/// \code
+/// tStringObj& assign ( const char * str, size_t len )
+/// size_t size() const
+/// const char * c_str() const
+/// \endcode
+/// The string class must be suitable for at least UTF-8. This is the encoding used for all general
+/// values, and is the default encoding for serialized XMP. The string type must also be suitable
+/// for UTF-16 or UTF-32 if those serialization encodings are used. This mainly means tolerating
+/// embedded 0 bytes, which std::string does.
+// ================================================================================================
+
+
+#include "XMP_Environment.h" // ! This must be the first include!
+#include "XMP_Version.h"
+#include "XMP_Const.h"
+
+#if XMP_WinBuild
+ #if XMP_DebugBuild
+ #pragma warning ( push, 4 )
+ #else
+ #pragma warning ( push, 3 )
+ #endif
+ #pragma warning ( disable : 4702 ) // unreachable code
+ #pragma warning ( disable : 4800 ) // forcing value to bool 'true' or 'false' (performance warning)
+#endif
+
+#if defined ( TXMP_STRING_TYPE )
+
+ #include "TXMPMeta.hpp"
+ #include "TXMPIterator.hpp"
+ #include "TXMPUtils.hpp"
+
+ typedef class TXMPMeta <TXMP_STRING_TYPE> SXMPMeta; // For client convenience.
+ typedef class TXMPIterator <TXMP_STRING_TYPE> SXMPIterator;
+ typedef class TXMPUtils <TXMP_STRING_TYPE> SXMPUtils;
+
+ #if TXMP_EXPAND_INLINE
+ #error "TXMP_EXPAND_INLINE is not working at present. Please don't use it."
+ #include "client-glue/TXMPMeta.incl_cpp"
+ #include "client-glue/TXMPIterator.incl_cpp"
+ #include "client-glue/TXMPUtils.incl_cpp"
+ #include "client-glue/TXMPFiles.incl_cpp"
+ #endif
+
+ #if XMP_INCLUDE_XMPFILES
+ #include "TXMPFiles.hpp" // ! Needs typedef for SXMPMeta.
+ typedef class TXMPFiles <TXMP_STRING_TYPE> SXMPFiles;
+ #if TXMP_EXPAND_INLINE
+ #include "client-glue/TXMPFiles.incl_cpp"
+ #endif
+ #endif
+
+#endif // TXMP_STRING_TYPE
+
+#if XMP_WinBuild
+ #pragma warning ( pop )
+#endif
+
+
+// =================================================================================================
+
+#endif // __XMP_hpp__
diff --git a/public/include/XMP.incl_cpp b/public/include/XMP.incl_cpp
new file mode 100644
index 0000000..19b4b5f
--- /dev/null
+++ b/public/include/XMP.incl_cpp
@@ -0,0 +1,69 @@
+#ifndef __XMP_incl_cpp__
+#define __XMP_incl_cpp__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+// ================================================================================================
+/// \file XMP.incl_cpp
+/// \brief Overall client glue file for the XMP toolkit.
+///
+/// This is an overall client source file of XMP toolkit glue, the only XMP-specific one that
+/// clients should build in projects. This ensures that all of the client-side glue code for the
+/// XMP toolkit gets compiled.
+///
+/// You cannot compile this file directly, because the template's string type must be declared and
+/// only the client can do that. Instead, include this in some other source file. For example,
+/// to use <tt>std::string</tt> you only need these two lines:
+///
+/// \code
+/// #include <string>
+/// #include "XMP.incl_cpp"
+/// \endcode
+
+
+#include "XMP.hpp" // ! This must be the first include!
+
+#define XMP_ClientBuild 1
+
+#if XMP_WinBuild
+ #if XMP_DebugBuild
+ #pragma warning ( push, 4 )
+ #else
+ #pragma warning ( push, 3 )
+ #endif
+ #pragma warning ( disable : 4189 ) // local variable is initialized but not referenced
+ #pragma warning ( disable : 4702 ) // unreachable code
+ #pragma warning ( disable : 4800 ) // forcing value to bool 'true' or 'false' (performance warning)
+#endif
+
+#if defined ( TXMP_STRING_TYPE ) && (! TXMP_EXPAND_INLINE)
+
+ // We're using a single out of line instantiation. Do it here.
+
+ #include "client-glue/TXMPMeta.incl_cpp"
+ #include "client-glue/TXMPIterator.incl_cpp"
+ #include "client-glue/TXMPUtils.incl_cpp"
+
+ template class TXMPMeta <TXMP_STRING_TYPE>;
+ template class TXMPIterator <TXMP_STRING_TYPE>;
+ template class TXMPUtils <TXMP_STRING_TYPE>;
+
+ #if XMP_INCLUDE_XMPFILES
+ #include "client-glue/TXMPFiles.incl_cpp"
+ template class TXMPFiles <TXMP_STRING_TYPE>;
+ #endif
+
+#endif
+
+#if XMP_WinBuild
+ #pragma warning ( pop )
+#endif
+
+#endif // __XMP_incl_cpp__
diff --git a/public/include/XMP_Const.h b/public/include/XMP_Const.h
new file mode 100644
index 0000000..57605bd
--- /dev/null
+++ b/public/include/XMP_Const.h
@@ -0,0 +1,913 @@
+#ifndef __XMP_Const_h__
+#define __XMP_Const_h__ 1
+
+/* --------------------------------------------------------------------------------------------- */
+/* ** IMPORTANT ** This file must be usable by strict ANSI C compilers. No "//" comments, etc. */
+/* --------------------------------------------------------------------------------------------- */
+
+/*
+// =================================================================================================
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+*/
+
+#include "XMP_Environment.h"
+
+ #include <stddef.h>
+
+#if XMP_MacBuild /* ! No stdint.h on Windows and some UNIXes. */
+ #include <stdint.h>
+#endif
+
+#if __cplusplus
+extern "C" {
+#endif
+
+
+/** ================================================================================================
+ * \file XMP_Const.h
+ * \brief Common C/C++ types and constants for the XMP toolkit.
+ */
+
+
+/* ============================================================================================== */
+/* Basic types and constants */
+/* ========================= */
+
+/* The XMP_... types are used on the off chance that the ..._t types present a problem. In that */
+/* case only the declarations of the XMP_... types needs to change, not all of the uses. These */
+/* types are used where fixed sizes are required in order to have a known ABI for a DLL build. */
+
+#if XMP_MacBuild
+
+ typedef int8_t XMP_Int8;
+ typedef int16_t XMP_Int16;
+ typedef int32_t XMP_Int32;
+ typedef int64_t XMP_Int64;
+
+ typedef uint8_t XMP_Uns8;
+ typedef uint16_t XMP_Uns16;
+ typedef uint32_t XMP_Uns32;
+ typedef uint64_t XMP_Uns64;
+
+#else
+
+ typedef signed char XMP_Int8;
+ typedef signed short XMP_Int16;
+ typedef signed long XMP_Int32;
+ typedef signed long long XMP_Int64;
+
+ typedef unsigned char XMP_Uns8;
+ typedef unsigned short XMP_Uns16;
+ typedef unsigned long XMP_Uns32;
+ typedef unsigned long long XMP_Uns64;
+
+#endif
+
+typedef XMP_Uns8 XMP_Bool;
+
+/* Typedefs to preserve old, unfortunate spellings: */
+
+#if 0 /* *** Enable after internal compiles work. */
+typedef XMP_Int8 XMPInt8;
+typedef XMP_Int16 XMPInt16;
+typedef XMP_Int32 XMPInt32;
+typedef XMP_Int64 XMPInt64;
+typedef XMP_Uns8 XMPUns8;
+typedef XMP_Uns16 XMPUns16;
+typedef XMP_Uns32 XMPUns32;
+typedef XMP_Uns64 XMPUns64;
+typedef XMP_Bool XMPBool;
+#endif
+
+/**
+ * \typedef XMPMetaRef
+ * \brief An "ABI safe" pointer to the internal part of an XMP object.
+ *
+ * \c XMPMetaRef is an "ABI safe" pointer to the internal part of an XMP object. It should be used
+ * for passing an XMP object across client DLL boundaries. See the discussion in <tt>TXMPMeta.hpp</tt>.
+ */
+
+typedef struct __XMPMeta__ * XMPMetaRef;
+typedef struct __XMPIterator__ * XMPIteratorRef;
+typedef struct __XMPFiles__ * XMPFilesRef;
+
+/* ============================================================================================== */
+
+/**
+ * \name General scalar types and constants
+ * @{
+ */
+
+/**
+ * \typedef XMP_StringPtr
+ * \brief The type for input string parameters. A <tt>const char *</tt>, a null-terminated UTF-8 string.
+ *
+ */
+
+/**
+ * \typedef XMP_StringLen
+ * \brief The type for string length parameters. A 32-bit unsigned integer, as big as will be
+ * practically needed.
+ */
+
+/**
+ * \typedef XMP_Index
+ * \brief The type for offsets and indices. A 32-bit signed integer. It is signed because that
+ * often makes loop termination tests safer.
+ */
+
+/**
+ * \typedef XMP_OptionBits
+ * \brief The type for a collection of 32 flag bits. Individual flags are defined as enum value
+ * bit masks. A number of macros provide common set or set operations, e.g. \c XMP_PropIsSimple.
+ * For other tests use an expression like "options & kXMP_<theOption>". When passing multiple
+ * option flags use the bitwise-or operator. '|', not the arithmatic plus, '+'.
+ */
+
+typedef const char * XMP_StringPtr; /* Points to a null terminated UTF-8 string. */
+typedef XMP_Uns32 XMP_StringLen;
+typedef XMP_Int32 XMP_Index; /* Signed, sometimes -1 is handy. */
+typedef XMP_Uns32 XMP_OptionBits; /* Used as 32 individual bits. */
+
+/**
+ * \def kXMP_TrueStr
+ * \brief The canonical true string value for Booleans in serialized XMP. Code that converts
+ * from the string to a bool should be case insensitive, and even allow "1".
+ */
+
+/**
+ * \def kXMP_FalseStr
+ * \brief The canonical false string value for Booleans in serialized XMP. Code that converts
+ * from the string to a bool should be case insensitive, and even allow "0".
+ */
+
+#define kXMP_TrueStr "True" /* Serialized XMP spellings, not for the type bool. */
+#define kXMP_FalseStr "False"
+
+/**
+ * @}
+ */
+
+/* ============================================================================================== */
+
+/**
+ * \struct XMP_DateTime
+ * \brief The expanded type for a date and time. Dates and time in the serialized XMP are ISO 8601
+ * strings. The \c XMP_DateTime struct allows easy conversion with other formats.
+ *
+ * All of the fields are 32 bit, even though most could be 8 bit. This avoids overflow when doing
+ * carries for arithmetic or normalization. All fields have signed values for the same reasons.
+ *
+ * The fields of the \c XMP_DateTime struct are:
+ *
+ * \li year- The year, can be negative.
+ * \li month - The month in the range 1..12.
+ * \li day - The day of the month in the range 1..31.
+ * \li hour - The hour in the range 0..23.
+ * \li minute - The minute in the range 0..59.
+ * \li second - The second in the range 0..59.
+ * \li tzSign - The "sign" of the time zone, 0 means UTC, -1 is west, +1 is east.
+ * \li tzHour - The time zone hour in the range 0..23.
+ * \li tzMinute - The time zone minute in the range 0..59.
+ * \li nanoSecond - Nanoseconds within a second, often left as zero.
+ *
+ * Constants for the \c tzSign are:
+ *
+ * \li \c kXMP_TimeIsUTC - The time is UTC.
+ * \li \c kXMP_TimeWestOfUTC - The time zone is west of UTC, behind in time.
+ * \li \c kXMP_TimeEastOfUTC - The time zone is east of UTC, ahead in time.
+ *
+ * DateTime values are occasionally used in cases with only a date or only a time component. A date
+ * without a time has zeros in the \c XMP_DateTime struct for all time fields. A time without a date
+ * has zeros for all date fields (year, month, and day).
+ */
+
+struct XMP_DateTime {
+ XMP_Int32 year;
+ XMP_Int32 month; /* 1..12 */
+ XMP_Int32 day; /* 1..31 */
+ XMP_Int32 hour; /* 0..23 */
+ XMP_Int32 minute; /* 0..59 */
+ XMP_Int32 second; /* 0..59 */
+ XMP_Int32 tzSign; /* -1..+1, 0 means UTC, -1 is west, +1 is east. */
+ XMP_Int32 tzHour; /* 0..23 */
+ XMP_Int32 tzMinute; /* 0..59 */
+ XMP_Int32 nanoSecond;
+};
+
+enum { /* Values used for tzSign field. */
+ kXMP_TimeWestOfUTC = -1,
+ kXMP_TimeIsUTC = 0,
+ kXMP_TimeEastOfUTC = +1
+};
+
+
+/* ============================================================================================== */
+/* Standard namespace URI constants */
+/* ================================ */
+
+/**
+ * \name XML namespace constants for standard XMP schema.
+ * @{
+ */
+
+/**
+ * \def kXMP_NS_XMP
+ * \brief The XML namespace for the XMP "basic" schema.
+ */
+
+/**
+ * \def kXMP_NS_XMP_Rights
+ * \brief The XML namespace for the XMP copyright schema.
+ */
+
+/**
+ * \def kXMP_NS_XMP_MM
+ * \brief The XML namespace for the XMP digital asset management schema.
+ */
+
+/**
+ * \def kXMP_NS_XMP_BJ
+ * \brief The XML namespace for the job management schema.
+ */
+
+/**
+ * \def kXMP_NS_XMP_T
+ * \brief The XML namespace for the XMP text document schema.
+ */
+
+/**
+ * \def kXMP_NS_XMP_T_PG
+ * \brief The XML namespace for the XMP paged document schema.
+ */
+
+/**
+ * \def kXMP_NS_PDF
+ * \brief The XML namespace for the PDF schema.
+ */
+
+/**
+ * \def kXMP_NS_Photoshop
+ * \brief The XML namespace for the Photoshop custom schema.
+ */
+
+/**
+ * \def kXMP_NS_EXIF
+ * \brief The XML namespace for Adobe's EXIF schema.
+ */
+
+/**
+ * \def kXMP_NS_TIFF
+ * \brief The XML namespace for Adobe's TIFF schema.
+ */
+
+/**
+ * @}
+ */
+
+#define kXMP_NS_XMP "http://ns.adobe.com/xap/1.0/"
+
+#define kXMP_NS_XMP_Rights "http://ns.adobe.com/xap/1.0/rights/"
+#define kXMP_NS_XMP_MM "http://ns.adobe.com/xap/1.0/mm/"
+#define kXMP_NS_XMP_BJ "http://ns.adobe.com/xap/1.0/bj/"
+
+#define kXMP_NS_PDF "http://ns.adobe.com/pdf/1.3/"
+#define kXMP_NS_Photoshop "http://ns.adobe.com/photoshop/1.0/"
+#define kXMP_NS_PSAlbum "http://ns.adobe.com/album/1.0/"
+#define kXMP_NS_EXIF "http://ns.adobe.com/exif/1.0/"
+#define kXMP_NS_EXIF_Aux "http://ns.adobe.com/exif/1.0/aux/"
+#define kXMP_NS_TIFF "http://ns.adobe.com/tiff/1.0/"
+#define kXMP_NS_PNG "http://ns.adobe.com/png/1.0/"
+#define kXMP_NS_SWF "http://ns.adobe.com/swf/1.0/"
+#define kXMP_NS_JPEG "http://ns.adobe.com/jpeg/1.0/"
+#define kXMP_NS_JP2K "http://ns.adobe.com/jp2k/1.0/"
+#define kXMP_NS_CameraRaw "http://ns.adobe.com/camera-raw-settings/1.0/"
+#define kXMP_NS_DM "http://ns.adobe.com/xmp/1.0/DynamicMedia/"
+#define kXMP_NS_ASF "http://ns.adobe.com/asf/1.0/"
+#define kXMP_NS_WAV "http://ns.adobe.com/xmp/wav/1.0/"
+
+#define kXMP_NS_XMP_Note "http://ns.adobe.com/xmp/note/"
+
+#define kXMP_NS_AdobeStockPhoto "http://ns.adobe.com/StockPhoto/1.0/"
+
+/**
+ * \name XML namespace constants for qualifiers and structured property fields.
+ * @{
+ */
+
+/**
+ * \def kXMP_NS_XMP_IdentifierQual
+ * \brief The XML namespace for qualifiers of the xmp:Identifier property.
+ */
+
+/**
+ * \def kXMP_NS_XMP_Dimensions
+ * \brief The XML namespace for fields of the Dimensions type.
+ */
+
+/**
+ * \def kXMP_NS_XMP_Image
+ * \brief The XML namespace for fields of a graphical image. Used for the Thumbnail type.
+ */
+
+/**
+ * \def kXMP_NS_XMP_ResourceEvent
+ * \brief The XML namespace for fields of the ResourceEvent type.
+ */
+
+/**
+ * \def kXMP_NS_XMP_ResourceRef
+ * \brief The XML namespace for fields of the ResourceRef type.
+ */
+
+/**
+ * \def kXMP_NS_XMP_ST_Version
+ * \brief The XML namespace for fields of the Version type.
+ */
+
+/**
+ * \def kXMP_NS_XMP_ST_Job
+ * \brief The XML namespace for fields of the JobRef type.
+ */
+
+/**
+ * @}
+ */
+
+#define kXMP_NS_XMP_IdentifierQual "http://ns.adobe.com/xmp/Identifier/qual/1.0/"
+#define kXMP_NS_XMP_Dimensions "http://ns.adobe.com/xap/1.0/sType/Dimensions#"
+#define kXMP_NS_XMP_Text "http://ns.adobe.com/xap/1.0/t/"
+#define kXMP_NS_XMP_PagedFile "http://ns.adobe.com/xap/1.0/t/pg/"
+#define kXMP_NS_XMP_Graphics "http://ns.adobe.com/xap/1.0/g/"
+#define kXMP_NS_XMP_Image "http://ns.adobe.com/xap/1.0/g/img/"
+#define kXMP_NS_XMP_Font "http://ns.adobe.com/xap/1.0/sType/Font#"
+#define kXMP_NS_XMP_ResourceEvent "http://ns.adobe.com/xap/1.0/sType/ResourceEvent#"
+#define kXMP_NS_XMP_ResourceRef "http://ns.adobe.com/xap/1.0/sType/ResourceRef#"
+#define kXMP_NS_XMP_ST_Version "http://ns.adobe.com/xap/1.0/sType/Version#"
+#define kXMP_NS_XMP_ST_Job "http://ns.adobe.com/xap/1.0/sType/Job#"
+#define kXMP_NS_XMP_ManifestItem "http://ns.adobe.com/xap/1.0/sType/ManifestItem#"
+
+/* Deprecated constant names */
+#define kXMP_NS_XMP_T "http://ns.adobe.com/xap/1.0/t/"
+#define kXMP_NS_XMP_T_PG "http://ns.adobe.com/xap/1.0/t/pg/"
+#define kXMP_NS_XMP_G_IMG "http://ns.adobe.com/xap/1.0/g/img/"
+
+/**
+ * \name XML namespace constants from outside Adobe.
+ * @{
+ */
+
+/**
+ * \def kXMP_NS_DC
+ * \brief The XML namespace for the Dublin Core schema.
+ */
+
+/**
+ * \def kXMP_NS_IPTCCore
+ * \brief The XML namespace for the IPTC Core schema.
+ */
+
+/**
+ * \def kXMP_NS_RDF
+ * \brief The XML namespace for RDF.
+ */
+
+/**
+ * \def kXMP_NS_XML
+ * \brief The XML namespace for XML.
+ */
+
+/**
+ * @}
+ */
+
+#define kXMP_NS_DC "http://purl.org/dc/elements/1.1/"
+
+#define kXMP_NS_IPTCCore "http://iptc.org/std/Iptc4xmpCore/1.0/xmlns/"
+
+#define kXMP_NS_PDFA_Schema "http://www.aiim.org/pdfa/ns/schema#"
+#define kXMP_NS_PDFA_Property "http://www.aiim.org/pdfa/ns/property#"
+#define kXMP_NS_PDFA_Type "http://www.aiim.org/pdfa/ns/type#"
+#define kXMP_NS_PDFA_Field "http://www.aiim.org/pdfa/ns/field#"
+#define kXMP_NS_PDFA_ID "http://www.aiim.org/pdfa/ns/id/"
+#define kXMP_NS_PDFA_Extension "http://www.aiim.org/pdfa/ns/extension/"
+
+#define kXMP_NS_PDFX "http://ns.adobe.com/pdfx/1.3/"
+#define kXMP_NS_PDFX_ID "http://www.npes.org/pdfx/ns/id/"
+
+#define kXMP_NS_RDF "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+#define kXMP_NS_XML "http://www.w3.org/XML/1998/namespace"
+
+
+/* ============================================================================================== */
+/* Enums and macros used for option bits */
+/* ===================================== */
+
+#define kXMP_ArrayLastItem ((XMP_Index)(-1L))
+#define kXMP_UseNullTermination ((XMP_StringLen)(~0UL))
+
+#define kXMP_NoOptions ((XMP_OptionBits)0UL)
+
+#define XMP_SetOption(var,opt) var |= (opt)
+#define XMP_ClearOption(var,opt) var &= ~(opt)
+#define XMP_TestOption(var,opt) (((var) & (opt)) != 0)
+#define XMP_OptionIsSet(var,opt) (((var) & (opt)) != 0)
+#define XMP_OptionIsClear(var,opt) (((var) & (opt)) == 0)
+
+#define XMP_PropIsSimple(opt) (((opt) & kXMP_PropCompositeMask) == 0)
+#define XMP_PropIsStruct(opt) (((opt) & kXMP_PropValueIsStruct) != 0)
+#define XMP_PropIsArray(opt) (((opt) & kXMP_PropValueIsArray) != 0)
+#define XMP_ArrayIsUnordered(opt) (((opt) & kXMP_PropArrayIsOrdered) == 0)
+#define XMP_ArrayIsOrdered(opt) (((opt) & kXMP_PropArrayIsOrdered) != 0)
+#define XMP_ArrayIsAlternate(opt) (((opt) & kXMP_PropArrayIsAlternate) != 0)
+#define XMP_ArrayIsAltText(opt) (((opt) & kXMP_PropArrayIsAltText) != 0)
+
+#define XMP_PropHasQualifiers(opt) (((opt) & kXMP_PropHasQualifiers) != 0)
+#define XMP_PropIsQualifier(opt) (((opt) & kXMP_PropIsQualifier) != 0)
+#define XMP_PropHasLang(opt) (((opt) & kXMP_PropHasLang) != 0)
+
+#define XMP_NodeIsSchema(opt) (((opt) & kXMP_SchemaNode) != 0)
+#define XMP_PropIsAlias(opt) (((opt) & kXMP_PropIsAlias) != 0)
+
+/* ---------------------------------------------------------------------------------------------- */
+
+enum { /* Option bits returned from the TXMPMeta::GetXyz functions. */
+
+ /* Options relating to the XML string form of the property value. */
+ kXMP_PropValueIsURI = 0x00000002UL, /* The value is a URI, use rdf:resource attribute. DISCOURAGED */
+
+ /* Options relating to qualifiers attached to a property. */
+ kXMP_PropHasQualifiers = 0x00000010UL, /* The property has qualifiers, includes rdf:type and xml:lang. */
+ kXMP_PropIsQualifier = 0x00000020UL, /* This is a qualifier, includes rdf:type and xml:lang. */
+ kXMP_PropHasLang = 0x00000040UL, /* Implies kXMP_PropHasQualifiers, property has xml:lang. */
+ kXMP_PropHasType = 0x00000080UL, /* Implies kXMP_PropHasQualifiers, property has rdf:type. */
+
+ /* Options relating to the data structure form. */
+ kXMP_PropValueIsStruct = 0x00000100UL, /* The value is a structure with nested fields. */
+ kXMP_PropValueIsArray = 0x00000200UL, /* The value is an array (RDF alt/bag/seq). */
+ kXMP_PropArrayIsUnordered = kXMP_PropValueIsArray, /* The item order does not matter. */
+ kXMP_PropArrayIsOrdered = 0x00000400UL, /* Implies kXMP_PropValueIsArray, item order matters. */
+ kXMP_PropArrayIsAlternate = 0x00000800UL, /* Implies kXMP_PropArrayIsOrdered, items are alternates. */
+
+ /* Additional struct and array options. */
+ kXMP_PropArrayIsAltText = 0x00001000UL, /* Implies kXMP_PropArrayIsAlternate, items are localized text. */
+ /* kXMP_InsertBeforeItem = 0x00004000UL, ! Used by SetXyz functions. */
+ /* kXMP_InsertAfterItem = 0x00008000UL, ! Used by SetXyz functions. */
+
+ /* Other miscellaneous options. */
+ kXMP_PropIsAlias = 0x00010000UL, /* This property is an alias name for another property. */
+ kXMP_PropHasAliases = 0x00020000UL, /* This property is the base value for a set of aliases. */
+ kXMP_PropIsInternal = 0x00040000UL, /* This property is an "internal" property, owned by applications. */
+ kXMP_PropIsStable = 0x00100000UL, /* This property is not derived from the document content. */
+ kXMP_PropIsDerived = 0x00200000UL, /* This property is derived from the document content. */
+ /* kXMPUtil_AllowCommas = 0x10000000UL, ! Used by TXMPUtils::CatenateArrayItems and ::SeparateArrayItems. */
+ /* kXMP_DeleteExisting = 0x20000000UL, ! Used by TXMPMeta::SetXyz functions to delete any pre-existing property. */
+ /* kXMP_SchemaNode = 0x80000000UL, ! Returned by iterators - #define to avoid warnings */
+
+ /* Masks that are multiple flags. */
+ kXMP_PropArrayFormMask = kXMP_PropValueIsArray | kXMP_PropArrayIsOrdered | kXMP_PropArrayIsAlternate | kXMP_PropArrayIsAltText,
+ kXMP_PropCompositeMask = kXMP_PropValueIsStruct | kXMP_PropArrayFormMask, /* Is it simple or composite (array or struct)? */
+ kXMP_ImplReservedMask = 0x70000000L /* Reserved for transient use by the implementation. */
+};
+
+#define kXMP_SchemaNode ((XMP_OptionBits)0x80000000UL)
+
+enum { /* Option bits for the TXMPMeta::SetXyz functions. */
+
+ /* Options shared with GetXyz functions. */
+ /*
+ kXMP_PropValueIsURI = 0x00000002UL, DISCOURAGED
+ kXMP_PropValueIsStruct = 0x00000100UL,
+ kXMP_PropValueIsArray = 0x00000200UL,
+ kXMP_PropArrayIsOrdered = 0x00000400UL,
+ kXMP_PropArrayIsAlternate = 0x00000800UL,
+ kXMP_PropArrayIsAltText = 0x00001000UL,
+ kXMP_PropValueIsCompact = 0x00002000UL, RESERVED
+ */
+
+ /* Options for array item location. */
+ kXMP_InsertBeforeItem = 0x00004000UL, /* Insert a new item before the given index. */
+ kXMP_InsertAfterItem = 0x00008000UL, /* Insert a new item after the given index. */
+
+ /* Miscellaneous options */
+ kXMP_DeleteExisting = 0x20000000UL, /* Delete any pre-existing property. */
+
+ /* Masks that are multiple flags. */
+ kXMP_PropValueOptionsMask = kXMP_PropValueIsURI,
+ kXMP_PropArrayLocationMask = kXMP_InsertBeforeItem | kXMP_InsertAfterItem
+
+};
+
+/* ---------------------------------------------------------------------------------------------- */
+
+enum { /* Options for TXMPMeta::ParseFromBuffer. */
+ kXMP_RequireXMPMeta = 0x0001UL, /* Require a surrounding x:xmpmeta element. */
+ kXMP_ParseMoreBuffers = 0x0002UL, /* This is the not last input buffer for this parse stream. */
+ kXMP_StrictAliasing = 0x0004UL /* Do not reconcile alias differences, throw an exception. */
+};
+
+enum { /* Options for TXMPMeta::SerializeToBuffer. */
+
+ /* *** Option to remove empty struct/array, or leaf with empty value? */
+
+ kXMP_OmitPacketWrapper = 0x0010UL, /* Omit the XML packet wrapper. */
+ kXMP_ReadOnlyPacket = 0x0020UL, /* Default is a writeable packet. */
+ kXMP_UseCompactFormat = 0x0040UL, /* Use a compact form of RDF. */
+
+ kXMP_IncludeThumbnailPad = 0x0100UL, /* Include a padding allowance for a thumbnail image. */
+ kXMP_ExactPacketLength = 0x0200UL, /* The padding parameter is the overall packet length. */
+ kXMP_WriteAliasComments = 0x0400UL, /* Show aliases as XML comments. */
+ kXMP_OmitAllFormatting = 0x0800UL, /* Omit all formatting whitespace. */
+
+ _XMP_LittleEndian_Bit = 0x0001UL, /* ! Don't use directly, see the combined values below! */
+ _XMP_UTF16_Bit = 0x0002UL,
+ _XMP_UTF32_Bit = 0x0004UL,
+
+ kXMP_EncodingMask = 0x0007UL,
+ kXMP_EncodeUTF8 = 0UL,
+ kXMP_EncodeUTF16Big = _XMP_UTF16_Bit,
+ kXMP_EncodeUTF16Little = _XMP_UTF16_Bit | _XMP_LittleEndian_Bit,
+ kXMP_EncodeUTF32Big = _XMP_UTF32_Bit,
+ kXMP_EncodeUTF32Little = _XMP_UTF32_Bit | _XMP_LittleEndian_Bit
+
+};
+
+/* ---------------------------------------------------------------------------------------------- */
+
+enum { /* Options for TXMPIterator construction. */
+
+ kXMP_IterClassMask = 0x00FFUL, /* The low 8 bits are an enum of what data structure to iterate. */
+ kXMP_IterProperties = 0x0000UL, /* Iterate the property tree of a TXMPMeta object. */
+ kXMP_IterAliases = 0x0001UL, /* Iterate the global alias table. */
+ kXMP_IterNamespaces = 0x0002UL, /* Iterate the global namespace table. */
+ kXMP_IterJustChildren = 0x0100UL, /* Just do the immediate children of the root, default is subtree. */
+ kXMP_IterJustLeafNodes = 0x0200UL, /* Just do the leaf nodes, default is all nodes in the subtree. */
+ kXMP_IterJustLeafName = 0x0400UL, /* Return just the leaf part of the path, default is the full path. */
+ kXMP_IterIncludeAliases = 0x0800UL, /* Include aliases, default is just actual properties. */
+
+ kXMP_IterOmitQualifiers = 0x1000UL /* Omit all qualifiers. */
+
+};
+
+enum { /* Options for TXMPIterator::Skip. */
+ kXMP_IterSkipSubtree = 0x0001UL, /* Skip the subtree below the current node. */
+ kXMP_IterSkipSiblings = 0x0002UL /* Skip the subtree below and remaining siblings of the current node. */
+};
+
+/* ---------------------------------------------------------------------------------------------- */
+
+enum { /* Options for TXMPUtils::CatenateArrayItems and TXMPUtils::SeparateArrayItems. */
+
+ /* Options shared with GetXyz functions. */
+ /*
+ kXMP_PropValueIsArray = 0x00000200UL,
+ kXMP_PropArrayIsOrdered = 0x00000400UL,
+ kXMP_PropArrayIsAlternate = 0x00000800UL,
+ kXMP_PropArrayIsAltText = 0x00001000UL,
+ */
+
+ kXMPUtil_AllowCommas = 0x10000000UL /* Allow commas in item values, default is separator. */
+
+};
+
+enum { /* Options for TXMPUtils::RemoveProperties and TXMPUtils::AppendProperties. */
+ kXMPUtil_DoAllProperties = 0x0001UL, /* Do all properties, default is just external properties. */
+ kXMPUtil_ReplaceOldValues = 0x0002UL, /* Replace existing values, default is to leave them. */
+ kXMPUtil_DeleteEmptyValues = 0x0004UL, /* Delete properties if the new value is empty. */
+ kXMPUtil_IncludeAliases = 0x0800UL /* == kXMP_IterIncludeAliases */
+};
+
+/* ============================================================================================== */
+/* Types and Constants for XMP File Handler */
+/* ======================================== */
+
+enum {
+
+ /* Public file formats. Hex used to avoid gcc warnings. */
+ /* ! Leave them as big endian. There seems to be no decent way on UNIX to determine the target */
+ /* ! endianness at compile time. Forcing it on the client isn't acceptable. */
+
+ kXMP_PDFFile = 0x50444620UL, /* 'PDF ' */
+ kXMP_PostScriptFile = 0x50532020UL, /* 'PS ', general PostScript following DSC conventions. */
+ kXMP_EPSFile = 0x45505320UL, /* 'EPS ', encapsulated PostScript. */
+
+ kXMP_JPEGFile = 0x4A504547UL, /* 'JPEG' */
+ kXMP_JPEG2KFile = 0x4A505820UL, /* 'JPX ', ISO 15444-1 */
+ kXMP_TIFFFile = 0x54494646UL, /* 'TIFF' */
+ kXMP_GIFFile = 0x47494620UL, /* 'GIF ' */
+ kXMP_PNGFile = 0x504E4720UL, /* 'PNG ' */
+
+ kXMP_SWFFile = 0x53574620UL, /* 'SWF ' */
+ kXMP_FLAFile = 0x464C4120UL, /* 'FLA ' */
+ kXMP_FLVFile = 0x464C5620UL, /* 'FLV ' */
+
+ kXMP_MOVFile = 0x4D4F5620UL, /* 'MOV ', Quicktime */
+ kXMP_AVIFile = 0x41564920UL, /* 'AVI ' */
+ kXMP_CINFile = 0x43494E20UL, /* 'CIN ', Cineon */
+ kXMP_WAVFile = 0x57415620UL, /* 'WAV ' */
+ kXMP_MP3File = 0x4D503320UL, /* 'MP3 ' */
+ kXMP_SESFile = 0x53455320UL, /* 'SES ', Audition session */
+ kXMP_CELFile = 0x43454C20UL, /* 'CEL ', Audition loop */
+ kXMP_MPEGFile = 0x4D504547UL, /* 'MPEG' */
+ kXMP_MPEG2File = 0x4D503220UL, /* 'MP2 ' */
+ kXMP_MPEG4File = 0x4D503420UL, /* 'MP4 ', ISO 14494-12 and -14 */
+ kXMP_WMAVFile = 0x574D4156UL, /* 'WMAV', Windows Media Audio and Video */
+ kXMP_AIFFFile = 0x41494646UL, /* 'AIFF' */
+
+ kXMP_HTMLFile = 0x48544D4CUL, /* 'HTML' */
+ kXMP_XMLFile = 0x584D4C20UL, /* 'XML ' */
+ kXMP_TextFile = 0x74657874UL, /* 'text' */
+
+ /* Adobe application file formats. */
+
+ kXMP_PhotoshopFile = 0x50534420UL, /* 'PSD ' */
+ kXMP_IllustratorFile = 0x41492020UL, /* 'AI ' */
+ kXMP_InDesignFile = 0x494E4444UL, /* 'INDD' */
+ kXMP_AEProjectFile = 0x41455020UL, /* 'AEP ' */
+ kXMP_AEProjTemplateFile = 0x41455420UL, /* 'AET ', After Effects Project Template */
+ kXMP_AEFilterPresetFile = 0x46465820UL, /* 'FFX ' */
+ kXMP_EncoreProjectFile = 0x4E434F52UL, /* 'NCOR' */
+ kXMP_PremiereProjectFile = 0x5052504AUL, /* 'PRPJ' */
+ kXMP_PremiereTitleFile = 0x5052544CUL, /* 'PRTL' */
+
+ /* Catch all. */
+
+ kXMP_UnknownFile = 0x20202020UL /* ' ' */
+
+};
+typedef XMP_Uns32 XMP_FileFormat;
+
+/* ---------------------------------------------------------------------------------------------- */
+
+enum {
+ kXMP_CharLittleEndianMask = 1,
+ kXMP_Char16BitMask = 2, /* Don't use these directly. */
+ kXMP_Char32BitMask = 4
+};
+
+enum { /* The values allow easy testing for 16/32 bit and big/little endian. */
+ kXMP_Char8Bit = 0,
+ kXMP_Char16BitBig = kXMP_Char16BitMask,
+ kXMP_Char16BitLittle = kXMP_Char16BitMask | kXMP_CharLittleEndianMask,
+ kXMP_Char32BitBig = kXMP_Char32BitMask,
+ kXMP_Char32BitLittle = kXMP_Char32BitMask | kXMP_CharLittleEndianMask,
+ kXMP_CharUnknown = 1 /* ! A bit of a hack, for variable or not-yet-known cases. */
+};
+
+#define XMP_CharFormIs16Bit(f) ( ((int)(f) & kXMP_Char16BitMask) != 0 )
+#define XMP_CharFormIs32Bit(f) ( ((int)(f) & kXMP_Char32BitMask) != 0 )
+
+#define XMP_CharFormIsBigEndian(f) ( ((int)(f) & kXMP_CharLittleEndianMask) == 0 )
+#define XMP_CharFormIsLittleEndian(f) ( ((int)(f) & kXMP_CharLittleEndianMask) != 0 )
+
+#define XMP_GetCharSize(f) ( ((int)(f)&6) == 0 ? 1 : (int)(f)&6 )
+
+#define XMP_CharToSerializeForm(cf) ( (XMP_OptionBits)(cf) )
+#define XMP_CharFromSerializeForm(sf) ( (XMP_Uns8)(sf) )
+
+struct XMP_PacketInfo {
+ XMP_Int64 offset;
+ XMP_Int32 length;
+ XMP_Int32 padSize; /* Zero if unknown. */
+ XMP_Uns8 charForm;
+ XMP_Bool writeable;
+ XMP_Uns8 pad1, pad2;
+ #if __cplusplus
+ XMP_PacketInfo() : offset(0), length(0), padSize(0), charForm(0), writeable(0), pad1(0), pad2(0) {};
+ #endif
+};
+#if ! __cplusplus
+ typedef struct XMP_PacketInfo XMP_PacketInfo;
+#endif
+enum { kXMP_PacketInfoVersion = 3 };
+
+/* ---------------------------------------------------------------------------------------------- */
+
+enum { /* Values for XMP_ThumbnailInfo.tnailFormat. */
+ kXMP_UnknownTNail = 0, /* The thumbnail data has an unknown format. */
+ kXMP_JPEGTNail = 1, /* The thumbnail data is a JPEG stream, presumably compressed. */
+ kXMP_TIFFTNail = 2, /* The thumbnail data is a TIFF stream, presumably uncompressed. */
+ kXMP_PShopTNail = 3 /* The thumbnail data is in the format of Photoshop Image Resource 1036. */
+};
+
+struct XMP_ThumbnailInfo {
+ XMP_FileFormat fileFormat; /* The format of the containing file. */
+ XMP_Uns32 fullWidth, fullHeight; /* Full image size in pixels. */
+ XMP_Uns32 tnailWidth, tnailHeight; /* Thumbnail image size in pixels. */
+ XMP_Uns16 fullOrientation, tnailOrientation; /* Orientation of full image and thumbnail, as defined by Exif for tag 274. */
+ const XMP_Uns8 * tnailImage; /* Raw data from the host file, valid for life of the owning XMPFiles object. Do not modify! */
+ XMP_Uns32 tnailSize; /* The size in bytes of the tnailImage data. */
+ XMP_Uns8 tnailFormat; /* The format of the tnailImage data. */
+ XMP_Uns8 pad1, pad2, pad3;
+ #if __cplusplus
+ XMP_ThumbnailInfo() : fileFormat(kXMP_UnknownFile), fullWidth(0), fullHeight(0),
+ tnailWidth(0), tnailHeight(0), fullOrientation(0), tnailOrientation(0),
+ tnailImage(0), tnailSize(0), tnailFormat(kXMP_UnknownTNail) {};
+ #endif
+};
+#if ! __cplusplus
+ typedef struct XMP_ThumbnailInfo XMP_ThumbnailInfo;
+#endif
+enum { kXMP_ThumbnailInfoVersion = 1 };
+
+/* ---------------------------------------------------------------------------------------------- */
+
+#define kXMPFiles_UnknownOffset ((XMP_Int64)-1)
+#define kXMPFiles_UnknownLength ((XMP_Int32)-1)
+
+enum { /* Options for Initialize. */
+ kXMPFiles_NoQuickTimeInit = 0x0001 /* Don't initialize QuickTime, the client will. */
+};
+
+enum { /* Options for GetFormatInfo. */
+ kXMPFiles_CanInjectXMP = 0x00000001, /* Can inject first-time XMP into an existing file. */
+ kXMPFiles_CanExpand = 0x00000002, /* Can expand XMP or other metadata in an existing file. */
+ kXMPFiles_CanRewrite = 0x00000004, /* Can copy one file to another, writing new metadata. */
+ kXMPFiles_PrefersInPlace = 0x00000008, /* Can expand, but prefers in-place update. */
+ kXMPFiles_CanReconcile = 0x00000010, /* Supports reconciliation between XMP and other forms. */
+ kXMPFiles_AllowsOnlyXMP = 0x00000020, /* Allows access to just the XMP, ignoring other forms. */
+ kXMPFiles_ReturnsRawPacket = 0x00000040, /* File handler returns raw XMP packet information. */
+ kXMPFiles_ReturnsTNail = 0x00000080, /* File handler returns native thumbnail. */
+ kXMPFiles_HandlerOwnsFile = 0x00000100, /* The file handler does the file open and close. */
+ kXMPFiles_AllowsSafeUpdate = 0x00000200, /* The file handler allows crash-safe file updates. */
+ kXMPFiles_NeedsReadOnlyPacket = 0x00000400, /* The file format needs the XMP packet to be read-only. */
+ kXMPFiles_UsesSidecarXMP = 0x00000800 /* The file handler uses a "sidecar" file for the XMP. */
+};
+
+enum { /* Options for OpenFile. */
+ kXMPFiles_OpenForRead = 0x00000001, /* Open for read-only access. */
+ kXMPFiles_OpenForUpdate = 0x00000002, /* Open for reading and writing. */
+ kXMPFiles_OpenOnlyXMP = 0x00000004, /* Only the XMP is wanted, allows space/time optimizations. */
+ kXMPFiles_OpenCacheTNail = 0x00000008, /* Cache thumbnail if possible, GetThumbnail will be called. */
+ kXMPFiles_OpenStrictly = 0x00000010, /* Be strict about locating XMP and reconciling with other forms. */
+ kXMPFiles_OpenUseSmartHandler = 0x00000020, /* Require the use of a smart handler. */
+ kXMPFiles_OpenUsePacketScanning = 0x00000040, /* Force packet scanning, don't use a smart handler. */
+ kXMPFiles_OpenLimitedScanning = 0x00000080, /* Only packet scan files "known" to need scanning. */
+ kXMPFiles_OpenInBackground = 0x10000000 /* Set if calling from background thread. */
+};
+
+/* A note about kXMPFiles_OpenInBackground. The XMPFiles handler for .mov files currently uses */
+/* QuickTime. On Macintosh, calls to Enter/ExitMovies versus Enter/ExitMoviesOnThread must be made. */
+/* This option is used to signal background use so that the .mov handler can behave appropriately. */
+
+enum { /* Options for CloseFile. */
+ kXMPFiles_UpdateSafely = 0x0001 /* Write into a temporary file and swap for crash safety. */
+};
+
+/* ============================================================================================== */
+/* Exception codes */
+/* =============== */
+
+/**
+ * \name Exception codes.
+ * @{
+ * XMP tookit errors result in throwing an \c XMP_Error exception. Any exception thrown within the
+ * XMP toolkit is caught in the toolkit and rethrown as an \c XMP_Error. The \c XMP_Error struct
+ * contains a numeric code and an English explanation. New numeric codes may be added at any time.
+ * There are typically many possible explanations for each numeric code. The explanations try to
+ * be precise about the specific circumstances causing the error.
+ *
+ * \note The explanation string is for debugging use only. It must not be shown to users in a
+ * final product. It is written for developers not users, and never localized.
+ */
+
+#if ! __cplusplus
+
+ typedef struct XMP_Error {
+ XMP_Int32 id;
+ XMP_StringPtr errMsg;
+ } XMP_Error;
+
+#else
+
+ class XMP_Error {
+ public:
+ XMP_Error ( XMP_Int32 _id, XMP_StringPtr _errMsg ) : id(_id), errMsg(_errMsg) {};
+ inline XMP_Int32 GetID() const { return id; };
+ inline XMP_StringPtr GetErrMsg() const { return errMsg; };
+ private:
+ XMP_Int32 id;
+ XMP_StringPtr errMsg;
+ };
+
+#endif
+
+enum {
+
+ /* More or less generic error codes. */
+ kXMPErr_Unknown = 0,
+ kXMPErr_TBD = 1,
+ kXMPErr_Unavailable = 2,
+ kXMPErr_BadObject = 3,
+ kXMPErr_BadParam = 4,
+ kXMPErr_BadValue = 5,
+ kXMPErr_AssertFailure = 6,
+ kXMPErr_EnforceFailure = 7,
+ kXMPErr_Unimplemented = 8,
+ kXMPErr_InternalFailure = 9,
+ kXMPErr_Deprecated = 10,
+ kXMPErr_ExternalFailure = 11,
+ kXMPErr_UserAbort = 12,
+ kXMPErr_StdException = 13,
+ kXMPErr_UnknownException = 14,
+ kXMPErr_NoMemory = 15,
+
+ /* More specific parameter error codes. */
+ kXMPErr_BadSchema = 101,
+ kXMPErr_BadXPath = 102,
+ kXMPErr_BadOptions = 103,
+ kXMPErr_BadIndex = 104,
+ kXMPErr_BadIterPosition = 105,
+ kXMPErr_BadParse = 106,
+ kXMPErr_BadSerialize = 107,
+ kXMPErr_BadFileFormat = 108,
+ kXMPErr_NoFileHandler = 109,
+ kXMPErr_TooLargeForJPEG = 110,
+
+ /* File format and internal structure error codes. */
+ kXMPErr_BadXML = 201,
+ kXMPErr_BadRDF = 202,
+ kXMPErr_BadXMP = 203,
+ kXMPErr_EmptyIterator = 204,
+ kXMPErr_BadUnicode = 205,
+ kXMPErr_BadTIFF = 206,
+ kXMPErr_BadJPEG = 207,
+ kXMPErr_BadPSD = 208,
+ kXMPErr_BadPSIR = 209,
+ kXMPErr_BadIPTC = 210,
+ kXMPErr_BadMPEG = 211
+
+};
+
+/**
+ * @}
+ */
+
+
+/* ============================================================================================== */
+/* Client callbacks */
+/* ================ */
+
+
+/**
+ * \name Special purpose callback functions
+ * @{
+ */
+
+/**
+ * \typedef XMP_Status
+ * \brief A signed 32 bit integer used as a status result for the output callback routine.
+ * Zero means no error, all other values except -1 are private to the callback. The callback is
+ * wrapped to prevent exceptions being thrown across DLL boundaries. Any exceptions thrown out
+ * of the callback cause a return status of -1.
+ */
+
+/**
+ * \typedef XMP_TextOutputProc
+ * \brief Direct text output from the XMP toolkit, such as debugging dumps, is done using client
+ * supplied callbacks. The callback is invoked one or more times for each line of output. The
+ * end of a line is signaled by a '\n' character at the end of the buffer. Formatting newlines
+ * are never present in the middle of a buffer, but values of properties might contain any UTF-8
+ * characters. A success/fail status is returned by the callback. Any failure result aborts
+ * the output.
+ */
+
+typedef XMP_Int32 XMP_Status;
+
+typedef XMP_Status (* XMP_TextOutputProc) ( void * refCon,
+ XMP_StringPtr buffer,
+ XMP_StringLen bufferSize );
+
+/**
+ * @}
+ */
+
+
+/* ============================================================================================== */
+/* Stuff with no better place to be */
+/* ================================ */
+
+typedef struct XMP_VersionInfo {
+ XMP_Uns8 major; /* The primary release number, the "1" in version "1.2.3". */
+ XMP_Uns8 minor; /* The secondary release number, the "2" in version "1.2.3". */
+ XMP_Uns8 micro; /* The tertiary release number, the "3" in version "1.2.3". */
+ XMP_Bool isDebug; /* Really a 0/1 bool value. True if this is a debug build. */
+ XMP_Uns32 build; /* A rolling build number, monotonically increasing in a release. */
+ XMP_Uns32 flags; /* Individual feature implementation flags. */
+ XMP_StringPtr message; /* A comprehensive version information string. */
+} XMP_VersionInfo;
+
+typedef bool (* XMP_AbortProc) ( void * arg ); /* Used by SXMPFiles::SetAbortProc. */
+
+/* ============================================================================================== */
+
+#if __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* __XMP_Const_h__ */
diff --git a/public/include/XMP_Environment.h b/public/include/XMP_Environment.h
new file mode 100644
index 0000000..f25676e
--- /dev/null
+++ b/public/include/XMP_Environment.h
@@ -0,0 +1,121 @@
+#ifndef __XMP_Environment_h__
+#define __XMP_Environment_h__ 1
+
+/* --------------------------------------------------------------------------------------------- */
+/* ** IMPORTANT ** This file must be usable by strict ANSI C compilers. No "//" comments, etc. */
+/* --------------------------------------------------------------------------------------------- */
+
+/*
+// =================================================================================================
+// XMP_Environment.h - Build environment flags for the XMP toolkit.
+// ================================================================
+//
+// This header is just C preprocessor macro definitions to set up the XMP toolkit build environment.
+// It must be the first #include in any chain since it might affect things in other #includes.
+//
+// =================================================================================================
+*/
+
+/*
+// =================================================================================================
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+*/
+
+/* ============================================================================================== */
+/* Determine the Platform */
+/* ====================== */
+
+/* One of MAC_ENV, WIN_ENV, or UNIX_ENV must be defined by the client. Since some other code */
+/* requires these to be defined without values, they are only used here to define XMP-specific */
+/* macros with 0 or 1 values. */
+
+/* ! Tempting though it might be to have a standard macro for big or little endian, there seems */
+/* ! to be no decent way to do that on our own in UNIX. Forcing it on the client isn't acceptable. */
+
+#if defined ( MAC_ENV )
+
+ #if 0 /* ! maybe someday - ! MAC_ENV */
+ #error "MAC_ENV must be defined so that \"#if MAC_ENV\" is true"
+ #endif
+
+ #if defined ( WIN_ENV ) || defined ( UNIX_ENV )
+ #error "XMP environment error - must define only one of MAC_ENV, WIN_ENV, or UNIX_ENV"
+ #endif
+
+ #define XMP_MacBuild 1
+ #define XMP_WinBuild 0
+ #define XMP_UNIXBuild 0
+
+#elif defined ( WIN_ENV )
+
+ #if 0 /* ! maybe someday - ! WIN_ENV */
+ #error "WIN_ENV must be defined so that \"#if WIN_ENV\" is true"
+ #endif
+
+ #if defined ( UNIX_ENV )
+ #error "XMP environment error - must define only one of MAC_ENV, WIN_ENV, or UNIX_ENV"
+ #endif
+
+ #define XMP_MacBuild 0
+ #define XMP_WinBuild 1
+ #define XMP_UNIXBuild 0
+
+#elif defined ( UNIX_ENV )
+
+ #if 0 /* ! maybe someday - ! UNIX_ENV */
+ #error "UNIX_ENV must be defined so that \"#if UNIX_ENV\" is true"
+ #endif
+
+ #define XMP_MacBuild 0
+ #define XMP_WinBuild 0
+ #define XMP_UNIXBuild 1
+
+#else
+
+ #error "XMP environment error - must define one of MAC_ENV, WIN_ENV, or UNIX_ENV"
+
+#endif
+
+/* ============================================================================================== */
+/* Common Macros */
+/* ============= */
+
+#if defined ( DEBUG )
+ #if defined ( NDEBUG )
+ #error "XMP environment error - both DEBUG and NDEBUG are defined"
+ #endif
+ #define XMP_DebugBuild 1
+#endif
+
+#if defined ( NDEBUG )
+ #define XMP_DebugBuild 0
+#endif
+
+#ifndef XMP_DebugBuild
+ #define XMP_DebugBuild 0
+#endif
+
+#if XMP_DebugBuild
+ #include <stdio.h> /* The assert macro needs printf. */
+#endif
+
+/* ============================================================================================== */
+/* Macintosh Specific Settings */
+/* =========================== */
+
+/* ============================================================================================== */
+/* Windows Specific Settings */
+/* ========================= */
+
+/* ============================================================================================== */
+/* UNIX Specific Settings */
+/* ====================== */
+
+/* ============================================================================================== */
+
+#endif /* __XMP_Environment_h__ */
diff --git a/public/include/XMP_Version.h b/public/include/XMP_Version.h
new file mode 100644
index 0000000..ed41d14
--- /dev/null
+++ b/public/include/XMP_Version.h
@@ -0,0 +1,45 @@
+#ifndef __XMP_Version_h__
+#define __XMP_Version_h__ 1
+
+/* --------------------------------------------------------------------------------------------- */
+/* ** IMPORTANT ** This file must be usable by strict ANSI C compilers. No "//" comments, etc. */
+/* --------------------------------------------------------------------------------------------- */
+
+/*
+// =================================================================================================
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+*/
+
+/* ============================================================================================= */
+/**
+XMP Toolkit Version Information
+
+Version information for the XMP toolkit is stored in the executable and available through a runtime
+call, <tt>SXMPMeta::GetVersionInfo</tt>. In addition a static version number is defined in this
+header. The information in the executable or returned by <tt>SXMPMeta::GetVersionInfo</tt> is about
+the implementation internals, it is runtime version information. The values defined in this header
+describe the version of the API used at client compile time. They do not necessarily relate to the
+runtime version.
+
+Important: Do not display the static values defined here to users as the version of XMP in use. Do
+not base runtime decisions on just this static version. It is OK to compare the static and runtime
+versions.
+
+*/
+/* ============================================================================================= */
+
+#define XMP_API_VERSION_MAJOR 4
+#define XMP_API_VERSION_MINOR 1
+#define XMP_API_VERSION_MICRO 1
+
+#define XMP_API_VERSION 4.1
+#define XMP_API_VERSION_STRING "4.1.1"
+
+/* ============================================================================================= */
+
+#endif /* __XMP_Version_h__ */
diff --git a/public/include/client-glue/TXMPFiles.incl_cpp b/public/include/client-glue/TXMPFiles.incl_cpp
new file mode 100644
index 0000000..83867df
--- /dev/null
+++ b/public/include/client-glue/TXMPFiles.incl_cpp
@@ -0,0 +1,347 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+// ================================================================================================
+/// \file TXMPFiles.incl_cpp
+/// \brief The implementation of the TXMPFiles template class.
+
+#if WIN_ENV
+ #pragma warning ( disable : 4003 ) // not enough actual parameters for macro
+ #pragma warning ( disable : 4800 ) // forcing value to bool 'true' or 'false' (performance warning)
+#endif
+
+#include "client-glue/WXMP_Common.hpp"
+#include "client-glue/WXMPFiles.hpp"
+
+// =================================================================================================
+// Implementation Guidelines
+// =========================
+//
+// The implementations of the template functions are very stylized. The jobs done in this code are:
+//
+// 1. ...
+//
+// =================================================================================================
+
+#ifndef XMPFiles_TraceCTorDTor
+ #define XMPFiles_TraceCTorDTor 0
+#endif
+
+#if XMPFiles_TraceCTorDTor
+ class XFPeek { // Hack to peek at the client ref count in the internal object.
+ public:
+ XFPeek();
+ virtual ~XFPeek();
+ XMP_Int32 clientRefs;
+ };
+#endif
+
+// =================================================================================================
+
+XMP_MethodIntro(TXMPFiles,void)::
+GetVersionInfo ( XMP_VersionInfo * versionInfo )
+{
+ WrapNoCheckVoid ( zXMPFiles_GetVersionInfo_1 ( versionInfo ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPFiles,bool)::
+Initialize()
+{
+ WrapCheckBool ( ok, zXMPFiles_Initialize_2 ( 0 ) );
+ return ok;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPFiles,bool)::
+Initialize ( XMP_OptionBits options )
+{
+ WrapCheckBool ( ok, zXMPFiles_Initialize_2 ( options ) );
+ return ok;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPFiles,void)::
+Terminate()
+{
+ WrapNoCheckVoid ( zXMPFiles_Terminate_1() );
+}
+
+// =================================================================================================
+
+static XMPFilesRef Default_CTor()
+{
+ WrapCheckXMPFilesRef ( newRef, zXMPFiles_CTor_1() );
+ return newRef;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_CTorDTorIntro(TXMPFiles)::
+TXMPFiles() : xmpFilesRef(Default_CTor())
+{
+ #if XMPFiles_TraceCTorDTor
+ XFPeek* xfPtr = (XFPeek*)this->xmpFilesRef;
+ printf ( "Default construct TXMPFiles @ %.8X, ref = %.8X, count = %d\n", this, xfPtr, xfPtr->clientRefs );
+ #endif
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_CTorDTorIntro(TXMPFiles)::
+TXMPFiles ( const TXMPFiles<tStringObj> & original ) : xmpFilesRef(original.xmpFilesRef)
+{
+ WXMPFiles_IncrementRefCount_1 ( this->xmpFilesRef );
+ #if XMPFiles_TraceCTorDTor
+ XFPeek* xfPtr = (XFPeek*)this->xmpFilesRef;
+ printf ( "Copy construct TXMPFiles @ %.8X, ref = %.8X, count = %d\n", this, xfPtr, xfPtr->clientRefs );
+ #endif
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPFiles,void)::
+operator= ( const TXMPFiles<tStringObj> & rhs )
+{
+ #if XMPFiles_TraceCTorDTor
+ XFPeek* xfLHS = (XFPeek*)this->xmpFilesRef;
+ XFPeek* xfRHS = (XFPeek*)rhs.xmpFilesRef;
+ printf ( "Assign TXMPFiles, lhs @ %.8X, rhs @ %.8X\n", this, &rhs );
+ printf ( " original lhs ref = %.8X, count = %d\n", xfLHS, xfLHS->clientRefs );
+ printf ( " original rhs ref = %.8X, count = %d\n", xfRHS, xfRHS->clientRefs );
+ #endif
+ XMPFilesRef oldRef = this->xmpFilesRef; // ! Decrement last so errors leave client object OK.
+ this->xmpFilesRef = rhs.xmpFilesRef;
+ WXMPFiles_IncrementRefCount_1 ( this->xmpFilesRef ); // Increment the count on the new ref.
+ WXMPFiles_DecrementRefCount_1 ( oldRef ); // Decrement the count on the old ref.
+ #if XMPFiles_TraceCTorDTor
+ printf ( " result lhs ref = %.8X, count = %d\n", xfLHS, xfLHS->clientRefs );
+ #endif
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_CTorDTorIntro(TXMPFiles)::
+TXMPFiles ( XMPFilesRef _xmpFilesRef ) : xmpFilesRef(_xmpFilesRef)
+{
+ WXMPFiles_IncrementRefCount_1 ( this->xmpFilesRef );
+ #if XMPFiles_TraceCTorDTor
+ XFPeek* xfPtr = (XFPeek*)this->xmpFilesRef;
+ printf ( "Ref construct TXMPFiles @ %.8X, ref = %.8X, count = %d\n", this, xfPtr, xfPtr->clientRefs );
+ #endif
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_CTorDTorIntro(TXMPFiles)::
+TXMPFiles ( XMP_StringPtr filePath,
+ XMP_FileFormat format /* = kXMP_UnknownFile */,
+ XMP_OptionBits openFlags /* = 0 */ ) : xmpFilesRef(Default_CTor())
+{
+ #if XMPFiles_TraceCTorDTor
+ XFPeek* xfPtr = (XFPeek*)this->xmpFilesRef;
+ printf ( "File construct TXMPFiles @ %.8X, ref = %.8X, count = %d\n", this, xfPtr, xfPtr->clientRefs );
+ #endif
+ bool ok = this->OpenFile ( filePath, format, openFlags );
+ if ( ! ok ) throw XMP_Error ( kXMPErr_NoFileHandler, "OpenFile returned false" );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_CTorDTorIntro(TXMPFiles)::
+TXMPFiles ( const tStringObj & filePath,
+ XMP_FileFormat format /* = kXMP_UnknownFile */,
+ XMP_OptionBits openFlags /* = 0 */ ) : xmpFilesRef(Default_CTor())
+{
+ #if XMPFiles_TraceCTorDTor
+ XFPeek* xfPtr = (XFPeek*)this->xmpFilesRef;
+ printf ( "File construct TXMPFiles @ %.8X, ref = %.8X, count = %d\n", this, xfPtr, xfPtr->clientRefs );
+ #endif
+ bool ok = this->OpenFile ( filePath.c_str(), format, openFlags );
+ if ( ! ok ) throw XMP_Error ( kXMPErr_NoFileHandler, "OpenFile returned false" );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_CTorDTorIntro(TXMPFiles)::
+~TXMPFiles () throw()
+{
+ #if XMPFiles_TraceCTorDTor
+ XFPeek* xfPtr = (XFPeek*)this->xmpFilesRef;
+ printf ( "Destruct TXMPFiles @ %.8X, ref= %.8X, count = %d\n", this, xfPtr, xfPtr->clientRefs );
+ #endif
+ WXMPFiles_DecrementRefCount_1 ( this->xmpFilesRef );
+ this->xmpFilesRef = 0;
+}
+
+// =================================================================================================
+
+XMP_MethodIntro(TXMPFiles,bool)::
+GetFormatInfo ( XMP_FileFormat format,
+ XMP_OptionBits * flags )
+{
+ WrapCheckBool ( found, zXMPFiles_GetFormatInfo_1 ( format, flags ) );
+ return found;
+}
+
+// =================================================================================================
+
+XMP_MethodIntro(TXMPFiles,XMPFilesRef)::
+GetInternalRef()
+{
+ return this->xmpFilesRef;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPFiles,bool)::
+OpenFile ( XMP_StringPtr filePath,
+ XMP_FileFormat format /* = kXMP_UnknownFile */,
+ XMP_OptionBits openFlags /* =0 */ )
+{
+ WrapCheckBool ( ok, zXMPFiles_OpenFile_1 ( filePath, format, openFlags ) );
+ return ok;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPFiles,bool)::
+OpenFile ( const tStringObj & filePath,
+ XMP_FileFormat format /* = kXMP_UnknownFile */,
+ XMP_OptionBits openFlags /* =0 */ )
+{
+ return this->OpenFile ( filePath.c_str(), format, openFlags );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPFiles,void)::
+CloseFile ( XMP_OptionBits closeFlags /* =0 */ )
+{
+ WrapCheckVoid ( zXMPFiles_CloseFile_1 ( closeFlags ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPFiles,bool)::
+GetFileInfo ( tStringObj * filePath /* = 0 */,
+ XMP_OptionBits * openFlags /* =0 */,
+ XMP_FileFormat * format /* = 0 */,
+ XMP_OptionBits * handlerFlags /* =0 */ )
+{
+ XMP_StringPtr pathStr;
+ XMP_StringLen pathLen;
+
+ WrapCheckBool ( isOpen, zXMPFiles_GetFileInfo_1 ( &pathStr, &pathLen, openFlags, format, handlerFlags ) );
+ if ( isOpen ) {
+ if ( filePath != 0 ) filePath->assign ( pathStr, pathLen );
+ WXMPFiles_UnlockObj_1 ( this->xmpFilesRef );
+ }
+ return isOpen;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPFiles,void)::
+SetAbortProc ( XMP_AbortProc abortProc,
+ void * abortArg )
+{
+ WrapCheckVoid ( zXMPFiles_SetAbortProc_1 ( abortProc, abortArg ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPFiles,bool)::
+GetXMP ( SXMPMeta * xmpObj /* = 0 */,
+ tStringObj * xmpPacket /* = 0 */,
+ XMP_PacketInfo * packetInfo /* =0 */ )
+{
+ XMP_StringPtr xmpStr;
+ XMP_StringLen xmpLen;
+
+ XMPMetaRef xmpRef = 0;
+ if ( xmpObj != 0 ) {
+ SXMPUtils::RemoveProperties ( xmpObj, 0, 0, kXMPUtil_DoAllProperties );
+ // *** Need an SXMPMeta::Clear method:
+ xmpRef = xmpObj->GetInternalRef();
+ }
+
+ WrapCheckBool ( hasXMP, zXMPFiles_GetXMP_1 ( xmpRef, &xmpStr, &xmpLen, packetInfo ) );
+ if ( hasXMP ) {
+ if ( xmpPacket != 0 ) xmpPacket->assign ( xmpStr, xmpLen );
+ WXMPFiles_UnlockObj_1 ( this->xmpFilesRef );
+ }
+ return hasXMP;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPFiles,bool)::
+GetThumbnail ( XMP_ThumbnailInfo * tnailInfo )
+{
+ WrapCheckBool ( hasTNail, zXMPFiles_GetThumbnail_1 ( tnailInfo ) );
+ return hasTNail;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPFiles,void)::
+PutXMP ( const SXMPMeta & xmpObj )
+{
+ WrapCheckVoid ( zXMPFiles_PutXMP_1 ( xmpObj.GetInternalRef(), 0, 0 ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPFiles,void)::
+PutXMP ( XMP_StringPtr xmpPacket,
+ XMP_StringLen xmpLength /* = kXMP_UseNullTermination */ )
+{
+ WrapCheckVoid ( zXMPFiles_PutXMP_1 ( 0, xmpPacket, xmpLength ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPFiles,void)::
+PutXMP ( const tStringObj & xmpPacket )
+{
+ this->PutXMP ( xmpPacket.c_str(), xmpPacket.size() );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPFiles,bool)::
+CanPutXMP ( const SXMPMeta & xmpObj )
+{
+ WrapCheckBool ( canPut, zXMPFiles_CanPutXMP_1 ( xmpObj.GetInternalRef(), 0, 0 ) );
+ return canPut;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPFiles,bool)::
+CanPutXMP ( XMP_StringPtr xmpPacket,
+ XMP_StringLen xmpLength /* = kXMP_UseNullTermination */ )
+{
+ WrapCheckBool ( canPut, zXMPFiles_CanPutXMP_1 ( 0, xmpPacket, xmpLength ) );
+ return canPut;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPFiles,bool)::
+CanPutXMP ( const tStringObj & xmpPacket )
+{
+ return this->CanPutXMP ( xmpPacket.c_str(), xmpPacket.size() );
+}
+
+// =================================================================================================
diff --git a/public/include/client-glue/TXMPIterator.incl_cpp b/public/include/client-glue/TXMPIterator.incl_cpp
new file mode 100644
index 0000000..318fa66
--- /dev/null
+++ b/public/include/client-glue/TXMPIterator.incl_cpp
@@ -0,0 +1,226 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+// ================================================================================================
+/// \file TXMPIterator.incl_cpp
+/// \brief The implementation of the TXMPIterator template class.
+
+#include "XMP.hpp"
+#include "client-glue/WXMP_Common.hpp"
+#include "client-glue/WXMPIterator.hpp"
+
+// =================================================================================================
+// Implementation Guidelines
+// =========================
+//
+// The implementations of the template functions are very stylized. The jobs done in this code are:
+//
+// 1. Set up the xmpIter template data member in the constructors.
+// 2. Call through to the appropriate WXMPIterator function.
+// 3. Copy returned strings and release the threading lock.
+//
+// The various kinds of functions follow similar patterns, first assuming no returned string:
+//
+// Constructors - Use an initializer for the xmpIter data member to call the WXMPIterator constructor.
+// Destructor - Let the WXMPIterator destructor be implicitly called for the xmpIter data member.
+// Static function - Simply call the corresponding WXMPIterator static function.
+// Non-static function - Simply call the corresponding WXMPIterator function using xmpIter.
+//
+// If a member function has returned strings the code looks roughly like this:
+//
+// <<<callthrough>>>
+// <<<checkfailure>>>
+// if ( <<<appropriate>>> ) {
+// if ( outStr != 0 ) outStr->assign ( outPtr, outLen );
+// <<<unlock>>>
+// }
+// return result;
+//
+// The <<<callthrough>>> is the call to the wrapper, and <<<checkfailure>>> is the check and throw
+// if the wrapper reports failure. The <<<appropriate>>> check is used to determine if the string
+// should actually be assigned. For example, GetProperty can't assign the value if the property
+// does not exist. There is no <<<appropriate>>> check if it isn't, well, appropriate. Outputs are
+// always passed as explicit pointers, and null can be passed if the string is not wanted. The
+// inner implementation holds the threading lock if an output string is returned, regardless of
+// whether the client wants it or not (which the implementation does not know).
+//
+// =================================================================================================
+
+#ifndef XMP_TraceCTorDTor
+ #define XMP_TraceCTorDTor 0
+#endif
+
+#if XMP_TraceCTorDTor
+ class XIPeek { // Hack to peek at the client ref count in the internal object.
+ public:
+ XIPeek();
+ virtual ~XIPeek();
+ XMP_Int32 clientRefs;
+ };
+#endif
+
+// -------------------------------------------------------------------------------------------------
+
+#define PropIterCTor(xmpRef,schemaNS,propName,options) \
+ WrapCheckIterRef ( newRef, zXMPIterator_PropCTor_1 ( xmpRef, schemaNS, propName, options ) ); \
+ this->iterRef = newRef
+
+// -------------------------------------------------------------------------------------------------
+
+#define TableIterCTor(schemaNS,propName,options) \
+ WrapCheckIterRef ( newRef, zXMPIterator_TableCTor_1 ( schemaNS, propName, options ) ); \
+ this->iterRef = newRef
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_CTorDTorIntro(TXMPIterator)::
+TXMPIterator ( const TXMPIterator<tStringObj> & original ) : iterRef(original.iterRef)
+{
+ WXMPIterator_IncrementRefCount_1 ( this->iterRef );
+ #if XMP_TraceCTorDTor
+ XIPeek* xiPtr = (XIPeek*)this->iterRef;
+ printf ( "Copy construct TXMPIterator @ %.8X, ref = %.8X, count = %d\n", this, xiPtr, xiPtr->clientRefs );
+ #endif
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPIterator,void)::
+operator= ( const TXMPIterator<tStringObj> & rhs )
+{
+ #if XMP_TraceCTorDTor
+ XIPeek* xiLHS = (XIPeek*)this->iterRef;
+ XIPeek* xiRHS = (XIPeek*)rhs.iterRef;
+ printf ( "Assign TXMPIterator, lhs @ %.8X, rhs @ %.8X\n", this, &rhs );
+ printf ( " original lhs ref = %.8X, count = %d\n", xiLHS, xiLHS->clientRefs );
+ printf ( " original rhs ref = %.8X, count = %d\n", xiRHS, xiRHS->clientRefs );
+ #endif
+ XMPIteratorRef oldRef = this->iterRef; // ! Decrement last so errors leave client object OK.
+ this->iterRef = rhs.iterRef;
+ WXMPIterator_IncrementRefCount_1 ( this->iterRef );
+ WXMPIterator_DecrementRefCount_1 ( oldRef );
+ #if XMP_TraceCTorDTor
+ printf ( " result lhs ref = %.8X, count = %d\n", xiLHS, xiLHS->clientRefs );
+ #endif
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_CTorDTorIntro(TXMPIterator)::
+TXMPIterator() : iterRef(0)
+{
+ throw XMP_Error ( kXMPErr_Unavailable, "No default construction for XMP iterators" );
+ #if XMP_TraceCTorDTor
+ XIPeek* xiPtr = (XIPeek*)this->iterRef;
+ printf ( "Default construct TXMPIterator @ %.8X, ref = %.8X, count = %d\n", this, xiPtr, xiPtr->clientRefs );
+ #endif
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_CTorDTorIntro(TXMPIterator)::
+TXMPIterator ( const TXMPMeta<tStringObj> & xmpObj,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_OptionBits options /* = 0 */ ) : iterRef(0)
+{
+ PropIterCTor ( xmpObj.GetInternalRef(), schemaNS, propName, options );
+ #if XMP_TraceCTorDTor
+ XIPeek* xiPtr = (XIPeek*)this->iterRef;
+ printf ( "Construct property TXMPIterator @ %.8X, ref = %.8X, count = %d\n", this, xiPtr, xiPtr->clientRefs );
+ #endif
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_CTorDTorIntro(TXMPIterator)::
+TXMPIterator ( const TXMPMeta<tStringObj> & xmpObj,
+ XMP_StringPtr schemaNS,
+ XMP_OptionBits options /* = 0 */ ) : iterRef(0)
+{
+ PropIterCTor ( xmpObj.GetInternalRef(), schemaNS, "", options );
+ #if XMP_TraceCTorDTor
+ XIPeek* xiPtr = (XIPeek*)this->iterRef;
+ printf ( "Construct schema TXMPIterator @ %.8X, ref = %.8X, count = %d\n", this, xiPtr, xiPtr->clientRefs );
+ #endif
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_CTorDTorIntro(TXMPIterator)::
+TXMPIterator ( const TXMPMeta<tStringObj> & xmpObj,
+ XMP_OptionBits options /* = 0 */ ) : iterRef(0)
+{
+ PropIterCTor ( xmpObj.GetInternalRef(), "", "", options );
+ #if XMP_TraceCTorDTor
+ XIPeek* xiPtr = (XIPeek*)this->iterRef;
+ printf ( "Construct tree TXMPIterator @ %.8X, ref = %.8X, count = %d\n", this, xiPtr, xiPtr->clientRefs );
+ #endif
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_CTorDTorIntro(TXMPIterator)::
+TXMPIterator ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_OptionBits options ) : iterRef(0)
+{
+ TableIterCTor ( schemaNS, propName, options );
+ #if XMP_TraceCTorDTor
+ XIPeek* xiPtr = (XIPeek*)this->iterRef;
+ printf ( "Construct table TXMPIterator @ %.8X, ref = %.8X, count = %d\n", this, xiPtr, xiPtr->clientRefs );
+ #endif
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_CTorDTorIntro(TXMPIterator)::
+~TXMPIterator () throw()
+{
+ #if XMP_TraceCTorDTor
+ XIPeek* xiPtr = (XIPeek*)this->iterRef;
+ printf ( "Destruct TXMPIterator @ %.8X, ref = %.8X, count = %d\n", this, xiPtr, xiPtr->clientRefs );
+ #endif
+ WXMPIterator_DecrementRefCount_1 ( this->iterRef );
+ this->iterRef = 0;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPIterator,bool)::
+Next ( tStringObj * schemaNS /* = 0 */,
+ tStringObj * propPath /* = 0 */,
+ tStringObj * propValue /* = 0 */,
+ XMP_OptionBits * options /* = 0 */ )
+{
+ XMP_StringPtr schemaPtr = 0;
+ XMP_StringLen schemaLen = 0;
+ XMP_StringPtr pathPtr = 0;
+ XMP_StringLen pathLen = 0;
+ XMP_StringPtr valuePtr = 0;
+ XMP_StringLen valueLen = 0;
+ WrapCheckBool ( found, zXMPIterator_Next_1 ( &schemaPtr, &schemaLen, &pathPtr, &pathLen, &valuePtr, &valueLen, options ) );
+ if ( found ) {
+ if ( schemaNS != 0 ) schemaNS->assign ( schemaPtr, schemaLen );
+ if ( propPath != 0 ) propPath->assign ( pathPtr, pathLen );
+ if ( propValue != 0 ) propValue->assign ( valuePtr, valueLen );
+ WXMPUtils_UnlockIter_1 ( this->iterRef, 0 );
+ }
+ return found;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPIterator,void)::
+Skip ( XMP_OptionBits options )
+{
+ WrapCheckVoid ( zXMPIterator_Skip_1 ( options ) );
+}
+
+// =================================================================================================
diff --git a/public/include/client-glue/TXMPMeta.incl_cpp b/public/include/client-glue/TXMPMeta.incl_cpp
new file mode 100644
index 0000000..60bd8e7
--- /dev/null
+++ b/public/include/client-glue/TXMPMeta.incl_cpp
@@ -0,0 +1,927 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+// ================================================================================================
+/// \file TXMPMeta.incl_cpp
+/// \brief The implementation of the TXMPMeta template class.
+
+#include "XMP.hpp"
+#include "client-glue/WXMP_Common.hpp"
+#include "client-glue/WXMPMeta.hpp"
+
+// =================================================================================================
+// Implementation Guidelines
+// =========================
+//
+// The implementations of the template functions are very stylized. ...
+//
+// =================================================================================================
+
+#ifndef XMP_TraceCTorDTor
+ #define XMP_TraceCTorDTor 0
+#endif
+
+#if XMP_TraceCTorDTor
+ class XMPeek { // Hack to peek at the client ref count in the internal object.
+ public:
+ XMPeek();
+ virtual ~XMPeek();
+ XMP_Int32 clientRefs;
+ };
+#endif
+
+// =================================================================================================
+
+// =================================================================================================
+// Local utilities
+// ===============
+
+// -------------------------------------------------------------------------------------------------
+
+class TOPW_Info {
+public:
+ XMP_TextOutputProc clientProc;
+ void * clientRefCon;
+ TOPW_Info ( XMP_TextOutputProc proc, void * refCon ) : clientProc(proc), clientRefCon(refCon) {};
+private:
+ TOPW_Info() {}; // ! Hide default constructor.
+};
+
+static XMP_Status TextOutputProcWrapper ( void * refCon,
+ XMP_StringPtr buffer,
+ XMP_StringLen bufferSize )
+{
+ try { // Don't let client callback exceptions propagate across DLL boundaries.
+ TOPW_Info * info = (TOPW_Info*)refCon;
+ return info->clientProc ( info->clientRefCon, buffer, bufferSize );
+ } catch ( ... ) {
+ return -1;
+ }
+}
+
+// =================================================================================================
+// Initialization and termination
+// ==============================
+
+XMP_MethodIntro(TXMPMeta,void)::
+GetVersionInfo ( XMP_VersionInfo * info )
+{
+ WrapNoCheckVoid ( zXMPMeta_GetVersionInfo_1 ( info ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,bool)::
+Initialize()
+{
+ WrapCheckBool ( ok, zXMPMeta_Initialize_1() );
+ return ok;
+}
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+Terminate()
+{
+ WrapNoCheckVoid ( zXMPMeta_Terminate_1() );
+}
+
+// =================================================================================================
+// Constuctors, destructor, operators
+// ==================================
+
+static XMPMetaRef DefaultCTor()
+{
+ WrapCheckMetaRef ( newRef, zXMPMeta_CTor_1() );
+ return newRef;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_CTorDTorIntro(TXMPMeta)::
+TXMPMeta() : xmpRef(DefaultCTor())
+{
+ #if XMP_TraceCTorDTor
+ XMPeek* xmPtr = (XMPeek*)this->xmpRef;
+ printf ( "Default construct TXMPMeta @ %.8X, ref = %.8X, count = %d\n", this, xmPtr, xmPtr->clientRefs );
+ #endif
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_CTorDTorIntro(TXMPMeta)::
+TXMPMeta ( const TXMPMeta<tStringObj> & original ) : xmpRef(original.xmpRef)
+{
+ WXMPMeta_IncrementRefCount_1 ( this->xmpRef );
+ #if XMP_TraceCTorDTor
+ XMPeek* xmPtr = (XMPeek*)this->xmpRef;
+ printf ( "Copy construct TXMPMeta @ %.8X, ref = %.8X, count = %d\n", this, xmPtr, xmPtr->clientRefs );
+ #endif
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+operator= ( const TXMPMeta<tStringObj> & rhs )
+{
+ #if XMP_TraceCTorDTor
+ XMPeek* xmLHS = (XMPeek*)this->xmpRef;
+ XMPeek* xmRHS = (XMPeek*)rhs.xmpRef;
+ printf ( "Assign TXMPMeta, lhs @ %.8X, rhs @ %.8X\n", this, &rhs );
+ printf ( " original lhs ref = %.8X, count = %d\n", xmLHS, xmLHS->clientRefs );
+ printf ( " original rhs ref = %.8X, count = %d\n", xmRHS, xmRHS->clientRefs );
+ #endif
+ XMPMetaRef oldRef = this->xmpRef; // ! Decrement last so errors leave client object OK.
+ this->xmpRef = rhs.xmpRef;
+ WXMPMeta_IncrementRefCount_1 ( this->xmpRef ); // Increment the count on the new ref.
+ WXMPMeta_DecrementRefCount_1 ( oldRef ); // Decrement the count on the old ref.
+ #if XMP_TraceCTorDTor
+ printf ( " result lhs ref = %.8X, count = %d\n", xmLHS, xmLHS->clientRefs );
+ #endif
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_CTorDTorIntro(TXMPMeta)::
+TXMPMeta ( XMPMetaRef _xmpRef ) : xmpRef(_xmpRef)
+{
+ WXMPMeta_IncrementRefCount_1 ( this->xmpRef );
+ #if XMP_TraceCTorDTor
+ XMPeek* xmPtr = (XMPeek*)this->xmpRef;
+ printf ( "Ref construct TXMPMeta @ %.8X, ref = %.8X, count = %d\n", this, xmPtr, xmPtr->clientRefs );
+ #endif
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_CTorDTorIntro(TXMPMeta)::
+TXMPMeta ( XMP_StringPtr buffer,
+ XMP_StringLen xmpSize ) : xmpRef(DefaultCTor())
+{
+ #if XMP_TraceCTorDTor
+ XMPeek* xmPtr = (XMPeek*)this->xmpRef;
+ printf ( "Parse construct TXMPMeta @ %.8X, ref = %.8X, count = %d\n", this, xmPtr, xmPtr->clientRefs );
+ #endif
+ try {
+ this->ParseFromBuffer ( buffer, xmpSize );
+ } catch ( ... ) {
+ WXMPMeta_DecrementRefCount_1 ( this->xmpRef );
+ this->xmpRef = 0;
+ throw;
+ }
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_CTorDTorIntro(TXMPMeta)::
+~TXMPMeta() throw()
+{
+ #if XMP_TraceCTorDTor
+ XMPeek* xmPtr = (XMPeek*)this->xmpRef;
+ printf ( "Destruct TXMPMeta @ %.8X, ref = %.8X, count = %d\n", this, xmPtr, xmPtr->clientRefs );
+ #endif
+ WXMPMeta_DecrementRefCount_1 ( this->xmpRef );
+ this->xmpRef = 0;
+
+} // ~TXMPMeta ()
+
+// =================================================================================================
+// Global state functions
+// ======================
+
+XMP_MethodIntro(TXMPMeta,XMP_OptionBits)::
+GetGlobalOptions()
+{
+ WrapCheckOptions ( options, zXMPMeta_GetGlobalOptions_1() );
+ return options;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+SetGlobalOptions ( XMP_OptionBits options )
+{
+ WrapCheckVoid ( zXMPMeta_SetGlobalOptions_1 ( options ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,XMP_Status)::
+DumpNamespaces ( XMP_TextOutputProc outProc,
+ void * refCon )
+{
+ TOPW_Info info ( outProc, refCon );
+ WrapCheckStatus ( status, zXMPMeta_DumpNamespaces_1 ( TextOutputProcWrapper, &info ) );
+ return status;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,XMP_Status)::
+DumpAliases ( XMP_TextOutputProc outProc,
+ void * refCon )
+{
+ TOPW_Info info ( outProc, refCon );
+ WrapCheckStatus ( status, zXMPMeta_DumpAliases_1 ( TextOutputProcWrapper, &info ) );
+ return status;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,bool)::
+RegisterNamespace ( XMP_StringPtr namespaceURI,
+ XMP_StringPtr suggestedPrefix,
+ tStringObj * registeredPrefix )
+{
+ XMP_StringPtr resultPtr = 0;
+ XMP_StringLen resultLen = 0;
+ WrapCheckBool ( prefixMatch, zXMPMeta_RegisterNamespace_1 ( namespaceURI, suggestedPrefix, &resultPtr, &resultLen ) );
+ if ( registeredPrefix != 0 ) registeredPrefix->assign ( resultPtr, resultLen );
+ WXMPMeta_Unlock_1 ( 0 );
+ return prefixMatch;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,bool)::
+GetNamespacePrefix ( XMP_StringPtr namespaceURI,
+ tStringObj * namespacePrefix )
+{
+ XMP_StringPtr resultPtr = 0;
+ XMP_StringLen resultLen = 0;
+ WrapCheckBool ( found, zXMPMeta_GetNamespacePrefix_1 ( namespaceURI, &resultPtr, &resultLen ) );
+ if ( found ) {
+ if ( namespacePrefix != 0 ) namespacePrefix->assign ( resultPtr, resultLen );
+ WXMPMeta_Unlock_1 ( 0 );
+ }
+ return found;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,bool)::
+GetNamespaceURI ( XMP_StringPtr namespacePrefix,
+ tStringObj * namespaceURI )
+{
+ XMP_StringPtr resultPtr = 0;
+ XMP_StringLen resultLen = 0;
+ WrapCheckBool ( found, zXMPMeta_GetNamespaceURI_1 ( namespacePrefix, &resultPtr, &resultLen ) );
+ if ( found ) {
+ if ( namespaceURI != 0 ) namespaceURI->assign ( resultPtr, resultLen );
+ WXMPMeta_Unlock_1 ( 0 );
+ }
+ return found;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+DeleteNamespace ( XMP_StringPtr namespaceURI )
+{
+ WrapCheckVoid ( zXMPMeta_DeleteNamespace_1 ( namespaceURI ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+RegisterAlias ( XMP_StringPtr aliasNS,
+ XMP_StringPtr aliasProp,
+ XMP_StringPtr actualNS,
+ XMP_StringPtr actualProp,
+ XMP_OptionBits arrayForm )
+{
+ WrapCheckVoid ( zXMPMeta_RegisterAlias_1 ( aliasNS, aliasProp, actualNS, actualProp, arrayForm ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,bool)::
+ResolveAlias ( XMP_StringPtr aliasNS,
+ XMP_StringPtr aliasProp,
+ tStringObj * actualNS,
+ tStringObj * actualProp,
+ XMP_OptionBits * arrayForm )
+{
+ XMP_StringPtr nsPtr = 0;
+ XMP_StringLen nsLen = 0;
+ XMP_StringPtr propPtr = 0;
+ XMP_StringLen propLen = 0;
+ WrapCheckBool ( found, zXMPMeta_ResolveAlias_1 ( aliasNS, aliasProp, &nsPtr, &nsLen, &propPtr, &propLen, arrayForm ) );
+ if ( found ) {
+ if ( actualNS != 0 ) actualNS->assign ( nsPtr, nsLen );
+ if ( actualProp != 0 ) actualProp->assign ( propPtr, propLen );
+ WXMPMeta_Unlock_1 ( 0 );
+ }
+ return found;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+DeleteAlias ( XMP_StringPtr aliasNS,
+ XMP_StringPtr aliasProp )
+{
+ WrapCheckVoid ( zXMPMeta_DeleteAlias_1 ( aliasNS, aliasProp ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+RegisterStandardAliases ( XMP_StringPtr schemaNS )
+{
+ WrapCheckVoid ( zXMPMeta_RegisterStandardAliases_1 ( schemaNS ) );
+}
+
+// =================================================================================================
+// Basic property manipulation functions
+// =====================================
+
+XMP_MethodIntro(TXMPMeta,bool)::
+GetProperty ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ tStringObj * propValue,
+ XMP_OptionBits * options ) const
+{
+ XMP_StringPtr resultPtr = 0;
+ XMP_StringLen resultLen = 0;
+ WrapCheckBool ( found, zXMPMeta_GetProperty_1 ( schemaNS, propName, &resultPtr, &resultLen, options ) );
+ if ( found ) {
+ if ( propValue != 0 ) propValue->assign ( resultPtr, resultLen );
+ WXMPMeta_UnlockObject_1 ( this->xmpRef, 0 );
+ }
+ return found;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,bool)::
+GetArrayItem ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex,
+ tStringObj * itemValue,
+ XMP_OptionBits * options ) const
+{
+ XMP_StringPtr resultPtr = 0;
+ XMP_StringLen resultLen = 0;
+ WrapCheckBool ( found, zXMPMeta_GetArrayItem_1 ( schemaNS, arrayName, itemIndex, &resultPtr, &resultLen, options ) );
+ if ( found ) {
+ if ( itemValue != 0 ) itemValue->assign ( resultPtr, resultLen );
+ WXMPMeta_UnlockObject_1 ( this->xmpRef, 0 );
+ }
+ return found;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,bool)::
+GetStructField ( XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ tStringObj * fieldValue,
+ XMP_OptionBits * options ) const
+{
+ XMP_StringPtr resultPtr = 0;
+ XMP_StringLen resultLen = 0;
+ WrapCheckBool ( found, zXMPMeta_GetStructField_1 ( schemaNS, structName, fieldNS, fieldName, &resultPtr, &resultLen, options ) );
+ if ( found ) {
+ if ( fieldValue != 0 ) fieldValue->assign ( resultPtr, resultLen );
+ WXMPMeta_UnlockObject_1 ( this->xmpRef, 0 );
+ }
+ return found;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,bool)::
+GetQualifier ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName,
+ tStringObj * qualValue,
+ XMP_OptionBits * options ) const
+{
+ XMP_StringPtr resultPtr = 0;
+ XMP_StringLen resultLen = 0;
+ WrapCheckBool ( found, zXMPMeta_GetQualifier_1 ( schemaNS, propName, qualNS, qualName, &resultPtr, &resultLen, options ) );
+ if ( found ) {
+ if ( qualValue != 0 ) qualValue->assign ( resultPtr, resultLen );
+ WXMPMeta_UnlockObject_1 ( this->xmpRef, 0 );
+ }
+ return found;
+} //GetQualifier ()
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+SetProperty ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr propValue,
+ XMP_OptionBits options /* = 0 */ )
+{
+ WrapCheckVoid ( zXMPMeta_SetProperty_1 ( schemaNS, propName, propValue, options ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+SetProperty ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ const tStringObj & propValue,
+ XMP_OptionBits options /* = 0 */ )
+{
+ this->SetProperty ( schemaNS, propName, propValue.c_str(), options );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+SetArrayItem ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex,
+ XMP_StringPtr itemValue,
+ XMP_OptionBits options /* = 0 */ )
+{
+ WrapCheckVoid ( zXMPMeta_SetArrayItem_1 ( schemaNS, arrayName, itemIndex, itemValue, options ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+SetArrayItem ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex,
+ const tStringObj & itemValue,
+ XMP_OptionBits options /* = 0 */ )
+{
+ this->SetArrayItem ( schemaNS, arrayName, itemIndex, itemValue.c_str(), options );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+AppendArrayItem ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_OptionBits arrayOptions,
+ XMP_StringPtr itemValue,
+ XMP_OptionBits options /* = 0 */ )
+{
+ WrapCheckVoid ( zXMPMeta_AppendArrayItem_1 ( schemaNS, arrayName, arrayOptions, itemValue, options ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+AppendArrayItem ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_OptionBits arrayOptions,
+ const tStringObj & itemValue,
+ XMP_OptionBits options /* = 0 */ )
+{
+ this->AppendArrayItem ( schemaNS, arrayName, arrayOptions, itemValue.c_str(), options );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+SetStructField ( XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ XMP_StringPtr fieldValue,
+ XMP_OptionBits options /* = 0 */ )
+{
+ WrapCheckVoid ( zXMPMeta_SetStructField_1 ( schemaNS, structName, fieldNS, fieldName, fieldValue, options ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+SetStructField ( XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ const tStringObj & fieldValue,
+ XMP_OptionBits options /* = 0 */ )
+{
+ this->SetStructField ( schemaNS, structName, fieldNS, fieldName, fieldValue.c_str(), options );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+SetQualifier ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName,
+ XMP_StringPtr qualValue,
+ XMP_OptionBits options /* = 0 */ )
+{
+ WrapCheckVoid ( zXMPMeta_SetQualifier_1 ( schemaNS, propName, qualNS, qualName, qualValue, options ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+SetQualifier ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName,
+ const tStringObj & qualValue,
+ XMP_OptionBits options /* = 0 */ )
+{
+ this->SetQualifier ( schemaNS, propName, qualNS, qualName, qualValue.c_str(), options );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+DeleteProperty ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName )
+{
+ WrapCheckVoid ( zXMPMeta_DeleteProperty_1 ( schemaNS, propName ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+DeleteArrayItem ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex )
+{
+ WrapCheckVoid ( zXMPMeta_DeleteArrayItem_1 ( schemaNS, arrayName, itemIndex ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+DeleteStructField ( XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName )
+{
+ WrapCheckVoid ( zXMPMeta_DeleteStructField_1 ( schemaNS, structName, fieldNS, fieldName ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+DeleteQualifier ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName )
+{
+ WrapCheckVoid ( zXMPMeta_DeleteQualifier_1 ( schemaNS, propName, qualNS, qualName ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,bool)::
+DoesPropertyExist ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName ) const
+{
+ WrapCheckBool ( exists, zXMPMeta_DoesPropertyExist_1 ( schemaNS, propName ) );
+ return exists;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,bool)::
+DoesArrayItemExist ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex ) const
+{
+ WrapCheckBool ( exists, zXMPMeta_DoesArrayItemExist_1 ( schemaNS, arrayName, itemIndex ) );
+ return exists;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,bool)::
+DoesStructFieldExist ( XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName ) const
+{
+ WrapCheckBool ( exists, zXMPMeta_DoesStructFieldExist_1 ( schemaNS, structName, fieldNS, fieldName ) );
+ return exists;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,bool)::
+DoesQualifierExist ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName ) const
+{
+ WrapCheckBool ( exists, zXMPMeta_DoesQualifierExist_1 ( schemaNS, propName, qualNS, qualName ) );
+ return exists;
+}
+
+// =================================================================================================
+// Specialized Get and Set functions
+// =================================
+
+XMP_MethodIntro(TXMPMeta,bool)::
+GetLocalizedText ( XMP_StringPtr schemaNS,
+ XMP_StringPtr altTextName,
+ XMP_StringPtr genericLang,
+ XMP_StringPtr specificLang,
+ tStringObj * actualLang,
+ tStringObj * itemValue,
+ XMP_OptionBits * options ) const
+{
+ XMP_StringPtr langPtr = 0;
+ XMP_StringLen langLen = 0;
+ XMP_StringPtr itemPtr = 0;
+ XMP_StringLen itemLen = 0;
+ WrapCheckBool ( found, zXMPMeta_GetLocalizedText_1 ( schemaNS, altTextName, genericLang, specificLang,
+ &langPtr, &langLen, &itemPtr, &itemLen, options ) );
+ if ( found ) {
+ if ( actualLang != 0 ) actualLang->assign ( langPtr, langLen );
+ if ( itemValue != 0 ) itemValue->assign ( itemPtr, itemLen );
+ WXMPMeta_UnlockObject_1 ( this->xmpRef, kXMP_NoOptions );
+ }
+ return found;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+SetLocalizedText ( XMP_StringPtr schemaNS,
+ XMP_StringPtr altTextName,
+ XMP_StringPtr genericLang,
+ XMP_StringPtr specificLang,
+ XMP_StringPtr itemValue,
+ XMP_OptionBits options /* = 0 */ )
+{
+ WrapCheckVoid ( zXMPMeta_SetLocalizedText_1 ( schemaNS, altTextName, genericLang, specificLang, itemValue, options ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+SetLocalizedText ( XMP_StringPtr schemaNS,
+ XMP_StringPtr altTextName,
+ XMP_StringPtr genericLang,
+ XMP_StringPtr specificLang,
+ const tStringObj & itemValue,
+ XMP_OptionBits options /* = 0 */ )
+{
+ this->SetLocalizedText ( schemaNS, altTextName, genericLang, specificLang, itemValue.c_str(), options );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,bool)::
+GetProperty_Bool ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ bool * propValue,
+ XMP_OptionBits * options ) const
+{
+ XMP_Bool binValue;
+ WrapCheckBool ( found, zXMPMeta_GetProperty_Bool_1 ( schemaNS, propName, &binValue, options ) );
+ if ( found && (propValue != 0) ) *propValue = binValue;
+ return found;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,bool)::
+GetProperty_Int ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ long * propValue,
+ XMP_OptionBits * options ) const
+{
+ XMP_Int32 abiValue;
+ WrapCheckBool ( found, zXMPMeta_GetProperty_Int_1 ( schemaNS, propName, &abiValue, options ) );
+ if ( found && (propValue != 0) ) *propValue = abiValue;
+ return found;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,bool)::
+GetProperty_Int64 ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ long long * propValue,
+ XMP_OptionBits * options ) const
+{
+ XMP_Int64 abiValue;
+ WrapCheckBool ( found, zXMPMeta_GetProperty_Int64_1 ( schemaNS, propName, &abiValue, options ) );
+ if ( found && (propValue != 0) ) *propValue = abiValue;
+ return found;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,bool)::
+GetProperty_Float ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ double * propValue,
+ XMP_OptionBits * options ) const
+{
+ WrapCheckBool ( found, zXMPMeta_GetProperty_Float_1 ( schemaNS, propName, propValue, options ) );
+ return found;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,bool)::
+GetProperty_Date ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_DateTime * propValue,
+ XMP_OptionBits * options ) const
+{
+ WrapCheckBool ( found, zXMPMeta_GetProperty_Date_1 ( schemaNS, propName, propValue, options ) );
+ return found;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+SetProperty_Bool ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ bool propValue,
+ XMP_OptionBits options /* = 0 */ )
+{
+ WrapCheckVoid ( zXMPMeta_SetProperty_Bool_1 ( schemaNS, propName, propValue, options ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+SetProperty_Int ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ long propValue,
+ XMP_OptionBits options /* = 0 */ )
+{
+ WrapCheckVoid ( zXMPMeta_SetProperty_Int_1 ( schemaNS, propName, propValue, options ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+SetProperty_Int64 ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ long long propValue,
+ XMP_OptionBits options /* = 0 */ )
+{
+ WrapCheckVoid ( zXMPMeta_SetProperty_Int64_1 ( schemaNS, propName, propValue, options ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+SetProperty_Float ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ double propValue,
+ XMP_OptionBits options /* = 0 */ )
+{
+ WrapCheckVoid ( zXMPMeta_SetProperty_Float_1 ( schemaNS, propName, propValue, options ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+SetProperty_Date ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ const XMP_DateTime & propValue,
+ XMP_OptionBits options /* = 0 */ )
+{
+ WrapCheckVoid ( zXMPMeta_SetProperty_Date_1 ( schemaNS, propName, propValue, options ) );
+}
+
+// =================================================================================================
+// Miscellaneous Member Functions
+// ==============================
+
+XMP_MethodIntro(TXMPMeta,XMPMetaRef)::
+GetInternalRef() const
+{
+ return this->xmpRef;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+GetObjectName ( tStringObj * name ) const
+{
+ XMP_StringPtr namePtr = 0;
+ XMP_StringLen nameLen = 0;
+ WrapCheckVoid ( zXMPMeta_GetObjectName_1 ( &namePtr, &nameLen ) );
+ if ( name != 0 ) name->assign ( namePtr, nameLen );
+ WXMPMeta_UnlockObject_1 ( this->xmpRef, 0 );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+SetObjectName ( XMP_StringPtr name )
+{
+ WrapCheckVoid ( zXMPMeta_SetObjectName_1 ( name ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+SetObjectName ( tStringObj name )
+{
+ this->SetObjectName ( name.c_str() );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,XMP_OptionBits)::
+GetObjectOptions() const
+{
+ WrapCheckOptions ( options, zXMPMeta_GetObjectOptions_1() );
+ return options;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+SetObjectOptions ( XMP_OptionBits options )
+{
+ WrapCheckVoid ( zXMPMeta_SetObjectOptions_1 ( options ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,TXMPMeta<tStringObj>)::
+Clone ( XMP_OptionBits options ) const
+{
+ WrapCheckMetaRef ( cloneRef, zXMPMeta_Clone_1 ( options ) );
+ return TXMPMeta<tStringObj> ( cloneRef ); // Ref construct will increment the clientRefs.
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,XMP_Index)::
+CountArrayItems ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName ) const
+{
+ WrapCheckIndex ( count, zXMPMeta_CountArrayItems_1 ( schemaNS, arrayName ) );
+ return count;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,XMP_Status)::
+DumpObject ( XMP_TextOutputProc outProc,
+ void * refCon ) const
+{
+ TOPW_Info info ( outProc, refCon );
+ WrapCheckStatus ( status, zXMPMeta_DumpObject_1 ( TextOutputProcWrapper, &info ) );
+ return status;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+ParseFromBuffer ( XMP_StringPtr buffer,
+ XMP_StringLen bufferSize,
+ XMP_OptionBits options /* = 0 */ )
+{
+ WrapCheckVoid ( zXMPMeta_ParseFromBuffer_1 ( buffer, bufferSize, options ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+SerializeToBuffer ( tStringObj * pktString,
+ XMP_OptionBits options,
+ XMP_StringLen padding,
+ XMP_StringPtr newline,
+ XMP_StringPtr indent,
+ XMP_Index baseIndent /* = 0 */ ) const
+{
+ XMP_StringPtr resultPtr = 0;
+ XMP_StringLen resultLen = 0;
+ WrapCheckVoid ( zXMPMeta_SerializeToBuffer_1 ( &resultPtr, &resultLen, options, padding, newline, indent, baseIndent ) );
+ if ( pktString != 0 ) pktString->assign ( resultPtr, resultLen );
+ WXMPMeta_UnlockObject_1 ( this->xmpRef, 0 );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+SerializeToBuffer ( tStringObj * pktString,
+ XMP_OptionBits options /* = 0 */,
+ XMP_StringLen padding /* = 0 */ ) const
+{
+ this->SerializeToBuffer ( pktString, options, padding, "", "", 0 );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+// =================================================================================================
diff --git a/public/include/client-glue/TXMPUtils.incl_cpp b/public/include/client-glue/TXMPUtils.incl_cpp
new file mode 100644
index 0000000..761ac4e
--- /dev/null
+++ b/public/include/client-glue/TXMPUtils.incl_cpp
@@ -0,0 +1,491 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+// ================================================================================================
+/// \file TXMPUtils.incl_cpp
+/// \brief The implementation of the TXMPUtils template class.
+
+#include "XMP.hpp"
+#include "client-glue/WXMP_Common.hpp"
+#include "client-glue/WXMPUtils.hpp"
+
+// =================================================================================================
+// Implementation Guidelines
+// =========================
+//
+// The implementations of the template functions are very stylized. ...
+//
+// =================================================================================================
+
+XMP_MethodIntro(TXMPUtils,void)::
+ComposeArrayItemPath ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex,
+ tStringObj * fullPath )
+{
+ XMP_StringPtr pathPtr = 0;
+ XMP_StringLen pathLen = 0;
+ WrapCheckVoid ( zXMPUtils_ComposeArrayItemPath_1 ( schemaNS, arrayName, itemIndex, &pathPtr, &pathLen ) );
+ if ( fullPath != 0 ) fullPath->assign ( pathPtr, pathLen );
+ WXMPUtils_Unlock_1 ( 0 );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+ComposeStructFieldPath ( XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ tStringObj * fullPath )
+{
+ XMP_StringPtr pathPtr = 0;
+ XMP_StringLen pathLen = 0;
+ WrapCheckVoid ( zXMPUtils_ComposeStructFieldPath_1 ( schemaNS, structName, fieldNS, fieldName, &pathPtr, &pathLen ) );
+ if ( fullPath != 0 ) fullPath->assign ( pathPtr, pathLen );
+ WXMPUtils_Unlock_1 ( 0 );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+ComposeQualifierPath ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName,
+ tStringObj * fullPath )
+{
+ XMP_StringPtr pathPtr = 0;
+ XMP_StringLen pathLen = 0;
+ WrapCheckVoid ( zXMPUtils_ComposeQualifierPath_1 ( schemaNS, propName, qualNS, qualName, &pathPtr, &pathLen ) );
+ if ( fullPath != 0 ) fullPath->assign ( pathPtr, pathLen );
+ WXMPUtils_Unlock_1 ( 0 );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+ComposeLangSelector ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_StringPtr langName,
+ tStringObj * fullPath )
+{
+ XMP_StringPtr pathPtr = 0;
+ XMP_StringLen pathLen = 0;
+ WrapCheckVoid ( zXMPUtils_ComposeLangSelector_1 ( schemaNS, arrayName, langName, &pathPtr, &pathLen ) );
+ if ( fullPath != 0 ) fullPath->assign ( pathPtr, pathLen );
+ WXMPUtils_Unlock_1 ( 0 );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+ComposeLangSelector ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ const tStringObj & langName,
+ tStringObj * fullPath )
+{
+ TXMPUtils::ComposeLangSelector ( schemaNS, arrayName, langName.c_str(), fullPath );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+ComposeFieldSelector ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ XMP_StringPtr fieldValue,
+ tStringObj * fullPath )
+{
+ XMP_StringPtr pathPtr = 0;
+ XMP_StringLen pathLen = 0;
+ WrapCheckVoid ( zXMPUtils_ComposeFieldSelector_1 ( schemaNS, arrayName, fieldNS, fieldName, fieldValue,
+ &pathPtr, &pathLen ) );
+ if ( fullPath != 0 ) fullPath->assign ( pathPtr, pathLen );
+ WXMPUtils_Unlock_1 ( 0 );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+ComposeFieldSelector ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ const tStringObj & fieldValue,
+ tStringObj * fullPath )
+{
+ TXMPUtils::ComposeFieldSelector ( schemaNS, arrayName, fieldNS, fieldName, fieldValue.c_str(), fullPath );
+}
+
+// -------------------------------------------------------------------------------------------------
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+ConvertFromBool ( bool binValue,
+ tStringObj * strValue )
+{
+ XMP_StringPtr strPtr = 0;
+ XMP_StringLen strLen = 0;
+ WrapCheckVoid ( zXMPUtils_ConvertFromBool_1 ( binValue, &strPtr, &strLen ) );
+ if ( strValue != 0 ) strValue->assign ( strPtr, strLen );
+ WXMPUtils_Unlock_1 ( 0 );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+ConvertFromInt ( long binValue,
+ XMP_StringPtr format,
+ tStringObj * strValue )
+{
+ XMP_StringPtr strPtr = 0;
+ XMP_StringLen strLen = 0;
+ WrapCheckVoid ( zXMPUtils_ConvertFromInt_1 ( binValue, format, &strPtr, &strLen ) );
+ if ( strValue != 0 ) strValue->assign ( strPtr, strLen );
+ WXMPUtils_Unlock_1 ( 0 );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+ConvertFromInt64 ( long long binValue,
+ XMP_StringPtr format,
+ tStringObj * strValue )
+{
+ XMP_StringPtr strPtr = 0;
+ XMP_StringLen strLen = 0;
+ WrapCheckVoid ( zXMPUtils_ConvertFromInt64_1 ( binValue, format, &strPtr, &strLen ) );
+ if ( strValue != 0 ) strValue->assign ( strPtr, strLen );
+ WXMPUtils_Unlock_1 ( 0 );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+ConvertFromFloat ( double binValue,
+ XMP_StringPtr format,
+ tStringObj * strValue )
+{
+ XMP_StringPtr strPtr = 0;
+ XMP_StringLen strLen = 0;
+ WrapCheckVoid ( zXMPUtils_ConvertFromFloat_1 ( binValue, format, &strPtr, &strLen ) );
+ if ( strValue != 0 ) strValue->assign ( strPtr, strLen );
+ WXMPUtils_Unlock_1 ( 0 );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+ConvertFromDate ( const XMP_DateTime & binValue,
+ tStringObj * strValue )
+{
+ XMP_StringPtr strPtr = 0;
+ XMP_StringLen strLen = 0;
+ WrapCheckVoid ( zXMPUtils_ConvertFromDate_1 ( binValue, &strPtr, &strLen ) );
+ if ( strValue != 0 ) strValue->assign ( strPtr, strLen );
+ WXMPUtils_Unlock_1 ( 0 );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,bool)::
+ConvertToBool ( XMP_StringPtr strValue )
+{
+ WrapCheckBool ( value, zXMPUtils_ConvertToBool_1 ( strValue ) );
+ return value;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,bool)::
+ConvertToBool ( const tStringObj & strValue )
+{
+ return TXMPUtils::ConvertToBool ( strValue.c_str() );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,long)::
+ConvertToInt ( XMP_StringPtr strValue )
+{
+ WrapCheckInt32 ( value, zXMPUtils_ConvertToInt_1 ( strValue ) );
+ return value;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,long)::
+ConvertToInt ( const tStringObj & strValue )
+{
+ return TXMPUtils::ConvertToInt ( strValue.c_str() );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,long long)::
+ConvertToInt64 ( XMP_StringPtr strValue )
+{
+ WrapCheckInt64 ( value, zXMPUtils_ConvertToInt64_1 ( strValue ) );
+ return value;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,long long)::
+ConvertToInt64 ( const tStringObj & strValue )
+{
+ return TXMPUtils::ConvertToInt64 ( strValue.c_str() );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,double)::
+ConvertToFloat ( XMP_StringPtr strValue )
+{
+ WrapCheckFloat ( value, zXMPUtils_ConvertToFloat_1 ( strValue ) );
+ return value;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,double)::
+ConvertToFloat ( const tStringObj & strValue )
+{
+ return TXMPUtils::ConvertToFloat ( strValue.c_str() );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+ConvertToDate ( XMP_StringPtr strValue,
+ XMP_DateTime * binValue )
+{
+ WrapCheckVoid ( zXMPUtils_ConvertToDate_1 ( strValue, binValue ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+ConvertToDate ( const tStringObj & strValue,
+ XMP_DateTime * binValue )
+{
+ TXMPUtils::ConvertToDate ( strValue.c_str(), binValue );
+}
+
+// -------------------------------------------------------------------------------------------------
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+CurrentDateTime ( XMP_DateTime * time )
+{
+ WrapCheckVoid ( zXMPUtils_CurrentDateTime_1 ( time ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+SetTimeZone ( XMP_DateTime * time )
+{
+ WrapCheckVoid ( zXMPUtils_SetTimeZone_1 ( time ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+ConvertToUTCTime ( XMP_DateTime * time )
+{
+ WrapCheckVoid ( zXMPUtils_ConvertToUTCTime_1 ( time ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+ConvertToLocalTime ( XMP_DateTime * time )
+{
+ WrapCheckVoid ( zXMPUtils_ConvertToLocalTime_1 ( time ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,int)::
+CompareDateTime ( const XMP_DateTime & left,
+ const XMP_DateTime & right )
+{
+ WrapCheckInt32 ( result, zXMPUtils_CompareDateTime_1 ( left, right ) );
+ return result;
+}
+
+// -------------------------------------------------------------------------------------------------
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+EncodeToBase64 ( XMP_StringPtr rawStr,
+ XMP_StringLen rawLen,
+ tStringObj * encodedStr )
+{
+ XMP_StringPtr encPtr = 0;
+ XMP_StringLen encLen = 0;
+ WrapCheckVoid ( zXMPUtils_EncodeToBase64_1 ( rawStr, rawLen, &encPtr, &encLen ) );
+ if ( encodedStr != 0 ) encodedStr->assign ( encPtr, encLen );
+ WXMPUtils_Unlock_1 ( 0 );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+EncodeToBase64 ( const tStringObj & rawStr,
+ tStringObj * encodedStr )
+{
+ TXMPUtils::EncodeToBase64 ( rawStr.c_str(), (XMP_StringLen)rawStr.size(), encodedStr );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+DecodeFromBase64 ( XMP_StringPtr encodedStr,
+ XMP_StringLen encodedLen,
+ tStringObj * rawStr )
+{
+ XMP_StringPtr rawPtr = 0;
+ XMP_StringLen rawLen = 0;
+ WrapCheckVoid ( zXMPUtils_DecodeFromBase64_1 ( encodedStr, encodedLen, &rawPtr, &rawLen ) );
+ if ( rawStr != 0 ) rawStr->assign ( rawPtr, rawLen );
+ WXMPUtils_Unlock_1 ( 0 );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+DecodeFromBase64 ( const tStringObj & encodedStr,
+ tStringObj * rawStr )
+{
+ TXMPUtils::DecodeFromBase64 ( encodedStr.c_str(), (XMP_StringLen)encodedStr.size(), rawStr );
+}
+
+// -------------------------------------------------------------------------------------------------
+// -------------------------------------------------------------------------------------------------
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+PackageForJPEG ( const TXMPMeta<tStringObj> & xmpObj,
+ tStringObj * standardXMP,
+ tStringObj * extendedXMP,
+ tStringObj * extendedDigest )
+{
+ XMP_StringPtr stdStr = 0;
+ XMP_StringLen stdLen = 0;
+ XMP_StringPtr extStr = 0;
+ XMP_StringLen extLen = 0;
+ XMP_StringPtr digestStr = 0;
+ XMP_StringLen digestLen = 0;
+ WrapCheckVoid ( zXMPUtils_PackageForJPEG_1 ( xmpObj.GetInternalRef(),
+ &stdStr, &stdLen, &extStr, &extLen, &digestStr, &digestLen ) );
+ if ( standardXMP != 0 ) standardXMP->assign ( stdStr, stdLen );
+ if ( extendedXMP != 0 ) extendedXMP->assign ( extStr, extLen );
+ if ( extendedDigest != 0 ) extendedDigest->assign ( digestStr, digestLen );
+ WXMPUtils_Unlock_1 ( 0 );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+MergeFromJPEG ( TXMPMeta<tStringObj> * fullXMP,
+ const TXMPMeta<tStringObj> & extendedXMP )
+{
+ WrapCheckVoid ( zXMPUtils_MergeFromJPEG_1 ( fullXMP->GetInternalRef(), extendedXMP.GetInternalRef() ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+CatenateArrayItems ( const TXMPMeta<tStringObj> & xmpObj,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_StringPtr separator,
+ XMP_StringPtr quotes,
+ XMP_OptionBits options,
+ tStringObj * catedStr )
+{
+ XMP_StringPtr catedPtr = 0;
+ XMP_StringLen catedLen = 0;
+ WrapCheckVoid ( zXMPUtils_CatenateArrayItems_1 ( xmpObj.GetInternalRef(), schemaNS, arrayName,
+ separator, quotes, options, &catedPtr, &catedLen ) );
+ if ( catedStr != 0 ) catedStr->assign ( catedPtr, catedLen );
+ WXMPUtils_Unlock_1 ( 0 );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+SeparateArrayItems ( TXMPMeta<tStringObj> * xmpObj,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_OptionBits options,
+ XMP_StringPtr catedStr )
+{
+ if ( xmpObj == 0 ) throw XMP_Error ( kXMPErr_BadParam, "Null output SXMPMeta pointer" );
+ WrapCheckVoid ( zXMPUtils_SeparateArrayItems_1 ( xmpObj->GetInternalRef(), schemaNS, arrayName, options, catedStr ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+SeparateArrayItems ( TXMPMeta<tStringObj> * xmpObj,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_OptionBits options,
+ const tStringObj & catedStr )
+{
+ TXMPUtils::SeparateArrayItems ( xmpObj, schemaNS, arrayName, options, catedStr.c_str() );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+RemoveProperties ( TXMPMeta<tStringObj> * xmpObj,
+ XMP_StringPtr schemaNS /* = 0 */,
+ XMP_StringPtr propName /* = 0 */,
+ XMP_OptionBits options /* = 0 */ )
+{
+ if ( xmpObj == 0 ) throw XMP_Error ( kXMPErr_BadParam, "Null output SXMPMeta pointer" );
+ WrapCheckVoid ( zXMPUtils_RemoveProperties_1 ( xmpObj->GetInternalRef(), schemaNS, propName, options ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+AppendProperties ( const TXMPMeta<tStringObj> & source,
+ TXMPMeta<tStringObj> * dest,
+ XMP_OptionBits options /* = 0 */ )
+{
+ if ( dest == 0 ) throw XMP_Error ( kXMPErr_BadParam, "Null output SXMPMeta pointer" );
+ WrapCheckVoid ( zXMPUtils_AppendProperties_1 ( source.GetInternalRef(), dest->GetInternalRef(), options ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+DuplicateSubtree ( const TXMPMeta<tStringObj> & source,
+ TXMPMeta<tStringObj> * dest,
+ XMP_StringPtr sourceNS,
+ XMP_StringPtr sourceRoot,
+ XMP_StringPtr destNS /*= 0 */,
+ XMP_StringPtr destRoot /* = 0 */,
+ XMP_OptionBits options /* = 0 */ )
+{
+ if ( dest == 0 ) throw XMP_Error ( kXMPErr_BadParam, "Null output SXMPMeta pointer" );
+ WrapCheckVoid ( zXMPUtils_DuplicateSubtree_1 ( source.GetInternalRef(), dest->GetInternalRef(),
+ sourceNS, sourceRoot, destNS, destRoot, options ) );
+}
+
+// =================================================================================================
diff --git a/public/include/client-glue/WXMPFiles.hpp b/public/include/client-glue/WXMPFiles.hpp
new file mode 100644
index 0000000..556ad54
--- /dev/null
+++ b/public/include/client-glue/WXMPFiles.hpp
@@ -0,0 +1,155 @@
+#ifndef __WXMPFiles_hpp__
+#define __WXMPFiles_hpp__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "client-glue/WXMP_Common.hpp"
+
+#if __cplusplus
+extern "C" {
+#endif
+
+// =================================================================================================
+/// \file WXMPFiles.h
+/// \brief High level support to access metadata in files of interest to Adobe applications.
+///
+/// This header ...
+///
+// =================================================================================================
+
+// =================================================================================================
+
+#define WrapCheckXMPFilesRef(result,WCallProto) \
+ WXMP_Result wResult; \
+ WCallProto; \
+ PropagateException ( wResult ); \
+ XMPFilesRef result = XMPFilesRef(wResult.ptrResult)
+
+// =================================================================================================
+
+#define zXMPFiles_GetVersionInfo_1(versionInfo) \
+ WXMPFiles_GetVersionInfo_1 ( versionInfo /* no wResult */ )
+
+#define zXMPFiles_Initialize_1() \
+ WXMPFiles_Initialize_1 ( &wResult )
+
+#define zXMPFiles_Initialize_2(options) \
+ WXMPFiles_Initialize_2 ( options, &wResult )
+
+#define zXMPFiles_Terminate_1() \
+ WXMPFiles_Terminate_1 ( /* no wResult */ )
+
+#define zXMPFiles_CTor_1() \
+ WXMPFiles_CTor_1 ( &wResult )
+
+#define zXMPFiles_GetFormatInfo_1(format,flags) \
+ WXMPFiles_GetFormatInfo_1 ( format, flags, &wResult )
+
+#define zXMPFiles_OpenFile_1(filePath,format,openFlags) \
+ WXMPFiles_OpenFile_1 ( this->xmpFilesRef, filePath, format, openFlags, &wResult )
+
+#define zXMPFiles_CloseFile_1(closeFlags) \
+ WXMPFiles_CloseFile_1 ( this->xmpFilesRef, closeFlags, &wResult )
+
+#define zXMPFiles_GetFileInfo_1(filePath,filePathLen,openFlags,format,handlerFlags) \
+ WXMPFiles_GetFileInfo_1 ( this->xmpFilesRef, filePath, filePathLen, openFlags, format, handlerFlags, &wResult )
+
+#define zXMPFiles_SetAbortProc_1(abortProc,abortArg) \
+ WXMPFiles_SetAbortProc_1 ( this->xmpFilesRef, abortProc, abortArg, &wResult )
+
+#define zXMPFiles_GetXMP_1(xmpRef,xmpPacket,xmpPacketLen,packetInfo) \
+ WXMPFiles_GetXMP_1 ( this->xmpFilesRef, xmpRef, xmpPacket, xmpPacketLen, packetInfo, &wResult )
+
+#define zXMPFiles_GetThumbnail_1(tnailInfo) \
+ WXMPFiles_GetThumbnail_1 ( this->xmpFilesRef, tnailInfo, &wResult )
+
+#define zXMPFiles_PutXMP_1(xmpRef,xmpPacket,xmpPacketLen) \
+ WXMPFiles_PutXMP_1 ( this->xmpFilesRef, xmpRef, xmpPacket, xmpPacketLen, &wResult )
+
+#define zXMPFiles_CanPutXMP_1(xmpRef,xmpPacket,xmpPacketLen) \
+ WXMPFiles_CanPutXMP_1 ( this->xmpFilesRef, xmpRef, xmpPacket, xmpPacketLen, &wResult )
+
+// =================================================================================================
+
+extern void WXMPFiles_GetVersionInfo_1 ( XMP_VersionInfo * versionInfo );
+
+extern void WXMPFiles_Initialize_1 ( WXMP_Result * result );
+
+extern void WXMPFiles_Initialize_2 ( XMP_OptionBits options, WXMP_Result * result );
+
+extern void WXMPFiles_Terminate_1();
+
+extern void WXMPFiles_CTor_1 ( WXMP_Result * result );
+
+extern void WXMPFiles_UnlockLib_1();
+
+extern void WXMPFiles_UnlockObj_1 ( XMPFilesRef xmpFilesRef );
+
+extern void WXMPFiles_IncrementRefCount_1 ( XMPFilesRef xmpFilesRef );
+
+extern void WXMPFiles_DecrementRefCount_1 ( XMPFilesRef xmpFilesRef );
+
+extern void WXMPFiles_GetFormatInfo_1 ( XMP_FileFormat format,
+ XMP_OptionBits * flags, // ! Can be null.
+ WXMP_Result * result );
+
+extern void WXMPFiles_OpenFile_1 ( XMPFilesRef xmpFilesRef,
+ XMP_StringPtr filePath,
+ XMP_FileFormat format,
+ XMP_OptionBits openFlags,
+ WXMP_Result * result );
+
+extern void WXMPFiles_CloseFile_1 ( XMPFilesRef xmpFilesRef,
+ XMP_OptionBits closeFlags,
+ WXMP_Result * result );
+
+extern void WXMPFiles_GetFileInfo_1 ( XMPFilesRef xmpFilesRef,
+ XMP_StringPtr * filePath,
+ XMP_StringLen * filePathLen,
+ XMP_OptionBits * openFlags, // ! Can be null.
+ XMP_FileFormat * format, // ! Can be null.
+ XMP_OptionBits * handlerFlags, // ! Can be null.
+ WXMP_Result * result );
+
+extern void WXMPFiles_SetAbortProc_1 ( XMPFilesRef xmpFilesRef,
+ XMP_AbortProc abortProc,
+ void * abortArg,
+ WXMP_Result * result );
+
+extern void WXMPFiles_GetXMP_1 ( XMPFilesRef xmpFilesRef,
+ XMPMetaRef xmpRef, // ! Can be null.
+ XMP_StringPtr * xmpPacket,
+ XMP_StringLen * xmpPacketLen,
+ XMP_PacketInfo * packetInfo, // ! Can be null.
+ WXMP_Result * result );
+
+extern void WXMPFiles_GetThumbnail_1 ( XMPFilesRef xmpFilesRef,
+ XMP_ThumbnailInfo * tnailInfo, // ! Can be null.
+ WXMP_Result * result );
+
+extern void WXMPFiles_PutXMP_1 ( XMPFilesRef xmpFilesRef,
+ XMPMetaRef xmpRef, // ! Only one of the XMP object or packet are passed.
+ XMP_StringPtr xmpPacket,
+ XMP_StringLen xmpPacketLen,
+ WXMP_Result * result );
+
+extern void WXMPFiles_CanPutXMP_1 ( XMPFilesRef xmpFilesRef,
+ XMPMetaRef xmpRef, // ! Only one of the XMP object or packet are passed.
+ XMP_StringPtr xmpPacket,
+ XMP_StringLen xmpPacketLen,
+ WXMP_Result * result );
+
+// =================================================================================================
+
+#if __cplusplus
+}
+#endif
+
+#endif // __WXMPFiles_hpp__
diff --git a/public/include/client-glue/WXMPIterator.hpp b/public/include/client-glue/WXMPIterator.hpp
new file mode 100644
index 0000000..c5e9e26
--- /dev/null
+++ b/public/include/client-glue/WXMPIterator.hpp
@@ -0,0 +1,83 @@
+#if ! __WXMPIterator_hpp__
+#define __WXMPIterator_hpp__ 1
+
+// =================================================================================================
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "client-glue/WXMP_Common.hpp"
+
+#if __cplusplus
+extern "C" {
+#endif
+
+// =================================================================================================
+
+#define zXMPIterator_PropCTor_1(xmpRef,schemaNS,propName,options) \
+ WXMPIterator_PropCTor_1 ( xmpRef, schemaNS, propName, options, &wResult );
+
+#define zXMPIterator_TableCTor_1(schemaNS,propName,options) \
+ WXMPIterator_TableCTor_1 ( schemaNS, propName, options, &wResult );
+
+
+#define zXMPIterator_Next_1(schemaNS,nsSize,propPath,pathSize,propValue,valueSize,options) \
+ WXMPIterator_Next_1 ( this->iterRef, schemaNS, nsSize, propPath, pathSize, propValue, valueSize, options, &wResult );
+
+#define zXMPIterator_Skip_1(options) \
+ WXMPIterator_Skip_1 ( this->iterRef, options, &wResult );
+
+// -------------------------------------------------------------------------------------------------
+
+extern void
+WXMPIterator_PropCTor_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_OptionBits options,
+ WXMP_Result * wResult );
+
+extern void
+WXMPIterator_TableCTor_1 ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_OptionBits options,
+ WXMP_Result * wResult );
+
+extern void
+WXMPIterator_IncrementRefCount_1 ( XMPIteratorRef iterRef );
+
+extern void
+WXMPIterator_DecrementRefCount_1 ( XMPIteratorRef iterRef );
+
+extern void
+WXMPIterator_Unlock_1 ( XMP_OptionBits options );
+
+extern void
+WXMPIterator_Next_1 ( XMPIteratorRef iterRef,
+ XMP_StringPtr * schemaNS,
+ XMP_StringLen * nsSize,
+ XMP_StringPtr * propPath,
+ XMP_StringLen * pathSize,
+ XMP_StringPtr * propValue,
+ XMP_StringLen * valueSize,
+ XMP_OptionBits * options,
+ WXMP_Result * wResult );
+
+extern void
+WXMPIterator_Skip_1 ( XMPIteratorRef iterRef,
+ XMP_OptionBits options,
+ WXMP_Result * wResult );
+
+extern void
+WXMPUtils_UnlockIter_1 ( XMPIteratorRef iterRef,
+ XMP_OptionBits options );
+
+// =================================================================================================
+
+#if __cplusplus
+} /* extern "C" */
+#endif
+
+#endif // __WXMPIterator_hpp__
diff --git a/public/include/client-glue/WXMPMeta.hpp b/public/include/client-glue/WXMPMeta.hpp
new file mode 100644
index 0000000..608da15
--- /dev/null
+++ b/public/include/client-glue/WXMPMeta.hpp
@@ -0,0 +1,610 @@
+#if ! __WXMPMeta_hpp__
+#define __WXMPMeta_hpp__ 1
+
+// =================================================================================================
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "client-glue/WXMP_Common.hpp"
+
+#if __cplusplus
+extern "C" {
+#endif
+
+// =================================================================================================
+#define zXMPMeta_GetVersionInfo_1(info) \
+ WXMPMeta_GetVersionInfo_1 ( info /* no wResult */ )
+
+#define zXMPMeta_Initialize_1() \
+ WXMPMeta_Initialize_1 ( &wResult )
+#define zXMPMeta_Terminate_1() \
+ WXMPMeta_Terminate_1 ( /* no wResult */ )
+
+#define zXMPMeta_CTor_1() \
+ WXMPMeta_CTor_1 ( &wResult )
+
+#define zXMPMeta_GetGlobalOptions_1() \
+ WXMPMeta_GetGlobalOptions_1 ( &wResult )
+
+#define zXMPMeta_SetGlobalOptions_1(options) \
+ WXMPMeta_SetGlobalOptions_1 ( options, &wResult )
+
+#define zXMPMeta_DumpNamespaces_1(outProc,refCon) \
+ WXMPMeta_DumpNamespaces_1 ( outProc, refCon, &wResult )
+
+#define zXMPMeta_DumpAliases_1(outProc,refCon) \
+ WXMPMeta_DumpAliases_1 ( outProc, refCon, &wResult )
+
+#define zXMPMeta_RegisterNamespace_1(namespaceURI,suggestedPrefix,registeredPrefix,prefixSize) \
+ WXMPMeta_RegisterNamespace_1 ( namespaceURI, suggestedPrefix, registeredPrefix, prefixSize, &wResult )
+
+#define zXMPMeta_GetNamespacePrefix_1(namespaceURI,namespacePrefix,prefixSize) \
+ WXMPMeta_GetNamespacePrefix_1 ( namespaceURI, namespacePrefix, prefixSize, &wResult )
+
+#define zXMPMeta_GetNamespaceURI_1(namespacePrefix,namespaceURI,uriSize) \
+ WXMPMeta_GetNamespaceURI_1 ( namespacePrefix, namespaceURI, uriSize, &wResult )
+
+#define zXMPMeta_DeleteNamespace_1(namespaceURI) \
+ WXMPMeta_DeleteNamespace_1 ( namespaceURI, &wResult )
+
+#define zXMPMeta_RegisterAlias_1(aliasNS,aliasProp,actualNS,actualProp,arrayForm) \
+ WXMPMeta_RegisterAlias_1 ( aliasNS, aliasProp, actualNS, actualProp, arrayForm, &wResult )
+
+#define zXMPMeta_ResolveAlias_1(aliasNS,aliasProp,actualNS,nsSize,actualProp,propSize,arrayForm) \
+ WXMPMeta_ResolveAlias_1 ( aliasNS, aliasProp, actualNS, nsSize, actualProp, propSize, arrayForm, &wResult )
+
+#define zXMPMeta_DeleteAlias_1(aliasNS,aliasProp) \
+ WXMPMeta_DeleteAlias_1 ( aliasNS, aliasProp, &wResult )
+
+#define zXMPMeta_RegisterStandardAliases_1(schemaNS) \
+ WXMPMeta_RegisterStandardAliases_1 ( schemaNS, &wResult )
+
+#define zXMPMeta_GetProperty_1(schemaNS,propName,propValue,valueSize,options) \
+ WXMPMeta_GetProperty_1 ( this->xmpRef, schemaNS, propName, propValue, valueSize, options, &wResult )
+
+#define zXMPMeta_GetArrayItem_1(schemaNS,arrayName,itemIndex,itemValue,valueSize,options) \
+ WXMPMeta_GetArrayItem_1 ( this->xmpRef, schemaNS, arrayName, itemIndex, itemValue, valueSize, options, &wResult )
+
+#define zXMPMeta_GetStructField_1(schemaNS,structName,fieldNS,fieldName,fieldValue,valueSize,options) \
+ WXMPMeta_GetStructField_1 ( this->xmpRef, schemaNS, structName, fieldNS, fieldName, fieldValue, valueSize, options, &wResult )
+
+#define zXMPMeta_GetQualifier_1(schemaNS,propName,qualNS,qualName,qualValue,valueSize,options) \
+ WXMPMeta_GetQualifier_1 ( this->xmpRef, schemaNS, propName, qualNS, qualName, qualValue, valueSize, options, &wResult )
+
+#define zXMPMeta_SetProperty_1(schemaNS,propName,propValue,options) \
+ WXMPMeta_SetProperty_1 ( this->xmpRef, schemaNS, propName, propValue, options, &wResult )
+
+#define zXMPMeta_SetArrayItem_1(schemaNS,arrayName,itemIndex,itemValue,options) \
+ WXMPMeta_SetArrayItem_1 ( this->xmpRef, schemaNS, arrayName, itemIndex, itemValue, options, &wResult )
+
+#define zXMPMeta_AppendArrayItem_1(schemaNS,arrayName,arrayOptions,itemValue,options) \
+ WXMPMeta_AppendArrayItem_1 ( this->xmpRef, schemaNS, arrayName, arrayOptions, itemValue, options, &wResult )
+
+#define zXMPMeta_SetStructField_1(schemaNS,structName,fieldNS,fieldName,fieldValue,options) \
+ WXMPMeta_SetStructField_1 ( this->xmpRef, schemaNS, structName, fieldNS, fieldName, fieldValue, options, &wResult )
+
+#define zXMPMeta_SetQualifier_1(schemaNS,propName,qualNS,qualName,qualValue,options) \
+ WXMPMeta_SetQualifier_1 ( this->xmpRef, schemaNS, propName, qualNS, qualName, qualValue, options, &wResult )
+
+#define zXMPMeta_DeleteProperty_1(schemaNS,propName) \
+ WXMPMeta_DeleteProperty_1 ( this->xmpRef, schemaNS, propName, &wResult )
+
+#define zXMPMeta_DeleteArrayItem_1(schemaNS,arrayName,itemIndex) \
+ WXMPMeta_DeleteArrayItem_1 ( this->xmpRef, schemaNS, arrayName, itemIndex, &wResult )
+
+#define zXMPMeta_DeleteStructField_1(schemaNS,structName,fieldNS,fieldName) \
+ WXMPMeta_DeleteStructField_1 ( this->xmpRef, schemaNS, structName, fieldNS, fieldName, &wResult )
+
+#define zXMPMeta_DeleteQualifier_1(schemaNS,propName,qualNS,qualName) \
+ WXMPMeta_DeleteQualifier_1 ( this->xmpRef, schemaNS, propName, qualNS, qualName, &wResult )
+
+#define zXMPMeta_DoesPropertyExist_1(schemaNS,propName) \
+ WXMPMeta_DoesPropertyExist_1 ( this->xmpRef, schemaNS, propName, &wResult )
+
+#define zXMPMeta_DoesArrayItemExist_1(schemaNS,arrayName,itemIndex) \
+ WXMPMeta_DoesArrayItemExist_1 ( this->xmpRef, schemaNS, arrayName, itemIndex, &wResult )
+
+#define zXMPMeta_DoesStructFieldExist_1(schemaNS,structName,fieldNS,fieldName) \
+ WXMPMeta_DoesStructFieldExist_1 ( this->xmpRef, schemaNS, structName, fieldNS, fieldName, &wResult )
+
+#define zXMPMeta_DoesQualifierExist_1(schemaNS,propName,qualNS,qualName) \
+ WXMPMeta_DoesQualifierExist_1 ( this->xmpRef, schemaNS, propName, qualNS, qualName, &wResult )
+
+#define zXMPMeta_GetLocalizedText_1(schemaNS,altTextName,genericLang,specificLang,actualLang,langSize,itemValue,valueSize,options) \
+ WXMPMeta_GetLocalizedText_1 ( this->xmpRef, schemaNS, altTextName, genericLang, specificLang, actualLang, langSize, itemValue, valueSize, options, &wResult )
+
+#define zXMPMeta_SetLocalizedText_1(schemaNS,altTextName,genericLang,specificLang,itemValue,options) \
+ WXMPMeta_SetLocalizedText_1 ( this->xmpRef, schemaNS, altTextName, genericLang, specificLang, itemValue, options, &wResult )
+
+#define zXMPMeta_GetProperty_Bool_1(schemaNS,propName,propValue,options) \
+ WXMPMeta_GetProperty_Bool_1 ( this->xmpRef, schemaNS, propName, propValue, options, &wResult )
+
+#define zXMPMeta_GetProperty_Int_1(schemaNS,propName,propValue,options) \
+ WXMPMeta_GetProperty_Int_1 ( this->xmpRef, schemaNS, propName, propValue, options, &wResult )
+
+#define zXMPMeta_GetProperty_Int64_1(schemaNS,propName,propValue,options) \
+ WXMPMeta_GetProperty_Int64_1 ( this->xmpRef, schemaNS, propName, propValue, options, &wResult )
+
+#define zXMPMeta_GetProperty_Float_1(schemaNS,propName,propValue,options) \
+ WXMPMeta_GetProperty_Float_1 ( this->xmpRef, schemaNS, propName, propValue, options, &wResult )
+
+#define zXMPMeta_GetProperty_Date_1(schemaNS,propName,propValue,options) \
+ WXMPMeta_GetProperty_Date_1 ( this->xmpRef, schemaNS, propName, propValue, options, &wResult )
+
+#define zXMPMeta_SetProperty_Bool_1(schemaNS,propName,propValue,options) \
+ WXMPMeta_SetProperty_Bool_1 ( this->xmpRef, schemaNS, propName, propValue, options, &wResult )
+
+#define zXMPMeta_SetProperty_Int_1(schemaNS,propName,propValue,options) \
+ WXMPMeta_SetProperty_Int_1 ( this->xmpRef, schemaNS, propName, propValue, options, &wResult )
+
+#define zXMPMeta_SetProperty_Int64_1(schemaNS,propName,propValue,options) \
+ WXMPMeta_SetProperty_Int64_1 ( this->xmpRef, schemaNS, propName, propValue, options, &wResult )
+
+#define zXMPMeta_SetProperty_Float_1(schemaNS,propName,propValue,options) \
+ WXMPMeta_SetProperty_Float_1 ( this->xmpRef, schemaNS, propName, propValue, options, &wResult )
+
+#define zXMPMeta_SetProperty_Date_1(schemaNS,propName,propValue,options) \
+ WXMPMeta_SetProperty_Date_1 ( this->xmpRef, schemaNS, propName, propValue, options, &wResult )
+
+#define zXMPMeta_GetObjectName_1(namePtr,nameLen) \
+ WXMPMeta_GetObjectName_1 ( this->xmpRef, namePtr, nameLen, &wResult )
+
+#define zXMPMeta_SetObjectName_1(name) \
+ WXMPMeta_SetObjectName_1 ( this->xmpRef, name, &wResult )
+
+#define zXMPMeta_GetObjectOptions_1() \
+ WXMPMeta_GetObjectOptions_1 ( this->xmpRef, &wResult )
+
+#define zXMPMeta_SetObjectOptions_1(options) \
+ WXMPMeta_SetObjectOptions_1 ( this->xmpRef, options, &wResult )
+
+#define zXMPMeta_Clone_1(options) \
+ WXMPMeta_Clone_1 ( this->xmpRef, options, &wResult )
+
+#define zXMPMeta_CountArrayItems_1(schemaNS,arrayName) \
+ WXMPMeta_CountArrayItems_1 ( this->xmpRef, schemaNS, arrayName, &wResult )
+
+#define zXMPMeta_DumpObject_1(outProc,refCon) \
+ WXMPMeta_DumpObject_1 ( this->xmpRef, outProc, refCon, &wResult )
+
+#define zXMPMeta_ParseFromBuffer_1(buffer,bufferSize,options) \
+ WXMPMeta_ParseFromBuffer_1 ( this->xmpRef, buffer, bufferSize, options, &wResult )
+
+#define zXMPMeta_SerializeToBuffer_1(pktString,pktSize,options,padding,newline,indent,baseIndent) \
+ WXMPMeta_SerializeToBuffer_1 ( this->xmpRef, pktString, pktSize, options, padding, newline, indent, baseIndent, &wResult )
+
+// =================================================================================================
+
+extern void
+WXMPMeta_GetVersionInfo_1 ( XMP_VersionInfo * info );
+
+extern void
+WXMPMeta_Initialize_1 ( WXMP_Result * wResult );
+extern void
+WXMPMeta_Terminate_1();
+
+extern void
+WXMPMeta_Unlock_1 ( XMP_OptionBits options );
+
+// -------------------------------------------------------------------------------------------------
+
+extern void
+WXMPMeta_CTor_1 ( WXMP_Result * wResult );
+
+extern void
+WXMPMeta_IncrementRefCount_1 ( XMPMetaRef xmpRef );
+
+extern void
+WXMPMeta_DecrementRefCount_1 ( XMPMetaRef xmpRef );
+
+// -------------------------------------------------------------------------------------------------
+
+extern void
+WXMPMeta_GetGlobalOptions_1 ( WXMP_Result * wResult );
+
+extern void
+WXMPMeta_SetGlobalOptions_1 ( XMP_OptionBits options,
+ WXMP_Result * wResult );
+
+// -------------------------------------------------------------------------------------------------
+
+extern void
+WXMPMeta_DumpNamespaces_1 ( XMP_TextOutputProc outProc,
+ void * refCon,
+ WXMP_Result * wResult );
+
+extern void
+WXMPMeta_DumpAliases_1 ( XMP_TextOutputProc outProc,
+ void * refCon,
+ WXMP_Result * wResult );
+
+// -------------------------------------------------------------------------------------------------
+
+extern void
+WXMPMeta_RegisterNamespace_1 ( XMP_StringPtr namespaceURI,
+ XMP_StringPtr suggestedPrefix,
+ XMP_StringPtr * registeredPrefix,
+ XMP_StringLen * prefixSize,
+ WXMP_Result * wResult );
+
+extern void
+WXMPMeta_GetNamespacePrefix_1 ( XMP_StringPtr namespaceURI,
+ XMP_StringPtr * namespacePrefix,
+ XMP_StringLen * prefixSize,
+ WXMP_Result * wResult );
+
+extern void
+WXMPMeta_GetNamespaceURI_1 ( XMP_StringPtr namespacePrefix,
+ XMP_StringPtr * namespaceURI,
+ XMP_StringLen * uriSize,
+ WXMP_Result * wResult );
+
+extern void
+WXMPMeta_DeleteNamespace_1 ( XMP_StringPtr namespaceURI,
+ WXMP_Result * wResult );
+
+// -------------------------------------------------------------------------------------------------
+
+extern void
+WXMPMeta_RegisterAlias_1 ( XMP_StringPtr aliasNS,
+ XMP_StringPtr aliasProp,
+ XMP_StringPtr actualNS,
+ XMP_StringPtr actualProp,
+ XMP_OptionBits arrayForm,
+ WXMP_Result * wResult );
+
+extern void
+WXMPMeta_ResolveAlias_1 ( XMP_StringPtr aliasNS,
+ XMP_StringPtr aliasProp,
+ XMP_StringPtr * actualNS,
+ XMP_StringLen * nsSize,
+ XMP_StringPtr * actualProp,
+ XMP_StringLen * propSize,
+ XMP_OptionBits * arrayForm,
+ WXMP_Result * wResult );
+
+extern void
+WXMPMeta_DeleteAlias_1 ( XMP_StringPtr aliasNS,
+ XMP_StringPtr aliasProp,
+ WXMP_Result * wResult );
+
+extern void
+WXMPMeta_RegisterStandardAliases_1 ( XMP_StringPtr schemaNS,
+ WXMP_Result * wResult );
+
+// -------------------------------------------------------------------------------------------------
+
+extern void
+WXMPMeta_UnlockObject_1 ( XMPMetaRef xmpRef,
+ XMP_OptionBits options );
+
+// -------------------------------------------------------------------------------------------------
+
+extern void
+WXMPMeta_GetProperty_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr * propValue,
+ XMP_StringLen * valueSize,
+ XMP_OptionBits * options,
+ WXMP_Result * wResult ) /* const */ ;
+
+extern void
+WXMPMeta_GetArrayItem_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex,
+ XMP_StringPtr * itemValue,
+ XMP_StringLen * valueSize,
+ XMP_OptionBits * options,
+ WXMP_Result * wResult ) /* const */ ;
+
+extern void
+WXMPMeta_GetStructField_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ XMP_StringPtr * fieldValue,
+ XMP_StringLen * valueSize,
+ XMP_OptionBits * options,
+ WXMP_Result * wResult ) /* const */ ;
+
+extern void
+WXMPMeta_GetQualifier_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName,
+ XMP_StringPtr * qualValue,
+ XMP_StringLen * valueSize,
+ XMP_OptionBits * options,
+ WXMP_Result * wResult ) /* const */ ;
+
+// -------------------------------------------------------------------------------------------------
+
+extern void
+WXMPMeta_SetProperty_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr propValue,
+ XMP_OptionBits options,
+ WXMP_Result * wResult );
+
+extern void
+WXMPMeta_SetArrayItem_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex,
+ XMP_StringPtr itemValue,
+ XMP_OptionBits options,
+ WXMP_Result * wResult );
+
+extern void
+WXMPMeta_AppendArrayItem_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_OptionBits arrayOptions,
+ XMP_StringPtr itemValue,
+ XMP_OptionBits options,
+ WXMP_Result * wResult );
+
+extern void
+WXMPMeta_SetStructField_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ XMP_StringPtr fieldValue,
+ XMP_OptionBits options,
+ WXMP_Result * wResult );
+
+extern void
+WXMPMeta_SetQualifier_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName,
+ XMP_StringPtr qualValue,
+ XMP_OptionBits options,
+ WXMP_Result * wResult );
+
+// -------------------------------------------------------------------------------------------------
+
+extern void
+WXMPMeta_DeleteProperty_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ WXMP_Result * wResult );
+
+extern void
+WXMPMeta_DeleteArrayItem_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex,
+ WXMP_Result * wResult );
+
+extern void
+WXMPMeta_DeleteStructField_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ WXMP_Result * wResult );
+
+extern void
+WXMPMeta_DeleteQualifier_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName,
+ WXMP_Result * wResult );
+
+// -------------------------------------------------------------------------------------------------
+
+extern void
+WXMPMeta_DoesPropertyExist_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ WXMP_Result * wResult ) /* const */ ;
+
+extern void
+WXMPMeta_DoesArrayItemExist_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex,
+ WXMP_Result * wResult ) /* const */ ;
+
+extern void
+WXMPMeta_DoesStructFieldExist_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ WXMP_Result * wResult ) /* const */ ;
+
+extern void
+WXMPMeta_DoesQualifierExist_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName,
+ WXMP_Result * wResult ) /* const */ ;
+
+// -------------------------------------------------------------------------------------------------
+
+extern void
+WXMPMeta_GetLocalizedText_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr altTextName,
+ XMP_StringPtr genericLang,
+ XMP_StringPtr specificLang,
+ XMP_StringPtr * actualLang,
+ XMP_StringLen * langSize,
+ XMP_StringPtr * itemValue,
+ XMP_StringLen * valueSize,
+ XMP_OptionBits * options,
+ WXMP_Result * wResult ) /* const */ ;
+
+extern void
+WXMPMeta_SetLocalizedText_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr altTextName,
+ XMP_StringPtr genericLang,
+ XMP_StringPtr specificLang,
+ XMP_StringPtr itemValue,
+ XMP_OptionBits options,
+ WXMP_Result * wResult );
+
+// -------------------------------------------------------------------------------------------------
+
+extern void
+WXMPMeta_GetProperty_Bool_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_Bool * propValue,
+ XMP_OptionBits * options,
+ WXMP_Result * wResult ) /* const */ ;
+
+extern void
+WXMPMeta_GetProperty_Int_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_Int32 * propValue,
+ XMP_OptionBits * options,
+ WXMP_Result * wResult ) /* const */ ;
+
+extern void
+WXMPMeta_GetProperty_Int64_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_Int64 * propValue,
+ XMP_OptionBits * options,
+ WXMP_Result * wResult ) /* const */ ;
+
+extern void
+WXMPMeta_GetProperty_Float_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ double * propValue,
+ XMP_OptionBits * options,
+ WXMP_Result * wResult ) /* const */ ;
+
+extern void
+WXMPMeta_GetProperty_Date_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_DateTime * propValue,
+ XMP_OptionBits * options,
+ WXMP_Result * wResult ) /* const */ ;
+
+extern void
+WXMPMeta_SetProperty_Bool_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_Bool propValue,
+ XMP_OptionBits options,
+ WXMP_Result * wResult );
+
+extern void
+WXMPMeta_SetProperty_Int_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_Int32 propValue,
+ XMP_OptionBits options,
+ WXMP_Result * wResult );
+
+extern void
+WXMPMeta_SetProperty_Int64_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_Int64 propValue,
+ XMP_OptionBits options,
+ WXMP_Result * wResult );
+
+extern void
+WXMPMeta_SetProperty_Float_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ double propValue,
+ XMP_OptionBits options,
+ WXMP_Result * wResult );
+
+extern void
+WXMPMeta_SetProperty_Date_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ const XMP_DateTime & propValue,
+ XMP_OptionBits options,
+ WXMP_Result * wResult );
+
+// -------------------------------------------------------------------------------------------------
+
+extern void
+WXMPMeta_GetObjectName_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr * namePtr,
+ XMP_StringLen * nameLen,
+ WXMP_Result * wResult ) /* const */ ;
+
+extern void
+WXMPMeta_SetObjectName_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr name,
+ WXMP_Result * wResult );
+
+extern void
+WXMPMeta_GetObjectOptions_1 ( XMPMetaRef xmpRef,
+ WXMP_Result * wResult ) /* const */ ;
+
+extern void
+WXMPMeta_SetObjectOptions_1 ( XMPMetaRef xmpRef,
+ XMP_OptionBits options,
+ WXMP_Result * wResult );
+
+extern void
+WXMPMeta_Clone_1 ( XMPMetaRef xmpRef,
+ XMP_OptionBits options,
+ WXMP_Result * wResult ) /* const */ ;
+
+extern void
+WXMPMeta_CountArrayItems_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ WXMP_Result * wResult ) /* const */ ;
+
+extern void
+WXMPMeta_DumpObject_1 ( XMPMetaRef xmpRef,
+ XMP_TextOutputProc outProc,
+ void * refCon,
+ WXMP_Result * wResult ) /* const */ ;
+
+// -------------------------------------------------------------------------------------------------
+
+extern void
+WXMPMeta_ParseFromBuffer_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr buffer,
+ XMP_StringLen bufferSize,
+ XMP_OptionBits options,
+ WXMP_Result * wResult );
+
+extern void
+WXMPMeta_SerializeToBuffer_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr * pktString,
+ XMP_StringLen * pktSize,
+ XMP_OptionBits options,
+ XMP_StringLen padding,
+ XMP_StringPtr newline,
+ XMP_StringPtr indent,
+ XMP_Index baseIndent,
+ WXMP_Result * wResult ) /* const */ ;
+
+// =================================================================================================
+
+#if __cplusplus
+} /* extern "C" */
+#endif
+
+#endif // __WXMPMeta_hpp__
diff --git a/public/include/client-glue/WXMPUtils.hpp b/public/include/client-glue/WXMPUtils.hpp
new file mode 100644
index 0000000..fa82f7d
--- /dev/null
+++ b/public/include/client-glue/WXMPUtils.hpp
@@ -0,0 +1,322 @@
+#if ! __WXMPUtils_hpp__
+#define __WXMPUtils_hpp__ 1
+
+// =================================================================================================
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "client-glue/WXMP_Common.hpp"
+
+#if __cplusplus
+extern "C" {
+#endif
+
+// =================================================================================================
+
+#define zXMPUtils_ComposeArrayItemPath_1(schemaNS,arrayName,itemIndex,fullPath,pathSize) \
+ WXMPUtils_ComposeArrayItemPath_1 ( schemaNS, arrayName, itemIndex, fullPath, pathSize, &wResult );
+
+#define zXMPUtils_ComposeStructFieldPath_1(schemaNS,structName,fieldNS,fieldName,fullPath,pathSize) \
+ WXMPUtils_ComposeStructFieldPath_1 ( schemaNS, structName, fieldNS, fieldName, fullPath, pathSize, &wResult );
+
+#define zXMPUtils_ComposeQualifierPath_1(schemaNS,propName,qualNS,qualName,fullPath,pathSize) \
+ WXMPUtils_ComposeQualifierPath_1 ( schemaNS, propName, qualNS, qualName, fullPath, pathSize, &wResult );
+
+#define zXMPUtils_ComposeLangSelector_1(schemaNS,arrayName,langName,fullPath,pathSize) \
+ WXMPUtils_ComposeLangSelector_1 ( schemaNS, arrayName, langName, fullPath, pathSize, &wResult );
+
+#define zXMPUtils_ComposeFieldSelector_1(schemaNS,arrayName,fieldNS,fieldName,fieldValue,fullPath,pathSize) \
+ WXMPUtils_ComposeFieldSelector_1 ( schemaNS, arrayName, fieldNS, fieldName, fieldValue, fullPath, pathSize, &wResult );
+
+#define zXMPUtils_ConvertFromBool_1(binValue,strValue,strSize) \
+ WXMPUtils_ConvertFromBool_1 ( binValue, strValue, strSize, &wResult );
+
+#define zXMPUtils_ConvertFromInt_1(binValue,format,strValue,strSize) \
+ WXMPUtils_ConvertFromInt_1 ( binValue, format, strValue, strSize, &wResult );
+
+#define zXMPUtils_ConvertFromInt64_1(binValue,format,strValue,strSize) \
+ WXMPUtils_ConvertFromInt64_1 ( binValue, format, strValue, strSize, &wResult );
+
+#define zXMPUtils_ConvertFromFloat_1(binValue,format,strValue,strSize) \
+ WXMPUtils_ConvertFromFloat_1 ( binValue, format, strValue, strSize, &wResult );
+
+#define zXMPUtils_ConvertFromDate_1(binValue,strValue,strSize) \
+ WXMPUtils_ConvertFromDate_1 ( binValue, strValue, strSize, &wResult );
+
+#define zXMPUtils_ConvertToBool_1(strValue) \
+ WXMPUtils_ConvertToBool_1 ( strValue, &wResult );
+
+#define zXMPUtils_ConvertToInt_1(strValue) \
+ WXMPUtils_ConvertToInt_1 ( strValue, &wResult );
+
+#define zXMPUtils_ConvertToInt64_1(strValue) \
+ WXMPUtils_ConvertToInt64_1 ( strValue, &wResult );
+
+#define zXMPUtils_ConvertToFloat_1(strValue) \
+ WXMPUtils_ConvertToFloat_1 ( strValue, &wResult );
+
+#define zXMPUtils_ConvertToDate_1(strValue,binValue) \
+ WXMPUtils_ConvertToDate_1 ( strValue, binValue, &wResult );
+
+#define zXMPUtils_CurrentDateTime_1(time) \
+ WXMPUtils_CurrentDateTime_1 ( time, &wResult );
+
+#define zXMPUtils_SetTimeZone_1(time) \
+ WXMPUtils_SetTimeZone_1 ( time, &wResult );
+
+#define zXMPUtils_ConvertToUTCTime_1(time) \
+ WXMPUtils_ConvertToUTCTime_1 ( time, &wResult );
+
+#define zXMPUtils_ConvertToLocalTime_1(time) \
+ WXMPUtils_ConvertToLocalTime_1 ( time, &wResult );
+
+#define zXMPUtils_CompareDateTime_1(left,right) \
+ WXMPUtils_CompareDateTime_1 ( left, right, &wResult );
+
+#define zXMPUtils_EncodeToBase64_1(rawStr,rawLen,encodedStr,encodedLen) \
+ WXMPUtils_EncodeToBase64_1 ( rawStr, rawLen, encodedStr, encodedLen, &wResult );
+
+#define zXMPUtils_DecodeFromBase64_1(encodedStr,encodedLen,rawStr,rawLen) \
+ WXMPUtils_DecodeFromBase64_1 ( encodedStr, encodedLen, rawStr, rawLen, &wResult );
+
+#define zXMPUtils_PackageForJPEG_1(xmpObj,stdStr,stdLen,extStr,extLen,digestStr,digestLen) \
+ WXMPUtils_PackageForJPEG_1 ( xmpObj, stdStr, stdLen, extStr, extLen, digestStr, digestLen, &wResult );
+
+#define zXMPUtils_MergeFromJPEG_1(fullXMP,extendedXMP) \
+ WXMPUtils_MergeFromJPEG_1 ( fullXMP, extendedXMP, &wResult );
+
+#define zXMPUtils_CatenateArrayItems_1(xmpObj,schemaNS,arrayName,separator,quotes,options,catedPtr,catedLen) \
+ WXMPUtils_CatenateArrayItems_1 ( xmpObj, schemaNS, arrayName, separator, quotes, options, catedPtr, catedLen, &wResult );
+
+#define zXMPUtils_SeparateArrayItems_1(xmpObj,schemaNS,arrayName,options,catedStr) \
+ WXMPUtils_SeparateArrayItems_1 ( xmpObj, schemaNS, arrayName, options, catedStr, &wResult );
+
+#define zXMPUtils_RemoveProperties_1(xmpObj,schemaNS,propName,options) \
+ WXMPUtils_RemoveProperties_1 ( xmpObj, schemaNS, propName, options, &wResult );
+
+#define zXMPUtils_AppendProperties_1(source,dest,options) \
+ WXMPUtils_AppendProperties_1 ( source, dest, options, &wResult );
+
+#define zXMPUtils_DuplicateSubtree_1(source,dest,sourceNS,sourceRoot,destNS,destRoot,options) \
+ WXMPUtils_DuplicateSubtree_1 ( source, dest, sourceNS, sourceRoot, destNS, destRoot, options, &wResult );
+
+// =================================================================================================
+
+extern void
+WXMPUtils_Unlock_1 ( XMP_OptionBits options );
+
+// -------------------------------------------------------------------------------------------------
+
+extern void
+WXMPUtils_ComposeArrayItemPath_1 ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex,
+ XMP_StringPtr * fullPath,
+ XMP_StringLen * pathSize,
+ WXMP_Result * wResult );
+
+extern void
+WXMPUtils_ComposeStructFieldPath_1 ( XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ XMP_StringPtr * fullPath,
+ XMP_StringLen * pathSize,
+ WXMP_Result * wResult );
+
+extern void
+WXMPUtils_ComposeQualifierPath_1 ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName,
+ XMP_StringPtr * fullPath,
+ XMP_StringLen * pathSize,
+ WXMP_Result * wResult );
+
+extern void
+WXMPUtils_ComposeLangSelector_1 ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_StringPtr langName,
+ XMP_StringPtr * fullPath,
+ XMP_StringLen * pathSize,
+ WXMP_Result * wResult );
+
+extern void
+WXMPUtils_ComposeFieldSelector_1 ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ XMP_StringPtr fieldValue,
+ XMP_StringPtr * fullPath,
+ XMP_StringLen * pathSize,
+ WXMP_Result * wResult );
+
+// -------------------------------------------------------------------------------------------------
+
+extern void
+WXMPUtils_ConvertFromBool_1 ( XMP_Bool binValue,
+ XMP_StringPtr * strValue,
+ XMP_StringLen * strSize,
+ WXMP_Result * wResult );
+
+extern void
+WXMPUtils_ConvertFromInt_1 ( XMP_Int32 binValue,
+ XMP_StringPtr format,
+ XMP_StringPtr * strValue,
+ XMP_StringLen * strSize,
+ WXMP_Result * wResult );
+
+extern void
+WXMPUtils_ConvertFromInt64_1 ( XMP_Int64 binValue,
+ XMP_StringPtr format,
+ XMP_StringPtr * strValue,
+ XMP_StringLen * strSize,
+ WXMP_Result * wResult );
+
+extern void
+WXMPUtils_ConvertFromFloat_1 ( double binValue,
+ XMP_StringPtr format,
+ XMP_StringPtr * strValue,
+ XMP_StringLen * strSize,
+ WXMP_Result * wResult );
+
+extern void
+WXMPUtils_ConvertFromDate_1 ( const XMP_DateTime & binValue,
+ XMP_StringPtr * strValue,
+ XMP_StringLen * strSize,
+ WXMP_Result * wResult );
+
+// -------------------------------------------------------------------------------------------------
+
+extern void
+WXMPUtils_ConvertToBool_1 ( XMP_StringPtr strValue,
+ WXMP_Result * wResult );
+
+extern void
+WXMPUtils_ConvertToInt_1 ( XMP_StringPtr strValue,
+ WXMP_Result * wResult );
+
+extern void
+WXMPUtils_ConvertToInt64_1 ( XMP_StringPtr strValue,
+ WXMP_Result * wResult );
+
+extern void
+WXMPUtils_ConvertToFloat_1 ( XMP_StringPtr strValue,
+ WXMP_Result * wResult );
+
+extern void
+WXMPUtils_ConvertToDate_1 ( XMP_StringPtr strValue,
+ XMP_DateTime * binValue,
+ WXMP_Result * wResult );
+
+// -------------------------------------------------------------------------------------------------
+
+extern void
+WXMPUtils_CurrentDateTime_1 ( XMP_DateTime * time,
+ WXMP_Result * wResult );
+
+extern void
+WXMPUtils_SetTimeZone_1 ( XMP_DateTime * time,
+ WXMP_Result * wResult );
+
+extern void
+WXMPUtils_ConvertToUTCTime_1 ( XMP_DateTime * time,
+ WXMP_Result * wResult );
+
+extern void
+WXMPUtils_ConvertToLocalTime_1 ( XMP_DateTime * time,
+ WXMP_Result * wResult );
+
+extern void
+WXMPUtils_CompareDateTime_1 ( const XMP_DateTime & left,
+ const XMP_DateTime & right,
+ WXMP_Result * wResult );
+
+// -------------------------------------------------------------------------------------------------
+
+extern void
+WXMPUtils_EncodeToBase64_1 ( XMP_StringPtr rawStr,
+ XMP_StringLen rawLen,
+ XMP_StringPtr * encodedStr,
+ XMP_StringLen * encodedLen,
+ WXMP_Result * wResult );
+
+extern void
+WXMPUtils_DecodeFromBase64_1 ( XMP_StringPtr encodedStr,
+ XMP_StringLen encodedLen,
+ XMP_StringPtr * rawStr,
+ XMP_StringLen * rawLen,
+ WXMP_Result * wResult );
+
+// -------------------------------------------------------------------------------------------------
+
+extern void
+WXMPUtils_PackageForJPEG_1 ( XMPMetaRef xmpObj,
+ XMP_StringPtr * stdStr,
+ XMP_StringLen * stdLen,
+ XMP_StringPtr * extStr,
+ XMP_StringLen * extLen,
+ XMP_StringPtr * digestStr,
+ XMP_StringLen * digestLen,
+ WXMP_Result * wResult );
+
+extern void
+WXMPUtils_MergeFromJPEG_1 ( XMPMetaRef fullXMP,
+ XMPMetaRef extendedXMP,
+ WXMP_Result * wResult );
+
+// -------------------------------------------------------------------------------------------------
+
+extern void
+WXMPUtils_CatenateArrayItems_1 ( XMPMetaRef xmpObj,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_StringPtr separator,
+ XMP_StringPtr quotes,
+ XMP_OptionBits options,
+ XMP_StringPtr * catedStr,
+ XMP_StringLen * catedLen,
+ WXMP_Result * wResult );
+
+extern void
+WXMPUtils_SeparateArrayItems_1 ( XMPMetaRef xmpObj,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_OptionBits options,
+ XMP_StringPtr catedStr,
+ WXMP_Result * wResult );
+
+extern void
+WXMPUtils_RemoveProperties_1 ( XMPMetaRef xmpObj,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_OptionBits options,
+ WXMP_Result * wResult );
+
+extern void
+WXMPUtils_AppendProperties_1 ( XMPMetaRef source,
+ XMPMetaRef dest,
+ XMP_OptionBits options,
+ WXMP_Result * wResult );
+
+extern void
+WXMPUtils_DuplicateSubtree_1 ( XMPMetaRef source,
+ XMPMetaRef dest,
+ XMP_StringPtr sourceNS,
+ XMP_StringPtr sourceRoot,
+ XMP_StringPtr destNS,
+ XMP_StringPtr destRoot,
+ XMP_OptionBits options,
+ WXMP_Result * wResult );
+
+// =================================================================================================
+
+#if __cplusplus
+} /* extern "C" */
+#endif
+
+#endif // __WXMPUtils_hpp__
diff --git a/public/include/client-glue/WXMP_Common.hpp b/public/include/client-glue/WXMP_Common.hpp
new file mode 100644
index 0000000..b21e67e
--- /dev/null
+++ b/public/include/client-glue/WXMP_Common.hpp
@@ -0,0 +1,110 @@
+#if ! __WXMP_Common_hpp__
+#define __WXMP_Common_hpp__ 1
+
+// =================================================================================================
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#ifndef XMP_Inline
+ #if TXMP_EXPAND_INLINE
+ #define XMP_Inline inline
+ #else
+ #define XMP_Inline /* not inline */
+ #endif
+#endif
+
+#define XMP_CTorDTorIntro(Class) template <class tStringObj> XMP_Inline Class<tStringObj>
+#define XMP_MethodIntro(Class,ResultType) template <class tStringObj> XMP_Inline ResultType Class<tStringObj>
+
+struct WXMP_Result {
+ XMP_StringPtr errMessage;
+ void * ptrResult;
+ double floatResult;
+ XMP_Uns64 int64Result;
+ XMP_Uns32 int32Result;
+ WXMP_Result() : errMessage(0) {};
+};
+
+#if __cplusplus
+extern "C" {
+#endif
+
+#ifndef TraceXMPCalls
+ #define TraceXMPCalls 0
+#endif
+
+ #define PropagateException(res) \
+ if ( res.errMessage != 0 ) throw XMP_Error ( res.int32Result, res.errMessage );
+#if ! TraceXMPCalls
+ #define InvokeCheck(WCallProto) \
+ WXMP_Result wResult; \
+ WCallProto; \
+ PropagateException ( wResult )
+#else
+ #define InvokeCheck(WCallProto) \
+ WXMP_Result wResult; \
+ fprintf ( stderr, "WXMP calling: %s\n", #WCallProto ); fflush ( stderr ); \
+ WCallProto; \
+ if ( wResult.errMessage == 0 ) { \
+ fprintf ( stderr, "WXMP back, no error\n" ); fflush ( stderr ); \
+ } else { \
+ fprintf ( stderr, "WXMP back, error: %s\n", wResult.errMessage ); fflush ( stderr ); \
+ } \
+ PropagateException ( wResult )
+#endif
+
+// -------------------------------------------------------------------------------------------------
+
+#define WrapNoCheckVoid(WCallProto) \
+ WCallProto;
+
+#define WrapCheckVoid(WCallProto) \
+ InvokeCheck(WCallProto)
+
+#define WrapCheckMetaRef(result,WCallProto) \
+ InvokeCheck(WCallProto); \
+ XMPMetaRef result = XMPMetaRef(wResult.ptrResult)
+
+#define WrapCheckIterRef(result,WCallProto) \
+ InvokeCheck(WCallProto); \
+ XMPIteratorRef result = XMPIteratorRef(wResult.ptrResult)
+
+#define WrapCheckBool(result,WCallProto) \
+ InvokeCheck(WCallProto); \
+ bool result = bool(wResult.int32Result)
+
+#define WrapCheckOptions(result,WCallProto) \
+ InvokeCheck(WCallProto); \
+ XMP_OptionBits result = XMP_OptionBits(wResult.int32Result)
+
+#define WrapCheckStatus(result,WCallProto) \
+ InvokeCheck(WCallProto); \
+ XMP_Status result = XMP_Status(wResult.int32Result)
+
+#define WrapCheckIndex(result,WCallProto) \
+ InvokeCheck(WCallProto); \
+ XMP_Index result = XMP_Index(wResult.int32Result)
+
+#define WrapCheckInt32(result,WCallProto) \
+ InvokeCheck(WCallProto); \
+ XMP_Int32 result = wResult.int32Result
+
+#define WrapCheckInt64(result,WCallProto) \
+ InvokeCheck(WCallProto); \
+ XMP_Int64 result = wResult.int64Result
+
+#define WrapCheckFloat(result,WCallProto) \
+ InvokeCheck(WCallProto); \
+ double result = wResult.floatResult
+
+// =================================================================================================
+
+#if __cplusplus
+} /* extern "C" */
+#endif
+
+#endif // __WXMP_Common_hpp__
diff --git a/samples/BlueSquares/BlueSquare.ai b/samples/BlueSquares/BlueSquare.ai
new file mode 100644
index 0000000..2391f02
--- /dev/null
+++ b/samples/BlueSquares/BlueSquare.ai
Binary files differ
diff --git a/samples/BlueSquares/BlueSquare.avi b/samples/BlueSquares/BlueSquare.avi
new file mode 100644
index 0000000..f29de6d
--- /dev/null
+++ b/samples/BlueSquares/BlueSquare.avi
Binary files differ
diff --git a/samples/BlueSquares/BlueSquare.eps b/samples/BlueSquares/BlueSquare.eps
new file mode 100644
index 0000000..ea4f79c
--- /dev/null
+++ b/samples/BlueSquares/BlueSquare.eps
@@ -0,0 +1,87 @@
+%!PS-Adobe-3.1 EPSF-3.0 %ADO_DSC_Encoding: MacOS Roman %%Title: BlueSquare.eps %%Creator: Adobe Illustrator(R) 12 %%AI8_CreatorVersion: 12.0.0 %AI9_PrintingDataBegin %%For: Alan Lillich %%CreationDate: 9/7/05 %%BoundingBox: 0 0 289 361 %%HiResBoundingBox: 0 0 288.9996 361 %%CropBox: 0 0 288.9996 361 %%LanguageLevel: 2 %%DocumentData: Clean7Bit %%Pages: 1 %%DocumentNeededResources: %%DocumentSuppliedResources: procset Adobe_AGM_Image 1.0 0 %%+ procset Adobe_CoolType_Utility_T42 1.0 0 %%+ procset Adobe_CoolType_Utility_MAKEOCF 1.19 0 %%+ procset Adobe_CoolType_Core 2.23 0 %%+ procset Adobe_AGM_Core 2.0 0 %%+ procset Adobe_AGM_Utils 1.0 0 %%DocumentFonts: %%DocumentNeededFonts: %%DocumentNeededFeatures: %%DocumentSuppliedFeatures: %%DocumentProcessColors: Cyan Magenta Black %%DocumentCustomColors: %%CMYKCustomColor: %%RGBCustomColor: %ADO_BuildNumber: Adobe Illustrator(R) 12.0.0 x5199 R agm 4.3861 ct 5.530 %ADO_ContainsXMP: MainFirst %AI7_Thumbnail: 104 128 8 %%BeginData: 29100 Hex Bytes %0000330000660000990000CC0033000033330033660033990033CC0033FF %0066000066330066660066990066CC0066FF009900009933009966009999 %0099CC0099FF00CC0000CC3300CC6600CC9900CCCC00CCFF00FF3300FF66 %00FF9900FFCC3300003300333300663300993300CC3300FF333300333333 %3333663333993333CC3333FF3366003366333366663366993366CC3366FF %3399003399333399663399993399CC3399FF33CC0033CC3333CC6633CC99 %33CCCC33CCFF33FF0033FF3333FF6633FF9933FFCC33FFFF660000660033 %6600666600996600CC6600FF6633006633336633666633996633CC6633FF %6666006666336666666666996666CC6666FF669900669933669966669999 %6699CC6699FF66CC0066CC3366CC6666CC9966CCCC66CCFF66FF0066FF33 %66FF6666FF9966FFCC66FFFF9900009900339900669900999900CC9900FF %9933009933339933669933999933CC9933FF996600996633996666996699 %9966CC9966FF9999009999339999669999999999CC9999FF99CC0099CC33 %99CC6699CC9999CCCC99CCFF99FF0099FF3399FF6699FF9999FFCC99FFFF %CC0000CC0033CC0066CC0099CC00CCCC00FFCC3300CC3333CC3366CC3399 %CC33CCCC33FFCC6600CC6633CC6666CC6699CC66CCCC66FFCC9900CC9933 %CC9966CC9999CC99CCCC99FFCCCC00CCCC33CCCC66CCCC99CCCCCCCCCCFF %CCFF00CCFF33CCFF66CCFF99CCFFCCCCFFFFFF0033FF0066FF0099FF00CC %FF3300FF3333FF3366FF3399FF33CCFF33FFFF6600FF6633FF6666FF6699 %FF66CCFF66FFFF9900FF9933FF9966FF9999FF99CCFF99FFFFCC00FFCC33 %FFCC66FFCC99FFCCCCFFCCFFFFFF33FFFF66FFFF99FFFFCC110000001100 %000011111111220000002200000022222222440000004400000044444444 %550000005500000055555555770000007700000077777777880000008800 %000088888888AA000000AA000000AAAAAAAABB000000BB000000BBBBBBBB %DD000000DD000000DDDDDDDDEE000000EE000000EEEEEEEE0000000000FF %00FF0000FFFFFF0000FF00FFFFFF00FFFFFF %522853285328532853285328532853285328532853285328532853285328 %532853285328532853285328532853285328532853285328532853285328 %532853285328532853285328532853285328532853285328532853285328 %5328532853285328532853287DFF28290629062906290629062906290629 %062906290629062906290629062906290629062906290629062906290629 %062906290629062906290629062906290629062906290629062906290629 %062906290629062906290629062906290629062906290629062953FF5307 %2F2929292F2929292F2929292F2929292F2929292F2929292F2929292F29 %29292F2929292F2929292F2929292F2929292F2929292F2929292F292929 %2F2929292F2929292F2929292F2929292F2929292F2929292F2929292F29 %29292F2929292F2929287DFF282906292929062929290629292906292929 %062929290629292906292929062929290629292906292929062929290629 %292906292929062929290629292906292929062929290629292906292929 %06292929062929290629292906292929062929290629062953FF53072F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F287EFF2829282929292829292928292929282929292829 %292928292929282929292829292928292929282929292829292928292929 %282929292829292928292929282929292829292928292929282929292829 %2929282929292829292928292929282929292829292953FF532929292F29 %29292F2929292F2929292F2929292F2929292F2929292F2929292F292929 %2F2929292F2929292F2929292F2929292F2929292F2929292F2929292F29 %29292F2929292F2929292F2929292F2929292F2929292F2929292F292929 %2F2929292F287DFF28292929062929290629292906292929062929290629 %292906292929062929290629292906292929062929290629292906292929 %062929290629292906292929062929290629292906292929062929290629 %292906292929062929290629292906292929062953FF53292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F297DFF282929292829292928292929282929292829292928292929 %282929292829292928292929282929292829292928292929282929292829 %292928292929282929292829292928292929282929292829292928292929 %28292929282929292829292928292929062959FF53072F2929292F292929 %2F2929292F2929292F2929292F2929292F2929292F2929292F2929292F29 %29292F2929292F2929292F2929292F2929292F2929292F2929292F292929 %2F2929292F2929292F2929292F2929292F2929292F2929292F2929292F29 %29287DFF2829062929290629292906292929062929290629292906292929 %062929290629292906292929062929290629292906292929062929290629 %292906292929062929290629292906292929062929290629292906292929 %0629292906292929062929290629062953FF53072F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F28 %7EFF28292829292928292929282929292829292928292929282929292829 %292928292929282929292829292928292929282929292829292928292929 %282929292829292928292929282929292829292928292929282929292829 %292928292929282929292829292953FF532929292F2929292F2929292F29 %29292F2929292F2929292F2929292F2929292F2929292F2929292F292929 %2F2929292F2929292F2929292F2929292F2929292F2929292F2929292F29 %29292F2929292F2929292F2929292F2929292F2929292F2929292F287DFF %282929290629292906292929062929290629292906292929062929290629 %292906292929062929290629292906292929062929290629292906292929 %062929290629292906292929062929290629292906292929062929290629 %29290629292906292929062953FF53292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F297DFF2829 %292928292929282929292829292928292929282929292829292928292929 %282929292829292928292929282929292829292928292929282929292829 %292928292929282929292829292928292929282929292829292928292929 %2829292928292929062959FF53072F2929292F2929292F2929292F292929 %2F2929292F2929292F2929292F2929292F2929292F2929292F2929292F29 %29292F2929292F2929292F2929292F2929292F2929292F2929292F292929 %2F2929292F2929292F2929292F2929292F2929292F2929287DFF28290629 %292906292929062929290629292906292929062929290629292906292929 %062929290629292906292929062929290629292906292929062929290629 %292906292929062929290629292906292929062929290629292906292929 %062929290629062953FF53072F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F287EFF282928292929 %282929292829292928292929282929292829292928292929282929292829 %292928292929282929292829292928292929282929292829292928292929 %282929292829292928292929282929292829292928292929282929292829 %29292829292953FF532929292F2929292F2929292F2929292F2929292F29 %29292F2929292F2929292F2929292F2929292F2929292F2929292F292929 %2F2929292F2929292F2929292F2929292F2929292F2929292F2929292F29 %29292F2929292F2929292F2929292F2929292F287DFF2829292906292929 %062929290629292906292929062929290629292906292929062929290629 %292906292929062929290629292906292929062929290629292906292929 %062929290629292906292929062929290629292906292929062929290629 %2929062953FF53292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F297DFF28292929282929292829 %292928292929282929292829292928292929282929292829292928292929 %282929292829292928292929282929292829292928292929282929292829 %292928292929282929292829292928292929282929292829292928292929 %062959FF53072F2929292F2929292F2929292F2929292F2929292F292929 %2F2929292F2929292F2929292F2929292F2929292F2929292F2929292F29 %29292F2929292F2929292F2929292F2929292F2929292F2929292F292929 %2F2929292F2929292F2929292F2929287DFF282906292929062929290629 %292906292929062929290629292906292929062929290629292906292929 %062929290629292906292929062929290629292906292929062929290629 %292906292929062929290629292906292929062929290629292906290629 %53FF53072F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F287EFF2829282929292829292928292929 %282929292829292928292929282929292829292928292929282929292829 %292928292929282929292829292928292929282929292829292928292929 %2829292928292929282929292829292928292929282929292829292953FF %532929292F2929292F2929292F2929292F2929292F2929292F2929292F29 %29292F2929292F2929292F2929292F2929292F2929292F2929292F292929 %2F2929292F2929292F2929292F2929292F2929292F2929292F2929292F29 %29292F2929292F2929292F287DFF28292929062929290629292906292929 %062929290629292906292929062929290629292906292929062929290629 %292906292929062929290629292906292929062929290629292906292929 %062929290629292906292929062929290629292906292929062953FF5329 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F297DFF282929292829292928292929282929292829 %292928292929282929292829292928292929282929292829292928292929 %282929292829292928292929282929292829292928292929282929292829 %29292829292928292929282929292829292928292929062959FF53072F29 %29292F2929292F2929292F2929292F2929292F2929292F2929292F292929 %2F2929292F2929292F2929292F2929292F2929292F2929292F2929292F29 %29292F2929292F2929292F2929292F2929292F2929292F2929292F292929 %2F2929292F2929287DFF2829062929290629292906292929062929290629 %292906292929062929290629292906292929062929290629292906292929 %062929290629292906292929062929290629292906292929062929290629 %2929062929290629292906292929062929290629062953FF53072F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F287EFF28292829292928292929282929292829292928292929 %282929292829292928292929282929292829292928292929282929292829 %292928292929282929292829292928292929282929292829292928292929 %282929292829292928292929282929292829292953FF532929292F292929 %2F2929292F2929292F2929292F2929292F2929292F2929292F2929292F29 %29292F2929292F2929292F2929292F2929292F2929292F2929292F292929 %2F2929292F2929292F2929292F2929292F2929292F2929292F2929292F29 %29292F287DFF282929290629292906292929062929290629292906292929 %062929290629292906292929062929290629292906292929062929290629 %292906292929062929290629292906292929062929290629292906292929 %06292929062929290629292906292929062953FF53292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F297DFF2829292928292929282929292829292928292929282929292829 %292928292929282929292829292928292929282929292829292928292929 %282929292829292928292929282929292829292928292929282929292829 %2929282929292829292928292929062959FF53072F2929292F2929292F29 %29292F2929292F2929292F2929292F2929292F2929292F2929292F292929 %2F2929292F2929292F2929292F2929292F2929292F2929292F2929292F29 %29292F2929292F2929292F2929292F2929292F2929292F2929292F292928 %7DFF28290629292906292929062929290629292906292929062929290629 %292906292929062929290629292906292929062929290629292906292929 %062929290629292906292929062929290629292906292929062929290629 %292906292929062929290629062953FF53072F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F287EFF %282928292929282929292829292928292929282929292829292928292929 %282929292829292928292929282929292829292928292929282929292829 %292928292929282929292829292928292929282929292829292928292929 %28292929282929292829292953FF532929292F2929292F2929292F292929 %2F2929292F2929292F2929292F2929292F2929292F2929292F2929292F29 %29292F2929292F2929292F2929292F2929292F2929292F2929292F292929 %2F2929292F2929292F2929292F2929292F2929292F2929292F287DFF2829 %292906292929062929290629292906292929062929290629292906292929 %062929290629292906292929062929290629292906292929062929290629 %292906292929062929290629292906292929062929290629292906292929 %0629292906292929062953FF53292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F297DFF28292929 %282929292829292928292929282929292829292928292929282929292829 %292928292929282929292829292928292929282929292829292928292929 %282929292829292928292929282929292829292928292929282929292829 %292928292929062959FF53072F2929292F2929292F2929292F2929292F29 %29292F2929292F2929292F2929292F2929292F2929292F2929292F292929 %2F2929292F2929292F2929292F2929292F2929292F2929292F2929292F29 %29292F2929292F2929292F2929292F2929292F2929287DFF282906292929 %062929290629292906292929062929290629292906292929062929290629 %292906292929062929290629292906292929062929290629292906292929 %062929290629292906292929062929290629292906292929062929290629 %29290629062953FF53072F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F287EFF2829282929292829 %292928292929282929292829292928292929282929292829292928292929 %282929292829292928292929282929292829292928292929282929292829 %292928292929282929292829292928292929282929292829292928292929 %2829292953FF532929292F2929292F2929292F2929292F2929292F292929 %2F2929292F2929292F2929292F2929292F2929292F2929292F2929292F29 %29292F2929292F2929292F2929292F2929292F2929292F2929292F292929 %2F2929292F2929292F2929292F2929292F287DFF28292929062929290629 %292906292929062929290629292906292929062929290629292906292929 %062929290629292906292929062929290629292906292929062929290629 %292906292929062929290629292906292929062929290629292906292929 %062953FF53292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F297DFF282929292829292928292929 %282929292829292928292929282929292829292928292929282929292829 %292928292929282929292829292928292929282929292829292928292929 %282929292829292928292929282929292829292928292929282929290629 %59FF53072F2929292F2929292F2929292F2929292F2929292F2929292F29 %29292F2929292F2929292F2929292F2929292F2929292F2929292F292929 %2F2929292F2929292F2929292F2929292F2929292F2929292F2929292F29 %29292F2929292F2929292F2929287DFF2829062929290629292906292929 %062929290629292906292929062929290629292906292929062929290629 %292906292929062929290629292906292929062929290629292906292929 %0629292906292929062929290629292906292929062929290629062953FF %53072F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F287EFF28292829292928292929282929292829 %292928292929282929292829292928292929282929292829292928292929 %282929292829292928292929282929292829292928292929282929292829 %292928292929282929292829292928292929282929292829292953FF5329 %29292F2929292F2929292F2929292F2929292F2929292F2929292F292929 %2F2929292F2929292F2929292F2929292F2929292F2929292F2929292F29 %29292F2929292F2929292F2929292F2929292F2929292F2929292F292929 %2F2929292F2929292F287DFF282929290629292906292929062929290629 %292906292929062929290629292906292929062929290629292906292929 %062929290629292906292929062929290629292906292929062929290629 %29290629292906292929062929290629292906292929062953FF53292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F297DFF2829292928292929282929292829292928292929 %282929292829292928292929282929292829292928292929282929292829 %292928292929282929292829292928292929282929292829292928292929 %2829292928292929282929292829292928292929062959FF53072F292929 %2F2929292F2929292F2929292F2929292F2929292F2929292F2929292F29 %29292F2929292F2929292F2929292F2929292F2929292F2929292F292929 %2F2929292F2929292F2929292F2929292F2929292F2929292F2929292F29 %29292F2929287DFF28290629292906292929062929290629292906292929 %062929290629292906292929062929290629292906292929062929290629 %292906292929062929290629292906292929062929290629292906292929 %062929290629292906292929062929290629062953FF53072F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F287EFF282928292929282929292829292928292929282929292829 %292928292929282929292829292928292929282929292829292928292929 %282929292829292928292929282929292829292928292929282929292829 %29292829292928292929282929292829292953FF532929292F2929292F29 %29292F2929292F2929292F2929292F2929292F2929292F2929292F292929 %2F2929292F2929292F2929292F2929292F2929292F2929292F2929292F29 %29292F2929292F2929292F2929292F2929292F2929292F2929292F292929 %2F287DFF2829292906292929062929290629292906292929062929290629 %292906292929062929290629292906292929062929290629292906292929 %062929290629292906292929062929290629292906292929062929290629 %2929062929290629292906292929062953FF53292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %7DFF28292929282929292829292928292929282929292829292928292929 %282929292829292928292929282929292829292928292929282929292829 %292928292929282929292829292928292929282929292829292928292929 %282929292829292928292929062959FF53072F2929292F2929292F292929 %2F2929292F2929292F2929292F2929292F2929292F2929292F2929292F29 %29292F2929292F2929292F2929292F2929292F2929292F2929292F292929 %2F2929292F2929292F2929292F2929292F2929292F2929292F2929287DFF %282906292929062929290629292906292929062929290629292906292929 %062929290629292906292929062929290629292906292929062929290629 %292906292929062929290629292906292929062929290629292906292929 %06292929062929290629062953FF53072F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F287EFF2829 %282929292829292928292929282929292829292928292929282929292829 %292928292929282929292829292928292929282929292829292928292929 %282929292829292928292929282929292829292928292929282929292829 %2929282929292829292953FF532929292F2929292F2929292F2929292F29 %29292F2929292F2929292F2929292F2929292F2929292F2929292F292929 %2F2929292F2929292F2929292F2929292F2929292F2929292F2929292F29 %29292F2929292F2929292F2929292F2929292F2929292F287DFF28292929 %062929290629292906292929062929290629292906292929062929290629 %292906292929062929290629292906292929062929290629292906292929 %062929290629292906292929062929290629292906292929062929290629 %292906292929062953FF53292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F297DFF282929292829 %292928292929282929292829292928292929282929292829292928292929 %282929292829292928292929282929292829292928292929282929292829 %292928292929282929292829292928292929282929292829292928292929 %28292929062959FF53072F2929292F2929292F2929292F2929292F292929 %2F2929292F2929292F2929292F2929292F2929292F2929292F2929292F29 %29292F2929292F2929292F2929292F2929292F2929292F2929292F292929 %2F2929292F2929292F2929292F2929292F2929287DFF2829062929290629 %292906292929062929290629292906292929062929290629292906292929 %062929290629292906292929062929290629292906292929062929290629 %292906292929062929290629292906292929062929290629292906292929 %0629062953FF53072F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F287EFF28292829292928292929 %282929292829292928292929282929292829292928292929282929292829 %292928292929282929292829292928292929282929292829292928292929 %282929292829292928292929282929292829292928292929282929292829 %292953FF532929292F2929292F2929292F2929292F2929292F2929292F29 %29292F2929292F2929292F2929292F2929292F2929292F2929292F292929 %2F2929292F2929292F2929292F2929292F2929292F2929292F2929292F29 %29292F2929292F2929292F2929292F287DFF282929290629292906292929 %062929290629292906292929062929290629292906292929062929290629 %292906292929062929290629292906292929062929290629292906292929 %062929290629292906292929062929290629292906292929062929290629 %53FF53292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F297DFF2829292928292929282929292829 %292928292929282929292829292928292929282929292829292928292929 %282929292829292928292929282929292829292928292929282929292829 %2929282929292829292928292929282929292829292928292929062959FF %53072F2929292F2929292F2929292F2929292F2929292F2929292F292929 %2F2929292F2929292F2929292F2929292F2929292F2929292F2929292F29 %29292F2929292F2929292F2929292F2929292F2929292F2929292F292929 %2F2929292F2929292F2929287DFF28290629292906292929062929290629 %292906292929062929290629292906292929062929290629292906292929 %062929290629292906292929062929290629292906292929062929290629 %292906292929062929290629292906292929062929290629062953FF5307 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F287EFF282928292929282929292829292928292929 %282929292829292928292929282929292829292928292929282929292829 %292928292929282929292829292928292929282929292829292928292929 %28292929282929292829292928292929282929292829292953FF53292929 %2F2929292F2929292F2929292F2929292F2929292F2929292F2929292F29 %29292F2929292F2929292F2929292F2929292F2929292F2929292F292929 %2F2929292F2929292F2929292F2929292F2929292F2929292F2929292F29 %29292F2929292F287DFF2829292906292929062929290629292906292929 %062929290629292906292929062929290629292906292929062929290629 %292906292929062929290629292906292929062929290629292906292929 %0629292906292929062929290629292906292929062953FF53292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F297DFF28292929282929292829292928292929282929292829 %292928292929282929292829292928292929282929292829292928292929 %282929292829292928292929282929292829292928292929282929292829 %292928292929282929292829292928292929062959FF53072F2929292F29 %29292F2929292F2929292F2929292F2929292F2929292F2929292F292929 %2F2929292F2929292F2929292F2929292F2929292F2929292F2929292F29 %29292F2929292F2929292F2929292F2929292F2929292F2929292F292929 %2F2929287DFF282906292929062929290629292906292929062929290629 %292906292929062929290629292906292929062929290629292906292929 %062929290629292906292929062929290629292906292929062929290629 %29290629292906292929062929290629062953FF53072F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F287EFF2829282929292829292928292929282929292829292928292929 %282929292829292928292929282929292829292928292929282929292829 %292928292929282929292829292928292929282929292829292928292929 %2829292928292929282929292829292953FF532929292F2929292F292929 %2F2929292F2929292F2929292F2929292F2929292F2929292F2929292F29 %29292F2929292F2929292F2929292F2929292F2929292F2929292F292929 %2F2929292F2929292F2929292F2929292F2929292F2929292F2929292F28 %7DFF28292929062929290629292906292929062929290629292906292929 %062929290629292906292929062929290629292906292929062929290629 %292906292929062929290629292906292929062929290629292906292929 %062929290629292906292929062953FF53292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F297DFF %282929292829292928292929282929292829292928292929282929292829 %292928292929282929292829292928292929282929292829292928292929 %282929292829292928292929282929292829292928292929282929292829 %29292829292928292929062959FF53072F2929292F2929292F2929292F29 %29292F2929292F2929292F2929292F2929292F2929292F2929292F292929 %2F2929292F2929292F2929292F2929292F2929292F2929292F2929292F29 %29292F2929292F2929292F2929292F2929292F2929292F2929287DFF2829 %062929290629292906292929062929290629292906292929062929290629 %292906292929062929290629292906292929062929290629292906292929 %062929290629292906292929062929290629292906292929062929290629 %2929062929290629062953FF53072F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F287EFF28292829 %292928292929282929292829292928292929282929292829292928292929 %282929292829292928292929282929292829292928292929282929292829 %292928292929282929292829292928292929282929292829292928292929 %282929292829292953FF532929292F2929292F2929292F2929292F292929 %2F2929292F2929292F2929292F2929292F2929292F2929292F2929292F29 %29292F2929292F2929292F2929292F2929292F2929292F2929292F292929 %2F2929292F2929292F2929292F2929292F2929292F287DFF282929290629 %292906292929062929290629292906292929062929290629292906292929 %062929290629292906292929062929290629292906292929062929290629 %292906292929062929290629292906292929062929290629292906292929 %06292929062953FF53292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F297DFF2829292928292929 %282929292829292928292929282929292829292928292929282929292829 %292928292929282929292829292928292929282929292829292928292929 %282929292829292928292929282929292829292928292929282929292829 %2929062959FF53072F2929292F2929292F2929292F2929292F2929292F29 %29292F2929292F2929292F2929292F2929292F2929292F2929292F292929 %2F2929292F2929292F2929292F2929292F2929292F2929292F2929292F29 %29292F2929292F2929292F2929292F2929287DFF28290629292906292929 %062929290629292906292929062929290629292906292929062929290629 %292906292929062929290629292906292929062929290629292906292929 %062929290629292906292929062929290629292906292929062929290629 %062953FF53072F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F287EFF282928292929282929292829 %292928292929282929292829292928292929282929292829292928292929 %282929292829292928292929282929292829292928292929282929292829 %292928292929282929292829292928292929282929292829292928292929 %53FF532929292F2929292F2929292F2929292F2929292F2929292F292929 %2F2929292F2929292F2929292F2929292F2929292F2929292F2929292F29 %29292F2929292F2929292F2929292F2929292F2929292F2929292F292929 %2F2929292F2929292F2929292F287DFF2829292906292929062929290629 %292906292929062929290629292906292929062929290629292906292929 %062929290629292906292929062929290629292906292929062929290629 %2929062929290629292906292929062929290629292906292929062953FF %53292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F297DFF28292929282929292829292928292929 %282929292829292928292929282929292829292928292929282929292829 %292928292929282929292829292928292929282929292829292928292929 %282929292829292928292929282929292829292928292929062959FF5307 %2F2929292F2929292F2929292F2929292F2929292F2929292F2929292F29 %29292F2929292F2929292F2929292F2929292F2929292F2929292F292929 %2F2929292F2929292F2929292F2929292F2929292F2929292F2929292F29 %29292F2929292F2929287DFF282906292929062929290629292906292929 %062929290629292906292929062929290629292906292929062929290629 %292906292929062929290629292906292929062929290629292906292929 %06292929062929290629292906292929062929290629062953FF53072F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F292F292F292F292F292F292F292F292F292F292F292F29 %2F292F292F292F287EFF2829282929292829292928292929282929292829 %292928292929282929292829292928292929282929292829292928292929 %282929292829292928292929282929292829292928292929282929292829 %2929282929292829292928292929282929292829292953FF530729072929 %290729292907292929072929290729292907292929072929290729292907 %292929072929290729292907292929072929290729292907292929072929 %290729292907292929072929290729292907292929072929290729292907 %2929290729297DFF27532828285228282852282828522828285228282852 %282828522828285228282852282828522828285228282852282828522828 %285228282852282828522828285228282852282828522828285228282852 %282828522828285228282852282828522828282853FF %%EndData %%EndComments %%BeginDefaults %%ViewingOrientation: 1 0 0 1 %%EndDefaults %%BeginProlog %%BeginResource: procset Adobe_AGM_Utils 1.0 0 %%Version: 1.0 0 %%Copyright: Copyright (C) 2000-2003 Adobe Systems, Inc. All Rights Reserved. systemdict /setpacking known { currentpacking true setpacking } if userdict /Adobe_AGM_Utils 70 dict dup begin put /bdf { bind def } bind def /nd{ null def }bdf /xdf { exch def }bdf /ldf { load def }bdf /ddf { put }bdf /xddf { 3 -1 roll put }bdf /xpt { exch put }bdf /ndf { exch dup where{ pop pop pop }{ xdf }ifelse }def /cdndf { exch dup currentdict exch known{ pop pop }{ exch def }ifelse }def /ps_level /languagelevel where{ pop systemdict /languagelevel get exec }{ 1 }ifelse def /level2 ps_level 2 ge def /level3 ps_level 3 ge def /ps_version {version cvr} stopped { -1 }if def /set_gvm { currentglobal exch setglobal }bdf /reset_gvm { setglobal }bdf /makereadonlyarray { /packedarray where{ pop packedarray }{ array astore readonly }ifelse }bdf /map_reserved_ink_name { dup type /stringtype eq{ dup /Red eq{ pop (_Red_) }{ dup /Green eq{ pop (_Green_) }{ dup /Blue eq{ pop (_Blue_) }{ dup () cvn eq{ pop (Process) }if }ifelse }ifelse }ifelse }if }bdf /AGMUTIL_GSTATE 22 dict def /get_gstate { AGMUTIL_GSTATE begin /AGMUTIL_GSTATE_clr_spc currentcolorspace def /AGMUTIL_GSTATE_clr_indx 0 def /AGMUTIL_GSTATE_clr_comps 12 array def mark currentcolor counttomark {AGMUTIL_GSTATE_clr_comps AGMUTIL_GSTATE_clr_indx 3 -1 roll put /AGMUTIL_GSTATE_clr_indx AGMUTIL_GSTATE_clr_indx 1 add def} repeat pop /AGMUTIL_GSTATE_fnt rootfont def /AGMUTIL_GSTATE_lw currentlinewidth def /AGMUTIL_GSTATE_lc currentlinecap def /AGMUTIL_GSTATE_lj currentlinejoin def /AGMUTIL_GSTATE_ml currentmiterlimit def currentdash /AGMUTIL_GSTATE_do xdf /AGMUTIL_GSTATE_da xdf /AGMUTIL_GSTATE_sa currentstrokeadjust def /AGMUTIL_GSTATE_clr_rnd currentcolorrendering def /AGMUTIL_GSTATE_op currentoverprint def /AGMUTIL_GSTATE_bg currentblackgeneration cvlit def /AGMUTIL_GSTATE_ucr currentundercolorremoval cvlit def currentcolortransfer cvlit /AGMUTIL_GSTATE_gy_xfer xdf cvlit /AGMUTIL_GSTATE_b_xfer xdf cvlit /AGMUTIL_GSTATE_g_xfer xdf cvlit /AGMUTIL_GSTATE_r_xfer xdf /AGMUTIL_GSTATE_ht currenthalftone def /AGMUTIL_GSTATE_flt currentflat def end }def /set_gstate { AGMUTIL_GSTATE begin AGMUTIL_GSTATE_clr_spc setcolorspace AGMUTIL_GSTATE_clr_indx {AGMUTIL_GSTATE_clr_comps AGMUTIL_GSTATE_clr_indx 1 sub get /AGMUTIL_GSTATE_clr_indx AGMUTIL_GSTATE_clr_indx 1 sub def} repeat setcolor AGMUTIL_GSTATE_fnt setfont AGMUTIL_GSTATE_lw setlinewidth AGMUTIL_GSTATE_lc setlinecap AGMUTIL_GSTATE_lj setlinejoin AGMUTIL_GSTATE_ml setmiterlimit AGMUTIL_GSTATE_da AGMUTIL_GSTATE_do setdash AGMUTIL_GSTATE_sa setstrokeadjust AGMUTIL_GSTATE_clr_rnd setcolorrendering AGMUTIL_GSTATE_op setoverprint AGMUTIL_GSTATE_bg cvx setblackgeneration AGMUTIL_GSTATE_ucr cvx setundercolorremoval AGMUTIL_GSTATE_r_xfer cvx AGMUTIL_GSTATE_g_xfer cvx AGMUTIL_GSTATE_b_xfer cvx AGMUTIL_GSTATE_gy_xfer cvx setcolortransfer AGMUTIL_GSTATE_ht /HalftoneType get dup 9 eq exch 100 eq or { currenthalftone /HalftoneType get AGMUTIL_GSTATE_ht /HalftoneType get ne { mark AGMUTIL_GSTATE_ht {sethalftone} stopped cleartomark } if }{ AGMUTIL_GSTATE_ht sethalftone } ifelse AGMUTIL_GSTATE_flt setflat end }def /get_gstate_and_matrix { AGMUTIL_GSTATE begin /AGMUTIL_GSTATE_ctm matrix currentmatrix def end get_gstate }def /set_gstate_and_matrix { set_gstate AGMUTIL_GSTATE begin AGMUTIL_GSTATE_ctm setmatrix end }def /AGMUTIL_str256 256 string def /AGMUTIL_src256 256 string def /AGMUTIL_dst64 64 string def /AGMUTIL_srcLen nd /AGMUTIL_ndx nd /thold_halftone { level3 {sethalftone currenthalftone} { dup /HalftoneType get 3 eq { sethalftone currenthalftone } { begin Width Height mul { Thresholds read {pop} if } repeat end currenthalftone } ifelse }ifelse } def /rdcmntline { currentfile AGMUTIL_str256 readline pop (%) anchorsearch {pop} if } bdf /filter_cmyk { dup type /filetype ne{ exch () /SubFileDecode filter } { exch pop } ifelse [ exch { AGMUTIL_src256 readstring pop dup length /AGMUTIL_srcLen exch def /AGMUTIL_ndx 0 def AGMCORE_plate_ndx 4 AGMUTIL_srcLen 1 sub{ 1 index exch get AGMUTIL_dst64 AGMUTIL_ndx 3 -1 roll put /AGMUTIL_ndx AGMUTIL_ndx 1 add def }for pop AGMUTIL_dst64 0 AGMUTIL_ndx getinterval } bind /exec cvx ] cvx } bdf /filter_indexed_devn { cvi Names length mul names_index add Lookup exch get } bdf /filter_devn { 4 dict begin /srcStr xdf /dstStr xdf dup type /filetype ne{ 0 () /SubFileDecode filter }if [ exch [ /devicen_colorspace_dict /AGMCORE_gget cvx /begin cvx currentdict /srcStr get /readstring cvx /pop cvx /dup cvx /length cvx 0 /gt cvx [ Adobe_AGM_Utils /AGMUTIL_ndx 0 /ddf cvx names_index Names length currentdict /srcStr get length 1 sub { 1 /index cvx /exch cvx /get cvx currentdict /dstStr get /AGMUTIL_ndx /load cvx 3 -1 /roll cvx /put cvx Adobe_AGM_Utils /AGMUTIL_ndx /AGMUTIL_ndx /load cvx 1 /add cvx /ddf cvx } for currentdict /dstStr get 0 /AGMUTIL_ndx /load cvx /getinterval cvx ] cvx /if cvx /end cvx ] cvx bind /exec cvx ] cvx end } bdf /AGMUTIL_imagefile nd /read_image_file { AGMUTIL_imagefile 0 setfileposition 10 dict begin /imageDict xdf /imbufLen Width BitsPerComponent mul 7 add 8 idiv def /imbufIdx 0 def /origDataSource imageDict /DataSource get def /origMultipleDataSources imageDict /MultipleDataSources get def /origDecode imageDict /Decode get def /dstDataStr imageDict /Width get colorSpaceElemCnt mul string def imageDict /MultipleDataSources known {MultipleDataSources}{false} ifelse { /imbufCnt imageDict /DataSource get length def /imbufs imbufCnt array def 0 1 imbufCnt 1 sub { /imbufIdx xdf imbufs imbufIdx imbufLen string put imageDict /DataSource get imbufIdx [ AGMUTIL_imagefile imbufs imbufIdx get /readstring cvx /pop cvx ] cvx put } for DeviceN_PS2 { imageDict begin /DataSource [ DataSource /devn_sep_datasource cvx ] cvx def /MultipleDataSources false def /Decode [0 1] def end } if }{ /imbuf imbufLen string def Indexed_DeviceN level3 not and DeviceN_NoneName or { /srcDataStrs [ imageDict begin currentdict /MultipleDataSources known {MultipleDataSources {DataSource length}{1}ifelse}{1} ifelse { Width Decode length 2 div mul cvi string } repeat end ] def imageDict begin /DataSource [AGMUTIL_imagefile Decode BitsPerComponent false 1 /filter_indexed_devn load dstDataStr srcDataStrs devn_alt_datasource /exec cvx] cvx def /Decode [0 1] def end }{ imageDict /DataSource [1 string dup 0 AGMUTIL_imagefile Decode length 2 idiv string/readstring cvx /pop cvx names_index /get cvx /put cvx] cvx put imageDict /Decode [0 1] put } ifelse } ifelse imageDict exch load exec imageDict /DataSource origDataSource put imageDict /MultipleDataSources origMultipleDataSources put imageDict /Decode origDecode put end } bdf /write_image_file { begin { (AGMUTIL_imagefile) (w+) file } stopped{ false }{ Adobe_AGM_Utils/AGMUTIL_imagefile xddf 2 dict begin /imbufLen Width BitsPerComponent mul 7 add 8 idiv def MultipleDataSources {DataSource 0 get}{DataSource}ifelse type /filetype eq { /imbuf imbufLen string def }if 1 1 Height MultipleDataSources not{Decode length 2 idiv mul}if{ pop MultipleDataSources { 0 1 DataSource length 1 sub { DataSource type dup /arraytype eq { pop DataSource exch get exec }{ /filetype eq { DataSource exch get imbuf readstring pop }{ DataSource exch get } ifelse } ifelse AGMUTIL_imagefile exch writestring } for }{ DataSource type dup /arraytype eq { pop DataSource exec }{ /filetype eq { DataSource imbuf readstring pop }{ DataSource } ifelse } ifelse AGMUTIL_imagefile exch writestring } ifelse }for end true }ifelse end } bdf /close_image_file { AGMUTIL_imagefile closefile (AGMUTIL_imagefile) deletefile }def statusdict /product known userdict /AGMP_current_show known not and{ /pstr statusdict /product get def pstr (HP LaserJet 2200) eq pstr (HP LaserJet 4000 Series) eq or pstr (HP LaserJet 4050 Series ) eq or pstr (HP LaserJet 8000 Series) eq or pstr (HP LaserJet 8100 Series) eq or pstr (HP LaserJet 8150 Series) eq or pstr (HP LaserJet 5000 Series) eq or pstr (HP LaserJet 5100 Series) eq or pstr (HP Color LaserJet 4500) eq or pstr (HP Color LaserJet 4600) eq or pstr (HP LaserJet 5Si) eq or pstr (HP LaserJet 1200 Series) eq or pstr (HP LaserJet 1300 Series) eq or pstr (HP LaserJet 4100 Series) eq or { userdict /AGMP_current_show /show load put userdict /show { currentcolorspace 0 get /Pattern eq {false charpath f} {AGMP_current_show} ifelse } put }if currentdict /pstr undef } if /consumeimagedata { begin currentdict /MultipleDataSources known not {/MultipleDataSources false def} if MultipleDataSources { DataSource 0 get type dup /filetype eq { 1 dict begin /flushbuffer Width cvi string def 1 1 Height cvi { pop 0 1 DataSource length 1 sub { DataSource exch get flushbuffer readstring pop pop }for }for end }if dup /arraytype eq exch /packedarraytype eq or DataSource 0 get xcheck and { Width Height mul cvi { 0 1 DataSource length 1 sub {dup DataSource exch get exec length exch 0 ne {pop}if}for dup 0 eq {pop exit}if sub dup 0 le {exit}if }loop pop }if } { /DataSource load type dup /filetype eq { 1 dict begin /flushbuffer Width Decode length 2 idiv mul cvi string def 1 1 Height { pop DataSource flushbuffer readstring pop pop} for end }if dup /arraytype eq exch /packedarraytype eq or /DataSource load xcheck and { Height Width BitsPerComponent mul 8 BitsPerComponent sub add 8 idiv Decode length 2 idiv mul mul { DataSource length dup 0 eq {pop exit}if sub dup 0 le {exit}if }loop pop }if }ifelse end }bdf /addprocs { 2{/exec load}repeat 3 1 roll [ 5 1 roll ] bind cvx }def /modify_halftone_xfer { currenthalftone dup length dict copy begin currentdict 2 index known{ 1 index load dup length dict copy begin currentdict/TransferFunction known{ /TransferFunction load }{ currenttransfer }ifelse addprocs /TransferFunction xdf currentdict end def currentdict end sethalftone }{ currentdict/TransferFunction known{ /TransferFunction load }{ currenttransfer }ifelse addprocs /TransferFunction xdf currentdict end sethalftone pop }ifelse }def /clonearray { dup xcheck exch dup length array exch Adobe_AGM_Core/AGMCORE_tmp -1 ddf { Adobe_AGM_Core/AGMCORE_tmp 2 copy get 1 add ddf dup type /dicttype eq { Adobe_AGM_Core/AGMCORE_tmp get exch clonedict Adobe_AGM_Core/AGMCORE_tmp 4 -1 roll ddf } if dup type /arraytype eq { Adobe_AGM_Core/AGMCORE_tmp get exch clonearray Adobe_AGM_Core/AGMCORE_tmp 4 -1 roll ddf } if exch dup Adobe_AGM_Core/AGMCORE_tmp get 4 -1 roll put }forall exch {cvx} if }bdf /clonedict { dup length dict begin { dup type /dicttype eq { clonedict } if dup type /arraytype eq { clonearray } if def }forall currentdict end }bdf /DeviceN_PS2 { /currentcolorspace AGMCORE_gget 0 get /DeviceN eq level3 not and } bdf /Indexed_DeviceN { /indexed_colorspace_dict AGMCORE_gget dup null ne { dup /CSDBase known { /CSDBase get /CSD get_res /Names known }{ pop false }ifelse }{ pop false } ifelse } bdf /DeviceN_NoneName { /Names where { pop false Names { (None) eq or } forall }{ false }ifelse } bdf /DeviceN_PS2_inRip_seps { /AGMCORE_in_rip_sep where { pop dup type dup /arraytype eq exch /packedarraytype eq or { dup 0 get /DeviceN eq level3 not and AGMCORE_in_rip_sep and { /currentcolorspace exch AGMCORE_gput false } { true }ifelse } { true } ifelse } { true } ifelse } bdf /base_colorspace_type { dup type /arraytype eq {0 get} if } bdf /currentdistillerparams where { pop currentdistillerparams /CoreDistVersion get 5000 lt}{true}ifelse { /pdfmark_5 {cleartomark} bind def }{ /pdfmark_5 {pdfmark} bind def }ifelse /ReadBypdfmark_5 { 2 dict begin /makerString exch def string /tmpString exch def { currentfile tmpString readline pop makerString anchorsearch { pop pop cleartomark exit }{ 3 copy /PUT pdfmark_5 pop 2 copy (\n) /PUT pdfmark_5 } ifelse }loop end } bdf /doc_setup{ Adobe_AGM_Utils begin }bdf /doc_trailer{ currentdict Adobe_AGM_Utils eq{ end }if }bdf systemdict /setpacking known { setpacking } if %%EndResource %%BeginResource: procset Adobe_AGM_Core 2.0 0 %%Version: 2.0 0 %%Copyright: Copyright (C) 1997-2005 Adobe Systems, Inc. All Rights Reserved. %% Note: This procset assumes Adobe_AGM_Utils is opened on the stack below it, for %% definitions of some fundamental procedures. systemdict /setpacking known { currentpacking true setpacking } if userdict /Adobe_AGM_Core 201 dict dup begin put /Adobe_AGM_Core_Id /Adobe_AGM_Core_2.0_0 def /AGMCORE_str256 256 string def /AGMCORE_save nd /AGMCORE_graphicsave nd /AGMCORE_c 0 def /AGMCORE_m 0 def /AGMCORE_y 0 def /AGMCORE_k 0 def /AGMCORE_cmykbuf 4 array def /AGMCORE_screen [currentscreen] cvx def /AGMCORE_tmp 0 def /AGMCORE_&setgray nd /AGMCORE_&setcolor nd /AGMCORE_&setcolorspace nd /AGMCORE_&setcmykcolor nd /AGMCORE_cyan_plate nd /AGMCORE_magenta_plate nd /AGMCORE_yellow_plate nd /AGMCORE_black_plate nd /AGMCORE_plate_ndx nd /AGMCORE_get_ink_data nd /AGMCORE_is_cmyk_sep nd /AGMCORE_host_sep nd /AGMCORE_avoid_L2_sep_space nd /AGMCORE_distilling nd /AGMCORE_composite_job nd /AGMCORE_producing_seps nd /AGMCORE_ps_level -1 def /AGMCORE_ps_version -1 def /AGMCORE_environ_ok nd /AGMCORE_CSD_cache 0 dict def /AGMCORE_currentoverprint false def /AGMCORE_deltaX nd /AGMCORE_deltaY nd /AGMCORE_name nd /AGMCORE_sep_special nd /AGMCORE_err_strings 4 dict def /AGMCORE_cur_err nd /AGMCORE_current_spot_alias false def /AGMCORE_inverting false def /AGMCORE_feature_dictCount nd /AGMCORE_feature_opCount nd /AGMCORE_feature_ctm nd /AGMCORE_ConvertToProcess false def /AGMCORE_Default_CTM matrix def /AGMCORE_Default_PageSize nd /AGMCORE_currentbg nd /AGMCORE_currentucr nd /AGMCORE_in_pattern false def /AGMCORE_currentpagedevice nd /knockout_unitsq nd currentglobal true setglobal [/CSA /Gradient /Procedure] { /Generic /Category findresource dup length dict copy /Category defineresource pop } forall setglobal /AGMCORE_key_known { where{ /Adobe_AGM_Core_Id known }{ false }ifelse }ndf /flushinput { save 2 dict begin /CompareBuffer 3 -1 roll def /readbuffer 256 string def mark { currentfile readbuffer {readline} stopped {cleartomark mark} { not {pop exit} if CompareBuffer eq {exit} if }ifelse }loop cleartomark end restore }bdf /getspotfunction { AGMCORE_screen exch pop exch pop dup type /dicttype eq{ dup /HalftoneType get 1 eq{ /SpotFunction get }{ dup /HalftoneType get 2 eq{ /GraySpotFunction get }{ pop { abs exch abs 2 copy add 1 gt{ 1 sub dup mul exch 1 sub dup mul add 1 sub }{ dup mul exch dup mul add 1 exch sub }ifelse }bind }ifelse }ifelse }if } def /clp_npth { clip newpath } def /eoclp_npth { eoclip newpath } def /npth_clp { newpath clip } def /graphic_setup { /AGMCORE_graphicsave save def concat 0 setgray 0 setlinecap 0 setlinejoin 1 setlinewidth [] 0 setdash 10 setmiterlimit newpath false setoverprint false setstrokeadjust //Adobe_AGM_Core/spot_alias get exec /Adobe_AGM_Image where { pop Adobe_AGM_Image/spot_alias 2 copy known{ get exec }{ pop pop }ifelse } if 100 dict begin /dictstackcount countdictstack def /showpage {} def mark } def /graphic_cleanup { cleartomark dictstackcount 1 countdictstack 1 sub {end}for end AGMCORE_graphicsave restore } def /compose_error_msg { grestoreall initgraphics /Helvetica findfont 10 scalefont setfont /AGMCORE_deltaY 100 def /AGMCORE_deltaX 310 def clippath pathbbox newpath pop pop 36 add exch 36 add exch moveto 0 AGMCORE_deltaY rlineto AGMCORE_deltaX 0 rlineto 0 AGMCORE_deltaY neg rlineto AGMCORE_deltaX neg 0 rlineto closepath 0 AGMCORE_&setgray gsave 1 AGMCORE_&setgray fill grestore 1 setlinewidth gsave stroke grestore currentpoint AGMCORE_deltaY 15 sub add exch 8 add exch moveto /AGMCORE_deltaY 12 def /AGMCORE_tmp 0 def AGMCORE_err_strings exch get { dup 32 eq { pop AGMCORE_str256 0 AGMCORE_tmp getinterval stringwidth pop currentpoint pop add AGMCORE_deltaX 28 add gt { currentpoint AGMCORE_deltaY sub exch pop clippath pathbbox pop pop pop 44 add exch moveto } if AGMCORE_str256 0 AGMCORE_tmp getinterval show ( ) show 0 1 AGMCORE_str256 length 1 sub { AGMCORE_str256 exch 0 put }for /AGMCORE_tmp 0 def } { AGMCORE_str256 exch AGMCORE_tmp xpt /AGMCORE_tmp AGMCORE_tmp 1 add def } ifelse } forall } bdf /doc_setup{ Adobe_AGM_Core begin /AGMCORE_ps_version xdf /AGMCORE_ps_level xdf errordict /AGM_handleerror known not{ errordict /AGM_handleerror errordict /handleerror get put errordict /handleerror { Adobe_AGM_Core begin $error /newerror get AGMCORE_cur_err null ne and{ $error /newerror false put AGMCORE_cur_err compose_error_msg }if $error /newerror true put end errordict /AGM_handleerror get exec } bind put }if /AGMCORE_environ_ok ps_level AGMCORE_ps_level ge ps_version AGMCORE_ps_version ge and AGMCORE_ps_level -1 eq or def AGMCORE_environ_ok not {/AGMCORE_cur_err /AGMCORE_bad_environ def} if /AGMCORE_&setgray systemdict/setgray get def level2{ /AGMCORE_&setcolor systemdict/setcolor get def /AGMCORE_&setcolorspace systemdict/setcolorspace get def }if /AGMCORE_currentbg currentblackgeneration def /AGMCORE_currentucr currentundercolorremoval def /AGMCORE_distilling /product where{ pop systemdict/setdistillerparams known product (Adobe PostScript Parser) ne and }{ false }ifelse def /AGMCORE_GSTATE AGMCORE_key_known not{ /AGMCORE_GSTATE 21 dict def /AGMCORE_tmpmatrix matrix def /AGMCORE_gstack 32 array def /AGMCORE_gstackptr 0 def /AGMCORE_gstacksaveptr 0 def /AGMCORE_gstackframekeys 10 def /AGMCORE_&gsave /gsave ldf /AGMCORE_&grestore /grestore ldf /AGMCORE_&grestoreall /grestoreall ldf /AGMCORE_&save /save ldf /AGMCORE_&setoverprint /setoverprint ldf /AGMCORE_gdictcopy { begin { def } forall end }def /AGMCORE_gput { AGMCORE_gstack AGMCORE_gstackptr get 3 1 roll put }def /AGMCORE_gget { AGMCORE_gstack AGMCORE_gstackptr get exch get }def /gsave { AGMCORE_&gsave AGMCORE_gstack AGMCORE_gstackptr get AGMCORE_gstackptr 1 add dup 32 ge {limitcheck} if /AGMCORE_gstackptr exch store AGMCORE_gstack AGMCORE_gstackptr get AGMCORE_gdictcopy }def /grestore { AGMCORE_&grestore AGMCORE_gstackptr 1 sub dup AGMCORE_gstacksaveptr lt {1 add} if dup AGMCORE_gstack exch get dup /AGMCORE_currentoverprint known {/AGMCORE_currentoverprint get setoverprint}{pop}ifelse /AGMCORE_gstackptr exch store }def /grestoreall { AGMCORE_&grestoreall /AGMCORE_gstackptr AGMCORE_gstacksaveptr store }def /save { AGMCORE_&save AGMCORE_gstack AGMCORE_gstackptr get AGMCORE_gstackptr 1 add dup 32 ge {limitcheck} if /AGMCORE_gstackptr exch store /AGMCORE_gstacksaveptr AGMCORE_gstackptr store AGMCORE_gstack AGMCORE_gstackptr get AGMCORE_gdictcopy }def /setoverprint{ dup /AGMCORE_currentoverprint exch AGMCORE_gput AGMCORE_&setoverprint }def 0 1 AGMCORE_gstack length 1 sub { AGMCORE_gstack exch AGMCORE_gstackframekeys dict put } for }if level3 /AGMCORE_&sysshfill AGMCORE_key_known not and { /AGMCORE_&sysshfill systemdict/shfill get def /AGMCORE_&sysmakepattern systemdict/makepattern get def /AGMCORE_&usrmakepattern /makepattern load def }if /currentcmykcolor [0 0 0 0] AGMCORE_gput /currentstrokeadjust false AGMCORE_gput /currentcolorspace [/DeviceGray] AGMCORE_gput /sep_tint 0 AGMCORE_gput /devicen_tints [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] AGMCORE_gput /sep_colorspace_dict null AGMCORE_gput /devicen_colorspace_dict null AGMCORE_gput /indexed_colorspace_dict null AGMCORE_gput /currentcolor_intent () AGMCORE_gput /customcolor_tint 1 AGMCORE_gput << /MaxPatternItem currentsystemparams /MaxPatternCache get >> setuserparams end }def /page_setup { /setcmykcolor where{ pop Adobe_AGM_Core/AGMCORE_&setcmykcolor /setcmykcolor load put }if Adobe_AGM_Core begin /setcmykcolor { 4 copy AGMCORE_cmykbuf astore /currentcmykcolor exch AGMCORE_gput 1 sub 4 1 roll 3 { 3 index add neg dup 0 lt { pop 0 } if 3 1 roll } repeat setrgbcolor pop }ndf /currentcmykcolor { /currentcmykcolor AGMCORE_gget aload pop }ndf /setoverprint { pop }ndf /currentoverprint { false }ndf /AGMCORE_cyan_plate 1 0 0 0 test_cmyk_color_plate def /AGMCORE_magenta_plate 0 1 0 0 test_cmyk_color_plate def /AGMCORE_yellow_plate 0 0 1 0 test_cmyk_color_plate def /AGMCORE_black_plate 0 0 0 1 test_cmyk_color_plate def /AGMCORE_plate_ndx AGMCORE_cyan_plate{ 0 }{ AGMCORE_magenta_plate{ 1 }{ AGMCORE_yellow_plate{ 2 }{ AGMCORE_black_plate{ 3 }{ 4 }ifelse }ifelse }ifelse }ifelse def /AGMCORE_have_reported_unsupported_color_space false def /AGMCORE_report_unsupported_color_space { AGMCORE_have_reported_unsupported_color_space false eq { (Warning: Job contains content that cannot be separated with on-host methods. This content appears on the black plate, and knocks out all other plates.) == Adobe_AGM_Core /AGMCORE_have_reported_unsupported_color_space true ddf } if }def /AGMCORE_composite_job AGMCORE_cyan_plate AGMCORE_magenta_plate and AGMCORE_yellow_plate and AGMCORE_black_plate and def /AGMCORE_in_rip_sep /AGMCORE_in_rip_sep where{ pop AGMCORE_in_rip_sep }{ AGMCORE_distilling { false }{ userdict/Adobe_AGM_OnHost_Seps known{ false }{ level2{ currentpagedevice/Separations 2 copy known{ get }{ pop pop false }ifelse }{ false }ifelse }ifelse }ifelse }ifelse def /AGMCORE_producing_seps AGMCORE_composite_job not AGMCORE_in_rip_sep or def /AGMCORE_host_sep AGMCORE_producing_seps AGMCORE_in_rip_sep not and def /AGM_preserve_spots /AGM_preserve_spots where{ pop AGM_preserve_spots }{ AGMCORE_distilling AGMCORE_producing_seps or }ifelse def /AGM_is_distiller_preserving_spotimages { currentdistillerparams/PreserveOverprintSettings known { currentdistillerparams/PreserveOverprintSettings get { currentdistillerparams/ColorConversionStrategy known { currentdistillerparams/ColorConversionStrategy get /sRGB ne }{ true }ifelse }{ false }ifelse }{ false }ifelse }def /convert_spot_to_process where {pop}{ /convert_spot_to_process { //Adobe_AGM_Core begin dup map_alias { /Name get exch pop } if dup dup (None) eq exch (All) eq or { pop false }{ AGMCORE_host_sep { gsave 1 0 0 0 setcmykcolor currentgray 1 exch sub 0 1 0 0 setcmykcolor currentgray 1 exch sub 0 0 1 0 setcmykcolor currentgray 1 exch sub 0 0 0 1 setcmykcolor currentgray 1 exch sub add add add 0 eq { pop false }{ false setoverprint current_spot_alias false set_spot_alias 1 1 1 1 6 -1 roll findcmykcustomcolor 1 setcustomcolor set_spot_alias currentgray 1 ne }ifelse grestore }{ AGMCORE_distilling { pop AGM_is_distiller_preserving_spotimages not }{ //Adobe_AGM_Core/AGMCORE_name xddf false //Adobe_AGM_Core/AGMCORE_in_pattern known {//Adobe_AGM_Core/AGMCORE_in_pattern get}{false} ifelse not AGMCORE_currentpagedevice/OverrideSeparations known and { AGMCORE_currentpagedevice/OverrideSeparations get { /HqnSpots /ProcSet resourcestatus { pop pop pop true }if }if }if { AGMCORE_name /HqnSpots /ProcSet findresource /TestSpot get exec not }{ gsave [/Separation AGMCORE_name /DeviceGray {}]AGMCORE_&setcolorspace false AGMCORE_currentpagedevice/SeparationColorNames 2 copy known { get { AGMCORE_name eq or}forall not }{ pop pop pop true }ifelse grestore }ifelse }ifelse }ifelse }ifelse end }def }ifelse /convert_to_process where {pop}{ /convert_to_process { dup length 0 eq { pop false }{ AGMCORE_host_sep { dup true exch { dup (Cyan) eq exch dup (Magenta) eq 3 -1 roll or exch dup (Yellow) eq 3 -1 roll or exch dup (Black) eq 3 -1 roll or {pop} {convert_spot_to_process and}ifelse } forall { true exch { dup (Cyan) eq exch dup (Magenta) eq 3 -1 roll or exch dup (Yellow) eq 3 -1 roll or exch (Black) eq or and }forall not }{pop false}ifelse }{ false exch { dup (Cyan) eq exch dup (Magenta) eq 3 -1 roll or exch dup (Yellow) eq 3 -1 roll or exch dup (Black) eq 3 -1 roll or {pop} {convert_spot_to_process or}ifelse } forall }ifelse }ifelse }def }ifelse /AGMCORE_avoid_L2_sep_space version cvr 2012 lt level2 and AGMCORE_producing_seps not and def /AGMCORE_is_cmyk_sep AGMCORE_cyan_plate AGMCORE_magenta_plate or AGMCORE_yellow_plate or AGMCORE_black_plate or def /AGM_avoid_0_cmyk where{ pop AGM_avoid_0_cmyk }{ AGM_preserve_spots userdict/Adobe_AGM_OnHost_Seps known userdict/Adobe_AGM_InRip_Seps known or not and }ifelse { /setcmykcolor[ { 4 copy add add add 0 eq currentoverprint and{ pop 0.0005 }if }/exec cvx /AGMCORE_&setcmykcolor load dup type/operatortype ne{ /exec cvx }if ]cvx def }if /AGMCORE_IsSeparationAProcessColor { dup (Cyan) eq exch dup (Magenta) eq exch dup (Yellow) eq exch (Black) eq or or or }def AGMCORE_host_sep{ /setcolortransfer { AGMCORE_cyan_plate{ pop pop pop }{ AGMCORE_magenta_plate{ 4 3 roll pop pop pop }{ AGMCORE_yellow_plate{ 4 2 roll pop pop pop }{ 4 1 roll pop pop pop }ifelse }ifelse }ifelse settransfer } def /AGMCORE_get_ink_data AGMCORE_cyan_plate{ {pop pop pop} }{ AGMCORE_magenta_plate{ {4 3 roll pop pop pop} }{ AGMCORE_yellow_plate{ {4 2 roll pop pop pop} }{ {4 1 roll pop pop pop} }ifelse }ifelse }ifelse def /AGMCORE_RemoveProcessColorNames { 1 dict begin /filtername { dup /Cyan eq 1 index (Cyan) eq or {pop (_cyan_)}if dup /Magenta eq 1 index (Magenta) eq or {pop (_magenta_)}if dup /Yellow eq 1 index (Yellow) eq or {pop (_yellow_)}if dup /Black eq 1 index (Black) eq or {pop (_black_)}if }def dup type /arraytype eq {[exch {filtername}forall]} {filtername}ifelse end }def level3 { /AGMCORE_IsCurrentColor { dup AGMCORE_IsSeparationAProcessColor { AGMCORE_plate_ndx 0 eq {dup (Cyan) eq exch /Cyan eq or}if AGMCORE_plate_ndx 1 eq {dup (Magenta) eq exch /Magenta eq or}if AGMCORE_plate_ndx 2 eq {dup (Yellow) eq exch /Yellow eq or}if AGMCORE_plate_ndx 3 eq {dup (Black) eq exch /Black eq or}if AGMCORE_plate_ndx 4 eq {pop false}if }{ gsave false setoverprint current_spot_alias false set_spot_alias 1 1 1 1 6 -1 roll findcmykcustomcolor 1 setcustomcolor set_spot_alias currentgray 1 ne grestore }ifelse }def /AGMCORE_filter_functiondatasource { 5 dict begin /data_in xdf data_in type /stringtype eq { /ncomp xdf /comp xdf /string_out data_in length ncomp idiv string def 0 ncomp data_in length 1 sub { string_out exch dup ncomp idiv exch data_in exch ncomp getinterval comp get 255 exch sub put }for string_out }{ string /string_in xdf /string_out 1 string def /component xdf [ data_in string_in /readstring cvx [component /get cvx 255 /exch cvx /sub cvx string_out /exch cvx 0 /exch cvx /put cvx string_out]cvx [/pop cvx ()]cvx /ifelse cvx ]cvx /ReusableStreamDecode filter }ifelse end }def /AGMCORE_separateShadingFunction { 2 dict begin /paint? xdf /channel xdf dup type /dicttype eq { begin FunctionType 0 eq { /DataSource channel Range length 2 idiv DataSource AGMCORE_filter_functiondatasource def currentdict /Decode known {/Decode Decode channel 2 mul 2 getinterval def}if paint? not {/Decode [1 1]def}if }if FunctionType 2 eq { paint? { /C0 [C0 channel get 1 exch sub] def /C1 [C1 channel get 1 exch sub] def }{ /C0 [1] def /C1 [1] def }ifelse }if FunctionType 3 eq { /Functions [Functions {channel paint? AGMCORE_separateShadingFunction} forall] def }if currentdict /Range known {/Range [0 1] def}if currentdict end}{ channel get 0 paint? AGMCORE_separateShadingFunction }ifelse end }def /AGMCORE_separateShading { 3 -1 roll begin currentdict /Function known { currentdict /Background known {[1 index{Background 3 index get 1 exch sub}{1}ifelse]/Background xdf}if Function 3 1 roll AGMCORE_separateShadingFunction /Function xdf /ColorSpace [/DeviceGray] def }{ ColorSpace dup type /arraytype eq {0 get}if /DeviceCMYK eq { /ColorSpace [/DeviceN [/_cyan_ /_magenta_ /_yellow_ /_black_] /DeviceCMYK {}] def }{ ColorSpace dup 1 get AGMCORE_RemoveProcessColorNames 1 exch put }ifelse ColorSpace 0 get /Separation eq { { [1 /exch cvx /sub cvx]cvx }{ [/pop cvx 1]cvx }ifelse ColorSpace 3 3 -1 roll put pop }{ { [exch ColorSpace 1 get length 1 sub exch sub /index cvx 1 /exch cvx /sub cvx ColorSpace 1 get length 1 add 1 /roll cvx ColorSpace 1 get length{/pop cvx} repeat]cvx }{ pop [ColorSpace 1 get length {/pop cvx} repeat cvx 1]cvx }ifelse ColorSpace 3 3 -1 roll bind put }ifelse ColorSpace 2 /DeviceGray put }ifelse end }def /AGMCORE_separateShadingDict { dup /ColorSpace get dup type /arraytype ne {[exch]}if dup 0 get /DeviceCMYK eq { exch begin currentdict AGMCORE_cyan_plate {0 true}if AGMCORE_magenta_plate {1 true}if AGMCORE_yellow_plate {2 true}if AGMCORE_black_plate {3 true}if AGMCORE_plate_ndx 4 eq {0 false}if dup not currentoverprint and {/AGMCORE_ignoreshade true def}if AGMCORE_separateShading currentdict end exch }if dup 0 get /Separation eq { exch begin ColorSpace 1 get dup /None ne exch /All ne and { ColorSpace 1 get AGMCORE_IsCurrentColor AGMCORE_plate_ndx 4 lt and ColorSpace 1 get AGMCORE_IsSeparationAProcessColor not and { ColorSpace 2 get dup type /arraytype eq {0 get}if /DeviceCMYK eq { /ColorSpace [ /Separation ColorSpace 1 get /DeviceGray [ ColorSpace 3 get /exec cvx 4 AGMCORE_plate_ndx sub -1 /roll cvx 4 1 /roll cvx 3 [/pop cvx]cvx /repeat cvx 1 /exch cvx /sub cvx ]cvx ]def }{ AGMCORE_report_unsupported_color_space AGMCORE_black_plate not { currentdict 0 false AGMCORE_separateShading }if }ifelse }{ currentdict ColorSpace 1 get AGMCORE_IsCurrentColor 0 exch dup not currentoverprint and {/AGMCORE_ignoreshade true def}if AGMCORE_separateShading }ifelse }if currentdict end exch }if dup 0 get /DeviceN eq { exch begin ColorSpace 1 get convert_to_process { ColorSpace 2 get dup type /arraytype eq {0 get}if /DeviceCMYK eq { /ColorSpace [ /DeviceN ColorSpace 1 get /DeviceGray [ ColorSpace 3 get /exec cvx 4 AGMCORE_plate_ndx sub -1 /roll cvx 4 1 /roll cvx 3 [/pop cvx]cvx /repeat cvx 1 /exch cvx /sub cvx ]cvx ]def }{ AGMCORE_report_unsupported_color_space AGMCORE_black_plate not { currentdict 0 false AGMCORE_separateShading /ColorSpace [/DeviceGray] def }if }ifelse }{ currentdict false -1 ColorSpace 1 get { AGMCORE_IsCurrentColor { 1 add exch pop true exch exit }if 1 add }forall exch dup not currentoverprint and {/AGMCORE_ignoreshade true def}if AGMCORE_separateShading }ifelse currentdict end exch }if dup 0 get dup /DeviceCMYK eq exch dup /Separation eq exch /DeviceN eq or or not { exch begin ColorSpace dup type /arraytype eq {0 get}if /DeviceGray ne { AGMCORE_report_unsupported_color_space AGMCORE_black_plate not { ColorSpace 0 get /CIEBasedA eq { /ColorSpace [/Separation /_ciebaseda_ /DeviceGray {}] def }if ColorSpace 0 get dup /CIEBasedABC eq exch dup /CIEBasedDEF eq exch /DeviceRGB eq or or { /ColorSpace [/DeviceN [/_red_ /_green_ /_blue_] /DeviceRGB {}] def }if ColorSpace 0 get /CIEBasedDEFG eq { /ColorSpace [/DeviceN [/_cyan_ /_magenta_ /_yellow_ /_black_] /DeviceCMYK {}] def }if currentdict 0 false AGMCORE_separateShading }if }if currentdict end exch }if pop dup /AGMCORE_ignoreshade known { begin /ColorSpace [/Separation (None) /DeviceGray {}] def currentdict end }if }def /shfill { AGMCORE_separateShadingDict dup /AGMCORE_ignoreshade known {pop} {AGMCORE_&sysshfill}ifelse }def /makepattern { exch dup /PatternType get 2 eq { clonedict begin /Shading Shading AGMCORE_separateShadingDict def Shading /AGMCORE_ignoreshade known currentdict end exch {pop <</PatternType 1/PaintProc{pop}/BBox[0 0 1 1]/XStep 1/YStep 1/PaintType 1/TilingType 3>>}if exch AGMCORE_&sysmakepattern }{ exch AGMCORE_&usrmakepattern }ifelse }def }if }if AGMCORE_in_rip_sep{ /setcustomcolor { exch aload pop dup 7 1 roll inRip_spot_has_ink not { 4 {4 index mul 4 1 roll} repeat /DeviceCMYK setcolorspace 6 -2 roll pop pop }{ //Adobe_AGM_Core begin /AGMCORE_k xdf /AGMCORE_y xdf /AGMCORE_m xdf /AGMCORE_c xdf end [/Separation 4 -1 roll /DeviceCMYK {dup AGMCORE_c mul exch dup AGMCORE_m mul exch dup AGMCORE_y mul exch AGMCORE_k mul} ] setcolorspace }ifelse setcolor }ndf /setseparationgray { [/Separation (All) /DeviceGray {}] setcolorspace_opt 1 exch sub setcolor }ndf }{ /setseparationgray { AGMCORE_&setgray }ndf }ifelse /findcmykcustomcolor { 5 makereadonlyarray }ndf /setcustomcolor { exch aload pop pop 4 {4 index mul 4 1 roll} repeat setcmykcolor pop }ndf /has_color /colorimage where{ AGMCORE_producing_seps{ pop true }{ systemdict eq }ifelse }{ false }ifelse def /map_index { 1 index mul exch getinterval {255 div} forall } bdf /map_indexed_devn { Lookup Names length 3 -1 roll cvi map_index } bdf /n_color_components { base_colorspace_type dup /DeviceGray eq{ pop 1 }{ /DeviceCMYK eq{ 4 }{ 3 }ifelse }ifelse }bdf level2{ /mo /moveto ldf /li /lineto ldf /cv /curveto ldf /knockout_unitsq { 1 setgray 0 0 1 1 rectfill }def level2 /setcolorspace AGMCORE_key_known not and{ /AGMCORE_&&&setcolorspace /setcolorspace ldf /AGMCORE_ReplaceMappedColor { dup type dup /arraytype eq exch /packedarraytype eq or { /AGMCORE_SpotAliasAry2 where { begin dup 0 get dup /Separation eq { pop dup length array copy dup dup 1 get current_spot_alias { dup map_alias { false set_spot_alias dup 1 exch setsepcolorspace true set_spot_alias begin /sep_colorspace_dict currentdict AGMCORE_gput pop pop pop [ /Separation Name CSA map_csa MappedCSA /sep_colorspace_proc load ] dup Name end }if }if map_reserved_ink_name 1 xpt }{ /DeviceN eq { dup length array copy dup dup 1 get [ exch { current_spot_alias{ dup map_alias{ /Name get exch pop }if }if map_reserved_ink_name } forall ] 1 xpt }if }ifelse end } if }if }def /setcolorspace { dup type dup /arraytype eq exch /packedarraytype eq or { dup 0 get /Indexed eq { AGMCORE_distilling { /PhotoshopDuotoneList where { pop false }{ true }ifelse }{ true }ifelse { aload pop 3 -1 roll AGMCORE_ReplaceMappedColor 3 1 roll 4 array astore }if }{ AGMCORE_ReplaceMappedColor }ifelse }if DeviceN_PS2_inRip_seps {AGMCORE_&&&setcolorspace} if }def }if }{ /adj { currentstrokeadjust{ transform 0.25 sub round 0.25 add exch 0.25 sub round 0.25 add exch itransform }if }def /mo{ adj moveto }def /li{ adj lineto }def /cv{ 6 2 roll adj 6 2 roll adj 6 2 roll adj curveto }def /knockout_unitsq { 1 setgray 8 8 1 [8 0 0 8 0 0] {<ffffffffffffffff>} image }def /currentstrokeadjust{ /currentstrokeadjust AGMCORE_gget }def /setstrokeadjust{ /currentstrokeadjust exch AGMCORE_gput }def /setcolorspace { /currentcolorspace exch AGMCORE_gput } def /currentcolorspace { /currentcolorspace AGMCORE_gget } def /setcolor_devicecolor { base_colorspace_type dup /DeviceGray eq{ pop setgray }{ /DeviceCMYK eq{ setcmykcolor }{ setrgbcolor }ifelse }ifelse }def /setcolor { currentcolorspace 0 get dup /DeviceGray ne{ dup /DeviceCMYK ne{ dup /DeviceRGB ne{ dup /Separation eq{ pop currentcolorspace 3 get exec currentcolorspace 2 get }{ dup /Indexed eq{ pop currentcolorspace 3 get dup type /stringtype eq{ currentcolorspace 1 get n_color_components 3 -1 roll map_index }{ exec }ifelse currentcolorspace 1 get }{ /AGMCORE_cur_err /AGMCORE_invalid_color_space def AGMCORE_invalid_color_space }ifelse }ifelse }if }if }if setcolor_devicecolor } def }ifelse /sop /setoverprint ldf /lw /setlinewidth ldf /lc /setlinecap ldf /lj /setlinejoin ldf /ml /setmiterlimit ldf /dsh /setdash ldf /sadj /setstrokeadjust ldf /gry /setgray ldf /rgb /setrgbcolor ldf /cmyk /setcmykcolor ldf /sep /setsepcolor ldf /devn /setdevicencolor ldf /idx /setindexedcolor ldf /colr /setcolor ldf /csacrd /set_csa_crd ldf /sepcs /setsepcolorspace ldf /devncs /setdevicencolorspace ldf /idxcs /setindexedcolorspace ldf /cp /closepath ldf /clp /clp_npth ldf /eclp /eoclp_npth ldf /f /fill ldf /ef /eofill ldf /@ /stroke ldf /nclp /npth_clp ldf /gset /graphic_setup ldf /gcln /graphic_cleanup ldf /AGMCORE_def_ht currenthalftone def /clonedict Adobe_AGM_Utils begin /clonedict load end def /clonearray Adobe_AGM_Utils begin /clonearray load end def currentdict{ dup xcheck 1 index type dup /arraytype eq exch /packedarraytype eq or and { bind }if def }forall /getrampcolor { /indx exch def 0 1 NumComp 1 sub { dup Samples exch get dup type /stringtype eq {indx get} if exch Scaling exch get aload pop 3 1 roll mul add } for ColorSpaceFamily /Separation eq {sep} { ColorSpaceFamily /DeviceN eq {devn} {setcolor}ifelse }ifelse } bdf /sssetbackground {aload pop setcolor} bdf /RadialShade { 40 dict begin /ColorSpaceFamily xdf /background xdf /ext1 xdf /ext0 xdf /BBox xdf /r2 xdf /c2y xdf /c2x xdf /r1 xdf /c1y xdf /c1x xdf /rampdict xdf /setinkoverprint where {pop /setinkoverprint{pop}def}if gsave BBox length 0 gt { newpath BBox 0 get BBox 1 get moveto BBox 2 get BBox 0 get sub 0 rlineto 0 BBox 3 get BBox 1 get sub rlineto BBox 2 get BBox 0 get sub neg 0 rlineto closepath clip newpath } if c1x c2x eq { c1y c2y lt {/theta 90 def}{/theta 270 def} ifelse } { /slope c2y c1y sub c2x c1x sub div def /theta slope 1 atan def c2x c1x lt c2y c1y ge and { /theta theta 180 sub def} if c2x c1x lt c2y c1y lt and { /theta theta 180 add def} if } ifelse gsave clippath c1x c1y translate theta rotate -90 rotate { pathbbox } stopped { 0 0 0 0 } if /yMax xdf /xMax xdf /yMin xdf /xMin xdf grestore xMax xMin eq yMax yMin eq or { grestore end } { /max { 2 copy gt { pop } {exch pop} ifelse } bdf /min { 2 copy lt { pop } {exch pop} ifelse } bdf rampdict begin 40 dict begin background length 0 gt { background sssetbackground gsave clippath fill grestore } if gsave c1x c1y translate theta rotate -90 rotate /c2y c1x c2x sub dup mul c1y c2y sub dup mul add sqrt def /c1y 0 def /c1x 0 def /c2x 0 def ext0 { 0 getrampcolor c2y r2 add r1 sub 0.0001 lt { c1x c1y r1 360 0 arcn pathbbox /aymax exch def /axmax exch def /aymin exch def /axmin exch def /bxMin xMin axmin min def /byMin yMin aymin min def /bxMax xMax axmax max def /byMax yMax aymax max def bxMin byMin moveto bxMax byMin lineto bxMax byMax lineto bxMin byMax lineto bxMin byMin lineto eofill } { c2y r1 add r2 le { c1x c1y r1 0 360 arc fill } { c2x c2y r2 0 360 arc fill r1 r2 eq { /p1x r1 neg def /p1y c1y def /p2x r1 def /p2y c1y def p1x p1y moveto p2x p2y lineto p2x yMin lineto p1x yMin lineto fill } { /AA r2 r1 sub c2y div def AA -1 eq { /theta 89.99 def} { /theta AA 1 AA dup mul sub sqrt div 1 atan def} ifelse /SS1 90 theta add dup sin exch cos div def /p1x r1 SS1 SS1 mul SS1 SS1 mul 1 add div sqrt mul neg def /p1y p1x SS1 div neg def /SS2 90 theta sub dup sin exch cos div def /p2x r1 SS2 SS2 mul SS2 SS2 mul 1 add div sqrt mul def /p2y p2x SS2 div neg def r1 r2 gt { /L1maxX p1x yMin p1y sub SS1 div add def /L2maxX p2x yMin p2y sub SS2 div add def } { /L1maxX 0 def /L2maxX 0 def } ifelse p1x p1y moveto p2x p2y lineto L2maxX L2maxX p2x sub SS2 mul p2y add lineto L1maxX L1maxX p1x sub SS1 mul p1y add lineto fill } ifelse } ifelse } ifelse } if c1x c2x sub dup mul c1y c2y sub dup mul add 0.5 exp 0 dtransform dup mul exch dup mul add 0.5 exp 72 div 0 72 matrix defaultmatrix dtransform dup mul exch dup mul add sqrt 72 0 matrix defaultmatrix dtransform dup mul exch dup mul add sqrt 1 index 1 index lt { exch } if pop /hires xdf hires mul /numpix xdf /numsteps NumSamples def /rampIndxInc 1 def /subsampling false def numpix 0 ne { NumSamples numpix div 0.5 gt { /numsteps numpix 2 div round cvi dup 1 le { pop 2 } if def /rampIndxInc NumSamples 1 sub numsteps div def /subsampling true def } if } if /xInc c2x c1x sub numsteps div def /yInc c2y c1y sub numsteps div def /rInc r2 r1 sub numsteps div def /cx c1x def /cy c1y def /radius r1 def newpath xInc 0 eq yInc 0 eq rInc 0 eq and and { 0 getrampcolor cx cy radius 0 360 arc stroke NumSamples 1 sub getrampcolor cx cy radius 72 hires div add 0 360 arc 0 setlinewidth stroke } { 0 numsteps { dup subsampling { round cvi } if getrampcolor cx cy radius 0 360 arc /cx cx xInc add def /cy cy yInc add def /radius radius rInc add def cx cy radius 360 0 arcn eofill rampIndxInc add } repeat pop } ifelse ext1 { c2y r2 add r1 lt { c2x c2y r2 0 360 arc fill } { c2y r1 add r2 sub 0.0001 le { c2x c2y r2 360 0 arcn pathbbox /aymax exch def /axmax exch def /aymin exch def /axmin exch def /bxMin xMin axmin min def /byMin yMin aymin min def /bxMax xMax axmax max def /byMax yMax aymax max def bxMin byMin moveto bxMax byMin lineto bxMax byMax lineto bxMin byMax lineto bxMin byMin lineto eofill } { c2x c2y r2 0 360 arc fill r1 r2 eq { /p1x r2 neg def /p1y c2y def /p2x r2 def /p2y c2y def p1x p1y moveto p2x p2y lineto p2x yMax lineto p1x yMax lineto fill } { /AA r2 r1 sub c2y div def AA -1 eq { /theta 89.99 def} { /theta AA 1 AA dup mul sub sqrt div 1 atan def} ifelse /SS1 90 theta add dup sin exch cos div def /p1x r2 SS1 SS1 mul SS1 SS1 mul 1 add div sqrt mul neg def /p1y c2y p1x SS1 div sub def /SS2 90 theta sub dup sin exch cos div def /p2x r2 SS2 SS2 mul SS2 SS2 mul 1 add div sqrt mul def /p2y c2y p2x SS2 div sub def r1 r2 lt { /L1maxX p1x yMax p1y sub SS1 div add def /L2maxX p2x yMax p2y sub SS2 div add def } { /L1maxX 0 def /L2maxX 0 def }ifelse p1x p1y moveto p2x p2y lineto L2maxX L2maxX p2x sub SS2 mul p2y add lineto L1maxX L1maxX p1x sub SS1 mul p1y add lineto fill } ifelse } ifelse } ifelse } if grestore grestore end end end } ifelse } bdf /GenStrips { 40 dict begin /ColorSpaceFamily xdf /background xdf /ext1 xdf /ext0 xdf /BBox xdf /y2 xdf /x2 xdf /y1 xdf /x1 xdf /rampdict xdf /setinkoverprint where {pop /setinkoverprint{pop}def}if gsave BBox length 0 gt { newpath BBox 0 get BBox 1 get moveto BBox 2 get BBox 0 get sub 0 rlineto 0 BBox 3 get BBox 1 get sub rlineto BBox 2 get BBox 0 get sub neg 0 rlineto closepath clip newpath } if x1 x2 eq { y1 y2 lt {/theta 90 def}{/theta 270 def} ifelse } { /slope y2 y1 sub x2 x1 sub div def /theta slope 1 atan def x2 x1 lt y2 y1 ge and { /theta theta 180 sub def} if x2 x1 lt y2 y1 lt and { /theta theta 180 add def} if } ifelse gsave clippath x1 y1 translate theta rotate { pathbbox } stopped { 0 0 0 0 } if /yMax exch def /xMax exch def /yMin exch def /xMin exch def grestore xMax xMin eq yMax yMin eq or { grestore end } { rampdict begin 20 dict begin background length 0 gt { background sssetbackground gsave clippath fill grestore } if gsave x1 y1 translate theta rotate /xStart 0 def /xEnd x2 x1 sub dup mul y2 y1 sub dup mul add 0.5 exp def /ySpan yMax yMin sub def /numsteps NumSamples def /rampIndxInc 1 def /subsampling false def xStart 0 transform xEnd 0 transform 3 -1 roll sub dup mul 3 1 roll sub dup mul add 0.5 exp 72 div 0 72 matrix defaultmatrix dtransform dup mul exch dup mul add sqrt 72 0 matrix defaultmatrix dtransform dup mul exch dup mul add sqrt 1 index 1 index lt { exch } if pop mul /numpix xdf numpix 0 ne { NumSamples numpix div 0.5 gt { /numsteps numpix 2 div round cvi dup 1 le { pop 2 } if def /rampIndxInc NumSamples 1 sub numsteps div def /subsampling true def } if } if ext0 { 0 getrampcolor xMin xStart lt { xMin yMin xMin neg ySpan rectfill } if } if /xInc xEnd xStart sub numsteps div def /x xStart def 0 numsteps { dup subsampling { round cvi } if getrampcolor x yMin xInc ySpan rectfill /x x xInc add def rampIndxInc add } repeat pop ext1 { xMax xEnd gt { xEnd yMin xMax xEnd sub ySpan rectfill } if } if grestore grestore end end end } ifelse } bdf }def /page_trailer { end }def /doc_trailer{ }def /capture_currentpagedevice { //Adobe_AGM_Core/AGMCORE_currentpagedevice currentpagedevice ddf } def systemdict /findcolorrendering known{ /findcolorrendering systemdict /findcolorrendering get def }if systemdict /setcolorrendering known{ /setcolorrendering systemdict /setcolorrendering get def }if /test_cmyk_color_plate { gsave setcmykcolor currentgray 1 ne grestore }def /inRip_spot_has_ink { dup //Adobe_AGM_Core/AGMCORE_name xddf convert_spot_to_process not }def /map255_to_range { 1 index sub 3 -1 roll 255 div mul add }def /set_csa_crd { /sep_colorspace_dict null AGMCORE_gput begin CSA get_csa_by_name setcolorspace_opt set_crd end } def /map_csa { currentdict/MappedCSA known{MappedCSA null ne}{false}ifelse {pop}{get_csa_by_name /MappedCSA xdf}ifelse } def /setsepcolor { /sep_colorspace_dict AGMCORE_gget begin dup /sep_tint exch AGMCORE_gput TintProc end } def /setdevicencolor { /devicen_colorspace_dict AGMCORE_gget begin Names length copy Names length 1 sub -1 0 { /devicen_tints AGMCORE_gget 3 1 roll xpt } for TintProc end } def /sep_colorspace_proc { /AGMCORE_tmp exch store /sep_colorspace_dict AGMCORE_gget begin currentdict/Components known{ Components aload pop TintMethod/Lab eq{ 2 {AGMCORE_tmp mul NComponents 1 roll} repeat LMax sub AGMCORE_tmp mul LMax add NComponents 1 roll }{ TintMethod/Subtractive eq{ NComponents{ AGMCORE_tmp mul NComponents 1 roll }repeat }{ NComponents{ 1 sub AGMCORE_tmp mul 1 add NComponents 1 roll } repeat }ifelse }ifelse }{ ColorLookup AGMCORE_tmp ColorLookup length 1 sub mul round cvi get aload pop }ifelse end } def /sep_colorspace_gray_proc { /AGMCORE_tmp exch store /sep_colorspace_dict AGMCORE_gget begin GrayLookup AGMCORE_tmp GrayLookup length 1 sub mul round cvi get end } def /sep_proc_name { dup 0 get dup /DeviceRGB eq exch /DeviceCMYK eq or level2 not and has_color not and{ pop [/DeviceGray] /sep_colorspace_gray_proc }{ /sep_colorspace_proc }ifelse } def /setsepcolorspace { current_spot_alias{ dup begin Name map_alias{ exch pop }if end }if dup /sep_colorspace_dict exch AGMCORE_gput begin CSA map_csa /AGMCORE_sep_special Name dup () eq exch (All) eq or store AGMCORE_avoid_L2_sep_space{ [/Indexed MappedCSA sep_proc_name 255 exch { 255 div } /exec cvx 3 -1 roll [ 4 1 roll load /exec cvx ] cvx ] setcolorspace_opt /TintProc { 255 mul round cvi setcolor }bdf }{ MappedCSA 0 get /DeviceCMYK eq currentdict/Components known and AGMCORE_sep_special not and{ /TintProc [ Components aload pop Name findcmykcustomcolor /exch cvx /setcustomcolor cvx ] cvx bdf }{ AGMCORE_host_sep Name (All) eq and{ /TintProc { 1 exch sub setseparationgray }bdf }{ AGMCORE_in_rip_sep MappedCSA 0 get /DeviceCMYK eq and AGMCORE_host_sep or Name () eq and{ /TintProc [ MappedCSA sep_proc_name exch 0 get /DeviceCMYK eq{ cvx /setcmykcolor cvx }{ cvx /setgray cvx }ifelse ] cvx bdf }{ AGMCORE_producing_seps MappedCSA 0 get dup /DeviceCMYK eq exch /DeviceGray eq or and AGMCORE_sep_special not and{ /TintProc [ /dup cvx MappedCSA sep_proc_name cvx exch 0 get /DeviceGray eq{ 1 /exch cvx /sub cvx 0 0 0 4 -1 /roll cvx }if /Name cvx /findcmykcustomcolor cvx /exch cvx AGMCORE_host_sep{ AGMCORE_is_cmyk_sep /Name cvx /AGMCORE_IsSeparationAProcessColor load /exec cvx /not cvx /and cvx }{ Name inRip_spot_has_ink not }ifelse [ /pop cvx 1 ] cvx /if cvx /setcustomcolor cvx ] cvx bdf }{ /TintProc {setcolor} bdf [/Separation Name MappedCSA sep_proc_name load ] setcolorspace_opt }ifelse }ifelse }ifelse }ifelse }ifelse set_crd setsepcolor end } def /additive_blend { 3 dict begin /numarrays xdf /numcolors xdf 0 1 numcolors 1 sub { /c1 xdf 1 0 1 numarrays 1 sub { 1 exch add /index cvx c1 /get cvx /mul cvx }for numarrays 1 add 1 /roll cvx }for numarrays [/pop cvx] cvx /repeat cvx end }def /subtractive_blend { 3 dict begin /numarrays xdf /numcolors xdf 0 1 numcolors 1 sub { /c1 xdf 1 1 0 1 numarrays 1 sub { 1 3 3 -1 roll add /index cvx c1 /get cvx /sub cvx /mul cvx }for /sub cvx numarrays 1 add 1 /roll cvx }for numarrays [/pop cvx] cvx /repeat cvx end }def /exec_tint_transform { /TintProc [ /TintTransform cvx /setcolor cvx ] cvx bdf MappedCSA setcolorspace_opt } bdf /devn_makecustomcolor { 2 dict begin /names_index xdf /Names xdf 1 1 1 1 Names names_index get findcmykcustomcolor /devicen_tints AGMCORE_gget names_index get setcustomcolor Names length {pop} repeat end } bdf /setdevicencolorspace { dup /AliasedColorants known {false}{true}ifelse current_spot_alias and { 7 dict begin /names_index 0 def dup /names_len exch /Names get length def /new_names names_len array def /new_LookupTables names_len array def /alias_cnt 0 def dup /Names get { dup map_alias { exch pop dup /ColorLookup known { dup begin new_LookupTables names_index ColorLookup put end }{ dup /Components known { dup begin new_LookupTables names_index Components put end }{ dup begin new_LookupTables names_index [null null null null] put end } ifelse } ifelse new_names names_index 3 -1 roll /Name get put /alias_cnt alias_cnt 1 add def }{ /name xdf new_names names_index name put dup /LookupTables known { dup begin new_LookupTables names_index LookupTables names_index get put end }{ dup begin new_LookupTables names_index [null null null null] put end } ifelse } ifelse /names_index names_index 1 add def } forall alias_cnt 0 gt { /AliasedColorants true def /lut_entry_len new_LookupTables 0 get dup length 256 ge {0 get length}{length}ifelse def 0 1 names_len 1 sub { /names_index xdf new_LookupTables names_index get dup length 256 ge {0 get length}{length}ifelse lut_entry_len ne { /AliasedColorants false def exit } { new_LookupTables names_index get 0 get null eq { dup /Names get names_index get /name xdf name (Cyan) eq name (Magenta) eq name (Yellow) eq name (Black) eq or or or not { /AliasedColorants false def exit } if } if } ifelse } for lut_entry_len 1 eq { /AliasedColorants false def } if AliasedColorants { dup begin /Names new_names def /LookupTables new_LookupTables def /AliasedColorants true def /NComponents lut_entry_len def /TintMethod NComponents 4 eq {/Subtractive}{/Additive}ifelse def /MappedCSA TintMethod /Additive eq {/DeviceRGB}{/DeviceCMYK}ifelse def currentdict /TTTablesIdx known not { /TTTablesIdx -1 def } if end } if }if end } if dup /devicen_colorspace_dict exch AGMCORE_gput begin currentdict /AliasedColorants known { AliasedColorants }{ false } ifelse dup not { CSA map_csa } if /TintTransform load type /nulltype eq or { /TintTransform [ 0 1 Names length 1 sub { /TTTablesIdx TTTablesIdx 1 add def dup LookupTables exch get dup 0 get null eq { 1 index Names exch get dup (Cyan) eq { pop exch LookupTables length exch sub /index cvx 0 0 0 } { dup (Magenta) eq { pop exch LookupTables length exch sub /index cvx 0 /exch cvx 0 0 } { (Yellow) eq { exch LookupTables length exch sub /index cvx 0 0 3 -1 /roll cvx 0 } { exch LookupTables length exch sub /index cvx 0 0 0 4 -1 /roll cvx } ifelse } ifelse } ifelse 5 -1 /roll cvx /astore cvx } { dup length 1 sub LookupTables length 4 -1 roll sub 1 add /index cvx /mul cvx /round cvx /cvi cvx /get cvx } ifelse Names length TTTablesIdx add 1 add 1 /roll cvx } for Names length [/pop cvx] cvx /repeat cvx NComponents Names length TintMethod /Subtractive eq { subtractive_blend } { additive_blend } ifelse ] cvx bdf } if AGMCORE_host_sep { Names convert_to_process { exec_tint_transform } { currentdict /AliasedColorants known { AliasedColorants not }{ false } ifelse 5 dict begin /AvoidAliasedColorants xdf /painted? false def /names_index 0 def /names_len Names length def AvoidAliasedColorants { /currentspotalias current_spot_alias def false set_spot_alias } if Names { AGMCORE_is_cmyk_sep { dup (Cyan) eq AGMCORE_cyan_plate and exch dup (Magenta) eq AGMCORE_magenta_plate and exch dup (Yellow) eq AGMCORE_yellow_plate and exch (Black) eq AGMCORE_black_plate and or or or { /devicen_colorspace_dict AGMCORE_gget /TintProc [ Names names_index /devn_makecustomcolor cvx ] cvx ddf /painted? true def } if painted? {exit} if }{ 0 0 0 0 5 -1 roll findcmykcustomcolor 1 setcustomcolor currentgray 0 eq { /devicen_colorspace_dict AGMCORE_gget /TintProc [ Names names_index /devn_makecustomcolor cvx ] cvx ddf /painted? true def exit } if } ifelse /names_index names_index 1 add def } forall AvoidAliasedColorants { currentspotalias set_spot_alias } if painted? { /devicen_colorspace_dict AGMCORE_gget /names_index names_index put }{ /devicen_colorspace_dict AGMCORE_gget /TintProc [ names_len [/pop cvx] cvx /repeat cvx 1 /setseparationgray cvx 0 0 0 0 /setcmykcolor cvx ] cvx ddf } ifelse end } ifelse } { AGMCORE_in_rip_sep { Names convert_to_process not }{ level3 } ifelse { [/DeviceN Names MappedCSA /TintTransform load] setcolorspace_opt /TintProc level3 not AGMCORE_in_rip_sep and { [ Names /length cvx [/pop cvx] cvx /repeat cvx ] cvx bdf }{ {setcolor} bdf } ifelse }{ exec_tint_transform } ifelse } ifelse set_crd /AliasedColorants false def end } def /setindexedcolorspace { dup /indexed_colorspace_dict exch AGMCORE_gput begin currentdict /CSDBase known { CSDBase /CSD get_res begin currentdict /Names known { currentdict devncs }{ 1 currentdict sepcs } ifelse AGMCORE_host_sep{ 4 dict begin /compCnt /Names where {pop Names length}{1}ifelse def /NewLookup HiVal 1 add string def 0 1 HiVal { /tableIndex xdf Lookup dup type /stringtype eq { compCnt tableIndex map_index }{ exec } ifelse /Names where { pop setdevicencolor }{ setsepcolor } ifelse currentgray tableIndex exch HiVal mul cvi NewLookup 3 1 roll put } for [/Indexed currentcolorspace HiVal NewLookup] setcolorspace_opt end }{ level3 { currentdict /Names known { [/Indexed [/DeviceN Names MappedCSA /TintTransform load] HiVal Lookup] setcolorspace_opt }{ [/Indexed [/Separation Name MappedCSA sep_proc_name load] HiVal Lookup] setcolorspace_opt } ifelse }{ [/Indexed MappedCSA HiVal [ currentdict /Names known { Lookup dup type /stringtype eq {/exch cvx CSDBase /CSD get_res /Names get length dup /mul cvx exch /getinterval cvx {255 div} /forall cvx} {/exec cvx}ifelse /TintTransform load /exec cvx }{ Lookup dup type /stringtype eq {/exch cvx /get cvx 255 /div cvx} {/exec cvx}ifelse CSDBase /CSD get_res /MappedCSA get sep_proc_name exch pop /load cvx /exec cvx } ifelse ]cvx ]setcolorspace_opt }ifelse } ifelse end set_crd } { CSA map_csa AGMCORE_host_sep level2 not and{ 0 0 0 0 setcmykcolor }{ [/Indexed MappedCSA level2 not has_color not and{ dup 0 get dup /DeviceRGB eq exch /DeviceCMYK eq or{ pop [/DeviceGray] }if HiVal GrayLookup }{ HiVal currentdict/RangeArray known{ { /indexed_colorspace_dict AGMCORE_gget begin Lookup exch dup HiVal gt{ pop HiVal }if NComponents mul NComponents getinterval {} forall NComponents 1 sub -1 0{ RangeArray exch 2 mul 2 getinterval aload pop map255_to_range NComponents 1 roll }for end } bind }{ Lookup }ifelse }ifelse ] setcolorspace_opt set_crd }ifelse }ifelse end }def /setindexedcolor { AGMCORE_host_sep { /indexed_colorspace_dict AGMCORE_gget dup /CSDBase known { begin CSDBase /CSD get_res begin currentdict /Names known{ map_indexed_devn devn } { Lookup 1 3 -1 roll map_index sep }ifelse end end }{ /Lookup get 4 3 -1 roll map_index setcmykcolor } ifelse }{ level3 not AGMCORE_in_rip_sep and /indexed_colorspace_dict AGMCORE_gget /CSDBase known and { /indexed_colorspace_dict AGMCORE_gget /CSDBase get /CSD get_res begin map_indexed_devn devn end } { setcolor } ifelse }ifelse } def /ignoreimagedata { currentoverprint not{ gsave dup clonedict begin 1 setgray /Decode [0 1] def /DataSource <FF> def /MultipleDataSources false def /BitsPerComponent 8 def currentdict end systemdict /image get exec grestore }if consumeimagedata }def /add_res { dup /CSD eq { pop //Adobe_AGM_Core begin /AGMCORE_CSD_cache load 3 1 roll put end }{ defineresource pop } ifelse }def /del_res { { aload pop exch dup /CSD eq { pop { //Adobe_AGM_Core/AGMCORE_CSD_cache get exch undef }forall }{ exch { 1 index undefineresource }forall pop } ifelse } forall }def /get_res { dup /CSD eq { pop dup type dup /nametype eq exch /stringtype eq or { AGMCORE_CSD_cache exch get } if }{ findresource } ifelse }def /get_csa_by_name { dup type dup /nametype eq exch /stringtype eq or{ /CSA get_res } if }def /pattern_buf_init { /count get 0 0 put } def /pattern_buf_next { dup /count get dup 0 get dup 3 1 roll 1 add 0 xpt get } def /cachepattern_compress { 5 dict begin currentfile exch 0 exch /SubFileDecode filter /ReadFilter exch def /patarray 20 dict def /string_size 16000 def /readbuffer string_size string def currentglobal true setglobal patarray 1 array dup 0 1 put /count xpt setglobal /LZWFilter { exch dup length 0 eq { pop }{ patarray dup length 1 sub 3 -1 roll put } ifelse {string_size}{0}ifelse string } /LZWEncode filter def { ReadFilter readbuffer readstring exch LZWFilter exch writestring not {exit} if } loop LZWFilter closefile patarray end }def /cachepattern { 2 dict begin currentfile exch 0 exch /SubFileDecode filter /ReadFilter exch def /patarray 20 dict def currentglobal true setglobal patarray 1 array dup 0 1 put /count xpt setglobal { ReadFilter 16000 string readstring exch patarray dup length 1 sub 3 -1 roll put not {exit} if } loop patarray dup dup length 1 sub () put end }def /wrap_paintproc { statusdict /currentfilenameextend known{ clonedict begin /OldPaintProc /PaintProc load def /PaintProc { mark exch dup /OldPaintProc get stopped {closefile restore end} if cleartomark } def end } {pop} ifelse } def /make_pattern { exch clonedict exch dup matrix currentmatrix matrix concatmatrix 0 0 3 2 roll itransform exch 3 index /XStep get 1 index exch 2 copy div cvi mul sub sub exch 3 index /YStep get 1 index exch 2 copy div cvi mul sub sub matrix translate exch matrix concatmatrix 1 index begin BBox 0 get XStep div cvi XStep mul /xshift exch neg def BBox 1 get YStep div cvi YStep mul /yshift exch neg def BBox 0 get xshift add BBox 1 get yshift add BBox 2 get xshift add BBox 3 get yshift add 4 array astore /BBox exch def [ xshift yshift /translate load null /exec load ] dup 3 /PaintProc load put cvx /PaintProc exch def end 1 index dup /ID get exch /Pattern add_res gsave 0 setgray makepattern grestore }def /set_pattern { dup /PatternType get 1 eq{ dup /PaintType get 1 eq{ currentoverprint sop [/DeviceGray] setcolorspace 0 setgray }if }if setpattern }def /setcolorspace_opt { dup currentcolorspace eq{ pop }{ setcolorspace }ifelse }def /updatecolorrendering { currentcolorrendering/RenderingIntent known{ currentcolorrendering/RenderingIntent get }{null}ifelse Intent ne { Intent /ColorRendering {findresource} stopped { pop pop systemdict /findcolorrendering known { Intent findcolorrendering pop /ColorRendering findresource true } {false} ifelse } {true} ifelse { dup begin currentdict /TransformPQR known { currentdict /TransformPQR get aload pop 3 {{} eq 3 1 roll} repeat or or } {true} ifelse currentdict /MatrixPQR known { currentdict /MatrixPQR get aload pop 1.0 eq 9 1 roll 0.0 eq 9 1 roll 0.0 eq 9 1 roll 0.0 eq 9 1 roll 1.0 eq 9 1 roll 0.0 eq 9 1 roll 0.0 eq 9 1 roll 0.0 eq 9 1 roll 1.0 eq and and and and and and and and } {true} ifelse end or { clonedict begin /TransformPQR [ {4 -1 roll 3 get dup 3 1 roll sub 5 -1 roll 3 get 3 -1 roll sub div 3 -1 roll 3 get 3 -1 roll 3 get dup 4 1 roll sub mul add} bind {4 -1 roll 4 get dup 3 1 roll sub 5 -1 roll 4 get 3 -1 roll sub div 3 -1 roll 4 get 3 -1 roll 4 get dup 4 1 roll sub mul add} bind {4 -1 roll 5 get dup 3 1 roll sub 5 -1 roll 5 get 3 -1 roll sub div 3 -1 roll 5 get 3 -1 roll 5 get dup 4 1 roll sub mul add} bind ] def /MatrixPQR [ 0.8951 -0.7502 0.0389 0.2664 1.7135 -0.0685 -0.1614 0.0367 1.0296 ] def /RangePQR [-0.3227950745 2.3229645538 -1.5003771057 3.5003465881 -0.1369979095 2.136967392] def currentdict end } if setcolorrendering_opt } if }if } def /set_crd { AGMCORE_host_sep not level2 and{ currentdict /ColorRendering known{ ColorRendering /ColorRendering {findresource} stopped not {setcolorrendering_opt} if }{ currentdict/Intent known{ updatecolorrendering }if }ifelse currentcolorspace dup type /arraytype eq {0 get}if /DeviceRGB eq { currentdict/UCR known {/UCR}{/AGMCORE_currentucr}ifelse load setundercolorremoval currentdict/BG known {/BG}{/AGMCORE_currentbg}ifelse load setblackgeneration }if }if }def /setcolorrendering_opt { dup currentcolorrendering eq{ pop }{ clonedict begin /Intent Intent def currentdict end setcolorrendering }ifelse }def /cpaint_gcomp { convert_to_process //Adobe_AGM_Core/AGMCORE_ConvertToProcess xddf //Adobe_AGM_Core/AGMCORE_ConvertToProcess get not { (%end_cpaint_gcomp) flushinput }if }def /cpaint_gsep { //Adobe_AGM_Core/AGMCORE_ConvertToProcess get { (%end_cpaint_gsep) flushinput }if }def /cpaint_gend { newpath }def /set_spot_alias_ary { dup inherit_aliases //Adobe_AGM_Core/AGMCORE_SpotAliasAry xddf }def /set_spot_normalization_ary { dup inherit_aliases dup length /AGMCORE_SpotAliasAry where{pop AGMCORE_SpotAliasAry length add} if array //Adobe_AGM_Core/AGMCORE_SpotAliasAry2 xddf /AGMCORE_SpotAliasAry where{ pop AGMCORE_SpotAliasAry2 0 AGMCORE_SpotAliasAry putinterval AGMCORE_SpotAliasAry length }{0} ifelse AGMCORE_SpotAliasAry2 3 1 roll exch putinterval true set_spot_alias }def /inherit_aliases { {dup /Name get map_alias {/CSD put}{pop} ifelse} forall }def /set_spot_alias { /AGMCORE_SpotAliasAry2 where{ /AGMCORE_current_spot_alias 3 -1 roll put }{ pop }ifelse }def /current_spot_alias { /AGMCORE_SpotAliasAry2 where{ /AGMCORE_current_spot_alias get }{ false }ifelse }def /map_alias { /AGMCORE_SpotAliasAry2 where{ begin /AGMCORE_name xdf false AGMCORE_SpotAliasAry2{ dup/Name get AGMCORE_name eq{ /CSD get /CSD get_res exch pop true exit }{ pop }ifelse }forall end }{ pop false }ifelse }bdf /spot_alias { true set_spot_alias /AGMCORE_&setcustomcolor AGMCORE_key_known not { //Adobe_AGM_Core/AGMCORE_&setcustomcolor /setcustomcolor load put } if /customcolor_tint 1 AGMCORE_gput //Adobe_AGM_Core begin /setcustomcolor { currentdict/TintProc known currentdict/CSA known and 3 1 roll //Adobe_AGM_Core begin dup /customcolor_tint exch AGMCORE_gput 1 index aload pop pop 1 eq exch 1 eq and exch 1 eq and exch 1 eq and not current_spot_alias and{1 index 4 get map_alias}{false}ifelse { false set_spot_alias 4 -1 roll{ exch pop /sep_tint AGMCORE_gget exch }if mark 3 1 roll setsepcolorspace counttomark 0 ne{ setsepcolor }if pop pop true set_spot_alias }{ AGMCORE_&setcustomcolor pop }ifelse end }bdf end }def /begin_feature { Adobe_AGM_Core/AGMCORE_feature_dictCount countdictstack put count Adobe_AGM_Core/AGMCORE_feature_opCount 3 -1 roll put {Adobe_AGM_Core/AGMCORE_feature_ctm matrix currentmatrix put}if }def /end_feature { 2 dict begin /spd /setpagedevice load def /setpagedevice { get_gstate spd set_gstate } def stopped{$error/newerror false put}if end count Adobe_AGM_Core/AGMCORE_feature_opCount get sub dup 0 gt{{pop}repeat}{pop}ifelse countdictstack Adobe_AGM_Core/AGMCORE_feature_dictCount get sub dup 0 gt{{end}repeat}{pop}ifelse {Adobe_AGM_Core/AGMCORE_feature_ctm get setmatrix}if }def /set_negative { //Adobe_AGM_Core begin /AGMCORE_inverting exch def level2{ currentpagedevice/NegativePrint known{ currentpagedevice/NegativePrint get //Adobe_AGM_Core/AGMCORE_inverting get ne{ true begin_feature true{ << /NegativePrint //Adobe_AGM_Core/AGMCORE_inverting get >> setpagedevice }end_feature }if /AGMCORE_inverting false def }if }if AGMCORE_inverting{ [{1 exch sub}/exec load dup currenttransfer exch]cvx bind settransfer gsave newpath clippath 1 /setseparationgray where{pop setseparationgray}{setgray}ifelse /AGMIRS_&fill where {pop AGMIRS_&fill}{fill} ifelse grestore }if end }def /lw_save_restore_override { /md where { pop md begin initializepage /initializepage{}def /pmSVsetup{} def /endp{}def /pse{}def /psb{}def /orig_showpage where {pop} {/orig_showpage /showpage load def} ifelse /showpage {orig_showpage gR} def end }if }def /pscript_showpage_override { /NTPSOct95 where { begin showpage save /showpage /restore load def /restore {exch pop}def end }if }def /driver_media_override { /md where { pop md /initializepage known { md /initializepage {} put } if md /rC known { md /rC {4{pop}repeat} put } if }if /mysetup where { /mysetup [1 0 0 1 0 0] put }if Adobe_AGM_Core /AGMCORE_Default_CTM matrix currentmatrix put level2 {Adobe_AGM_Core /AGMCORE_Default_PageSize currentpagedevice/PageSize get put}if }def /driver_check_media_override { /PrepsDict where {pop} { Adobe_AGM_Core /AGMCORE_Default_CTM get matrix currentmatrix ne Adobe_AGM_Core /AGMCORE_Default_PageSize get type /arraytype eq { Adobe_AGM_Core /AGMCORE_Default_PageSize get 0 get currentpagedevice/PageSize get 0 get eq and Adobe_AGM_Core /AGMCORE_Default_PageSize get 1 get currentpagedevice/PageSize get 1 get eq and }if { Adobe_AGM_Core /AGMCORE_Default_CTM get setmatrix }if }ifelse }def AGMCORE_err_strings begin /AGMCORE_bad_environ (Environment not satisfactory for this job. Ensure that the PPD is correct or that the PostScript level requested is supported by this printer. ) def /AGMCORE_color_space_onhost_seps (This job contains colors that will not separate with on-host methods. ) def /AGMCORE_invalid_color_space (This job contains an invalid color space. ) def end /set_def_ht { AGMCORE_def_ht sethalftone } def end systemdict /setpacking known { setpacking } if %%EndResource %%BeginResource: procset Adobe_CoolType_Core 2.25 0 %%Copyright: Copyright 1997-2005 Adobe Systems Incorporated. All Rights Reserved. %%Version: 2.25 0 10 dict begin /Adobe_CoolType_Passthru currentdict def /Adobe_CoolType_Core_Defined userdict /Adobe_CoolType_Core known def Adobe_CoolType_Core_Defined { /Adobe_CoolType_Core userdict /Adobe_CoolType_Core get def } if userdict /Adobe_CoolType_Core 60 dict dup begin put /Adobe_CoolType_Version 2.25 def /Level2? systemdict /languagelevel known dup { pop systemdict /languagelevel get 2 ge } if def Level2? not { /currentglobal false def /setglobal /pop load def /gcheck { pop false } bind def /currentpacking false def /setpacking /pop load def /SharedFontDirectory 0 dict def } if currentpacking true setpacking currentglobal false setglobal userdict /Adobe_CoolType_Data 2 copy known not { 2 copy 10 dict put } if get begin /@opStackCountByLevel 32 dict def /@opStackLevel 0 def /@dictStackCountByLevel 32 dict def /@dictStackLevel 0 def end setglobal /@_SaveStackLevels { Adobe_CoolType_Data begin /@vmState currentglobal def false setglobal @opStackCountByLevel @opStackLevel 2 copy known not { 2 copy 3 dict dup /args 7 index 5 add array put put get } { get dup /args get dup length 3 index lt { dup length 5 add array exch 1 index exch 0 exch putinterval 1 index exch /args exch put } { pop } ifelse } ifelse begin count 1 sub 1 index lt { pop count } if dup /argCount exch def dup 0 gt { args exch 0 exch getinterval astore pop } { pop } ifelse count /restCount exch def end /@opStackLevel @opStackLevel 1 add def countdictstack 1 sub @dictStackCountByLevel exch @dictStackLevel exch put /@dictStackLevel @dictStackLevel 1 add def @vmState setglobal end } bind def /@_RestoreStackLevels { Adobe_CoolType_Data begin /@opStackLevel @opStackLevel 1 sub def @opStackCountByLevel @opStackLevel get begin count restCount sub dup 0 gt { { pop } repeat } { pop } ifelse args 0 argCount getinterval {} forall end /@dictStackLevel @dictStackLevel 1 sub def @dictStackCountByLevel @dictStackLevel get end countdictstack exch sub dup 0 gt { { end } repeat } { pop } ifelse } bind def /@_PopStackLevels { Adobe_CoolType_Data begin /@opStackLevel @opStackLevel 1 sub def /@dictStackLevel @dictStackLevel 1 sub def end } bind def /@Raise { exch cvx exch errordict exch get exec stop } bind def /@ReRaise { cvx $error /errorname get errordict exch get exec stop } bind def /@Stopped { 0 @#Stopped } bind def /@#Stopped { @_SaveStackLevels stopped { @_RestoreStackLevels true } { @_PopStackLevels false } ifelse } bind def /@Arg { Adobe_CoolType_Data begin @opStackCountByLevel @opStackLevel 1 sub get begin args exch argCount 1 sub exch sub get end end } bind def currentglobal true setglobal /CTHasResourceForAllBug Level2? { 1 dict dup /@shouldNotDisappearDictValue true def Adobe_CoolType_Data exch /@shouldNotDisappearDict exch put begin count @_SaveStackLevels { (*) { pop stop } 128 string /Category resourceforall } stopped pop @_RestoreStackLevels currentdict Adobe_CoolType_Data /@shouldNotDisappearDict get ne dup { /@shouldNotDisappearDictValue known { { end currentdict 1 index eq { pop exit } if } loop } if } if end } { false } ifelse def true setglobal /CTHasResourceStatusBug Level2? { mark { /steveamerige /Category resourcestatus } stopped { cleartomark true } { cleartomark currentglobal not } ifelse } { false } ifelse def setglobal /CTResourceStatus { mark 3 1 roll /Category findresource begin ({ResourceStatus} stopped) 0 () /SubFileDecode filter cvx exec { cleartomark false } { { 3 2 roll pop true } { cleartomark false } ifelse } ifelse end } bind def /CTWorkAroundBugs { Level2? { /cid_PreLoad /ProcSet resourcestatus { pop pop currentglobal mark { (*) { dup /CMap CTHasResourceStatusBug { CTResourceStatus } { resourcestatus } ifelse { pop dup 0 eq exch 1 eq or { dup /CMap findresource gcheck setglobal /CMap undefineresource } { pop CTHasResourceForAllBug { exit } { stop } ifelse } ifelse } { pop } ifelse } 128 string /CMap resourceforall } stopped { cleartomark } stopped pop setglobal } if } if } bind def /doc_setup { Adobe_CoolType_Core begin CTWorkAroundBugs /mov /moveto load def /nfnt /newencodedfont load def /mfnt /makefont load def /sfnt /setfont load def /ufnt /undefinefont load def /chp /charpath load def /awsh /awidthshow load def /wsh /widthshow load def /ash /ashow load def /sh /show load def end currentglobal false setglobal userdict /Adobe_CoolType_Data 2 copy known not { 2 copy 10 dict put } if get begin /AddWidths? false def /CC 0 def /charcode 2 string def /@opStackCountByLevel 32 dict def /@opStackLevel 0 def /@dictStackCountByLevel 32 dict def /@dictStackLevel 0 def /InVMFontsByCMap 10 dict def /InVMDeepCopiedFonts 10 dict def end setglobal } bind def /doc_trailer { currentdict Adobe_CoolType_Core eq { end } if } bind def /page_setup { Adobe_CoolType_Core begin } bind def /page_trailer { end } bind def /unload { systemdict /languagelevel known { systemdict/languagelevel get 2 ge { userdict/Adobe_CoolType_Core 2 copy known { undef } { pop pop } ifelse } if } if } bind def /ndf { 1 index where { pop pop pop } { dup xcheck { bind } if def } ifelse } def /findfont systemdict begin userdict begin /globaldict where { /globaldict get begin } if dup where pop exch get /globaldict where { pop end } if end end Adobe_CoolType_Core_Defined { /systemfindfont exch def } { /findfont 1 index def /systemfindfont exch def } ifelse /undefinefont { pop } ndf /copyfont { currentglobal 3 1 roll 1 index gcheck setglobal dup null eq { 0 } { dup length } ifelse 2 index length add 1 add dict begin exch { 1 index /FID eq { pop pop } { def } ifelse } forall dup null eq { pop } { { def } forall } ifelse currentdict end exch setglobal } bind def /copyarray { currentglobal exch dup gcheck setglobal dup length array copy exch setglobal } bind def /newencodedfont { currentglobal { SharedFontDirectory 3 index known { SharedFontDirectory 3 index get /FontReferenced known } { false } ifelse } { FontDirectory 3 index known { FontDirectory 3 index get /FontReferenced known } { SharedFontDirectory 3 index known { SharedFontDirectory 3 index get /FontReferenced known } { false } ifelse } ifelse } ifelse dup { 3 index findfont /FontReferenced get 2 index dup type /nametype eq {findfont} if ne { pop false } if } if { pop 1 index findfont /Encoding get exch 0 1 255 { 2 copy get 3 index 3 1 roll put } for pop pop pop } { dup type /nametype eq { findfont } if dup dup maxlength 2 add dict begin exch { 1 index /FID ne {def} {pop pop} ifelse } forall /FontReferenced exch def /Encoding exch dup length array copy def /FontName 1 index dup type /stringtype eq { cvn } if def dup currentdict end definefont def } ifelse } bind def /SetSubstituteStrategy { $SubstituteFont begin dup type /dicttype ne { 0 dict } if currentdict /$Strategies known { exch $Strategies exch 2 copy known { get 2 copy maxlength exch maxlength add dict begin { def } forall { def } forall currentdict dup /$Init known { dup /$Init get exec } if end /$Strategy exch def } { pop pop pop } ifelse } { pop pop } ifelse end } bind def /scff { $SubstituteFont begin dup type /stringtype eq { dup length exch } { null } ifelse /$sname exch def /$slen exch def /$inVMIndex $sname null eq { 1 index $str cvs dup length $slen sub $slen getinterval cvn } { $sname } ifelse def end { findfont } @Stopped { dup length 8 add string exch 1 index 0 (BadFont:) putinterval 1 index exch 8 exch dup length string cvs putinterval cvn { findfont } @Stopped { pop /Courier findfont } if } if $SubstituteFont begin /$sname null def /$slen 0 def /$inVMIndex null def end } bind def /isWidthsOnlyFont { dup /WidthsOnly known { pop pop true } { dup /FDepVector known { /FDepVector get { isWidthsOnlyFont dup { exit } if } forall } { dup /FDArray known { /FDArray get { isWidthsOnlyFont dup { exit } if } forall } { pop } ifelse } ifelse } ifelse } bind def /?str1 256 string def /?set { $SubstituteFont begin /$substituteFound false def /$fontname 4 index def /$doSmartSub false def end 3 index currentglobal false setglobal exch /CompatibleFonts /ProcSet resourcestatus { pop pop /CompatibleFonts /ProcSet findresource begin dup /CompatibleFont currentexception 1 index /CompatibleFont true setexception 1 index /Font resourcestatus { pop pop 3 2 roll setglobal end exch dup findfont /CompatibleFonts /ProcSet findresource begin 3 1 roll exch /CompatibleFont exch setexception end } { 3 2 roll setglobal 1 index exch /CompatibleFont exch setexception end findfont $SubstituteFont /$substituteFound true put } ifelse } { exch setglobal findfont } ifelse $SubstituteFont begin $substituteFound { false (%%[Using embedded font ) print 5 index ?str1 cvs print ( to avoid the font substitution problem noted earlier.]%%\n) print } { dup /FontName known { dup /FontName get $fontname eq 1 index /DistillerFauxFont known not and /currentdistillerparams where { pop false 2 index isWidthsOnlyFont not and } if } { false } ifelse } ifelse exch pop /$doSmartSub true def end { exch pop exch pop exch 2 dict dup /Found 3 index put exch findfont exch } { exch exec exch dup findfont dup /FontType get 3 eq { exch ?str1 cvs dup length 1 sub -1 0 { exch dup 2 index get 42 eq { exch 0 exch getinterval cvn 4 1 roll 3 2 roll pop exit } {exch pop} ifelse }for } { exch pop } ifelse 2 dict dup /Downloaded 6 5 roll put } ifelse dup /FontName 4 index put copyfont definefont pop } bind def /?str2 256 string def /?add { 1 index type /integertype eq { exch true 4 2 } { false 3 1 } ifelse roll 1 index findfont dup /Widths known { Adobe_CoolType_Data /AddWidths? true put gsave dup 1000 scalefont setfont } if /Downloaded known { exec exch { exch ?str2 cvs exch findfont /Downloaded get 1 dict begin /Downloaded 1 index def ?str1 cvs length ?str1 1 index 1 add 3 index putinterval exch length 1 add 1 index add ?str1 2 index (*) putinterval ?str1 0 2 index getinterval cvn findfont ?str1 3 index (+) putinterval 2 dict dup /FontName ?str1 0 6 index getinterval cvn put dup /Downloaded Downloaded put end copyfont dup /FontName get exch definefont pop pop pop } { pop } ifelse } { pop exch { findfont dup /Found get dup length exch ?str1 cvs pop ?str1 1 index (+) putinterval ?str1 1 index 1 add 4 index ?str2 cvs putinterval ?str1 exch 0 exch 5 4 roll ?str2 cvs length 1 add add getinterval cvn 1 dict exch 1 index exch /FontName exch put copyfont dup /FontName get exch definefont pop } { pop } ifelse } ifelse Adobe_CoolType_Data /AddWidths? get { grestore Adobe_CoolType_Data /AddWidths? false put } if } bind def /?sh { currentfont /Downloaded known { exch } if pop } bind def /?chp { currentfont /Downloaded known { pop } { false chp } ifelse } bind def /?mv { currentfont /Downloaded known { moveto pop pop } { pop pop moveto } ifelse } bind def setpacking userdict /$SubstituteFont 25 dict put 1 dict begin /SubstituteFont dup $error exch 2 copy known { get } { pop pop { pop /Courier } bind } ifelse def /currentdistillerparams where dup { pop pop currentdistillerparams /CannotEmbedFontPolicy 2 copy known { get /Error eq } { pop pop false } ifelse } if not { countdictstack array dictstack 0 get begin userdict begin $SubstituteFont begin /$str 128 string def /$fontpat 128 string def /$slen 0 def /$sname null def /$match false def /$fontname null def /$substituteFound false def /$inVMIndex null def /$doSmartSub true def /$depth 0 def /$fontname null def /$italicangle 26.5 def /$dstack null def /$Strategies 10 dict dup begin /$Type3Underprint { currentglobal exch false setglobal 11 dict begin /UseFont exch $WMode 0 ne { dup length dict copy dup /WMode $WMode put /UseFont exch definefont } if def /FontName $fontname dup type /stringtype eq { cvn } if def /FontType 3 def /FontMatrix [ .001 0 0 .001 0 0 ] def /Encoding 256 array dup 0 1 255 { /.notdef put dup } for pop def /FontBBox [ 0 0 0 0 ] def /CCInfo 7 dict dup begin /cc null def /x 0 def /y 0 def end def /BuildChar { exch begin CCInfo begin 1 string dup 0 3 index put exch pop /cc exch def UseFont 1000 scalefont setfont cc stringwidth /y exch def /x exch def x y setcharwidth $SubstituteFont /$Strategy get /$Underprint get exec 0 0 moveto cc show x y moveto end end } bind def currentdict end exch setglobal } bind def /$GetaTint 2 dict dup begin /$BuildFont { dup /WMode known { dup /WMode get } { 0 } ifelse /$WMode exch def $fontname exch dup /FontName known { dup /FontName get dup type /stringtype eq { cvn } if } { /unnamedfont } ifelse exch Adobe_CoolType_Data /InVMDeepCopiedFonts get 1 index /FontName get known { pop Adobe_CoolType_Data /InVMDeepCopiedFonts get 1 index get null copyfont } { $deepcopyfont } ifelse exch 1 index exch /FontBasedOn exch put dup /FontName $fontname dup type /stringtype eq { cvn } if put definefont Adobe_CoolType_Data /InVMDeepCopiedFonts get begin dup /FontBasedOn get 1 index def end } bind def /$Underprint { gsave x abs y abs gt { /y 1000 def } { /x -1000 def 500 120 translate } ifelse Level2? { [ /Separation (All) /DeviceCMYK { 0 0 0 1 pop } ] setcolorspace } { 0 setgray } ifelse 10 setlinewidth x .8 mul [ 7 3 ] { y mul 8 div 120 sub x 10 div exch moveto 0 y 4 div neg rlineto dup 0 rlineto 0 y 4 div rlineto closepath gsave Level2? { .2 setcolor } { .8 setgray } ifelse fill grestore stroke } forall pop grestore } bind def end def /$Oblique 1 dict dup begin /$BuildFont { currentglobal exch dup gcheck setglobal null copyfont begin /FontBasedOn currentdict /FontName known { FontName dup type /stringtype eq { cvn } if } { /unnamedfont } ifelse def /FontName $fontname dup type /stringtype eq { cvn } if def /currentdistillerparams where { pop } { /FontInfo currentdict /FontInfo known { FontInfo null copyfont } { 2 dict } ifelse dup begin /ItalicAngle $italicangle def /FontMatrix FontMatrix [ 1 0 ItalicAngle dup sin exch cos div 1 0 0 ] matrix concatmatrix readonly end 4 2 roll def def } ifelse FontName currentdict end definefont exch setglobal } bind def end def /$None 1 dict dup begin /$BuildFont {} bind def end def end def /$Oblique SetSubstituteStrategy /$findfontByEnum { dup type /stringtype eq { cvn } if dup /$fontname exch def $sname null eq { $str cvs dup length $slen sub $slen getinterval } { pop $sname } ifelse $fontpat dup 0 (fonts/*) putinterval exch 7 exch putinterval /$match false def $SubstituteFont /$dstack countdictstack array dictstack put mark { $fontpat 0 $slen 7 add getinterval { /$match exch def exit } $str filenameforall } stopped { cleardictstack currentdict true $SubstituteFont /$dstack get { exch { 1 index eq { pop false } { true } ifelse } { begin false } ifelse } forall pop } if cleartomark /$slen 0 def $match false ne { $match (fonts/) anchorsearch pop pop cvn } { /Courier } ifelse } bind def /$ROS 1 dict dup begin /Adobe 4 dict dup begin /Japan1 [ /Ryumin-Light /HeiseiMin-W3 /GothicBBB-Medium /HeiseiKakuGo-W5 /HeiseiMaruGo-W4 /Jun101-Light ] def /Korea1 [ /HYSMyeongJo-Medium /HYGoThic-Medium ] def /GB1 [ /STSong-Light /STHeiti-Regular ] def /CNS1 [ /MKai-Medium /MHei-Medium ] def end def end def /$cmapname null def /$deepcopyfont { dup /FontType get 0 eq { 1 dict dup /FontName /copied put copyfont begin /FDepVector FDepVector copyarray 0 1 2 index length 1 sub { 2 copy get $deepcopyfont dup /FontName /copied put /copied exch definefont 3 copy put pop pop } for def currentdict end } { $Strategies /$Type3Underprint get exec } ifelse } bind def /$buildfontname { dup /CIDFont findresource /CIDSystemInfo get begin Registry length Ordering length Supplement 8 string cvs 3 copy length 2 add add add string dup 5 1 roll dup 0 Registry putinterval dup 4 index (-) putinterval dup 4 index 1 add Ordering putinterval 4 2 roll add 1 add 2 copy (-) putinterval end 1 add 2 copy 0 exch getinterval $cmapname $fontpat cvs exch anchorsearch { pop pop 3 2 roll putinterval cvn /$cmapname exch def } { pop pop pop pop pop } ifelse length $str 1 index (-) putinterval 1 add $str 1 index $cmapname $fontpat cvs putinterval $cmapname length add $str exch 0 exch getinterval cvn } bind def /$findfontByROS { /$fontname exch def $ROS Registry 2 copy known { get Ordering 2 copy known { get } { pop pop [] } ifelse } { pop pop [] } ifelse false exch { dup /CIDFont resourcestatus { pop pop save 1 index /CIDFont findresource dup /WidthsOnly known { dup /WidthsOnly get } { false } ifelse exch pop exch restore { pop } { exch pop true exit } ifelse } { pop } ifelse } forall { $str cvs $buildfontname } { false (*) { save exch dup /CIDFont findresource dup /WidthsOnly known { dup /WidthsOnly get not } { true } ifelse exch /CIDSystemInfo get dup /Registry get Registry eq exch /Ordering get Ordering eq and and { exch restore exch pop true exit } { pop restore } ifelse } $str /CIDFont resourceforall { $buildfontname } { $fontname $findfontByEnum } ifelse } ifelse } bind def end end currentdict /$error known currentdict /languagelevel known and dup { pop $error /SubstituteFont known } if dup { $error } { Adobe_CoolType_Core } ifelse begin { /SubstituteFont /CMap /Category resourcestatus { pop pop { $SubstituteFont begin /$substituteFound true def dup length $slen gt $sname null ne or $slen 0 gt and { $sname null eq { dup $str cvs dup length $slen sub $slen getinterval cvn } { $sname } ifelse Adobe_CoolType_Data /InVMFontsByCMap get 1 index 2 copy known { get false exch { pop currentglobal { GlobalFontDirectory 1 index known { exch pop true exit } { pop } ifelse } { FontDirectory 1 index known { exch pop true exit } { GlobalFontDirectory 1 index known { exch pop true exit } { pop } ifelse } ifelse } ifelse } forall } { pop pop false } ifelse { exch pop exch pop } { dup /CMap resourcestatus { pop pop dup /$cmapname exch def /CMap findresource /CIDSystemInfo get { def } forall $findfontByROS } { 128 string cvs dup (-) search { 3 1 roll search { 3 1 roll pop { dup cvi } stopped { pop pop pop pop pop $findfontByEnum } { 4 2 roll pop pop exch length exch 2 index length 2 index sub exch 1 sub -1 0 { $str cvs dup length 4 index 0 4 index 4 3 roll add getinterval exch 1 index exch 3 index exch putinterval dup /CMap resourcestatus { pop pop 4 1 roll pop pop pop dup /$cmapname exch def /CMap findresource /CIDSystemInfo get { def } forall $findfontByROS true exit } { pop } ifelse } for dup type /booleantype eq { pop } { pop pop pop $findfontByEnum } ifelse } ifelse } { pop pop pop $findfontByEnum } ifelse } { pop pop $findfontByEnum } ifelse } ifelse } ifelse } { //SubstituteFont exec } ifelse /$slen 0 def end } } { { $SubstituteFont begin /$substituteFound true def dup length $slen gt $sname null ne or $slen 0 gt and { $findfontByEnum } { //SubstituteFont exec } ifelse end } } ifelse bind readonly def Adobe_CoolType_Core /scfindfont /systemfindfont load put } { /scfindfont { $SubstituteFont begin dup systemfindfont dup /FontName known { dup /FontName get dup 3 index ne } { /noname true } ifelse dup { /$origfontnamefound 2 index def /$origfontname 4 index def /$substituteFound true def } if exch pop { $slen 0 gt $sname null ne 3 index length $slen gt or and { pop dup $findfontByEnum findfont dup maxlength 1 add dict begin { 1 index /FID eq { pop pop } { def } ifelse } forall currentdict end definefont dup /FontName known { dup /FontName get } { null } ifelse $origfontnamefound ne { $origfontname $str cvs print ( substitution revised, using ) print dup /FontName known { dup /FontName get } { (unspecified font) } ifelse $str cvs print (.\n) print } if } { exch pop } ifelse } { exch pop } ifelse end } bind def } ifelse end end Adobe_CoolType_Core_Defined not { Adobe_CoolType_Core /findfont { $SubstituteFont begin $depth 0 eq { /$fontname 1 index dup type /stringtype ne { $str cvs } if def /$substituteFound false def } if /$depth $depth 1 add def end scfindfont $SubstituteFont begin /$depth $depth 1 sub def $substituteFound $depth 0 eq and { $inVMIndex null ne { dup $inVMIndex $AddInVMFont } if $doSmartSub { currentdict /$Strategy known { $Strategy /$BuildFont get exec } if } if } if end } bind put } if } if end /$AddInVMFont { exch /FontName 2 copy known { get 1 dict dup begin exch 1 index gcheck def end exch Adobe_CoolType_Data /InVMFontsByCMap get exch $DictAdd } { pop pop pop } ifelse } bind def /$DictAdd { 2 copy known not { 2 copy 4 index length dict put } if Level2? not { 2 copy get dup maxlength exch length 4 index length add lt 2 copy get dup length 4 index length add exch maxlength 1 index lt { 2 mul dict begin 2 copy get { forall } def 2 copy currentdict put end } { pop } ifelse } if get begin { def } forall end } bind def end end %%EndResource %%BeginResource: procset Adobe_CoolType_Utility_MAKEOCF 1.21 0 %%Copyright: Copyright 1987-2005 Adobe Systems Incorporated. %%Version: 1.21 0 systemdict /languagelevel known dup { currentglobal false setglobal } { false } ifelse exch userdict /Adobe_CoolType_Utility 2 copy known { 2 copy get dup maxlength 27 add dict copy } { 27 dict } ifelse put Adobe_CoolType_Utility begin /@eexecStartData <BAB431EA07F209EB8C4348311481D9D3F76E3D15246555577D87BC510ED54E 118C39697FA9F6DB58128E60EB8A12FA24D7CDD2FA94D221FA9EC8DA3E5E6A1C 4ACECC8C2D39C54E7C946031DD156C3A6B4A09AD29E1867A> def /@recognizeCIDFont null def /ct_Level2? exch def /ct_Clone? 1183615869 internaldict dup /CCRun known not exch /eCCRun known not ct_Level2? and or def ct_Level2? { globaldict begin currentglobal true setglobal } if /ct_AddStdCIDMap ct_Level2? { { mark Adobe_CoolType_Utility /@recognizeCIDFont currentdict put { ((Hex) 57 StartData 0615 1e27 2c39 1c60 d8a8 cc31 fe2b f6e0 7aa3 e541 e21c 60d8 a8c9 c3d0 6d9e 1c60 d8a8 c9c2 02d7 9a1c 60d8 a849 1c60 d8a8 cc36 74f4 1144 b13b 77) 0 () /SubFileDecode filter cvx exec } stopped { cleartomark Adobe_CoolType_Utility /@recognizeCIDFont get countdictstack dup array dictstack exch 1 sub -1 0 { 2 copy get 3 index eq { 1 index length exch sub 1 sub { end } repeat exit } { pop } ifelse } for pop pop Adobe_CoolType_Utility /@eexecStartData get eexec } { cleartomark } ifelse } } { { Adobe_CoolType_Utility /@eexecStartData get eexec } } ifelse bind def userdict /cid_extensions known dup { cid_extensions /cid_UpdateDB known and } if { cid_extensions begin /cid_GetCIDSystemInfo { 1 index type /stringtype eq { exch cvn exch } if cid_extensions begin dup load 2 index known { 2 copy cid_GetStatusInfo dup null ne { 1 index load 3 index get dup null eq { pop pop cid_UpdateDB } { exch 1 index /Created get eq { exch pop exch pop } { pop cid_UpdateDB } ifelse } ifelse } { pop cid_UpdateDB } ifelse } { cid_UpdateDB } ifelse end } bind def end } if ct_Level2? { end setglobal } if /ct_UseNativeCapability? systemdict /composefont known def /ct_MakeOCF 35 dict def /ct_Vars 25 dict def /ct_GlyphDirProcs 6 dict def /ct_BuildCharDict 15 dict dup begin /charcode 2 string def /dst_string 1500 string def /nullstring () def /usewidths? true def end def ct_Level2? { setglobal } { pop } ifelse ct_GlyphDirProcs begin /GetGlyphDirectory { systemdict /languagelevel known { pop /CIDFont findresource /GlyphDirectory get } { 1 index /CIDFont findresource /GlyphDirectory get dup type /dicttype eq { dup dup maxlength exch length sub 2 index lt { dup length 2 index add dict copy 2 index /CIDFont findresource/GlyphDirectory 2 index put } if } if exch pop exch pop } ifelse + } def /+ { systemdict /languagelevel known { currentglobal false setglobal 3 dict begin /vm exch def } { 1 dict begin } ifelse /$ exch def systemdict /languagelevel known { vm setglobal /gvm currentglobal def $ gcheck setglobal } if ? { $ begin } if } def /? { $ type /dicttype eq } def /| { userdict /Adobe_CoolType_Data known { Adobe_CoolType_Data /AddWidths? known { currentdict Adobe_CoolType_Data begin begin AddWidths? { Adobe_CoolType_Data /CC 3 index put ? { def } { $ 3 1 roll put } ifelse CC charcode exch 1 index 0 2 index 256 idiv put 1 index exch 1 exch 256 mod put stringwidth 2 array astore currentfont /Widths get exch CC exch put } { ? { def } { $ 3 1 roll put } ifelse } ifelse end end } { ? { def } { $ 3 1 roll put } ifelse } ifelse } { ? { def } { $ 3 1 roll put } ifelse } ifelse } def /! { ? { end } if systemdict /languagelevel known { gvm setglobal } if end } def /: { string currentfile exch readstring pop } executeonly def end ct_MakeOCF begin /ct_cHexEncoding [/c00/c01/c02/c03/c04/c05/c06/c07/c08/c09/c0A/c0B/c0C/c0D/c0E/c0F/c10/c11/c12 /c13/c14/c15/c16/c17/c18/c19/c1A/c1B/c1C/c1D/c1E/c1F/c20/c21/c22/c23/c24/c25 /c26/c27/c28/c29/c2A/c2B/c2C/c2D/c2E/c2F/c30/c31/c32/c33/c34/c35/c36/c37/c38 /c39/c3A/c3B/c3C/c3D/c3E/c3F/c40/c41/c42/c43/c44/c45/c46/c47/c48/c49/c4A/c4B /c4C/c4D/c4E/c4F/c50/c51/c52/c53/c54/c55/c56/c57/c58/c59/c5A/c5B/c5C/c5D/c5E /c5F/c60/c61/c62/c63/c64/c65/c66/c67/c68/c69/c6A/c6B/c6C/c6D/c6E/c6F/c70/c71 /c72/c73/c74/c75/c76/c77/c78/c79/c7A/c7B/c7C/c7D/c7E/c7F/c80/c81/c82/c83/c84 /c85/c86/c87/c88/c89/c8A/c8B/c8C/c8D/c8E/c8F/c90/c91/c92/c93/c94/c95/c96/c97 /c98/c99/c9A/c9B/c9C/c9D/c9E/c9F/cA0/cA1/cA2/cA3/cA4/cA5/cA6/cA7/cA8/cA9/cAA /cAB/cAC/cAD/cAE/cAF/cB0/cB1/cB2/cB3/cB4/cB5/cB6/cB7/cB8/cB9/cBA/cBB/cBC/cBD /cBE/cBF/cC0/cC1/cC2/cC3/cC4/cC5/cC6/cC7/cC8/cC9/cCA/cCB/cCC/cCD/cCE/cCF/cD0 /cD1/cD2/cD3/cD4/cD5/cD6/cD7/cD8/cD9/cDA/cDB/cDC/cDD/cDE/cDF/cE0/cE1/cE2/cE3 /cE4/cE5/cE6/cE7/cE8/cE9/cEA/cEB/cEC/cED/cEE/cEF/cF0/cF1/cF2/cF3/cF4/cF5/cF6 /cF7/cF8/cF9/cFA/cFB/cFC/cFD/cFE/cFF] def /ct_CID_STR_SIZE 8000 def /ct_mkocfStr100 100 string def /ct_defaultFontMtx [.001 0 0 .001 0 0] def /ct_1000Mtx [1000 0 0 1000 0 0] def /ct_raise {exch cvx exch errordict exch get exec stop} bind def /ct_reraise { cvx $error /errorname get (Error: ) print dup ( ) cvs print errordict exch get exec stop } bind def /ct_cvnsi { 1 index add 1 sub 1 exch 0 4 1 roll { 2 index exch get exch 8 bitshift add } for exch pop } bind def /ct_GetInterval { Adobe_CoolType_Utility /ct_BuildCharDict get begin /dst_index 0 def dup dst_string length gt { dup string /dst_string exch def } if 1 index ct_CID_STR_SIZE idiv /arrayIndex exch def 2 index arrayIndex get 2 index arrayIndex ct_CID_STR_SIZE mul sub { dup 3 index add 2 index length le { 2 index getinterval dst_string dst_index 2 index putinterval length dst_index add /dst_index exch def exit } { 1 index length 1 index sub dup 4 1 roll getinterval dst_string dst_index 2 index putinterval pop dup dst_index add /dst_index exch def sub /arrayIndex arrayIndex 1 add def 2 index dup length arrayIndex gt { arrayIndex get } { pop exit } ifelse 0 } ifelse } loop pop pop pop dst_string 0 dst_index getinterval end } bind def ct_Level2? { /ct_resourcestatus currentglobal mark true setglobal { /unknowninstancename /Category resourcestatus } stopped { cleartomark setglobal true } { cleartomark currentglobal not exch setglobal } ifelse { { mark 3 1 roll /Category findresource begin ct_Vars /vm currentglobal put ({ResourceStatus} stopped) 0 () /SubFileDecode filter cvx exec { cleartomark false } { { 3 2 roll pop true } { cleartomark false } ifelse } ifelse ct_Vars /vm get setglobal end } } { { resourcestatus } } ifelse bind def /CIDFont /Category ct_resourcestatus { pop pop } { currentglobal true setglobal /Generic /Category findresource dup length dict copy dup /InstanceType /dicttype put /CIDFont exch /Category defineresource pop setglobal } ifelse ct_UseNativeCapability? { /CIDInit /ProcSet findresource begin 12 dict begin begincmap /CIDSystemInfo 3 dict dup begin /Registry (Adobe) def /Ordering (Identity) def /Supplement 0 def end def /CMapName /Identity-H def /CMapVersion 1.000 def /CMapType 1 def 1 begincodespacerange <0000> <FFFF> endcodespacerange 1 begincidrange <0000> <FFFF> 0 endcidrange endcmap CMapName currentdict /CMap defineresource pop end end } if } { /ct_Category 2 dict begin /CIDFont 10 dict def /ProcSet 2 dict def currentdict end def /defineresource { ct_Category 1 index 2 copy known { get dup dup maxlength exch length eq { dup length 10 add dict copy ct_Category 2 index 2 index put } if 3 index 3 index put pop exch pop } { pop pop /defineresource /undefined ct_raise } ifelse } bind def /findresource { ct_Category 1 index 2 copy known { get 2 index 2 copy known { get 3 1 roll pop pop} { pop pop /findresource /undefinedresource ct_raise } ifelse } { pop pop /findresource /undefined ct_raise } ifelse } bind def /resourcestatus { ct_Category 1 index 2 copy known { get 2 index known exch pop exch pop { 0 -1 true } { false } ifelse } { pop pop /findresource /undefined ct_raise } ifelse } bind def /ct_resourcestatus /resourcestatus load def } ifelse /ct_CIDInit 2 dict begin /ct_cidfont_stream_init { { dup (Binary) eq { pop null currentfile ct_Level2? { { cid_BYTE_COUNT () /SubFileDecode filter } stopped { pop pop pop } if } if /readstring load exit } if dup (Hex) eq { pop currentfile ct_Level2? { { null exch /ASCIIHexDecode filter /readstring } stopped { pop exch pop (>) exch /readhexstring } if } { (>) exch /readhexstring } ifelse load exit } if /StartData /typecheck ct_raise } loop cid_BYTE_COUNT ct_CID_STR_SIZE le { 2 copy cid_BYTE_COUNT string exch exec pop 1 array dup 3 -1 roll 0 exch put } { cid_BYTE_COUNT ct_CID_STR_SIZE div ceiling cvi dup array exch 2 sub 0 exch 1 exch { 2 copy 5 index ct_CID_STR_SIZE string 6 index exec pop put pop } for 2 index cid_BYTE_COUNT ct_CID_STR_SIZE mod string 3 index exec pop 1 index exch 1 index length 1 sub exch put } ifelse cid_CIDFONT exch /GlyphData exch put 2 index null eq { pop pop pop } { pop /readstring load 1 string exch { 3 copy exec pop dup length 0 eq { pop pop pop pop pop true exit } if 4 index eq { pop pop pop pop false exit } if } loop pop } ifelse } bind def /StartData { mark { currentdict dup /FDArray get 0 get /FontMatrix get 0 get 0.001 eq { dup /CDevProc known not { /CDevProc 1183615869 internaldict /stdCDevProc 2 copy known { get } { pop pop { pop pop pop pop pop 0 -1000 7 index 2 div 880 } } ifelse def } if } { /CDevProc { pop pop pop pop pop 0 1 cid_temp /cid_CIDFONT get /FDArray get 0 get /FontMatrix get 0 get div 7 index 2 div 1 index 0.88 mul } def } ifelse /cid_temp 15 dict def cid_temp begin /cid_CIDFONT exch def 3 copy pop dup /cid_BYTE_COUNT exch def 0 gt { ct_cidfont_stream_init FDArray { /Private get dup /SubrMapOffset known { begin /Subrs SubrCount array def Subrs SubrMapOffset SubrCount SDBytes ct_Level2? { currentdict dup /SubrMapOffset undef dup /SubrCount undef /SDBytes undef } if end /cid_SD_BYTES exch def /cid_SUBR_COUNT exch def /cid_SUBR_MAP_OFFSET exch def /cid_SUBRS exch def cid_SUBR_COUNT 0 gt { GlyphData cid_SUBR_MAP_OFFSET cid_SD_BYTES ct_GetInterval 0 cid_SD_BYTES ct_cvnsi 0 1 cid_SUBR_COUNT 1 sub { exch 1 index 1 add cid_SD_BYTES mul cid_SUBR_MAP_OFFSET add GlyphData exch cid_SD_BYTES ct_GetInterval 0 cid_SD_BYTES ct_cvnsi cid_SUBRS 4 2 roll GlyphData exch 4 index 1 index sub ct_GetInterval dup length string copy put } for pop } if } { pop } ifelse } forall } if cleartomark pop pop end CIDFontName currentdict /CIDFont defineresource pop end end } stopped { cleartomark /StartData ct_reraise } if } bind def currentdict end def /ct_saveCIDInit { /CIDInit /ProcSet ct_resourcestatus { true } { /CIDInitC /ProcSet ct_resourcestatus } ifelse { pop pop /CIDInit /ProcSet findresource ct_UseNativeCapability? { pop null } { /CIDInit ct_CIDInit /ProcSet defineresource pop } ifelse } { /CIDInit ct_CIDInit /ProcSet defineresource pop null } ifelse ct_Vars exch /ct_oldCIDInit exch put } bind def /ct_restoreCIDInit { ct_Vars /ct_oldCIDInit get dup null ne { /CIDInit exch /ProcSet defineresource pop } { pop } ifelse } bind def /ct_BuildCharSetUp { 1 index begin CIDFont begin Adobe_CoolType_Utility /ct_BuildCharDict get begin /ct_dfCharCode exch def /ct_dfDict exch def CIDFirstByte ct_dfCharCode add dup CIDCount ge { pop 0 } if /cid exch def { GlyphDirectory cid 2 copy known { get } { pop pop nullstring } ifelse dup length FDBytes sub 0 gt { dup FDBytes 0 ne { 0 FDBytes ct_cvnsi } { pop 0 } ifelse /fdIndex exch def dup length FDBytes sub FDBytes exch getinterval /charstring exch def exit } { pop cid 0 eq { /charstring nullstring def exit } if /cid 0 def } ifelse } loop } def /ct_SetCacheDevice { 0 0 moveto dup stringwidth 3 -1 roll true charpath pathbbox 0 -1000 7 index 2 div 880 setcachedevice2 0 0 moveto } def /ct_CloneSetCacheProc { 1 eq { stringwidth pop -2 div -880 0 -1000 setcharwidth moveto } { usewidths? { currentfont /Widths get cid 2 copy known { get exch pop aload pop } { pop pop stringwidth } ifelse } { stringwidth } ifelse setcharwidth 0 0 moveto } ifelse } def /ct_Type3ShowCharString { ct_FDDict fdIndex 2 copy known { get } { currentglobal 3 1 roll 1 index gcheck setglobal ct_Type1FontTemplate dup maxlength dict copy begin FDArray fdIndex get dup /FontMatrix 2 copy known { get } { pop pop ct_defaultFontMtx } ifelse /FontMatrix exch dup length array copy def /Private get /Private exch def /Widths rootfont /Widths get def /CharStrings 1 dict dup /.notdef <d841272cf18f54fc13> dup length string copy put def currentdict end /ct_Type1Font exch definefont dup 5 1 roll put setglobal } ifelse dup /CharStrings get 1 index /Encoding get ct_dfCharCode get charstring put rootfont /WMode 2 copy known { get } { pop pop 0 } ifelse exch 1000 scalefont setfont ct_str1 0 ct_dfCharCode put ct_str1 exch ct_dfSetCacheProc ct_SyntheticBold { currentpoint ct_str1 show newpath moveto ct_str1 true charpath ct_StrokeWidth setlinewidth stroke } { ct_str1 show } ifelse } def /ct_Type4ShowCharString { ct_dfDict ct_dfCharCode charstring FDArray fdIndex get dup /FontMatrix get dup ct_defaultFontMtx ct_matrixeq not { ct_1000Mtx matrix concatmatrix concat } { pop } ifelse /Private get Adobe_CoolType_Utility /ct_Level2? get not { ct_dfDict /Private 3 -1 roll { put } 1183615869 internaldict /superexec get exec } if 1183615869 internaldict Adobe_CoolType_Utility /ct_Level2? get { 1 index } { 3 index /Private get mark 6 1 roll } ifelse dup /RunInt known { /RunInt get } { pop /CCRun } ifelse get exec Adobe_CoolType_Utility /ct_Level2? get not { cleartomark } if } bind def /ct_BuildCharIncremental { { Adobe_CoolType_Utility /ct_MakeOCF get begin ct_BuildCharSetUp ct_ShowCharString } stopped { stop } if end end end end } bind def /BaseFontNameStr (BF00) def /ct_Type1FontTemplate 14 dict begin /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0] def /FontBBox [-250 -250 1250 1250] def /Encoding ct_cHexEncoding def /PaintType 0 def currentdict end def /BaseFontTemplate 11 dict begin /FontMatrix [0.001 0 0 0.001 0 0] def /FontBBox [-250 -250 1250 1250] def /Encoding ct_cHexEncoding def /BuildChar /ct_BuildCharIncremental load def ct_Clone? { /FontType 3 def /ct_ShowCharString /ct_Type3ShowCharString load def /ct_dfSetCacheProc /ct_CloneSetCacheProc load def /ct_SyntheticBold false def /ct_StrokeWidth 1 def } { /FontType 4 def /Private 1 dict dup /lenIV 4 put def /CharStrings 1 dict dup /.notdef <d841272cf18f54fc13> put def /PaintType 0 def /ct_ShowCharString /ct_Type4ShowCharString load def } ifelse /ct_str1 1 string def currentdict end def /BaseFontDictSize BaseFontTemplate length 5 add def /ct_matrixeq { true 0 1 5 { dup 4 index exch get exch 3 index exch get eq and dup not { exit } if } for exch pop exch pop } bind def /ct_makeocf { 15 dict begin exch /WMode exch def exch /FontName exch def /FontType 0 def /FMapType 2 def dup /FontMatrix known { dup /FontMatrix get /FontMatrix exch def } { /FontMatrix matrix def } ifelse /bfCount 1 index /CIDCount get 256 idiv 1 add dup 256 gt { pop 256} if def /Encoding 256 array 0 1 bfCount 1 sub { 2 copy dup put pop } for bfCount 1 255 { 2 copy bfCount put pop } for def /FDepVector bfCount dup 256 lt { 1 add } if array def BaseFontTemplate BaseFontDictSize dict copy begin /CIDFont exch def CIDFont /FontBBox known { CIDFont /FontBBox get /FontBBox exch def } if CIDFont /CDevProc known { CIDFont /CDevProc get /CDevProc exch def } if currentdict end BaseFontNameStr 3 (0) putinterval 0 1 bfCount dup 256 eq { 1 sub } if { FDepVector exch 2 index BaseFontDictSize dict copy begin dup /CIDFirstByte exch 256 mul def FontType 3 eq { /ct_FDDict 2 dict def } if currentdict end 1 index 16 BaseFontNameStr 2 2 getinterval cvrs pop BaseFontNameStr exch definefont put } for ct_Clone? { /Widths 1 index /CIDFont get /GlyphDirectory get length dict def } if FontName currentdict end definefont ct_Clone? { gsave dup 1000 scalefont setfont ct_BuildCharDict begin /usewidths? false def currentfont /Widths get begin exch /CIDFont get /GlyphDirectory get { pop dup charcode exch 1 index 0 2 index 256 idiv put 1 index exch 1 exch 256 mod put stringwidth 2 array astore def } forall end /usewidths? true def end grestore } { exch pop } ifelse } bind def /ct_ComposeFont { ct_UseNativeCapability? { 2 index /CMap ct_resourcestatus { pop pop exch pop } { /CIDInit /ProcSet findresource begin 12 dict begin begincmap /CMapName 3 index def /CMapVersion 1.000 def /CMapType 1 def exch /WMode exch def /CIDSystemInfo 3 dict dup begin /Registry (Adobe) def /Ordering CMapName ct_mkocfStr100 cvs (Adobe-) search { pop pop (-) search { dup length string copy exch pop exch pop } { pop (Identity)} ifelse } { pop (Identity) } ifelse def /Supplement 0 def end def 1 begincodespacerange <0000> <FFFF> endcodespacerange 1 begincidrange <0000> <FFFF> 0 endcidrange endcmap CMapName currentdict /CMap defineresource pop end end } ifelse composefont } { 3 2 roll pop 0 get /CIDFont findresource ct_makeocf } ifelse } bind def /ct_MakeIdentity { ct_UseNativeCapability? { 1 index /CMap ct_resourcestatus { pop pop } { /CIDInit /ProcSet findresource begin 12 dict begin begincmap /CMapName 2 index def /CMapVersion 1.000 def /CMapType 1 def /CIDSystemInfo 3 dict dup begin /Registry (Adobe) def /Ordering CMapName ct_mkocfStr100 cvs (Adobe-) search { pop pop (-) search { dup length string copy exch pop exch pop } { pop (Identity) } ifelse } { pop (Identity) } ifelse def /Supplement 0 def end def 1 begincodespacerange <0000> <FFFF> endcodespacerange 1 begincidrange <0000> <FFFF> 0 endcidrange endcmap CMapName currentdict /CMap defineresource pop end end } ifelse composefont } { exch pop 0 get /CIDFont findresource ct_makeocf } ifelse } bind def currentdict readonly pop end end %%EndResource %%BeginResource: procset Adobe_CoolType_Utility_T42 1.0 0 %%Copyright: Copyright 1987-2004 Adobe Systems Incorporated. %%Version: 1.0 0 userdict /ct_T42Dict 15 dict put ct_T42Dict begin /Is2015? { version cvi 2015 ge } bind def /AllocGlyphStorage { Is2015? { pop } { {string} forall } ifelse } bind def /Type42DictBegin { 25 dict begin /FontName exch def /CharStrings 256 dict begin /.notdef 0 def currentdict end def /Encoding exch def /PaintType 0 def /FontType 42 def /FontMatrix [1 0 0 1 0 0] def 4 array astore cvx /FontBBox exch def /sfnts } bind def /Type42DictEnd { currentdict dup /FontName get exch definefont end ct_T42Dict exch dup /FontName get exch put } bind def /RD {string currentfile exch readstring pop} executeonly def /PrepFor2015 { Is2015? { /GlyphDirectory 16 dict def sfnts 0 get dup 2 index (glyx) putinterval 2 index (locx) putinterval pop pop } { pop pop } ifelse } bind def /AddT42Char { Is2015? { /GlyphDirectory get begin def end pop pop } { /sfnts get 4 index get 3 index 2 index putinterval pop pop pop pop } ifelse } bind def /T0AddT42Mtx2 { /CIDFont findresource /Metrics2 get begin def end }bind def end %%EndResource Adobe_CoolType_Core begin /$Oblique SetSubstituteStrategy end %%BeginResource: procset Adobe_AGM_Image 1.0 0 %%Version: 1.0 0 %%Copyright: Copyright (C) 2000-2003 Adobe Systems, Inc. All Rights Reserved. systemdict /setpacking known { currentpacking true setpacking } if userdict /Adobe_AGM_Image 75 dict dup begin put /Adobe_AGM_Image_Id /Adobe_AGM_Image_1.0_0 def /nd{ null def }bind def /AGMIMG_&image nd /AGMIMG_&colorimage nd /AGMIMG_&imagemask nd /AGMIMG_mbuf () def /AGMIMG_ybuf () def /AGMIMG_kbuf () def /AGMIMG_c 0 def /AGMIMG_m 0 def /AGMIMG_y 0 def /AGMIMG_k 0 def /AGMIMG_tmp nd /AGMIMG_imagestring0 nd /AGMIMG_imagestring1 nd /AGMIMG_imagestring2 nd /AGMIMG_imagestring3 nd /AGMIMG_imagestring4 nd /AGMIMG_imagestring5 nd /AGMIMG_cnt nd /AGMIMG_fsave nd /AGMIMG_colorAry nd /AGMIMG_override nd /AGMIMG_name nd /AGMIMG_maskSource nd /AGMIMG_flushfilters nd /invert_image_samples nd /knockout_image_samples nd /img nd /sepimg nd /devnimg nd /idximg nd /doc_setup { Adobe_AGM_Core begin Adobe_AGM_Image begin /AGMIMG_&image systemdict/image get def /AGMIMG_&imagemask systemdict/imagemask get def /colorimage where{ pop /AGMIMG_&colorimage /colorimage ldf }if end end }def /page_setup { Adobe_AGM_Image begin /AGMIMG_ccimage_exists {/customcolorimage where { pop /Adobe_AGM_OnHost_Seps where { pop false }{ /Adobe_AGM_InRip_Seps where { pop false }{ true }ifelse }ifelse }{ false }ifelse }bdf level2{ /invert_image_samples { Adobe_AGM_Image/AGMIMG_tmp Decode length ddf /Decode [ Decode 1 get Decode 0 get] def }def /knockout_image_samples { Operator/imagemask ne{ /Decode [1 1] def }if }def }{ /invert_image_samples { {1 exch sub} currenttransfer addprocs settransfer }def /knockout_image_samples { { pop 1 } currenttransfer addprocs settransfer }def }ifelse /img /imageormask ldf /sepimg /sep_imageormask ldf /devnimg /devn_imageormask ldf /idximg /indexed_imageormask ldf /_ctype 7 def currentdict{ dup xcheck 1 index type dup /arraytype eq exch /packedarraytype eq or and{ bind }if def }forall }def /page_trailer { end }def /doc_trailer { }def /AGMIMG_flushfilters { dup type /arraytype ne {1 array astore}if aload length { dup type /filetype eq { dup status 1 index currentfile ne and {dup flushfile closefile} {pop} ifelse }{pop}ifelse } repeat }def /imageormask_sys { begin save mark level2{ currentdict Operator /imagemask eq{ AGMIMG_&imagemask }{ use_mask { level3 {process_mask_L3 AGMIMG_&image}{masked_image_simulation}ifelse }{ AGMIMG_&image }ifelse }ifelse }{ Width Height Operator /imagemask eq{ Decode 0 get 1 eq Decode 1 get 0 eq and ImageMatrix /DataSource load AGMIMG_&imagemask }{ BitsPerComponent ImageMatrix /DataSource load AGMIMG_&image }ifelse }ifelse currentdict /_Filters known {_Filters AGMIMG_flushfilters} if cleartomark restore end }def /overprint_plate { currentoverprint { 0 get dup type /nametype eq { dup /DeviceGray eq{ pop AGMCORE_black_plate not }{ /DeviceCMYK eq{ AGMCORE_is_cmyk_sep not }if }ifelse }{ false exch { AGMOHS_sepink eq or } forall not } ifelse }{ pop false }ifelse }def /process_mask_L3 { dup begin /ImageType 1 def end 4 dict begin /DataDict exch def /ImageType 3 def /InterleaveType 3 def /MaskDict 9 dict begin /ImageType 1 def /Width DataDict dup /MaskWidth known {/MaskWidth}{/Width} ifelse get def /Height DataDict dup /MaskHeight known {/MaskHeight}{/Height} ifelse get def /ImageMatrix [Width 0 0 Height neg 0 Height] def /NComponents 1 def /BitsPerComponent 1 def /Decode [0 1] def /DataSource AGMIMG_maskSource def currentdict end def currentdict end }def /use_mask { dup type /dicttype eq { dup /Mask known { dup /Mask get { level3 {true} { dup /MaskWidth known {dup /MaskWidth get 1 index /Width get eq}{true}ifelse exch dup /MaskHeight known {dup /MaskHeight get 1 index /Height get eq}{true}ifelse 3 -1 roll and } ifelse } {false} ifelse } {false} ifelse } {false} ifelse }def /make_line_source { begin MultipleDataSources { [ Decode length 2 div cvi {Width string} repeat ] }{ Width Decode length 2 div mul cvi string }ifelse end }def /datasource_to_str { exch dup type dup /filetype eq { pop exch readstring }{ /arraytype eq { exec exch copy }{ pop }ifelse }ifelse pop }def /masked_image_simulation { 3 dict begin dup make_line_source /line_source xdf /mask_source AGMIMG_maskSource /LZWDecode filter def dup /Width get 8 div ceiling cvi string /mask_str xdf begin gsave 0 1 translate 1 -1 Height div scale 1 1 Height { pop gsave MultipleDataSources { 0 1 DataSource length 1 sub { dup DataSource exch get exch line_source exch get datasource_to_str } for }{ DataSource line_source datasource_to_str } ifelse << /PatternType 1 /PaintProc [ /pop cvx << /ImageType 1 /Width Width /Height 1 /ImageMatrix Width 1.0 sub 1 matrix scale 0.5 0 matrix translate matrix concatmatrix /MultipleDataSources MultipleDataSources /DataSource line_source /BitsPerComponent BitsPerComponent /Decode Decode >> /image cvx ] cvx /BBox [0 0 Width 1] /XStep Width /YStep 1 /PaintType 1 /TilingType 2 >> matrix makepattern set_pattern << /ImageType 1 /Width Width /Height 1 /ImageMatrix Width 1 matrix scale /MultipleDataSources false /DataSource mask_source mask_str readstring pop /BitsPerComponent 1 /Decode [0 1] >> imagemask grestore 0 1 translate } for grestore end end }def /imageormask { begin SkipImageProc { currentdict consumeimagedata } { save mark level2 AGMCORE_host_sep not and{ currentdict Operator /imagemask eq DeviceN_PS2 not and { imagemask }{ AGMCORE_in_rip_sep currentoverprint and currentcolorspace 0 get /DeviceGray eq and{ [/Separation /Black /DeviceGray {}] setcolorspace /Decode [ Decode 1 get Decode 0 get ] def }if use_mask { level3 {process_mask_L3 image}{masked_image_simulation}ifelse }{ DeviceN_NoneName DeviceN_PS2 Indexed_DeviceN level3 not and or or AGMCORE_in_rip_sep and { Names convert_to_process not { 2 dict begin /imageDict xdf /names_index 0 def gsave imageDict write_image_file { Names { dup (None) ne { [/Separation 3 -1 roll /DeviceGray {1 exch sub}] setcolorspace Operator imageDict read_image_file names_index 0 eq {true setoverprint} if /names_index names_index 1 add def }{ pop } ifelse } forall close_image_file } if grestore end }{ Operator /imagemask eq { imagemask }{ image } ifelse } ifelse }{ Operator /imagemask eq { imagemask }{ image } ifelse } ifelse }ifelse }ifelse }{ Width Height Operator /imagemask eq{ Decode 0 get 1 eq Decode 1 get 0 eq and ImageMatrix /DataSource load /Adobe_AGM_OnHost_Seps where { pop imagemask }{ currentgray 1 ne{ currentdict imageormask_sys }{ currentoverprint not{ 1 AGMCORE_&setgray currentdict imageormask_sys }{ currentdict ignoreimagedata }ifelse }ifelse }ifelse }{ BitsPerComponent ImageMatrix MultipleDataSources{ 0 1 NComponents 1 sub{ DataSource exch get }for }{ /DataSource load }ifelse Operator /colorimage eq{ AGMCORE_host_sep{ MultipleDataSources level2 or NComponents 4 eq and{ AGMCORE_is_cmyk_sep{ MultipleDataSources{ /DataSource [ DataSource 0 get /exec cvx DataSource 1 get /exec cvx DataSource 2 get /exec cvx DataSource 3 get /exec cvx /AGMCORE_get_ink_data cvx ] cvx def }{ /DataSource Width BitsPerComponent mul 7 add 8 idiv Height mul 4 mul /DataSource load filter_cmyk 0 () /SubFileDecode filter def }ifelse /Decode [ Decode 0 get Decode 1 get ] def /MultipleDataSources false def /NComponents 1 def /Operator /image def invert_image_samples 1 AGMCORE_&setgray currentdict imageormask_sys }{ currentoverprint not Operator/imagemask eq and{ 1 AGMCORE_&setgray currentdict imageormask_sys }{ currentdict ignoreimagedata }ifelse }ifelse }{ MultipleDataSources NComponents AGMIMG_&colorimage }ifelse }{ true NComponents colorimage }ifelse }{ Operator /image eq{ AGMCORE_host_sep{ /DoImage true def HostSepColorImage{ invert_image_samples }{ AGMCORE_black_plate not Operator/imagemask ne and{ /DoImage false def currentdict ignoreimagedata }if }ifelse 1 AGMCORE_&setgray DoImage {currentdict imageormask_sys} if }{ use_mask { level3 {process_mask_L3 image}{masked_image_simulation}ifelse }{ image }ifelse }ifelse }{ Operator/knockout eq{ pop pop pop pop pop currentcolorspace overprint_plate not{ knockout_unitsq }if }if }ifelse }ifelse }ifelse }ifelse cleartomark restore }ifelse currentdict /_Filters known {_Filters AGMIMG_flushfilters} if end }def /sep_imageormask { /sep_colorspace_dict AGMCORE_gget begin CSA map_csa begin SkipImageProc { currentdict consumeimagedata } { save mark AGMCORE_avoid_L2_sep_space{ /Decode [ Decode 0 get 255 mul Decode 1 get 255 mul ] def }if AGMIMG_ccimage_exists MappedCSA 0 get /DeviceCMYK eq and currentdict/Components known and Name () ne and Name (All) ne and Operator /image eq and AGMCORE_producing_seps not and level2 not and { Width Height BitsPerComponent ImageMatrix [ /DataSource load /exec cvx { 0 1 2 index length 1 sub{ 1 index exch 2 copy get 255 xor put }for } /exec cvx ] cvx bind MappedCSA 0 get /DeviceCMYK eq{ Components aload pop }{ 0 0 0 Components aload pop 1 exch sub }ifelse Name findcmykcustomcolor customcolorimage }{ AGMCORE_producing_seps not{ level2{ AGMCORE_avoid_L2_sep_space not currentcolorspace 0 get /Separation ne and{ [/Separation Name MappedCSA sep_proc_name exch 0 get exch load ] setcolorspace_opt /sep_tint AGMCORE_gget setcolor }if currentdict imageormask }{ currentdict Operator /imagemask eq{ imageormask }{ sep_imageormask_lev1 }ifelse }ifelse }{ AGMCORE_host_sep{ Operator/knockout eq{ currentdict/ImageMatrix get concat knockout_unitsq }{ currentgray 1 ne{ AGMCORE_is_cmyk_sep Name (All) ne and{ level2{ Name AGMCORE_IsSeparationAProcessColor { Operator /imagemask eq{ /sep_tint AGMCORE_gget 1 exch sub AGMCORE_&setcolor }{ invert_image_samples }ifelse }{ [ /Separation Name [/DeviceGray] { sep_colorspace_proc AGMCORE_get_ink_data 1 exch sub } bind ] AGMCORE_&setcolorspace /sep_tint AGMCORE_gget AGMCORE_&setcolor }ifelse currentdict imageormask_sys }{ currentdict Operator /imagemask eq{ imageormask_sys }{ sep_image_lev1_sep }ifelse }ifelse }{ Operator/imagemask ne{ invert_image_samples }if currentdict imageormask_sys }ifelse }{ currentoverprint not Name (All) eq or Operator/imagemask eq and{ currentdict imageormask_sys }{ currentoverprint not { gsave knockout_unitsq grestore }if currentdict consumeimagedata }ifelse }ifelse }ifelse }{ currentcolorspace 0 get /Separation ne{ [/Separation Name MappedCSA sep_proc_name exch 0 get exch load ] setcolorspace_opt /sep_tint AGMCORE_gget setcolor }if currentoverprint MappedCSA 0 get /DeviceCMYK eq and Name AGMCORE_IsSeparationAProcessColor not and Name inRip_spot_has_ink not and Name (All) ne and { imageormask_l2_overprint }{ currentdict imageormask }ifelse }ifelse }ifelse }ifelse cleartomark restore }ifelse currentdict /_Filters known {_Filters AGMIMG_flushfilters} if end end }def /decode_image_sample { 4 1 roll exch dup 5 1 roll sub 2 4 -1 roll exp 1 sub div mul add } bdf /colorSpaceElemCnt { mark currentcolor counttomark dup 2 add 1 roll cleartomark } bdf /devn_sep_datasource { 1 dict begin /dataSource xdf [ 0 1 dataSource length 1 sub { dup currentdict /dataSource get /exch cvx /get cvx /exec cvx /exch cvx names_index /ne cvx [ /pop cvx ] cvx /if cvx } for ] cvx bind end } bdf /devn_alt_datasource { 11 dict begin /convProc xdf /origcolorSpaceElemCnt xdf /origMultipleDataSources xdf /origBitsPerComponent xdf /origDecode xdf /origDataSource xdf /dsCnt origMultipleDataSources {origDataSource length}{1}ifelse def /DataSource origMultipleDataSources { [ BitsPerComponent 8 idiv origDecode length 2 idiv mul string 0 1 origDecode length 2 idiv 1 sub { dup 7 mul 1 add index exch dup BitsPerComponent 8 idiv mul exch origDataSource exch get 0 () /SubFileDecode filter BitsPerComponent 8 idiv string /readstring cvx /pop cvx /putinterval cvx }for ]bind cvx }{origDataSource}ifelse 0 () /SubFileDecode filter def [ origcolorSpaceElemCnt string 0 2 origDecode length 2 sub { dup origDecode exch get dup 3 -1 roll 1 add origDecode exch get exch sub 2 BitsPerComponent exp 1 sub div 1 BitsPerComponent 8 idiv {DataSource /read cvx /not cvx{0}/if cvx /mul cvx}repeat /mul cvx /add cvx }for /convProc load /exec cvx origcolorSpaceElemCnt 1 sub -1 0 { /dup cvx 2 /add cvx /index cvx 3 1 /roll cvx /exch cvx 255 /mul cvx /cvi cvx /put cvx }for ]bind cvx 0 () /SubFileDecode filter end } bdf /devn_imageormask { /devicen_colorspace_dict AGMCORE_gget begin CSA map_csa 2 dict begin dup /srcDataStrs [ 3 -1 roll begin currentdict /MultipleDataSources known {MultipleDataSources {DataSource length}{1}ifelse}{1} ifelse { Width Decode length 2 div mul cvi { dup 65535 gt {1 add 2 div cvi}{exit}ifelse } loop string } repeat end ] def /dstDataStr srcDataStrs 0 get length string def begin SkipImageProc { currentdict consumeimagedata } { save mark AGMCORE_producing_seps not { level3 not { Operator /imagemask ne { /DataSource [ [ DataSource Decode BitsPerComponent currentdict /MultipleDataSources known {MultipleDataSources}{false} ifelse colorSpaceElemCnt /devicen_colorspace_dict AGMCORE_gget /TintTransform get devn_alt_datasource 1 /string cvx /readstring cvx /pop cvx] cvx colorSpaceElemCnt 1 sub{dup}repeat] def /MultipleDataSources true def /Decode colorSpaceElemCnt [ exch {0 1} repeat ] def } if }if currentdict imageormask }{ AGMCORE_host_sep{ Names convert_to_process { CSA get_csa_by_name 0 get /DeviceCMYK eq { /DataSource Width BitsPerComponent mul 7 add 8 idiv Height mul 4 mul DataSource Decode BitsPerComponent currentdict /MultipleDataSources known {MultipleDataSources}{false} ifelse 4 /devicen_colorspace_dict AGMCORE_gget /TintTransform get devn_alt_datasource filter_cmyk 0 () /SubFileDecode filter def /MultipleDataSources false def /Decode [1 0] def /DeviceGray setcolorspace currentdict imageormask_sys }{ AGMCORE_report_unsupported_color_space AGMCORE_black_plate { /DataSource DataSource Decode BitsPerComponent currentdict /MultipleDataSources known {MultipleDataSources}{false} ifelse CSA get_csa_by_name 0 get /DeviceRGB eq{3}{1}ifelse /devicen_colorspace_dict AGMCORE_gget /TintTransform get devn_alt_datasource /MultipleDataSources false def /Decode colorSpaceElemCnt [ exch {0 1} repeat ] def currentdict imageormask_sys } { gsave knockout_unitsq grestore currentdict consumeimagedata } ifelse } ifelse } { /devicen_colorspace_dict AGMCORE_gget /names_index known { Operator/imagemask ne{ MultipleDataSources { /DataSource [ DataSource devn_sep_datasource /exec cvx ] cvx def /MultipleDataSources false def }{ /DataSource /DataSource load dstDataStr srcDataStrs 0 get filter_devn def } ifelse invert_image_samples } if currentdict imageormask_sys }{ currentoverprint not Operator/imagemask eq and{ currentdict imageormask_sys }{ currentoverprint not { gsave knockout_unitsq grestore }if currentdict consumeimagedata }ifelse }ifelse }ifelse }{ currentdict imageormask }ifelse }ifelse cleartomark restore }ifelse currentdict /_Filters known {_Filters AGMIMG_flushfilters} if end end end }def /imageormask_l2_overprint { currentdict currentcmykcolor add add add 0 eq{ currentdict consumeimagedata }{ level3{ currentcmykcolor /AGMIMG_k xdf /AGMIMG_y xdf /AGMIMG_m xdf /AGMIMG_c xdf Operator/imagemask eq{ [/DeviceN [ AGMIMG_c 0 ne {/Cyan} if AGMIMG_m 0 ne {/Magenta} if AGMIMG_y 0 ne {/Yellow} if AGMIMG_k 0 ne {/Black} if ] /DeviceCMYK {}] setcolorspace AGMIMG_c 0 ne {AGMIMG_c} if AGMIMG_m 0 ne {AGMIMG_m} if AGMIMG_y 0 ne {AGMIMG_y} if AGMIMG_k 0 ne {AGMIMG_k} if setcolor }{ /Decode [ Decode 0 get 255 mul Decode 1 get 255 mul ] def [/Indexed [ /DeviceN [ AGMIMG_c 0 ne {/Cyan} if AGMIMG_m 0 ne {/Magenta} if AGMIMG_y 0 ne {/Yellow} if AGMIMG_k 0 ne {/Black} if ] /DeviceCMYK { AGMIMG_k 0 eq {0} if AGMIMG_y 0 eq {0 exch} if AGMIMG_m 0 eq {0 3 1 roll} if AGMIMG_c 0 eq {0 4 1 roll} if } ] 255 { 255 div mark exch dup dup dup AGMIMG_k 0 ne{ /sep_tint AGMCORE_gget mul MappedCSA sep_proc_name exch pop load exec 4 1 roll pop pop pop counttomark 1 roll }{ pop }ifelse AGMIMG_y 0 ne{ /sep_tint AGMCORE_gget mul MappedCSA sep_proc_name exch pop load exec 4 2 roll pop pop pop counttomark 1 roll }{ pop }ifelse AGMIMG_m 0 ne{ /sep_tint AGMCORE_gget mul MappedCSA sep_proc_name exch pop load exec 4 3 roll pop pop pop counttomark 1 roll }{ pop }ifelse AGMIMG_c 0 ne{ /sep_tint AGMCORE_gget mul MappedCSA sep_proc_name exch pop load exec pop pop pop counttomark 1 roll }{ pop }ifelse counttomark 1 add -1 roll pop } ] setcolorspace }ifelse imageormask_sys }{ write_image_file{ currentcmykcolor 0 ne{ [/Separation /Black /DeviceGray {}] setcolorspace gsave /Black [{1 exch sub /sep_tint AGMCORE_gget mul} /exec cvx MappedCSA sep_proc_name cvx exch pop {4 1 roll pop pop pop 1 exch sub} /exec cvx] cvx modify_halftone_xfer Operator currentdict read_image_file grestore }if 0 ne{ [/Separation /Yellow /DeviceGray {}] setcolorspace gsave /Yellow [{1 exch sub /sep_tint AGMCORE_gget mul} /exec cvx MappedCSA sep_proc_name cvx exch pop {4 2 roll pop pop pop 1 exch sub} /exec cvx] cvx modify_halftone_xfer Operator currentdict read_image_file grestore }if 0 ne{ [/Separation /Magenta /DeviceGray {}] setcolorspace gsave /Magenta [{1 exch sub /sep_tint AGMCORE_gget mul} /exec cvx MappedCSA sep_proc_name cvx exch pop {4 3 roll pop pop pop 1 exch sub} /exec cvx] cvx modify_halftone_xfer Operator currentdict read_image_file grestore }if 0 ne{ [/Separation /Cyan /DeviceGray {}] setcolorspace gsave /Cyan [{1 exch sub /sep_tint AGMCORE_gget mul} /exec cvx MappedCSA sep_proc_name cvx exch pop {pop pop pop 1 exch sub} /exec cvx] cvx modify_halftone_xfer Operator currentdict read_image_file grestore } if close_image_file }{ imageormask }ifelse }ifelse }ifelse } def /indexed_imageormask { begin save mark currentdict AGMCORE_host_sep{ Operator/knockout eq{ /indexed_colorspace_dict AGMCORE_gget dup /CSA known { /CSA get get_csa_by_name }{ /Names get } ifelse overprint_plate not{ knockout_unitsq }if }{ Indexed_DeviceN { /devicen_colorspace_dict AGMCORE_gget /names_index known { indexed_image_lev2_sep }{ currentoverprint not{ knockout_unitsq }if currentdict consumeimagedata } ifelse }{ AGMCORE_is_cmyk_sep{ Operator /imagemask eq{ imageormask_sys }{ level2{ indexed_image_lev2_sep }{ indexed_image_lev1_sep }ifelse }ifelse }{ currentoverprint not{ knockout_unitsq }if currentdict consumeimagedata }ifelse }ifelse }ifelse }{ level2{ Indexed_DeviceN { /indexed_colorspace_dict AGMCORE_gget begin }{ /indexed_colorspace_dict AGMCORE_gget begin CSA get_csa_by_name 0 get /DeviceCMYK eq ps_level 3 ge and ps_version 3015.007 lt and { [/Indexed [/DeviceN [/Cyan /Magenta /Yellow /Black] /DeviceCMYK {}] HiVal Lookup] setcolorspace } if end } ifelse imageormask Indexed_DeviceN { end } if }{ Operator /imagemask eq{ imageormask }{ indexed_imageormask_lev1 }ifelse }ifelse }ifelse cleartomark restore currentdict /_Filters known {_Filters AGMIMG_flushfilters} if end }def /indexed_image_lev2_sep { /indexed_colorspace_dict AGMCORE_gget begin begin Indexed_DeviceN not { currentcolorspace dup 1 /DeviceGray put dup 3 currentcolorspace 2 get 1 add string 0 1 2 3 AGMCORE_get_ink_data 4 currentcolorspace 3 get length 1 sub { dup 4 idiv exch currentcolorspace 3 get exch get 255 exch sub 2 index 3 1 roll put }for put setcolorspace } if currentdict Operator /imagemask eq{ AGMIMG_&imagemask }{ use_mask { level3 {process_mask_L3 AGMIMG_&image}{masked_image_simulation}ifelse }{ AGMIMG_&image }ifelse }ifelse end end }def /OPIimage { dup type /dicttype ne{ 10 dict begin /DataSource xdf /ImageMatrix xdf /BitsPerComponent xdf /Height xdf /Width xdf /ImageType 1 def /Decode [0 1 def] currentdict end }if dup begin /NComponents 1 cdndf /MultipleDataSources false cdndf /SkipImageProc {false} cdndf /HostSepColorImage false cdndf /Decode [ 0 currentcolorspace 0 get /Indexed eq{ 2 BitsPerComponent exp 1 sub }{ 1 }ifelse ] cdndf /Operator /image cdndf end /sep_colorspace_dict AGMCORE_gget null eq{ imageormask }{ gsave dup begin invert_image_samples end sep_imageormask grestore }ifelse }def /cachemask_level2 { 3 dict begin /LZWEncode filter /WriteFilter xdf /readBuffer 256 string def /ReadFilter currentfile 0 (%EndMask) /SubFileDecode filter /ASCII85Decode filter /RunLengthDecode filter def { ReadFilter readBuffer readstring exch WriteFilter exch writestring not {exit} if }loop WriteFilter closefile end }def /cachemask_level3 { currentfile << /Filter [ /SubFileDecode /ASCII85Decode /RunLengthDecode ] /DecodeParms [ << /EODCount 0 /EODString (%EndMask) >> null null ] /Intent 1 >> /ReusableStreamDecode filter }def /spot_alias { /mapto_sep_imageormask { dup type /dicttype ne{ 12 dict begin /ImageType 1 def /DataSource xdf /ImageMatrix xdf /BitsPerComponent xdf /Height xdf /Width xdf /MultipleDataSources false def }{ begin }ifelse /Decode [/customcolor_tint AGMCORE_gget 0] def /Operator /image def /HostSepColorImage false def /SkipImageProc {false} def currentdict end sep_imageormask }bdf /customcolorimage { Adobe_AGM_Image/AGMIMG_colorAry xddf /customcolor_tint AGMCORE_gget << /Name AGMIMG_colorAry 4 get /CSA [ /DeviceCMYK ] /TintMethod /Subtractive /TintProc null /MappedCSA null /NComponents 4 /Components [ AGMIMG_colorAry aload pop pop ] >> setsepcolorspace mapto_sep_imageormask }ndf Adobe_AGM_Image/AGMIMG_&customcolorimage /customcolorimage load put /customcolorimage { Adobe_AGM_Image/AGMIMG_override false put current_spot_alias{dup 4 get map_alias}{false}ifelse { false set_spot_alias /customcolor_tint AGMCORE_gget exch setsepcolorspace pop mapto_sep_imageormask true set_spot_alias }{ AGMIMG_&customcolorimage }ifelse }bdf }def /snap_to_device { 6 dict begin matrix currentmatrix dup 0 get 0 eq 1 index 3 get 0 eq and 1 index 1 get 0 eq 2 index 2 get 0 eq and or exch pop { 1 1 dtransform 0 gt exch 0 gt /AGMIMG_xSign? exch def /AGMIMG_ySign? exch def 0 0 transform AGMIMG_ySign? {floor 0.1 sub}{ceiling 0.1 add} ifelse exch AGMIMG_xSign? {floor 0.1 sub}{ceiling 0.1 add} ifelse exch itransform /AGMIMG_llY exch def /AGMIMG_llX exch def 1 1 transform AGMIMG_ySign? {ceiling 0.1 add}{floor 0.1 sub} ifelse exch AGMIMG_xSign? {ceiling 0.1 add}{floor 0.1 sub} ifelse exch itransform /AGMIMG_urY exch def /AGMIMG_urX exch def [AGMIMG_urX AGMIMG_llX sub 0 0 AGMIMG_urY AGMIMG_llY sub AGMIMG_llX AGMIMG_llY] concat }{ }ifelse end } def level2 not{ /colorbuf { 0 1 2 index length 1 sub{ dup 2 index exch get 255 exch sub 2 index 3 1 roll put }for }def /tint_image_to_color { begin Width Height BitsPerComponent ImageMatrix /DataSource load end Adobe_AGM_Image begin /AGMIMG_mbuf 0 string def /AGMIMG_ybuf 0 string def /AGMIMG_kbuf 0 string def { colorbuf dup length AGMIMG_mbuf length ne { dup length dup dup /AGMIMG_mbuf exch string def /AGMIMG_ybuf exch string def /AGMIMG_kbuf exch string def } if dup AGMIMG_mbuf copy AGMIMG_ybuf copy AGMIMG_kbuf copy pop } addprocs {AGMIMG_mbuf}{AGMIMG_ybuf}{AGMIMG_kbuf} true 4 colorimage end } def /sep_imageormask_lev1 { begin MappedCSA 0 get dup /DeviceRGB eq exch /DeviceCMYK eq or has_color not and{ { 255 mul round cvi GrayLookup exch get } currenttransfer addprocs settransfer currentdict imageormask }{ /sep_colorspace_dict AGMCORE_gget/Components known{ MappedCSA 0 get /DeviceCMYK eq{ Components aload pop }{ 0 0 0 Components aload pop 1 exch sub }ifelse Adobe_AGM_Image/AGMIMG_k xddf Adobe_AGM_Image/AGMIMG_y xddf Adobe_AGM_Image/AGMIMG_m xddf Adobe_AGM_Image/AGMIMG_c xddf AGMIMG_y 0.0 eq AGMIMG_m 0.0 eq and AGMIMG_c 0.0 eq and{ {AGMIMG_k mul 1 exch sub} currenttransfer addprocs settransfer currentdict imageormask }{ currentcolortransfer {AGMIMG_k mul 1 exch sub} exch addprocs 4 1 roll {AGMIMG_y mul 1 exch sub} exch addprocs 4 1 roll {AGMIMG_m mul 1 exch sub} exch addprocs 4 1 roll {AGMIMG_c mul 1 exch sub} exch addprocs 4 1 roll setcolortransfer currentdict tint_image_to_color }ifelse }{ MappedCSA 0 get /DeviceGray eq { {255 mul round cvi ColorLookup exch get 0 get} currenttransfer addprocs settransfer currentdict imageormask }{ MappedCSA 0 get /DeviceCMYK eq { currentcolortransfer {255 mul round cvi ColorLookup exch get 3 get 1 exch sub} exch addprocs 4 1 roll {255 mul round cvi ColorLookup exch get 2 get 1 exch sub} exch addprocs 4 1 roll {255 mul round cvi ColorLookup exch get 1 get 1 exch sub} exch addprocs 4 1 roll {255 mul round cvi ColorLookup exch get 0 get 1 exch sub} exch addprocs 4 1 roll setcolortransfer currentdict tint_image_to_color }{ currentcolortransfer {pop 1} exch addprocs 4 1 roll {255 mul round cvi ColorLookup exch get 2 get} exch addprocs 4 1 roll {255 mul round cvi ColorLookup exch get 1 get} exch addprocs 4 1 roll {255 mul round cvi ColorLookup exch get 0 get} exch addprocs 4 1 roll setcolortransfer currentdict tint_image_to_color }ifelse }ifelse }ifelse }ifelse end }def /sep_image_lev1_sep { begin /sep_colorspace_dict AGMCORE_gget/Components known{ Components aload pop Adobe_AGM_Image/AGMIMG_k xddf Adobe_AGM_Image/AGMIMG_y xddf Adobe_AGM_Image/AGMIMG_m xddf Adobe_AGM_Image/AGMIMG_c xddf {AGMIMG_c mul 1 exch sub} {AGMIMG_m mul 1 exch sub} {AGMIMG_y mul 1 exch sub} {AGMIMG_k mul 1 exch sub} }{ {255 mul round cvi ColorLookup exch get 0 get 1 exch sub} {255 mul round cvi ColorLookup exch get 1 get 1 exch sub} {255 mul round cvi ColorLookup exch get 2 get 1 exch sub} {255 mul round cvi ColorLookup exch get 3 get 1 exch sub} }ifelse AGMCORE_get_ink_data currenttransfer addprocs settransfer currentdict imageormask_sys end }def /indexed_imageormask_lev1 { /indexed_colorspace_dict AGMCORE_gget begin begin currentdict MappedCSA 0 get dup /DeviceRGB eq exch /DeviceCMYK eq or has_color not and{ {HiVal mul round cvi GrayLookup exch get HiVal div} currenttransfer addprocs settransfer imageormask }{ MappedCSA 0 get /DeviceGray eq { {HiVal mul round cvi Lookup exch get HiVal div} currenttransfer addprocs settransfer imageormask }{ MappedCSA 0 get /DeviceCMYK eq { currentcolortransfer {4 mul HiVal mul round cvi 3 add Lookup exch get HiVal div 1 exch sub} exch addprocs 4 1 roll {4 mul HiVal mul round cvi 2 add Lookup exch get HiVal div 1 exch sub} exch addprocs 4 1 roll {4 mul HiVal mul round cvi 1 add Lookup exch get HiVal div 1 exch sub} exch addprocs 4 1 roll {4 mul HiVal mul round cvi Lookup exch get HiVal div 1 exch sub} exch addprocs 4 1 roll setcolortransfer tint_image_to_color }{ currentcolortransfer {pop 1} exch addprocs 4 1 roll {3 mul HiVal mul round cvi 2 add Lookup exch get HiVal div} exch addprocs 4 1 roll {3 mul HiVal mul round cvi 1 add Lookup exch get HiVal div} exch addprocs 4 1 roll {3 mul HiVal mul round cvi Lookup exch get HiVal div} exch addprocs 4 1 roll setcolortransfer tint_image_to_color }ifelse }ifelse }ifelse end end }def /indexed_image_lev1_sep { /indexed_colorspace_dict AGMCORE_gget begin begin {4 mul HiVal mul round cvi Lookup exch get HiVal div 1 exch sub} {4 mul HiVal mul round cvi 1 add Lookup exch get HiVal div 1 exch sub} {4 mul HiVal mul round cvi 2 add Lookup exch get HiVal div 1 exch sub} {4 mul HiVal mul round cvi 3 add Lookup exch get HiVal div 1 exch sub} AGMCORE_get_ink_data currenttransfer addprocs settransfer currentdict imageormask_sys end end }def }if end systemdict /setpacking known { setpacking } if %%EndResource currentdict Adobe_AGM_Utils eq {end} if %%EndProlog %%BeginSetup Adobe_AGM_Utils begin 2 2010 Adobe_AGM_Core/doc_setup get exec Adobe_CoolType_Core/doc_setup get exec Adobe_AGM_Image/doc_setup get exec currentdict Adobe_AGM_Utils eq {end} if %%EndSetup %%Page: (Page 1) 1 %%EndPageComments %%BeginPageSetup /currentdistillerparams where {pop currentdistillerparams /CoreDistVersion get 5000 lt} {true} ifelse { userdict /AI11_PDFMark5 /cleartomark load put userdict /AI11_ReadMetadata_PDFMark5 {flushfile cleartomark } bind put} { userdict /AI11_PDFMark5 /pdfmark load put userdict /AI11_ReadMetadata_PDFMark5 {/PUT pdfmark} bind put } ifelse [/NamespacePush AI11_PDFMark5 [/_objdef {ai_metadata_stream_123} /type /stream /OBJ AI11_PDFMark5 [{ai_metadata_stream_123} currentfile 0 (% &&end XMP packet marker&&) /SubFileDecode filter AI11_ReadMetadata_PDFMark5 <?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
+<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="3.1.2-113">
+ <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+ <rdf:Description rdf:about=""
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:xap="http://ns.adobe.com/xap/1.0/"
+ xmlns:xapGImg="http://ns.adobe.com/xap/1.0/g/img/"
+ xmlns:xapMM="http://ns.adobe.com/xap/1.0/mm/"
+ xmlns:stRef="http://ns.adobe.com/xap/1.0/sType/ResourceRef#"
+ xmlns:tiff="http://ns.adobe.com/tiff/1.0/"
+ dc:format="application/postscript"
+ xap:CreatorTool="Adobe Illustrator CS2"
+ xap:CreateDate="2005-09-07T15:18-07:00"
+ xap:ModifyDate="2005-09-07T15:18-07:00"
+ xap:MetadataDate="2006-04-10T13:36:50-07:00"
+ xapMM:DocumentID="uuid:DEC81B9F214411DABD12D45BA291F212"
+ xapMM:InstanceID="uuid:DEC81BA0214411DABD12D45BA291F212"
+ tiff:ImageWidth="289"
+ tiff:ImageLength="361">
+ <dc:title>
+ <rdf:Alt>
+ <rdf:li xml:lang="x-default">Blue Square Test File - .eps</rdf:li>
+ </rdf:Alt>
+ </dc:title>
+ <dc:description>
+ <rdf:Alt>
+ <rdf:li xml:lang="x-default">XMPFiles BlueSquare test file, created in Illustrator CS2, saved as .ai and .eps.</rdf:li>
+ </rdf:Alt>
+ </dc:description>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>XMP</rdf:li>
+ <rdf:li>Blue Square</rdf:li>
+ <rdf:li>test file</rdf:li>
+ <rdf:li>Illustrator</rdf:li>
+ <rdf:li>.eps</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <xap:Thumbnails>
+ <rdf:Alt>
+ <rdf:li
+ xapGImg:width="208"
+ xapGImg:height="256"
+ xapGImg:format="JPEG"
+ xapGImg:image="/9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA&#xA;AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK&#xA;DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f&#xA;Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgBAADQAwER&#xA;AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA&#xA;AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB&#xA;UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE&#xA;1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ&#xA;qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy&#xA;obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp&#xA;0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo&#xA;+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A5YqqFAAAAFABnU4MGM44&#xA;+kch0cKUjZ3boMs/L4/5sfkGPGe91Bj+Xx/zY/ILxnvdQY/l8f8ANj8gvGe91Bj+Xx/zY/ILxnvd&#xA;QY/l8f8ANj8gvGe91Bj+Xx/zY/ILxnvdQY/l8f8ANj8gvGe91Bj+Xx/zY/ILxnvdQY/l8f8ANj8g&#xA;vGe91Bj+Xx/zY/ILxnvdQY/l8f8ANj8gvGe91Bj+Xx/zY/ILxnvdQY/l8f8ANj8gvGe91Bj+Xx/z&#xA;Y/ILxnvdQY/l8f8ANj8gvGe91Bj+Xx/zY/ILxnvdQY/l8f8ANj8gvGe91Bj+Xx/zY/ILxnvdQY/l&#xA;8f8ANj8gvGe91Bj+Xx/zY/ILxnvdQY/l8f8ANj8gvGe91Bj+Xx/zY/ILxnvdQY/l8f8ANj8gvGe9&#xA;1Bj+Xx/zY/ILxnvevf8AOMQH+P7803GlTAH53Nvmp7Uxxjw0AOf6G/ASbt5COmbbT/3cf6o+5onz&#xA;LsuYuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV69/wA4xf8AKfX/&#xA;AP2ypv8AqJt803a/KPx/Q5Gn6vIR0zZ6f+7j/VH3NM+ZdlzF2KuxV2KuxV2KuxV2KuxV2KuxV2Ku&#xA;xV2KuxV2KuxV2KuxV2KuxV2KuxV2KvXv+cYv+U+v/wDtlTf9RNvmm7X5R+P6HI0/V5COmbPT/wB3&#xA;H+qPuaZ8y7LmLsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVevf84x&#xA;f8p9f/8AbKm/6ibfNN2vyj8f0ORp+ryEdM2en/u4/wBUfc0z5l2XMXYq7FXYq7FXYq7FXYq7FXYq&#xA;7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq9e/5xi/5T6/8A+2VN/wBRNvmm7X5R+P6HI0/V5COm&#xA;bPT/AN3H+qPuaZ8y7LmLsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirs&#xA;Vevf84xf8p9f/wDbKm/6ibfNN2vyj8f0ORp+ryEdM2en/u4/1R9zTPmXZcxdirsVdirsVdirsVdi&#xA;rsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdir17/AJxi/wCU+v8A/tlTf9RNvmm7X5R+P6HI&#xA;0/V5COmbPT/3cf6o+5pnzLsuYuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2Ku&#xA;xV2KuxV69/zjF/yn1/8A9sqb/qJt803a/KPx/Q5Gn6vIR0zZ6f8Au4/1R9zTPmXZcxdirsVdirsV&#xA;dirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdir17/nGL/lPr//ALZU3/UTb5pu1+Uf&#xA;j+hyNP1eQjpmz0/93H+qPuaZ8y7LmLsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirs&#xA;VdirsVdirsVevf8AOMX/ACn1/wD9sqb/AKibfNN2vyj8f0ORp+ryEdM2en/u4/1R9zTPmXZcxdir&#xA;sVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdir17/nGL/lPr/8A7ZU3/UTb&#xA;5pu1+Ufj+hyNP1eQjpmz0/8Adx/qj7mmfMuy5i7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FX&#xA;Yq7FXYq7FXYq7FXYq7FXr3/OMX/KfX//AGypv+om3zTdr8o/H9Dkafq8hHTNnp/7uP8AVH3NM+Zd&#xA;lzF2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KvXv+cYv+U+v/APtl&#xA;Tf8AUTb5pu1+Ufj+hyNP1eQjpmz0/wDdx/qj7mmfMuy5i7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7&#xA;FXYq7FXYq7FXYq7FXYq7FXYq7FXr3/OMX/KfX/8A2ypv+om3zTdr8o/H9Dkafq8hHTNnp/7uP9Uf&#xA;c0z5l2XMXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq9e/wCcYv8A&#xA;lPr/AP7ZU3/UTb5pu1+Ufj+hyNP1eQjpmz0/93H+qPuaZ8y7LmLsVdirsVdirsVdirsVdirsVdir&#xA;sVdirsVdirsVdirsVdirsVdirsVdirsVevf84xf8p9f/APbKm/6ibfNN2vyj8f0ORp+ryEdM2en/&#xA;ALuP9Ufc0z5l2XMXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq9e/&#xA;5xi/5T6//wC2VN/1E2+abtflH4/ocjT9XkI6Zs9P/dx/qj7mmfMuy5i7FXYq7FXYq7FXYq7FXYq7&#xA;FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXr3/ADjF/wAp9f8A/bKm/wCom3zTdr8o/H9Dkafq&#xA;8hHTNnp/7uP9Ufc0z5l2XMXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7&#xA;FXYq9e/5xi/5T6//AO2VN/1E2+abtflH4/ocjT9XkI6Zs9P/AHcf6o+5pnzLsuYuxV2KuxV2KuxV&#xA;2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV69/zjF/yn1//wBsqb/qJt803a/KPx/Q&#xA;5Gn6vIR0zZ6f+7j/AFR9zTPmXZcxdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdir&#xA;sVdirsVdir17/nGL/lPr/wD7ZU3/AFE2+abtflH4/ocjT9XkI6Zs9P8A3cf6o+5pnzLsuYuxV2Ku&#xA;xV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV69/zjF/yn1//ANsqb/qJt803&#xA;a/KPx/Q5Gn6vIR0zZ6f+7j/VH3NM+ZdlzF2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2K&#xA;uxV2KuxV2KuxV2KvXv8AnGL/AJT6/wD+2VN/1E2+abtflH4/ocjT9XkI6Zs9P/dx/qj7mmfMuy5i&#xA;7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXr3/OMX/KfX/wD2ypv+&#xA;om3zTdr8o/H9Dkafq8hHTNnp/wC7j/VH3NM+ZdlzF2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV&#xA;2KuxV2KuxV2KuxV2KuxV2KvXv+cYv+U+v/8AtlTf9RNvmm7X5R+P6HI0/V5COmbPT/3cf6o+5pnz&#xA;LsuYuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV69/wA4xf8AKfX/&#xA;AP2ypv8AqJt803a/KPx/Q5Gn6vIR0zZ6f+7j/VH3NM+ZdlzF2KuxV2KuxV2KuxV2KuxV2KuxV2Ku&#xA;xV2KuxV2KuxV2KuxV2KuxV2KuxV2KvXv+cYv+U+v/wDtlTf9RNvmm7X5R+P6HI0/V5COmbPT/wB3&#xA;H+qPuaZ8y7LmLsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVevf84x&#xA;f8p9f/8AbKm/6ibfNN2vyj8f0ORp+ryEdM2en/u4/wBUfc0z5l2XMXYq7FXYq7FXYq7FXYq7FXYq&#xA;7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq9e/5xi/5T6/8A+2VN/wBRNvmm7X5R+P6HI0/V5COm&#xA;bPT/AN3H+qPuaZ8y7LmLsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirs&#xA;Vevf84xf8p9f/wDbKm/6ibfNN2vyj8f0ORp+ryEdM2en/u4/1R9zTPmXZcxdirsVdirsVdirsVdi&#xA;rsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdir17/AJxi/wCU+v8A/tlTf9RNvmm7X5R+P6HI&#xA;0/V5ArKVBBBBFQRmfgz4xjj6hyHVrlE2dm6jLPzGP+dH5hjwHudUY/mMf86PzC8B7nVGP5jH/Oj8&#xA;wvAe51Rj+Yx/zo/MLwHudUY/mMf86PzC8B7nVGP5jH/Oj8wvAe51Rj+Yx/zo/MLwHudUY/mMf86P&#xA;zC8B7nVGP5jH/Oj8wvAe51Rj+Yx/zo/MLwHudUY/mMf86PzC8B7nVGP5jH/Oj8wvAe51Rj+Yx/zo&#xA;/MLwHudUY/mMf86PzC8B7nVGP5jH/Oj8wvAe51Rj+Yx/zo/MLwHudUY/mMf86PzC8B7nVGP5jH/O&#xA;j8wvAe51Rj+Yx/zo/MLwHudUY/mMf86PzC8B7nVGP5jH/Oj8wvAe51Rj+Yx/zo/MLwHudUY/mMf8&#xA;6PzC8B7nVGP5jH/Oj8wvAe569/zjER/j+/FdzpUxA+Vzb5qe1MkZcNEHn+hvwAi7f//Z"/>
+ </rdf:Alt>
+ </xap:Thumbnails>
+ <xapMM:DerivedFrom
+ stRef:instanceID="uuid:DEC81B9E214411DABD12D45BA291F212"
+ stRef:documentID="uuid:DEC81B9D214411DABD12D45BA291F212"/>
+ <tiff:BitsPerSample>
+ <rdf:Seq>
+ <rdf:li>8</rdf:li>
+ <rdf:li>8</rdf:li>
+ <rdf:li>8</rdf:li>
+ </rdf:Seq>
+ </tiff:BitsPerSample>
+ </rdf:Description>
+ </rdf:RDF>
+</x:xmpmeta>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<?xpacket end="w"?> % &&end XMP packet marker&& [{ai_metadata_stream_123} <</Type /Metadata /Subtype /XML>> /PUT AI11_PDFMark5 [/Document 1 dict begin /Metadata {ai_metadata_stream_123} def currentdict end /BDC AI11_PDFMark5 %AI12_RMC_Transparency: Balance=75 RasterRes=300 GradRes=150 Text=0 Stroke=1 Clip=1 OP=0 Adobe_AGM_Utils begin Adobe_AGM_Core/page_setup get exec Adobe_AGM_Core/capture_currentpagedevice get exec Adobe_CoolType_Core/page_setup get exec Adobe_AGM_Image/page_setup get exec %%EndPageSetup Adobe_AGM_Core/AGMCORE_save save ddf 1 -1 scale 0 -361 translate [1 0 0 1 0 0 ] concat % page clip gsave newpath gsave % PSGState 0 0 mo 0 361 li 289 361 li 289 0 li cp clp [1 0 0 1 0 0 ] concat 288.5 360.5 mo 0.5 360.5 li 0.5 0.5 li 288.5 0.5 li 288.5 360.5 li cp false sop /0 [/DeviceCMYK] /CSA add_res 0.882353 0.768627 0 0 cmyk f 1 lw 0 lc 0 lj 4 ml [] 0 dsh true sadj 288.5 360.5 mo 0.5 360.5 li 0.5 0.5 li 288.5 0.5 li 288.5 360.5 li cp 0 0 0 1 cmyk @ %ADOBeginClientInjection: EndPageContent "AI11EPS" userdict /annotatepage 2 copy known {get exec}{pop pop} ifelse %ADOEndClientInjection: EndPageContent "AI11EPS" % page clip grestore grestore % PSGState Adobe_AGM_Core/AGMCORE_save get restore %%PageTrailer [/EMC AI11_PDFMark5 [/NamespacePop AI11_PDFMark5 [ [/CSA [/0 ]] ] del_res Adobe_AGM_Image/page_trailer get exec Adobe_CoolType_Core/page_trailer get exec Adobe_AGM_Core/page_trailer get exec currentdict Adobe_AGM_Utils eq {end} if %%Trailer Adobe_AGM_Image/doc_trailer get exec Adobe_CoolType_Core/doc_trailer get exec Adobe_AGM_Core/doc_trailer get exec %%EOF %AI9_PrintingDataEnd userdict /AI9_read_buffer 256 string put userdict begin /ai9_skip_data { mark { currentfile AI9_read_buffer { readline } stopped { } { not { exit } if (%AI9_PrivateDataEnd) eq { exit } if } ifelse } loop cleartomark } def end userdict /ai9_skip_data get exec %AI9_PrivateDataBegin %!PS-Adobe-3.0 EPSF-3.0 %%Creator: Adobe Illustrator(R) 12.0 %%AI8_CreatorVersion: 12.0.0 %%For: (Alan Lillich) (Adobe Systems) %%Title: (BlueSquare.eps) %%CreationDate: 9/7/05 3:18 PM %AI9_DataStream %Gb"-6rK8/2OXKo,q%!3rRn7t-g5*PRDJdXuMPPE==u.r,k]Xtc`nDh!>N1H-C>%t$lCS"Qk8ss4!`bMRCoN?%@WY[OH3/&@_r5QY %3"TGEEV'2,GMg&YpUcphs82!"ft69"LSK(](fEDBn\p!-oBY#cojt;C1^+T+6ICL9L(pfm'n>rVeb=9khgPFQL\IuYJ+qddqmZ#Y %I/!6mm@Rb"49"g4n*$7-a.'Ok?iAsQ`V&,BY@"qfqte;/%sKZk*qRnbfXuT[oDP/fhu(CdGJAS)iTJ68QNF\oRbR\`GLQo+LVF#j %GOJkOrVi;<^S42)J+Il.o_!G',(7^cJ+`Zu7j=HoR#/E/?iJ7+hgYU]a7jf5!!2cgahRiOp$^abp[Q/EO)NmiqmW24fsV\pGbX@K %^NfYT[kHV[T=o^Pa5^7)d@p#9UWWUZS?=U^R%$FWq!e.Q48DchY@%7nq[]lu1Kq8ga^>(klaLfis2bVlRf^?RrCsCc6dU;Tec5LF %j`eK>WGq'n?Jk_OmE:QoH1]l["*J\h6eD7<-##>LN8mp.-:4'&67MFAW/R>qIn[si\RIq3NqVf=Gk:c-5GoZRp#b)NpYYpU7dF,o %?HG06J,&fhS,\fZ0$_WpPsq@\rr2<N&&3Dajs(<G%t9XU^O6(+laK)C0"(,*[kBIh;rs/@PQLmWo#'p&Ij?ass7UdJhp7@/d]Z3! %^3ob>f,nQ$J`%XMq"if2^&NSLg7KtB?\L>KA'1#50jjb:*.0clo.h>QaETi?gJqAWA<uB*(n*3"QnZ9!WVa^HDgqHCh9VA'o^sk$ %]_Q0)`3^Mjr8:=8AEs36rYK=Kiu^M"I](]Egpm=Eg<MN\rUMI)n5$fsl149()rfRFUGOY"R#.+J''a\e?@I8nbUi?B*WQ$&s*_QU %o1)K:M>fMjT/#><.JS18CJa3`gGsZI*56Pj^4#MQ[A?o_-l!sj`J@DHU/[()?<E\nTF?ZS`)"GaI\Tjk.##G*';]Sb;<mij2/dF' %c0[+*]Qf!G?bD1,[9pS^pFfiD*MHU!'m^"XI#FHe]lSr^n.VYF-i?@]oZ;D/hk<R8M)+9,I\P`>$)rhHi?pg_8,.q,KMU#OHA%pS %2gtjd4oqR#;t-OrqLtOioATp]2Emd=GV!)60&`_XPb&9U6G(SkfKm'-Od2#X.#%ZZ-X)ZFP[;OW11L$<;Wsa4Y]*%rU4;rp:["@. %5CNt$JD_eITmuhdUF9"aHklRpBJKS19n$p&KKe?U8dXC60@Fp8*g@%<Jlc-anWFOY%qX*LP>(TY[ADLG/c(6p-meGDrWuAr/q0N' %H?]/$,hqIAE)&*CFIN].XI-AGEfh&u"e-;dVS[PN::Mp$Kl<X>7`>-M[%ijoQe&"IHnYMQEg`=>bqeFu)en77rtG36B=lYRHss@( %SQWt1<VAkm:$u*Y6g[m.Co4D2Cg:;e!>HD!;1%DZd;&:l?>3JUcL]!Sn6<9ZXT+ST^0,s/5O[_*qHNq>^'I"IlYlTcP'gScbJ0S/ %F3]M%lbDb$q.BRWs))`8oD2\j*PQdl9H`Y>q=jftHsV<G^T%2GI?(SM:Dm70CnKcIol!uRE0pN![4eWWQ`QaL]m-gCV+gFYs+rfJ %I/DRr5=Y$*EZX"(k/d+&.K!H?Rqc;4'@1"cpL^f%h"P$_p/$U$ILGR:><!.;4'LA,(Y[aSrdRhRF*]I6`W)9[J*V?O:ic2tC0t*7 %I,$J\bJTM>A'U7\E7_Y.S1(ptbuo'ImQ+NIFd?97],e#O3(qQ;c(e9>9t8t+WFu81d:_[bldk7*NqM_he!q^#r(jc\3U9`Gqrt7n %rOUPZrm>B#,rKs[X^$3fZfH/^UNPl/c&rHMRiZsgZfHMh&$9&3A<pJTHa@HMbuo'Nm`3n\V_CarWkJ#4T%5I'*;<t/<r`''=N?0Q %f$g$5QfC8@h>7'3fR;W-e!VNFj$%,3qN5C3A[iiS[[tJi3VU#45%i^JD!'BF;8UY#*=KOCHHs+Ps*g-sfL\rWcYji1<U7cPOpc&t %)C></f!0\SHBPVq1>HM2#sXJnCufFr]ifAQmB^uFQG;uA\K(@bgNlc(j>,M'mqrI"VnS2IkA<AM=`Rs<96Re9p,_o7\+M"YaX&NH %^Z<8fXf&dkNRk502bPduT3!V0o-ZLj0#rB4Pjl"`a7=DgjJgCebAj-m-2bF<=M&<2buo'Nm`3n\rqC'3NpXK]V`.8oa*l+Aojc=2 %MeWd9Xf!sJ0#rD.mZuH'CX&$cE8Ttu4cNTb3UTO`\"<R=HcXrf)RJM[h_O&TmV_ugB$"Vo+,pp4pp9&:RPqLV?ZOiferuY7-Ue>+ %^NHX20=ap!Q1D]>/@c2`a\fq$CE71lXX?,%0!'IrPjn9Ha%"q:PFEkbiBB=.ropUrpN]t=CR/4)qs<.@cXS!-ceEb$ZfEms([Z*' %rH7HMDsL!=Opc&4]"=g!r<1`WdCT#3B#u>VS+@q%FdAPYqn@4=C!DeKC=Q>MC!MmbEM"-qr2eJS]\P5dC9uuAguh'35G'seY?F_? %QCO$5P]c:^SgB`^*dV$dCR1KOqp]cSZ^YJ!H<X0TQ<]IIP237Ti[hVKpOh>RO$?8ia*m4?f$g4#O*Oqor[^(=VQF%HI`Vc!rZp+# %PG3`&f/hKc>#0@.>ZCU].,j?sNjYq=PFNqciBAbaq"_"$rMoPOB$#b7c]&Q$rH7HjDsL!>P07fOFMlSV?H4,X[[tbq\Z#3j]3EHc %BpN"aq]TnD8^*>j>0,IsP,C320$!pX\+QNBP)F'mn)J_OZfHMhpT7Zun'>klCX/8/eQHoVmYBAqV_UmtWkDQCT&)$/*;;Hj_Tug7 %gNd"!CR/4cqqNUYk:t"HhU^/E-0O;PFku>45P]Hg?>o/ob`_R;T<iE`<cdUnDsPH9-(!Z+FE^A,s%C\$bA]Za-2]mWZ0"6QV`@C& %XF3^*nFKi(g/[I\cB?@is6]b2T@4eWs7Q7^BXA-GQeM#^-,12hKe<4a\9Vs<][I/thGj1;Ds$je,tG^Iqm)[Ri5RjYY\nmZr7s;V %NMHDoqu.'Yh>GQ)nG'$pn)(kZSU=N=k&7t[rUKbLb,[#fo@O$3Sk?bCLDNK&rdhi+?iTEYp[luh5.pppO+6olg\6Jq>^uAE\$(k- %HMR+*a.'QAhgP+P:QGjHO%608cnF;Sa(p63]mTFlT0Coa5CL>Z6%=+Va5?mnlW51-Z3&Ul^A@iRa4HA2o[PJ)'D'-3k/6rNrVlRf %n)(m^oPM@CA1Et?./u,Cr/*#;qo<otkrg@FcssZdnF=V/U!i[FTJ)pXlaJP)^4#Ub%kmtXq_t]J#R90f9_.!WaBlN-q;M!MT0M&u %'?'IfGJAS+p<@f*X#)_r?bQC,n]e,DYJ9r*G9:2L4l4o!fAF=BE7_=RU!MWpa6U5's4@lc+YV`$F8VX`5Q(&FVD1d%^3TG^bn-Jm %.i[C'r=Q5q5(<2%Q[aD-jF7%*$SM8*$"Ei+jh$j$NXW*c6N*#DP!7X#,_=K8_q1\$>LiJST08h\j728;oCXb#]_pn$C"o7%J&7ZB %of'ou;sV3;9::!cj)du8Rr8f:HMF\!(GB)WkN<^G\+JJ&F%oH(-e":CM=^ps4?\]G1-8gdoLsM>3rV:;kP"ECpA#.^fCTc'1-LJd %85Go!oAf%;kaD77Skm\"#.26cKY6F0k4%_lSniWZ5FJ+]:ZNnMj8!]m/H!`i9[BS?maUWFI^m?!rK)Lfr*8hloZ@"VIA/nk+0UaS %B>JZI?ZYg4m;qkcT#6%&G3:=#]OJJ=F3$)6S9)g(q1d6[,?DK+;jka&E5e#j&PFUaP]C&ILcG&,H$OBm?-h-G[Cc.aiG]g@dl#[j %/pQb1p#I"\rPd#Lc[<(S\/To2DB_7.-Jt&WCOQ`U/[=sDbmUCe-JBJ_$/LNKl+m6N`/u#$d5,5N0p#Kt1LhF[)D$q+!#UU16Z^/8 %I7>GO,=l=$&RBX7rIK\anB`Nu"c1)S$ODLJ)+tH2&Bb\s$F0gQK<.B$+FB29a<G0#**>=WV_Yh-37%9FJ&Lc3T)&0#f/Fc]1[uOT %9V%Kk9n!FJSC3Y"10kQkDFmTp'6_#dFd_(Pk:jq:c$:r5omFYeqM`#X@[WO-=VeLA,qSSj,dpaWQQ$QfB-bYR*4>3H[lEQ`$SK$O %Z7G@sh6=OS,EBG+PFqg5SbG>C85Jg0(Otgj%O>6(G]LG&;jbH8>bEhqKG[V.TnI3-DJ5i;d51oCVDuUB3j]MeN%ma6WEA.;7QfNK %BS&?Z##8l-6uI%%d%uhu]\#*(I&6-s_SPgBN9;XW4`/lmJd]s`iJ%%nJ0Dc@il&$Q/M,$Ujr9m^cWI!8o?^2_fJB#6`0(5E2^B@u %%Om1'B7@bg2,!fU:IgQBk88E+HH85p+0lFApL"5#!).rccrj3+"ggB.0H2\fT!QAVSA;5A]YMb,gp#I_q10E83Pr,`_!9kr:R1)o %Cbf:.T'hUdND5n`g-TCH@=</pkKbqb4X?m0kTeYO16EPl/X]:p24@2eRo2/DT!:nPM.KVD-eEqBBW0C\SRCh!4*cu0l7B7jB%'C# %(/'?6)UEZ5\E7?HnH.ZpBpa0;^iFD;X$C+l+'J%of(ThnH"csl<pTRsg,uSLL[La9@m=H<IEbAEYnHc3EbEt&c\Xrs1ecLX@[T\= %dR\[&eV-J;3Y;89M2Si"QIdApR3X&@XE]ntKk+kk5!C>hhpQaVPK[U$^IYZo8Mh4rdY[bgS4;P)AE'$\1ET0),>#Kpa^8]s9Z4'r %1h='@37fFhR:]BnH0&ap/Mu'+iokG%elrciCQe0\;_ui9oe]efR^COpf`%D\rg"i!R\iBJ)'3LhH^aO6c2EKRjuLQ(/P51a9pJED %2NfibUc9,f+;54AF-<5$P2pDI:\d8e-Bc[EUjEm*5nf7JEtYia')-28X4%\QD0]#d$`UCfjPW$)j"3u^CRUWY'OE'(k=G\,U^1]. %^VHS&'o]"2Z%OrG,gAoZ8W2RceGlXN&Ft!Zf!*N+d'D$)U1p<:7GE^6'ocui=1#-p?.HTCWdLF=jkHeB;S];^>7E,EfJN(e#9PY_ %G=pN;E)jcVK:d9IGc60()[1'C=-W0UBO96$Y3OfDqGq^?kh5u^!3=l_I@faLp5GCXXK``q5$.N1(/FcqIKDatOuqT]k/7AC!?N9m %b^&?4Qq4\;))j)ef/<7'.=n!WQ5)pujM`/3S`2F.LILB[Qu+rF[k'oY,7%1U@=gHb*mMJejb4=(J,ql";T*rn+aYQ5&rRZ]Xg#Sd %(:hLq`&qMV>?K)r(;P21_226m'B\C$1UEX>LJ)7ASug!)jh2S=f9rWr&#(u8&rp`,Woe,>VeJrUT;FoF>-"Ad=cXV'Q&7=3FXd_u %<9h=.kCcidp$+>>>]3TR(1);#lWDQ?rkO].Yd0gF87/UDIEkL^/M#Zs?L"_>dEenG'<C*5AqB,8A=Z-[+G*T]2L(d%e)EA,):-6; %B>`ba9os/AgN`'lWXg%?#M/)3q"hM_=h88&4k'6Ig(3p@>M8f'_fV0\E@-HWU7YjTQ?&7f.H9Zs%UXU3hq'gE;%qDYcu31"RV9DV %1P&d`<r8R7dXlr4__EcF1eZQ&qsUJD1cQF;5$c.LkEXi]\#;fm/A]&X=#<YLd;@!RY`-"f^RhW"&,>0)YC'#bgVeM/\:n)#>_jCG %8b@5/\c7P%gcVX?\[g@&YPYA]Y@#%-hZ!=&LC2,emJtaAg%a?P1S=YY5##WOZ+2LDn-_/%(H0QIQtNkIDqGPL/f(tIqB>29p?4=M %EB#`mdD[<^&)2a\%UBcXNBsWXLc,/CfnH`Y!s]l(ll\S!nrXD#EO`8e"$8niL*Xj%f`/L"R3WCY2N6AtkC^'cP%5V%1g:Y5hX86C %D97tC&;0Ji0`"&#mpR&\(kj$>2Xe<pmpQYcI&aierVi9%r'*g^Y%.L8=NY%pO;;Y5DM+m%6D%/d+rhPsUk,g3;W^O+dP'a`<)srM %r$Br]2jYq"OEEoh`NQ[=?V7Gj8c%P,i30*ZTrBpE;@KFQM'-/e'c+k9C@%e5QX%]M&saYI/<OXMCQ6'h>*GjMe)na>U$:CcAtq"\ %?;DT.cSL'"oBtGX]@Yp[J#ArLEF]02T[^2)6\t]_a.E5o[s@oJ*8"m5)BFneeOPSnU(9=5l2aNt?i8pH&k1^aflUVe3cdPp@Ahgp %=<XopSQNpEp/8%rdorF=)>inV=QbRmj_2QJqb>j)Z^V%3g]SZt&T7ceVN-Q=+B0R-i#`K(^h'1++#=(F_)buCii'e;cG01kLLW7J %q,JNGHi3"4RjU*iP38KXV6&&jH`l[UUX-Ljo1Ye>&q?(ba?7\QL83gL)OBs,+pSQQ8VekdqODhj/fa_tjrha)D?=h-lG,+e$+W\' %as;:uh,RQO865gLiAAAuEI_;c5<:1iq[5@XY^Du5*%n>&h"UFBH-W`4?@!+Z"/DX=YtodSfQ10pCrC&f4K^kJD'&E);e<48TWJPq %9f/Y^<U$2ldoE03:,T0-BNBQD7_P7J<@)ug4W?5lRInU$itdW0hGh18X&7@/VL;JE63GO=oFM$?ZToV=L<_T0ADGdmk8NaCL-!pO %k8NL<#!$IT;^V@Oo)A-[7$BJ:]FP),9b>rD^`3K[&`>8Ggp6QL9D6bpldh"Xgh4Z"5E,RT6J2%]^W*JgRkT"l_q6^Um9ID2F53O> %>"&[4O$s#+c@[t+!siY<\@N-R^b'Br!d$AOpB0"*6T?jFKac/*3CcIJaWXqL.S!P3gfs-CP\$n;??29Timg/H7,O.^50\m7_C-f/ %[l4&,;/UAF"W2<<pb`5qA5#i3P=\F]WNj]D.kZ!h7UO57Enhrra/M+>gU_JAPFider1r>EAkDln-1*XWZl1'^kGEOU*#6_[frd0t %,''V4a4=&n4%!RmVUS:qg!&T2`[#$$QreW;D<5L]]3THq?t\o3$WZ8&)n3)0H_M79fheT7&tSiE(tu-`e_1kB]tq9;<ln#u<(lo[ %`_pZueC@*,:"6:j>"fP=X`\@\?S.%U`*:-d)=8eZH2[sV`I#Z%;[c)oB?MEgoF1G\l;QF"cj]:>'>C%.mBkbGI[5W(^pG)LOaGFO %*iJn^R#>1Pqt`T/;-'P1IlU/=R1=)hW]/^:e#bRc:>Vm4XB+,QG2+;Xh.GC5AmK?'o`e];%^j='Aip$c0g.FHg>VhV5\M5E4k)a\ %7:FQVq07-8$n<T)CKQRZ.[lTZ`g#1i<%-A-p?9ShN]KrWZ:WZ!G]p#qd3i"3m*[b%1A"2bI1@:U#<$[Jk,oW8bj:#g%*ul0p4A(f %3=k"'c+^mM@D(`r/@o]EBoQp_E52lJ[Y#F5XJ-tp1Y"UW28a%6YOBf>;)($m-3maJg+Sl]bW'sX3_L)iGo9`4-^5?=>&E<!ckeF# %8K5`;G#os^NOepoW>"W2^Kf$dh:4`l34Bl[T@jGBgln-j\L%#t%-SAJT4:1ecelM5q"d2sDr/3Uo`m7C2]ml0bMTbes3KJNH>FQ" %jDCklgF?q!nb?l$^O4d-WBlZ*ni("US$7p,oc[ak9T\]XeoQiod5Oh7dDL5TgqWXRk*tE.G=VQXWSW#U1A?Uha=g_YQ:ZRg49*:O %heO-rA=ibkTD@OITKiIIJ:BWVj"HJnqJXjQ)i"CaYL2H+K6Jh6)a/XATIl`NUkQS=[04Q47e;\HF1NV=36#NZbe?d'm/7$QqR&'q %eGm35CWAZAXh&`lOgWdPki]#5At`fH=!Zs;"'^ld[`"r1Y?^@#r-OG*_^;j^2m<cB5ej/q\bTr'1--f40PkI8c*`Xe[t;,,Wkc.B %]S.e/>SXWW%B.=XTk2n27R8U>I(Fq)DdX_[fWf"H_-/1=j_?4`8;GYb@9IPR[d<*#VQ5m.L+O-U_j1`Xb(I3/-*iP7:lj(=dFK1< %M"_4_a\*#JeeqTqA"qs`?<UHd[?h\g6:gh\OpT?-HDt6gKUb,+K39Lt"nbtZM.p+fTU$$60eLVhUh,P%>0J0F4'Ipj@r1d@`i-h_ %9JDSH8T2e>&M5Ig/Z?^)e<p$aB]%W%4%HX0,j@T`BFpF$N>+60NL"2).4(_q0q('[E"1[;DDFaMaVLZ!d:o>q=Mi%Dqo*iVReFm7 %T`0DPTDjm+V57`K5m'DO:eStskHqO(En)pWUEp-9GI0u%(,H+[9$:7==q%I=['U7>j^?5i(5D\kWMO/jaW#LcPqC59\<WD?()eTu %]damJ^IDO)AP5[SaieDL:J8krhgcKJ@l.ibC8P?2B`FHsPeCQ7BYMgH)(CGo5++kD>'^,@+D)H.l@l@DH0/3sMBG7QY^oZV<t>BR %EhD0n$qN@;+5MkY-.uRd1U=Ik[Z%`B<Z#je/of#nn5-oS,HpH-$IdAJiO_V2l;mH1CQWd$iS23H]R+2RC[jMti:V=+KbE-%kb)97 %-4e>rH.-Vo]XHPsRs)A]*?6Yt8k(/7Lk*GMMAdqVRcTSp$l6C>/H[5<\o/<'/XA_YUFG,('^PPCk^2G^QqE[4\[NtWl?Ju0VoNVl %F67"ks'@df`I=Fj\-tnfM%Q<,CSp1<aP-4D5#Z:9N3adodCZN6mS*Ip[COo]Dq_g&;HnH:/'2JDH-"k1l1rT_\V(B1s-!QoL*;5R %5/-saiQoQJrpXPa79)PlkCo.;>`O^e">^a)7$7g)o*CRR3a<@dkZYZ8@+MRQ^-fA`>5^)ZD$&;.'+41P5YsTO.*2^[(![tj>Zhi1 %]7&.PpGDiJjGL;YRR@f9E5="*BiuXc-6Om,0,"L$SB.OuUUutB.RFl4Yb[[D=7B:4R`b.P.h*,Bj>'$clQldeOtOkEg7:f]JcW,X %iR/H-@9P-ed>T52hHdZ'Zl"pr@j01Ojf;r&=eW1]nX8Ic=]t*=@&^%bKdMU4>A+YRnG'%`JeGZ\e6?Jl&3;^N,,UM!jAanpW]Pud %9pMM[869]Oe4;!N"(])NJj\5eC<f;gZs6&Z.T)/"!a:bAE=ic,0;H`u'cK7#E4EdaMfjVD&\!1=MDHl\X-B,eBQhran:oOQ_B0DM %r7b)XXM642n<5R^:W+<k+jMYO4&HXpm4*1O-W,m!=MS/p*)AB`V5.Uur[X^FLf5?b2PrT.5?"?i+LRVoFrE]%A`<c>5e3C$ktbX< %UdAk=9j005KJ4Pm)@64FV#Ca^GqMG=Xr#YPkbM29hC_24.GR!6*FgP=P"=SF),-JT&Jj"]d<q<\c4Xjb9`6UP%SmAZ8/i<d*I<p5 %e0T9h[5fG#XV/!O:G)Z>]GJDWY'M)ITOMVqft'+<d2t.ZS!M3NR=pIm]_Fp(I4qV-;O\O:i#q,.XX$XI<mJd-$RT]>PCc1ckQ.kB %6+fWHRX$&:5ujl=16GC.Zlm[uOt6k[&XMg\#_#s^F/FX(6j6E2,r<dV9[&oL>GOj7gkkA.cni3XoISrN/MoI1`3)c`kC%QUT7h"B %kt:7g/c&6=#oUXVA>D78BRTHc@/>tt#,a8"(/_p'-qQq!<XjWcR`/0Z,Vmeq"#/KNcI=U;Z4uBr$#G/6aljqNMb+/+1g0Cn91RH4 %LQ^kq<>RbF%L&EH]<86(LSS`5@A(#N.`F5?]#nP_*(e,2nE=C0.5*OJE+V-Y;`hooaGV\s^X7RiR!us^4r>T`mc@t=l.HW5IV>2S %;@0HmG)l]]>mno25WZdiP#W8OLdVfpA#2cV:S@5%jcUC_[JTsQNY45+_9a?6>D`pQ!bom"qCIQJ<L(/6G*g,C@JZ+IFce"oUq,g& %j'Y]0R]!PKbpf;3jgZj"a9ufV>(@VfUfrr$Bm-j)GoDeoXSnZNj[j7=P'(e!6QCIgi_gNF^,snA/Ai`k]QAk#!u_8"]-3fBA%aXd %GSpj&6*sF&/=FBJe*L5MQQV6aeOnDD"VP+J+>%pDb7MoI?9riX3#N=tFdd\4I4_c=1F>iA<)nrNOk6E]_8qA>E+h`(p9$W&%AAV4 %AX7#$?#!3ILrJ!i%:RPZ4"&\1-oilZc`'\d6b,0%#>?>;+k%^TEWr#-lU\rZEgLI0U+0?`6Sk&#($R.+N3bqY\$'ho&9Z*Gedp+9 %UiE8:(GL$<J\0,Uc$af9gd3=(0L6'Skl?^pF(thK,tgc4P#`>=-\nO(qF!q$(>M[c+^@uR6*kP$"0%a.9Hca@dhSEo9/[H81__V; %cq:X$,`+_1os&8T`TBNaUBbk2<,/g,19Du6FjVPcY#fCg]e&0UOLV$N+-g17@jIo1Z7[(uVb:G9,Xt8hRnp-G*TiN.R$KttO/$VM %5HVti0oRs1[)>QTfrpE;'@P-@2rZSc$Y2<qg?$Dm!Lq%'arK!iTO;c)NS@dA$CK<J3.]J0X`gUs'<f)<`DeYu!^f@.(?si'n=n#r %g@eW\,e:Fb"9ZY&_bg#,4]$'2Hjfj->G060UQSU^JAspg/s$nhEDj5][_NO!F05\/T6VtAX<oINF_L.k$ut8-%0ha?SX*"f=DG^B %gp:*k?qZU+'^J^AQOn>f]%/G%5A=Q!:3gIs#jsFBE2uL!.p3J%b#V;@4+KJ6PY@e)Z=N^XTMkM3;KnC%CaN'S)q2Rf:c05sSC&5X %AP06V^,Mb+KT33THo5MLF935^BJpiqj7+C#7-hPY'&!c3M:JNfJr59;(QX@Q)2Y]Q4?T!1Nho6_KL21SA^<[POIp&3,D=W\/&ieO %Z-_d'pYDe(bL17UTknGu8Qg<:W1RpX,h64?Jf<K@b-Q5E#EcU1Ga0+T"-4UJKhZ`%"1*_im"m/S0p$trc%8T1P@2UBf9CDW4TmkJ %jKeW<6o#8pTlhXcK5J2.h';g:jT7(EVUd$DH[qs0r`-d3D<W2=RrcaAnn>8Ok(Uh\CLed?h5ndbn?Se)92(8$3?b-9.^FPjB3iD` %iCm&sW'Xh%/PNu4$b,@p+2I5o)?<@iqC-UI=+Ks65lTg2W(47r7Af8W"3=3BLf.ql`PG;RFY/DeNuU3FUiCJ,.oCD]cXoW(FiJFV %U^d_(:cS^VdoE\c?CIh_=`k8&+%).DeOrD.Tj@^m0^=WF+GbIoZa=oSBfd5hC)Z\7Y(l=f'XIIAI.HXP*YhJWO2R)22C6J_i-!DR %l<V10-@*BY5*>b06dE+?M/uSE0Kin(@b#M:XM_8>F"X?/X:[A@M%m_')otX&`"OrM>G&NF<24ADYFR"-L&lEE7G/B-d51*a_T9$n %%I8$LQj"Z7HP-nj)qW:S@0UF#@Ec$gfIZ\jXtg>FkD<pje?F$B2)_0B5DW^J9h&<J]J=XBD!lG:YeF7b("#aE6hnPlQr@J/cn[4` %&MMLW1:D'9mgtBuoi0bc,Ru\^<JeTt>G<\";k>M$[0hkajHV5*bH@&:53]Z:&.StbbMX.^;c>sh;MAr`N!q;d)iQl3>2^#O^eDX$ %AE15d:W!HkGpS#a-;B>Y=brKQ\oNCWf43D=/ms\7_YaaUPmSI$:8^ZWr9CAh)4\W;UU=MbL9\2Jk`31_`*-'_1BWhE+`Jsk/GruG %=F9357g,,m9fk<tF(UfG&KlN_2%UG<(N2fl3E7&2&%@n$QDB_qa'"$.ACEQ?$%ubCK*$V>84/HZS[mUaG-JRZ/S5@o#6qD7+d-Mj %%QjoGN.B!2)+6Zo(f8%b$T6pS"QunalB*8=RB\aA<7>4k6?61TTnLk"U=jYOA80us>b$(`_l"EL+a;+fM,;G.oP_UL$FH8$,]I3a %0KS"Shgo>PFsb*P6La]q33?V(>^MN./^4@V8=:f34#f[g$^JpN40]t50RWRGbFn#"gpfC%?%5V8Ld`+UEogt2HqejSGblO@?rCU# %dP$=+PTh%V!7KlL_^Fc<%MbBI;aN%je(6%:5Z+X+lWLVX30_9a_6'4qF^2.+>L44i$/AH^GEq,Q_DO,&J``s)*BIIQY`qF2_5)u) %l$%-0-*r?;Bh_];%O4dj]Zt/kXjfP<\B]2rk?+hG5*s6CC1?mm%?n,dcr;)*`ZoG'B+^PiE-m5(\YtI+_D7Pc0s*!:4\aS00'`:S %W^LCm`/FDt)BjZ5J0b5iZmD^-NMn70D++83N^So=$S[ig(!/b_kHJJnE@QcK#"3ZLP[R*=OSY2mH\/WgdRRV4J;&q?SXI+N5I&6/ %OuR^,^d\4a)'36&6sY:;(5JUb3dA6-RMAR?TS.1K=ZmA:5amPIY)(f_E'!7I=98^\X!s7;V+O+8:7"Q.^C3gE6ZG`!6]1YeMOoI7 %2(h9l(KP3!kIiq0"bY#=K+6g@Nc>o%E7abtf:UMl`$-6IP`Z@,I+(ZrJNTHPeP3s_%aAueEYWK"Q(^k6ft;e#TO;Z"ks0&l2j[X- %+OlTL/D.dli#o8E>A"!HZ;Z<d.uRgRY][q=gf,Hoh2sXCBP"2j<di"`f+hgM,V/r$W9$o%VS&j;^FX_iH=i"W6:\Z,e0-`d0KHC% %\@IG5_Zn(X;V`Q-^gu;@_na;MN3SUL3(UP39[lj];,NX-:?)X&%mle*[YZ1*KASsO<.AuHZ]uu;D,1oQH,QDS):lPt)g8I-jBlO/ %/Y*.tPOblr6q5+3@D=spKq+oSn`)7L=Z8Aq&XL9L98rq:-sN.m@l$3B"MmB=OVk6i"8Y8rR3pD>?Ii1_2.dVJf+$aATj`F+l<M)f %U?qes/6G%QCdr\<b/68i1T^>=6Q4KX+uRM1NbqJE7a+<l9*<*UB@E1NP9-2"B'R`*a%:`oW-),Y6A,kQ+9&TF&Hj'2nA5-\](G^p %Yl;JI`&8a(]G]!AgW<4`1-Bu_d1-Y<bM$R^aC<V#ca-'aYU_TIXCVJ]e-HN(P^'fbd2#:``T6c"K"qeb37cB%[lU#CCXL!BLgEpD %RH4Re)XQ5O`k(E.Q!sJ54qK;@'/f=gL?;Ik*SiuY[1upDB%&!OJ_i%d(V`C^(1drac6FO3gZ#$TUD`a7#_DZ%H0bgH7+Oeo.ls50 %o4#H=5[Nk.6TD<#:o]rf]Dbo&0ob.3dkX2U:9(7s^Ra&"MO8C`V\(-5I<)V1MJ^>bSeP9t%Z%/$X@?[W/t/o31_'s.ENrQ,GQ91Y %SU+ii,X_b83['s6K%;%RTPKOMq]^S35bg!p&9Jqn4be=#.hah!D.h9eFZcolOkjcCca`mkNl9k$?G"FlJ)J6(/aeKM)+'q$ljXhL %=St1(K+68N<SCtn!(NQd7E?:MnC`U,)LY*fM$Y?(;+'X,&+:<&`0"kamCTh#R=q41@e_0e.+EL$#_MV`;9Jrd%l?Q@S(+2['*4F' %+L479h5kpcD+&!)Qm6K!SB1OLJ[X?s`Ja(mlRM2b$$S9M`fW:2Tm?c@19rHY[:+o]l,]HT\Na@1XCmHT?"m7;G>ab""P#/3ok7eZ %Ji?nL+9a,oiDA85.HAF>$r6Kj`ZN+(c!.KSj+Xm%F4T\eR1HVBIgAG:^+)F/1aD"MF`d`rYf5_ee`uV8EN8PoMQhd]+$3bu/-2@s %o9-q!b2"G894WgBQQ:fLjIdK<VC@^\R*m%,AlU4+)u7AMHZ?2@?C\2!dBPQlXB_?c5oj-5YHdVXFkDR'N%HmN+akG-[^'q8UI,;. %_WS[t`cs@l_eD.]BeT]f:Ku!T]L\i#3q8LRL@#/Sh7;Zk&2.N]:U;=>.(pV_J>m4UrJ]QH>+WFaiNBkdYX]+ab70dLYCRP:)YEI0 %EO+Od@7p]<6:T["4cKU1!K1s7/63EEgNn`/mpQ,](868=?&GetA.2-Li@'aKQRp16*0LTNN)re2&BSs8\3h!g4U/6]iKge&c&#VH %$@,30&p8$%%@J.:F]Df9]*7DV;Zq]#(Cibsbac$<:G2c--d5u+N>?=V!X[!CjK#aHGtH%$*DsLKN]^bI@++B_185KBB?NI],iZFE %ns$F,d]k+@I_Vpt4C1Ka<o^%INIsB)m9qGIF!A%U3a4Z'k9/Qe&J"$c.[)>$94MF3dE(WsWCb+HRi&jQ%-4XhYS@S%>sjg+.Mq2] %WdCit'i:*f3drOm95.@Ehj]gp7-,Pm(KVh`.M<6-2"M8X,Y1uAgH8Aj+SBQ/7[44fk/OA_?r"bE1eaGWGf`SEUu6"*-'eTlC.h8t %m(./A$q+p@([TMOH([nf=7X"9JU7#-3!XEI!F=bc$=^(pf!OSe+@X'1Xr2!a@6j[GAUn6n**Z@_ridtPlou:kE=l7MaK]i-$M1VO %IkJ)4OBIq5-M+S0`5s6bBKV^93NZGX;$-E9=`Zo$Z#`Mc!]"O\.'8+Y02l3K5ol7U+pf-O(7q<&pE[mq?Mu3=307T=.b1Bunm&EF %JMl*B(Vde<]MO414A`sS@'?IZf\c,nY]fu`9OMZYZ"(5a2WSiP0&;Vj,pXIJndTjhYtm>i`r_)aD8II_d!`pmN)ZWZas!r^IEiuM %S=I*+P7Fj(V$3Q`:"J:+?e*LLKS-p)/4I1h6WhNqUdqh\LER((&!<Qs9g/u2P^SA^Yk718;!@fS_\k5D90f#r1<;`9pZc8u&E(SR %gM.D;8&TXU\d1KI:rt\66hidtfXBGNnDUd3K=;0H#7XOJU\O<eTfBV;r\TGkZTA6kGT4^OT=9J;P/$>:l"^>YifPA3`puDbS@`/m %A7XYXKJo:FS*l+/Cr6#+T6de[4J-l3-7.0/-c]b@&UbqPm6^XldL#q31&X];]=1*)Y%MB_N)0_M,(`7>J$lF'7qN%W``Y_-#@;-1 %/[?o=1Uc-al$R1#`a-M>g%gQmkX0&B%cbddgDc1c]cFVAAaD4i^14"FFW*i:bfeRQ`:1r)]@Lg-8>AQGC#_.h>iqQONT19VmJOsZ %E#^$*YU*K!OUYkU]lb?`*I8]DQ*@taVjdpTA0l0\!uqe;='Gb-K?[iDNJ2nILsABoIUFDY?<Hdo=rRKgSU8m*$0[pfBrhHI#-=k/ %1BCDq#=l4G6J%\_e3W6YF^ljoRdnsr$;c%2n/GR4Y&&#-biULdecOV1Cr'r4Kh5&$2"lMp?,&66B$SMAH"/R:j>fceRLEJ?:)*to %XAk^!$+^S^pGWWe#s&YqF'!*;L+FC%*6]>(-\3P7#74qpo'cBh0F@-XXE2N/"G&sLbSZhb32OVT-QZlQHC_^d+=a[O*jA+RaHJ%C %M]iV4bSZ_F=Rg2hFL""OE`i,'&E9b5$!(MhcUlA.?"AA&&eAWP9kl.c[q'+5/5[E&W'`c.^o?S@7^%S[G]u^m%LJ&(b'CIBHT4;J %_'";um<&Fq5QXH==jllh0T8A\SC'>9E7::T"X5/3K?-*l&G)6P`4c)nb1[=e@3qA:`(ilYf-G>r)1m$pMDd@h30asCG%V+d5uW]' %9UN1;O[I&"<`U)pRNI.tA%&K7aeGOerM"2J7*Wna=$$,6B%rrAjaleX=N7l7RWN%&(4]Xri34@njr>X.+g^!FrG>(MVgiBCQjF8t %l&:UnnMAPC$W`<"P/nGBf*ltK'\G)f2?,mQ`&QBZT.@felq0rU/^.L5c8H7kYg,GE=U;HEJ6bZXd:h8f=Jj(VW;?`h.'!r&ZR2.Q %@'a-X[Dj0NDSb,nA_ScW9m3u4'd2;sZQ[c!!c77)4/(t:2%qO0c=[d^,[0"P5jnEImWG.P>i03VD0;<JC"@G[XP"n5%#T1k5k;IF %.bQ&6)L#lN,%q$)lOEs?T5(n$"p$JhVU_-gFQct0J>B[8\!d:org[`+.4YIiU!P+.e,YNDfPZ&d!_F$J2G*t+HZQ(eg;I8s!dnUc %dfDGR@6n'q!JmN#r5u/]B.Eu-1WXPls#Gb/qpRV+iDuEOC""0LrTn9rXlOph,AWKmd:3pGaY2Lg485'g);F;f*VsR75/]:[a,W(6 %Yl9iG_e0l21IuuQ/U?#E`S0X1Y&"F'-g\QUc)KqVKJ[tr#9\l+^]g^0]T18&<]8">3RL,ab".R`ckB8T3t.@EatkC,''l+kgKpPo %[[8k66mpYcNJjX"FhKe8aDo!Q#>$gXZJ'lN@cD5jfH&hW8]Xig*EJVg,UD'S/-hB#k\/_#.8+,(\kKi7QK5GL&jC7@U&fNq!K:-D %7:r+O-#i]e=t1b!U1ZLa[W3qDN',@NJ^nu.A9fi76p`Ve]%l8'#Yco;/_Qgelu0[!,hV*5-@tbC#[cM7Y8ms<;A>uI+)nRYY$%(e %jB%I4\jFga(6VkQ7CQo-Cm#.a"ZrDH6S&CR[69^OC'MSa';p]g@>m!FSI%Blf(iJ>r*\N^<:e+SK&K^R`T4;&eK<le-GtuljsIk2 %(4hkr*Ia"PH-7bEbQ/io@h=cWpu#toA_n1UGq97n)l[jq`\(7`X2E<Yj5e$HA-X/*B<,-$4>?gj/pKgnV<BpH/l(^r)^ZPbe)41k %<_WQe'[a9!,ieX$@,U,OSu)[Ui)=.M7U3m_"9_C\Dqir;M8LBCi=),^WGnBi5St&1Yh\ue&#Tn$+3L5o)4*5J(D[8G*kRV2,p,]: %8ab91annVCWQ0J<b_'(kEg'*YfE5.Y3I@"XLb*o\*01M:NVXc4!c<e33OVs5i<NM8U"P\;\n@'mA]j<VKXMgIO$-7[+W&t\le!Eq %NNY:`le$:6QB+qn_4M=l+?;gONX\0I!5S7mIZP"&ncEgQ2)<d#n83@Ll$G>`89.M=).S;[jW1TC98-g,/DdVSleqN.3-F_1qAJHs %r3QqtX=(qoau]=+\`K`3n<'c-oH@bqeYC1MS)YdH[$K`_;o!5=eNe2Y8`J:D16?HSG>#T%*0IO;@h0Vh9+ClsNIB]BPK/.'/4kN[ %3Ci+)3m3r/7JFI6N9!oW"X,%q9=+,Cdr$bU,<$l5?d0A0.<:1K/qPJu%lj)H3Y&c[FqBRUJT.nKM'6:*6DP>&Ce_2k]K<cHh9L`A %H?&N>cP#-s?&^sHfuMB:OYc&VWZ7tQXV2jX+D9;mgiOW0.#:@3\k58/&75[`NmSJkM%=RVe7Da*WGogS4,S[d_=Op.b7%o.AKHWL %i*@^**dte:c4",OJr&:?)9BhZ,>\!6@hrqIijq@2**&p["?LV,=_P=>+6T:V"b^<q_1g?BB"Pna64OJ8*T`a?`i6X(XCeKQ;8nA` %RHHI)D8m/Qf-DpAh)KQL4]YMJ#8c(.dGPhETPh.nYhas8G9dij7ma.0ftr-6FK,qY)$_jX]"BBJ$/].Ob`u9MO2*)a4f-/t2he:J %Rj&,u/Y3L(/Z)^f,[)lj*>j:<:7ON@]cM+3+7(2.X6\gt%D1f.B!eNr&#U3sCf2\Z4E^h(2;K>hZeS.aS((sk_0.VA9AnVE@\.%n %ZDkj2&HlJLGZmfahK';CG`e1u!f`Af5.<Td]:PQC&U__La^%-Y&maTW+(\"RG*X"Vb_maDc?2(jklr:4JiV/BH[KdUjqZ(C5nW(T %>AYB;-;d.^SAXBo*$d.VZFm7$HO>,T!;a\*EtDH<<;1[OBjoVsdo?N%?<dgpo8=q`6i*khr[/P()IE&%7Z`Z^3'/7I,f>nN3j:uL %(g[GE^eG'j-9H)j642.or?fcs6G1q?NR'Qrh&'G=Qq!Qg=tnT?"&iAZ,D1a(!@6RI)4k]#:,Wbu4+0scjl9)TitFsCBp!N'%1XpI %Qm\u#Y0LY9Jk#$!?+0$_^i`1s2'6IU[/cAaX$@8^$$eM(>1p2'3H;.1>1p1s"F52]AJh;^'\>ag^,mhaB&$e9Q`6bS&<1/Np5+Up %9S*#U2h02K6R&^J-:nt7S7K^d:25k=9AgK*P-_"&6E<V[7n2gIQr=W[-*X6SZcremYW485<oe-8PcW!S4I6Zc(%[mT_to4&0^MsN %gs19q(s1G6/\^@kF<*GGGJIOTK&dJ:#R2,=pe1qP5,KJD^DgE16V/f^9&a:rT.oRbM>;as=:*T[r6WR=fc8$6,["80Xl3=38ZFfj %,3tps5%uX^?TI;?N*Yprc=GP+1ZcQ?2/OW(3HDK`fIiRo3SCPBFU@aRCeh=p&5$P5V_4RnKu-h9V)]:Pe.>%ARU%+ijU1bM[&+N1 %V:Z:&ld\S>RZXt.'&+bLU'%#-#+u.XqHf\.@;)r$?]j>Q[dO$\%t&q`lciD5Y5o#SjUMfl:q)bMK-M\EpY]FNJDF'6VpL]s@!PL` %FCn1s6,-eai!pU%o#6A76Jh2KM\Vu2(l;Md^Y!_i>TlY^^*Kb=0Hl8]@'dk#%![PhJZ("4%"m5lX/3HHj01!U"#6ll"-X-K&0!,$ %ndHClH?#*f'J^5B!\(=?b;&St4^*e5!1U"N9QkhD<<@[_XG]N14LFQ.!!ph=UI+l/hB>\&UI#e%40BP)@8V'RPqX9Z(cRe/nG"7' %?"I.0ZEZ&nf4SO[@/QG-WUc%h5NXG<>p%?3I71(O\YL^0U)D^LT)<_(Z\+Te&]a,Yn*22rI!F#_let_%1ZO>s51^V9IR)oi!ZWs* %1_RFajr1N8c*53!;Ri&./b0(I=u,&o7&FV%r:sJoE#amMX$Z3#F/g?.]*f99s.ZB%d_f/%i/A%tci<JH^:E+OW79(mC'M0.X<an. %V/h.K#='ARqI6K.d3h-K2oU*bQiuR1LfAOhLg,+0\V8YunsH6G6HO(Oc8?YN)UTI]o4tRlmM*[L"!YdL/c7RA$e#-3"fpB4A[*4o %"]N*T?qOlfi3[LKSAC%l+NgZD:5Y9:9U$OYSh2J7FouWfX9V.u1PmtL_pGj2RnC!:J2>,e0!OfkaYj6[:b8etSPmau'/1;C_<-p3 %m_NF!W86(lo;q$722q_IK>E)ug!q=:Z<mL!jICnrK?XQFgj@cj7HZA1\\53^Ck/ptj`_;X+\ONLmAMrQ)sjH^M7j;nK@Wm>0f$L: %DejG`[X[WBng'R2/2[HiF#$:3@_l=<I.4E\_4%d'"k29b54>ttGiOf/N94@K$!tIuX"c[]`c?6'F*@]ScLUr*H/3O08I^S1a_[rj %4-^D(!ODOY]^^o6C/M[c249iegtQMq1G6jh_]`+9^pRrMEnE;#b>mV`N5G,%28@:L2B/9+9WO)s3uo_P\(Q2:(@/LTAe+MlJNB%g %$AqQ%:*+dhoD!u&,2G9dGh\CBe0hkH%iK;UnA@2_/iBtdeM6W/<C994.F]@nDqE2G^??<nWm74^!0;/#&O_VWF+\X1(j%sIiddG3 %e0ajs!=X.Ob'Vm0dDuDE?][R-pl*XlejOfh:/'0,O)X`Z:%BDS3>KUO&c+?k($5qQ8bnC!ajp'8eH^V:a@3eO"C2N"H=/Vlr*@g\ %_lPgj=IZ\`A=,B`,#>a%LtgdV53oP.\9J?l2%4J[+Q!QW3F,S+UYKrBkA8@&8t*)G0N=$R+L[Bn9`J#:hIO=9H!-1Sj$\c8@c:c: %b;%')7D,J^RKJjEm_@d"B6i.9W`5QrPH1tFD23l;*aqH#9900q0j)M&Z?uM<h#e0Il,D+._s8XC4`Q-Vobi,OC/`DAR7o?oJrV7k %m%hA/!BJA]?;Hk4Km5ghm=OV8r8<aqg88"dbTFOB+QlR(Z0fo[!e:u4N`JPYK.jR%/*AH(A:-Cq+lI/oSDtG)j40lb808AcHKQ"* %%n1<2WP=<B-GIqPo"LMJ>?Z4GOf_N@?a$B3UL/4Uq7\0"3N',gXJB+i(3!HOhSH\gcY36-<t`'<XKd*)iO!,];9pCGc2Qd/pQX99 %:Wf8TA$",];LCIWDQUo)LjX&/Cuj/-n[['53LU=I$5H.#>^]a<P-rPFj5AN&aMi8jY",C*!!IIa\fN<,<<G3\!GQ<>Nh*0MkTJ'7 %EiK.LBbZ(r%D^-8Y?>Sd!&;ZnC][NEJG$cRF"N4/eQCB*.];k[MQSeP(7tQ*4\O2sAiTa7)hCI'nQqCP=DqD;9nEmGKJ<F7^=NPF %l26<@<%lI9Z!M9Pn"nqb&`u<"IVq-bQQ.2JW:"/9DD,/";(c4\:=ghnWT/*s"*qT&V!H@kP@*c[YmA'M[SW]oj4@NnGfK7OO[*Gu %%mbcfLB3Rk>hGP*MkJmPO9"j&f;El(R#=8?[M?itZ)k(Z/F^q0oW2V,Z`-B7c\HYdMj`aqP%Zr.I4p=253ig@.(9Is$p`)J[o&)4 %R<37c=Vc"Y#8HIN!PU%8<cQd4G.isc>JgGFjr.1Y1O4B>bXsOdF.o*EWPl#UHRAA[ZfQ_GL17`3S354Z:VhTRXPQ6]SjrXG1R,/D %U4H#Kf^meUKjOlP<m";>V;,mr0a,5hhsh1RZ1H+HAs3f]]u_nc>V$\>>5,/:U73T\=YH_niLUb&*$E\9Q(6ekZJglr`8:6#1upnA %(0OP1L4Vd@)b+lp/i#=jOb177W[MBu_5:7-H%C$"ajs?^lNW2JL]H.W]ZAi7S8?BN2glkNHBQI*;SC9%X_h+d#Ce)T;R9JAhkAN$ %HbD6O$dW?tPap'Vq^oM;fSetD";b]R,IS2U%:$Slh:cC<(J2)I2:#^q,%Q:H]k3OMXK(bJCV:];l?`n`gNffr4o#1HMe-Whk8!=a %05J,4)l#\hR"g#Jh<NRob!i/F5Kao(Mt1pMo)4rVDhG]0g_OX-WX/0(cNqo89:C]P-ZXlPWJ8,['Ak9C_hh4d38DTY0aKXHPZ83$ %VY\(@ls%#s\Nmmp`p'Q"XEPN#d(C9*.WU/P`$W!bT:*!T@tX/[Ad%Qj'i&/:@7J&bTS`9/EQf"7^3^aL$.h,Ai+tsC$^L\eAd.ha %kt)gu6ZG+,^BR!-9!U@#P:X<-AIVppL?gkh6M!Z"JYtT1ag'T48"ZPRCiK/lWuC`aiT_#BX0KAu!Wd8q"2-Mr.M8*m<l_$s:k^## %RW!,l!,g@D-s;OdH'T_tfGpaN^^^cH[[##So\/s#$tBb`I.B!/(b&coiT,t1I$1j_*0<J,amW?TlFtmprT5s9<6^W[Y#B<*`<ic. %O[dTN-GANUZ_>.TXjPOjV^SUdL\P?+>*NY-doEU9LX"&?5#N"D!I_`&G+I6cPQQj]]<*)N>e'BQDD!j':\'N3^<s)_4?QdB^("F$ %dRg`Zq#k0*<nANm*JQ2sk$-oF/0DX.hQPE$T?F*Hrd)2ob--/Bcu+/^;dAU)VgZld('ts>_0+&6\LnJV"fSpN2k$0+gMfI4P,i3W %]f+Z1@b)='%<0lIYDZ5GjaQR_f0pl8ZIM7[Or_D1Zc!5m\?[D8/X!A3PZ4KKoLb%S"qCH)N(+m+EUk5"nGr!a*_q,oh"`%-8(mj` %CPF(HS1'&1:7S;%X>\b80-S2)Kb]YVdI,2aaF8#+2;TC+n2*U7,8bfU:n,o;#OF]>FUi3\>2P1#LO%9/F>su#orNt^p7ZF.BhdtD %HJ]%gE$a%]>\2dnn%nO;M:/2d(6Uk]pKuiDaXdV/q/OK2S9X'6-dG_MnbF8`i_>VSQlr#=ZB1A4El]Pt2>EH]Ok]PA1upXh`9.\D %^L"j2RXD:ZRObdm%U!!K24H'l\)lEan0selK3Pq2K]O^ATofnlbIR1P%^Y"e&7!HhN.jWcS.&=6Z*kNkjTKL21@f5in,(QBs!&n& %]]p:T\M&.ICgO'h#XTYoaN#2+YDi=d3ViU<^uo<?ZY;#?2<)'3Zr2Si9AOT)-$G[8MQ'LKAUNBkhdbZH*fJ$!*,Eg2%ci9&$j2e6 %!#A<@%JDr56q\ha2n,+*[ErC1.LP0K$Wkb7_A5dXYUCMiU@^%%*>ZBVd6nY^Vr%+!J=&T<0Cl6BfN`E4A_Zs:S8[o[SO`r:V/)b. %Ufp2Q8I/SU86[XeYcMqKM/<W+?`]1BR)uP@8=%b+@4Z5$o=FbB&;B"*.NI$cBT,mC0F2H^>pC:^>,fA@fP2pamqIDG5AMR=`ldAV %OhA`QQfSBZ5maSnd_PWp/rPJPMf+U72BVp)5P+)`)2qb=GA[+,*j&p+ra"7a*M1X90j<-`gGZnicaP[+"eO;LC5(Vo!a1FY087;4 %V^MX)T\o?ReL*\YQ#U(KDMuOLQbqB)X)4XB:MTA9/Sgbk)h*j'2:/-Pf(!N?/'J<ZfK.$r02C6HRN-.9d2"WXYs[E5l.akKd5hJA %)J^;+_rE\#KGK8!oQ(t"J#o85hValc-?41s)Ap)b6t;Zs;FJ2U%(;4Gc_"R$V8JLt.FYc2_4u,]`\^j<C"hROcWZ*<WF_BuNFe0+ %Fcjg&EgN<Qk1II3dN?-IM5V5HGb$eeR2(D#X]i_gD>5\(XWoM_[SkjN*M1d=0j<-`gGZnicaTVV\Gm_Sj&oeO[r<Q=GSp(SntNVH %g1StI:@L/QqDL6V[#VtI/8?-'_im!'KGH)u]/KR.&&1+pH0UmhCg]@@60Gu6YmRKQHo%?[F\"+E\i/=ZO4Fo1N^[e0Fa0AFXL,'? %[Vbe&*du_>Kq`<H)]7%[g`fL\d.u]KiNms`-!\/gbOfXfn7Whnl$_BqNMXP!D"%]^9?"AWA)?8)nI-$g>Oj8Q'p_8M&6M3iIo0A- %(N.@h<M".n&$aoebdItq`M7Pa`\LWMa;pl-i%\E:9^(19HT^j?_'"WfQZYPt+HH`iWq0HRMqT_G3o1'c`RVUNLSiS(SIIKX`k\7( %7(&R>Fk@+1eRY]2;PA"Vm'56e'=g9e^9*r4JX'>4r(0Q5S[>b73,)kSjna/U(7S;;TJL&Z*S4eB*K-=4f<Jq)a7$9QVe:E:+.nlU %)kqo/,*ABdc8I%V3$BsPM#%0/K.n`q1_Q6tqmNpmX_*8Z4DSeLg#62E30gpU0(%BXqcRc)]p0]s3kBn4?q#MB8l1-7WcS!M%K]u9 %L\]SefsWVRnRrqoWICsdU^g1qUFRosB'J#Op39cs`NPkR)qDprVM-7,qLW)'jf1r#O0.PJ96;c\%@1%7afDM;40EEO>:`Fd;X'8U %Tl2+@Y^EK`%teLAmVW-DQF,\39fXIWF0;Q&ioHjQ6?7jTQ>h6[DM*YD1n_Y=[^D*?Me-e1-ll>tf0YP;h?-s=TTe_rV[\ST!>'OS %2YKfaJ"Ecq[YAQUfr:u_ii\QV_.C#2=>e3&XR4s*cPDjpI\d_c4_pJ"Q*eG?Dt"KCG%pWu$8nA09cDql9^bZdn5kFE8m<+cEr3;R %33?eHMG@=/>';ll/P`.EQCE)8p&/,U@!]'aWGR/*>i8P'nnK0OQiS>@ZAGU'=YPrmPhJ('_.WEjO@'FN9<lMR2u&Ue.i!7;`B?D1 %1PIH(HtQoP'O-,TYBLbOab%Ca.teYQKQp]>Ro9-<2Ya@["U_qY9;T[12Y]0BUCH29OPf)^3UTipGhXk$[i/>@d#4rQ=G:.N!"(ga %DZH2ORQ&TZl5Np8poId*$GC4J994"*n5ZKiPhS(VpA"D(,/*QAm<8qJC3/"m]VqQ@3h<lHf:.P1,Kgjd<iRjN1O&e'0s09V?#Nqf %V%L2W,gm^o@bIi<]'h[&-hPZ(pE/j1Tb-C?ErcHWdQ,.t[4Todj1!+2RK5E%@;X'ZfR/TO8ZIJ2hb;ZIdqG"k)eG!m2DDl0#_s>J %A)Tj&Qg3,NW*h7.o<C'?2O_spWFIWr?ECS43]pum;e]*26S#XnpSSM'S[2Qfj%)!lE<))8#Au2l8GV@O;IVNNO_CVc:G%k.G1%.q %<>/b>#GAL=HYft+Ai)BA\p!WcRp;8WZ+JN(Q<PI:L2fso,%DNOk+hiZU'WL!jsmg9G3s+M=Z$:rG*THKH>I#J9k^h1%Fr$A54,Vs %,dnAoe'opG%8a$([[(BE..^)Gl-LSW9;Po]BoC=&<M6KGa\9<<(S>O;hn"_BWG5*!%HT`:o9Eh?J\)Dj-h)QO\%E)mo!RB@YYD:o %>>)N@*Oj""eQ2+Z+)^JS@q3E[h-Nen^NS@(oaU^[54Opdo-.9%]7l*t4;IHX`Nl(mH*+.?4k44:/[KAl`FZF[<pf&'N`t!K=(?Y[ %HF-AB\@0iYX"MJ*PW&",Cd8U,?foHKca[pVRft>b=neAQ>YFEeBX)4c"Vj&B[C/r@=A"37l&ZO!hnm%D_J\mQi+B0+"_o/?bgs;l %"GPM7BXWi9CdbG&G3s+NBse;4YZu#mp"7[sS'kiDQG/p(DpA9KZo@5=bZtHYFGEOreiDu<9[kb?"mCD:Wf\ad,jX0(*B($#JQ_`h %;@V8qZ%WBdV.hO3[F=lP$%V4rDZ_*sA-!7p6_7m!4O!Nt)?>nJkfElK>ml+67B7hM%=i+2b8*_i!)YeY7+XcX@GuX"XKeBEK%[rl %?GJ/%*'_lm,equ;^9;\[a/+2tbA>p(><H(Z?lF'eD7C'O'=b-N=IIsPOnX*&IPl6TH``K<7+8sH#Y3CN\N&Ar1/Zn3=$OH_3rE0@ %=seH1j=MFUZblK[7^W]_iUIjL6H`Q0De"PmpZofY&;d[jq?i/MAbaR0,]A(MHF?pp9L$:T9);j(/`Z^tr"]rIW\>2bG?e>Y*N%1m %;JKs7>pDF)ZF4LCHu:j)>+f!084dA7V<Z-)Al!=<OZ7u[c2)]k*P6Kl/N0XV5huZKgKAi=D6Ue'e<K7PRJ5?Yj36ZU]\8DuN1EsM %Q%=T$>ZcW(`^*[+MO*d\,CYPB.odG@HaT,ag1$LPZa!E7QK]:oHVAUR2CEb@*T#XZ=1:MYL03LI\MssIS.G2%fOAD/nk,I2KPTg1 %jncE_%]@jYd',(AVQ"-^EbSBOdV?>'DlW9f.c<a%Y_8QMD`2Y=j?qe1?!rK[(ikpC%rE1L6r%Y2>>+(lS\2pReI3j_`3gWCA+M91 %UT#]m[8ZeO^/^-_G3^ikqb%Ybfq)%"Z[;c&/Y$??R]W/,a87dVp.]C$>0RDV>=.&p]YcaJE=-Ef=PbpcpTeOQ$S!a=8\&SdI&l53 %fRAU$l*Kc6Ua@$q[XF@I<7fFN@FJs+aLBR"mGo<m'4k<\Z;O?Q:>\"rFOK55V"<6#)_>3n9bB8"JJ]khCR"Mhb5%8j*RupUCEmcf %BH;^sWf=GaVCeCf8<qTNPhEKBp3=OSfBr"Q35I+=Hrhu1%<r=&bdQ-Z"tj<[c@.A*\i/=ZO4FnFZp[H%,Be<@)^&!]ehYu<r#Up1 %$Z\LPD@SJ)0Fggm["5`3>qr*lM:lOJq&suWR;Em\Mb!(M9N$_KNOcq_2gC8s/*"6"r#QBlD;5@E)]7%ki\j&i_EL5AfBBXDaqVEF %_EMqk^mN-q7d9D!+c/gLQ&/ccnX]_,a*/:_HI-1`X?b$,R+/4:g[L#[/>WD-8?-sG#"-V3D5I&uRQ:N!/aM+[l4GoNhCCT\WD,1\ %DH6L4?Sf-GnQ)%!*]oZ-`tu:ToEstcY1*o[AX9KYAW'(E(sG`a8K4hMj#6KsBN`MpgMhL%R]X7XL$r1^G-='$%-3`aApma6abkLY %e^++iTe4a&Yqrp0(t2O?QodG%#*7-*Y_ITufp_VZFIk,U*f>e]b^J*ZGkW@MH/Ss7E&dB`93)%bFjeC&>AKY0Og)g#Pq%`RS?K'= %*N",$<2n8#Z#:oU0kopR6n8AJeJE/7Y6s@(GKqsIJt+BM."ig.<e(3EK>)E#/[]G-mVlmB$M6N[j4[2lOei7b--8b2I62l'G$>:N %HD>p>!QohsQ!gqo#5?lO<4;k];S.*1fJZq?Q?g0Pdr/L0DW=&sZ;M.^gT?,ERqs"^2(,SN\cE/C:/u`s"LoCQdfCEB5SoKi<7amt %@^BeRe<:Nr:?\s"/.nYVQAU)PEK<gTX]C=#m7u=Ae/^0t96[i9maV#OD%`@eBM7aHfjM.$!q`q=AaT76S)7ZgRVF;/\)[58bR^#@ %iS8Od!=H*Alp)!h9fJGmpBE<IekD',WbZ8$@^BeNZn#Et4/L!KVK,_+C8na^BAR.q<b4p86#W^9l_/]Y)'GXgq!KgU$a)c$K=k)* %;.6Ner2qX/iO#$gb,<XV[`T(mBlR2-RW<g\I6[%(MLDbj27]E38R?uP=4kLPK:kPdIccV"$dr,ph`'Q(R']bF8R=`#-$Pa-Um[L: %>,H'\lnS$DCYZA*5/4qX:"S%$3F/u2LKhf8eeiF+B%of/imBdk'AqU!QodF4Mf5t)RG>34pNUpVor]>QEL%,A@>g_JdJ*Z/IH_2Y %A(9s_Sp&[hd$le=)]LnCa'`re`nGAP*k/s1ZriaO[?:3.Gj@b]r_aEJBOJKKE1X,CK8:mR:o?'+&I_th8EafVd'XIoGdNLIpigR" %GBb#2XO=D?fsVLeGdsA'#qsg\U';k^4LWSGn1hgW1]HZ*`0u!Y9C,hqZ"OjUA_l:DD<*:7ggEu?Ur;&t0^l6=Mn_875C@JLGOFe[ %n%SVJbE!`PIs<?5DdNJ3br^XWr:lK5]R0DDme&M/KcK9J*X8hnaUB&-oH,shr;igjB0@(0c[Y)<s+C=KG67d.k`<J@rp.<na);go %cbG2s*qa)cB]Dao)OnJss,lt5Onn["!fHgKN*H'Ir1rl%/[K\%jl?tr`C5e4_L+Zf#M!ItFpSY>pd6a\\3\uXZ+oMW05J*O%sGng %R<VO/0;c"$WU(kEdEQ*,MdQ:9=7F'co(ElH30P=&<m](Z8$,eYj'mlRT5]JlW`W8+.Yk,[Dh%"`)^A@Ed:@A=P&9"Sdr/'b&pO(\ %Lc^NepBUeSIcd[:Q@d]uP+Oe5kjdZ\8]3s@VOJ.T.Pr#hh!\;Dd\3"J>9SN/DM4[3<2,N(fapl,:I?sF7b7'3?e&RbmA"Vf58gZ+ %Wj4CuQHt:b5t7'gD+NLh_+NM=P9K?FIQjV8VS(j<DnMs%?Wt(TDjk>;Sc%S<[7om.45I,u!2?6]d5J/oA't*-CPN]Q1ts+r\@'eQ %BYlC&B?]CM-6JJW>#!\Am17m7&8_'s(F*OsWsU>YS$B.rh)te=cJd]0'>J)5OGUg*5GGir=Ka+J6_3:YYht0Ra4BN_4(YXV3o4W* %N-bH$1ueqML1WZX7)SD/3:,FT`V*/r@@rca<`M.Om5Ac=V"SBTZFM-(1\`J?G>Et'ZhX>f'0f8>"M)g%!j$n9d-#*r"Ah:A&Ccb5 %F:&t]e'\lbC-2QcZIGnTmc:Z^_e6$]C>jonL=Er]><XtkDhMLEmdA1.G8<D-aTR].YBHRC9\6ItmBjdf%eS5i%V1E5lkW.!fIcr$ %CBl=[XXU;c+/d]>Z:SY.FUmEmO`"fH.EH2.\dccp*N54X4W38)io_\'!h&^r#O9\5h#+S/%XU96KqNm:>J!<q-2DG7DH5V0C0B(e %R5Uq.nZ$?\Wg4Sf)c?hW9s'!h$,K6hh30#M/:N&29d$cKm6LMDbeO"p:,hP,5i%?t+4JeuJNU7RUOP+DTL-SuWqC04XVP!/Qtef2 %[CGjif&BS(-"bk7>g;\og4;l6h%QIH*"IFt*N3Jn(S$tl?iSh/K=r;(UL$0^Xkf_IOuPBg[i00B[B/Yn3u_,!.b;,g1:>l@foXpS %EQdL!jPCA_7fR06G8<D-8I4lt6BLM\a+^2Z0-0mOm=i=a(#+Jf>GBA[;,YMRBo$ZE+02AP<S'K.@qsOB9A].U8QdR9%B4cD[sW'a %md7eZ#bD6?BCYRlj+7'\:AS`]<F>dYl%ZkdQo@JWX/s<SRCsIiqH%G8.`dk7]Wne`CM%k&*4f1849Mr?J$i=CJuT]bpI\M-HNR*D %\9ejAS]/WF%0Gh9dpJ<<qte?.+m_q<]WqBn@^B$u:1QPi'Xn+)e[Vob23QD?<m%7B;0[mt<sD`j!ii\m<*dW5XhJE.Isf,Yio@ZB %[Cn#m]>cC!OP(XSKDA58Z@902pq2GTju+LL[up<"+FOnnhaC9m!Z.*I:&OY<_s%X?U*OM-CBu5&(>ap)DL,GML@)inn_gD6VChQM %;KKXRg;g%t($`pS2gnt'?9<MfLo.$9C^h,4blVBWmBb5?5DJP,U]!bWgY'#pF\T6Cp2Ofu`#;CmS'J/^2k<*'>J]VW[BnC0/fTSW %qHrqVDKMmI<U.$:@QLoRWmoRHBpX>gR8'/iE7tGHW^U"58n\8lSJXT$.)WZ$4'Q"*Z>gk"phAE'[XKc325:&chSc]u`ti2:S'Ka. %fW%*8;VgD;W9\9.C!\=L"dqiZG-g'c^\+AV.NESVF6i`"FY[$P;sS9%2B,`R>WntlVfC54R=d36f3VK^h/*j$`>LVJX<68!iE5#H %C:i0-Ypp`oC*0?SiDb:RDYgr-I'-SKV<r*,8_lkp[$n8aD#NS+$:juWQF=-%L0bUT<F$>PUN!56c(!"],[[3`FF(D'a.e%3epOZn %rC5b5q-N*2P:<$AHuIbA'i#2=UeTVfD*3hnFk/m=a)RunBf]HMO0hbDX_)B1><f!e_U8@9fQO^Rd&Y$_^2@XHCS.K+_HBn.Y-Y$0 %6>DOgMJ9NCjc+t++7hrR<I_gLH<!UtJ`^%Q<n1*Mf=DQr/SUK'QJ>Z,B3ISq%r:r+5ZR+ub1QF75#o5HD0h"mrD"XfaAi&L;+\=K %8ETH\9g;^"0<ftqN`Hs#5ZQhM;Yuh?lH#p+FhOcLVPC7r]W*3W>&Dh[)ju8L2]Z2G[>nR^KB*4s8FECrE4,JX5P`5L^DN8dVg,]s %/#dCSY("q;,rW-LZ@PT\0=uBYK1WbCm5mRG0Iu`V?\.[b5qX>Am&_iV#K?4FlOL"5fS*d_,<agcl/C?TIGHj2_sMLU-`u\JZ@VO0 %6kX%VYI`;/?;E>C=cQ(b$d"2%Ou#Z"?5)__b/><.jf/s,"'Ac7mP(&5^SuLf!]1ae^#"3a!:Rof%K)63]Zrt/Dm[!MJE,LC`i:t& %#cW$B1Vu8NQ<);&NuKDsRYTdP16b43Dnq/LdJJCc6lEJB-1?!s1+Ck)H3dHmYaLH6!'\Y6hidE#!>j=7,u.SYlln*\C.*g6q\;&[ %i0WckZiT,rA(X>fW1SDTp\h$hYc67%ALuT9KY%JY'=K%bQNX/^e9&Wt*.[I>6sDF[a;nRh39)kp?#g'j^o%WO#Q<GA^ILJ\0I;-5 %E^TI7i>QEGFjbA`,-^WFDJJoN=PSkQ<HqXUXP`'VYAp,O*lK"7>(rb.WR1u0h3oe2P;8A'^$n#o/#?Kd$/-'*ldJ*"DMbBP\sbEE %('A?`-5ZlcQE82/`E3Z)H/!MYe5"a'dlT/#f$4IHUi!]XB@;<q>-[>G5d(X(T+TgWm/+?aBsID4/_-`(<uB1;'E6@WO]MBRO).9Z %'hR05&O/eX=P\_uJZ9V;1fZ2'7@T-NqZ^j#Yc9:gI:%>DeJK)I%A]Z*[acA6R]>Ps85g0krnT`n*3mEH2I%1MUAG[?gDd3(l![)P %nPNn@CDBS:dp>c)V\Ro()ob1.f.$0.k+fYUXYD5,[-UCO2=*$d@A?js5$I's@c#S>Vg"s&XEbQV0DBRZ4%&>fh"7XNVG5*)3OCq* %*RaZ!6tHH6;;!X7calD4XCBZ7Oes+4e4OXX\*rY*.q^T+qF@@71M=.d+;95AYiY;E-4OOEHDL1&$H%,<eue(#K;1I6%0LD%L<kTa %,AKio#%f\NF[oof.^W6U&(R#`>!,i0"M<:.G\h,``\?E@mU=IuOgT)En=`m/5Spo#Z+?D7G4]W/RX)N)7VNlN"+cjI@U8E2TTdku %g[=mgX=>=[:"X,Elh$P(0'n_h#om[$%\^/PjK`?%Kf(t1E,IpGhqF)L-i':4WES/;1uUu8R\ji3Bgf@f*>*V4]X0OXif&pf7*EUX %CR@$>m>..D]q1Fc3MV#Smi(TCp0a]8L>#BM?!GppDj`GVIalQgd!Rq5gtb,14r!)3.#jA_<*23pUCl6oc]`rMVP75p*icLNo_2k$ %0]ID>G?p@ZUH91V0d(dX>,p7XR?#&5=Xk&lR#+bA!gCKNcc*ck:PYLeFE\S4KD58%&'':q!MfOe8hIWf+89!-2.VbAOnk[!-eTT* %LUAd_+MEr(!-=2kGA3iJM`@khJ(T$9mGrT3m2L;*&,;6I7"bbqUOgbbgWe(LfDlJ8qPr=?$rD`:QFn-H`>G=cqYS1U$bU9I6UT!E %7Pfk%4:m!f`2+H!SpUK:]5M;oQQ<O)qK'f,q>8(dI(hZNXmCTj5&rgSpJ;of=q"jZ,K!i#J;4ScNcQTQ4gVjtipN6@fM'[-]3*$A %!d[5HSH4fI$6u2&+lD=bBZ;Ic0ldtW],ffZ#T4i$RgG:4!#GGmDIm2mPSjW]"qcEKF8h77s-OlaoQLLgOg76r"MVlLPX1Gheof`p %o_(dUje6:&3sF>/_SAJVfMM`toDu;k&U/HW'TXe7)g`?.BR/.m=_1u&oVNM+WFa6qpUmt!gPq?9*5@VgplH`rQo-t2H:QP+-i4Dn %"/i,KhDMr-N*WfG>e.nVae@8\J9AHnfa"Z1fPp*SDB/$3`h+;b]Q^8Arf*u+E!s5WjH'+UaY%Mhl<OeHL3;W@%+Y2]%bg8D>\F%h %)EJFV9u`To"7:n*8Pe;,\`_'_;j\e$T![TGC1IaYRU6P.CCJhl-R%Zoc[.DUf&FWkDsr=d8Gi*]6;D$KeLu8iW/j$i,?WVt;msX> %!Uou;pMRco2rK/BhT=Q6"7F21pVVOY@DMiU]lU_+pY:f3mY:i;_k-aFbl'BVIN!/i%_*Sch!`uZRJUR2rA*;[*cO=S\DOc>0)*P\ %qdmSA4Q(\FF2*[EO#QUr(!e_b4<rB4dQN#:'pZYR5fL^U4r]$h5fJFM<EpB>\2[;t,?Pe]\32"uWAli`EIOS,7PHbtEpau#(C"%q %%Q)lF('[t1liDop!Jl@/#_N-`K)t2j]2ZtaJXZ04Pr=6)JY)04+:SMt%0dpb"s=B[TPs:872H/c/e4-"#SmW%ma;+aK)mBQ!Q]lo %aFaNWgY:u(0[b)`T[uZ;0[b)lf1e?gJZ][W2Mu>Oaobq90@b2jT^,dOeQ*U(nj(go#rtf5`IY0b"2-UE`IY1MpZT1Ncuj1Ih15NC %0E?NJBC!,kcugqg0Go<o(kB?696FM[kdiUtCElq$kdl3CdU3('?i]1o!9.AdqY&4cFa9YG>,6Et!-p6uI=%=G\iA&ZBqX'IYW1!P %r;]gAPXi<&UMiU_BV^=X((F8D-sW`md\Ke(V2^"+qo_9`L+*Td`=\t$_A!3AqA'N=).4p=9R2:?%l!Z.Y(BT9qI\Ia/%/$t*!"@! %,S"t@\maZE_l0k@,j"GJG/a.?!GGm!2BW-H7WFWq%aF/#8R2UK6:YAJ-tZ<;C#F,O8bG:RWHh;)aMf)YfPs]%*g<%A&5q\::MYYI %k)YfkZ$gt!#5[90A`WQIUK1X;?8`%]a5Tpt_"o-@@,4(W+*.HQ;6s-TVNoh1UUH4VZpOYW^GLg'NT(q[fR=aH<Qs5hDBEpQ7WFi% %M`]&Z1lD0\5V'Bj0;\iuA)W,BEmkOC\T&b&Nu@Sb@*$D*D^G/,W9kVM<cT:gIRfNQOlP.fm\`odjXcE;pG$/tjCn!cge$q3;;Ad- %XlLu"X[+Xk4m"A7bQQZWq)%&IaUKJ8X&UhT53?0gN.k%P\9Autq;'C57g+nN_3$gb0c<07i$r[t`TtCu;HH=5O$'@HRsW'3?D8N9 %O("b/4j%#sI:/n2J<t[\h#*[j>ihR@6%d#b:q-N9[n#Gu8CAPN)Bak=,]SkjNKL:PhnTQRn7KVB!Q1d]nCW3+?r[&Q#R2D1(mb%C %fPWAsIP;$PQlD".I=YQ\(`P[VLCq`>#3XifU`0c(*t6*ok!nC;6Y/R/_#U>1BFI.G0L5Adh;VgmdU4auYW*Jmqk?`'0L0>+(aE-& %%+)[RPW0SS1`2/`/<0pJLWUrE'6'mrXc4pb6lj(scpHXH::E**r!8?&+`[ZYI>^/jf3h2q9Q>_7%P[Q-m^6<C]P5I#+o=b,le=7, %QfbiS6(UaG.:1soq80=USV"S(aQFtdb@Pl8oPNGB0Q#EBnJ9^\Ap(j.Zj57W&:u4PlfjaP(U195bX;_!^XHU?H+e\-kIi]G\l^@> %f^Zc><1qd&iC[Ig<*NV1OMp5L7RDBA#U=j,oO[uKHXPTI;oY8VJaVd3I5[,@2J?hC7!Rf/+E#*,e)KW8FJNgOEbf.>%FN=l27^#) %%belc%>T9sg0r;n'&W3Dn$9#8*-JbE;s?nUF.r-+i\:0Y5EUqNgCg]Dda^+T?(!SV[bpIC*:WRSe)`,36pP&_Ed$/>)6:Np=`%"? %04^f\2BV%b:eU/`JCQRJZ-P!hqD*:sF,1?bEaP]AEmp"(H"csWP%Zt"k%CK9Jp1S:*<UrI0RJ:<C3AXULbF1E8s]mQIGRNSY)p89 %;g_^.q_C=>UB*?,T2og%q]LD['Qo]\>#T'FL:>]7OfT#7@%5pgfT^VRDI:D4&*qq;mE5K8S0&CC^.:cY[OZ!r;:/Z!Po[8V/'*H* %bu[h]2"6SS>o=kZV+j0l,dJp5$@P?qrfH48ANE-_N'DrUrORLH6IUkE>luki\[0bb6GO.6ZJY;[02r6V:/tf"j^qku@XMS1qD(-I %#8?5.L71`nOXs.:W58;kUm'\</Zc^NY@`^C2-".Y>I2:V'd$JFH!jD>"k4NsqR4>N3;PBnSUFjkX(>:+kKM&>P1F6M3FMQ:@+][H %qgC=DBV(N8CnC<2`#t3=;q#aphbc8hi<<gc0/CcY)-9TL4]&m./VD`<M'6=F<+iT1D@9F,6tl906s%/TOG>*j0=)n.lc+X5b"h_* %O"L7P"8B4X0rQcHAhu^U_k&71n#N"PJi30dqD)f4gaCt5msFn#9Y\@ufo'9uak!;]k_*h?ZE8[m;J7a'if2o$QE"_)MYf/o/<R<Q %e^,+/X5a4`mu-gKp0G5Q2VAD2AH"F=5oIn1E;]QQU+Np8AR`Pn<en%Hi5au,1CmI%#1c+B_U.'cjkK5cg'5d8^_jUurTJs72+=MS %V,i?9EAL#6hJEX"><mHiZ46XcX^*h'T'c86!XCO@!pbJfEu=4Jl*L5'\>Zj8<e4BrL;VN$I;Z/$K2mg1E&Y3JG%DA[[:-+PMl/5W %e(XQZ9Qh>s<i954d^6nhgJhHr-B$h"Z)00aD=EFhN/b?]N#48"_R+$,qq[:L!TPgeD[%t2pH'pLRnHj:6eFh9>+)I/R\e0XMd]F6 %eC(r\:e_B6[?9_$QSJ*n+gLLZm)\P)EhS>r(WV_K#<g&.NFQI82N4=HEMbC!D4%+.h3Pd6id45]q_C=:UCk#OhDn#+VKLpH]k+,K %qO1[?2Kcg)@']0TZ[-O]m`SSq6NqC=NU4fd7J";'k_o)/p>*:'kS\&+ZPd%3&T+8QZ[1?!YQf6Sc)NK$6`tNB@_Jh&AStnGF<t*` %qEF04bB.h93.HJ_FQnD+b?&H]e\J&N3*"e(("Dr_04^%ZVabi%?`&gMhD\tnR2rPb$.FVIg<'("LLqXnXDO,7ZSH#J>dm33_oS)+ %b>bJ[Ge\:mARt29(8ah'g[@3".d\%T+t`+5M<Ia)"[n0PV8:k,/U2]38l&sXm-Mj.9OjOH2`Q5R/Z!59/lQkYE_i`3Xc='P9RBpc %,DFp>0k-TU=/UGW&oG_T^&dNBCoFH-?`;W^Hoik*4Df2/ct(;!:))/jD6Ne&Q(W;YZdUaZR<Ds.^*2dbFJRK*2#OD@"KchP9@=?\ %fmRJ*WE$3?B`IGDm.1=bh]D4=1q[52rY,"rCeX*t5,#TdmCmH2qcNJ%SbI!-T<Jk*T^7(&#54J$TrgYKNHLW?Z^jH(N:#:;f]S#n %^HE!Lr@Z`q^N;R*_3$d6.h>L$h_t:?'*!UN/"[af4(kQ&`pW3lj`;ZAh]BcVS<rT7J&8YSK7\.K?QS"Z+)b^T,1Sp1VWJ'0JJ2#- %BLhTU^!03eDs]<gfi1"Vs7YG8T*N?t*7in<g3@U%@9<)s)?5>*CL5rWT;/Pnp0Fu=GtBEd=ijk>kAK3a[Z,@VaIU5>HO1ZFnXh<* %5L_=I-*`ID1tH&>0A3Eh57lBuFY3<nG@N;_hE#554,#?^mh:a_s$n@6#MTd$+F\<e,LXU10%h2U,bW\jFITCd$haQb+ln.$Ed%k? %*hr*e9Am(WZ6*Tfl[hsY)?*a]RS3@Z/d^i$93I2PK$Cl"KCUClnu&_S+mSK"jWB]O+)6SqOtbHM6Z^@%deQ2PFu=$>?a<[TkmkTK %SUYUVDS-ZJ,+81q/.21Mofp*=pT"gChL0eCmWUnmR=P+K;>\>k+9%(7Z@$`biVW(mDsc&L7h!?;Un8^*j#-f8c[S!'J(U8E)P8YA %ZUI)O3P2>JeM7A=ZKLrdr[ao*i)%$#qW/K]n9/*++^],V\-H9nG^$s[%e^S/,uJa>P;Pmn4LIDHKaCg2dlL86e#9c*0Q@)*^)!-Q %\A00$RD^Qi!V6(?5ju%F,f25p!a\LGZIHTgO,Ag31-nlse*;0&J6']p&Y`<e,^<KNQ:6?G@H(]#D@[;<s)S(sj0L\J5/)=BmcB3g %++I%YTA[<FS7;E\n\9JEOX/k/a.M/B>ebUXrS=[7Isd*I5<]!Y.enMBs%LCP[:Bb2TPn]tb+&WlVHLaR8VIoFgq5V#269rX=o5YK %(#oAhfk]9K)fnX&-k390^.i=D:BS<]l=a-3(hRQjU]1S[NP!?\,fK6M;$=I.m$Ap'd3P<A''r3t$Cp+O>i8i'Dmb.]j<aZ$AHQqm %J?uYp-/]"KpIO"/V/KuG8&/iE1%m>5j`(X68bK`VVTrXETAuui%]Ig6&Pdcc)i]17Zd$RqBZXM:9sR[f6]=Ie.G>mqd>7O\16t>Y %`4#"1?\>[n2D($'1"JdWke'O`m$66MUrle@foR6Ih.Bg<rhariJ+9[%A7Ml.?g+\i:5CpA=eP@c]FN?%YTW%19H!qXNu,D1kb<,Z %DR>^BgoCr>6%q8s.aP1JJ1Gr6;-:Zt$B1iS"-mF0b>8G%85;!2;QEg4a/`=annp?cSnoMTS0fWM/L5uu9<7D2!sj=pL(f(_HTF>f %Ada5iR?^m@N2kgC^>l"*!P72V(#9^3('81>ZGjm8Ls:*G$5QMrb1=(Y^.kHnb68SRn=ot`V#XV"?NR_gITEVe:9t.*r:<l(Y,MPA %J<mE9f:qV`^mOA//_"D.TWX.BUn^@`c/';AQ(]9n4CM@QAFi%3]$RA7YGNVHDFT"\@*Ui7<+LtSjSjjk#4_kjl#sS<!_bUlV\uVl %[$5p.Ad(+T$6MhLjq+n*5=[<kVE>6Jk&+3B\R&Eh5#+!IKIhr\TT4s4KtC#1.gg0%ZJLlnVqSq\qMrRFSs+?L01g_j3JB"fE_9#/ %&pDa+E\XR#7'bh.U1L)U9uRn9OP`:d=L&bN+699O!aa<Vr+-7@JDMRSk"=Dl]aMe.gOkudQ.=t%F!au^,giau/(iR+T:LO=0aa4C %aV%V$g:7AfdS_%2=Tu#[iFq%ieppuaEQEbS:mEEVM3GBmH9cRt&SFMIKbqpX(7hH,O]]/V#=iR?$$u*@apIE$<8hhGb$*B:V6W$K %"ib4rl?ubR:pggE.6B+cC'/O?Kl3bfA+hg7VaWK-m&QCTaPTTj2Q!-YV_gI=QJf0S'6KNs5WU%3fuf3'+s:$Y`K3ekJP0rOetNd$ %i)%8#e?UOX'V8?5WENuWZBu2jbTPqs?]5&Q(8]TIQ%Ds=(Xd+6bgEdo7(_0VBP!B0=($U-PS4XDkU5P9A5YuglC<`GOLTIKN8@@H %<#Z:+Q45!P"&q**0J1t(8ePAJ.+oN3j\CO\2KR(GD'00lPuk9p;0F\Q,(nF5[>oG5]SD)8RC0gs[=4CjM;eD"0NBhYfoW20e;@[J %j;@E%X.N'l[%j\n7I!5e@A8l>:SLNp:D&u+\#p,@FA#0UJ.>0a%CE9IYI&j9c.8dql-,YqXt4S3J5PJ5Xc:H%3C)L:NIhj3e?UnO %X_\PqJq0\Ng!&I0I0-<XC"cQp0N4QkB*Bn623r6!5aVEKO0s19[;ALD_nMfC@D<Xq_(,#)H'FWe?o*e%i>cqn`e]%<=gFFf+R:0J %p[/X@>0EFWN3u:q;%tl<<Zg#$k;=kD>!+i=Ck-/C$dG&!G,MS9@WOm[IW"J>,<Jh_<_4]Kl`0WQ^Hh#*)>*<I"s3<_E3lb0GSbN[ %'uDkS]]R$O4Q6s0bk;@fPm.oIXd;2/ijZ\CZb'i+cEOQG0nZ":gBs/'&_=PJbKEL?ENZ<TFm7Qc44UoR^)7`)W\#PM4$bHGB!GcX %N]dTqc%h53`L#r[J,7]jDqk3Oqqq&=m8s7,"?<^5ku-Qhk;(eo?]Ts2-p;']`KqLP<S49dEjQntK!s;?=2D(%n7K8g:@-.Jpqm:, %D/oNlT74<^h_*Sh/FTLm^9Er;gH;+Tntu-9di$(qkJ;Bi+X[,TVA.Y8Hk(e5cK]K9joOEZEC[EL(Ai^Q=Trb%Zu2C;&3gMiO)96X %-H35QSo['?SSl0CpoY4lY;afeXcmI&J+_,.c_!"R""W^RZS8#jPo;cK47O!HUM6f+-#7VMKKBO6\aWH@>\I_$mUNabI1R3$??5b+ %03^fnrNQPKfsr."TY:--pt,eb2eqtEhX-%c(ieO6Yi]"(JPSpSj7huDF"`)I@6%;m=a=qe'Si[p%?8!hVY[sR^O84fFESrZDO4f1 %nHEJDPp9O%I8F'Rh<"n;7CP"3hfbtX]lHuRXq.h+M_!s&\f9$YDaBU+2Y`(KC27J0b'SH==u[+odmp+^9F\0VH>-(lf((;CpZ(lB %;F[0!:"Ja]5J-NsfkX=oGGp>+='HNMcOdJ'mBa]6E+,T#[B7k'`HCZ.?a63do7hkG11!tPRo%^@$=E'CDH$j7M&_oKR1jqO_YAM3 %ce)_/Xgc7Yi((Fs=5eb3A]C_eV4l;B)n[#jG+B"e_2eV\e:_]7&S.G,d:h$l`05PmUSK_(Yh,P.\!l'Njtc0U$/#_mY#SiQdZDt` %1_Z.R<AV?I<G>QF<]Y9<Nqs>WJN>]_i`1n)_*-4YUT*gOqXe8[HQKp\\*/Rqjk5ciA/%(VX]NPp_X1rfAb?b4!Sq>\@0I!pd"!I= %k**[d(;e3*6B6AlB\/3I&E76nEIn(OGd<cfBhQ]CcOaWCWTI:b3<hA`)_P!_Za7IpNX`A?Th2a!ZH&<rH#&DrZk\n#$12p3rD11S %p/eBqU'GU`qt@YYNPX)K*$H,fEr,C0+=d=mcUOW"d!HU)Y!cJ;aY5G4A];)t@5nCR2Q-rT$-cYMpG%@t@KiV24kO12fsBgSr8HL& %lI@uKF/&b[GGAY^TRfPfh?nRpPp&O`@<n0Y;?Kb)+*#-1R7n-bX%seh9n",7haUTJXjc3+0^H:&1Q?!jpYo\(`iG8>E=V!\]]U'- %dF]3b]b.S7,Q%4[[O*I]<"gm.Dt:cQIk]aMS=)?aD!%kUB=MOj\4PO:08_gRBgB8`UE3rnfJel65Q!J3f%=,<NYg>S$t7l+<p?V4 %8VVCU\8a$BB&3XR5[W;(SQF*Rk`'5V35mp\a('JD:3MVZLA#Vg3*me^,tj::3eY7r_XIMAL?J"L])?RHqN"umg],eIn)*^9n"=k8 %'kBA9k`>P<6-h`O)^2"!?_u3Z@8@$7qceo+M't;T]DP0;l-Zn;pl%^2>!=)^X$UMp]t2D]&\@]e1tgi3K*h.n&0@b5ZAmSkDK1_i %$WFu_T4`MC&3e,>o[ZNF.Vcb/)(nD2d"KbC*oS0*Xk"Ain2UC_)^G3!/='3rL2M`hjC22I324TZ\jCPs2-r6$%ZMf9g:r%VHZNTF %o=DUb)L0c)VKR1Ff=CUj?9BSCQ1`/ck`M3A%>QUP7qX4ClT)1+3b-*M5FUp1UYLPR%%nB]F0l8j7=1=d`UB-BA!D]MefJ+bA$C:F %R,;%^j%AP,1b_FR\7Ic`&gnm2[=3J7^s(hTs'Q%Q*7'\s<"N2XUlQ[Sl1*LR!$3RgV\ko2q[nU,BT&\LE0@-gB#P1>khAiE#)mKT %0R?FJV\TS&fii7O&?s'`2[H*FR;d54fs;u=:X&#g[Kn\p@TCM)-ut`&HIMs)O8m0g(X,N:N^H@Dm2=!ekfttl"8EF3XY!S*q:o\V %<mILH^4SMtY&qtM`n(^cV_1pZ!j(?2Tbjha2>$e/j7okp5Rl[%'0@5CQO@H"E5Aa?ighf2DC0ei_bsbO1MjI<s2=IVR6oNR6<Mi? %]*uN_J=_/XF]`(5V:BO>Cor?1HK#1!.^01#>%q`iZ#Ml8'N6gI$X.ZKh>69FIi1_I\@g$Z4GPiPjt7&%jUZOqqe**5O7<$7rWNcC %XBSVd$hgBQCQ*o3cCss>cEO*Yg$mgdYc`Fhc=(!C_cJaKoT+DAQ]m8m!r@_'4I.u(@*YNd=Z!H@h$ru^LKk>6k"<c5gj+t-0cBLt %%i+UHqL+"+o>k[^K4+5NmB-tU=$W&;K6rtoXUBT>)#O"S48jFG]4\`km6U:-BQo-G*iOb/[lpWg8MC^JrA!iNR4#Vn34e"E#P7(i %oOq3'0l:O<'rg[QS8W#TaY7Z=$D4+qF$E_I4@1>FmLV$9#8[h].,45\II@.Pe;1WYnHjV1$l.*)Eq='cG^<'q[tL.gnRpLR3IGSF %mIGt]>SA?jliq,7;Jc.l0uEU,_6m+m9c+>g0?47/kJ.;r"6`,33\E.@md^')bdUF9k/):_J384a0:Z5diKk(m#PZ7(I9dq2dQfT? %*G7"Ce2KDO*oWk`a_fPt_>`eg'SjD>_EQ"5"(+-?N`?H/`=8!I)<3l\47E`@3(I*J"(J8?R5h<=7Z\iiN=`6*Z^/KTp(P2jFBq!J %2st2G77>C3RKs"g1cCeI6J8tcK%S\!9Q6.-R^E71M7A20("pJTf2;a*>\O+B9Q1>-fr(qP"a"mg4C8c+8*`GK<Mga!g-9BVWl4DC %4l]ZUU4s56]Ep)-BPA5>O@I&6\1ck%rUbKU]\-E[KZbO.rVT6,b>;R$3VO]ek0o,nGnZT4F'ZOtpZHg1)URG:On]mao>kQL>pZ.f %p''EfobR9#m9R']834gG&'4<4HF=oVk1t=VPe-(=$T75:g%4O9h%ZE3,Pt?K$<lr?HuoC6K%GIB9=^+?Zdj!OcTf!M[%GURD_ZOn %BNr;(i;3@8.6-3d$J4M-lZgk-d'.rmHO-35%;rsOgj(;I%_d4pEV5\`^@S/!$g8dM^gZurGK(\NKSY&EMg<TTS2BG1>4>@Ld<V[E %9tCn:L^.?pGrT2ErI+t9A/QdGB'<s%6Jq"c'FQ'lT8uee]Ytps)tsAXc3<p7`jW:"5i6Cc=Pu50d*=fb!)2KE$m\iCb<1;&@L"gB %,olA:#+.R;[:<f2@.5Bb-(C#0^oL-gF(J]9KJOTid4Bg5I;2,k\ZHr^>6CM*kcsA./ogVBoF\TUHW=d9W":K4LO'k&M>7%*Ldt"p %[-hNPL#_&_h$j",+NAL`)bccq8A_h3J9YH:%d=WImYD\r+;pa_gkjMA2@9]_bd[m=6:f))90kEY^,64WDa0#kAf](th<M9AUK]bV %\/)nQD0'\CmK1GJ7(^%s9WXpR"P4D$2U"-R^@@f!W7IDMa2)Aq03DE6$(#uDUsZYF#eGPkO3BgL?3JO?&JCH,%)`K_^dDrPUGo^b %Z6CPRf;$kdo50N@YV47'mM5n=fWflg6PpWA[AkPF>ip#Eg@446LE</Xo6==H-2J4>Z-e,730@ksdFMOk&,bqL02/Cb=>9Kf#RCs% %ra2V1'5oAHAqp:>/Ck>BZOZ!b*#oFXQ%N1Q1K9*OUS+*-DA8aHK6P`rrOu.]J4#l4b`K^eb_*/R.M'cJk);%&TqD(bn6LK4LTlbt %H]"l5/NVG+^_;%.m>+]Zqk86.'Nd.UYi/mXq%'m[cG6Qgob!8/#V&ld?ko_r#9!t(2*P\g&/T--"kSRB*mm6D&2GHn&cK[QW"VMF %/c21`JD)d9jXPDoGc]Ck;<)\dp[.VGdY+(>dtMab37B7oS+4*n$:i;BFKpoc(3d(*5$+("=^9"DQd,1<\sE`pSm5WR,^JbX0DZ=, %o_?-$S?.Wg9,Qf?EfZPBq.tRT^HJ!-RMIQ4"#3iONI.+^%BTQLPArb?)eZKbj]ZSPHi!h6pZn3W'Y"A4IW2cA==[>E,CVj+!PfDd %`LrNLp3?YfW^+tcdM"Qf(6&7IX%#SNa3Pne5h.2!,(c]o'c)]V_;XnS$0U($X*,RXY55R^)9_C/1Z6r.1trLN5uWlaKon+Z:+q<G %&f?3pfPo#&(WOg`II.i;foi>J,Dc@+1#.ngJ""(I_5D:@QnotQM4sMJUPZMO?<ZIV\pQrDP,<UXjW[Fl(qT,[nuZo2J(3=KfWWJ? %n<!:3M)QWk!-Y%+7]_.j`f3g)"-CK3_P>VGk[h-5!IqAAr4oWK<VqF9Q??%L*AiFkGaU^P"4<97P\D=49)"iGIMm0u\g;.UU-N8c %f4U6CD<':`G&B)<5%E[T1Mi'1PV#)0r:t=;V&![+$&>Z?=psI\VmFS^@#b50WZ2oc4uSp7mSA]JfX-ftH9,jd+0B(UM7()C]F^i, %6VdnR%cc>u@pWop?KVCH]K^G5GEJh6]2U\$f$u,'+,`WROSu>JeZDX2eC@$d&s@(d\3.sq=ibQ`WOm3"C1+Uq:ur`d;dp'5H+mkJ %g"Hd>jpjcHYQOQdqYdmOLE"U)'CB,`H(Pe3!r&gp[R04L'%Vj\S$;BQkf47,f=?5c!'e]Z#/9cGcAI,AceaPIlPgnP@42"$`-isT %Z5Teo'BV0NV8U's$rYdQGE&C5HB_I\VL!n?iWj)^btV7b_"H92j7B_$Tt*1(Y&Zs3Co^#o`I3L5mJ/p?_`\#_KA$X@\gKUjk`3*h %W**S0@2E;g2G87.:k*itdZp55X8LgN&"_)?8bHct+9)U>j#-67H@?^j89Ts:6+:Kh?KtAu]F&gf0dBb,JBS%@FJf')d2IR<$j!G# %lY8Ku^f<DQ*j_Sf*fsa8R0u_1o98*O!Ho#K5iHTfJg,h7q^am6%@r&3Wk<=U-?rm$.+5V,G=S_%Q9A==7(Y%mAOZ"#`NPpk,\kq6 %kHeqEr*Ukk1g!34p-tDu"6e.A*q1/K@6`Z`JFRor"fon4+kUEbHo'QY<%b2P?8I^#%rKHS8K."g2mmc.keMBAhPjrCd1\6B8EUSV %3B-J[h$CBG)b:Va5Z#3%,C[:U&)[\g7#)$\f\OL#0X&sQX_8,,b@S%:"is[t:K<[?<s+@gQ8`&`Qbq:VP^cn+n-'Zu1bgK1iH=M0 %E444\(9XhLKcn8(m6,-!^d0%pA7j'mJs_[=HV"GT##IplRDC';4"63-`r`,"WTl=`!MP='<TUC-f4![9!1I"(]#s[=S@149s7WYD %20c%d+)T3m&>u]7$\U2+m>ZDC@HH^^YD_A9?,&AumSCs^CUoRFmg$G@`fsW$`0[sc:Ef)?U?h/i+]:Uq&KW_?ZO%eL*kH;,`0gqn %GjPO]i%gS8G^FEPEEsG62gLUF)>ehf:SS4AF.IC8[9^MNE8f,jjfXq:Kk\D`n,[M>Q]4Kc6FA72=Ha_2^UNSS^:pMXg?&S\9_4c@ %OI8(j3FpQ=2"AGE:80L\oRLg6iF#p:/aK%t?O-PL#\a:J5_A2I`KfoppoAImMpu=E-4(8'XKaGb&`*MX<!=a,nBN0[<q<X#B1`HT %aFV%aPi2*f1%q^W)$*Zf;GfR,gj'VnYU@*Uc$%!1C-n_BB%IB>0m@R5KqYltN`,BXIcGfRXCaB_Rn'u/rYDdqiF$a;O`N@0%Mo;d %:"]7V)ijC=*rK!h>2E@^Nd+s`E9E^8`5PQ]E`$#MJ0BlHei$:^h>GtZ`hGZ+9:lL]%E7M1!QkIaKGjZ;(t[n$b$'.\fP'%/k&E]# %[`^pRU3#/AU"MN"&ApLgCZpllL82kDJEPJt2]H5ke:_TMm+4Qd*KLh,pncAV*T0[G$A6VH3;J5pJc/0s',P+\9JWDs0_QN?5M8;Y %'6Qb]kMuO,51C*N.N"C\5>k7l:k`dq-ntD57T=E2%cOG(YL/o5,C5IS:]`)MD'e0L?[r+HIS?:uZWG!fZA(Rm`V=POKr"kWm.+0p %2EW^ja;m<0B(s+u-b?o`-j8'?U%Z0AJ2>fEl>7S`1I-4O*g`\\HtKU)4A42'&MQV]RAVkaJ&7hC&Ia_Q^T?[2EIGLa_<K[_QH9b) %7BJ86jhe$VQ%0c5KgEN-gmKllP.uWCin:2Nr4Ubk\7=BE>MLVuR4()J6TuseM+ItlkaQN(Eog/_&7X[hE2Ji)YnQY54>OU$_([gX %6=,#S;9OPm)VJ6OV2K$*$IiXEO+%JjKGG+lXV"fOr+XOd^N:icOPI9M:cSVUL?2r=c).*-8cmohcalB*::/_5)tg!oQPHA<4)QlU %Pb5j_mokS%'"eM\n4_?b)XUuMDsDO,bWP>/T&d_L_W)PqnOiF4!G#P)Ba*9gVrYpe6E5SoGf'6%a3]SS0Yo><Qm"6d/&Li-#F3If %c='g!12#JO,c=?qHI*k?#h1A4Kr0a*1PGt<p.,Dci:.R+=4a^33jo:O\1&WD-6,QrLPL`R%cCcB+F2UW/es/*-9O'qjY5TJrp\R2 %d/=HmgtpQf45Ci:p</mhpJS,8gb1`IGotO&-^Gj4]N,m"YbuJQ3<pFU>]rQ/L_Q<+chFWT</&8XPZ&-A;S;7Gnr<Z80mjcp1l)^k %McK#DI;S\*pE$,4o.0i>ic^7Uh1W]u3fHC-a/e]F]2VK5k,)BUS$c%Kl1BOt'gdB+S71TLE-?[;4\>Y:Cp/m@iSE^a%^9S'ekTnE %AugAQ]IK2qn.3'Kc`_)b$)_n"-Dd]\"V9]Or-ThbPo=G>c8Rnr#E=2@97aapB]>ZjX"Ysj55F='f<`7,36LBm\$)\V?'QK:"P+s> %S!Ofe;8j=r4o9CJr&pWo@YYKsM"9Z\;'KEHqD.c=o57^h&,:N*rh)6Tj<d@IQ3lkBN,QPI?b0WC\3kcFWngM-2B?B>#D<h-@^7*l %VlgG27tQ#C_$K"p.e38MFkX/E+Xmcg=eeX:6NgS!4)h<o07-13-U<f;HGF#hRrI7EBcr?c(&&e_&;9hbk>[&tE$24SA73/ig6fH> %s,[md0q_WHTHQZ2*jfrC/=&2g$'fLD2*s#fl/I:=m'Ru5DgeBBBK;987>(Tn0tIX6fF]X4NK=JYq9^IJ&D<&jeqgknBuE+(*EKE+ %Um&q1^!t`O.Pn%7g5f0NRFJcgE$bZop8mHqV%G=L7?+bWk.NLR<&0bcPjp+biNrt5cP]Od#qb?XI=u*fmZUh,O$P)t$f]A'BFtau %=cg)+F[a*0@t&l&B1>'5i=u@-GS5N\:djmKmW44TAP[ZZ,c>WGaH']Q0Z3t[/qs>J8L-(Z36@%[)k!8Xdjm1D\ok(^:rkO)lIU1N %;[_sHqVVFU6A'FaHa:FJ:?XS^gf5=g;uK$BcD5CdH"Xl(_S'6Jd5)A4H0PSmCHe^E8X\$S<$!Xm2o^U%W&FHVrf.1TbaW5iM\O@p %XCtujWV($;Lnn^8AC`[QDbE@dNW]2L`5397Ld8IqI#N]!k^QpXN8)Uk30]@'<Pl:oI$MR36o0%+!\_7K"k&V]1]o5s8MOIV;clmA %`^Ih_'NR%J3>uOl,lL+5]/GbH:]j:K6kq'(JPo9]nmc;nVG@Y3mUE^K::D#!0X"j![BjBTXRH[H69G@Ci=*JX>YaqgXFRt]_4e9t %:L!p6J2$M@+cc6'#<t*2crMLG/3)pN;I!IFO0C!0d#m352$X!GR(l/)(@FOVT2N9,o18S:)KFsS`:%MmIdSe2(jfE\,b3#4,cT\8 %i-\]83/0B9Lj28?#fQ[`Jti'"qF,W'5,>>ggMCW_lhdl!rQF%ohG582H''RnB9=FbX]L@!!%r!\XX`j_*>hnP_doo[CI`&enBQRY %dN[?$)2Km7D/]mD5#*L9==!=Z%l=Z'IGZ_<GtKbs6k`sOZ+uZ]M/+<%K*A\%D^U//)X'=hfSeb^8@GfOV%,TsXN\YI_5:uc0Bs<? %TBR5AdPZlue,^294F;tFB,qLEc?B\*VWQlA/OtOPGtTbB*s/H6c]?^Dd2lU?+)h6h@F/:>[*O7s.Vr6J@$An\lhfH,/W<XZ(YHYT %%cba*,ch^/)acu3>`*t#2Zo`G%_+k3pb<='GZc7Zek`\e2aoK@`%;i.:/(RB0Mk,Q57,D-mQ!)Q,LKQq?X)gEU2,pXJu'm_8mkm? %V,E3FGchaE]ElA'J[3>"';8Jig$69_Y=Gdu97bh1No#!rTh^A6"Z4S4'n3Jh:9(QX!'n<3\=O$BNX4?H+iJ*T'J<(92";il1Vu1q %$@H-d46d.]bPI)EZY/ASp+(gL=Nl:DG8HXs:a.VYKJY;S&8h?`ct9)3e<nN'8H%h@DISTQA;Yn(?,'1XpFALLe4l)-pOa`S@R2_l %lYE)CWT[Cu<6dPZ#`Qo&$*3?EI"B2b7@MjZAZ2asdB(.?KK<5uPqOA9]o'J<JXhjum#MY/Nu]c02M].kT.Cn-[\W_9Fj:Aq"S])- %JHE!:n\YQ'YZj's1M;F"1(XdmG*i$O"O7-5n6<q:Lg_G=2becBXt/ZJa,!Nb6kFPOiA^u#8pP["`28l?V.,!*h3J;7IG#t5p;r3" %i*n[@9UsFbJ\nDmdGi&Gn>[u8VY4tt6j%tGRLlAbNO8X+DY$X5\\$PJ5jB&i`'NeO#dVb[,c)P!EfJh.%I?dd3]uBH)2Mhn.\3AY %!UFNO0%kcMWag'WQIgT]$3q1d]n,($.tg.%(5HbX%lcpA^YipI8^<F:/]Jb,SN@;?c5[!kGkL-^?%$Pk$.]K/=q,r#-l-6`'c?sQ %0jq&a._K0,Xb3dp2&lLG>$111W;$G2goCG\q5q^2I2Y)PCII2^gcFu.M6m2cjP?dO[F!gIK.<H=D]:IF+Tr,]^cr%%=6"6[XRcO' %#C_DP1U=bCQP"::b#\?VTXSg4)O*M?$02[Hk74VD"ugL$Wj4d4=?X,iH`&VbfnpZu_ine<-kELLNk&WuOF:cAHpA+$NLrc#1Fi"e %e`g@<n^MlsaX3PiIK3<10sU6!ggObB'r1u\,D=9+/)d%/]7^Y8XDnj;`\V\p@pO1WGk@>LXK:Vsgt?]1gP92KEca3m`;$0b'#j;E %"7aAO6+k[.5;t))fnA>OnF?kL1r(q3$c'VP4N,a9_?p\0M$4o,eB,m)EOF3i>g%s9L#,\NX$Jp_GJ3n[cH-?JQr^>Cd-_#OO=-Ai %]4)pSqW"-5Ra14d!R_WDX+M\a`X@BWpG.QtE-:O<IY/W^B86+_l#F3u4OJkNGhXME\?0+j\T#:^fk_2!Sa0Uf7T1Xh+kLoK/'":S %97nIQ`E+f=<ppK.C9JXiR#RfH=!^s4;E0hVLNF,X_?;S:=,]H=G_*8M%;]NLZd0'#Kul[dKW,ro40h<%9EAScQTNEc*`A8ohb2c/ %@(,tNk];ZN+K6UkJ.Ubh<9e!K-roPtjZmF!,;g6l$=Ffki\kVgBoh<-Y0Jd*RWZ*+as'a/fZ75FV$`;e"?nb2iPQY``;iVR"56lL %^rRXsH>VRMo+jK"<N:kcIMOTFPJDL,QW>W1K0<rPXGmeh6'D6cG#k,^oX%@>&=.9Dr^6iY+.H*)N7/JOZ,\UR>1Z?G<o7cA^jW4< %h9oI*ZuJ?jCWu`Lf5YRM)?=[7b?8]!9%/A)k1/2aO\&)Yej/79Ui\5ihlsV&kr$WFcA_u[/`.u[K%$*3LmZa/dKcT+aBBrK1DelB %Kl@>32Bd!6nq]FJTi;)6U>6g"A>-c`I)JNH8tnas%NfMA7c$epUH'l=7cSZ)DB'HZ=piTB_n<OFl;k(3@h7ab?34L<D\\r?bQ'r? %noKLZ0eo'eI#h$O^ebdg'-#d/J+0^8/>[f'cb^;FMQIc9k\r^=\u)P6:f3+un!n"^n3^gie7`scMeOV7V&1H$r?I+[79JZ=g`K;( %f`ZbE-[.CT(aRB-]ffC19&i?ATF$aZQS8=CGF3F*3/I&+ijF#:32njUa"cO$6],S^0[n::Z^Vo6T\tCs`!_j3.ef7B9F8%5-$)TR %W3TMT>@!NYZEES.'J^o@I4[We4&'H:Whk(*0*8Poh'mRO/'rEikNb:>"SpS@b<"L!Zg..V1Ra^ba'_G]q(4l2?"]-$bbh)U_k9u? %Xb[s1lVr[1V/6p]\&<J#(D1^;a&RW7\WdD7['pi`>G`AH;XnOU>ci0ZVQU/GO%bp/A)_RG"pf:O12Tq?6:O-fq@la\hY1iZJf(0c %^cd>urK!*!PTgSY6Ijg_XEq-Jr!:/7,Kf]?J&&B]>&\O/Hk5JupIp$.l!fA@RlN/q(0'Z\UNU:ZlCutVF8G_rQ4Q-)<gI-1RgAu! %>3ntr5`LIm24'VNQ5WVm%u?8S"pm^F">nJL(SI8,_b88n'=2FV4`EWl5Sg]Y,%8q5#Dg_XRK\o'B33m"4BW":-@`29,>N*tG7"c7 %@$(8]N1,jk7QKm1'/P!6Lb[Bt&:em9T4k[\VMC=0?LIo:#263Yqo04LOgp`:YljUE'eG_1?4*h))Ko2>$+mjbfu\$h608=3!7+*? %?2g&3$B6IF7L1Xji+<!$fBZE@fDpnYF')F+3t$1cX&\F4jWp.;c*So7/N03PJfF?A$.[Xl&7(;$-_BFZhZ<@ef4`^Bfdg7.W"'i_ %DjSTJeB4&-`'e;FZRQ]mIN"l_4<Ig;@mQ/U"C:CE*.XP\rdK[b$Fm-e?1VM?FL>jmEYroG5aA@0@dajdq'UeCjprTd]PG?3&7@gO %r6lVCYgYo*k!GI7'!U%MZ""S@or*;7HnD(.8t[<EcQgB9;Aao2eLYV=lCg9.'rFG]oKNi[?]9?*k`I*lJ^lOj'4luoGg&cmY=p'/ %$reEhYNf(c^e7/YpIY8S0;shu%HuYTYjO3??^7%?561qj*9!J[GG4r7WWeke70?m:.>dhN$O2D<Q`U_UnWLEFqPUnn_KTFZ.og+i %M9'=H/f#o-3mMPl(J'FfoEU\+(R7.HX8U]7Uti$TKapUts&K\oVK5(coH50Ql\If!#^+(B@W_9d:<pLSO:;@\r7oJir(L2s#$E:S %9d(_t$RF:YO7'S^M3,43#\S3@f*%$S=#!+>*DW2PpUC^Q;k<NUO)oG[%SL8b`$o%_MC_-MP_Y.8Zjeq/q]Gp/Cc<rFXV/=7EIT?" %GRgYu:K:jm0b_i(7*c.u2V/9[II%LKT\W&G==(!F;#hND2i*.S"#`O&lal@Q3PPMe'S:h"Wqmkc@R;>O]5UZ!^s2In]hTk?+>V(i %Q"7l_%#@>/#]A%0g_K3`VkA[GQc3E1QFQ_+M\;\u)>b4o:Ea+m:]kCY(uRFGjKotQAmpFHPH*PDLHVA_+k23ZT$IGrk_@c564fuH %+p*37@iAtC\ie8eKhiL[$(:F7,R8[J6SsONW5UT''\P3M+=DG_rA[,^D,om'4K\JZB*/:.c@GkJ&>Wp0L"?8n+r`.8X'K;JM(UKT %[77q?E!N*JK+KY2L-Ta?EDjNSqpL>6F&oo.$rf="n7J/BT[1(bCEWnC%,43h;.t+UKd_Vib`>]?a9Q@^=;Sh\Xp.QGIjD!%T^A.1 %^aWG\8/LP=h5>#H2$P#4!>I?nKohObc5c;h]"1n;[7[UnlXmG1J2l#*l"=!#kY-Q.,/jeLSc9`IgKb]4e%s.)?Y@NmXp,YOQ_N>j %>4!SkNkN&hk+#5VQpE5d8llTT):iGNb20"ea31+s=NV0[EPrtQ:CUlpg-OK?17?EO+3MF19b$m4ArRHZ%RAUTXeADX>c]/!aVp$0 %;`W8XP,^inl6on[P^f)eSjRq7Ks3J]Alb=5,W3!dP%<2lq';%\S22`(?(>L?`YMrM(ZM6)F;4P_-Aef/8]c>s$PUBVTQse5"i#lJ %24@".D>_2i(2:fm)<(U#?T8J0L)>i,XCer!ckpTlBrk");Vp%$KH=HL2F,Lj`2"BAg)?FD4Ar%UQ[YtK@$nE&_gF9O,_+$5jI+o; %M-4HGG>n"8IU)/UqM28t>Ld<?R-E6:eV:07X#cKG(h(BD1GMmo)Qn"^rIN.(#nPYuAg$Mic=,[,Gb/cC3JCF[-3I\j4YF^1E',G# %RrATgQmIH!.T=,HQ36gMcb^UkEn$"n;^,FseEdpJ?1`51-!.>)cU]q/KVqRHQPZ@QXI`>9Q8*eZB4Th?U5JipQBks-.>CIXQ"7+; %:!@F7(=j)q9$#$@kM*GFA%%1edK]q4KG2G-!Vc]/IS$@PZ(ap/O!kN%G-H4UL?cOWg,#ClG2[$Cl0*FXDtcVPBl6<QlE,*@S$;JI %4QPQe!i3AggKF')=jK+As3+F<E9EV'/ps_+19nik"G5-V'T!D$;GK,i55'/'k?HHpp"C?9&-OV3C#;J6'cb5[enV]+#&hYJY#&V' %j?l>Pmbro+Te>Cqd%k7t`ho)FfC[<gH1$93-lq/b5T`!8$"J;PK$r&LM@_7uOIBs]:X?_t.*tf.s$rD5&`bfiF$`E`R=gVn<L&Nc %*W/_reij,FETX[LYu@(Gla=q:bcPm]12]?]Tn`RccU*=6U_5Rg`&sSs66-o%WEd@fl+X]cC9\e6PJb,%#5J[EB.O3nL(4IsX<;C7 %_ouF4,7)ud]Ob<te4qI14Y#\a"H'bR>t)td7?Ofc=ERUTYpa#=0gPZ>7J9!/J<QT7S6AU(7XQ=b"p/\gKq@=\'=61g*m#XHW]i[= %@m9_@NF#9ldVutcZ#\FlBIY6?%7i,p7o.E]9N`ir_Zm'8<\`@"#ii#GRe'F79o"ZW@OBKt*%5)V8blB^0d]:4=cMW"#EjpiNHVKg %99f2p`;Oi$,h$gmGj2;\bRtBmTI98=PZW&8P(GcmS20b?KM*(\8%)AD4hGPN0l5Mc_Bi$CenXk>;)u;EX:M3YE%0g8=V:/.?-7OH %F*4d_aD$kbVe^OJfRY%;N/:(L_r#"(W_pE,@d0YEM[!G8d5#m0L"2k.QZ0&_#[ah_8jp`eR)G*i9g,6G4b#\]X9tsEA,L(La64t& %NhkV4-Goj%XmL7`\ejs"X^di*:QDGOIs$r8V]W_\XQ\%5j$5=q%^'XNN_ikX_X?t4M7r`;rrsl4L^N\dSZ9P0`=6MPr,>124D_J) %ag5[/c?n$&"s4D/GB5ZW4siBqAP&+@HNp7dAsoG*a@?NpXZmdi=\rGnPlMh1W@(]%]IXQSqktAfcgLRF*i`IJQ"+A79\/fT%3%W9 %JgGqgJ'\:fe13<JEEY8gSL)/?*.jc-bp+WN1G^3Z4>UhbTC+;>-=M][A+T;RJ*/0Qa!&OL9f]",\g"@QU\<2&"CU\e<7;`up>0eA %iRpgXkM,F__:&WcFo-UJ?r&K6BPgck8e)EMb"upq5PS_nfANm'6m!rDWM?UM*pD6'%6-3kS!rj(cBHn!KgHTTaeYruEM^?1jIa]& %l;.fE'L>sYq^";IVeHSUl$EWRg=3Q1[!G8#/R]m.(IcA+$55ldDK:hU/m?s/2,4qdS@-B%.EsuO;cHUW5!j#3jiWFg$K!7-&$B\s %ma`Ob5]LJQ[7$QMo4+\9Z?kM@f'ZZuVcHT"9\X]l=*(pT8leWbn3#aUI0uoEhSbZ28TF$Kn&r1\AT@>(C'Oa0(i;*>MOl(,pI)/) %k-^F![CM/<3")Cu:LF]HGo\C4XH]J_KK?NT*`H:qFSjic.t`'7-FN=oU&iBV!%t0WM^?6$dCDN+El`$MYV.aM0X&,/=.#&liqglt %8lUsGP30:!nYM@;2IW\#$K0UZatC#,"fC!SIHF&-8Y)k0>KFf6E6`?r'G;+%e^[Q_@3j[K(ECSt'd:H#_m&&3FXhgU;@\/d!2!C/ %/"AG+&=?T&nNVpK7e7$o%Yo^$i@lVZ+i)W62YVHIAnd`+LY_X6FGrR?d:Q!%:aU#A&p$Cj4h;I[oVmuD[&t9feFs2;]YLVpibYs_ %*MC'5"gkVlJT[?@BAE4dnq'NqQA!W\AtYAg6>R57F0CX$`e>_ED;.AZ/4DGQg(!W/EigE@X41@S!u[4EIrgfjhaeU<UapaRO?ET, %Q1[8]3D()C_9XDiM",fna>9O&p8uKE0sNPDR[PS)9ugB:4%kn!<c@VPB&_RAU6M`'_^HnQ-b6sV\n<^0pp!FrjW>&/FG_YSj^<CY %H!dec?ocGcLI&qQeuED-N"MO6&@\5o@LTC.c"AbPfXQM`"+U:!E/0a3EgIm*`\He&/OD>IO[)C`XFiFO29Knum%Y&4ei4Y'5XpX7 %`jf4]:<.(H1I@bA?W!@pnoS5,:,ZR#L6O)Wn0<JYM2mW!HnC-2kuMmGMU.HlSjDolE\_UiAC\`+FG)![6V.'&n\m52cS?"XD]>:+ %V(k9ZDC,DM8lNFg.M,rQlInXK,!;b2>6KoA.s\^V5qJR<+IocO1*)!J20Q3Qh\i50K8u?1a/_aQW?o_%g6qf=+TgVK@_@h?6PGGO %XC\55cGn,c1,g<S!Y+LjUM7dk;juKNYaQse2;G1E@FKaO5IOSucg<JZ$gnlI1:R?)[>^!]&6sg4;6&adr5G0q5GCIbMS%M%2=r:T %GmjWYqL9fq!"8(Q-;GHL.a@_+"I:[b]S?`J_Zf$H&()rj-IG0Gb/X,EVH</p2JpI-PkKXga+TT!Yc2Zl.s5tk0U]lDVW2,L)rSAa %CtjZ'FJdYfSj`ID#HmRj8<K;,D#5O)6jl3eJ'Y^[5gk>tKoF\fFPo6)G-joX"j.N5;/]1c/NuWIIR=ql@R-#f;o'8C!N_.[63T%. %o(AOlGY\DhHEJ4`cln;igNe7;>bO2UC:XZr3>",S?9'>B>Rf28<sqo73iVAFF8"P^m6l3>'HFf_a.e<X1PG_^YSeY5I[=P+eeB"F %EDhE(VVX1<#Q3F9lV90?Q'nkE(j=Ba/l#n9/+)'MOCV6_1Xm.-dN,fnX$<-*&]L^I9'@P"Ah!MVZ:45LX$`D;QIiVtQ7N<kS@0Ec %7b.1Tg@RoEY!o3p/f5O1$qZbKM9Q(dA,^pH=Xkf[*__/SWmWGR5C?fO/XV1"gW=57Zk42>$Uf-Y)#>]um=s_P%f0^+3HY#fn/'c. %Fq2Un_3,cbS9/kCMAjL$Y95='Kr(eeoa94bMl"]PX?Lh3nb6/r$*H.$!4]sf*CM#>pc>KDd*AB@H+PFOPphDIoDYSWEmcp0;3P2_ %Q2ZUK(OI#4lKs7#;WEe'589RlPZEJ@&iThX3jse$Ak=I>=gjR7I)(?J$<h8_'HLg=2UC"i`7Q4Q#f2dIi"X.!5qO+H;t]Hm*J6hZ %(1#E9/eJ@>^\;8E<*s@pF-DXt^%UeE\5Fn%54VM:_[^T3\0dl?`qugrj$c(U[HbE9c+U."RqBOB"',8"=co`L'ac=Cn1^:fmGnrs %6O8N?8a\V<!=B%&(oM[s<S=<rZ(H+M%&ZIC0GJ$>&JL',L15!K/D<H]gUTB-On&S"@:#.-K@`\TkT\!E"@KY*#Z'Xg.7)8C6/RT1 %E.6g@=]NT<c+J&U[S/!M6b>1uq-0,p9kr:PC1-A#SL!.VV0q8rmo]BQN3kTpQ8Xs:,rhI<!Nb$l4R+!DJZ*F#F;0H&+XnIlG620r %EYY"QVR%\^?k&bM7T"0QC2d#GX+o,MCLGWC5r,-[Jd[,-a"#o5'0OPd>+$(M3Lm+G%<HV-!"cON(!QLbC]N"^mNJdM'Fpftn=;M) %r>ORK5fM8+>M+6:'GIfXV+g7a(,6YOBaCa:"<7>\'-d)'Xt.]J3sM\2=fnZH'&K*)8*-HQ6I7?20b`^`^$8OsK0dPX#Y.%No-QtV %*BM.)PltiKE[M'`;5VpR:+#UgKL4]s^JBO5G&O5Bl7OaXh?'n!_:R25/Ql)7a#Re$S/Mf_eoPh3"_m:"[]@'":'nk\3V@/^]G+?j %43Y8Y-3Z;\o0VtILQcC+$%JNLEYB47iHbEYU4T<UIK7WP)S(SG>e"2m&gCQrR3lf)cGT/#V.IHeCi,b_2X#,G;P^Q;h:#K*F:W69 %k8@VBGk+TE9B1o`;M]K@2:npg6TE6CgMQ24+So(dcEk_%&u+)A3@sRIB$DmQc3V3]1scgIDkSZ[L]U>8"T[?*&l6paX/D8E;po50 %/f*hj=a$Io[?NNk[r,8RbEl,\70[r>"j,VfaZD41aJOmWk,8Q5HfZg4+.IECZFglJQ.Z/"b!j-9'*:=%6>OPJ(Fk-Aj/<3:Q_T&i %#A6_JHrdOJQWK&Q4VPsEk@$a'32?Mr-$(t*\YPYOgld]T*)HesE)(OV=?NCk8]@6[JIj/9]'^++4l#TVN.F9J$id$f5JgB&Y=RSY %?\_S!O\fGu+bqZ;RS5n/jJ'nHfCI5(L1H!s:*DCEB!gRD(S(91X\BDEF+]lWeFE1[1aL(,;_<d)OQ"*)p_Kq.6n&C.IfuT!Co2:j %BP_,q:84Ir<KYgRC.tWCWI9@XV-:KI"6*FO1K?_p(UmpV-@n/a1lG'LOW;1?Q=<7u4rZu>n94Bgf]O%:HZP5pk_TNNB]@8@Ll\h+ %L`dj8.^\=1)6'\Y+pBJ!LcQn3=rbjp]`,"H^1>=?N&+63N'<uuC^>lsb2QC06A/N`-[iXuXIl4ts&36DIOX2]F=:KY_NQg<DUGJn %FjYN4gXKuW08@a^(Rogj>dsO!;bO:V9X<umRC2B_KaJDES[1$)@WM2H5Cb-QOj2!ero2^NJ]6T's,#W?O9Trj9\=(<<E<O68ouQa %I+Hd]C47Eu[a$d#:l2it7\BtCmho9%Y:KeS"(F#!,8*B6_18M#6YJ`#K([)!YVG8=hEf.JL2F/2JYG4AD<lDu?K=K*DCXhNmRm:+ %JgK.eM[Wr+*kL$RJa4("W(bjXRlmfY?52MJplQ]o";Ql=G_n4q'()&4q/X,+e=R*<k*r=H*a?NaK+mYEh9R6s'LFm\<=6"1!7]6e %nnb*;\"f_H7'pG9>Ccuf"4p=23>/``is35?Z^Gb-Nd@J4RRE]EaA?"@gZbY2<"b&P0Oe7;#uiVP(f=X@JRO6J%67:,)4PV/+YJ3G %K7=-`(gfr9P(bL?C_:]>%'K<,5mrA'<A0SmJ.F!GSiMIu(LM*mgLPGpG-VR\)Q""/<<M/sEoBj&e&?&kLWf(#"*:&FJ6KSqb%n'_ %m"I7bCd%*O(0fJTDV`?D@i(Th">pSg#iVS^Oj1m?8,]1=FamQJTJ=>A9$V$0s,Z`0`M-8MjrpQWIXuga8o>:s.cQ^OV6X+'M'^_g %Jc#Cr7D`fOcmW`[&p_0>PN^2F+8j\ofBccUZgFeEC1@[t$I():O$dZIiX7L![+K`:1=jn31";C0kGJ\Nh'm98ZM'INPP)^Z-In1? %^EHCo+0AP?Me^]'WdtaSW102B_upD6q[)1>O\>E]L3L:ENme"]TGCUW4A1IeTd8r,/ts+!]56C.MEL6d#%/0iBi_pGITaG@-N2FU %4BO29Fl0]e.q%Vt_k2m`Sd)2[GK1$:Rf_tOpODY[>4;%#I0^tDR8Nt]/R4NG<oK#%95rR5Q0@K(8j`-Mc^38T1qE3J^i1`oRDR0k %BbbeG'0efeT]Ua?X-P<2Y&'!08@iG:".[:__+C(u=.^BS?sSF@;t\m=fJNcOhpA9Y^%UBF2rPMd"`U%EK!EW;L8%9bM3>QOgh=1< %,TTtA#!8j\`=c#BTl55V>*p-KBU45G-D]fq=63bQ65k^I3t.O_>N[D*5k^3hn7RsT22XY</^QQ+5SboGaY>K,!mb0']!],;K3%<g %!$P'Bm&JV:p3.;oF>uo8P=-*fZ=aDD/.U?1"b:9\<ZU;E+$TR8f`!EA/];Tt;1=>#;@SU`Hg?GV_o*[&EZ\R8JE(1X2c:*q&8;jG %6pX=CEPSaSBs\7h\WA@$)B$i&;>JF+(VoVB!eqHXA&t&l^gSVl$?otsH(:,S/p,A`4HK[IMoS_i&0T!?^`k;-]r]Sm5*gRV4X`DC %fZGc2%'DcL`ln3idZ,=U3]>FI0euMPaXQOnG%aa9.&&2g9If!T$_ZR8Cp2IVd"&>9<O.ft3Fn,[pOiMV7ek6j:$`Uo+D6S+WmN4D %QqUa':H`_+RS_$?>c20gkCQZ^_&uHl7Zm4\W]U&i+np(,Pj^sN97FhHaoP&+!]Y-^p[iP])B<Sf4Cp:'(^&Se1!(bm9fk-;^TCuI %,s01ci%$"=15gNg1P1Z2j?YIQ1b$+_nU:K%(^Gq"_>\ZMBnJH4g$rjL8erX.V[nS$OR?T9o.a(AmDdqQ]Yf2DmbC2X9*'H!o0<C\ %g"9hGd27WhBXt"\0hf+Tlj.>'4o!BiYL>Hka/-\lES!2,EU_0S1E3.5Sg*1b_OZYEH&=N3TpIKkJJiKfFFb0C8oVi\3Dk`u"/c(- %>cgq)"IuN%i&!.],SVEe7-Y]>#@b>5Tf+D\1+S/G%Zd]r2?U*ELeD!N2XFiE;AUNf0eQk@<sC8O4Yp]/I]AKIK=%RMe:)ID!G1HB %_5gte)7p>S"XB2knUBDsVO)ekYF,PNKn_H?Csdt+qjj*+FHm`3N6snV/NDrJ1*T_CX@@SZ#[MjB4#VP;b1_fQ?Y.)(20OelgT"$l %R;6,?ad:.EgU%!mkIg;[EbR+CcR%.OUO<_PE#h+\d/J][OiAiaEj'u6+ZT#!<Nh:'N4l>c[O?J?N8.EE@&tk#_jD(QeZhH]q1+hW %^+Y6T\Vg=Kk(=r2@RW&!'Cb]GF9[a_.A2^SA))1+<(J3*HZk3u$C[XpEM;b-P-FLG43#?n/W?JdB1I1r?l`J&4'p9a)]0Y0WsL$j %0AV+..I,tO?Q-JcCiB63bmA?gZa@\&)ESLN/skRqIVEX1Bq6Z(hbW;R$W=b$G7+`"(g4(kR`QChOoqTQ23Et0a:POrbS"qQVbB(h %kE^6+''HsGJdN[]M-JnV5M*GH:&uD7]c(O<DC(A*P3.d52b2B#HOcg%.WWZG+]$l*S!=58:[j9pXC8#QS7b6H$OkUB\X4]mdQ!$M %E8Kq3aX@!e5,<EtQf$:R,2]T[Lo?At%S9MG;>N&d>[6=LMIWCQ0QW*j_2BF`dj(DA/6:/pZu.UcRkU(\"Unou0PK^^3't-ma=5)b %#7'SYpPRQRN-i_3iZ7'^%m%SQZr]PQgfJg6]kjY<*00jBFet\K1&=mUF/dlSC&XYB_.W+eikc=E3;l>\e^IFHOs(l<SrpB8L(4nu %:)sS90m2"WPqncnMYMN#XSk!g8fF9<_As+ZZRVeaLGHg*'E>B"]mk\U)Qq6LN@J\-*RFid5$)b\dU+c09S]bIh`:bGh/oLP>._&Y %([*kC@/c]AQ.5*Z3+nO$)rkVaqrAKNXJiuGJ5ceM^Db8hfTS@+%SugiTmT96!8n_d@Iu.<pdg!+mdNNK!IACe'"1Jii8GI8b.IoI %pu"F9*PR47O7F&[V=-)A^PkfeR5#ZL9GQI'RsQK"5So^2O-LfD[H;X;#lJrgkP!SN(eo_((FU*OEDII-+C`$4Ye9'l6>5A4ngMi# %A<u3[`&s8?f3Ic$hsA`'7mug^TG]#QWnq@6L9b3*Mj`g]N4Ec2dBg>SEb\KgO6\XfSI&,qAE*@DWa>.['gIUu@9WajH^C$&'#8f0 %Aeu-)%a[m)51@k=Hb0Pdl&b?`4c1nhhiT2\8PZ<YI#7M<2)3>F)'fJO/Tcl>7s9[m'"57EDRWRK.-Eb:kh#o%Q1I!*no49o"(K^Y %D'c0N;`_2IM^sr6m$2[i-dpc`/!%rWgs:H-kbf2k2is\<qPD7;5kjS7UcmDH</K?_#.s8lMc;'\3U9+0a[F(ULu\/;312L%<">@) %&7W/BWk>o^$sNm#!8!8ZQg+e$'5:gEn+Z&,#?l7e,/il+`hJ'uX&4B_9Z?q<C>E#p"gtV`T2hQ#K!aLrF';m43Z5DKb:^-G9&@t% %]C""ah8r=#*R\bErL/\Q@FCiWMeI'q^9n6+BToq"@,]<NoXs^jNQ-d2FWh@;fD9V*K.PZ/B?0E2qm3m"#mR<H3p@p3C0cSG^.9!O %=k8S_ZV>//kF-4b#k<qUO.itH<UCOB$3WA^-a6<W1>OFl4^+i,He'VJIXN52>k.0`@^[;Bi[mKTGh]qU,>B#`IHn#E9.SA2^FB*Y %(YD='mFdUpr(6FH1>nm#LudnYAaAislq7X?EFROuaK6,NEeEB=qgX)VQ@Je`eqhk6K0hZ[LA?LiE/lA3YQ<TNQ.H$:jW`E7Gr[cu %@E#rNbga4=V&3hAHEbu4^@IW5G'$St<gIs^ZFH!!6aSAlH5dEMVM<QG`ts-mHS_!AM]b$oQ\D;j(%(Sbc&3%Tq?;3L&0H9:Wd@O0 %41,DBBF-1:'B%VqUCqf'QRS5'cb($iO)J<#QD>Z%R/s74\5r?hJRc+_i(r5sB%FiI/T[t1XlVMNWg)MJnUq5fD;b2K8%GEtde`&- %D#G_4Z_Akn$B(6Xf)a<*Vllf65ZHC&)"'a7[(b[FHu&K:XR5-an+=uZ$q.Yj`%$9amR0W!W$fW3EAV1GEc!;I)'D@3$fFVipY\qX %=)/L?g'U9-^Ln[<.DfMAeTK,qT%=LgOj]DEW$$cUQa'0WP'ae.0H*96BL(CT7,oiG8or[PqX6oXEM[A]I)nclYk::L^T]Cu4,+e< %*1@VY4I>RO@N;S#EHZr^$"2XA=m]d"Go;'&d5[u?Bj"QS;oEg%33,Dkkt^6219n9N8s<#HMXGG^5q&!N.ID(&jn[Vf,P!%nIDBnj %g`)Zr7g4fDcSAV;mR!^X3RiQB/hEpcCu*TRQl@bZ\1@e[![$-q]8?L?-QiskTmVP"&1SJ&\c-aJY0ELE[3&W"B&e>,I#NR--E..* %I]R3"W)h?EOYOKhf#-O@>`lUPGKG3JMoces$h"EENbIA?GqN+B[IQ8Gk8>q&UEg$?^^diU2;j^dNOIb:F#QS29VVj8k,EH4X.pZ' %;Y[$=V&ERQZKeO/R^H<^+q+^,no\>iT$o96"[$Ca3M-jMT6Fp(g!cGlOsdAYBL><p(U`[[6p3""lXlXkdHN!0L.PukY6G^SSmtf[ %W\@a78J1=KX^3FW5KS7cmN!^3WJYt<rL&&*LE1/98]t..8ldrDZ]b,m1)_I'_M$#.=CJrBNWs0[/TD.Dckt^gNC,!L<Z8G=="Zb< %9#9D?8@48>Bp/hXK]GYZ=3@<J@:=G7'+qV'WFu;\ZX&s_)rZgWME[IJTBAh01X![&R''&>_Tm\#3FcGonWG=!FDK7,$eEsG%.%NG %Rdm[c%(4pWAY?taNa,F4U</%IpUsQF;uIF1btkECec<Ejf#`bbp(R(.IraJh,VQ[:X"+8Q)VZ=E>>R&qKOrceWTd#E>KV?$Qc[dh %Og^^5nr!-p#"aHtR/Bcgrj&f.(:D?&H&!tuOc%qIe?`1$]10Cg@YX4B"/L'b"I]+P:25sr.&MI.V(,BBZjoddKZK$jRB1A<L!p`] %d6<f-99i^].)^C4(O+-TXlXtBKZ4\(59R*a_`RA``mG]l9b/JBLtQBgL6XF,DV?oYCb;tgiMIQBj[4L/<<tF0V'4CK&mt=G$M]WU %f3R)[C7b>=d)1M4!,6k`Y+t\BH,S,GC!2IQ3t3ZP7_@e:Zn3UX)q"*3@B>AU(VdN-O_0uXQG<oikhkE'H:Lrn_LtU7T+R`FHdP*V %4-bXS?>F2l-cKiRWKAF7]IJ2N*nl,glLT"?ThZ#96ibTKY+4:;H&,J+E_XQQWgcG?Nm_]ZJ-<!81;n4a=WEDaZ>*+$,)b&W4`6jS %"[a1?</tTo!FR>+d29>X^GN,LoZ#@7o5=clg(1EBYpp%G$)@"Ur)VGHiqKB`Je)XEQB73%8@Ai2?iu2Fep;rr>9XFu&R4kVGX_Nm %KYgb-j^R9HBOnFi+qC5;,d8Y-MNl!r4-eX/_H81p@:(j`)W1VPLEX]M@:q*kgFQcs?c=ZbZ[DfP^[g&^R/3;=A\]"GnpUF_l%S5e %SlMMG@B+"V*J8SSSPgf)1_sd*\o9r[&k7k>'"_c@%a$9XD<b4,X_AT&#=()m^kjaTH:]`9<56A)ceK9"RFe_-1o^\3H1mWDKuXX. %]LIR3BqJ:ZE`6H*]HTm9HonVj<KNDJ6A$%&1((,FE2?0Qdbo2W*&eps+e^PLY#UV)q43'jSqeKZA3A-f2J1r<gI2jsS96h.bu#^4 %2gHs?Lm=LQ\LE8$^<f59^B/h8IPj#5.`2*r?FoB?_.HQ?+CPZ8)MKU&#ug"2hmoRPD>ep+=]o,F1Z>3hA<>j!Y]K0[`UR&p2s"%" %8R,K\,7u023>H9&GYt#FTF,;>%l\7:MUuDB_=FSZ@i+*4Z_^9<*#q_gbalZLl&4WSp`Hh#"7`qf@cfK:VL+S*:Fi&sV/`5n\VY]O %8(?[FmNrVj9SD;7-'3?g%u5#bG';?)ag<BY+fiW]bW;-UYekUY:cp;(ETsK8XWhPpo>>]F6U$M?/5/ui'NE//nmf!ifM1N:]a?n& %Q-'SER!R*sidKPC-QM$;8:lWTmh%<c#;1ADf!b@(jZ.P0T42cSXX$ih^0r_`85_Vb<n?oT\?Ug(:8XZa@_9]-3\f2QD!L]VE1ee. %1\\:>pD#BUY;Iu`@8:h6`06i1YSW.+bue)cUqW's@rXpDoqX@Y)=X_;hm%_QPZ?:"&!t=Fi\_lni[cf,6[q;ajs;JMC'a]W3#gfg %o4mH@m<T[O1dN]F"lFq?h,X&.eKL052NKcH.F^L'((L4?EVhC6K7neUUcBT'(r&S8Z?+m.XR/;.)XXZlca#0MhTT0.#+A!s^*n>l %lkg[EPX$l/#38JdE?3V8)j\=oV^Hq3@Mh$M@,2oSqDsF4H"s3TB%Bcp^QVq["XTa9,/2H=<n8X1->?&<O@`.m?,^Qb.Xm`p*dm,L %lon?sWn?<)ZUa&Sp+l&me>fF2rCO4AR5OAJFeg1/J+Hgm^icAK!%.8:j1lUAE1_oS&]mX9`n;!k7u4Na0'0qp`OC;.#EZQ-Vt.)Z %MJ@M[O0a])m\%R-K,Bl]<[+'dl)P1M65!R4UApCq-op8"nZ3PGYJgXKR;"<#!`\"+Yn!aJh*`-kn\nO#B!W#G=lO-LpL.;h<L.S0 %BscjT?Ae=gCl::8aI7ImJGUOs\Th998gEk<4n0c45"\bZe.MpU;13"Sr8ttJ8g]h&.K[VQWVVQ9-sqs5>-ClC8FTl;okJ_^6>/O5 %+_EQ"bl%&]5*96I6B0i=12bASUJ[Kf-uo_?,@Zii\;ta1jGl<JOcsga54*?@3nG\DhGShRMhtr1S'8D;UjJV^VGm+!!4%JA(?%;= %fEJ#u7!8*C.bkr'>@.MZ@-uR`0=',?bs>tFX:9a526kL26U26^c)b$Y%ZNp%F@CF]#C56r.M@(b:k?qaFI).*b-f]T%B:O;^rMHK %_M6sg5%9H=W*C5EF#E5kS\@Ecq9jB?PQ!YXCakN'ORZM\f'\iH;Tn0&4;O*>6C,rcFZj#8l!-[%D&:(S=e_rUi?m:-Y@G"64SH$J %C1d.o\O=PKP;A&D^Qq3P%s)Lg3o)-t/-37cP9<p'9!bNh=gOSd)S\2GK<Us.R!j7qN+jt#b/a'"`\^d#>_];[-?1L%=B'%.&TXTW %WqiKtJEiQ)@bpl'?9G6)nlT=j`2HC1.$pcNCd4m"2`P;3DV<0*"U`B]>c*.l8/Ts`42f7QYOIdK3O-bY4/S"S'1"<S`C,^5G3W4h %f>Zg]Nj?-tE::mWYYUARb+*?2PCV%A(0Oe?Zb(h?O?Igug\H!>Q$#e]#rW6r5ss7J.h>(G=e,gn61tM!o#aF)H"L?-@a6<((^*bl %6K]#Y4,(l$KHMlC,%S=q5!-2GHHCHR2!:.`!ZFS((gV/kb_tl`"Pm'W@hKaGLAg'erHc05E/^XScPl)g-cLkl)d8%*&*_d[We/b= %GCPpkkd=Ii5-*(+G-s[aE73cQqdj`,J+7`467lU[0pnlb->%,KH0Pll;_Wk4[5SJQ&9iu&@`DsKS4)Ug7HUED.[CKmks/nphLllt %7Lm_(0p-S_i@k()iEBt.EOFZ/36aRmQMtHg1.<Y>O10')5VJ?MD:bEu:7i)!Q$'8]K:8dJGjM.o*RSt[JZgi/.@?#<r_bPabWnh4 %^B:G4Pn//@26]0mHhbIjeP6RmWRX=kg]f8&C]FW6X^dL9@5$r`BWNZA[k[ZW_*L8_=aK4TkMWT*4>+qjM?EeA(6*(8B3BRA:?IW3 %D0&0W*KlTLPN#/+:[3mn5Y,EHhLN%;l-@/W*@JD;Sh2K^_.69X)P"Z[KbZJ[FTB"VZNIH^JWH2es!qG4.RHV-A.pSs7*]u^M;CbJ %_V8\m^9gmmZj.d$YR2/<-ca1/^I)0@o`k4S/E5>SO`>,q,e2"qUR<j)g^T*>dKHaP3`U*9o(L[qIAk3)3eCq#4[+!):l@Cb&sB+G %_bXm,`6&Dl?35^39LY2!>L?+klIJ%=8p9,2&Z22h42r?9+L;E=?V!ooI`2'G?3@e';eL+3<W4P]m'R9ZDGFM\gJ.<9Ll#G)h'COr %/#:$GD!8'^SCS"P/[5cb7dIf#Ir"*R%-SlO.b8QHOGLQbXiqr=am8bfB=P[`_8_heKG7q:FTNAUSWBWb0u+5-gVcY%8`K_n830,P %hjVMZb"VoD&nq;@GZm\#>p<@?5&<P.l<R#e.H@O89WkR9F+1F!r$?(ZI6pVXHjQTZ#aloVQ$g_@UYI]g^M3aKYL[-+J*d9W_pZC* %e[%@ENX$16.1Y<#2EYc6G-RS*:q>f$AoZU#qH%HS1:N'%IBO[dRlq\ln6\='qrgW$HOW6]WLaeWC'k!#8Q6&1\\IRd'Y2a(SqTsr %8L03>Je("='HE/b05*k"#!fO2Yh`!uE8MPnV'N;"iPpSUBnDMBcFiUhOG>6q]*Zg7(JeT`/c"a>6b[;#YuR7Zr\B2[ON`lA7s48r %5&kLma\VJHSt\QWhQ!I1\"PrmM'8%&O)bg`OUg=uJB(\B7bi0-$<:MU!H/7%TITefC)Ktcl-6+[<gAF0KsDes``Eij6f!DF7Ur9k %]m]srm%rZ:LhRf?V50>SORa)&.&p./,?W'JOh`t!K<r_pGc4a%I2TL:d:+u]JoisPFBl!^<#-C)Hb@@Us*3E,:;tX7ZGNra+#,p) %=l?<#Qr5^P_51MH4jJFuZ#1kieT.tiZA;.\huC;8Uh72SgcX_PYbK`Y*W&_eZtLI0Yf3,bFWpVJfdX-OPV&Nh/T?f;lF.7BWJk'S %24k;*Y&p%;'h,nu&sq*CX9CHtMn*3Fh<n12M:Kn+>dfEYn[/T<QmiUZDjugBo,K/jck=L.F@oe,gV,V_Ki4/2=Q:CsKU<<D0oT?, %]Z(mf"do_V9FL(ITB\jt3AMHt.`AKm;hEQFK1`OhWo!C$U!#7`q5tL;bpm1cf+0iFs'*BGBcoPnnMuhg,%-?VgZ]A8*>:&N`@L7[ %/QMahAdsWT8eA^afO*QfC:_,4B\L1`Hcbqr_F!0+LZ+T&2'r[$'Q4X;L8-^%`CgGblI=`._h-gG!@K8F-<=++iDTeg'5P+u+mRdG %b/YXJgEoZH-"SL@<TV,VWqY5BaEFpL+i1\FJX2Yj?Kk(9Pc,X4?q/Hk0aJdA:Ig5eWgY>flm5n]/-^He-(.IBkWgikojpfI3IGHg %*r5`/f@f,E<*Q3*4N4;$64!@%]:?SMf?T9#9Z(LIOW6EA@Bu=,:td+]:sAqeb*+Ff96286W1bBRs4+USpAGtf_oGe%AGcaRNA0Wc %K_g<s:\)4@!8)'3SF%I0K);_B9H+G)bRR8q;72o]]',D'8/gql]8u]'J*<*3HG70Sb1oCXl;hC'g8]F?52*;7N.`EaeO/;!;4kY# %oi/20;6A]o`:'8(5'o2eE!VE#L$XGamlQH2k_JE+6se^t`2=.Uj',"6fuPi7Gm+bZ?<Ik>\S(FN'`m]J&O>q):R9=eS;_J'D!P6. %@_fZ$FoB[g(53[>$$nB]k+4Z\1=N.7E6kO1>be$(#VWLJIV#[GTmTucq'S3gG[uX:8I1aJ"U%B'b,@kAnpX8[b4(SN1+>+],,G,] %aCdS-L`Zkkjk5QkSdYl6/.i8d82l3W`;0k23?rX6A^B)Eb2AN5.'(_Un36I<6Y\5:9'pR/B'Kb@X%\C"S)\&J1J&`sV7rF,0OA]J %X'aflni^5KiB%\`cr5,;"t$["*+Q!3$+$46Xk5,?l:b'1Qjo/',p-URbc?.=\H+<T=qo$RM/C.ne1h4NggdXL$qr=RC,$tJZKrt3 %24Z=2AGl?.pDrd8/[8g(g%P:U+Y->A`;3UAFF+o.Y0-;q+S:<G`R;8L>k]S)+U:R^KS,TK+ZJ[\R*-ISb7L\HKX`S%4:=/9ESeK% %$H@ee5m#YN@A:@K5scf78[N,\FLud/F8.rP.VX]r&0-,A#F/9jdTBf_GN29k2P(^^b'1?sqj&J680\sCeMBg&2XCI(`hJ?&eptoD %HRoXnD#LsU6/TiEYE8qV_`;-*&=<IKL@>mjBS=NrFGPJi)&,R8$Z6!,[tg'#=,iG(2S^;Xk[EPE3G%MZs3:=io3l!uA>MkOBA-D; %E^,*P)?_Z<TG`Yui@%jU:Jo_Bc_uKH34c/\$543kWqPp$=#dnN71aYfHN@s=8FS-4VO:-fZVrsK9[D]*285D,DY"5#j%@CbQeoj> %VS$08^M(#ifj>CiY:;i6Gd)'[QM)%tC+h=M8l0Pim:BAMh9igCKq3I*_\.;r#,&]DhM%Ra03+s1?7rk4<'H*E+$EnPhUXgPD&k)` %LJY]D>4-V5i\LK@[M4p__I`?7LBkoI?8#[p*U,%58tq61<ghXT</!BR(%_ee0<)%k'-i.OdO.[4V*2B`E\(PRLu^l'mfm^K']>gU %'q@1J)HD.J7o`s2<^%7k?b6]Jmj_V+*,PXH.CAVD9=&K;^F\0cY:oTVIE#=887\8oO)`o%Ac'.4l_jT;F3B0BMsa1&>MR('>,W,A %-$T3Rrpd]7lG/ff+r?./Hr>ZXjElMMJi1AD709j3*,HlnKrD*sN2l+OSN3j:>,c7P=U]TGpYT<W;uOR^?8t4#YO,)eea>4QbC]i) %d)Z#QnC=;Q!aGduHr@&=N!RP[<?$uE_W)n?f8Ht\*2cc$dr(hVBOJ/tD`p(L]'lM3C2d6eH5?FQX!D%6L#`7!#YflX;[(eqVg]G^ %YOYegVq`EsOClHjEZ?#4PFAs/\im@O4,Y;Y,HE:0plhHdjbf._B%!X:L[%SXLg`.2EbQWl9I!E,e1l@fP+6H/I`3bIAl#VKUC!@B %7M$t:RFL6hW[S*)g5fX&bgc;+e/HS,nSOVcieV5M=ec,i>6qF:C>nS7p.3^C9'!R"=#Hb=6*f,GFt,HLA.ur\Z,<Yo0V@a8"_E5S %6*AFiI1Y0t)C'M@2%7GFWM7\0K0V0WQK<W?@*DVPRmb<:OsnSu[;&GUVq<Et6X.%Qfi4*$YiFJiX6J^,N@'C@,5gJ_[p`<k+l;T: %oG.ip<O'6"Q/5J?;XS]-*G!0O;=3H7T+lL8*6b,f$mh6L(_T#hKqCI`Tc)bA4YNVV?a&[Qc,&J0kku\T#M@W?*rG6CqsKU4q^`M4 %U!.jkb%D=dBXn\RYFWSY8lIU5JDDC8F]2:B**"O#Kr,6geO^u`&(\k;)Q8t%13qG9@OY&Q=7baLFa&jAhAY#L^p+6&gSCnS`4QJ% %G]G/I!W67gN0hX#"_NU=Mbf/n0nR6Zdt>RWjT(e,1ice"edPdGp:I6W`'Rjnc>tII=b>6gKWOBWgGnX_*Sjg60Yo8>HpZ%nlJq.J %>Ki!O0#nN0<SV/N]s`8oa;j5\WBF`sC3Na)oQSQ5GatMiTPf"-XLMBN!;ZK&T,R`J"3l9K!Nqr5*:(1TBF<JZRd-KjoA+?"j3=t1 %"]cG'_MiGf7S"c<ahp@7fQ\Vs8]gMM'Vjg(qa]aKr8'8;3EX>Hn4?+R)a]MA8qAZUPh%k_qG>6A\PbZF5d9d^;aAuA(=Bm>DM-O^ %:cef2cLXO:R*6qrE&Oi$32lAb7S0-#7E/ucJ8d$@I]-9C;Nb<!F1[\j6?:[X`G,VQJ."%1js1PU6M29SJBX\+5YkI$YgrM[lt_CO %W\jq)WR[#5CIUJFkeNnE*EP@"#5:r/l`$QSX3$bdVUdb?D-WeLaZA%WZ1Mqr\",:Ah0H8KFH#Gsk.:pLe`Fa^,n'5,M"?jP^b6P` %(WLi4ac)VH[u5d;j08QDYZ*g^BdKLZ6aUN5h5PK[];l-P6$P-,.RIuXe*l71\)3eqs4.2l-<W(k*=9u_e;FJcil,[:Mo<e3?c"3- %4*=RFl,ZJIh\R]t'V$VD<BsWf%jD+GZUjl!A#I@>W0pSma=lC>m:Il\Eo\a]M@f](NF%5^#'Z,qnneU9erS?IEfl8qrQRht4@jup %-9E$,W2H8F<o85m;bBbJMQnnlHr;M.5(Q=4j/:f^TsrZZm;i.cEADYDdKQ1G`+o3$@PgNns3_!mD-s[mh>$o$po'X:i5kLbM!em_ %/VbX@5`(tsB$$HE/dggb-*bBW\WWs=X`ALW,-Soc%7659HL^=-+PH6b7C<<VdRsgo599XTE:g6;>.hBi?mR?<*KN*dO=\e0Ok/eF %)ApN6OU9*7p#ZY'mF2F#Z"dE4S]*hOiOom"h@7D1rq(DaqX=FFs1&'SJ+M9Ar)`p_TDtO5s1eQFs88Mhks,,(K`C>0ric@kf.Z.` %rpTj_f73Pj:]L3Z97M<,^QniX:[,?<q>C!Erg,kJoCG3B\)dSb\,YpgJ,ZA/O8o(hrKlEqDu]EIs82hYIeuW^npg8&H`(@;VgV%e %NMt<P8IRdq8=riYjAk3SqWlW(s73(4IK&UuU6V"^;jOSqFXGT^9kJ\h(m6_kLNrR:r#CiQ&7Jj.M+!4In$UK&n+tYf,7.cf#!pM% %ej0H*@O5-tY@-?[6Y'AO3>k'<2hGjuARKiT\G:o/6<sC7E]0FVcc1;9+Oa1(kE6-e9k[oecsrI<\Re#ji/XH@Lsm>WJe:J9G"JqV %XUC3K$od&Nf@6;XEg/K(oBc$>KAU+jVj/.Ji<d!;O>NA'=p'Lo:SRL58d?U'im(\8cAN'!2'3a5$R[qh=Yn0qU[[aR,Dcd3k`21? %2]m"Qlta62YZc<o3!STifD>/o+o>9S^.OfA@]iJ38b`>d$#p^OKW@`f&@Y.&C8KB)ARo^)VKoM%\%S-D5"RrN'fj=hZg!m[No>9N %f?)E+T[EIr<O-(hcg`PgAn3EsD'WkB09Sk$"',8rh4GUZ[Y2YmA,NGF5)WH3EQjUS/(Qcf\blg_;mOC*im/tBZ)jrK*hjhr)PM*J %3ZTht>PPY[ho?/cA^F?6,1O/aU`Fr*e!j-[`#$e[V$M%H0C5[T$K5]HIK*(`4_#"1oDG?CdDH[d&qIb.LeAt,L'JqeFAS+V!dCsW %B-qUg?ln1;mH!4HE0XX+9Z3Eg_te+=-K91<CP(-kKnCnPkKNk1_I0d81SBJmk6!WnhLMrfq]K>b"QA6[m.C)-$e]$%S"rlPq82;? %cdtL<:oXG(meNmod2qVT2puoB>!af'hS+pr^X04ob_&RRa%IX>En\Jj\[Jg1N8TP,ls2!!eHSprK3=91>8sL18,;6hRQK^Hi[O:j %<+hc6X43qZQmGf5e%fEq'%\C<G.VI[9^]&(^Mif+Ti6+i*YnbYrb+="S(bZa-*o3?l4^l,!)?/L5B+kp6G/bs5/IJ4_NX&A@R,Fi %[:`T%PZWej.U_D&])/T3m$T.4*9p1I4C-`a6LpL$J?C_@-lUk4,EbEYTo@8hPc2'L8=GHXkOH7UERd`9OrB&Intoopa.r5gFj9@G %O'hZeeSHQdRO6h#P)_'jk:T`NlPS*M*9'iDA:XNr)_IfU3fSUSfBMcbm+i&b%[.Prjo,+Xe%(n/08G/*P#2Fr+D;Kqo9dkY*aD:C %-n^_fM79gF5Y'kofnCeYq!Uq$9\>&26h6mO==A3_2i\Ea^&6Qs8IRH<8`RNHn@Q]AB#]i/jOLM<RlH1Df!3?ISPP!L_&2u3+PH\7 %1pBU-meZbYFWY8aFsBN)=D.&.T#];sPD=<[c[Tfm6cVOHeC<8"_./$#U%;Sus/XS<k1Xu>3It-h1sQG2/H))_.?VMZl_qp@9/o]L %\[+EK*0iZXg8(m"^\r\T3m(;%_cE:i"n=#0QkQZRN'jq<qL+,:\qh0n@.;.SRHuWZWQX8.!Q/(>dK0&XhR/.V%<HNhCjGDMhXcZm %LJ^"]F(,at.5b?m=[)/#G*;_!l-kqpqt<_<9?5=-adk9A:><Uigm]'#!p1g4lcK8n/VNsY`sHf@GG0KQq;7QOE?:kXj<(H:A7bS[ %(0<n5EO=ZLHLh0-$`g[;DRJeoih1O!EWVZuPbAN3XiZIm^/!*9([pDP#sH`U*Fo^KPkRlWcMHqoP^=lmb`<qWdPVh9l-+^3F5]+. %N`AG11:OM5Zm\Vl,i40jD]SVB4WBS"+U6R;RUO$X,DA5S%i3'(W,iVlrEIT9cjkQJ+)K3YGdEU1UKs2OJE?[o:Ks.Q`qTTuD^G[H %XG(b:jj$3#&BbGrPP^U_7#6bBB)t`e^9WbhgCR*8/:VGNDmE[L^@bK^)Xu<XJ6;1#,R8mWSW,/,Cn0\npIqg@G%R5fE@=,A`h/IC %WWXgcg'i5_@6l_YJMNNeOPQPb9XZ-2Lsc#p-@-.0Is0mDpeCGQr="'M*0GqTc^%`=n3m<eaT6<lp70,o$cLGR499W!D7V4!P%fAa %T$\,_o#VV$+1RD[FutCM>jsc&,&[L8G@;;u)""k@T$^,iVcA%'*W,[J+$/=PAMZt_bTQqLBb.!/-it^baomjFq'9"cN$:G4:6!Jh %Mk2[SUg@`@Fktb5+4Xj:2)+=4Jo&IsQt^M._u4.R:fpP'Xg1\4(,(.2L#HU6c[*b(+"A_tbIVW_@3A(2+X!NToc]sk:@CjMJIG;8 %Mtsl!(!t`_kkA5/^#Q^!+s'$3(dagH,NX,93g!-!kQ;a$A%?5$i;0[j<8W%u1H4L&*M_q+]Fi2OqH1FEXF6(dU(>b.`jJBs-2G%% %`L5'3C9?aI0,iM0'*P-mrh'LW`Pg'1H+r2ro<c#V22(/GHanEN1GNh2p>,7IjSeu\WA^>^WNBCURurh[fA/5VbB*_IXV0LUQ6[Z0 %:`bjd^*FuqXnRA.&u`8*=`/Z*GZAe#0);*QFl;o94Xk@kZ;cpDEQKV3_S'NM9H2KWbdol=a^_AaoGW/R4TejKR$bYd[%9A.GId2M %9+O&gc10@2HiRqpH)m2Z_+oS)H`uY)j?Z]tqf:+n5sJn?\fS6P(i)'dro26)]QBdBI#-[7p"$u@r+>r=[+kZZ>l^JEj0_qMB@mA? %0e2%H!'=$4K0d_-_X"eTr%>)GoqiOlOgF8DFp.K=Ocp&tFo=Y)e&@IBd`@49[%WYo6h)*/#>p"W\iFW8^)Cp,pEk:#DhPWH"..!h %m?-fN3-EU[X<,c>%u?idL6r-U9Sdr/,OE5#^U-XAI$R./8(uiJ`JD>'^h\Eb9HBj_o,C$OP$KJdf6.ZbbALV8ieZV4@sCkDZE-a> %EEFXOB1+ln@oqa]Q49,T'>K%bFO&JVA5-8%V+;5_70N9MR`F031%X%<fI#+bdKj'U:38f#O#8Y5n0N_pM4A/k:+GBu:Gli1Nf4t1 %ea&D4(5;rH-PPV,hu3&emTBS6:Ml3'Pcj>9!;-*gkK=\Sm/\HkQSCC-pabp])cJ6YPGT=$@nL#95U@dIHJ@l0_Ut&&AMYOlBpWT8 %.FbMr&+]C]1a#VOV%;0S8b1J68]s"_F*N$n]SoZ]9VDHp,T647P_Vd%W?)M6:F9(=)KuA$\-)Y?,+N:7LY!UFe36+h^P_-?p__;0 %n[B\U3K*COKS^blXHHi>Y.2JS8Ap0]"Sm=7ppC>H[<VonHg2k[F0)DNI8ilr6;P,pOE#'tZZadU`k:I[8u7ep9Gm;j*"sA$r.AFe %B8^5&RkG^Y(^mi5?9a!#T?^\J4%Jlf"KA^oUS":^]J8@j%ao3;#XQJc"7PiF%D\7Wan0MW_+2E2IImFG&/6iEpSj<"c?[<0YeU^! %&<;2Z^6uiEaX?O[BLDuCe&kM]#*s(rLoJ)P!?a\M;dJUqafKr*W!;Ot"TP9F+[b%:IeW`3Dd31egRe!TlA:^lnTFKJ=\_Adlh%#= %",LBLMTWL36'.Ija+i;J^a!a62Agn6fZ5^/i'78f([%`;pIm]k\A8$W[)HHOca#ZqBF'*nJZ8q*f!Cai)T?7Dp>Di<m3qN8n^f$d %m/pmT-_o9?:8fBZc\.2THT[gn2LEoZMpItHa+X6>*h9Bm,c^Nj!0BDu="A"]9pk.(Dub1iT/kmC6/#<T2qk9SY,u=?8].47FFZM) %\h)<a`_VV:r.^QEjZ3RilWS&<(pm:2NX-rQKGOtk$htNBA($@m^uAk;C:"bu48AXU^C(3;s'1I7&-WF+:_U<)&EgBlE/!n1LZ`C] %#[(6PTq);6*lacZiCdrFMY(*X82*tqPOD@>iD\ac.F'2S.UrI#:-uglS/Du@mVdSuo%=@V0l&X1XY]jd'S/CCKp[>Vf3u-Tl"j:D %-Vu6=*[P;EG#dc4>)\O%PPY:=(UbVZQ9dR?f@N#OoKTD?[qX<Fb-l0O:`P4[S4sE@O)X.g*?8(]+4V[X&MsP?&o*&cM2'$YE,\%f %c:2B;ebGTuGVTk]M8FONN-)8E<Anm_#$?'Ms(rE<OK3MNWrXmeH!dOm[KDU/,$2.qhbDj7ibUGD&+t)oCX0?/L&M-:j;Oer@A_kK %O<_"'Th7VUG#na0Xp\Us3;Ea?gFa>qPF5o@]QllPATc<O7(FbJbcn<g1p?tNfS:pOZQu4%2(Y>Hc`_qM`.`/0GEjL1@GVj%6]f\i %d@?T-;AQf1*hsFm<s\q`ENT7DA9lb.cM^A0G5H^Jg@`s<4?4cMn9c`*W62:-;59K]#lQ:Vk!rVg7H`$6ct4,5!eh[W'EnOr6<C#$ %DP3JV2<S)3&D!0#C?'/IinV&,U%VW4&)=Bp"BN4XL"QQEc5qL'fdB[i0G0SVnIdV[?!mQmSF?q3*Z.G-m0Ce]%`ubjU>1bBeQGmq %=HW!TKJ\SiF5uC.:)/:KHR)]^"*T"\0RU5=dUk1pftFuP&("hUgi+)8Ih/-7"_,O`LlW4da[mpnTWLYS-)it&]tn_sQrMMYN5?4( %a2:J4W2X,;@:J@=3M)1/,7,O+F&Z<I9%Rf%Vp\QC/DDEoq3g<)FC,@l?\[(nCJR`WiJ5lSl1\!n]$/3DU/YEae0@BG5/.NI`RU=I %aK@S+:9:b2`c50df$nB#1FGq*H4e?4%B6EL2*?:lC>_&<agmftFfIk&9iRM)A<&NboJf^nh8YPh*F%LCIR5I.YQM-+#XXG_+SEQ^ %'3I%(*n*a*6^FAUlqJ![)eS*]d?Th`JtI*oZ;gTingO44g5tJL1WrIbFO.m\-ap&]dE&,f0YJiH.79MmhnAd!UB)(a24"Y$Q#Rnj %#l'dK!TkH=9r;6pS_*oN6)P>dI'urCU;O$WAj-qgJdP\#Z1A'r1H7\:0,-?m5d+?2Msk;OZ,P`"!SW/4^DN=]nH"d&\Z.3;;-6oI %ohjfI(O9>,*3]J?BoOra+4c%,\\8EW7>ip")?G44Ut+3E?lSK6=dDcDIsBKRZjOO\;+\Xi)IbpI$=Jb]XLu&"?-!,0ld2Z\="8u@ %E66elL0l1!HJ&&<1eqRe3&:RfJ9n5r%]GUB8:?,#Eqi,gS<k?X)I8r.G5.TodB7"SUljC.ccM(H?hXKDm[m[r_qi4@.tfWjg^IcY %JATI;!nI[AmC`/?J/-'FZq3Sq2KB'?P>,qU@E1C-4r%V5B:i%VTtE>(hhnBb17X#QcZ7#A=\kj7N&q:;0[:(o*A%%E7q&mH*6KFq %b^$(0Y$XS$@gO.+%m@lEi3.tDDHKc*8Y[d,Q5N0'c"C/dF_hp[/OFn0ClOq]OL^esdI.jUk=Apc,EgN[_9m1XEJl?%kC[j6AXtjK %Ut]a"@kI6p8VY%MFXJJk'2IY-<o%S4+2Ag2c*kdq)e/BFEYaN+,$:DLQ:4:OSq-Ur]k]4<[F58SaZB<A.04O$63bI+<GpL.P9"$_ %5AN."m>]kLg'bER4n?YuR">JniWJ2*-^uMp2OMgEgcFgpd'ZX+73"(eW6_0>O7KYBd6J]k%A5P`(O<$iiakGdHnLr\:6I[hVc9\Y %/5?m45g<p\Z;RfnP8*5=A7Aa!.aPi.Q_g]^#G6bD5W\9Nl1Em^gOto>I\h-aUcGO<Q%s8]fS!D=>RPl$E.qo'-]OO*+f9tE1q"/f %D7nPJh\7j8C-.1Yf.2Pmh<g-8c^"I/'%6,^iN5*m>2Cd2[7g)A\1Z`WpPKu=;^E((`JN1M]k6tE_5><MAuB?Uc-E:]`&37&!/$oF %*tZ&rD$<fb/&*kRh7VZhZhH?nROo_RYr?<-&,EOR'K:Wa#2D82lQZ?d39G\WeE4?aM?8(IRHQ<\_\R5eoMV:opD,cZ9X/:San1I% %/3o%+Yp^JX>g]5\\#j!4AZQ2"q_^2qNk96;j1Y1I'T*n-4"!3rjA5ElC`[c"5H/F:qI7-8jub7(dKi^6"O@iaE2&se%TZ&a6u$7h %b)6:!V^@5+4YK,.Ag>8g!T_kl"haT"i'eW":!_D1O^SU1h]ieuOGLJe3h"UH/nmMiNb[Q.h?@ta=@8+d`I!Y"54b2"<!:-9/$!3Q %?,q$BH\>Jp+XJMXNEu.4TQb]GXeIo[0rmpA4#,n<\bVp\bfP]EjEPY],]aElR%>AlV[:QZ#S5D!BN\k+6VUKpXB4bCp@$?Wk?o!# %S6b9uA]!i/c.7h$K^2'nhIt?&;Lif/"ZB?Xg.R#og`(h$^g4Q+8N9#*:eC#b;!XT3FPS.`,Q4#d>RJ0r86>Ih:5eG-/p!f33m;sW %L-(II]N8bPS#W$+8RFBk,LF60rN\&5WjFNsh0B\+E)LnZP[*#r=2FD]as#1oHO#!XpUCl+8OoVF?((N.Qd&r<(X-%-LO<S#D!-A! %q=aDOSdE;s^VAurm+C=UHBmP%f]o,mAbOo??o%i]9aNCH8s?j_:_'*i08lkf;No@h;\S2N/E,DH$%3Qjg%$L*<=b0oDZ6HCoe]6B %>G>?XG=2_Y:K#(DaC[_4k:l0\(S.IkG6:JkpN&+Q:n$W^UXM/W-V.K-TE)=j\3rRFM6Dq*AnVf@jGQ:Do&4]mp3tf79M7]`RG_Xf %6;SR:5Bpb.)2V26]:HL[Oc0l7hE8Td>WI5p#C)P*T&5iF,kI1;R<57f=CZ`hbpWT7a3SKp6&+RHerkk7YaMr@UM;8HYUXkA3iqB5 %_ElNTgZG=k!7'_hMbt5^VP[s7c(_P<INYGlUeV2Pk$m*j6LR(po'Eh;$pqIj>?,LcaAZ2eW#:KsVl,_*]u\Hj'fZ.MQiikspP>.D %p/]WhR"Mp?*7[+&J;:F2!1a,faNEhnKRB7C'qImTOGfD-&'q!;Ce=0=_p7*)hIdmcZZE@%VW*u]GLV$e64p$a#Z$<c0p#EjFm#m2 %BrpF-=eaWqE#@c!n7:pt$-NP:FZGqjH4>)Vb'"I9W@LR_a&knNYhoh16AKXTnoocIJcMZ/,FX.9<s.CX>Y6iY;@uu9(jK_oeR0aj %e-W8-H0$).mYKC?dc,-G,hQj+e1+95/s1HRb4=^oaE_%D&e:1eB"R!sruZUV\fBCCS;TQ3hdQLD_KHck\mNZgd`?J(*9\$0m-PfT %:+/@9-t3Q$ckq]eqWUf;jiaY.)Ot]6*&PI>6deZR>1L%3WliK-QX:Z'"pok21qM"Hjh@N9\p^e+c2`iEO;\!EE0sQH0^/ks8ZF59 %UBmb8YHT8a#L,2)%bpi_6t=L2."pPk)6MW#$#M7*-6eT_UlD>c9"/8(jY_r^l<iW&W^dh+-k6LDA:S(8)fIiTd4Yu0f&0?2IM@1f %+i>-[fKT,OU3.b@s2$h-GiLXh9.H"\I0Feb<er]9GRgO>8;lqqi_3*n!(8eH.N1%[RI`6^(i&h%#o>p(ZP@XBF"6F,3WlEdo3;n0 %"R3i\4kC!Z,<XX"C6[.b,qJd[0#(Tp9qc0d!&%[7FVuch-<L=[Ddd704fZ:dS;`C,mEE0'e`9t!iQa8NH+50X(n*mIB?Q*=]S,V^ %WsJK"^L0K$D!WQJ01"E7:p:puCQDZ_8?mNjIdqH.=\Q9$/R1WJI-K.+eFQFD1g\OK1-i3C/`EEZg/\7Nk19f=+i,5Wk[apV7Gr@n %(dgmNXPo%3Gk:j`.T$g&b,E#2!09D#c5YXX5q)lVJO%m-][])s`C:>Y\'SOoGQhqN;_JHnV(cCHb6-3RLGm8q$j:4YBJ64#nn[PW %3NT]GCHG;FT'^t/a\TB-\:lP+Mn$eH!_Ft,Jf5TBgJREO<>::F"c,s?,fT/?)&pjBbI>Gl9'/&/[X\FQpkLPI32fr:KYVJN<>l\s %>Q%GulnaV>;9b8gSX'I6!:FBTp9RMSN`lspG3i6_WTW_;YVualZW+23hq)JP=^-$@0\j9Chsg%Rg1*kj-LSu'j48qG6-4V$J-$W7 %1sst\,1gV\K<hM#*jnbn(XOA5=AdFuToccL8N!mo8SD]*@,!'&2\Hi5(\+nX@pLlg^+NZ-Gi.$i-]8DB:LBXjFqH(m;ZKjr?DPF* %&(o1A/@]56KMSu*.qhVfp@4q2]ahin8X8Y+U!0$'FNXYTRa98?e.amffEDt[:Bnj^7_e18Q'jS8LF8<M[Q(2"A:S?S]<Kj_?fjOR %XZF<_(]_EURmBhh;A=+jrUUsK^jAmV0sX0dp%HOnUlpB@ANiNEil-UlI9CYJORKat5Eh-sKW#&nW2AZWg`G#C$Y5R?>N#>qLQ?=# %f>R'<0;6`78)0il<k&C3IObuBfVe@FO@q>S1Ycdb5A\^K+D!::aA!=J.kP==Bq[ZK-kjPQ!1%I&g$"Ftn5aD#r2MA$(&bB[na':k %'P<mMiFF&t<liZcBN:;uA?IO9L".053n85X)fW,5;SG'*n3]Cl9nk#)Q!iD"EQ3$Ei2MTd\`Dt7lN4XIZN[P_$/@HR-[LBIE+(Jd %Xm<VY*iAb\]]FU5d#uQM7$rb(f/Bg,)6>Wuds+^Q75bK-!*Y^N__8:AI'-qa=a"^1S^Y"o)tkKaZ1?joD*oo8g2,A%]@K0V@f6$& %N7&rX549#j&=UG&)sYXDM=`d9H'VFmACliiA`3CdE'5tE:0?.[J.49CU9tbSU!eg(+iqqE]bem6"t3NnX6H#*XjpFX:,aF<B?84L %8H\IiAg]>":P9mb7TrZA,]qG>*lSuj-qF?Y>EOF]S45&upGmhO_bO^N)?]U=GM85sGPW0u(^??3nf@=c^s^CD+3[kdGP]4fhVJrT %6jBHe'5*u/TJVKV$aAWuV7XIoJ;m[B.94-q/p'rmf(&A6#md]6.tCQ!YI1Y@6`l,t*#!8lB3dfj;)QWV#?iLS1;gc)6U@.i5Dk#8 %oSqA'9/LJ#YYu@^@RTdoolUorVeD#)D*D2+_1%:U.nA;T)5F`'8>NqY:]ZQa8:,!fD5W"^^Jtj*eXeoJ7\D$ZWU5l!L`"_JC\heR %biUjpBF]/=(S=[<1G7)+0`W[HrGq8R`9bG&q<F.Mbp7_V+p_@B3)hERoldEI"&dSaQ]r8XNQ@og/$$kW0>KaZbZZJko6=an\YRq0 %4[#l^1WtmYG7I.G3la%j%>ajdZ(MT7[*\*$a^Pf-&W?bKas>_"Fb-o?.pN\_M%HL.<pm.lX<.V9W.S87?FfTNWYuGA#t2CT2@kNC %c,F<59_Hd2FTGKU$)LrI_"3TO7ou%'+N4FZQ!-SReVn)WA4`&\0+^BhZFX3lpKldD_B0@7DB-Kpb/01/TOo;%Uq7&.B+o@7AZ.TM %`?HJp#S@ElF3t@\-&+POA4[^e:C4'bS*g%Q*8Cm>mV.iYFUV)-TM&S`\L5pf!Dr)N6GkW=1X<WL-s9b_dGA)eI^3Dc]$^UXAu5Xe %mni2AWOQB!O*:o+81h(&>m)ioJlOp9><i6Yh8Wc(Fl^Fi1mEI3>*jI%VtgiaP9<[Y&V=0::QI<a,50I^*.A2l&cm[^Sm"6fIGK^; %qFQ+.\7J>677_]M@F;T4#csu]D+&_i`iGFd!>L)3ZPS$F^hPb-M^RF'n6k:L`W4-="b\9kf2FmkH8:M/EY$\J8Chj;SAT/6Ho#5& %XKhe9cp45Ae86^DO[b=$&/m1@k@H$Y%NV/-</1+XMWK]dgu"$:8fS+-.[)ie+:+oIT<60rRfPdkllU=n(r+(^]mR)8ecDAJ?3":4 %Pidml!82C_^)3bW(1ml3gC$VMd'eNqSWt8D]R1h9#iep:%?PFf+R8.]6JI(2_OeQSE4gISiJlBJc/>ZTPKumrZPnMB(CMjXbC]Ko %\6>%1VGO'4LU&J8qdGn'3Dg.,pl)ne[D5F779e1l&M&YP>#%BhYW0E,^+Z_WAdrQ)5j&.6o>r1WIG$aHV<g;?Q-m+u`WbUIQEjOZ %"5<s(Wa6-P6'Q[!/^]gaFf#hT:%?:1<3tmV5=EkU8/\moPtBRg@#1@34V$&rPKm2ba!a\tp0?'*(7_4aP#/CKQ-q=FOjOpmSH7N! %KL=ZC0=7:)Q0A]B;kMp.6OkWZ*NTQugLB+UlB$Qu0sC+jDruO-e!EDR%?O02(-bitkRElF//1VWF<oY8e0qJ*5qa8LN7S:b,k<!_ %%>f4odQ&-U`qT12:*Cc+bV4`3!&SeI6"T76GNHF^irMf-oa?.jfTh8QKkr_SD7=_hic121=CVh.Zt@lgcrF$NY+\'<Yp1N;fV9jb %$H8`6o>Csg*2=cbZn+QW@!\O#-57uVc<rN,'T9$:["LSF0ouY-4#tO&C:\.:Jn,`WNql\K=KQ#;F?=&T3\65g.EYJ()<M+J&ZW'P %kZ07U0QGQ\=`Sb@c*VLpqYgqD036?Z&\&8!H3bl#$Go?$9Q><Qj+%_7JrMhCq^3Hk!+%Jc_a't(M4PhtIoZ+-8F0&hB^Vo=_+,1\ %,CW]3S[E(c`ji<(Q8P*5(:kg"M0r0@&<mV4L>Xtj,<@o%P1Wm7.L)7b9DLfj?&9YdPc]NO`Q]U"L?'rE$+.[8Og#\>IV=h9q+kqV %Lc"&o?HcaOXU\qZ+&UDsH^rc!7^gF8MI^!Jbm@'n/Bko!ZSR.5@\8Xj1]pFH<n.fOllMk*RCJ;+&0_jXK<Fj(nm^PqZAPn$ZoZXA %AS6*s8.]/:12*F*O_rkaoM,DF0+3bU+6g:*H$$'p[gcB=6:.N-$dqo^^B>`2%`%$4-AsZ_1L5I5^es$_U\EK4^/q3e^hr^++pK]F %"SYb%Mr"iLi+(T<lN&\J/0`P4LcR>N_(7OQ`hN.ZjDkG2C;jidi@Htt+=7(KbnKRX?^jWgob]DU?(FZiiV\S\)SoQBFl^sq<RKU; %8;-T1SjDhd2&&$!JdjD,%Udu:Pu\H6FIk%D0Y,!-5sg@\0])FO<)7lnglL.`,dKh)!LuHt5W86nTkV/"4;uJ#H(i5u)%)A-3tC?d %#'DCb'UGj+FKAuMU3:k6kRFf*C$-,W!q6_>)oX9c`g'_lb)e"+NRGj`7MoQpXS=)QJ=gHHbrfVFk>Y<d@;)6Ehk3O$8;%7&0Ekpk %!C3!@K`gaB`UfJF!$L=2XO]nR#r4!S9OU$]@UG";P<+7^311AAp)G#<eA>drET@.`>LjBYj9Vm=R[3%k!(;Kb"_BFZH/&TJ.jnY# %Eon;V8\Brm$(9#E\@B:$\%6OV3j3-&*?QgeMFKgS;>=qt`ooqu@'o)`^bo>W^uWF&PI9X/<IiWJP137`fH'V^#=TWXNb!qer[jA[ %1c:bdQ`[,C<3]k_9hqQF'184^FJ9E(4lE9V!6)J=U,2'q$E2[Un^XG_-/5hb.:%3h[/?&(2^;ci`-o_-LLFho-#,btY=4F2@bE1K %A#Y1dADB_%\DMXAd2`'nkBbR.4W[ul=t,l2ba-["T`\43o&U!gNQ/ne^/uXMDbT/=Ld8pSCf-T6/!e&oG2>#$M80cOrYBXY"U*a/ %7,FS-D"iUf[ij0O9:`l9h_CpEWR)V'X;\qo^_D;Cq1n;c6qcR)>/d29#qJ(k+`cTn]H.NT`%K9OWiHTF$Ij']!d`V8`Zp5UM7.n& %d:X8ik_BfO:S0F[Q%]/->/`9G)\TX^Vs.gsK[)7h8W)nDq*]XJdoNA44!k0(n_jU9TbJ<M#Sh2`hoh!-b;t<l,,'!)$`u.9"5Ljm %6kQA)-/@TEHpj]k6[7?45SI(r*#FS[7?LK8>mM:fK(dtih9&&F#"L$OS[.@a$t$1@e07;,)VWh<>#cm*_Z0sYHHUXh?R-1@GWGN\ %^FWFR"qT?77qJl(N0'mC'X>6?KWG_mga--h\C"]&)4#aC+9*?.X[USSi!$\_'J[j71CN1$Zb(;L>qQD52//ea8I3?DjY.3XYRjI] %&S[32+pJ2m-b`QI@4%\bD(GEX>'I+r1=?<<B$_92AY@g>/*3"i<.K`Bo%"<*;jJ6$)N%'1a>`)e=B:K\,$ZlZ>TIk2M+B=0W(6dT %pT^=sNt53[mmbmj(750dpaqcfJ-83h3!g&FU(mAbmNs1ra`).u[&>:;DJDIme+_h6AePVUr_Y(2N'cDHqM/C#L!WF_Q;q_%0cVq[ %VTrLk`)RA16UO9n;r+@OW>7qM0aGJEG=SH$[`f*mmK,1_!\1T1JDIjCmOIj$&J,jp$PMi(#Xq%!Torfa\/MNX)`.ZIB7O>_N9KE; %<lSen8%JkH]l^C13r/SN'1Kd7R!:*Nm2gs"N;#kD/V>r(bod2DIorT!8/WA\5N/lWr`cN7&MNJ,$ms/)1n\Iba'Z'TUbaW-&p@5* %19s6#&K!F'639VKj$)7F9O]iSm]D9LS.G@DJ%dWk]uIH/)Y)ftNA2.54%_0?,8f@?`S?)#-Ac=e%`IDY]:2&4#*IgPUg['KET0q? %J48=I4M=btUs*(T[;5qrOGm*Y0l<Ka#WEKMs);;.,kBg-coXV^>(IaA5,\RV9,mLr%3RO[L.A`h.9E0;Bi(juKg3'6a\3q*AA^E4 %J=3)@2+eT=1a5PIj-%`63!_]I2D\\hk.sk&C9esnl_b:E<D'KC-=JFS=]l:o'K&Bib#pG4rEMi-:016@;3)'s,S'fkSJ^3R1)QQ/ %:p*fWR[],II4X_UV/_P"&]0B]e*D(sP$<eS38ORLo>Ml@Y$oLhLc^u>!+L/YcVZH!gTB-12EL>^Ano3XLaP?)102d-'*,d-Q(fHF %b3.ZiMIT"+3HiU<&Vec=4V_DeLP*B_BObV(,)a,t)4`#=l5:KS].GWXkkHR>R4!8_>6*g*LW)A,14YG\Z(PWTKVnLb4Lfu*%8ABU %@a%JYP53kG\NYcI^\8"Pm+LfdN+[cWk(9;f],?Ap6de%MPB-f5(m5D*\n`^\K[%@RaJEd"1*L:*$QP?bHe0`BhR]gfM@m35Z`ckT %QFhp)SD*2Wj65O=+\&Y`G#,.]cTm2=_$O:K.YEM)c#90c'<h^LRQ^Qp31.r%*(<VnCPXi-;P[4/,'$kU;^@t\6?m-3GV2bDp#Xu6 %#jW,f]D$C1ILr@K2?*dM"ekeom$>MU1c.E^;EmgWkB-S<(qa%JV+?^F>/dF).L*1P`?GWm).ffh2C_V-?@)5<rRHG$PMY`d"FcG= %p$$htW_Z*k<n<;;;2Y:Lq"1.[:P@2DK01?d5ot3TB9ntfKFYo`YNI**<d[G"c1p(EO]m2XThhtO,E<0\/HCU\$7U>sj0QLW0/uB[ %3fO%b@*csQo]Ba`1KPs6>AbK[*C?OZ\E-IrXs:IabI8Ap5dH,$9oK<;S7ZQ0^4c?q[#,ScD6cncg-.'`7_BaL[5-H+T"#nH8bE5k %:,-d31)uAseK/]MP-C0fp2pQr:qN8FDg/Rs95-G=AH.16DV3*K%Zm`>i/F&I9[G,!JJso/P]0?/5.HCc"<sTdS1d0lln/T<?7+V. %`#6U'/9Jlakb]7u7p4)fJ.i+*4g%>RM^DT:4<^j@F+YkdfcCIa2N)+.D2*nl#:nfXkinq@Fd)_m>LR_4/<58"iN/2NqLu7?#79F= %)EKenQQR2cIoPDJ>-]4DUTSU.a]*uD-gb!)#Z%s\agc-m:>-:51!h2^TT*<`+i@#`DkFgtK>i0\nnjP\1u'B9T%0`u#b`N!YWM"M %JGdUp'TYp^M/g).@p@DN'L[d[8Ke$(6&q:T%g,<i4Fh3$&!\#Y`XcjHY-@Ph5k2'+a3PC"@.WtU-pm+#afs1Nde_Be'W3rI6Q(\T %PT/`;?BM;B/9GHh:lq&d>;Hus#u1"ak#kcPm6c+)'G*%G-,Z`oLXO&h^d:!OSm6sT\3pi3\>t?s=pc<Jb*<_F!?#t+TYX\)b0b-i %WD?1LBJuAp#7cGbHk&CW-.A`+<[0h6#!`Q[Zk/E00i(ZT:9uG'mQi5a;=R1S$:GS@5hL.k3BifGDicY]lSdkbomMD31URVqi.Q^k %:^l'5VVhilH4>]L'SiL0G]-SV&2Z(9UamcL/1eFL@mLAqQF`%/)dn(m:U3STd@+bD;V$Jh0ne@*69lr];f8Lmp>dB%?ms+=CZ^ln %J3H6o3<4SD!;r&oJH]tRp[hWl2+]]K[fNN9C=jm^5ZA/ennc&DlRBXFi]/A(+:*V'D@H[U`dn$)puDCVf.t=BShrJ\"YZ&kfVYrj %4hnWEm0teKI+3GhCR&16Sj$RG5oJI1!P/k[!WissPfi5'd(4JAcQft,URo8Q'3Cm'qum&ciVk>Q2CIG1K(1W$6>:OX(b`[`OKJLq %AqLt:\8ct+J.b-:aAm;3+>WD`QiUCO5X3hNC""\m4Dm$7`>_Q(91A-cH-[$ib@RVt6t!t@XP[P9,7%b5TaCSZ:_m52YI#=D)IcW" %H%mK$`ceI92F<]&WVU@oVP@<rZ6[gP5jduj;bg?:0Ei$j``UJdekR&+lupZ.7hWi/eM&mHB+dJ*>,L-N0=Zg@cddPigD19ITOnJ` %QgeaqI^!F8qCDaU\::qbE/JoaA>1+3?IR;q):+2W3+W)afaS]'O@imnHK:*gnOT"^PR8!/B#l-%QU<9'VA6(\0=ta',f.O_-&N8Q %.[9SMhM.St')$%<N5m@A-eV'h2S(F\'*dC!]t?`EP70Sr&WeGFi>-&4kfTDg1bR@Q!T[*'eFLRpG[;S6BeXhbNlM.[MZT`MAhKhY %@EtPVQuI$On!h-##&[C*:8,`id$9D9&.*!Y(44I*Dai\GdW0&iQkjoY0[@rNR+*i]<O</gZ!K_JJ8I^jd'X@rmB?ddkckdJdjW'" %$3ic]$5-rd0nI8)L#d6.bZ\Tk7t=hQ^(ehj-ENJ_3s^J:7BG3e!e<?Z"I"[VrC1&fbmR?J;$*0^]gAt)`h1Xq7A8\Yh.4Zsr>#u? %P@r=eP1U*cZlgqMLH'ceY^@'ecEM%QKM>?+0UkL+@lBM@4>Ej=ReF09@nSS0AQ8!T&<")XL,Y'9I4.^I=[MCoYF/%'FumlKb8oi; %krO/&'U-l\YcI"_RZlu<Rs^q/l52c\EMD^?YbW)bCU'1^ft;bP^f]bc)'62(Nm9LWqQJoK;/?\>Yu&7DJ9iV:=-q&+6bpP=KhUf3 %5>*0`L5+U4!f6o8WNL/*K[*A0+C8oMR[L^I6jPiT@Qk"DV02"^E<o8Y@kn-Fjb5;r":08cd8g"@S"HB,>'bc$@[6\h]3aA(*MBjJ %5rD]F<u=);D0(6adE9N:$RPs$kMh_B2f[+H[-*fNRUTJfpYZI?I>Ketdj!#2mC54;Y'og`5lsDM-=ps@6CMs>TVhjU0'c%n##RFQ %`TIl-1NO$S$"jC;H(h%3q[L%BX>Q]CCu^(@Q&q(J/#HI!N\nlD[HZ"oOqbo9GDi\<49:cL)ecJY*!eTM&pcB0C/NP5UD%WY2on<0 %E[3_I'7c#I3>Q*<+n!>-EMfH*4Ga([at(,e)2(s0H_<879<GtimJbdP$[r/0'-RM7"(;`[O=JI`LB1#V`T7n\,]gN[5m=o0L_2.< %$$<-]Ym#WGZ-B(9=Iq*'8IUtugE9ReVuf$GgR<e&"@I")Cec)lU88^M9$6;!Y6SX-r@P<Oh28G*%0MtMJI@D#c5F\N<GbI)]UX%W %UPYlqMg5N2:Dl\ZBAdXS9-AgUF[3+H#u?Kp`V)&6H((kQRRPSU^l?GMU?WbF"9VjaI=^?%S&%j`cB`LeJ->a!m6[d0S459V639G^ %(N%o<$rE)fVDJiMfat2cj\2Ua6aUm=bT>[f:24tg/%_R(84,oV]tR$Njtn0N(cRkXZ#IaLDTu:)!-p+aM3g(I"14mTG-Z9!9Ju]T %kHuVA#9`sVL'TT6R#h::>*.jke]dPo&]P=RBoTEfnXSYD'URN_H/`5)3ET!dePI(\PQ`$A'SlMDj`!RBSUm>5-sl$RfS3)kra`.+ %@(?mTY_/JUdru'6PasfWe>:J9TMW&CJqPl3dH85=m$4i]89DiU0]154CL,Y42F@\,0F"2[Qc7UZ(-!8N)E/0p34Q"45XMde=Fo0+ %hN7JScF-r`?mY!0Ba#pN)4)<%g"QPbX.)DXjUWQ:c>:7/+Dc'.]q*%M'.A#2o@^(W'Od)ml()FrNg8JfXDMPjlPUA^1Y3u.bg'R% %i=$[p17W=*##do)BI9IGYe#!%6tEMmW.tVNAr@BP#5IT=/\qFKHt9):e&;cc1coIjSgEhPI,$N<3*0S_dSrsg<mfS44_2Xm6stkj %3*pmP?s"]-W+)Xi#`F\>IaQU4OhpHHC0:>AW$OchhUs@h>!`H`Y[4?t_u85ZLd1!/iO\:-k$Tft)UGq,>CaTICU=Y$1&-!b[0WfZ %6t3Q"MY26<@Bf*FYjR@Pl&4U=AH7H0i,,6UT,R)J9H(8aUA'Dl3tp)d!4:2EYnL7$HU0?=P8#LJ(*1KIV6ELc=C%@b@6_@(,u&Vq %iibWn__r<&/V7WmH<sd6r?UtP$ie3@C[s#N/k3WDm0NlpKbiWhQ`&(r>mhlb$Ku4jf7os8OO2+21LK]Y/I+b3g0(tn63Ms()\eli %(3U))R#90hXF'grFBDdKL(W9>Mo.YoK9!Bo^t9H@9-uEsQ'5()#b/aAQhoD/0KR[[?CS2X$&$Q%"p<r70s7+I\X=q875`R;d9\@O %L1L?WZ^>fl67cl+Qr"E*)kgITV.)ShkfO/6aMtHg]o+S0SOb]YBKB&On^R9:=Hodf(H3h\Km@7C_Lgn-b3Vn@eu)fco/62Ub0l]A %H<PE<?JhiF?8imU)XB`36'$!p!RFIpi*:jrKXuSFNCkp)(_%%-nZca-QQt,u<J-U,lN*:c1p9<t$qdk/:OiIRVAALJ8HWX*VhdEZ %ZI.O480o)W-s"f0D_YD/Y.W>q,^!"i#I++hFnbL8iI,q*c<kkg!Kr.@b<f!!SQK^knptq`@\bC7-DcL*=A_pgTB>DNqO`oIP%4rW %\:ZAsI]ce!:3@J7M]>R%Ahjd1@Nh*)^3TX"JohjaN(;osl,_2""%DfAncStFC2u4\VG:[\Hl0;Y1&``k&.>6#KeO9ER^V"MGh?iU %)!Cg0mp6]oQ>C6));(^uLIMq2%n3'T2<S#i5@*S!G*dMT,qli;Fos8J$CZic2A'C),#_IJ8Y.ONS-Y2350O]<P\/RkCeIj\00h]( %PVe?e_KC'ORB$TZl;f0P.K^AXH59.YP\b?F)8N!JQ<3;5!+9js`hl)I+0.1dK)8K!_`mr2Q=<<[Z1_Y'XLh]MTgC"G0Y50gWEH%s %[b<Fpmnuq.&%eX3HP9SOlGAe?X4?eX#'?E9e>f`q$WJW8.$criN_iB1YhP8T=;2n(8D&&bB2&\q-pb+?"nZX'.ndW[BWW-36YUR3 %c*)jDmN$HUqUdAaN*o^im=6(<fsi%3C)aSCe1Y5N7gZ>LeN>Vm,Yl_Y"iM^`/QOp<+4QouQB>d+Wa`_#P;:q!'Au9#kU*"rC52"f %QBX&>_2.uXK:an2^84K?+k\p/,u)[!rUS[nC&!t0$=U%g1\Dtkr[i!4JT4s\'J+!DP((Uj2!c8%f1nDGU&#pm"e,a=3Rf+Wg@H)L %(qQCV6+pY+cs[W(8m*RY3"N['1;jF?P-(BcblO1?a<W[i">P3$Xa&17/$nNDT`47F3l%/O#0[**3,SHSRbHa/UOL:ihN%l`7@MS] %0LZs5n>rWG8<n"!gclSqP&o.[r`Sni6*n1>8ms>k)ShXIifheu'fL]=Ja0>m.16MYFfWhpd+"4^[ha%&ag+;&f*S^7kscmVi2CM, %?4^:7,)J9ckh:nbH-i3\SWmA^[$M%s1rOqsn]FPqd.ti0=hSr].[FtUe3Yt#q&/;n?nnA:MhT-giFo7t&Qd^h1,Dm9N'Y,]l+Eb5 %6[PC/988^cOK+&sP?BQi@#=#$444b!%USH0POJRLW>'YVUNNB&Hb:hL9Ja]j")ouSg-,s1<b@RtJUhldg=1Y1c(LkZ@04$kc^rD8 %3*+4`VGIJQ9/%*2(?ulRn7^oH-(.8*D"aJKYqt]?/+)PC`F@d?n\"+Q1-B3Eiig97AG7To?X8eQel%^5HF"Q&PM9d?T-Ds"'dao0 %$9MZ6eEkE@dBFYs/I1B5<=Hb,,,J'H!ubAh_PKV5%N.u%O]tc&]_p3RG:6]cB5KgQ%M8D81h)4^.OIcI<j5^PSqKE":2kedDJZa` %/c+4&8hmr8eR[=T@M&K!)`/;G,3kiW*$(f?TPH-H?tu0[XBL]To'\G-qGMKeiQZ/DJ5.hHC/pedjpjr*?CB.SlEk<_@[c[c&Y@V' %r^?Xmih[EKSoLscH1GWMBJR0c*B"<5-H76T:>B3)]<C8dOuu=mqQs^9'Ib]T!3RR-NM<kMN,#[)6qN)u@$h7_Wd^FnPt6a=(\0e* %As9<!"kM0iaa0@NluL?_&l2=CFjQ0DZG@.^gfW<eH"O\D"i?qk58#;.(`"]fNJoV3c%!tG:(1g$=r%L'5m]:H/KW*l/!0o?4ZmMi %%lH!CZV,B0,#iOX&]E\07A>p6$[LCt))$0)Ap$,2Xl42(A+n&+>O-=pbR!DD,87%m.j>DYNk"4+^^Q'2$]372%I4QS.CqE@JX?56 %,jZ;hZ2T(!)8+3BP@X,r[]SFgj`QE3cOOD@K8eHJP.9'\D4H[f&pgALB5^W3/3_B3%=6N=YgEbHV(6C-b\B!&6Cr$7<qImq[Q&7B %FMm9TY#+PaTH4jL\:0m1]t.WO;44'h1!Va8pTqZOLC;Kn-JL_]1;F%*M_tkgC(Mnl5eqq4dEL22"i<hA(<naUWs-TP$>n1g9ndmg %DN\LcE"28,*s2T^iLu&/)[*IQCkE[d(u8',W"Zb$"?"p'ag=1I<[9T]'REP5^XV9:N>Cr\Ms@NpQsKb0hkCDai`n0h*!W6t&1M7G %O37O>C7TITBPK_nB2KPY\bOl<@)]&)?Kl&gRl9?YmAM8iGg`RKk;q\>M2;\)N!^[Sg,0<;m+:)Ekj3Z5U89'pLfZLXOh&R8.[/5b %Pkd16LS][rbghNDNFi?+1ot,`!6:p>EsnuK@a!R!W$Y@k$+r!o0[L:\YAr-&E.P]"&Nc6T[qPQ(AG",'"3h/bg06ZRVMdj)*IGd# %^&VCbKPHlr_+<EMYZV]Z(\U&][qZP_9V^.#6&HFUZ0q>2C>S>cjuQ,-gVI8lMpVVn%\?I&Tr:n[eT`@b&2-7+CW922JmNToB0\=N %pbC\VW/`j15)dZ2<2\q-YY$2u/t,F+KYc:\Mh:hq[]#ORD2;3'enP?@Vc@0A^'2Q1[$Ito!2'Wck:uce4b9*rop0<gW@0Rf"t+%+ %lX*KC:9msh'idM;%\:*:Z+?pp<WJuD@P`-gKTg,]g'jIc+ljkGK[]!r;OjrZ[d1AuP>/<`EOqcB37d`^G1[tp'Z[$=Y@W+m.@BAR %cs?guW\k/YX^"F-339sO;(`$&%s]8R#3aOf<qa_%E1B&8%/gtLfH8dH`GW&&K<,ja4E9n6;32A![TV4QLYQ&BbM1QGW!6c!eOgY] %/.a.(QA2HsE])?+7"oMmPr$%;;2@`)5hc)<TboCWB!HqYb%,aX!+8Vo0DG,[,,,k>`rHOAR%Qfl)QM(3W0j8+BA!?A7]dnmibXC3 %4!0AWpBUq=NP&d'T.&dd5tQ^U'nrj!%P8T=)o]od`nO+O[%(AA>-`W%H'nfphbq'4r&"<l"k[S36+(!n=R$N!%#-`uP!V<o$u#o; %'6oga2\q3/$+nBVk)0l-5aE4hBJbYo-%r[%#JGe@@>E:MYSK=Deo[@PU.Eo`\$`u6>'cF2G1\"F6g##-UJo9;%Up&SgEf"e.4\b_ %^9=Ne)+4JeQ)MW6"?5h;5b&sQE?X&\1d;!OW2kc<[ldZ1;'&MZ?HqGmY^mTorIV*gFqIp'.F4:udF].S?M4hs0^!7@C2kR[Z50gi %rTZu:A7=7I@16"ZPKQoW+cphZ2Il=j+d7-9Db5m17u<M;O?'j*!;a`*9+`rKVM"G.@sU/&@h:r>VIG<>ma^Q+J3TM*(dg>'RPKCP %T&1slgdaj\Znf?>UY]M]B1;'K7sbO)_1L4RW&X.UYjc%"qZsD:P2\Fm*=CAX$qBRcZPq7C&lIKcUDo3Vecl+>MA@k*6B<6U['br& %MD:PM)^fXlUc+$Bn!s#caR>U>80I2Nm/b4E_JiSX,#HT!7;]?M=k9.5`#Y<LFP0&ZX0B;dVn3:O"\Fr@CFqO<.+"n+7^jUo44bfX %$>8,9W1kK_IE%l;bb#/nOm4/;SD:E2ZGGF3gl-6`&`nk4)B8Df8k$<:$"\WFb7;$&Vb.sH<-+MOfN=E$]%+f@1-i0tdl;,C\-3=B %+a@/]3\*:m@Tp3gZEbSe,"LnE+;Z4((F;A!qb[l"qd0h6&dC0MK:TW=5fG$?5n)oWgk4O]MTJHnPL7@g[![L/gIh->)%FB_3[ks; %2pQFa1/jij3R]P^`3kq/5fMC(UIF3*0cEX*_TtYKbp:5]OY"eR6'SJ*$!5s!",^^V';&ogBjnWF.Q&`"LN\O8RU9h3`5^O<f14/) %-qb'WB6@$ZD;bR*@B^03T;BatMEH+`5J+Ns/#aef_`J:\_1D@l.N0$Q`)k>GPp=@T8N)p/!a33[DNdB2Eop,$kg?=g<$H\Q=B]YM %Hn[rk=:-^kf9h];Bl;K`6\beslr+QXop3Gr'R/@aggC9i,]%-%"=&d.BVnJZdV'KrP(Nl^:*EA?&EN`o`5,Sl"u+#=,>k28'ot?t %HOpsFg*st"`@teX0j"b/U6S"V2,6Sq`*$]gI8I27[Dsm50.-=Je536N;VD-7[Edj)&N5t"2i&Kq>;*\tG+_EqUcLgHLeAC+p!C1P %%fM.pKS:^s&10[[RjrHlo';Ai9;k*O?+ol@!Vj#%A_9TDE:\uB-%uR"FmS=I1Jm)88l-'d7["IuL3QV_.RK]d^BRHaWKAk:(uo4k %[9D%L,5"h])tDYhj<A"5R*Z^=UX"2Y@Y(K#E"ntb41sX$:Okqck!g&Y:qVOm+rt0W-jr3?4XFjJ-q%4lq)fWuq8kT>A%3hB9O=d0 %)P"9KUh"(-!Nofkd6ph[&E;cLam?TJ2-;^RK"i/JmGS3)fZ`9<.4tc[K,%lE8;[KdS2Y3+W(K\pl.T9u-]':J)3De,mCE[,]l!^r %9T49I"454ui#6'cM(.D0V%Ri[9J*g<%E2FUf*P<AR7tM/GU`<!K'c-[.,=]FS_"'N7;30%(+PK_c92*o9W1E:JS=UB,f>A0k^\4a %1([&`MCN/BE;=.3J!!bODmmjs[!6$DO"jec;cqe*1j#QAYu*#jK]$tL+K%\7%q;^n2AE+UU"X-"B64Lc9u3=H=kIbi'\8*UV7YT8 %k'e)J,+\II!r@mC>jCV,0Y`@P)g;G8.\OO[CP^bc`927>+K%F,V-j5YP^ZG^74E=o/IN&Z`M]27i\[Z#m^MSHH0`W37r]08nZ0gL %3L4,WaQPY%b8N&f0FoZ(B8)mhKh0I%ZCK+T=%d#eW0W?a[@=.>W\`#g-5CmsnXnPS<%MK/[rJtcDn/PB=j,!)"A]RS8\,].[h,=/ %kas[faka&9C'?J_MTRI-$hmuD3K`tJVW/E?A'f^dWAl+doU1a\Wk$1/d`gI*MEquN`ZZNB=%_C3bMST(;_IBiVb5M1>(+p0cV-[e %YMad7DcS?F[rNIKPm8<039uk1(8\nIaWnAWH0Iu+\L&^R-R>>;$+fD*A*?OlQTYnZ'Gdmb8#]Zc/NO5]$^a(=0m!s-DpjJ&F_eNZ %"/rHW8^n>:U70T]An^'.7"VFU'mi^o=NOXB,R&Pc!*UmE(!G2$R\$QFN+-et1GZ!9C9aLh;Kg<cNln&*Uh=eKd>uh<oZU@0^3gia %*/a@.#D`@3V_%U.VNi>a<\heHHpntp;1;#q]i8hV;K>rW[T%p7c*B>2\>'[A-%+[!.=6=3^:e,paXcB'03*i5KN$P)@80+/,K_\* %qs*ad\t-+u\C1$P@4)KAKEe%a_FtKH8&3!7Z#\4NauV9_kM]%__l5=fM>i(1@h#O"V8+[c1[IS5n`EgWN_Dd)9+6AjC0%E0#]N@= %e2SshWYeo=BP*7U(j=/i9hc!G'#iG`SItK_pMs]D7hHo%KSn:5&(u7k&qW8']ta@K[/4lnDKl6OS-l#u+Rj,Ge$ZDQ82YGsU2$(W %6u!+*)Mg(&+RYSRJY3ZD(6j<-]ckNW'b=_(Hq74g*!9S;i`(&NVA,0j_:Yt:Tp!Q>_#^&%,U@$_*&E]'!p.)E$KUIV<YV&EK8_`$ %b8<!boL+g*WBdD<:r171BSe.V:g]V;:hLr,9CfM@=r:-p:b2D62.VrgB\'';.i`;obcc:-/m4CgROmt(E##"KlF;[3c;\,'f1^,C %>,B%eCC90l]&i8Ei_5&s660DjiqPtJ(lj:;!$HE)5s7.MF+]_m3[sLY$m;(e>_L(*r*eT?9#,FQU,XY!Sr2!<Ha_t0"XnA>1,=_$ %ob"]>\=mVg&W#Klj<GWp`sEhaX[2WeRX:]AX5+Ai6T<t&V3;64!A&+`J7<4?OCs2L7Pp$[OKA=>@@oWa$s9E\p(hL4mi?X/@LdU. %.7dT$PK51NPhol"(Au'c26=clk5655n7GHB.oE(n,)$$h!$T2Jd9J.--PXr`YF4T-)q)CQe0cVp6*%5oZH-1_Pmu).5u3LkqD"t> %UJ)6#XFSMqc8.F_\V4Z.lRt9#g1lF1(2m#lWlC.K6eY/=C9+&C<O&Ec`E5FL"B^i$QGbFnqOoakFU@>[TiC2+>>o9!)BEBIL6&-^ %!.0?P.8c7adCHr8gMu'eeL?Os(fO1FZrdC1_pi'rZ)./O,];pYgL9ujX'1u\"n^eSNE>)+ONjoD,gmS,$F=_lf<sn#(;D]GV>uB@ %_eGNqe'.lFN);Mkd:th)U[$0prlHi@$Ct#Qbu>6m;3*mg%,/reX:S[(KLj+WOL&=#'rm#0>8GT2&1_.OHcJZdPW70_[L((6#G<3K %nT)-mQLAgfr>bbgn!;V-s.-4]-,s1=i2@*7.FKXWF34o*ZZN&mAikU6=;I1dqN5$B/et"`LWL8Ag1S7MU1rTPm:PH/Zr71m@]>/L %VZhN;<h&lZ&s7n-TrIuXAMZPb=ca%g!)t=PKP82A"j9ck;R8*L^1U?mY7je?Y<\LE;E(O6]r_uj!/C9jQ/eOYWcH3]PAa8$$7?`b %Fgbd4;SAAZ\.dg9Q_"aKcL-S.\ZYJ6XIX`73*NE%@AH='!OacOU:l:lJ.;iI<DL^ei+TBC"kq9hI7?Q*7OiDP#V"E,61!Ui0\#N@ %A#(#jM,DYeekY+MP\&7rPqh]%[C-n8ETPh@<1V]2Q.KWu#?dJeGR!7#aOe[k;kn3-i>1FsLsg>/iEk<lZ!q&O]r#=dA!DNjS5Sk\ %d<PFS3iYh8R[Y"h8\W@40)DD2MHEWM</u8k>EeS02"mU^^mTK_8rpU2f(Q9g"tic,l@($c8C=n?SggQV2-9K,!B4.BU@AuIT8\L\ %$c+8d<T6[_T7=:?e,o'4PTK$RV%o1?=I1hlTg9Iu-okO%OXf<^]^:9)Zr?LX)O(]/HDoJ,3BneTVda*Z/jf8&X'H`5c]hj,Y&+oa %0Pu?Zp_.GD@eoS"-2)Q"3As%Wka:T9LS64eB4l(db$&3M[2J>TGu@-//6P@^TGcb*=0OUS`mC;9#n\7KC+/CkL-nJch5VBMT=Vm[ %/6TMrPJ&S-RB-Kk0emKI/0P/cRP9#TQjCo3bmTj$e'N68U['e."YK!ikcfK7FgDk>%/$X'0r;rKR,J]^n8aT:jY5$u#rPN(eb\2\ %KQhN\qLXm`\/%?VlP9IIGL4X4b2k1IQ)ljX`)L*KO0-$E0<!3V6+F3r<]4eeE.cRtU8igD8)Y[I'fF`JEM>OHFcE+]2)bB"G1`fd %[d'A7qt#rP]PYhVU)_8FAN`@#mkk7bXZ2>qFQ,C&Lg##2-7k1J`85'@!_AL$Kd2e8H4WZFS2W`M95oR4q@[n4QIZ6kOOm+')U5Y: %]C9k'L6Wi^E3<=]#j(U0XQ(n.)&T)^XuKN13C]t5*`d<?^he^Da>?R%'"Du'ntuU8msq&?V:EX?i9&V5U-&`OLkJuWH'f_pAe78C %QCE0<ZnK%i>\amAer2N$+1e^[gN0ZJUe%h:/,(4XJ'"Z'M2F4>,ca@mr#h]AF4ETGZEV:Ui(SVn?=Cs12tpM,8(:a@6?(8@iW+r@ %j(MrE*[]c6")JBGi$D(IaHfZpMH=7A8g6fi$WA%15,0Vq!/#E:Z5dEUX%aq5#oWOc'e8S!FJTRi"_f#e,ToO(Xu8#[Z>-I@eEKD: %GfhSCG@#k(r*ml"kB8^\jiQLi"1WksQ#-*OBt@`2LbZ3SC.&$=/Jd2D>B$Y!pkXp?eJ`kcEntKl5.$(eZ(8AYfip'!8$)HeQMspW %i">utX08eY.s]'cg#D@7onjf1TXO]#O*G5?4h(ji3BCNon'F&ekTJ8tM7:'jW(g:R!USI:;aDjmI6\YM#t'A/[I)K!HGFD]MB=je %\"3"m9n>gYL92fB<b#[@h6PSLfkq3]@Q83^ZF602O-jh>c+L._i?QA&<^ZJ.CqadEMB=RG\(TJ>NUfRJparrR<i=k1#@aa?Z-=fP %U2h>UcW_.[,>-k8Gq6-Z+4/bDMj9^(ajokNTssmQ><VR0?MloCJqh>gT!-a"EZ^mlO.=p.:\_'C^fJ)+&K>5L3V&!^ZH^DBC(G0j %S0"r@[T[3GD7<%%]WF*N<pOb;V7Fi!h/9oD1NU%Z_qQa*8$)'Z(AV"cr@pB`X&#tMHe@b"AG"=14t,-;TeH/8:n4cWP.G&>XV&ra %/t.5hHAThQEorHdU&<$`h'0k8VN*C`$r\J!5QP1rI4A\:pL<+oclhfr:>2@q<rg&AjF1]7T'[9bfPd):MqY1%^7gZYE-DY4$d%sR %"W\tZ:c@BN/6FVND9dfq@6m0%O"lW(;I;p[';V,F#D4'JiPIY-^bBE+@C>*P>+Fe/9GZQ`73kjFUbEJS?&5^K.?b.Kc6Hdg2/-`1 %ekt[;("@qI?dWTkL]^U:!O"m?)m(c<bg>84'Pqn6[^[66_A%F?4C"E9+h^5L$38m]Kp,*%k;\SR#mAV!,F0YRS@$$U+h0N\LE`]F %lEu<[W>_mIOpIB[qJ_H'3[A2d8JT?6p0`F$7c:fM6unV\bs>"*/u]ENP!WIhToodur2Gs8B)cSe#iuQjOhg?*\P$Dc:IZnj>uJ06 %3\N2^U1>\!WnKW?oLC7T&pd/,5\(-jTJe#4C4c4+kU(k%A?/_W"qeAq=]rPmFSnS>.0)j&$[U/Q]\1f07p-i1g:KnDJ=LVW;Ga30 %@31OR=J8p*g.!9<:bFZSf!>6(2d&tF&t`($khPIYls1-'1iA4@%8!E'kenM:*pF5OkU&e/)<Asr)/_`5M6S3]s-llE6t]%hC^:9q %AH6=5ckF;3D*25)Hcbl89$cAq`?fFH=K.h@f0lHPOB%r1jeTl/N67[8r!l&]C$Eia,XnN;MCK>K2-d0BarU;fYVLiq![>dkd-N'C %WVL;)ndi5"`a5;-rHh-G5gCqgn.A[27B:<-^tU^=,>.os"(:FlZ1V5PH3A(JXL93egCM,;VrdW)Fo*?[k]+</BQpbb=Y,AN&dk:p %Kun.``bU0[nA]-NZ3R=p);:E&'Y^]dN0k*.nd69i%B"R)G4b\UP>7f,Zi^Hb*9pEh6TS/We5E2+,m'l\-Z-uB,TV8C[qsl&gU?#b %gNEDEhPp]";&G?BQ`Y"9S''HbhR4rO8!N-orOP]85GGNaQ(QR9eX7h\Y9^`o2Od\pn;+&i,JlS%?B7>eJ6-jf"'W#c#%5_/FLtLV %W&E*9gmYPabVgUqZ-='<C,^"=YdRYD;n`!`@-1@*2FY.0&I<!FWqJ6t85MB&k%SkmBVRDH5V5ln@@^_o<#u5N:C8qUU?nBbDD;o_ %bj#N(CYZ**=#-Y37]0uF<i2qoJVK747)Gl\<g/!84DsV5Z6nfp%,,(I6s5`+GmhH=V'IV)$RfaG$Z*rsZ_'s@+K3:8BJ0F\OeZ?s %ZODp!3mUEN3<Z+'9&,5,/4-K<TGCSQR'j>=0.AU@$TH?H[568W=s8Dji6".8LJ%S%m&2CV?j':Mj,%D6LPsY]k/l"=YpTj1E<1B< %cqD\13i0JH&BHi,M`3g2,.&0$ZD=J.ZBPsd7L!!).F'Q53,apdWhg9N2LVB(0s$BaYk[_1cj\MekXC_XV/CbQ<\&*h7C^lkI)O=c %As7,??6?Fo[p$c*mH<l6p/\5AS,*&^V>nmmf]k[`k%ef+9-3p_gDq<.m*nagBHckL/.C64jIpbNcsc4#4^;NLnU+k5DHXQ3/G#uJ %@b^$jA>=#!PZtWcp8u&//SnK2O!pL"MJ9*uHUQ[i5RaW5nDr(tB#ILS2b'9;,(ju^juO$).$[,@+DHZ56[PS[>L9p`>0?p25&+m] %"R[l>^1`_>Lq8p]9PA8K0\uA+9cu4pXu@[IMWfoql6]95U>1q`(`-&KWAY6/d7[N";fT`%BDk_!fPrKH;UP:l<Z29mSm6h6j`,AP %Y6l!Hh@B'YpQ7<%NI,*JCSjOR)T,7b=E&"@QbsM7PpbQ:+Uo2']IGLL:!l!(dJ9rSG7-YK/YkR.1*R"84X%%cfEi@=MY!Jl4E#<J %(9Ie_ntRCNPnu\8Y:#O6E]Xi/`^0d.YHD"AL)TH-G,]d#Tgg02>M+*)]r[6[RmooPI"Sc2CZ7KXQc^mki\`8%(CJ8r33EKkb](0d %8=9@OBVEdu$(<,>-9Om9CQ<MFD_'UqRkO-FD>?XYXX4mCQJnI?5HK"!AN$H\hCiU]H?j$u@aluoh(5G(DYFiO<@S\[NDYbP+:MF5 %/@</7WFu`VA]EkJ;$Vu0kfP"rrRpE@pJrN^a:ZH?m/u`nT.-i#e2UeRr=HSmoKdItLIQ2[QpKp9ce<,i+b3FCd>7Th/<hS_(Ss,Z %8pr"2dV`UNUq)a-MB"$_pZL+L!ljadR:VqsKqN)O;T>jjC3Tda,g*OQkTQB,r?Y/_;IWotb?_@/EdId+JIG_(.ah:u=A!6bj[$fj %c;hB1?1@'c=^=*TrY$4n[>Q+(NYs7CMS+MunI7du5T@cK5W;Ilq>lYMecqC8.4lXd[X\sH'-AUg\Y;)o>c==em"lX?e:DD05Xe`H %$t=?%+tc&=fA"""gPD/jC%iibN-%pE3>&!r9Nolir;5E"oU7KX0AG.F5XnLOh$.W48[H@+o=W?``QEinE*ZTqd&)nn^Be\ncn!YX %iDJ/Bj9DRZ9oLVj-^iE!V6eEOhJQM81W$U=lp!aDDuH:Cp8V3Z+qAk)m[Fgr6;`Z@=hOW._KW,I]\\ND\L)oVD;#%>9$PdgSW:<s %1_GU=W+@_n-Am-6r>\a`UB:qj<NkM[k:+DfW8#2B91>f-etPoWH`:O+9>ILNXN/>Nk.O<(4Er2L#8#f\:?a1[d;'J0Qd[-BI3@\! %)oP`[i)#9/_H'cS1nZ)?U>Wl6@3,k'Mb+epY#RU`XFhAYiIbo7fNX9We6m3(7AprS^k$Y?`=NT%U">h+8$7#EA>a,>X"%2&_A;Ij %N8`RCF_O\^iF=/U0<3jWM"=GE/7<.VU5/k9=\3[*>po4Wk%AEOL88gY'bYl6_*uR6/4Vj"nRJdYLD#Wj\1/1;H[Y:^O@+N[-hIK# %&*+>ga+W]a5/D:>K26kP4h\*n"`\HQA+LF*.D*9BnEDjF^N6YE=ND!W3OPLPr3Lk47gUTB>gcAfhq'=f7Hia$EQV2n+"s.G?BPI9 %<)<tS;o@.]EKu[6>IS/&\kM$6dMNl[T90GDXQA,KAr=L%cn)I&Li?Db>*K%fQ<c/##n0XA'iWe*#\`(X,5@rF`,c;XeXXFpV4<&: %gF$/\kc^OJ3F8lfhJ[\7P[EU]>cZ2$4tjeseZ5*OlMf*iM3H)WJHXX43b@W44?!T\I?Reqi8G'q^sC&uNs(HPm8R))#0<-e$8`Gc %=?3\i$[8LJ7t;b,,#g$gb'U*41Y3(iFKAHF_nfD'3XI6lI*PA`F*_AX.`g;#X.oqS/%YggR]_IJ'P\/^p6lnmN_4?k0V`1MYI;0N %2]p_b>[pkM--@)Q]OW/!F<D016/1NtC,bt$ZGk(lb32b5Ci0,mlVC4^l-dpq#V;?(>G6#ZP9bBuKJ_B>QetEtRF+Y@GEmQ/4?H=& %pIkrB4q1=cC:[Z^jfLalLMo(MfDR]bnZTW<?aWEA4q75uMsKBTHqTq>3Mei\ZmPt3^n]o"(7Bn95*Y((D(NX2cQQKgSo.SPJ+ZAq %=:MRc4)X<d$:P6"Xd>QW$FRF'.dT)T5VB#h.f2W^bV@pPCdhPah:Jc.(^_u?WhgPjRCC[OiG`(M0S=YQ5/Jbg9jY$3Sr4Qldb+iL %rY=EHkrOIMAUBit%"g665YuS0]&&52(@!Z+17\\&-kq*3i`$'kkCc2$FRr^5-YsuW6M&IYPNEX3@P23V3ZZ'u3ca-rj=&U7C1H%Y %T@5G`T&&b.7hM_dmu;.eSu-,T(J`[J@(Q-@l<AZ*'W[Vap2CZBCT!Z&Pu=pt%1\1&+LUo.CpP?@3XW#W6pa%Sr?,ioHO:]N%?PQ$ %92M47<+^k&jbtH_Q(V!<W'#6VNTs:!"-We2\[E@cJA>/KV$@*1#'qR"^pVG(3?+a=@PDDOSeoQJ`"B<]:N]Lq$m<`sJR)0S)!XM< %&u]).!'&2,-=eZ`)Zd2LEs.DUcW3,`/'H?n_g?LZ,'"+Rp@6W9%Z[7ad2\*8MUhm-m@]JrF2YU\,2#oDdWX]^W/*\I*/_/$N]Ir0 %/22-.&-Ir5gkMZs)<EH]s41'3&NRXY.qJ]1C<?<^%(6hCQ@e&8:)JK:>YsDG!9H$T,>XV&G#I]JU9ir*X@l>YB0FV_S'n`&6eF!+ %JMlN0rotEaS$Y.-!@:*.(0MNQ.TXTC)r"JCKt=J?1jWa%3WOC"_78bE'A&C*L2pDuF;!n<IK:qF&0q;n,9p7%M!(JmkU#JMU(kPK %(h:=P-hoIE,Q*;9Q>R=4cXUQSfF9J"W81gkkCh(JboL=?=R?H;1KjV*#Y(e&W[T6piY\2_mmX)Vo\N_La!f1/Dfg+H;Ab+Pk>_0W %pb.8-2'>r;O<T4^&g::,3!RbPFGN3aE]f$=jV!kS`6//Gb/hm$am3GeWe2c8`2V8L`Qk*Bncq>VD"HY#7eg@Bp<23YN=sjP4#I`j %#?bh,9I8Y.5=%;!^V@L1Z<gccL8q>EX7?0#E1.gh+_h/lS%h!CX4'Hgk*=h?>14EW[Tb\EX4'I-U!hDe;+cZT=2JDUSoC-nGLXFt %Q,nE]"B1T+4k4Pm_tdlX&&qU*TB]:<\Rfn?EW\dh',Sa4BTjiL.RFikD;;=#@a4h99=6O,A?%k[R4]9M`d:R?-R&PTa<]Ha?!8IM %[T]-7Cq`t[,QjkR2dI&i2O/hd[.VVB3C1ZDI^(HcB\+0fY3J8`UVEMt[lt[,.KD]5[V&Vn08.K#;VG+7[O+?.nO_E8N;M/NA\&Z[ %Zusa.jD#O.6shi#9-WXX'7!bZRaIr="2TEqg/=7GNQ,PqWOgS,j_2&(FX]An9_4fDbY;59<EpfBa6b;%6@t<`:('asf7Gq/1(/hP %lhd7q6DM;[.r7JG;mN\:j,]'n<NJK'.Od\J8P(+/=9;<P:/^^QRG77X]WAaY%:qk>44\3og;18g6OXBJF)SL-s2.uR5'=$(NF0Pu %_?*V;-5D3bicK5nP[L=SbgFK!%Fku'lB;k+/Lr;]FurF)Y/s6KPS;?iW;T%O7:$X'R9DN7W!gV1OE[4.,]KN%ocf'g(+W,A/S6h- %!EunbM+(*7*k3-1H;Kp\DJY`YA<TWM@BQ%Km^^P]e^:7+oYh_JB]t]Y7BIf1"M_`oM_N0XnhnSU(Qp._*1RXN\.lp/nG"c>c9*Fu %0kr49OL#9+8Lgsjohpo0B`h#u.-i<Le<WF67)^)ZGrsOe2@e+_=#5s$7.X[M*0pmi,"<BRTsuI1!&r)a;6c'A(JU52-pk'!-)%mU %Mm*Mdn=Eg9(b=*/#FY6B2Y_Tf6If*N%'d>@11,'C_Lq)2leSq,:^%Q?q&6W(4n*_c:9?9[giLhW1sF-JATcr)@28+qdh?%W-itOF %3#gF;2]o*%m:rMmd:T5"Mqt/$P&YqI.f<;Br(p%UQQ\-9<c;^pD=VgV<GD2-$k)]7k+K4TM*/E8No[KILq38GlsDWb3D1C#Fo[9n %6T)%CI3*Lc):2qVB_A(0#G/,?75aBMeh,@/p<:@oC^HS5d/JPiiq(JS2W<'o-Y6.=Cf:GB2MC@%E=XIMjX29Z:;Wp?T`q@sW)H^? %bkK7H4os>.]>lkpp`=s]<"2PajQcE_Fk4^8*,JK]\UW-0!4BA>&<A0m'4a4$Si3Qg;hsDWr7J<D*e'T>7D>*oW6>/9JXGIZQoDCo %ULG;*FSj_JS]mhJ4*Hp2V!n/2(gTNB<@Zpc\!fsNjqB%5g?[#$!RN/A^q*d0"G4!0=2nucU`_,)p#t9Me8,'Ei=kFP+XUhb?e!<1 %<jD@j+F[#d%%jP%Yu_L/E%Oa<j:tug,`=pF^Z/4)X*)4*GU(oWWVa#LU^98Fgo<2I9N]4?]d_Yqr']JddVW]hPt-q@BJ4=U,^\## %fles`.)dQc(6tN?MHU?E)O2Q?fb$X,`f_ON"HFq6XR/h$5[@A!B;IVb3Y!lJ0eQeW=<["V@9iK]fD0#(lIPco%Oce:;T::rLYL2O %YooC@(e-n8m\'/[(bJBH/ZUhA'Ju"KFnd"`DFlBC10(i"QWk@pZsoI%7N\eGah+`B([A_Bn^e?"7#k09g@6CA!kdD(7YH1<burFg %Jk?e>]<)Y1!(sih/2J.FW-'ORB^jS<CUT#;`"IrWMH>V?n)310>(&)!QojJaq(&gQK^r*^In_aL\pk"\/$Fo9h>0"@WGsEc:eSP2 %j/<Ao9U9gQKLm#\P(Qrg/f/["PsO-;aT,jdJK3278t&!t"m$$8Qk%-#)?gk)^A/%7RkgS8=HrmF5]ng.>EHg#B2b5VXQ2nWGb_GX %&]eW"6,B=A'D#`>Q%ATb$JR6%<rdH(.!aO.Tn29Z0NV*(&2/WGcgeLabFm.,]O`6U@?7ZN-_5qSbu+ZW>p6F=$1eB55iBpk;8p+B %2M>K%h[oA!H(tJ;OAm2oD:@'5\n,'3Y;RcjXVLKGSbKBf3m^X%b1Y!UCp1)iEq@I8_bP2<npmc:[h&%^oZ1_GdiKB#$,N^KNN$jo %,!Ofs=&gIY6MF;3D^ArMn'0_aJ&e2\WkMZ"%YmG#:1;`>cbB2@n,E*gTASN(o()_Ho&ec]mC0:uH&2J!6rIRGs21n0I;sIXq<h%^ %rr*_Kq"aa]L[3jTgmuj#s7#<G`g*0Ws1kNDF=OVqo9];^#2_fTH?g8u>Y-E;ijAs0G\p(j(HRqW<ZTS,oPu.VU2"a'<gKh$-po2V %-O#8Oc<2aV[^7W_bp)G2c#Zhu&Ln"dA$o#[QYt%d/WX*>m`e)<?M!Q<OkkNu.3b24`Z5UNE$b'kX5YEY"cTRQdo&:ff*7VsOW=p+ %o_PSdPDKSP/8ARf(K05*G%!#OPjsE"0X\p!=go"!iJLqkic*%;O[YZd*t]fUdFi0@V]?"/'_i\-_Q'Im'mc,S,!dM3!F<UdN;$E7 %U^7?4/`D4=3a62p7a$n?ZhM'bG&9_@.s*0Mm\JH2K0/&afg;!u!_Yh9-`psR>`/33eg*13E7<;>AO+B7UY!O<gq6RE\9:+\`b92q %a]0ppX&/C9PjGck%?rkfk['<.+@/)>90u@*VQi]BO9`j[mlX[LEQK[3:$o%t_";1ecnDM1C6F_]7'm!ZNtXeAOa:Z'IYi*1=aiVA %4UZ#4.\]=Q<(8GGEA6"T`BZc1)l:ucRWjoH=A]_uZW.6c1/kK=C7;hI1f)4fdfn;AZ%PZ3BLN\Z"K][<K8?(A>m=[3`,F)<O!kZ, %KY%C:fjeGj5VDf#bU=kn7T.Z=%f(.X5L+a=9qXQ75K\i(U5NT[AI6L,fQk&/[jsCXOV<$Va>[lZ<42In%NlAuj`9C.YAaRiHKJi5 %)%2gX^@J>&]ToU+o^na%AT"NGF^s5Y`O>E:kC(eoR=K1DbQ3k`pBq.^1p#cW,5TAZ7P:@V"+<o^RV9)Rg*;3@THX\$gU5MZ$4(*, %OO@9>eLsH2nr$83-(_@rqFa.!csASh<IjsDVC>,@G8$/:-L8->Nt"hU,*PRdZ[0=9.qF5sdfp#FXk=SRm1iQR[8*CaDBN%59lJgV %9_5.<E];8%L!qK(9!JkmK<EbYM/(-WH5dX)PJfW4dRmk46>MGc1'7HL;,bW-B#4O=TlX`G9.$B%Vc>u?8XkR`=q5VU5C.5q_hX:S %UgmT-,$g#_g[+)g;?r,Rc_&Y'0j%V>KgdAcjF"`=Tkp`G7a;N'3;JqJd4X5>)"e+nR>?1)@A*_k6[1aOWj&N[MU[*B\S\`[@pP<) %o-m9TMF.C[.I"_,A;f.=QQOMu,u698CqB`8mO0QK!HsRG'-66C^8oCkqEn!<ET\X3n;k>pH2"p*`n_Koj@$rQe#`T=fl+TuJ+6;5 %l&5T:f3_fiNF>$JRJh,!m:ZIpldObH]Y0t&DTqq(J,&rlhuE*?lJ;65P;02ob:c*8?+d)GO2nst]6D6if9]QWD_Ln=_Q0=-gUk)n %DtIC\hgTW4s7Z3D\\B)ek25'%Se!R4d!Fq`cE9@P[=>l;Hh[2W?VJ`b>s"pX=9$_m5LJ(!Q[el.DWaO,je)I=G(66)GCGotTAV_I %^AP_^kBF\Nq=*h>R+a32rjM-&IDu(q>^H-nk6KePkEA-qci<Bn5JR'Wla&hP?(^ZXm@p?sGp^,bJ61Vu^?>&0J&D;8pN-p7:#:<. %rURkV`Ok`"?!i<@]&VP\msOC24"Tc)TBFD(pD:TU^%ecAj!F&pAFA:Hae/(YbnkSjGNU&.[H:E%kH"W%H$-C(T%UX:P<WL.p!MWE %\Gkmkh:Z0/Gd@".:]=b/j`Z'\gPbeJY'*%MEVV4*k`MkAn!Nrp/\W3:(OoQ;a`gPS45Ti8Iuqit+'FrrR7>eWo&]P`c%k'FMgrE' %qr[4foA(L(O/I;UL\f[$k*+SJF)cPMGB:Cfo?8/FCtH>1\c1aRrT2ifS*%bY!8E\ZrU$6Uo&?]OT-(b[_gA,Q[s.K<IV`pU*PK-< %&+[rW]ru>"L=pqHS"%Uq0?i>.3>caXpC>[.gKD92h7]SqGBES>mbZ@Iq['l]l,C2[HT]\sEVE5F96'`](\EWD^Kb#lnb(SiS%l[f %bh#%Nk/DX6EceU6qbdpL0<[Qej='p,N6O`_%,TmTrT2"*/f"8hZe)P?oOKkr^Rfjus8MTUh(Rgk4r7FLTCmBkHY;Map3(Y>q"AW% %n/sYsIJ*U!mMA*!<Ub0UHfFG%:UoeAbFe(0iLaYu^]3HUr3mb3ZL"4@-Fk=AT7EHp2chrIs8:KP`REW4#lXI3pLpa:rTTlLSKDKl %i=B"&[r60@]tZXU\,43mGiKG_!;CoaJ,.hX2t&B5a&C8&5P\7G%+BP&iV'=Yo8>9Ich:M7)`Ko-hrM_fnUE40HToPu4Na8Pk,7sC %pNW#(hYC=Rq[%,$hq_PO]0"Q)dSn(/0>:7GFK-_?1U;eM<t+'7Esd747YbmEIA1Pp@=P*9Q<N&k8TH6%@./Mbk_e:e-5Y!G0CQWh %^:;qrM4To7\@T?Mh:^o1S:KeceaDeqrH\-3p#i7*;nG7bh#0Ou'0O@]B(2EWo#U-Lpk+$WO2N-l#>*8?m!M"2o)A1I]oT*>qN/J+ %\Gak[]uant"RUO9]u4jZj%\G;)>_(fY!57-ScNA8O(UN?T]]+O7c_h=c.+Ib0/!6Nk=j@`6DO+s/+A@RH9P[8gWQY(h=I;calD:S %'0R.5J+khpG5!lg'WT*dhO2=?p?_2.LYW\//q5otpu_:>YA^R]rq,S6E_VS:m,4/^O'aAZW"3uLAk-G+j".86=(Yh-*"dZYH[`^2 %OTXJ4-V),B;t'=E>I2*9H#g">J*\&F[Ut""4a5gsd*=>pkJf^TjmGUmF#dKLI\OLdf-`VBSgB<3*hVEL@88IGO+$g9bfDTqmQ3Y\ %U"e!W5KNa#C)g(*n;/7MpH*"ZhL'bFmbPk4(Dg-hkPKq+*o?\V;d2=2,JW\75.pF-cCnTO^Am?\m/5l>in`Focb=ZoLXGeJ(i&4B %lZ;QUp/$*kIO+;#6?kCYdXGGW#CIejQ(iWulG4S@`ZKDQ@fFjE^(DuI6E&tqc0_^.5+[\HgLCC.\ou`Zo6rUO@HT"!FR?;ZRJ!I$ %?9+8+pXNS8Vlq_VY4_m:>s6#j^:J]9EOIZLH8lo-^V5!*]+$W9q"0-NO.8X3!ome[nMPshi@1:ZSJB?(c0j`]bonU'YAS9]GMbK0 %nY`S.gfaHtkH^`[%8VJo#J>94VoN@SrUoO3SbLSmJFCd$pH#P?qG7)q[hnE)melV3^:h1kr6$/=c#.cX*7VUVT8S"#IeYn,BRR2J %Q;?t^m(=%IUje$0k7-P<-ZVf(hHaH[4W--DZfRm-.K7]iMZ^l`r^;P0&"U'P)!8qGYEoTN3ArGDI*1W-L=nrA*V^eb48%BMK>X4o %3&o.M:NV9-*6)VNGW<pj;.SiC%M#iB'-4YA]sBGAKYtG`_I9%o*'1rF[X=\pnrNK@H\[%q]f8!qmS@rg8('m]0Ln+HJa0j1<oBZe %LDL2Ng&6a;>rs#E*9Npc5L0SZZc<.'=*ZpU2ggXeJU='PNaLbc6[8Nn5JiI?JLC<ak>0h,o7-Yt0:D+fO8FXEI\?3(TtH*r8]1OJ %3K/+l3ko3sS>/RNDN.\W)XXKNSr#qkH*&,Fg.tS@rQFR>*)3dVVpI'[]=p[]G-oVVqWt!RltE%4p";.KB1MjcW6`1FT<1\U5OOl? %Ipm)/kD0'Djm\;bAs[@5J'-MXkD)9>S"KJaq.[6"qVC8j0!9YIFnY2EpFC8H7!M@JYO]uK2L4o/hZMT@h!pmkhsJDUc,WHTT,6,& %qeq;XA_/;U:0]IOQ2`tV=$D]FG-Ao84s,7qs82WeLK?]$@e5f8ke/*NRiU&$F!jepI/!?oX35^R]-iGQ0>=tV]DL\2+)ndNP<[re %+@]\TOW_Z8lpq]Z6TYUd'>tlJ%J9e78Ue3?Zgm41eDKGW%NVU"$s4L\3nQO%FQc`rHYoAW=)T1Mht,'TS_m\%F7Xi_hnT-Z&U"!R %..8P3$#f<lcV>YMBce>+3qtmsmEjD#g$RnWf@Lg_];t>^WZGId$fB5?o]P$het8RD?g[h8*s$Yh%hbMO45K]u54Ze\KD:(JOH3r0 %f*=mnr="*<.?<knpPoE-qb5q8:-PP=5PD#pl/_e6r=1O`F%ds"HRga&Sc"(DLX6C*KQ;%(n$SUF.HDk$Qt$L!;%N>e69_9.O"'." %$Mg&Ur_=!sJFc4U--CI++WjY(#Ihtg>S"K\r9C<n]6?&V/ui=*a#\<ZnEn3Fe]hHFI@@4[5CIr=rr(oJpf)HdZMV*ODK813eJEQe %ZZ"W?\<!KppW^spi@DRqIA]6<n'_LmG!</pgjV,NOo7K$k"WmhgG.pcj6>7Cs)`U-na?!gb[5aHq<mY3T5HjmbN7"!`SK^d(N2OQ %\NP<6Vk(TcZ\c]8UfPJ3*.Z(kgb*7&0dQM2*t-,NgbC'u%*<qTo;_2J&3KdXbNf[_+)1\`XtO&[aVS%3q3`k<`aAEHq(-_P=hNpa %QgC64ddd67LmVP,UNEL__D>Bd0.H8[rgSi;Tu(_4"W%*$kI#MWK_6YXmHd'MnHo,II@p(;rq=U@$bjY[c5WCk8Gbqcn-&sNNcCOu %guc/fD)=j0E>oAHE;8Q4[lMHFNcCOugu]H_3Q>orELR'7WijkGIh?Dj@h@oBK_f"rpd/9@B,H>KOlc/k,91ji&[n#tU@B\mL/4V; %Sg0$1^2U]:<sUIb!QE5/d($["qq]rea5Y:g0;#I1_81\DBC,U?#L8mF3siuj46(R/r[>5<Tq@tS.c]R:GmHq'Oa$(ecd!d(eFDmQ %%VOtr8al,Mo8]>>qb5q)If.8Iot38^^A.QkmEK!fN;c8l7hZor"eLE"\MG\gYp02RNW("^bK`gKhgXX"=Q*M7H\)L5q<G$T(O*6L %DD0l7V;@f%9%a)@ICoBSqXt6)s)7^srA5LEn%UtlU*jn.?ff`^hO_Og3P&f-kF25-rbg=6q:Eg!H_A(El;&L&N4V=%f,#NamOaKQ %b<PeYSbTkh1[TWBJ,9oae5%e5nGKhppK<$YS+(nh"uVE,N?A(dat]i7Ybpn_$>QqX:uf*bK\\lC0rT)2a6k[\EJU(](t:ML2%DLB %nIot!n':XBn@cbVo2iD6kBCQ?^U^o1]j='DhXMQFQTd8Jlh/Ok-=<@X^\H@H`IE<GG^$m6%<M!@-`G>iipQC*r$+MHeRPATs)<7k %#E?^B4eMWYc[S&.f"lAl^&)dIgT_k#ZH#I=Du'%_B]o0GF7FHtJ"jX"d@\aaE$RMk5%I/:M=JX"hRV%Uh9G@7aN\-4+CEs]>joCV %pu5'kmG?Yi3`7^"EkEElR""ftlU]"e:HngodusopG,Hth;1_8epi-,lLT@-'SmNK-KlO<_@=KB/fCt+M=.Uhc]2*k-1"<ct.e)He %@s^>cF2<q)r^99Kf\lu,kB['IO&SA/!sI<F9CTp[a6m"*lie[agbDHAo=VCD46'hB>A0Y;glEN3Ij3qGkjBIK]=6*94$%aZL[XHr %D-J&OL[XHr*?@=dpi\QpNt1(+3d`RsQaS\C^sV1(9TO,T%s[aANZR**j#_R78!!*dlga'QkOIs07*ij447Ph5mlC5ls6Jh0m@S:B %G#uNclgX;J!ai%PpEH*.]L8'A]pK'8]P$-IcJ4QPilH@aV"+@30OEOb+QB;qi-m`b*M47t]MJ:mkH[\QHDj3g,@=^c:I;Y:s7;RY %BBOdDr0<(U^,\9i]_hDppP@P<^\d_>pFLu(rFDD^=7hm+BJ9<[#]1&70Y6/-3cKH/AbMUAq8Ua-VVQXkUMBO9&C*HRIJ8n0TKTmg %5F3CsDmSI+[tXhXocAh5=5'nXA;@L,H*I1TIJPM7IZ*]Ro<USr\rD%HpX+*=^:AO`rpK,_XZ9JGn,@a-r"4,WGeO,rqpjBq`I=Ft %o;:[b5j*"Wj3cJ+E\dK^^[p-.?XA67,C+%UJ+A@E4#90.>`HMb'l74EGVU6(Q^=cf:,VS='W?R;#?F[!HH7).]dL)Y^.0:2k@3uK %I)P"bm!Zl;]^Z<$rVJe?^\mJgRs,\+j!j/N7r.j407@;Vl"D[ic)%&>\b(SjiFcgW]h!PCpFr*Ih%kC+aad0$i>tAK5?^2Ci"a+e %`'p9R?J^*YIBa%Src:sH=-n-G41kEX/+ia%hjr#s5OZ=crqmIWCA.u/#^t5!+RtP'&V'f$Q0X(tKDm&:J`<aAP)a2<O)<;brqX+. %1-QbMa.r5T(%m,"S\%,-JKLGpT/aldo,/U?cR03Nm*^-7[a:(Q2EZV1n`*@%)(gN.8k!hIT=su`c]<tIHR1oegUhaA^%20,2i%'I %9,B]`P,7KN1"=K:):(URn%[3Z>q,^;\Fog@;(9gF.e(UFs)7du8ToMurmU<#&=5VTUN^j%qeL#`kFs\;i2QU:9A5C?+,@In5"X,] %;j05T(p8qW^A)a#PFZ";,<a&_/[E8i4mm0r*kH69R7KNa2p_X(_[@eVIZAB#n+0fpI0Zn#Zu`A3F#d"omS2#g`qCe;:+u#lU:p2k %?X;IdlLOW[@]G4SSaXk<h#/0VLO`u][<#5rTD_"J$\N<Oo5mr:+5WRgrY]F6(UqOnf2qCj:LfsolZ&IYiB$Qp'm95.Vh1;?ZU6&# %J%.Xgp\q36\k!gdHN0Su5)10dq*)7@U"c1m2]<lun3H@*@m!/o$mXqaIW]c5hrIU?anK#@8$(i:'6p5nhlH_)hu3K1]_ga(]R+F2 %TLb;=o#KYC]_gM%JiQq.7/Vt$5@)!-s5C<AI%t3@5CN(hop7U=TDe`7DpQ/1GlM+m/mb*])RA[e0phL<X+0og^&%R"c[YreZO`], %j+m/p^Dqb#m:Yj0MEUb*b.S;4`u;u?gA$`0.Jm1rrbR0Jrq"n7QiC^riVsD8?XKX2^OGj*r]g/B/IhRRcVA6BnTD$!]P>"Sf=?S4 %lC,]V[?!bq,SaGjTe2Ug0_q;.R)YB9q=agA\Or2HqKEaqV9P:WcFZ&h[CgBedR30ol^Sl#3$,oH`qQqR?FT8`M>cb/H_Y@D*ku&3 %$0e't@UXUh>Y4cbIJhM4*h^169ua<=>B='TW0)cs]_:BH.SRQg''@e+\"Y\2&Bhu^$t<[SI@Z#:YQ"9/X15Z1DaSuT^+Ps_6#l:7 %.ZJp/qU`EmnHd*pk=T6mr*tlG#7ob5cPDpc)SbT"$d3=X'$h]@nIFf)'d$eD2,N@R=e&O_<[#dIO4fiAEsSs*IAJ)<I]T=dBt!t_ %:ROFB)3YAl#&nk3!'aN%lf^)5i9G)BY+f]IIiZ58K/)h^q2:;0;L7>Hi8cukisp'Od6m8-6,l\nZ?^rmG(1A#H\;1t^P$scL6`ni %)Y8U=n*[UXV.-U!+*N$/+*-4_Wp\;;a!'8c"+>PohoAf%hcBL3g*.WdhJ44*DJY3CHiog'%qF4NrO)04HQ9NV&iNcVO-TEb`ekY[ %`A>"Ojpeaf80>LBnWt*h`_,T3bdP^([5C%"[_DRX8F0hgp;/8:j7p4"Deu>C_X!Fqg=UX5NP-?Q\@5%D>jpmA0,qL#np4Q+2n"02 %I>m:VX,1.rlL`?!7d5%Da2#$MWi+IMgLeu6,k\>4%>@9gZ-`'Aq+-flcc_$P^[RCpZ!LO"nKNf%^Kk+p,4i@d,3CV<W5u5ddb%?n %-?`\5TiI02:G/VcCd&,1%jLX5LZkPRXBjui`enQ6^609I8u=VuoQk<or[O<G%/q`a^@&@IG_#;b`]oTSXmPdXd/6qb[iV09a9V42 %ak@_A-$:lucd=q>[2F'6k0iT(N8<I5WZ&`JX#.,:)TP7HQ(BLe/)/]iZ9RC8>$4W3EUUK*8^Re>Z(\4'(ZfK@,*sPWLk;;m<m0X5 %oX/_L2ej5n:Tj]r%#0cNe`Y31%P:sl-l^L__AH[^m<e;PNeA0n(!ZJAVcp+5N96V+'/4$)K^2^4_pXm]q8L@o*REj$`j_cXfEI\Z %Z4?Y;kG)Wl1WsJs<u26;8BXVQUBB^m`4A*cfTripEKW2G@77c^C0$jSp=1iXIefB[7JT'A.75'Cm$boR]IK?AP]td)N]pGOU6W?j %WM,6>pT1A.SRnfr`[f4b-4tUf$XYu5F2!R(bN%4eSN%<o/!3V^E?mW4<*@B^1m\"(.LU`RZfl`Lh)@N#;?^B6&$no9c8afOs,I=t %o$JC*&XJE=)Jb!qkAJd41,L1NS1cI?!$m#e3bYS"aV&<]b"=.CGFJ.0@W>&!piO.ClCk^Jr*4B=XMtL%bA"f@Z.m:@Pd`VqH?LUW %B5j^:l\]5GA1ui`]<8=a3`Y*[j>D6S3Ufr)PMFVQY<(XY3hSo.VU%4t&jQ!7k1rI/+N#BCDmehIGE)")16`X%/<<$7l=F%Xo@^Sq %_QgP]m&@7RADN>Na<;og>`r_G5*Y-\U:_qq?IhKB'N.$GoL^^gMZt$1^r,_7M=m^CXj441[O7QjF_l`te]q[dmZT&WPWETAZ0c=< %$[->)W/@jpa2d4Y6Q.FRSNnGVW/8#brf/7_^*U%)S;S6"[B?A;lOTE"R!0%O7u$ITYCQU#"p1?ZZ19sr<_sLb.u\])FU$mBHP8co %]e4%eO098(XO.7,CV5VrD7aVS'W^N,+`>1QQ)BTn28-H=MM4:Gf0/(PdRbNg!#;t_:jN!o=sdAeA(+;q<*Lqh8YhYO[uW0\4<LH. %ac7_,QqW<^(@k<o_QaLOq_gg/o(_]0!1bQTN!s^rSS+$GF9fKgZ/@G&fRcJ3BQ$%=)U&Ch"^TE9ENO$9nVfblrI-(dSZN[5$KUr: %\=#'-VQSO2P6&+J'9A!'OZ*LOc$g_GV_gTY`]"1>M<R=cnWJKQ)LX9,N7tEikF2g,lREkm!&$72$]mI*LZh&>qlj*7NcWI'YU!<: %SW79XV\Mo%Z$D,E&+W`F;]232p?VLR-.Zf5p]QXtS53G(Rdk"W"%9edjLlA'X$P@f=92p(nHp+6aZ)t9[NY6kUJY%O$k:ikQdWlH %2?D5NCnHZ/am2<I@hYk"QU7mF_G1lLh%!j)PpaEefg[6:gm@L;56T;Sq>IRu`5!:<0P#T7'h0O<>(1o:hfWR%H;^gO0ni0b^!:#5 %@.iHt$A*"0b::nT-/ie[TGhK$MIKu*SJTh\T>o!BAHk?frHW'X>u]i0=)TrrdRX-8fLt2D,&sQ1&X./NH]B<O6T()2c^#&@27gf, %5E9Whg/8O50_A0p?N'@J$SUDa#Mg2Y/?Pk>Tni`sL/TrL+l;Th%(r\IPakuh(Q=!JhE/9h,S$D)iZ*Wscf(gUNLqF;DCiSM1SajE %rJ0USo^qS.j7YauZ\cc,7R&Mn0u:j%24hYt/,X2\-$[hDD%u.\b:o\H408@&Z`#&[F$'OH?%h7IYWS?W8]Wq3#!g1#nl>YSEW5Wj %2:pN-K@&1^-UY$*f:fT'#Bcr:XeB[7H4ij.@rmEagIffdFqYn"dFZWk[g;.,S\hq(jepb[R(L)]Zt"ZA+MUr`<Y?F[-keLM`<2Q4 %LL/mUoY-&(ECnPrBJVE*6gJ;Nmu^Et1XV=Vh.>4"aC"ThNB2I1^7fgdWhJolX]h0c+Rj3F7VAD2iu`a];&%Du3cm:1F58fI82sp\ %>)sYdeKcN1Ska4rl1qQTBA'8Aa&;CGk8k!Er,k.G=]f*<gM,A)fe2mS'r.6<&BFM!4JGF2QhR](3PEr]6<I$4q>`8D9bW()&=mV2 %bR)u?A%AKHdpjrI75q0-6AmF.V[J;n,n%&90rr;i?kk\,`M"XdbbX/UKc;Ah,+dp57=\:UVbrXmr05O4h)FUIgfni*m6@&@"G.CV %O`j4X\_f=qfsQu&h)%AgJ'gpG0NH02`8i#-[6m'`8%WC8B6F/2N9*0<+82`o$u:anA.Bk97Q<KL]l';)S[KCX?5od?R-d^mBu:<$ %f<1@Nkq7poNgK#!],#M'kART7+[]%j&2tUFdY#rr45=dmBGm\_g2/l;_dOTUI+[qU[N&00FcGYJ.Se038T`^p^7$1I#\c(PN(@%B %U2"`h9!:.)0qI<_ppd-P@SRl/d\:V!6s.JLRkF<]iqMQhd\@V,iMG\6%U*uf*Z;/nqS"rjHJdf2^<snSNei)O>)E^W8mY#9n-8O8 %`2H/'\[q]R`X+aigU?&V;rGEF#R>ZlX:6>#D2AnUZ/$\0\iB5Edm+c$gP-ca2>g\g/sK?24[qKm`>DpU$Y8ioV]cU;-B$'gk\.nd %X=GsWPKl)"mcS#O<T!FA<crA94t&F.6qk\_b;%Km](/<RPa8=eh4`STRZa`YB@Q'.4qi9,`KiG,4Q?O(.l]k6TcffRf\IUrJuBVA %NH<^Zc,`50_t?Y_Cr@I)HpmhBs7l'(X@Xs[W&Hm6*%_>)_fW:`Uml`A&WU/_QYT%BLFKBE3Tq>Hq64*9!9YYL_BHXenr"pqnHrCa %"Xg/RlZdTN,TUHYm]l=M($CO-N*Sd3d:+2.("O458['\_;Np/C/W&++RhWkXQ=Gr8H-PE/;1"4,QKn+'mYSo/,,''mIQ9/)O:W'[ %/W6dje$5nT#>Z`Wd4*R;hh6"k%3IGpT19_EPR?B/TjO7J"\P3lCKULH>'I*iQgRVDlR_2&XGOCnOUrJ?\/2EFXG<ln4pcM>UtjL? %l9,kBV@"OCPRhOL$`"Mr'j*J+_/YVmm3I/(p`cDbTU%>'#V<,b9k0OOpg^!;Q%!4nAcj=>_arM(_b3)blS<-qn\G@lW,9XdZDjl* %:qD=;m'52N/%sbc"_@'1'cP]571oP4jVuoh-&5uXqS%=Y$)^\nhJ[jH$E*`NXJd`QMPiL:)A^Q$@DtOd'MF&<Thlr'PeV<[@j+`& %C)kcLA'%K>/T9^PL'^tJX`1<"5W8,CRj`:9]S,6\hf5<uEr]h.U\o2`pPo.,8O[9scY_iDlA"\g9eAYFSutP=BbX0q8]5Mo4d8'l %D6oq6329JPgsBa\UfXstrH]J[*_KV=PQ?L^`f#Sj@`aaOVUSel-8]e6mHuno!5E2j8*F4-Zl&aHM^g&(>(mG81sV*'Cr\aS&Ip$R %='2:5A^so2YX@(i+B(oqh+H@12LOcFE_(aUmmL"S8W+#]lIg'MJ8`B#nRCE6-Qt>Rm;%*(U<'^0A;(MO^9cWd+]SCKFC[sb@iV]4 %-fEG`bLmM.7Dk,g^IYH-F15g"V0iW*-k#/8";>3IJuh-Wi/JXQZ0/cF/U`B3mYs8nN9%i7B94RA`K@>a>E4coNMdu$A=-g(hAbD% %VFtOLhA.,J_eW!4CSd9J=@;W8(SLB*MYfHL<p^T8Dk#XLO7CfM]f!T75&?PXZ5i[]A[,(klr\s[F9'^f[Ur;Y[\^(kS'a![+gRZC %`P,I'@TC/RW@Q,:>?Yh[G#>RAf[Rgm+($a<:1)Q%GX8Sm%IS<**M0U<Y)0Z5p$gX&%r.huRj9RDr1#1V$At"hNq1^Eq46jUr[gJ# %[&PjHlDg]"\g4:9bbSuu4@#(uhV_^<7VOgcC:Q53+k#3b^92nnYNN^JQG^Vi5o&0A8pn.-;*@c3&`7tJijOY=[u7F2MBsQB6<:E$ %K&C`!:(7faWu9&Ck[&Hj.MO4.r14t3BGusB_h.)HoW#sR:5oU>+<3o_$Markp/bJM_+]ar1EhW#6XDIP@]^@#mC?:)dCQ%/@hip$ %8Vll@`!RWLP!i>CQHcWEL[siRC@T]mUCJ<$Ulq<<PT:r(eJ*q?dF-'6M#BUA83ECR#u-#N@m<U'Ogac3p?LXoG&O*/\h"fGTns[- %IQ5ir35PYOEoM'>&HjqK)nJfb%ZZ9S%8LMmdYY2=>ffV!>b+j4`04`g:*a2FL;Go&KBTp6`_c.3S>!%4)i`_cqc[hj"%A42*+Y1T %Zb\$lQ4TTlEeApBSL.oOQWum(,Z2G,fD,:goE7sqqc,[^gCu,dCT(r#B7JDs.=mR?B%dNNegrCR.j(W.`iA=0ED2P_$-V68j/*V% %@s&1/e!Z@N@MK!.25*@KLS3UU;Q0u#-;s+Sp)V]p@Q6`r^+S^]Nk*7?L:Yp&*ufsUMcGc5"^G(?GSheq;W2T*2/lt>2!9/FeW2kb %1`o0u5`[R]FCT;u5kC>eB4T-LfP\9"Z)37T5taR[\J*D7i\a38k&e3TC`G0(d@Nk5.23b"ZbB6C>0NJC3\*c[CC=oEN`,[I;e8<. %A:4J58$c>*KO'Zgc#J^)>Ve_'G>4\UjJ4OWm5;=gl=Teug%)>cisE:+9<kXY9p&%F;m%MD/5nMl9.3Y)p5>:Y@(eBHfL.k2rM>f: %OKgM@A<315!/oS%X9*"*;iWXD9Y*48"[IWi?l6I(W]G.,X=?-InFk@c)[H$EKXb"3$01&5P%(eaSYe/%]Ir'?f9K>a]d6OFZ0s`$ %MJi27(.0ajQVJMfdVZgN*G!,ma75XiB_#T>\]Bm\b$/Pj3!Nc98P@'$/M/l>Y9oakMu>mCE.j3<AQ`<Y#7&c&MCDA<3OfnRep&^j %+Xed?-"fDkN#Xj]>%!a8)&E&I6VpgbaLe"(93JO)!pnJ$[O3;s$Hrm]nPft&Ur\1?FjHqIZYu^I&1(K]4SMYPU#Z%Y7lBeh`=/g0 %jc;]bji)u;gTd8(dR&duV9?Fpf=P#'Cl)%\4\+,.RcSfD7[t<14kDip%g8o@mL^(m%C`m?33UlE?T6gk>P@8)T)2Z>96(ZRo=N3c %>(ZZVA;8+0%3$4>?;!niD<RS:7[AuoeJ+ps"OJk\)@;nKlDEtoWu1mh9&MV'VM7#P\>#s$Bn5.N`!u+Wq9#)nCMNi**SH'QBs7oL %;!lU']BV<c$BgFWlo33(=oq7&f]bc?kjeOt;Sg5R`@Zi`;Ia4i_?1+Q$AU4aECfZX,OkSRQ;XldCV6nYW:5HR_m(EBW$aE-=m+Nu %J=Li)9?r`nd<r*7g'BfndJuXg4[BIKeC6Bm%n_aG42=C\[B<mj6=A6C/18t8KBXWD*//B)atT!!gD$gae0:H\(ZiDZ^dh7KMRHXV %%h(L"mEohhIl(:7#;'OsB8;(%]FC'f*30^iVYS?eR-HU><D)elrkPJ/Xk*t/%g0>/j0tDuA_96HJQY_E>Z.&L$-k_Nop`r^q88d7 %Y78C@!fK(W9dbJ]W,-r9mK.eI0>>Qn>'+CB]]k/m_]MU.L#2/Mmc4>nhO>q7<?,/ZrsS$2areV=#"^a0Df0A\C*=NI$q?W'*fO=Z %-.L;"gl":`VuLZd-SfU?[:m.jiai=u'U9Duq\!o.`6.+pf!YQL]8$s.`Rpj:5FL(5.Cd?s+S6O^m`#sc/QNi,K)l2_loXK)*XFG_ %1WNJ#2hhN7*XCIG;:b5^]iO^t3c6Tc+N$8u^@FX#l>q.*aSSGhbM;,4c>,[.?BZ:<VEUXO19Qin;t%7sX_W=b`u#b5CO>Afhh7tC %ebRn)R-jq(76I6>BdU4-p6L$?65BrEpPe9C+19.8>LR]P#Ctj4M$&:SZm8f,bR<JJCV(K)h'8Jp=QjM+TF4d50++1-!\@`1&:M-e %V]V2uN:(8jd=af3iiQ,UMVJGhJkZn'+0s[-WLn7ubVl*Ym<uQa+DaE9-o$j8`6F6,Hui!#$jN]"B2#t+ST/)llNsGSAnHkl;,kTg %T<Gs+eZITHVm?BHQbRiVqY+0!>^p>Tq.Eu$SA_^MLi3+g&LGTdA(`\pD7ZMY$=]KBd1j)Km9P>hCZFot@b>o-::qqebUL*(/$rD< %9P,9-lk5`&.3,.Y#&Zb8N*`&OjoqS+Cq>mldat]`9<X?'WC\/,CrYQm0R<4t7js2B@6@?iHns3<ZPnM5YS,F?&,]*,A2208=a<!( %Jm.tiY-Aqrdkt-1A*Z9C,Iha_Y&fugZtd16a#eK_n*HPbI!g$NPZKogH=ubFUSSf.J"YfB2OaiFLGWPC7;pHP].Lp;7M547$b\?B %/2>t/VUZ!s/n*)3m*#ql9fa@h!;L@CO*U6+5h(*M!EZZQ$>Ykb!W=_u"e)ddg90[cbi4TP;H[`Z794GB<sG=6XUAH;pX7W]VWBJB %ks]`f;Mbb>pS<D*l%W4Vc:XE:5uLZM$.9%#jpo$%nC/[;T>r^Zgeb$-#KU+&_P#aY%`,KNQU9*6/IGscFI!!304sW=0;P+[m:8O: %mHDfg7^$^_+W%&SaE.J.a=teYHEI-!W,(WPPj.R1=-2[JU_qeLQ;*ZeHLT:A1[QqY\8p.3!6f)HhU>G`0G:T5F'l*a@0DB0'&IP6 %B2U0IYA1FqMDT(X5[qs_1`R'.$*0S>$O4@2XPjk"K,+,tq+7JG=mu5K5iPIGKED[<Lo89gp54Tt5W@orK?M^5I):\a3fV.\0FrIf %m-D)?h3A\h_@%=B0leNa22_q^&^u*DX-fGM-nW/0;N_=s[BJ%goFWUAVA7$JkDpf.d&Wsh]"@3<RGWr"qV[mP$U'1=$FPpD5?'MK %>5tk;38IGdeudD01L_r43!S[]@-\-<3rR/mWsaUM):c."R8'7N(Gg9kiqARO*:ZYiidmW&16ZdRD4aVJ5lU+g0dg[ao+5R8[pVA" %,'*s:PLA\:PBNnE`UW*3*]TbUG5+$$\*F+R1JJ??M:gnPMcscGM$Zu[^\+kHF5Rj1!O"BeB1M>gXcNnLJ@ltH;6dZ5'I4-[i2Pfn %aprDf>XcT!8lJMD[bR9ZkkkmAM^\9'V'bu1T!P-rbg](d!h,;1%<kR<X0c^$pa4=V&,KL?p(5N(i.^Q,'&l\#JO99Gcq-["QfY^Q %atFLqOtD_"Gl/AE]/*@p*=5$_.H,CB>*+?84\fY$8HpcHSce7>/9WdL%`!?h?.39gl/9jj8HoO9ET\((`^b4E:1n.#gCG=GF=G5Q %/a/m$&*s<4"Bjg8qhT,qmt)A,rtemkoHkWCf9nsl\c\57.g8$aJe"^QNL*"09Kj20-+II[_-O0;@WWo<fdN?l6(hS*!mCIrKPV6N %r?;Y=<uUGt%"u#Z07B3"SA&U;_*F)a>TrAl._(VsOK+tN&U1CPZ8b6h4GSRA'h%j*"qdm:--2R/+P-+6W`cU5/?F*RnniAG&7AKP %@&8B!G17,P8;R])])TfTIgcs5<FJc683488@5X]Wf%/SY:(TsUVOEt<Z:!8ZEO\:HhB]m&YLl`6X7WA.ou>-uJ))G#T!G`n0-#Sb %,;fa1N_X@Y#YY=Ln\8$(]cGS09E;nDAZ8uXL%$p!23>uK)3WsSk?[R%Y<TH'noK;,rmQ+O\d8RN<8\!Z_@9l'$Xq<P=J:TW&PXL> %\fI_!97n$b)]oDa?B>?>ROt;?M!==sK7sD<A<0D.Qj[@RWqp5&_f6U`M"hm22%uA`SVoRU-VTeTN'%r]+U5W&OB/eaD!Z]po*cfS %GL3B@_iW:E4pea*!9Gg$7Xj#epM7DF"U>K'PEEeYZ@fJX]Q0%*/[420Ddlb9"YVLF1%Y:o&__VO2LrX^5b1daF2GG=+PdiB(8n_H %m8F5JR:T^_MEVjn!mN4JfI/^ABZS;!(VI9Wa7EkA/'1>7^]L]m5@am8FfI,j0GHC`;'9kC]sUCUcb@[uF_%0;5&LhTp#>kK`3ZA% %?57;7gfHE]U?MI%lSZ4K+K(\t*aKIAj/85(bos;.OkG2pH$lYre`BA0-Y)kd>WbcJ3=;X6P@NmMI(gFid#\f`qkAfJI0a]b8Zo>R %_C;_!ck[<bN\BZWQ^jGD^0RoJ7AcH?KT/MH%b4kq.ct(h;<p`'ND>=AVE5H1/:*RkE:)06T5%S8P-^h#G&k[/drt=MjU5pu#&(2_ %LHZnP\MlmGSY17\i;B1qV]-O,_eiVte7n!/l2SPgLCAC,n?\'BS0'NA&Q)P<&PnmTPQbZYF:fqtgn^=olrD9=JpfMMl3!A\\E%)< %,>X<E6u-7IK!2?d5TtY2R7HsZVikFd@UuM8B'$NW$1Xo#N`M@Ok0TUE\@^i%@GUQbh7Oo8%Rt4;3NE[t<GHZS3"'lpF]&Pl-a8A^ %Vo,.qHfp5u3f<@7p4N+Io$]-]X+a8/dnHhDnq'%qh!6(jYr8HY_/,6oZbe&[Br5"P&tU?9FYNiH>Pg]i?u`;l9fgm2o`fN0\CX$< %Wp7Id&!G0i`NWOuUbg8=Ps8&,dnp+6S,ZmH/S&2?UqLC&[n?HVi_B`2&eaY9r=:Z65u>D(_Bu+%5eu:mc0'nX(UM;"XZ)/b-!`I# %,G$E"6a0]U;pr\`*:Z]o2kN!dk=TOlT-KpVkn_<OnOuMYNTZ+19"L;%=ZfX2[[)!QF!Y\Xg+8gEREdO0!1kF,D,;aPkP^.7mNr^' %<!5:I+XJ';:>]s#SKemjX&Be^7k<&jrF.FNWG[ph*-(kpFj9ZMK3BX2pPYTL=5?TqF2ZlfY%bm/[].s[@[$Mc]*WhE\GsNJc2*@S %K^F5nPP2#gBmbrNqo(G;qMX/dmXDF)c;_9pI?(i7`APp7`S9Z1Ic$YU7rL*\;M,F!&A6VGcJ0nE$M")*\Blf8@AciA3T?psd=n2= %7)btC!Tj0>RM"n"-GD\\(CE"B\AXbtF2UcZhmN7A5/2&.Z\.fL-#qc`bf/%1@)=FQP!U_G&OX\=c+;XVe5q,2],tXgOD:3YregJt %og)M#CXdu6-S%%P?q&jp4@/^no?S#LP5C_k\#i3EcW]%Zqmn^DkDB(b=kDJ5lM7tGD^c8YMU,m8pJ*hdBiB&4Gbq81_7ZU=gc)52 %k]u/j9@n:GCghubhdHa?ia,?gR*H<<F]m=U+)OZYn(q)of"IW!o>3[e4R_.8#\Mg\-glJkgBc(:pHQ6lqtk<IZ4j%PYtBsG#HF1T %.u[>W=KW%\OWK_SU)^]h<M\7dT@Uqr\iYP_7=>eZbiO%o-?On7<^-UU0YRoi/VMhUQZ-cS<*96\3>&t/iFHJX(IFoc?>he=L9W5; %F,.3"!'T^_7+%.,7U^-c'!6,*Xj,!bR)qq]Z3nQ,6sA8&+po_N_.a>iQ9po%!B$g[G8#UaE4pg8KApksN,s=57kfoNM%Bn9AO-(0 %=2p%c!WWL<Xsg,#[0aqO1>QLGM7Y'TRo^S8cGC7S]-s"DeYc-/4$udF=M_=om^4"SDs,ifMn()?a<i>#[CWU`F:JO9P6:*_%"^&V %QB`'Gm4i4D%On+=m/3hb32(q;7\!X-$lUEZc3o7O:6uut(h8@o:p*_UGdnGEgm,[9:4$LS=Y%Ms35_Ldb>g'SL!u9>dkG1M;-Ir$ %-]2;G+h!:\]iZ(ZfZ]<jJ@J8u>*PmP:.B2#0Vj\2UC`E:;k.V4"/>(GQ8O"6!2,Kt!;(F+^uQ-t:f+$Ad2.tL7RtIVK72c.deM"W %;1d9E$-D.@)O)q+].>Fc+?*4H&QjF:$`4:$0B$R&0hc*[Pf%s3p]+/f1'^*BLlM*FBpD5QU`N`.bD9`#`($I\WlL4t62N"6O$b@0 %(nA@9]ADc)qFnhO>$#2,aVnOqO!P+G49KX@/];+T6VIR,Ol+UVKG<COVNQSMK2=[3!p5tik"b7a`.NTt&sG%M!6d^H+^')#,*L&/ %[K_!01FU7<!DXUgQ#su$6;&r]dr))#0Wf4m5W0Wc+H<mu+q?t:]JK\eQr,9s\/<#HCQfslMMIUOZ\2pP3s!?W:c\;aHZB]5aQgt1 %e"Jf*B*F.bj[g_'80DX8Ys8SOapMftM-rLN'7Cp]*,,O9-?Y%cFD6X5RnJ@^RFdeFP>eY1hbSLh25>[EPjS!mV^&NuAmNK:DnmPh %a_?:*9d'l@p:<@V56/)AQrtK17O(J1QD@FZ&H\aniWCW%*[=5%MP@qoag['^,qG^6=&6?jFjo7PX!Qf)X!O4hSR7^$*49gOP>J3? %"^N4>:oJH!0U"dgP_1g_R1/AE;:o4]XdlUPS'7VnH"m^Q1bCkErmA&DY-e+H<Z)=T\T(HMQpF?W\Ua?/!RFJePE6FJ`0O4Q-D7K9 %/Y[6`]"?UP0=GF+0Hd^,?>[,>2WHB[KT.-*U_.U]b,:d8crd,\<9Y+q3fMVldn/TljRsn6W(!N<bnh!98tr)s%D#jsEg2#G2W?h+ %s.A]g`Sp;c49q(<io6l@k4c4iV$pP68c[9AL^1-P6uZkf<["Of3=0H^L.%:sl%Ih\.2+p:eu0YY"hdTr!Gt4K/5]9<NX]@&N,49h %gk1eL<7$INh`Lj0@p0'uGRE:&Du`giXIMG.N$Yfo\jQ;);8=n5UiO+:Zn$Z.0JIQnU+D".M$U6CN"uN<<SW-V-Uu-c6,FO1h0(J4 %$5#sWSOU#LgIIaiUCk`dMkJCk1#8.kYf\@5E4a!ND@-Gh*YopsaBn;'19@;VrI)ZX>jMMQPog1.9\`0\rPR^D(nWo/bobc/RCn?f %?MRT8o2#'JUYFaf^6]"Q`Y\;I^gNls(MF-`aFf0KIYn.,Qp&U59Y;aa3>0Gi`5Cc>W&P:4EJ##X$()Q%8RX7UV8D0[*8LcfUXl0& %_OaPM^lWF$N-a4g`dGrd_RM-!kp&S$G(JbJTmPolSBc:Jn8JGFl5p3kjQO)mVYa8Kc/^0"H[,9%]9be&.E>m0C@j.cQ#hk:$)]V$ %<oPD:7_GH,=Z-RL#9h0kj3*mQXbQn32)1c^Q$HB7\V'qdCA!;m$F8I&k%1"sMjM'`K`cn'63;uW1UgiIBNYrt_*ugF_Ve<tWBlf: %3k&-Jjm$LGRL?5.k$j",%*UngSjb@"!1Hk"L9:if@[f=Aej4$@6s,ud;sf7:JU5f.ASWd*)<J@TF2XB#mmA(RJXD\uU5rG`]4dL) %Hk0OnmXh/<>o0E/oSa&BkdW*9NE*D'Ntcr?r=WN3Sh;^1<X<rsYn.7!(i`m5NS&MD(a'g(4f)m2fB,ql,R-1g8>V\r.]A)e,m$EW %jCj<s=#L>l+$VtaCD4-hdnC0V4BbAYS%!DYZ*96*ReA9[64d3Q$IsT!M#,f%@8Kbd-RqLn,\UdjQHVH+Df*0FG='/T%h5Vm_u]5& %:$ZV^>1q;HHK-#aNYYAJ]jupFQNBCj2.=*@HCPheLMFG1'+`A+@b+tFpOP$0<N6UO8ai%K/5Is23A@RV+kOLVUPVJamHq:o/7nH( %2,L"6M@SsZ/)/c8JdQb)%sD!%-PnpV8gW<qh-B`&L=(LlA+%8ZFP^eC'TjagAl2(5j)(WsC"QUR<f?;lQ%QeqK2l<%-e,14Cb8@$ %,_1r*9P?=D)i'fM.,6;&H?QZK+_1]oL:C9-\l,R1(q`D,EFE:iAi(YmS7l22jhL&e'$5Z2rV]<djD=FN&o5k'C*ma[0Gj%ZWj61T %?&0Wu(9]sFKkCcNW&T&6ZqCaZ[[)WaY"D#>\5%huk\G3F2J$B='*RW+(g@u00=Ek<!F4u=*]`PR#W=n;YH]\F"&'rX=VLhC&=8Q! %$nJV+:IJ0TM/@I4A#%sAEn2du2_h"oHim(B-qfah#GH"g1gSU=*oq1B3f=%cpDPdH#!=ZW%RA81$*Q6&U'Ab63A7Ea_`?AMD'ifR %4qohn/S6rl*0Ja+fpbeKA54;9XU/m`&pN7_XN73Rmur^leTR,Wd3*6ap"3!?/B*6O2t:l^`#P3?H5#mCI8sph6`o]ehuA5kqHNDg %#A[cP%eGd-b\rJcjh\?AP(aa-l$)]%=f!+0CMcDMnBJq@2K5g!.2:r&?m-5kg3.%3]/m&EI;nuaL(.r&M`"MPS$`%n;SEj`Cp?f2 %A]<:%p^GGM<t88=Sl5a6.P?E,TJ<MSKDBP6WTBg!NcD\]f8T/'[ANSn18:W`o=.h%=?BW#JPu7E7NltC"*."O[:lt=c#e8X=Osn; %p\g#PQ,P8TCK3$(*RIGf2CM8IL^m+2#m8J8Q8435AuJ%T:dL21lkN,2i[mm]L_+A7[qeZ=[b]W:4CRBh9W3%]B]9;dA.NigH<%aT %KSWiRV:_!gisDJs@[o%NYEEV,_Re+QI%,t$'VU(,AjD1TRKY4Q$8IA_7U]?KRI/'S6\@0jKU9="l7DLNYjj9o$od&@Yr#emH,6Ej %2,G4]H!*,a]ijnfTk(XKpRB[5FdRgc&"(Yli^Z+=Qm!>!;!L:Y.o.,k"!0.@;fl6#$Ddq/]Nfm<_,>R_H[j7m*7bB!9anb\:?u_K %>1q+PEPAdiV^k=UD*r,Kh#>DVAT)\Grb6Hf*\].`5\N9$?^?(m+g5SHKj4^RjsC:NH`'lI"S3P1&2b;oTqR`gmHV']oYIBM(Lj<u %cRBP"*2kiaA!t:c<5:t5VJeHt8SD-[.Q]VtM[sPK@lc0OdjO1tS-cl3a_##W'6CQCI59hHiEh2j$plA`EJSCAKnb.U'l#$>\lNsU %-h2JT#rP^I02(PJL2fXt)2&6@pA8Aic"K@D;COH7<m?<"#A.H7IhMRHqQEgZ2<[V.eRE<!m4;:el%BU1(<-=Xb'7+pjZP;kXm?<u %8QW@c22LIMigMF77Q)'DRZrbq(8.H)[bLn_dRXW_R</HL+Wb?6#_*.J-+JA8_F=X]M+?MPduc(u)!#/NnnO(a+V_GLi`]K8#h6_o %6K-1$k5f7W\lhE.eAb;1?tYgeMR3]4-3k^VEI1,tAVHgCSsH5g64+:h<`0S]Z*^SXUjMX,V=VWN9[@M,aJ`po')250ABOJ;A*_\5 %2;:j<fuS1iLNI+Lm>0R$T&l@oR>l#07Y[S(eo$OPg!@D4&_$Dt'_'_jRTQo+OUt=\BGk`%G\s2aY`\GaaW]!Rd_#sebdG`L))ee2 %(l>@UXiV4$F>Zl<"p23'Q#5o?f(D5:r"5-085arUA346u)np,Y9PR'k[Nd-l7ng?9-FY3HgTcmq&^q-",Gl:3&X2U<amIa%G/WJ@ %LrjhYbf\q$amFo+G/WJ@Lrm(cFCg@N0qHmi8'L>oM]FOYOuPA2<qX>4#C8+bQq<)Y-JK,"69SduGJoSFO-j`R$je-kar77*Yp1T> %7gtU\eZ`'ik=3<#1R#3kAgYM06V@$-8Tr$kU.JT'g(D5.i;1>mKmIP\4(;g=G/SL^BL`JjN#j_$NXZmoF8**fL(f08\5jA89XH%! %K\etjm>,J_.(1?IgCY+RZ'"F0M>\$M]>`WlD9%AO0hn&3,Gl:3&X2U<8aV>UG/U3ULrjhYUis[e4(;)L2Yu7*4(>K9#$onma$sf6 %9J>amQsOT!9WtkYUK7)p9,o[ga&@K+oO9mkEjoc;&X0g9^)\pb6gQM2ZGhi`:2;M!8'FYCLI'CXgTf.@OS^9"eTP!%[EGq[otdJc %(rAsmF0-&QpAr4c%'hT2YqRj_U[WQ/:f3XNkL74C$8]kb%l@;5A!/iCBj>7:-4\e@[OTj-p\\4rLd9/Yc/?%[$%Z^Z6V)!(6YN@' %##rh/'amQ[6S.fbYEr74rOLKkB:IGEH8M>=:Yn?rB\,r1qHtZ4?m6>GGj@,&<.CooGQr^<@4B2s%3u@[:&):U5hY)RRdk5apBK!I %XO9+Qk(uj3[*qju`$r).mf=8jkq'&>R6-m@)7Q[PTO7og^U$j&(n9bpB[GD"f]gsDFc/;`]f?1/$qJoR\M/ae<52HlN\HJ9EuRWT %Br_H]C"Q-(ju,Waq.]Q'd\7WS#^)M$l@`7E2*h8cVQ.9^r*tW(RL)"G.24VDU(Uu[2+p\B=Z)8j8<,7&ABd6jYS+U]KaWHb_%^9- %$&oIN"":j6/Qu<%lV!EAOQBe>-Q0YUUpZ4r!0ke&Vj4s^q]@IsIqr6CK/GACXZ>@*+Y/fCL^)I8b<S\;F2md5G%FU'EOaKOKNnVK %M5?YrbB>*@o<q0gR8s>'iqoZj/))r)PcjbrjUW/:fEsSA/-.6JB05QDYmM02pMdVT7!O6'Q@1>hctd5!2gU]/LQ$C$Q$k:o7M7Tm %><3C-.:ddX?A'^<6(,!u%_G%VdR&d@AI5p6b0$+e4$4oe3GAO4'N/6fWtZe"XU(tqeUTD(U'Y+.i=DEcWu#r-0GEJ'VJECV,i2uB %1uB:#1MDA0(j%AL&rqK"3o0@0Qr>A#%I+56U6SGF2]K`lg\j8@T<`jR(W/C2$56\$S?H7K]FK+>j9D#*%_d2+SgDQ[a.$Z+<"lQE %`qn$"88UtoU50:tJN>W>)6OSf630EKB4\adJ<q(a$6:g.S<IB(%f$lO'+I^p%Fpt<6^F\_ZPZ9%An>HhTiJf"SM1?J(_ee]OKg(T %0]srj-i]G,<LB*m.p93:Yg4lQO87H*biX8/$;gmsNk/->.@N!</%_qj)romNN:_dof%CP@ZC>.ZG\K=D"IfX3ihR%m)RP;L%VT]g %qkWP2QqN7PR["mN,@[RY(E+lK0-:!u&SN0oAD#F?li;lJD7d*U?(KQS5.LLk';t(n1e`kQ'aNA1K060)=YWeW!AGbN/HqL#Xd(CW %$S1J59fH2HRj>,u6k=#bR0bk]%Q^qQYpuIkpg(MO`%LV<L"P0;CNj-OJfp4+Ql_P/;Po6o-gV4FWW9:PZa'SZca7-^Y1*I7^oT*( %XBMrV=k<bh=>@ZDe5OtM$(M'X+qjl0+;G@$CiY8j-_]B"?->m-lnPV/WBdnu\1:4"N<kctYgp;2Lus'S?k.5*WY)7`6-uQ5%^FcY %Y%5_e5UOn*16,'qh*VBfMp@%%[?.74Ag222Y*s55+V5;1:gHH3:rEGg]__6*\G?X$APOQ_Y?EMBE^,OSJbDC8LC.m>"iA+Qg'R/* %oWG9[V4.i:Xl-^]#rtb[h/XW-a8dk>"G.s0#c=Gg#&OF\A(Vf5a;CDTP[SbU,eNu%.oDu\dMdWn/*eLH?lmO.3"n1m?mg+ae2l2B %gRqS*ZV-fAXi$\l6P%bf_-W7iS"1o_k,0`\Z>MP;*ncm=)S=n+CdS)GI(tMH.INE]b>cpg^'a8)=Kk8sCu8:B]%-m`3aC_a6<0$= %HAS*j_8JC2"Se:OooPr%UIH"($R[,%Jl!f!U29Ub.*70@MdPh)C$]a*9t[',OuB;5]=NaL$13*PKQ:FcJ-D]KX0aJ1AOLl#8C'0u %_3WBiC3&1A<jouNrdGXWdCa!%pJKhJ?J+p90*_E5^D=4T(.V((=k/'@?.T&co7Im,COcJ!LL(RG15'hbBY8+^2Cg44#qal<M2#]i %QR7^sE$h--:Sr!P=U]'XHnoVep3]Gfb9SfYYmD`shFjqW4/&?pBB#S[U!tZ7SY3G\H]`%=BaF*J&V0GbXJ3XIheU't?3&+nbk?Eu %P:/=.%__1u`n807cL8>Qm"AIGl2dB@N<2/<*t+BL[0\i6L>C<PbUiHi84eNkNis$^I#[ct>ndI8b\,(SK0]0N<]/UnY+&#Lr/f_. %@pU\O"Ep:lBu[0WAQS?=*$gF\5jN6E>1q1RFhFBf'?>hKXGm<0:Y%8lR,M2C>FB9C>39ZAaK6<M>1lbLa1^%NPR?&B1oXQ.nkNm3 %9_Z1$W<7HjQ0l`fNA[i=4Wp`V42N\cP2!s\%+Q2:<lAD@BlDfs[RTtedBAJ[FK]\N>r]n]=\)MQ/Kh<m&"DI:de.;/:r='1;!ip! %[X]'j]sqJYC,3kL_\UILc*KSI@iM<fo5OG6SMY*!R;]he$hBgQ7?D0"$]n2;4F:lFAJWYN]WQ(Z+O<eu[NNn!%C-._cH7>MZYNVq %m/!@k"'n/YNA#,3!rAlOK+Xa_#kDfq!`C_rJ-6FX#n:0*"?d*VS<ZP(VP+B0ZA(!!M=FgtV&JFJcir2Uj=+p/!q(ZgK,[fmi<'=r %?m]^RJkk+J"k51DjOk(H1l<'hhp;Okb=@1IB4V\9g!BmZ@5Q'37i-:=W1aT61/hFF%+(5uTE8fj!m7bZ!B'2c,&jl^$T_^W/sqKH %/tfTd^sE7,!=:X)ZUYgn=FF`i?,0Us,(La@h!Fd!L+],]'d!7/Q&QQhg!BmY@7(jT`'>-_[!'(2b)UY%+OAX!4h>#J"qI:E4%Y2E %TIn-kb(_OAC#auU;Dqb;AuE$Q2KZc/$lhO1[35ac)YE6FY-t[BX^.fHXUd&_KVE9*#lpM3jB9Tr*CD2T@7"jN"F8R3GjX,eH#f2_ %#<G="Q&A*;'$XM4#u_r*fS_=$P&@2UBs>CpW7a.(#R/\Bf<(;AHWt6dAeDS;RDpMZ4M?taCoqN]<G5RXi%h+9)A(mH:$B_hhl%lV %Z6nr7?m\@1-XER-W=E@.Zst5QZjZJ!aES1LFpp(:=m0HQZA[@jGp_;BB4XB\&R1W80C6P<Ha/9M-6mkOCbr`=!C>FnH#b"*!XnTF %Es8Mj&E_YV@isjdMfZ?l)PG$c4B!?\jgm([dF"5=7[?$BfR+SJJ=Ki2B/bl@$hL0N3$Qf$P!DOD&rtd8OHs"&K!+H^G=E%k8iRKm %0[H.(%\q_kVBX6JI`dbu/^0F$(*(I&o-C"jo:q"WcM!G;k"-Gn'(uth45r-Dd-3Db]D^'o#kOSNm.RBCrTk.e9^D0"KmCt^E';cc %X?4fr2_DqV$14B"UA_eW*L%[/0s/-nKmCt^#frNM7Him8"te&?<njcnCKIEVV%52.`"Z]A@lbgWil_lMPH$/Mg_5eiNH2$Z4!0PV %R`_Yd\@X^4)d"koAJj$P/LY?\Sh=_J":l>b1/^>/Of>_/WR&Oe5\N&/$X\&i#!roRSrud&Z!%g</,F!`9!:.+'s/3?^3L/+`V$=6 %)M@m0otmjBHElk_"HRcj7#IoWiAcE0QC23j<5BCPeRUCf\.IBKLdKbA";[^9T[fTu"n*62=N.WkUm9d/5neJ/7&^ks0f4cML'6Z! %Gg#p`$>)+5+9;g(`\jFpqIq8[Dc^da-)5G;kpRH==<kiGbg/JSPoU&jbu-ur4YR@6H1J)_UTnHB_1Q<8Uor12FZ@QHLma2EKNVG" %KC17B:#mY]A.SHa-a(G&?gZo-QIINDNXXY!d/nt_7,u'-"WA)tRuo;bK%D"Nm4hfr<!?j>!D%=i>8=SKf9t:dH^iT8O.,NLQT/>E %(KSV;bC_Zl!e2ueZF8FhD&@:_AQagtW+DeNnM:<WU9bZEJE'Cp,[Y)cZ[9s+?VatCF'$gnfbWGml!.s&jl::UM]h303e1=(H6`!C %P#-1+bM3J5R6sr&P_:;d:loWV)YM+7qjVfXT_+Y6:X>SIX5Z0$q_8Po:<&JkO63^Y:+-I<Bqd+N[LJbL8=`>hp='F$Duq0==j`<B %9\CkK`FYkI@)SY%D71$l<\NgNTGM\G?PTHSempN>!s1gam=6Ob4=MD[7BLJP&fPs=$`+%A;h@3;ZF#/P-L(YGRZN0QT`F)l8jljB %h#[7FDAPS3\[F2pW=/4jd&Rn8Zl!)C@7k1L(:hhNN>sd!d!ah#BbVfE"uTP]Lo7p7YEd)EFL;"8-;69J4$E7;k7P4+R+E"LLm#c` %fbp"h,f;+IF1X)n*!54&GFf,9SZO\fdVpl!O`dZ;]]*`4!V.aRpu(4>Ktu<fIX_@A2M8tkp.Fsr>O]O[#]""Bg-#bL2l%0s'G>R; %BOY>r<[aMU:+I::,m&!gDb%?2*NT\O-us%7!bUT%TWeo3Ya.;B<&dpXNb`4d!+<*HD8Oq2nn)@kaDG,@9m+[&'o3mtD6%G&fsfL2 %Y'%PAT`rQbO>Lq7VI=B&d<4FflBB0kgc;iI?$o6RF+bDK)q[@uK2IYpr-0QI*Fbs=F"t[I(_^@G81&CSWR1Rs6`hkMVaWedp&a#O %mb[l3l$,k9+$9W'>#F31B0)6[j+cGE*Y%>UeqsZ6X*S4@?t2oG.)0R\]<QnjB_*gC,%K4)aop.L<G4\N#ioD;>/3J(_/q*8P#ofS %_\)&MLHNk9UR].sd)8J@bt1V\C`^=agnFc$9k@%tJ8iO1icr*TRuqA2A5Zr;TS](L?b=Lk?U;4iK;^_pSt:`$j@>u/De2E`4#Y;I %"\K\u&<`%FZY8\3n\(%fJ>eSQ(P_`-HK\WrDlmj%%Lff,R4ra@MC'A:IDtM#Js$_F(6!JY-aVc1lju'Eq.(NuJlm@N6u4/!D!6i* %Xd/S4iuA."Yntsq\SC+nQ.p#DD,;aPfd2.PXi$nVg^huU_#Wc]OMh:b4<lnu!Tu?K0pU\_R[&jIoM;#Y#djjp(JP=$mS7Q)#dg`= %Z"%A6C>5$@S*M$O@AOL5+9/u6*AhDSY)DVL/3a+#g<6t_F2M)J*pu4:G4>!7?iPRfq=WU<9!5pQpupoV3iT!+5QBn(4g]s_LC.?i %b7?N_hOjf:bp</K@U+;bq!49a@[Fh,Z(ALp*J0*CaD,[u,%g,s;/`hjhS:.!m"5U\'0(,7-r9L:M/XV-C.$@b2\jl\$I\lT-e+$1 %?5$BnBd)oJL]c%[M(-MpXAZ])!;3*f$pqK+=u.;8Ir3ct:.=K=m`.A^<buPmru07ZK:3KA"B7%8iWBoGNbf?'[n8tp$)P?:LMDKl %(dah#KjoOp>:CMg$Tdb!PE;=^2hZr[J=2RK&dfVQjX9RXA8k-i.Z&s@F*2OIOT^u1,S+A/E[/Fu%d-0uRg]Js31H@2IoQYNDgK.f %&p+"Zh#'IpN$V[<WPX4SSC]G$l:r#rfI=Ao/B\r#-;'R]1-$br/-R@IUdcn-Fu9=O:>G^aqeDhO7(scXEfl==D.b7TVbr(0NeClg %UYKSr)[`DKPdEXdhnM&g?hueD(a>$9,i;@Vf8pOFI!6i9)3;U#rZsa$W?2hc=!HiiBMoQO,Ua74DsCQ!7VeE`d"O(f)&[-YUphd@ %cV^d[Em(/MN&j(cN(^H%;Ynto7RHW-PT=PTA5&9%N5W@8L8eJrlqTJQB8NQ:!=>#@d8Cj/^4oApH`K(D;elAEpDT0*+Vi(uF6G/. %Es"aNC_:;M?e3S<U_Hd%FT%4LS6#,m,E=3JHs7Y'X$"(PDqOlu-KO+u"a-8?Hu)0_&$]Y/WZ9SBSOd95=]]]EO6HF0Z_Ig9'@P9m %+NsN;)L>;IYDVePLttc,`SY%M+k$>6RPj!Z$T\jf0=N%**/G\Wrcq+)9$&OqB<:m"k9:op`G8Y_3fSh3?R]qj^_]H=,jFoT=qqH[ %]\W3Jj#_N)n5:WR(A't^(-K-c=90e5k7&U>Z<pR3^kiFU)frtD-8BSV9-WKU,\%c>a5T0eS1\@4-nOC]&D`PsO^BrS)@T%Lj>9E\ %;'&l1$!bBn\6YjPQAO^D"RSE..i*Y5/`Bn&KD*Jb's9e66fMAs._OJ;WUn1iA`?sIT6dWST*ZQ[H@+$i]UDi*1M9CbEA%Hs(ml6* %S=Qg;e"^E+k;\KDW$PLr1Ktk'MT`m$o%2ekCj;Pi[-7`BW0Ch)&lul;^nK$:&(,-8bc76Ad;-I74u?EAO/%8!#X:0QadSD4"N$9? %DA%0XoqH!S&I$#?;4O,6($+NL*F4LG`64;T'XU_56@*E-THY656'*nFB@<H1dn]="4:Yh++QOJgJk87"*^U&ZZd:Wi@hq]@.q$,\ %#SR4>-D@mK9MQMi=b5mcY_Y6)`?E.Jb()SQ^4uTJHR_Tc*PJU:cU&VXLg=u^8Wq('7,4qiXWeU#((MC02;6c^>F$NC6sa5D?a2T0 %$tm[=af(a44\l05KpYB@Ug:bq4TsY#8N\$Z85R."^I^sl3_S8E-ItaZ1VC.)(HSWb_"EIa+QJq^aL)a+j8,RI+%KP;dI@nl]I'f@ %`#Ss9l4R[o(d1c5<1^jedKkd`-NUii=?=G&5K/[Y(:&u96Ee8i;R533a@r0`0qb\GlHQu%hU5./r;<A04<WkubmGLC3lcVAju(A' %_oQk<J&X_8,n<X%bZT"B&?21ict(7d%`5,K<j-p&eh*4$!6G86OYqdb<fUm]KOiI@ka3R3_.(+QOFjHc:)"*c@rk\?m3H3i&N4Za %$)n!_)sAOq8NLJ;E$>BQVjiEWaYF'B,@gsQa!u'k0RZsIMolpan5\=R=i_7Y^?PjWb2OUDGg[rG9NYD4<>h^3Onr$OEE6@q_h2_M %a+`!_mPLsam$f8bDB`L/nbW[e@qg+Lqo7#&L2<H<o>5#Dfm#/K26!^e3_IaY<`(QlNMk2?8`AS_eOT#S/9bkFd\TgTT>c&pdc+f1 %*0KU0_KP2Ki.<9?nemr%3`JVX3Spc\<Cnsr8]]Oj?@fTk394W2AXP"d0T@#'#2THp*).^.1MG2TFBpo$W@TNpihF6;SYkTtil/Z0 %l0P1l,SosIK9sP&k'W\n6DD+`J]p>r)>2QZkk.j)+d@]q#XHa_6+$p]6Q0m%X`kCG,XWg&9@CsKT0/'-D`ErB'<(.Hb0deT8X<I0 %R=(uIG"IU$BW2.qi;5d?OI4:pZ4Os*91jIqb::diTPMMf81QLLcTBZLfgU%$)dsKK@[NWbO<g$O;"UN2T@n?hW^3aL$PS.bkY?a* %P/X]I66Em8bs<t,FOfn!ZR?)9W/duS=`-j;@H(_<ds-s5HQZBQ(+6!lj.4S_!K/Jm17gB,2b%#B?J)?[ZQ.A7=35:Q,tgM'&BZch %a,a=2FjUPnKAKs]S"r].m,OTr_A*g.RV25B%rHegJmb?$XB;(ijsqELoIs#P4)Q+$>J;:(N39<E?fZcO\Tk.8>:8S1W=Nr]YjIOq %C=Z?J*=@R(E72404E+ut<_R&fHLO\99K%;j"UAJXdK1fdF4g+&1sU;P9d%Xe'&-`[D&B/\j(RP;>jX^PKqO.=A!Zale'>/d>p;FU %%W;\;Neqe(^qM`uMIZI1?!R%"Lh;.c,MEUD4!VVYB(mG2[8`g_(.B0u<`Ln!OsnC;7ceGk-F#`@-n2jT/19dPr(O?.f^&7N$,MJ5 %#2eTSb%a/j`C14*_JrE>7H9V]9M3mqmGoa7:qNOWj%8J#W.rP.;H4mp[R=5ZjiM5n.8bVZLHs$SKmZC8VIbrHgD>,EC(1m==+h%@ %WE)\FHMk&gogm[2FWmi9bml>SWBnPC^1DU6@:qbnJ^&p#A)!>nm=8Rnk>HLO(b?+D[MU[M^`nmM.B/C^E\''4&fF347`I19e(1aY %+m[mm9"MMVYpA2g2H$^,$cXRm4pQRqbKkP%"N;1mQ!-eo.Lm)6!:)BI'gQ?T9u&\K96[#&?-!:)&HDoQ<`U8WD"SkoKXtR4V(t3f %9gOU?YY2Oj7KQuoBL=aUGQ@M@VTfsieqhl$e6Xm8kYCHZZ;Q+oLDL@)d38Us.3LTr"@cI!(*%Ro"A/Mt7V>5Ld@n_l8C3cC:EI@C %//)b20A@h3@oY.412,mk#Wi"u]8cNAQ<.&Hgq:1k[H4-u\\1L]n;`Y8<&+X/#R+`.)V&!2'MQ=kB,Z&uU-_s26W$.B]4Rh:!N.#0 %R+dHUaF9oCWX9jX\5`e:P>e13UP[I@innM_G:AH`g5Ba.pi$uaB5-XH8h,c8b;3EqK1+f+R0P4+[nZG')NmqkpnTi\..Hf=R`*\S %;7.rRFD0>9@uR#$<75TWeQKb(-[nAoH<CQrDW2q3*Yh+sd<GDkMO`U=&ACUGMD^-q3^9Vq%r?PcK,?iCrFo"sW3t\c*8&Kt.(ua> %nWP&=Yt.IuZ&'5>P*j2<`dlJJa\bi;;aeJMB'5>cNa6D!+Q:h7VC*V7S=WYNT2k_\@O+T]@"<h?1)'lPTjmUEO!/_5(gj>jJ0lqH %iZ7^_E52cU![-\6h*$HY^mjMVS/ij3CnVRN3'N\JC(=WEn%`4r`b&?!17XN6]9K08bD?3[]_RU#<_Dl;,V4b8+8QnSAXtBFMBXSh %LE]/h_m#\O!FinNo7[b*%$V9;;.+Hj&0?_I5\cSSb>Gul]^eW<.-:=l:%MMlE4hP,dA0*78-Re3,3CJL2_Np4`EEa$)'?3i7FIXJ %^?;R*LkQe<84`;H?5I]U[Id3]em[fJ,L/>h`#RdkOB;$hXHk==AnBleV3La9@V3D7PK@DcX9b'd+b@^Z*#Lb+>>B(_.m6\*n+3*% %KOiIE[K_'CA`RICH?V,!7DT67,V>CZ8\?oi81GRD2Kk;iS8<*]R@(;:dq-BHKgYPnBZZ':*,&iMKo(N?m$F,=J#O9ncKsX>,"k;t %7q/c=qdVCM?O*>qEjh++/3#rP>mu1EE<1qs7b0h+M5L`<#7";0Wr5XNEn@h(:ff`,R4ouP%Qc^ja!nLU[->E?P_,Q%=\-=Mq0ETK %(e`gYU=1H$h4BUc1Z86ICC`B3\D"r;l\2o@*>Z$0H3eY?V6.7>co2AJf4Ar"((Fn,G-HOo1J!IaM/tV+^;1*hZ&G@i"gR'Y&F!%; %F#3*&Om>'!Oh-lKoh=XZTKI@L]_6F_.?hh\eT,+6Zl7TP84eCKl,Vj#8IbD,6q9Ha&$//p61%%.,q5h#"pK[).r'ef&rHufVIm1i %:nm"bg*@[-A4T"X,!#pS9q[GWL3%?8JRDSjRROfQ:kErtE^d[rdj1p6_*g[:*]oT8+PYGF$7`WKDH1(cBl7,R1!le>1EIK/ZE8Y[ %GWtA#@#mE>j^a0?B]r$u#1LVEE2IcFjR/+J_N.#c1^WPZ"Ps,2>i*4u(rH@QBZr@id2EkR_&Go(U4cXf7]XBQ;YZ;NZAM@E'Tges %.Cf\L!HW5&_imb?ZG"ZY&c?4bilqKj?nK;:TNs2\8h+FU*di/h0/`lq=Q_rHa+FN?1,@YUO=KOT"*oFDj"jjQ0_SUU4^Ke])5^5" %:Zd6c&Sui*@3[&B<BUcgR.MVNrH/t-8Z5)rE[@cQOrSr`YsRMe01k'n!tIOCpjR\&+r`?,\mAb9,r]Qj*CMY>!;m\l$/c4cEj\]3 %ohN^iU[=p"Y9j>=kRB3pa#.(_&4/fY2O]\SLqsc>2>)XBiABIb;`^@H15Rb]M%C:%+E,_0P/Er(3HMlue_:=[7eCgi-,iQnE!F*2 %BeT$K`C4:Xl"goDFW"cV<h\:k$2]j)08s%sfs/L*2q,i^P8'YK7u-K!c#a#WYp5No$o,V`B^Cp;RCOaa0UBB1@Pt!_>f!flRU;M% %SoX\G,]d7A-q]a=UCBp5T9^m]l7-:COn'X8;-g<"5`HC&#3>7ujFdd!@M8!E<nO4Gh]JE*0Tt5ZA$DZ/E_tKa9g$,1H-/O$'aZ4= %%UaQ)`<"O6::lJZ8K<Du=hl';;^)BK"+#H2XiT:h'W^>s!FqC-R6WscKfg-@^Z6f4Y,h,j+"Q4JoE`uOE:dW7?st0s_:*0DAfR]3 %X]ACRLLb_^:fW)b6q4eOON`pP(e%0GK3=g[D7Bk+VX&khehQ$IbgZs?fU-2rB<d,Io5kQ\+uO-Q=2%G\6c?7K,XtG4H0G,TB#,Oh %7PR*Fg_n60@?.=hB/5=WJ:M.G5u6tB37q4WTMt6d7b7mu38"S1-`U)]2Igo&_F;;a5!Y0O$bW2mj:KiaT:Ba/3@=.Z;>4@FQB&a2 %<^\McLSmQ-DA=4*(QVt./^e5r$15=&gD4p?[-oel!.Q*f;c6A)(?2@6=,N_:5;`S&Bn0VePu^X"H9R'L4hr$RMX*$4jY-`"EhSLj %Z<TEu>>T7Emr$l_f[jZ8E*KM"-BOS3CFIV]e]L+0R&_@/;oJF(0KTVBn09&jF_i3PJlX--+_C_N192#V]j`EgFg-dY7m>DrRBl]* %Z[;;59Cu]$4k5FHVeS'['k`(4QWP&3k$aRV8hu4gO$4k*K)^l"7)Ek9:+c"nEDd<e&WjI`i"F@8W`>VJ82NUc3R@21nu<."!s(`M %0]pl*I2"C[P-5@sP"#3Dab(GH5[B&q:V=T)&\k8SNI@2:.`llhnTPItX/%6g>A'o\?V<gReI+TueNYZ0.>%[Qb#g4c6*N'(L:+\2 %KJr"QPf,HjM`tALi\;YP"8Ih[-`&I_A'O#5QS$XcBG+cR8[q0LK7I*&(Uu_5j;<(sV"Wrm\ihee7I:t7Fll=V$*u@Q-,h>>asDB' %;Mki7%IG(YL)@qd%!5($m5<)qQpEVTh@WmL81N?tJ&%IZ\sH4poP%tS)5`[qadL5bV)0bj244UBdnCC]Qa$:@`9LF`9nQ5/<mX!) %GUYH<BQT6iPUS0eB/CHhX""R1QdX'S$l4,.bc!l^W?C-$l/ip:YCaFC)1C%+PN@p$LoOm"P`X"6-dlCeqKtM;PZZ9T4*knO\Whch %LsqN!IUG_!TE[6Q<.P+Sp2MkMnQ@CMCkpX#&k/E]r#!HU0d_q@+J*:Y`NDVu2r60`#I=q4C-^C8VqAK__WT@+*`\LG\]%c$L>Wu\ %!bO/]f`m#A'eBcODiiJ'kt["QWSjNY")tbegMlOd9+-k8OPC*!dk8Le_EnIW@"/aa(fla*Z'C]PP)Lq)Bi>W[k5gHU;:>WO/i8Q. %/#tlm[YR^e6[<DL^uFrnF-Bp1g"qNg/T56Bg.e,[X;WGU7[.*tM.7B>6dF+cH>+$9kCFETSm<H%9OX:m,Q!AdVa8"%]G.XBC-Di. %F"pfESPf?I,Z^QA$,pGr92Tn>NX93sMk`sH\_.tApJ2-R-GPLiHnr')D3e&YTm23(S06%E-[;=/DIjCah;nt@QRqPaVkQ7P_E?%s %N[-RB?od&]S]tB/c4,XBQQ:e]$[CZ.7`[lWJD"Vd3D3l14`XMh3G3Xi$9G7'W)$/O>u\#\D6%W&nhF#7AjamP-X*9I2/ij6ZN>uq %oYPXVUr*GdTI?eR@#OB";k0DdPVs#n\JsfGRDB6u(%b-'.,\A)r&PrT:4s5o"%+H4Jd+dp3"&2r=l'Yr@aO.JYW"S;nj`l)_&,jJ %&hsI</4Y><58_R4QQr=L,[]$Y1kL8&^<a0"a[rZDHK?DZQ/36FGr5";7h<5![1<IQ`u+k^,nI;5H1@&m8^')g/bR;DWIiGF+GZMr %MUhfeBRE["HHbKuHW)%N;dT/9CI%>9g4lG?bn+?03k9!A_6l6:h+WbbaJfK$FsD]E:eA2>dr*5B#:OO;kb4.sXIoHY<Hh2m$`]<U %d7L!$pAN(8J)5NF.iN]X\n&?p30$R65j0c[%&eEEOr.?fa:Tq\K+t8ZU;H3<LQ<abTPLsDJEBCS!ZY1Y,2,,\<IC!,0PD+LE/s9X %k4^81@6btZS*W\eY!"186+^(b"G)F:)4q^eeHRcm<d=n,'o:Y/#:ckX/0Wc.qW?Fu_,kHY/ZHLE8r>Wl,&Q$k@Lsrii1k6)eG$@Q %[mk]kas2HFVTph<DlV5s^@MUS+S-KmWftjD'OA\2qG7`V3Lr(*@.tMS.C+MCYj<+"=r99=AU@6%d#L(?C.646gj9dB_m0mRGVV_u %Xp#jqG`^A=lDuA7dHD9[;)0=@"i/6!'=/G7$q"9;+^Gse=^`IEYfFmP_dJOk]hh9\`-*Zn+p@_-4pMGV:/VW6,s1A;C6+l']LPMr %BFf8EEI.G:FcWaFQG'$p%7eiUSuq/42/=Z^M%K6b_,YdqE&%r$`6C^-p$?%EnEpJO[7h+F@P&/,/U:"I"JX0Y;7=>)35RjNL(eL^ %]hpFli]%AiP#++[9g*IA'LO,o!#'"QD!:3eBq^W)d8Bs866meG>9edUE),rP6JTCrZI=3D3f(;f(-S4![*m<KjQpY5P46H'oXZsE %:0R>_ar1W&/s*p/qAQ5]9V`SWQN3]>;3\%W&o:n@P:Z3$-\KDq_I:kBFsmRM,W*?Zp:q$TG18"-StA:e/=3IL]8jueAgW4+Ta"MZ %5bhK<aEKiU>\3:#r+a[BN+E2-a>PpW(bPIQo6VUc/O'67:aB0bc&L57%a;U5djR;N70'B-^^p"_.Yu*$`FDF,"c/`glu#c7&],U3 %XG#A]22eWH7`IC&fMB4R@(Z^=$J6^i!cats"D`,ho#(B]/;>a3Y6tML;.!,,H.lPnaOPFid$,I2-p`YoEHHo]H)N$5E%X5RAOQ"X %BjYrjE9F<I@k_)<Xp@i(%)UY,][TVL92TmH&gfjdOJSV=)i1&Q'tCL_Oi/I.G!$)]q2HX;:nSS0p.@6-S!?\W4/_i"V"n"Y!UU8X %*$[E)DMjkl$<O2A8dC1nTpMi$WRZNNA?Z1c])kuQ<7G0gL.1RJls&qr4.0ojF$l&kSdj;!M5=%X!(a$81K2:-j9q>]Zkg<<OenI3 %_";+>?5s)s5kkh?.hAD'T*(i7+t00YZT^D1qan]73mL&%e#?`t:f%CL3\/9%gn9K58Xp!TZ5Pko$Ii.q'T]+klqKh$Q:=g27o1Pu %=;0,)FJ'FL&j6`g8RRa80:&lG<g6*?M`PshVGU`#X3lEC]FbGN$iDA8C)#LkYhjFf=uD%CLT!.pdHf1O@X]h`=CJ1^YTH0DXp:$G %\0YFO*oj+_S8c^CV(o$er6^c1N=*T67f"fB5XuBg1r3g_4.;GW:<kh6JbV;o/s690=`1?[!:PN^.Pc`2J;BEY#[JPrgkZA5(;(*M %d47PcFNO]Z5)7Ps%:2M5SQsB8@Bb)IO-W'5EtgMcO=(+^a*nRGDOB>$0'[uQ6D,7lCk-#2JH\`pHVkpRr&2"jVhZg'+BPWH6p<R: %S?lo\&9kil=';m:2n7:FI0Q'53V("uCb%LP$A\C$`:?O$*k-AIXttp5#QPmmbo%\EF@pn.LN"0!Vn,&]%j/,?e2cG]^p:rQ<sIoi %B;Do=<PeJY$]0'-R#b*r%L\4TgkTIfkW[bF)>5XF,AA23[NkHh6p*J#W-9hJ<7c#KdsrJ0mifPIJJiQhTI73VVH^tKh$F)C(+U*> %qp:U6qSc^XA<kLF9(!,\R1VJ97L4'7>6hA#SSP98]pI--'q%Qc4^518B8uDfPSGb1I4t-2#hr<?1I\t\m8ge"M[u[XA4g=NPGkg_ %i0QE&;Tbli'G@TAD(MH&cf,dET>4!$c./Mmmm?"Qi4k(kbc0'B/Ro!$Y.DGh4>-u_Md1u_FI2hlT&.78Yg"hR&V_Zt=J<f=?Hb+@ %O9W/E$tbmcYYMIi1pb20&Wrp1.qak@-"gim0o)dCV9\"aFbR.6$;f9)\/`pm-<M+d1m!S7J,$9Z?@K1m9n.JhGAH;.B<#AF.M%*n %Y_PrH&d@e\1_9@0L+*XA`<!</q-2KC8G51HGmFRX4cGMhAWgPd0YSd'#>QG_e-ieTnqNK1aFH/si%2^m@ql>je0W<S::7o36Ds@G %RP5-\FkA)u1K`F/>!^6^:]+1Oa35pNii(64AH"2Y-QOt9n`)]E&340GnXu/BNbb<VJ;dS@T(O!c@AkRAJ:Lm`=]R,0Q0QucnZK^r %:>WM,[%pmrL;?Cll"-g:`lST_KNL&<O)4e.ETIXA6=OTFTH7A`4`tujO[n#$'+do5VcMjD5rM`rNs?="!+<?Ee5d`I)+rDO3P)0o %b_&1XZ%ghK^Q-sB@rlf92LUhYaC'^,e9u5a\"bWDY(0Nn:gebNW*k>=&=^U2#>:(8[&?qeJ9#GPW#u)]a=VIhYYnrJWe`SMTHM<g %fUXK:>Oqir_s!O28hm!HjYrdnYbD2HcV]MI7"HfLUK%k`2sP2ML<=F;1-OJCjHi+Y_N%97iK4tVD1f@@"PGL0!hqDN"9E3Gn;--L %]S_^M@7V$(0q`o'"&74DZCM%(e>C(B2*uj\bfPgHcm"(,bK[+<-ic4HJF<b^?XY!UC_GP]a@Z8.b6!'X`AN!PPM)4h93)@4S2:-W %I1m8"1,Sh?E<HUH#p+2U[FoFPSDuqJ/[GW`nlZQPc`,2(D-.717R:@<R:r9fr,coF;2g%KA=QoT?lr')X',`o$d1':=WC1:?58Jb %"IZtk*"8=_1mSH4'TjUSYf=bn+:u=n-1#VMG>[Op&^/KWF/aeKR^J*&#9/&WG&Fl0*iKp5lkq*3@U_m,LA%L^.3sRu!8Loc7&c>F %=:Nj7K.nKh7[0qMb-[<gmXl*D0L4p&bD_B)68ShB_1pL%i-oa)Q*.u$d:uKTfkd&00Yi3p)\&5('rgL[.ki,9p#59In5YX>XFigi %(i8HP]4pJTg:W$B=2Udh@/f?EK#KjFe`?P-QHG1.I03qc'gf5j@*b2m&KFV[cWNsA*UA3YZ2QQN,(@7Q/V*ogX0_%tU@aoR]5\b% %r7*e@!?YQq.^4Z.9a4X<[HZ%QETmcQ.]tTS7)bE<Kac$kVo?hd4duBKZdQC$g?^Ibk=4R1.HPA1i>mWfD:AM93"^I>n:RD![c3Ro %MSnkQDqg/hjq'pJrQ/#*lr^)i<g_Zj:h.TaE5lLN#Zeh!CUt?<@>k/=N#`gL8`3^UrA+\W,mcJq2"J4W,B">20b84-=u+3BM_6<\ %__&u'5U$906#OVW8.Z5iS`J-\\_DG(W<?bO%:XGN%Gt>7]:bOR`.C>)>6?A><EB22AJg;+o+hUs.?He+UNB-W(?qg\E"]T=:QA]r %TeIre8>k+3$ZL+pllRIT8OL+co[bA`hupa6QQ5Lg(;)6)!abEqB"0G3k5*5B\bH4!hjO2qRJ,WPg80kV%FYm/k7o><*.CtXMQGf0 %P>O/ABf\jJXu%;ALgPI#MLqm&9$qUCBaG4bS!`dLr7po;d\jULTLMhK]02D\o]:Wcbs\EW3R@q`W%lmKcSY']l5^)]klIUA0%C5& %-CPLlN"\NY]da>1JF6_"2qI70%)s8K1:7+)*,Hp3`+$&Ih.Zi1@ca*ur;^.O^l78IP>SJZZtZKHe2K-&!?NW-)B/Of8mXda_GY;7 %e%Jd*h*[Zu=hOrEc,6(8.02SgS"ao=dR.:rhpAMKo:NH%,<2OSWq^U-"jIb%H"o$@'V"U3&QG'*jsD`r-K/bi#6lRf='h5;e0>[+ %.!OiQS@BKO8AQSU3!7!3O>0^KZ'sp.4VJt&@9<8,1^M!Hmm1Xh(bF>pabZ4OT\D%oCG8B1-j6n9`6g5H+KgMJ*@*_!^d-RI"To5C %dSVbo49[-!3>I1cGZ,P0-q,][8H0S2F!./5B##Rp]$)"i,bdRaV.ebB`_W?16Hnp2gNu`0o#,hT>Y=VYQBpoTD:(WMSA3am=R.42 %9W*II%s$6)?n)0,Qd,/(/V'q4p>u@^T-9<827H^+Z^Pem$sc$KC-IUi3\'2q6#DsfEA0--V>B!TTZ>".(R=RAFi97"6l3IS<AkO& %ECjPKA4/<QUe9:Xe&lo7'aV])AjK<eNU%g&F>i_o!gP-M:($#lbBHo=4Mk7$L$R-[D`fuE_^=E-"[n_(G%]j&g%R@'>k(i6LTuiB %)M)>pKV;Ar'T7Tq:P*">aN=e>=4"==k+a,e[piU!#R+OaB2idQeB87]:e48o!Q?=e2PV!"6a-Y%Pbnh>ZBR?W&Bma$A.EAu"Q;/l %./76TrUj8K]\#8,po-A`L),"C3:E@uJ_T)s\9#a#)FdZP&aD,27(t;oZcp$-E&eQ>acZ*\*%$Gh!r!--.Z2S%<K89iF>48m0a[3O %k=h\ZnST"K7>WU<]f'Fh:(lP\7Q9kF8T1gV.s*Y;H&MXi6F`4F-7S`f6%NaFab521H"flcZrK-mJ>nE&UGN:/#%[IYn7.&/qOo>< %&2>%c56Z*9hMqG@[9*NA20s9:=p'H-KFBd>YlT^-,8L]l%eOh)286E&JX2m>Co+J14oaScl:'d-e1C3EIiUdS0dui4!ICJA!f][= %`,CK0X^GPh:=Zks#j#co=R&6uJ=s0-><j:ZW8n4KC/bNu")SA&>2YKFr'OA7.b(A$YokG5\sA;t:`(bV4P_5Eq#,q^:?RT2G'Z5` %N[aBejF:a,Pio3)m'(j+(%\s@T9I?Dl12Xrn=B(6lL(Z2c@QLUn2Zs"M+JWkjf:Wend)-'6$C%*'C<e22\Bk?IQ0CeRj6:29SNO# %RcfAKs#%*ZJO1U#KkL'(%Nn0:d!b&8Q>gTXCCm>4d!?G%o&ZJVgM>d'gh*ceIMJluONa>''%ess?+>TXNo$OFCnrRhQQ7#i+b6=, %00,F)5!+231#!6Jk#Jn@l-eo#G+Y&9>(*Vnb^o<[>Op?KVf^:0q#s>1^9H$%UNMY?]aD#sBXe\_K;c9]\H<ONRbg=E>_V*%1hZl_ %;EWUu<GWVLWu[_bS?bF0*\p$C@/8.dNN.M''l(Lq(9-RN/JKL"kS-_h=JQF_dNgr#6inm7Mqu;a+Y'Y3'7iaiQdh^IiUm%<'_]Y% %_=C]j2nl[e1YgDITdK\D[7VQcGiH94Z]Z?^:dJ0IN!=U_iq2M<om&%('tt#'\,p/oW%_Chra8"@P&k%0#UroP];?U1A/JOJJal>n %<CT53Pdue)1.&&jf5:f/74<"J:ol,@0FW&c/^4>[hi6H"PrSpb0$g(3f!Hs4B8DGFZ/$!kPrHY"VNaM@a:`B4BJG8&d%,U.%!"^$ %*\mYXS<'<sBnUVuE'\0Y"r,HS][7WQ8JGu/0l=ijD88VtMSV3DCpE_63m)DPn\Buf-iDXc_\!*B'A46$.#eUp:FAP$,#i@eGnl%5 %PD"%,2AO[K'r>]b%t`_L*"=m9L(Ub`=@8<i`1Ch_WQE((3^TW]Y^E'B3\)b!8B/9(gh=RS[bN&=EWWEIO$El\!<j?RKA0u2ai][( %a])(J?.&9[J1N$X(aL836uQm.luad-8qUr></db3TBMnNl)<"g^?,-cMjQ2q"E6bGU+=';^&h`"p&1^992LHqOHr/N'kg7E_d8qE %"<+F.>p:c$6se;:MTaG7TG!S=0S+u%;j`Aq/!62a`C4H6^9B(oLr]^IHj(u5S$A;,1Vpr?!hBWUO=Lm2i"3I$V$U++J^ahZ`[fE) %5fFIo9`Xt!!jr>6>b9^R%a-BLRtuqP&Y+Z7.oDhpU3?d('3t0-5SSf?Pk-"FP5*[o+-X%-"Jt_JE#.4DBnK/!O]!H!N'P1B"rCr" %27A!g6%p;<fi6nnMuq6:@:N[o$74FpQ6If]7$f)IY!eX$.O_f1hD\;&.rU5ne>Io]Y&Wln'sDs*TeA)'ptjdslS5>59]e8lLV^b> %]cK#:0t_*]'F/;.ZD)ZA=b2-\Bi^r\]q/iT%=3E2=i"QcoIWP=1:gl1<(o7rH>.N31t>5tEG;_FL<I1ch+L[d=i-N&iR3rD9uWr# %?_HBcZnG.m'o64i@ZC3f+']u>WMm=)Z;[^3I(E8(E.rtC:iM,QVkW0C8Pc&>$>E:)`>'#X6GXC7T8JLUqkti+<LJG`)/l7P&NV$+ %lqW_"8qkqcR+q=:%;M!k7Rs/M0&u\jn=s`]/J6Fe\#I/)/P@R<&SB9cR,nGdiE?^l;K9Z,XAEnj4KP::$CP!nLF_Fp73/OmN>6MO %oDrr2RLt2DZ*L($QigTH6)h29OP5d+!H+I.\HE.H)1VaN/LBS5>Y@GYRF.ct0o7TD=^`3\bS5dcU:UaUkI4DZP"7bpVlB?VUVTHB %OO3W<bQ'.3f\r"T"-;MRoP/J_@N3^T!^_<qFY)B!;8c'M+)!HD6\RO='VO.!k]NqZN^q*#K8&!ZN=@9O14Juu("o)[r.0e3B;kKh %[Pj'c_?'%+a^khp=3>-u.P@4:<k`sHN4,J>.QM?7_j.O]MMeIq[1s-Pa_WIGY*@[A<*Ula/ZZBhIbQN_oL1RkRdSA^\A\tb+j2Gu %l10+;d>gk4\j[>dTBd72/t_MH'D;e/DP?%s)/ld'YE8>k.^"m+(;&36o%qMY9JKY$80<E(@H$Da#>lN:=H[o`8N%:?Bpe0CiWD,S %l00(hCAD.U@hY\3;rMN-#Ip"/KS0r^,-kE"&<[T6?RWcZ"^SG;AJ&h><#^oB[!3N#`_n1D7c5j:8()o$PJJmVM&V5GLmTkUkT(BN %i['Jq]5^jK+G7_1AmV8+"0gT#nc_D"<AFd=BYAf=@%?[C,AXNh(C5@a#,fi[5tRlj3@$.1G*SGD:/r]BJ`L5[<N)9(8aa`=B+i4- %Kr.hR`g<K^:(g;T&IkDkl#C3CmUBk>6M=keES:9/H:te8#%M>V64RM\<N_G&=B&NVO7=#eqI5kO;8"L@15:\0B/?t8iT9YKA#*?9 %?r"m7P3-3Sb8T*niE'ZP[0hQfIipg6-Uk2JQO^DgDfA1[[`[H]L?*"kbgjeTU64r%R=nXJ7S[<&KPd(IBp2QIG.7uJ6rnun/fP&O %C1_%UaHEVM7o3QsE!53lVP)n=6<M?3k[mVD![^'!Y)!Y]GY4m@M+J3r1]iHnfEM_(2Rg0A:g-jl[0g"s.q7lrP+\6`)k$dZ![>00 %_6Z;V*)];%-cs`::u#a94q_V:fXB8#>*uJ?Eja5I6c&Y8NR6$IpiZGNNC8UB8/4S47LI.0>`B\9*F\V->&0"<<u/m`ImItN'tV27 %W09@_b^qBV=l>GI+ek_hje?jfC=2(>^8="5jO2pH!i[V#_($N31<;2#h,IF0j9YGl]%(DWJtSkDUR4^tDHeB]b_YSJk,F86)Vik0 %644)1$*lY9>=L'goI`*+!.YnL2n%[a*VZMh<7m;3BObsE6r$L:5^AAR6$Fe`Y4NFWl^>B8a*kANh593&ft3s;$Mh<Y8:L@ChGAd) %X!?L"*9/_B#fhb$EO%P9k0faa6O"X7SeFFR>>`!-*+jT*SH9>i>*,0$>K/$Z_2l"qA-Di[^<3hi^k\q;+;ZI5W[M;.E1Vq,)Qo0\ %*%Igqa3+^F[jK-n"LIU)NBdSmNgm71@qraK#fl'[!]+_PZ6eCm6RCB9em*6AO\RK,-4)7q[kTFPaGCBA=3-7/'j0gTf]#jY\!eo_ %/Hr6j2aTrcH?(j#%*0Pi<eWRjLZTf8_"8$M3KIA,TJ.RM?"*@PV2ItaTdS;1Uo_r(2JeXt'u+D?&QMZ0R\*l6i>_?o_po\rj;$fr %;(9c0$.eDVT0gC<C3?F1XnNT,41jV_#0N)NcVA*g^V3+G6G)&QjG82sI,(`@'_69WnVIDT5S9=1qlDqmXi1Q":VP*h`8#0$'b;$! %Rjkp+*G!P'%p;\W7(.B-]Q2J"Qp[pm0Hbj'P#kQ*KC17%ZeNE+%e%*F*g1Gm\/FpEPZVmXJm9R[`eu'`b;;UKac`O_UtGV'Co_ME %-*s&G*\&!r_]KR]@oGpTmXr@664>c.]&g3STW<d6#WUV^6cF-a@Fo=K2JZjm>shYlj3Jm:?R)A%MN.9$Ru-Q78b#MD`UO^RUX7<s %6M7[(GCiDbh`&)-#<asGEMS?1CS$S]9b*8HR[8_F]-3A:M9+);<s[(Si)J?k#-F^,0GWoq"?*+tfT;g-%7+$O@Ssod9LZL['Ne0k %DGRGdjAp-B#_BP5#t,#Cb;=9<<k]oV5qa-l+]G5T4d#h8lqDL@#K3e\9qgr#<`=[]Rek_)La##-VS1jM$]!Bon?5]o<s@QU8Pm"F %O=anLDkJJh$4ke,Jl,R#%=aB]jc%Ml:PF\1IYpui]U\iMR@bs=jlV;Oc6HS)bd1E%A(.JC$Pac(r;=XI62MR""@PLPNXiT3&kF[_ %F9`7kY/pkP3HNRV1::3^!$6Q71lO#5H829r9AZgSLeU=S?,<hHB8tT*S.3MC(kb#S-6^,Q<!B1f7V6oRH,sHLP*<6REg:I2O)<Ka %d#052P6KApK#F07.-p\]`9f,Bie^QpX!l/do?a.8gQWU[B6F?U"BCbKb>(LB;-[9OH+]o0AG-Y0"pE:e??63-%uOiS&!S"X3H]ai %/Mq&`[6,k%[CYn$,\Mtc#:&W3]7E'm.%Ud^JncCjqY!TnZ,j61&!2$i-B:4,]B`H8XD/[OhpoSU$Wu?N#;*K?f?dImM1DWoCnQ'B %2[Pi$W_Wjpf8Dcmn/PWLYt`j&NJI)jE6Q^c,ee"p93o>u"4\oU^P7JfV(-1*6Aq9LiU9@5O[7@I-cW?cd@O/H@AKWW#qCNNpE`I% %6jE=a)c2d+l;035FAJ,3&C3^[GC%$T\=4EUI3djHY<Lbk3-C=@pn2j^?1e%dftdA58VWZ@jliBKW\%,8MuKC+Cm&gjZYV\#qFXGB %DEU/4*mNp;3bY`WSl):aN)[0HoPe]ENhM)";,di5`]hocjdt"&:kW'g]@C9q>"YQU*Y@4%_Nr[%foP[B@EVXFd;h>5UPj*C&okt/ %!\h'[bbF^;$U#ahp/mUS:jl1\*#"M+'-c6DrK4u#3#bGECughm*8&7qD.%/sgrOQAO>EVr@nV,04CSfs!Vh]M6kOKE]5Y*u.Vm6g %>O7dc=KWZ"A^G^ql0@NS-k=2=c!"#V\XgFeU?U?Gcu8Hh:uu!"3@`Z;[\+5hY+;?0=+$*L@]!#h42Eh9:&2Ol_o?M$)tSr(a?_.& %BXb!V4+_$t386s-;.-/l^utbViXSLJ+%YUMOC.3/MHW.k9gmAWbeaKi`XC5+U2\C1V'nT1$td#pL'?Fub72)6L<OQTF2Vq:-RUB% %AtM.4:Yf2L4/c7WJ@?t+hPRB#G'[uK_7(jth[7?pQDmCf--b:F%7_bK&tH-6gA'/i$Q+phaDrAuX+V<pkQdYI2!]Jp,E=gS$,*]B %P?<fB.2o?H(+_14[+F-Q,4[51#?B#P0pr\.)/2*6FX%`n8nf*rB\$0q.[:CbU]UI#76I'668SSeUK9uk7"n()dj%opCN3<AC1R<# %jnB7NO@>fA:_=t!8\Fg9)?f-GKLna3_D-.C@%'++1tW%9N<.E>Io$JL!FqBS?l,kr=GWY[d-rI/qiJb3'*0s<+_nGT,sWB)Tkso3 %^p(?AhVm_YqX+%4Yh1rsG]InL\@X_G]_uBO3&oVt^9W!#.eUgRn+=rhY>5,VZL4LTe'mFKiJ2'Dqg4+AHUl*eSfDZ5>98"M_0k`- %l2Ku(_qbRD%NZ\Yleh.^^YV%Oan61*^V782HG"ZR]"##t3]]B.m[P==^N+0nga5Y'IpP4Kp7!k3QXg$)n&#G^>LY>dNE9ZUJ:j7l %W-F2qr@$b"$b@9[9&'H:-c1mTRoNdKU(f7b:_9q<VT3.F]oK;EF=]gG#nuMhm7C;eijP)415IZ_0:QhQc5+JsQFo85[0fas(HhJ! %F+hr@#Ys3n=d)Ah-Q>LJ9+OG8>@LLrY5=]8OYW/=S5n0ZOKE`J28-<*p#,Ien*oY^ofIA8n*HPbI!g%I9kCr)ns_k98!!1g-dmW] %g)MZPp5dLB:M/'Gk0D$!-k=6/R36.?)$ogMM-=lgL\ZUDdtDc):8l<46k"FB&s3E2Q7OFm7`B!C@SX*0%HRZgF68ipV(U\FoIZoL %R79KY:rpLC(:flUpJJ+J'4m'gKCC@!PbD_(>=ke-n$ADQ$g8Y1FV)K\mr>5aRi\nP-rG.Af'Bsui-8NZ/(e?K=k/h?GKn^H3tI1l %n]uuGgBYpX`Ri/b]6h_8e#D@Xgte6AhW_nSs5*SJg5Tf[kl9GTB6cJb_h)>Eo`K@<qIK!Ak'hbe?hK>>65nX'I<?OJ^iF(#)IL%^ %a7&l4-r,FW#8d@HkNJu;%5JgPkt:d,D\+mjbn>67GEXupJ2k-;-9]$((O,:LeqHt`$[g_LJDWs?&-OS<Xbq$oXqOE2$plSrQ*S=P %UY"6Ef8_M_lr;GJL3jdW`]Hl25^*MX$Qi)/'67on1)j"*AI=TCSbTpVI4<=/V$LPV.!aWhPF*4)nsHH6RFud1;jjf$:-j'GQ9ZM] %14mLJ7(;J&[WCk9%MtPU;q2n^+f:U,(tnQq?;2TF2Kq'G6b^ok_]YX\4IIEY[dnYA?5=JX2pnKl:aGGtS_q\<=.Xncg='_\I)gGV %($.QMi"p2Wk$OV:QTRPXrUm3U*Z]\dSPlB76$;4BM"t<?5IgF--hKum:HmJsS,W<D_f)EQb-gQEGE3dt(O(nc:*)&PfKS*iH?m0u %n9B/g%mBs!Km^D<]t_<@9r9;!pNEq)-V$]([h`EBjE0oHh8sPO./M*G`h]=^T;_\$rU&(QVXh'fdsZ-ab::g9Jb^*+IGr)Ag\^T: %XC=PB5G0dhWL?h?@9*=aRNESG2pKCL_UCYfs4bMFS`@D=&,2D=b::g9_XYq!pAT0C]XOCp>TRh_!EQJa9:n?'4+)LBm[``;79IO> %`SN\HlMZBScKFM''ib$^mGi,_WH*X2s6I_OYJ=f*PKo_or?EflM)8a]kM*tX<u*`+dS@,r2J$7be3@SZV^X7iN2INkNTM8],QG3C %Ed1nj0DEXJ@HE7hr=]G4-h0F4=hjGJDDRo7Gl"J-Q;7>2oT-HUL&Yskl0(RCDD'E<:c3]pSo.1;%3E()H-flA5>[QuI`FZ8*VMP/ %DGYCm>d2I+EZo7&T2XS.Rhj82Bns\c6:t![>.@cEr'/Gh>79jZGND86I]ZXo`cGqXJ$PNjp3U\b`ZMZn[*bLIQW=cG;%e7"HbQ/" %#+jHhDTT0^_cF-+C<l4Yr8[M,r&d'M<oqB(ebnLh6hB*5`P-*JO=A*rnbm4t^%[sFT1mdbE;FC#H#i<'*tFA2H,tK'DRe.fffN@) %06^c+h"p&1ho0B_DV^n%^e^:FEGJ4lHM@.,Vma`l[eC7J;F%&KI(?(B?JG+K#H-<Tk</K3GIC<@G.O;+3numQ4$BM6)qPk74sH3J %qA6%om6CW;qHNsKn>"HnQTI^dV0\IlUp"S"(Dfk._<Fp:h-E3J]WnuT\8Fp[:c84FSS>f30>E_4]2+cK+7AQ[pl,GYAC3?t;SBcl %I[RG_5'h=V4JeJ?p_@[8qndLON'=h`^%Z%UH^SMFJYgYDla*ePqIK&:J,*A5kLCLKc/In#C>ZP2p$m(VKWcKami@MJ7Y^!fdE1Wu %?*MbG#H,U4h_(PU!M9>(s5C5KrN6`u@Vq(GYW"`$.rW(O2VUn@9R8dT<RW!9JR>#PDKQS6^N762b0\s+qnN/X2Vm:e^0M[<roi0. %O/Dm6gnDVoI)0642^=(=j6bYcHHC!)l[R8<]bu:5'@fN75,S??B5UJNq;5h.rc`8*k2uI1SXDp:,,#Dip"%B.rquCAAqL#+fRJXn %5-DH6m,IYhp8.d!qp/[&R3%9<7<m/]]hQfjp@.Nl(u5T:].:!ap<N[.E;']X')m@GItH6XkZuUt\7ta,UAF[<WZlrp:[Z(cr+^o3 %4E"g0qcraj,p"3ojKnm([_iQLmVs4Npq7><?J-[pSKi:OpuoiZ_;jq=UOTEU'n%DNSNB`UY?u+Q2KW!AS8^Pdre*SC5&_cU\k8$S %m-Gg0B?AqR\:;L"Vi1K3ro*8qr@?jjanCaDK+%%9*:r'_WS$#jr`6cX"7TiJ:O_A:p*fQTH$m1QH[Kr5Im;J,T3qM6J*kh!s1@&H %UIt"\r7tBE?oL"[%uq^%rX@&)5Jk]n8K6U^hg'\m-;Rgj'G*j[C6::6%`Hijhu3"h*Mu!j!qs4q]CrgMY?foNh"T^o_WkGDIeo&l %@U8`f\%-\n*ZglBOLJhOn*juK$[E=Cn/po?9'@bLYrt4i./?4KbWe,E5!4+4FF:=$rp>njQ[ebc$U+Us>?iO;g\]1OJ+_4[G\;;H %g>=t%cORCDT'S%)Ap`A(o$RGYC&XWp+h!1;Nh2Dse!&HbkEq@VbHL+f4B54%#1i``n*m*I4o)dZP#".cqLdOX]13*Qs#8hU:XN^l %iGYgY(Gka>dSIWh\'<:r^,UU_J+$4&]%T0:p7:5EqJE*Hf'9ljYE,$n+3WC8UFh^m%TU(W4"pX0$.d8FiO#Bp5@MB=,kO<96"E%7 %(N=tL%^#?KclBgd$k;*BL:Ynke6Uu@rRp*.IU&66^]3]\pY3^n7u,D+>=\SfgKuU`%bHX=^7el[dIDf1?5=KQ-hG335%jgas8U\' %7c;J/P99`lp4JhrI!kHWoj;Li_ggaWL]@!T:]Hj#rZAo1o7,i2QQL2!s8B-d!]RjlO0e5m+.!ZRrL\>:Uj'5EjK\l7lI*1E1I**# %RtrSEOE^AYeBF&\0Q8hko:"qC`L@a%qLk=%>cd*Ie,MZM`uh:GM,IT!/&QEH).""Rm\do-&R,pX1@a-_VjZS'C#csi.I_p0o>;"9 %J)7U3a4e*Q>[FllGQ+P<IuR>(q*2`GXFlk<YPI+Y-(I3$q-RZ7J&kLcY<DbIi8O4X8\0>YJ,3aNjERnQn7:FJ*350WO7dGS6A.;I %gZ^6^UM3dhm4-">NUIqV[ZJMtN/RUIH[e&hZag\j4hTo6ipuqQ5Ft&%3B^tDW@qs:5!QTd._YQ':=kftT0;$m?$8OY':X;kH5cH& %ah@=`MaO(a7#8A=^Z0S2R3kO066G#IGs%8p&jA:Bp'hV?"4<=iN1=PQiI/!Ui5<J]4Gj.ho'+a!PI$gN]u)'H&]j]+(63FqrEq,H %_9pQgmCpq<qP0BIqTVj<OFHUT.\H_0/P"uq/3[D.Y'`h`I=1bXRC9$8:f;U3V&u6K4Sb;;[Ik41i5,'*D4Mm)jb'nWPK/$*XVX^\ %nT+0=Ee",QT<1TMe)g,Vma8"_dX?(an!)Uq&"Xa_SXhB^GJ%0%c3n?%hr!9ZGN\cL+4+8@s(m2\KKjZ]>Q+KUKB;Xsrbh`Z/(]h( %/@W6`[/sTY*_@OU=Df35md-Pt;$Jh?)nko\Hi@UPm.]97gtpdiq;P-Gplg3q&P'^ue+r1[$;>C<j(V0_j(]He!dC!S-OZrgI4/Ik %FPJraSig?7hk#!eVQW9'f/;L.rmH,JjL5YcViRI@SG&.>5PfX%jPb-ZR8'p"00\%fH?j`b1\M=Kr5dlGD'@)FJHahsfnaW^+?lHD %;:U26i6L@_AIF6,m!fP:pdV=>K@Aq&Ii:S(+Q6ij=4Kq%VM-u)l+$M5g,:%9O8c\)<_JVt%/,<lT3]Abfb`hTs))"GMs:/4s1OMG %fbaLUiqi-;Nui3-o>Vt%#47pT2W#qPM=).[?^PaUZZ#Kj`Tl(+\!"&fD-=*DhjZ3-rr8BU?De`lX'<DXp:^87>Q+!d!rV8BSW#N. %^CO>[rTOaWch_cKp::QN%8"#06/6GiXI\JNS!Tg/QnpacRfAHDS@0Ll:]>@B>hiFT+&';fn_Ob>bl%J(lt"4#(QYEqn,!"Ep7k^7 %k7M"YKj:;PP92m$db:gIO*8eYVX<U8p?=JTNT'>"1H)l=dGI1gi;OgZG*a.4Ht.0pIh25`ViPaikPfQIS=L!bMAaWu[soA400k"g %C?P-DrpK;SBg!'FK2:_rVpCq_Sa?#V*M.ZOFLlG(dF!U?7A"Jh!o^F15<5V]\R:XlFFf%IrQFr\_eIq$9m%99S>d/D/5Q;eh=05` %e<bXOVetJQdG]@Nmb>4#[.>kJRs\l';"=c!rtSc,T%j)LNU,Hp_u8[c-N84LjA3G8GKrrYNt-W;V>d[*MnT,^_Mt=b(SAi7gcTu_ %A=LdEFQQ;%a$lod&&'Zn])7Meo'`eT:EKK+B7(Wt`67(LIrFLWI4mMBo6H=CG]Z"6e+]2i:-UktS*mm))<LP[r3UgV-gl?@e5m4U %H#<NChCcjDIqJkki(r)Wb'`e$%=5Z4_p1\SKT\Ri5e2.24%JPg7G@A"Vf%A2.Bi71SZV_F$Z2@tMdrCR]*Ci=a#hI+jPp'Yci**M %qPgN7YWUauSZY7[X[g'64^QiB]>I(7;cf>3?+(QY0`/h2K/n:a\A*Iep"B&jbJctA:X5Q5S/M6YO,fPSbN#MD`@&k/4^G_4]6Cjb %E,U6p'J"-6d@%o>J/KbG,Jt^NZG!l^nf&rPN`n;/[(X5PZT_k.mQT=9.ADW3T;2?pC[g`c(:VUbNtrgUT:@Np2/KGEa:1G5/G;i! %p:!haMhbh2SU,=jgi'r/(E@,_A:#6.SS*kaaio$>8mPM9qtTgBdJ!+uJuM/GJtCC%SQBF^Vk:r,IV7'3`C,!FZH%1pVauZMc7S:l %$@HL6Xod5TqS@2rn*FHPnT*p01NgCaADB#PLna]eH+5u&8T_OW7Yl,?k1df<5u17GYE+`\3jt\pWoF?FNPIfcYHP!h::Oa+N=X?1 %T1g`,s.-;ZFn'#>a].Mg]n<Zi/o/^Up6H.R^Oh3Z,O:(3=A).[QcDnCgo(m7m*odR;6Tu`Cn"JZir8N5ErYs8O!H+%ie3F$=?iq! %Zbjc<'fV_iTlfgDH[kp3BD'-Ons,dE]dK="C4H&o;a\<kHKA[c-o]]?FP8[X;K$\qnWgdteS@@n3!k!1kjCU)5<$>;H?f)C<.;EN %H%,;_dDNqYnkh?hDV`uuo%O\`hKuHE]@.;WP3;`(n[BV>lE@D*q:SueIUi9HfA7%QqXDLqGE./snG)[[%tF-K]jJEqrRY8#gG_oW %RK!-]GLK3g^[pXG^&>eBgXkooc`]QXkP/j@hg<t):gS>*psLjdh#6C'f<5XuI-6L(h>GMZDnbr+jIMK!pfl?VIcl^f^Gn]VpJ:7* %rVJh8J*5'rq-\",Xg`NBhRr[MYLe6grpCTOn)_1U?@G';j`dVH^\RHGpm2r'h**g0IrbG"#H*ViI65,aG44kobKoU(ZiB@;Y.]5W %dI@.QNQQ^<l_FCBTDn[O[m/QWq<@]>g6[0bbBMh@p>2/)]RFnmi75HC]mP"lqX8SL?$hu$le^O6qXEk>UG"jTGP9qIs8;O[G93Ao %4jJOsZgRVcYO:hgqu:p(c/8Ns1XS!Yq./f0?iTM,qU;YIEVI0&pO7,F7eu25[iaCMktp[7q=a70[?p2<f3d?ZG:3CSqUX]sX#JnJ %rGq\`X*=R<g>?7cBC"0!^:1L4qp!lf^AlXA2g0AQ^SO0^^&%/lqiBj*h/I-k+7K1!n#u3YmJYj&q_/!Cf/J^srL^FNpE0=u+&r8A %hKe/[a5Paql&AKRI-:4^cE@abIHuMEDWQNNH##(r>:5KKmGjc3goK>HmS)Zdh=j]/S[pEQHC6u*_sZi;>IV&=nT>qdFoB<qb<,Us %UB>5H(\_9cBC!5i?i'-Ff4mF9`oXnKVO-/b>=X0ip!$9Vs8'<VpsPM1p?fbaVZsi*Ie+0]a^<M0ktd)a:N,.dp6B_eVrjnhpBUHS %9-;s&[Jf6kmeu.q^Dt_+,l6G;XG)R;H[0l2s5"^jc`b'2mnNc0S"ICk#:[C[g:MhNAc<);hDB@>+'sBmm<;q/GCTM_>H6km\))LB %pR=DHNCVDH4R)b4:=NX=$Jg!b.e%#MJ@kg3a&H_4Z7Q"7cJ>\6X7%Z:IQOFAUi1EoIrb:Q=78>aonS%0]=n1/?f"?bs88cRIt.3n %[r6ceGj"_m8&*jTi:\N^9V[)!J,.&Vds$!8o'Y[js6Z4sOj)P42#Z1<9j-/aH2N!tfG@&%+$FjmQhti%]D]mQDnkqaB/2fLq:a$\ %IcXo7oZm7-qtJr-5(<Fmnb!DVq^mk*M0m9W)SFt?p?J3DqR>"XS2\+LGP%(-/?-5Snf+dHFa!`?h0jK[GX&o+rTACBT'1G]4Zn&R %NDE=LhsF4r5<W6>b*A+UqAf\<q=-+/p;s\&rT!%smF?YHqm\9I?2rH==100JO8ne=_r8ktgg(sC^G[W-HKu$@LieDp`r4fNrp"pP %ZgH!VJ%nK(oaa"M^@tA$s(f6lp#L+0I0JCnJ.Oc/hE.*n"@>[N,LhBC6eQPCcbB)ta\=[Z$a?8lR1*J+93RKZP?t@7ZhBdfNOJjf %p"\S?rgkadC/N,T+&1t9ACX2e;e?H\q.2PY/CY\(1fCOQ9#mHb[)$,NXdD9fb6uK-OD6)8KF(J]q"*XT[F0)*nB#f$Db[!/baA`# %82ud2mPhJhHp8-/C$C(^qX*E[7Hd`\)S]L-Q2G0Je*GkYWkHtCU>PE)NWm3s9>aUj$mr#[ql<cic@_u,;o-[]$0OADS*t0s;]X;_ %B^<WFM;LDn=;>c`6C_e9U?R6bpqsg?I8Qgq;"R:T-=-RD3>_KJmW2A((_OoU7c(W/>gns`@p0-AZb_5]1]H1C]MH,_o9W^[F6CEI %O,k2"9@e7WN?=LPZda?$E!jR(=.J@R;bZcR:Vl8$cV$LAg<T52qR5]7r9UCQMR1S\>ccUcg1<pf(8U0gC]HZT!8[<rUiYS*)-Gg\ %5>^FG&#N,,HOBT^cTR]C&%!o([[5dP=g4:.^U*Gsar0sA9#es$a!:j9EAe4('M@j*>[2B2q\4TW$YfB?<qI?%#LX67LFL?[==EYl %U/+MU%f\FoNop?UB_^`sr[DkV+u)K>/r<,m6<HC,9(B7qU%,u=W?Tq4VF^qj$UZ5dG;IK&Wm1L^<*%qV1hBdR,8!WohCoq%2&7sA %\$PRL$N?>(WlX^aZTK%.+r2m1I,Je^$%9Vp8nhtH%tnI1(b3BfP^-jUptsL^T>^)(H6ms`oA-5hD.'=3@k$Z#L*8kO17r57;=#g- %,!Rg3VaWu&.q,HJbZR>fa=N)'GnE-B5.=*W'sGa]/^3:>DK>2"TD0l]Xe@%^3\;\9lH:sC,-Z\`*E@i<"hosB8q*`nI#"o%pdN$C %8m3'[VHV6Gei7"JbL6lb-N=Q?nCTg>m_puZ+e$k?D"J)tm77.SS*pPrqu^GdA:F5B7dh?9e]7%E@!To&Nu!p]@;LH?^UJo(=/?Y9 %qLBG_oDWPW@B*B).mQu#.#n[h'em5j$_Vb-+j@Xh`IN;4c\JX<:p[VbUSLgM3cUF?Qg4^RD`A0IHV(`XP^:;j*:NhKm=SXDkR+nO %dXFoJ3^fCB4f]#_R,VZ0pn3P==20D\,k9T]F.o\E>HHK.k$5UW?AkBbho!',V4C>l,GnqpBb#t^52][4"&!IH!k/_R9RcV>S2s7O %;,8oV_[.<Gc<m_W[D*MJ^^6:*J8p($`GDb4/VF%%BYT#=1UcCRlY/@8^#:&Gb=78RfWrl4A?B!:=W:HbO+fscF^k1?IjHm>`e]-\ %Fn.%S(XFq`+Viirk@Z4.)Jd^r.dt@8])2u=g'(dQ!Dfp?Nqk-]k)P>sR&>H^iNRsDO//?NWle^X.r0h0FL(Q,i@Pk,Z?rFu\UmgM %%$jHY@p1P2>5PaPhL*MQM[&l9i&A=uqhpoU`TLUd,I;HcCK[l-#dK<Gga9aKgT9hb;9@+ahgYHjj:"5B:W77]4i9sT<o@n[X$=AS %K&u#\e#*?FJrP>e;h6e/=T<KG39=69'0@+gT?esqYQ/-jBtXKmbl,IOIgsi2@_U5sa>=UB.Go'N]t$h0eLPn?nXA?PP>j(-'7r0Z %GY)5-ClWfl9qpZDWjWaFr*Kb#'0`8PPLYftdaD2aJkKf`FX#L,]l*s9c&[u/rAa;0QBoa)Y$IXsJiT.Nq6O@:N*.:+>OPe=G4\R] %HZ_8W*q5@6q8badXUl/XI8V.H6"L[9ONP.9TOtGqPmncSqj-$t2IFQ2O*Sn2lL+I*qr%QroBe=M9@VeqK+@(3VS==;Nak]3.]*@, %[`=dQ`IB(fZG@_Tqq@:.(1V$a;c4NEn\6^#KqER!gmKc*#,8[lp&*h+H0\-_B>P"7_\)[f0Dm8onA&Gj,9QpEeC])g0;j)&@;^J! %!g/pi'rfr[>\UkG]0i>*qq]5)qK#]Cd^`Bn#l&FunT-+.3-WD8kEf?nGX8*lp\sD?#AXh-Z+e[)POic?IfhHkBjA=d2k\%P5aD!] %>LK"/QIUmPK_=.%(#I..Pmd8][)Q]hfu"Vp2a8tn]G84C&)Vl-<dSKeX4Nd-IlQ)#U&=/i'bCB&`p@&E4QV=FHH\fJgM`.VdW<6M %d"-Xl^Gtg%6OZ1X[G@FS^6OnpJh"`T_i]_:T]tqJ"\<d+Q.10-08fDu/+;%oVsr=kHCcJOD#@]r(GqF3n!J@b?01;S3lQ"`fB3(" %Mg:X!Tdhr+#^ppOj15=;,d6VhTVk7b;"rTqk\dh>IKLof47H7Of/JQ'f-2:>k!]!L=<0J-i4"`-[09\'Y/9oDm0;^@bnP"B[]cNi %Qhgp;`Q7p;O$A">k+tr<mS@Z?KUGA6kO,cQ&'T5noUqU6^f^8#^@C*H"W5"A#t@-0TY=;P^PoOi5UHm$%ASs#8R$B$NZE0m7rai= %a/<,JdC:iEI%]m*joJR[^'Xh4iCqcD-H4(Vjq9(prn2*qNmYDLB<[2U6.$qCO8!;`q8H>g`L_\O.iZ=)S:"rKo"G5<7fd\QD=iLX %?/s+Zd0CuHnQE#$-Ph;&Wo60\_LGHofs]7["^$]-\(Z1CS@K"BlW%FVf!PA'fmU!mbJmpm$$/.c$?O[5QsGI:&njX]l]TO&G*Bf? %PO6W+GrW`HgcAuH!om2XLtKDO;!"H%[Sb_/O3[@7dO4GNk$!US$YBOJK,Cp0C]!64XR36iCam+0EpIai812SERnsi0O1hf^c83S^ %Ibo-=Y_\53\Yi3r&%B4)Q?e&Og2Q*smtj@hrqn^949kr:>UR!@R<&;Ri\)CZLOl"d>?;eoFHR^6Z,r/(K`c/!YW-9'U9F$[=d#c, %:QVg6"PPR.cA"9e047eg/=WkjmHX3'<%=!qoJ2>@1;/+WFhRHYBk.YbMtDNDYj\8<bjjZuZEdr:$b;=:nAd[G=Qj5chLA_JhNcp, %3u+u5&jOfU60p&8.=g%@<dY-OP,6M-@!2<9(ipg`l^bmgkg1l,^UB1#mpS)ol[DS4JVJF'Q^j**$ocJJ+89r?s311S%gSe6@.[Cj %Y@FY:Hi:`@%#&Z911#Y<<qGkR"qnGVp>KjpSD@22dEjN9N4*4/e'I0;b^9G4$nAJ2&35b4\r_t5TW.Vbm(1uT2#M[+i<)-d*fJq< %pHEO[Cu`r'Ces2lFDW=lqh]%=5;(OT].ZF8<nq(X^Qei?6jkE'!jR]@21Bh<JTd@j^p\Xd.b7JuJ*HQEoMM-$efLMg\.t/mc6Z9i %nJ]%8"^D3s6F-RuW9c%#HeaRhZ%p]!#)6[e"AI'<-PqV&I>c_:04P3;:HuLC"Y28[Ee/k<R!W#o(JCOV+=0M]'FNQ'O$K%.XjZu) %)jRQ\C@?HX^HOZ4^lYh8aD$I7M8$`W,>]f>N&->V-1lM2,Zg,r#"uL'B%EVlol:K4S.o!R47,$X8e[g-^;!DNo2I&oG!,77/%9N7 %(Nocl@dbpMX3gk9k*O&$o$[^e9XFEg!3Dpm4g+Ed\J6e.So7b5K&)B5c*^'r)7(XM:JJHq2m?[Y`_Rse-9e@?!udR`*#ZaaHHSb_ %#1.9]KC*3(\:^gb1oFRHB)#bj'+LGFo.*c3(\<EfQ0f[&.QM-mV=GTs%O6h]@hVrM?2pn&&+,8)eU1./VYLs?iA+)Vh-4?!^&AjE %4rGo*qan\1GUW336sCfQgN^c8dAGo(.G)+WrW%keC<E`MGI$OgUYX-V]RWkM8'&qj:5WPg-S2#/"2Krff]2_O^g!tjZ*a;Y"fH;H %&#Ii9lR\i)<b,'c<(>UCbscD#lDbW*M3%';R6aff@C*:q$4\`XFK$+7jMT8t5WK*e9-(kaLt9iP.+,M@fg9nkq;l?)'q7BC3R`cP %9CpGsaurom9($Y/_oTCDPAu?pPF0A04a%2n>jFH2m8l*a`Kgh!p15XM`b=NU8C[afc0r%QZi(!8GD'sM!NgE=><s2K/RW$j?$UW< %&Jm5d!QZWS[JatY*Xd4VYUt6=4hUhW\Ei-T=F-!3(Wl5g4j=3JP=^?IhNbI^c-,0)nDgr00_[Xl+HEF>M3?ib1#>!Z9ZA)BAd&Zq %f;,JIe]TW%^.u4'fRAZG(am"A_8WHR7Tcp8(oYEjJ%f#&DDG,cho5F-;Q1IJ0C>hh51k7BFM:AUV!Ie>&#]FIM:/nF:PiPFW(=m# %(QUSd.J\nsmOmW@koLZ.&WK!$[$8I]6s0*G=L\U.1:P'Y>-h7e\43h@MtPfE+-MS787X6AIhlEk@@E7D%tBejan+>a-/r2n&!ong %p`1b^"MYiE(j*&C.6/JRGJMhS:&#!2(p`E1qCeDpF7D=+2T6HbhaTM5>!6q"pWf_SH%'_B6Q.OTC##>p-&0a8hkIUPCS=DKV[=c7 %9@1Ksk8rrS+n?e=["Q:P>+?S=^"aqn$VLjdc/B^&n$86mkB7j]l4s^G/>.6%!o<NVHB?Fc_>$l1/r0rdF+",k[s*?\CtUKp55N-J %".!W(qpA%HB="R:^L6_&U9.-oU:Wke\6lSa9`@T;GLa!("jojf<<8!?c3*3`]+7r=.%VK7HfEW)ph6,:V^_4pmsc>OV&:kNO5dlN %D>)3]8s_ac:eo6#A`16'Dl_4ie*A7(rd&A^IFg'`!GV+ka26[3j1u.GDX"V%\a]OtYsqrUoQp")r:p8apr6H6/]g>\^B/;[c,TE& %*IbF3]e:BZ;]1bY?pK4";`\;"pTtImcb4:rM7tK![a(Drpu=#."8DfSm9?*L)Om^fZ/G*PCV6sN*Hi6\r'9\_33u3.A6h7O<E%8+ %qZuVBRhrY\GeM?bD1G]uY^LoT#6(+ScGE26_\LShATSnG&dnsM!l_"ip]4IT,ij7rS5m4iYL*ZlboU2AEn8WIPnSZFYt_E@rnY3b %?7e:7j`EQ:b\!HaAo$"%FsgZ=1mDTK/aQ>1@e%uf\(JUXbN\Ad\M2oU%:ueFCFG1ORQHssQ_(;iSd@(O-B\s&/[O9X2Z/,*;R-1? %Zp0?W9T.W5#CPLVWle<C8rV,j9Z84Al1YbGKrS5\cGeU]^W4[ib*Q<S&F`eqbgH`3)]h`a&5115Itj0ODQ:Ju=D3#2a'dMlD>_2j %eg<#gT@UtSrSQ0N3hM>!-<FrkPFQ;UkGI?5IS3<HaoT5mr#!<H?+KbWP[dH0/!jMd[u)Fig[Rb0^g:Fl;1Zhdn\BHp4blOX\^SHZ %f@Td(ooo5rPMP(O>seVU7&AE"\/m./5#[2!/'UcgRr\,I42^`["&&tjTMJ07k\K`kN)q&d,hT]"[ccdu3k?bVL'JiYhehcDa6(#4 %k!+=V(4g5/]?P0+S<?;B-j+S3FM:eC7&V0hB`*,Jmt/beXPeh);p(%UG-dT7F#QaZ+ULgFiJ>!KF7tBcB>W/S'H^+@\U+#h>@*[d %>2Iq-i*\+fRN&Z*BWdkn$2baJ&o5*XSM78V9:]'W5/40q"6D6/A0aVqKd.4Y@?8($"6JYq?pe>Uee_=:b:D=D/E@*eQc52+,SEp( %N@S3JhSY[J_W8)\Z%Q9@69)._WnO,IbGph!MOc@T=:.?eaCTfZ,;:55oC)?K=c^@MBMj^j8>0ca9V*Yu)t$5f_eQ-C:gd.tN)\i: %$m'dn=VHa\4--[E"\Wg'EP#)RX'eNUa<!'[S.Ws4-D&J"%dundjuY+R"6u1FBI+eaUns/9O4P[6D\1H;O5`Q=bHP&MpuG-t=:/W% %j6BMopE/K\m`4)Dpg43TK$'&(H_h#ZarKP:*XYI+*uLj9E3%7h[[]\=OVP'78t](/mcmSjT`^3/U0Leg>2B8nrW#m6Yq:NNooV?I %TEQI>9.[R5)ie/RPqqCU7UZIq,$Q19kO?JEj^L=<qG/uC&?n)3me."J.!?((rKH/ZZ-XfBEA-*4cW2PodXRI].\S),&0<=uaC=Df %,]k+X`?6/64U0K((W#re&1(8d]GjV=+LrAm-S28q#tN+M";=8]jEAa?#SAV9aX:fPUBKj17MhD[D=u1/`AI=L.B^.,bZh[Ta#7;Q %6'W:B][`%L)OT\Ql[C?$J[!dU1#E$aYu]3aYh0H\iOf%&'&G((KP'b9Ms,tpGAT-fGO8h&qdaFW+>C1<!^iSN^eiE0mdM9o(/QaH %Z,X2g'\:hZn_=eHU]sG>X"K`/,\OnD]WU,m>Lb:QK)u`_`Q^V_jr1,nI'(ZMLO=jF1Os+_M>-pihT?GChlJcsTA=*:Q(ps-L1l<B %.sI88iT,.e?!T!VpP1b=HTihrC)iooj-\X5GDcr\mt0O,?o:u1XWno]+Um!0[[a!d\^rpTq$K%H)0^oOa8s]^YM;AThGJu`bPG-W %Yt*k,csUmE1&>Oh>NAd.Nd*&^6AUZ@Z>4[q2AF6-cHgJf=qBdh"k/ld#HVse^pEmdi=$:4?d;%dN,]RnKXoLm58r*o*a0.@ZRA@\ %Xsbga3nOTMCu[ij[Dm?>ak&_eVa?[SSBB8.Mb(aabVAWEPqn:@;_X7%"%-ao<"LlFbP>6`Y0=T-h+s.ik[5aPXn)Yeapm;(c/E;] %_hL3i^eB;<_X;@Aq3eC(p;?nqJM^Whi&UjAg,Ho4r)pP6J@j4GEs&AW.`#J3AcHY.2d;rpi=3q..&]GVO>Knl2pA6U(D1]D!+Pl, %CVZU4_Zj-rT&.]=k03=,3W']MSh]#<!@o"$]K_F+@.UDf6ltjLKk_H>CG5r_d(7Iq+@"c@*7kRc4M[^p*05=8Xg739cZ,U0Su8@? %I/8oTWUQ]5)#]DT8&9iCH47;1R1V_Zq@B([Jm;;^HZ5F3Q_%Ap=X)#2Mhu`AJ@@?R*ZDqGV`S`MA$JT*#_4qWE_08LqAJ)l-51m4 %8Vh$dBXj?sI@)mj(=];V!LW&fh*g6P.-NgJ)c$aQ=2)gFIN(buSs"+]j1qok/cL/pN[9Q_NUkXG;%m\LAZSLSTe5LQdpR_T?6ho! %-taakeQ8,;A#\0PU*YO#g_(is$c=Q;j40[+Qh9_t8^ohHcM0,]5G1!0g;adFWm1D0"P;3bK.BV&\Qp-/*X<DK)npo]VD"J)MFq3# %SFXS("<$[_<$sr(c"D+Ca&TRs`>4;"5=J.mic?2dcCcF=Xp*\BP6MJ*dUNpEiL8LS=$I^FdQV&<0)#S]pg4#Um'kX?O_U_40BdL! %#t996iUS[/mK2`7JaST8b2T^HaG)Ki6<G?NB":d7jnF;qgga8Y\TknG>^pfl9=:)\4YR@!m)uE6F1rIa,1RUk`uCbi:Q"83?WZJ7 %fntp;!A*:V\('qK*u&!hHk,)i:har8gglBb$tu';IVB&)WfqY8S,OE35Do#bAN/]?#)VK8)Ip^d::W4#m0IFcN*e@4.W`slcTsQo %->Ks4h34Y^'JCEeRORJ$WN@of6PO/,G]Qi)=7Iapc^#AJ>a?4,)54?KHR]e`g=Ss\P!4?Z[":<Q<15&#[;,$EJ$L]6oi@R/nr),, %`mR%f9b5<%?'1BbdA8gLnZlm=U!D_m:GOksS3j7I8+Xq5Lq0]92^jON;I8/t-(SCd'lo_Ue2lpEhcY@@P:c1n7+>rfXXZ3]L\4e[ %Z[LPp.?]j/Z<c5m`M0)QQ&Ps><3iP8U)o.]SLRMh<eHIB^!W-@FhP;9M4Lj[X2Lt\/L7)*B6Sr-0Nk%+FqFDlJD:D-(YS[RS`rsj %&^3@dV5_RB4,^hMA!PeUiB\S.%7J+;iRKHi?OrhHZ.CIXBjnJDVa`\up7[eSa7eb2-2Ho$2m:&(C%qU!)(`a.]&02[\^]9pa@4Z' %A&7"/mK9rf*e9B>niH7<_.5'f#\5uOHuToP0.Q+^e?Cp-qJ#r.hjJctrtt-S9$6Ak>+^c!oHJ"V9RV&YlfY`oYeV>o:S8:%+&Z;N %9AntE88mn;/SK0A`AW#:P\34/eM='V*q);b#<oQ)-Ug<#p/-.ln_7OO>D!+KabP33-o>]5^Aj2pb0ct?>rLOCp\t+S=)G;aGYXW= %i+mTEhX),i4u`2I?"3iFqa`Oc.;uG-6Z#7[!>U?*g%QP8q.[?LM10j8.n$+?s0($F,!+G+HC`B4MO5qfoHA-3GIPbM*7;Iq1Rog) %Xe]0`F\b=<;F+iGp(q@Nr-0kbFEdY?gDlNTnOnlj78oU"JS<\`)bnOcBI:pp2;!DVkYAi<gJ\d!NE[IepJ8(_bN;Md6Bkb/Loe#8 %#i:a^gtfZ)rA@-qI_ssIkrE,X*N\2,i9"QDj0rFg=gCc&<ALSj:8GNj7);2.Q,H'TFs"EF'7jhE&F*$)]`M&`"XEp/mQ;&;7_H(9 %<M!mPB]&4;cFl?fB&jV%@H[)N?h`,nha\e-qQX8re$;*`T`)cr9WYIiU3i#V;&tD8J)TG$*)VTr\+0Zr@C%6o%:of5qZAO9ktS'# %gK.>L2KdW=rcD_.Q<V`XM7o09\'afb&1tRKBS^<?(i6MHX]ZHLYiCCMAZuO?3OTVE)VI`>2Q@90/CD2d-L%MG&d`hGY6%j(?XND( %A(?IX'<R^`d7/U*PpQ::S5oce?sLW\l^kknMa6pZ8[TLe7sUj%^h8:s1IaC!?sGbCH'R%6p3jIB73Yp2HIQS$SnQ#YmS!hF"<n1m %PN'=M5#ZePd@P29fTM'I;pXl*?B1u#!m$[tce7Nb+Nr\E=6Gc<o[hT,j9\63_pl`rbDD$!bd=m`&)I%*DL$3C')h`U)%_XBVA\-t %*)V=lP.dd-8r]Q-KB]PboQ"VFjbW>J%rO0rF;1rP(6(-4-j:/ZK>fc+*Qhij']0o5"UYlbSIg3Cg&=0.03LOs[?D/E`]&;^96:be %#Xj5;L1DmB2\Vt/rV=12.M`Rk<9`AD%#MPkFm=VVFra+1!R\bMb2-%\f7SmrENtd6&lE>53*E3p\;_<i@So+-VP4T>OJqo<B\6cd %od^bBZt:#._L!i,-0<H;r\/cF`*48hK7>hZdXiX2kr'Ghp4@korRi<a$;@C1!IsB!XGm/RHGiu'VpCEJ`kZ,mQ%'^ZK11t69hA-) %?o$N`Kr8Bo)=0;];Y%*24?p(S?;jfJ)t9W#VZQiT6T(Gj6+Nn,-GS]A`hXY&]j7<!NR(JMdh;=5Y!.u>%]FPZEF:eMqY\T,[<lL1 %l)BI'AFFB2V]i'Ur::1i-2PSOm>f0lqtsDk<N'6UQsuXZQW`g[7eOLO)7cZ$@rDhAq)4N`^&:2ZLJ%g!djFa&NdQq[r_agkY7?S& %-dUZpeAq%%7=#lI5.cXOl"QG%KEj6jWFV"uG!:t^*[86[[/"0<rd2N2OkH)9qkT&g)mt+eQDm>uHbAl3/GsS+dtuo4s/k2#57N%D %4,N%WQ,GEW^1jt.CCfX.hjUuR`(tGD:F2KBSk:<$s0+=,K=,(F.H"=Em<HK20\`D`b]!1cN7_Y<Z_6Uj8u4Y;GLO3plcD2S)4r5@ %4]i)6-PP_h?aBH18pUp8=,JWk4l\jPn#\Zks6\"8K^B("oJ"GMJ/,VH8BO4_k=q%chYZNj8pO>g8%:>2J8h#)L!dXoHfqAj*NUG` %Bch32Rj*Eq1\n/PVOLF-d*KP(4AIa*"9"aLKI@fV6oN\I6"FP`RcoTp8/1k["JW]="b+`.\&\!P#5_a77*G!87W`ZpB,6:Il^oOC %5X^a$`%i05rs=^!Gq!4,abCH<[Vl>D^`W2oLd[BuO4e"D8RJ1as"7)(fRG+Y"mfOj,t&1XSAE#;-PD-as+Ed^8gYI)JG8IFqhf1s %!mtZbg(XW%d?\<:%2SEf*-\Xs5bH\s*^:Njq/QcNjVY&%TrH&)]ucLKUkQPq('fL\$^X$Y:YY_Hi$0MbV`_9D(u`@%<`nlpT<%:! %nUKD7B,tq113JMYVD%*N<q+&:T`o(Lo54Z"<tOA$6A1/pKe+#3#7frRD?R9K*r4A$U$kLH,*LTB_30hD]1qe4SV@"uI).@G2I+6R %>Yt3tkUV)Jb?/ua-GsVH/F4J1rJ'8?kDO?>=QfdQK*;hhER*a\5LZ>1rW*Zf6WKD@KShJ[L!V5Lai40dq<=*$"L]GrO30"4=9QpU %4[ab,D#]qnp&:XL:Qk5]H$j9.JXq0A2hLi"%?:q$nVg6gf=qbZ_uVJ#UHX9_r["'Qk,1M`/;;5OQV;S*0?eMkpUAbB=k(Z.l3hup %C]Ae-oCQ!_N^3cRW!f!#'h>F@4<'.H!L-ko&HR@;knH;-jp0]j@oZpQISBCdn'J_3k?Ztf:i6`C?dKm\G:7D[_n4?DcU\]'nuIpn %Ch-QmpsiGa>hCpC=jf0V>XYZjVG5AWZ^W)TA^K8q9"e;M9Ws,`Lo:,_M43iKc^0[B<mVE%WXQtpoQ'n*@]PEAWT_kd!tebqH6G(V %5h=B5o[*9:1P_UEN.3$9PKTa""dOpE^2JA(l:1b;`dbODh9dp4<$dPMg>t=uJZX.bih_ft+9dP-s5TKMoA(]$-iCk?SI%ZmGeGcq %Ti_YZ.Wa]gCm4@33Jm-tAd-L"]Dlp*c,Z-?'rEf5_7u0W=[[J4=(q>&?Iij+4ePk0H]hQA/4P7\d:O*4[k*fE;RN;W]!sBtMGMC/ %iN9M."m]k71CCHi[)7eV.lFW3::WsLT7;jNjI=)s#6#4c$b9,HU952b:3lb>RicTkEN<bTQo0qsN'YL)9Z%-.Qpj`)K<EeIJFC1o %=8"`CSN4%GW&7eI=J;6d),o)0qY,"fNf!/7$TU,'gKq)'0dtMrY)J?UEH.@5qG2'8d1eK@r:u[TU);<g*Ih.HY+WUOi_%9BkR-*R %WG$BiUm;(k.e>;$doBF["n$rk($F5+UMM;u-ZGQR2`*P;J2_9ak+k/oh*+t'$LhZc;3T+h9gS'&RSXPQ7,HgV:!rC:&0&JZ!Ps7G %K-u,M%Dg'GZmj/@?KrEJs5XpE+h`Z3P,Rj1HucSG.6_:\^#;FT'#N=p28<-6"bn>B#`437+fOB"fWS;,)?u&n+>&]4Wg_V7e0NgB %!f]7.Y9EtH&ck8gpU(9Whl9]X?r2\*q*,?aWud*LgE`S%^e@S0'r81%[H46k2Ie6YI#e+X/a4?<F/=@arFfN!m+N8gEp3k,bO9os %1CLGpoL7pU='ue`J]m9";eClQ\E@sjYA.a-':gtt.02bW.<$4bR<6C\"PsHrE`H'-oCP!W)'9M=:lg^:LL`^&Hrd@T,>.r8/Wf4> %ma_5DV=6t42YKX4r(;YC#K_:l!@kdBL(5(PEhe?5*JnX85OOa*eW0,]$nfrRA5#NGegHH.&0a"i`H[B4.)7#9#)guucGZ1WM(p$l %F=eD_M.BOg=>/F?fU+jXGF>V[,1d_u7B[o:9.aTJ)1ehSid0;/`JX/tY,1K`C]'d6%]L^17&p/UoA!_NR-F.,;69T=l]<Ek.FtCF %!9trcmZ]:-9oP2_3a'HNfs7.)LYNKB3WaL^fs4XDfk_D3@[WWh!5I5EKY,c?fU'&%mY%+NV\o"X2coj`*?Tj!WU.9BX'AX/bJfAM %/fL?/RB/ALiMbFHQcs\_o^.Z3<t;7L.9?nd^TXCRQi>Q,pQA?9DLJd>K&/jpGr/Y?g3+t4p/?>0V'G=\E;#YuBP<FHJ]cKmNBs>s %"^@k.kp*s`a7oRT>UFZD9fl4>q5GXeJE%9J1GehmTE9S%CG=g+8@5NBd7E;l7ABH5=s]V`"<LTeWC5eF8l41U,hd\Z\AHsT)t@Q3 %U6@T\HMZS?M$@b3,`$,@9Q*'8XfWc8]qThc7(;%MZZ2kP=X7nni)+8LA58sq+`-Jk.r1uc#JJcd!^.UF8SfCGWb!=&2dd$O5ugqk %@Fhs"AbOPNhT-uM=h4KZ:ml4%T%krCp49aJW`@:8[i0X.KA(@#UF$sr3`@H2UOTO_cdY:%k/>Xgom4o)W'q:2=HD%.8'9#:WJY&9 %)UFHnC;ZaEm$-ePTrEV=1npqV?>]J=p%4B0`s7$olU8)+9EpbfbJ&K+PLG4@0j*Oojtj!T>dS4MU$;O`=q&n)h6B#MSh$<R6M4/V %l'5'(n"6]kiIJHRj2q/*@GL".BLDP6faP[B_.q>OTHS4Y9h2+7@i1m5niM]4ARpQq`(FH(P'5`5WrPrL?R8_^.jM36Z/jNB\d(;k %QEFo8O?")jNcPLrZKKeY8rXs\?PGlZb`(IUF_YZU`Yid%\Ce<f6o"N/07C;t0qFi)d%QaNB<GS;8r?3`agFW9]7,_"kU:_%a\S1R %8(KU[kHlhB9Ts4Rft.h@L"XVO22UpQe")eLZL$G`a[iEQ^;]ib$&a5==#t_ecNn!DKX`=C'KIkKq5gThcR:G0E6*AAlkhFCYrr#M %QbD@NBV$2:FR1p_8U&V-OrT3O)*oXXqTd(,iAdK/"J'LY_dsZGAHX%-XhFjk:)Q>f5RZkscoDgQF?Ear64=lc.#X`3Uuc/)3b8Gb %J/5d+6UrI1&TgFJTM>od14i7`qWDAPPS&""Npf:CSMGeWM3(u&Ti4G-@Je,(<CcV^.!O<4a_,+'5Vd!1Rs0A)LKu_qM%:)X4E4cr %BS$JH6VO:#VjO#KMWDMe`V-JrT?*/OVU]o35)DX#Ep&[onk#S>:X>Gc*%p[A(3pagkdZZ8q'9#Ve1\t.;fhsQE-&Z$,O-GW;6#ub %q'MXV+/PGeW_=cu8Nh*j^aHCgd0,k!3N&Zi_L@em*<dUZCJ4,W7#,!u;32Ct)Jb0$C'Yc.QBXO9K9g`skh<XOh$kULe^6rZ#^4[? %(dnPo7Z&!tO7YcCS)t.r8Vd\j]p:Jp##X2q!,RcX$6j^1RN)pP1,54`dALDhISjYh4N#7TOVe[n@'SKLf-lhQrhK$$BSMla9`pSF %p*>q.OK!KpdE2GY\1a_s[tdgO^])$:Lh#G[+gcAti\3qA18^k`SC"KM2(:%h2A$Em'a5@9>S5$NGuW?cH>n7H[[.(,>)A[n3Wj:p %9o0u0%ApK<R\k02rp`PaU.N?oWL\UlKB"23caAe*JE,t+0<U8;as3lX7dk,rN4`XQWJX1T-rd'q\'`5Nht8rU4md_2`r_TI9H<h= %Y)!c4Fo&8>g$0cf&ZgD4JR)+Xm;e+j'eMpB5A@&_:#M\PmF-T5r2s;km.$Ci+euW[3STsPU<;7?=("k.,/"eb,#B+j&kATa<l<7` %Nf[da6r(Md7L]shVRg#4R3=`>Ig/!aTs5)[QBMQX6U<l_!3$\^ngcN)i_ErQqEO]2#9@\/E@(eLW@Me)#!<C9nmLl8)%i\s]VE:a %qlO1;`Bu96WS:q:p`p[4O\AZ*72)<cKm/?8.hXb#*,/5_dRch2oCt/g9;Y:,+u7:H4'`F9KdNeZ?5<5\Nl\"+dYJ<b,cR>deeXBN %eMK[)e4utHDWA1[M^'uNCqOr!K7'`R'i#<kXp&\=!tUPXnQ"uIL^Y8E8ONd;):8UT;qV;?6tBiuqmC3-A0<po;kf-s]%*M:O?4Ar %3=6[-Cb0p/NTG"_)2B]CBJuSU17%6mh]%l<[k)8A<O=e*JP8!hL5m0'H@e3N1[bbdc",0]q_d;A-V"uKqF)@+:@Gl)Vu'p/=*FfV %U]ii!Epi2.\jcs^R2!,pJEt9B:t=+>a4o5`/<l8tktW`'9k?(n;fj\[X5)=)MMF"O3E(,[*_p>9'i]?n4P\U;<-@0Y'MbT5&J'(G %,#o!l:,?)C,!6hla"Tp:[IJ4gRB+W$:^rh(.)j*_?BT3)L1WQ<5o(%[*LBFhE;WDl0`VasV]-/EZKmG/`@f^k:qb!E)97YL4qe5P %;h<Ci(l7U3QG:fK<^trnd=M(-CYH$k`[Z*gT7g1I8(4j]aud87*jPTiDQi,\G^W,cm[89]b'Fg,jZ@uM^^29E&4N_M%d>`"]bcnN %W9s'X(^@>QYu@3+,-+\9(i5^Le'V^lT;Il@\lM:XZ-qegb)WIF_$9kh3.q]Hj#1:EcXk:]X+ai4Qe^DJlI"Zc/)PK%lHsM''+K:X %_XpU+Qr1J49'LF"kas,T`T"kD]$uTI28gV#ahekdag(#E,#Y&:LIcj-%O1TEmja,mT?2Kr6n5.u$A_Y`b;Bj1Yb#VQ;B^K`gGR@K %kV_m\$3%?fY,M2R-0[0)lqS&b_;G#V8@m>VgG77cKbJ5V,$O.r.%E7X$Lqp3$RhP)4n)O*_J.^q]GM!2qj"&a8Zi5N_l2e1VHt>Y %cCj:=P4P>cQskf`=/'Cgg+2r23c9U`1icrLU$uX'\qTc'`09"9NMidaAUhkW5?R]JMiAAOaKVt&#'We*%F^YM1486H!Wujmh8#/` %9hX_o?7=%2$7_+0*/M(<JOW6!qUUG&A!I.VH-`7t4_3d8ahhmj[h4iF*9IHD(u8'`_!%^EHq%3-l.P:cIC>-<_5(R_FE1gbW<p`_ %N:-Nb"MLUt7>+Z2WQbK_1:PjZ#.rP&^huk"L%C[!S[#^bpX\(.ScDb!G-d0GT,%RbRJgD??/2>^XS4#K[s[t55W!9m_4m`5[nfGG %?.g'XlRSG4\\.8"7&=!:L!4C*j+eI]-%UTSZ;2<7$.pi7loku:L41,qB?-<kYRC1%8mo,HMF`u+5:U2sSRpdINQ;C;T`WUs'djXM %mD!FK#uM[NB7)Xn]-ITmP^6NHPDgqqY&6WKIH!^\qJ_rQQXn9&R\s?3R3#9rnOZ8<ak^s@^es0scR4Gq[rB0q/t58".c7)"IcOO= %_)Ca_dUVk-GUa@I4VL>l-&.s9;%jCaXKouM2/?n=P::Eo*N0hFSfH_5e[70Sa[MPPRIX<4a_;_UX%D3:.ttWLWYn;PkP?f),)>b] %<#+h&C.KPH\UWTHO_*s3QQ44Nkb%Kl33c%KFB#5:WeW#\1^Q`H[JY$uq:#\ab;G.&/1H)(oaE[J>RN8SlBT_<"HHb*9daS5P&kW7 %Ml)^(g<$H8(Sg6UY]Rh^b-TK;\r_tcUZo!kihObb7'5RuFE5Y32Nt=tVGfV]I2+RZ8L%RY9rB:PI6!`k%SMTRE`Fre_V(M2U?PFN %c_RXu'0ck!-`93(HPN]<VNV[qZFchIU$4s>@^1#WFS&1=3]S`3KBBZjRSIbu`0&nlT]tOAFJQ!fkG.:ehVm"=VUL(!]E4Ns%SM"+ %a&I*Bki8%B1n?bLY)T<BgI>Tss#&2GEYTEBf1+62X_f4BH7^tE*0s@Y-43Wc.VLlR$H*S>)JD/l/=eW\j5jr83@p_7m9^#k-O7C0 %gd4A=LHYr>El4T\6g(6/,Yd8<5^eGfYlbj#T7D-%79L9kI,[mGOH,R&P)(iU[4\Io\LJol-YGMNZdm0$(Dl26P=n`L2/e(m^,dRa %)R_;"<QeRFR86%ForW80%_6B?H"aH0.@dlsOK)&kPF0f>b"69Snqk#HAT'S-i0.pL=kP-m8f5pRn/3EKI(Mr-2R`)^rXaj5PB]Kn %kE!!'_2)gnFIe.I43a<)roGuaSZ_R?U9:b8mOj?%BMW]iTE\@.h-CSN@FEq:Hp1\3RQH-KK]/bAmU0'BeO4U"0=)t&\Wb<L9rAPF %Vn(8r0-&=Hjte@eVI/Ui_c^gA&nDR\/#iWs*cG<bb>[#7(./Q'BLGWL4)5;G>g%t9K0#+^iZn6QqPgV[O"opu1i8('+Eo#BY$NFZ %.mXm&:*!o5S*kYm-aJu6_guX(1VLT,TJSQSp1Ypco3^f?'LMh,H;5J)+"prJnDLu8Ln2#p2:SB;;_*WP!qffggQec"FT%bo-W,Af %8VK9`f)aI.Sct'1fM6t)^JgE2,jhh>h^PB2?`@r%_9*`c@7JHt5s2^0?>F!rmRB7Vq-Kn1W-bFH]'qZ75R&G/.=:<m$4r;A]aTYO %CM#9eSp<VPAF9+L(FQ4PC"MEr%!lt'_0Y_U),>6<TR*blkB'=7cT\fZL"';#Z`46&AI''-K)^8=%PP'":7!.!m8?%YRu*Dtj%^u+ %MdXh?B1TB^__X('&bB&03USM!SSX%mbE7ih1>HTdP]njRLs)$,nM4(fE2PKjhO,8LA?sF8EnooZ$p+O5UF/lm]@2/2=#jrF%]K`O %E5!:o`gmG^>qg?LmN%"HBu7_:RQ4WC+&j#gfQ@5MT#tLqF<_n#!c.U6T<t35J[Nf:f:&3W;8"%<QW0*Djg3s[E;DgnnE*=,iL7sZ %m4q1I$L$86=':)g>_[m%,/-q[N/9uVklidbNY)k3,BEQSQeRN[p7pTVTSC?dY[%W2X&;:tXr%$Z-DFj-fP.pP:)Uta[s=(,-0]i+ %(g#'071^,Uhmc.7lf_m"(&b"C(`Kbk>k9V4,AEIBjJ.p`qf^XQ4)lXQZdtIP>X;qY=&Xrl(c@9<BWjYV,FN')L*obeEo<(Q#0t#o %p(^T!"SJjq;&X)#]Q2pSnA>#rL[Nd"o[km3lutPkiKaZ3eREr_mH_PP=eg')WBjWn!FbjfJO\uAo9&Jec!rtpTP;$Oca(I?V`53V %aWHQUdbL8Y$l1#qDg2-M\FI*Q:32coJ!2\68TO-JE=nn_?BqaE^HNi=MOlu<M*qf=4'uhY-=Qp$8pT([D2bD1R^P0T9JJXL>a6K; %VuLX9Hs\1E3'/"2#M>LiB:K(!:WFjrp+L6rI9QG28KbYV,s9sH.'f$_fY=`XX%+FMS_>8P,S6Q&8CV#JA/eQY?[)Bbg.3K(b^R&` %U+r4Y3:c8H3t)=O^$n'cBdd]q4Kd88jhg/pcdL"3U`@"9+=\9*@HSZ3-6[9i4XVsF\VQ2]FeUq]j%^eYnGO.heIgi[@V\tU2s@@l %GAQi_/7qU,9aEJq7S"LeS,]Uhmq<HH8\j*rhkPEKg58qFNCS>-QD0,/<Q&jZ`8c1pl8r0<jHJ6;]a0nc+?ESM;/%NU%Sl2N>ZE3' %#:n8C:.qjAZM@eIV[&J0DRrSWJL1t+S-da+kZXHTn@W%>]d1Z(>BtnXl02<T\?_`aX3Zs3(c+0b9'H]7dIpkoge[+.O\5(*ARF/# %d-:UtY-Q7"GFs5X7KdmuO)+!;O$OK<=^0J:;`>6kG\L\+@K<5@G+P3Ee]&Gs=#Q6%0I>^=/WK;*XiTe.I/-P3G"2Hq[4na!#rAB\ %k9H#h-KQQl2",b.R,GNA?-1k*%@Eu2)8:ieSKt)<Li/o>&Z:nV"rPZMl<P1l2VD<[oVH+t[G+MI2Jl8UQ$X!_@B;qEmPuD&MDIhm %Usg4u2+\eU<!!-,)Hd(J.$jVj5rk((1b#J;^!R8Mgr[BS,bB^Mb1+dDGZ@9Z.o`C777U:gi4-SFeE=Kq:27T8BWk*Hk>E,:<:fA< %iKsZhm0#%8Zjt1p5gbVB=WW\@$m:$1a]U#WXVa;<CKq#H-nn+."/mT=I""OJIO:\@!Yi%.!<[S8`Jha!9/>f&=OFHOJ=%NW_uQC% %Cl%Gf,blEDr+Dc)AND(E)^>1#>#9`)Q:Y/\=3r"P!"]&68bn$uD#_\SHqI8GlQtX;7cCM=Pg?"*BW,;F(!VrkS](Os;Ef*7V#OFm %4q2_8>p1Yhar0t)-07Mi.uT/jP4FI!1mM@[N(hMPm88K?/*-A%p2W%G%AbMWT/r/$)L;8u,hM_WL6BmKVt7:_R<eaqZhg582j@!B %5NNBsa'eT'oogDnX5"/<kOhb;AtjTl=CYZ%jg.jP[(IfjT;'/.^IEZ,R+G+cVPMbY=3g-0I%EoOeiJ;0?9`G]Ul!mPLg/$aoi%HS %EnM>Uam1=0]">fc<CpL]jb9agYImKu%j$pZ2>@b<X.O_;8o8kPPZOE!<8&Y_!@52[cHb`'f.KAD?%D&S%Q#KodZBMc1DX(QX5B35 %nYq%'2<X!uam5j0$]>n533Ssa8Q'Z%]X61\f8j9!Z<@.%G7^=7f2!9U_SjJIcg-AN/f@]1j)Sj?5NStq*+J-[]RBo]9$VNC"-ob3 %B/r%?hR:q+f2"E-h\F^+b3Ps:\,,[.I`f&(q=lS_4cm#Hl-ICo:3(5$Rc?6.htabeiFZ]t41b+F*gF#-Oo6)EH2T?cV.n';VejZM %LnP4JqMErQobPlX`b"c<l*n[Yam2HqV74"fHc>UQ.G(:;+5]*%:f7[i@k&'EX^Dc^<kktYe<.l=k>][jGIfT)#dtl<p!\mm]2nc; %/?9j!=g'cfT<c_;H>A_a]RH=?nS,etC<<5@MIu+ta*1hmo->F8`HPM-AG,PP4hgOZqT8(RBt-61DdGZi\/#m3^GN-d*9Kg^Md;_% %:XVgkgFdQneQI1rPhgN#Q1Fc#mq-#K]-skTBI$BZqC26*"MlCRfC.MDKDP08.3"##QZRLZ5:+3d["i:?YE@EiXdIWLGnsK&l_hC* %K<4SnjRlI,0SATCX5rqH.q\Gfmj4Nsf8gX1,i.6r?=#j:PMi]n@^]YB8RJACqi'_taZ1YeP8VW<Eeu5&lc-Wdcn>)f\sUHL'N)96 %KD-#2U1c`-,r$r)36d'5%uSEhbIPW\J7&F@"DVUR(Kc-,Q*IM%VM3hYrA;iH&'8##(O^2uX_C]G'nL$JLumkXLHD9mh0EXdTcg-' %ZgqVuUjdC17/AS!9I?A-cH^gBTh;.g03.jka!nUV.T5nNhOr#nR%%hi*sP\S2>a6lQd[%VI348BSa*jXFn\*VW^e)fWpG/2NmtDI %B;8d=>s%^61-JO-T.`!8n.[iY?\'"DolY1gm<6+)GIN(Z,^)]8]!ja2U:.`mEX*&*VZT>1>2AdAjg"@fRq6pgYMVgiS`Q\n)bhl7 %eRrU)bI+sSKuIS[Gopkbjk*H?`pOm<^G!R%K7a4DO03?hi<p)$"+/5=SW8E8SPHt=c&Je-@E52FUa9]nILcIU%AQ#B%q6t1ffXlV %4FpZ*+CN7[O8;Itg3:.6\!,HC80qr!E@(e=/4JafH&A2QCK1-"@C8%DL.;feC1QS*s%:R9o\kf#dK:`4,dsXL0/>e,r[@6qe0S6l %_XcZ)YP:MlXb:pLehobjn=5$(EG)X+++ctkf@kk5gS45H)"eeQp1tND<\ld@V?__W!cK1=UQ!Tk$VZM^qj32fnRi&S*WAL\3DCUS %I_4JDjlW\k;=Gk=o:ab@HSrkk)TEd9*4k4GO+L0pXj?\=SHb^4Ir(XInh*TWoQK.N[Q76Lc/V6"Thr,$T73[Jn4psJV!FORs.&SZ %PPlE/\`$UKqm@#H.f`K*:`;"d@ZX3\9''*C`]dIRIf9=Fi"0B;RZ?$S#C$d-.4=gsG[!^Y%gm45JNs1gc(G<'9"O:&*Wb$]43,&+ %ki3b4JcW2/.;q6.&:VMGQO>G4!CjV)ocRQ)EWB,5mKE3MmJ`1Fmh%[.ntE7<9\0Qa2R>a+"(WU-he3fWiW(n11lnF='SK=+9,g_N %NZQ$P2BTUdZKsoho'[@lcpcJGR)/;NhZD[3p*'LnmJusMP@jU>#mbcVPdfN])"Y^Dq#UX?IWZI?_rP,$HYr/ua\qUES&lWiZi&7g %*ETc\1OgXha\@J(-']B")QMmE/?79-Mmd*B17bgJ42pK<9iDAppYt4FEl[W"\h$A*<iK-up>s)+Yb7s"$4VVM'8H9M)a1bUZWr$s %OYupfoqE`45.se,;57k2TAFsSp$3WHqU;^L+,noe(dO_gVuj"%$b4Ueo*H35r;+nd!0ZhM%K=J"[?'C!lYlYK0*%gDF1le%CGsb9 %!$[m!`oGR"efmr!D$T>h&fL3<E[Iu'LdG)E1=)d?4g;]OiNi3nj_SE>D,0g5Gf7/P?rsh`jRj>FDbdO2;_DrEi7\Fu!r/nUJ`b&^ %j%G"hG2>t(d9cY,#`oJMjFbp5Ri>b[#&V_CpJ;Nm/^CKY39l7C=8Ik'\_j\F1rmheVKhq>5L:HF5^_ogMu;#1VL>UaJL]66)sUBD %!8!\X3Zo,a^`J"]o"g/P9t\B%X;#?a$:C:XD2%#ABKCpE0fnagS]#nAk(GP@/kr:$AR4*Y;WBjD%>0V%A=[_5:iUuY1C=Hn)#=]= %pV#aipc>D43,8EnjVL'8ad_a*rAE!e%eQeVeR*;#_nIY4!!1C!@)%P"&_bU[$3Ja:Tn51h;j]EY!DhVV@M^+LYkmafHj%_kS$2bc %9u/i,B7Cm"3S<4)-79eJOL*G`WPGd-M"hJC53OfLqo:?tEJbA>%tO_&d``^D:^<^"G$F*GM&EKF=Y4]!6uh,H01CCoQt%Hd__Gu) %M6S]0igV*-gpi$^[ui'8K5CBn2?b@:%!/fZCP;aE-eZEie<,4_oa;bZj&\-hFi]_&DM30hf0,\5>EZ;G`D;pEa4i4#ibZ08:LY]H %"=:!lW!^g@8g[S7S:+ptJIfs[=eGZ^JC\&0eHQCKQ5p7'LH#ir9]nZT*=0b@Yl6hm,Ko!B_,p/X=##0:Q`C2B9>W_BWdr>A:2C)4 %"hY<5Ou=FF1-`-Y<PcU:'Nkb=U=]o%0u[iA+-O0qZi"n`@So*(c<I+`L#/RElMQ>ZDj#--$NZNV)V&F.;[#DIW(O<Xi^p8kjm5gK %=P;*"kYAi<Iu=V@S&?+S4X,>[4q@*$`oBb%d1BK6hShK%IbVk3H[%a9qn=QR("J;&&n%be=]LdQ#N`T$W;#u]$2V=<jq^[>IY*#% %!SRB3r<3(*K#+2=:XJPV+O<BPT:k(7J/m&(-g::;:o%0jT:k(70NduE$2V=<2@"mV59VZg*>0Ha?!^a?Y5qRkn^rVo)NldLIU<L9 %3A>Y>d!CH%H/HO&?JYa0#@A]`$A<ecquqRJ>OXM%$tH5fg-Kmf`GL+[]#qV3F[pCN2M/-J>4:jG?;6oO,U5=b1459KR5k)f^@MR- %*PY<Ln@>Vbn18_<0(@NVMB,N#6?O[TCVpJ1I[sX=51aFXb"8-bW$9Zj'YY?n#o)\u``@<@<e%V'%sHe@chkioP6Z@UE$gpX:2%Q# %F!8L#J('-C1`Er^L8'eLn'c8:h*(2ght-N#bE+E&F&ej9]:Nj&h/qA=rnjEZ)';r/p#.6Hj3=t>eS6p?S;oOll&A?#\.T1`MLpP5 %Ho)BD^P5gn8bX%7M*)$Aa_</C\1TF]^SC_YI4LY*XaM:JN3=$LRO?.=_,;g`hETA'P6hF<pE9Q;<PCGNPnt2,;efF);>i?6>Ti(] %]']F3n6-!MN@[QN@.IoOq<>?8<nW,>^`WE3Bud_6ifGZ)q*KI0Z6+ocN-*]M3#5lckmM6MiM6>C&q26&9INN%p$O16K8#>R(X:BL %2Xm,ZD623Zf.ZU'9%Z*idou7+dIt/t\VS&U\b_rR38^nCBunWp0AqU<4fn+pUgm#PqX!SA*c03%*$!UR(%PJ;:Hf`'mb)`A/W]04 %q6&p3OIpGQjL0*4d9\(Z&=!TV:LWQ"Y:6;(I`Oa89_pLD^l:S:VE_C`]_J7=iL>>;LHR'Ks.FO`E8\KRD'OLh\F9a\_$U.W"/u8. %!4]F>MNKq72[u%iK9'/qQ-9p>g;<.sI6/Tb>:ueopbiatN="P,1FmJ3:-kMQj[G:5+S*R@.[7Iq[b>`%MlI4o.]>,T=dY"uh&V.m %U#X,rF=*L8BDb\Wl1oM`Rc@PG=K`Xt'UBf(5CQ`HDaDJc"j-Z/'fr=!Xe\jI78pUr7S6dTTgSEp>5ic+IcoG*gNi%+d\L:NI)8SN %IiL\ZXIe[+#/GQDZr@TH689/4Vp."B0`Ask!D;'Y0.VWAc_0^R#<^E2m,Jf#1Q",.i26SH8T`TW'Z:bRfUMs"f;B)Z&H@"1fLjKc %H_?8fp>rF`KL*,202\=dW;tj&$nD=ZCs4pV[3D)rlUGs5Y/Q_2A$D\5>@`:Oi/=R[a4m86:;(oi[tci66:!].)GBO%pbhL#695jJ %TLZg;4ZGbC&)+7Bi$f0l3l"EAIsN5ZWT#4?ErsJ!9ti]*DLaT[K/i'ZT8Qm&na"iDC;#4Q?`nOI?dPu^j;6E2\.n^5H+?1?K;(]- %H:C@FKYcaHIUn*u]"^Ndd`u+b-TVI.)R)WYq;adf2u6406jUCIF`Ud`%.UToQK43(']e&]nSll8>!Ij&*Gg):MWSWca\ha7/%HB2 %e_3"D!b:YF/21[oo`Lr(=P.GsjDTrCD!e$M]GIWa8&(::(j%jc`mn"9)q%L<H+I3H1XnL1`RAKqF2.DI\DR-En,.1m%,<1n?RV]g %aRgP=U:JTe<Lje>@@T?G&<TYb"cS@5YXNNc'qK0Q[a:=YM`-Zbkg:d7+j'\`Ms+27BT!G9GaD_>lc+N\TSbDhc;JhH1A#&qh*/LS %PohP54?5^aT!Xps-a3^#=,;0r<.`g.68AtN(5'GG4'0C(nOqeL41GVoa70M`[<$)F2]0qd?IB&A;T*FTbIUR?\<U3R6G/335fXFH %WW6ng@WNVnCC]>\`".hoEUD7TA(SaX*it?Xf-u1O/hFI`:dVZq>2rGs=@&k+a-%oRncC8]Va%7&:_%Y,ONcK]ba5[>+,XE7?sX]M %qE'\p9Pjo2pt*i.#4IZH-R.[i[>s6R)pSTcoeVcJ^OE*/XAK%8FXEabRjmMH5RF4;:XJPVTP\G7IY*#%6.S%snItPA$%RnN5=*&N %!$mM@5=*&NJ2jFT:XJPV(bGO^"T;X.Yf:h_$2V=<%[*R,:OjoJUh`mHD-!0C.pmX%)6M&FD<5PO.^L)8P&9;rD^qNMI'TmPhm=P8 %Ye\W8TX:<K@4?iJ!e+iZ&'$7Q&/sW-ht(u#q!W<;nD,eu..@cHNPo^^rof>+'EVW.nCP\$?peLDI.j$6&8qYhDKdMSa+sJ&4l$!_ %'8Jfcgc)gpi_B?*.6@N@'/qhr)JT7EK1C)%$QFU3%Lgi]%fH(l%j7IuJkqF3aqKd2"/3L>jb\Yc@=JEfB*"Se)(;q1FT]Uk'>42q %peh29I_eh[g]VQ`Dr*[VRgH1iaUemUDu@?=c-"rP#!E[iI*gK"n21o2?XYtR'2rFPB]L$X!LBF^\D?Xng[KRDfa[+;^p<G-n3>Bk %iHi0t$kLf=G]NDhS*gfVh=P=ZZhXk*!aaiC"6MhrLAqL@P;(S~> %AI9_PrivateDataEnd \ No newline at end of file
diff --git a/samples/BlueSquares/BlueSquare.indd b/samples/BlueSquares/BlueSquare.indd
new file mode 100644
index 0000000..c8b9680
--- /dev/null
+++ b/samples/BlueSquares/BlueSquare.indd
Binary files differ
diff --git a/samples/BlueSquares/BlueSquare.jpg b/samples/BlueSquares/BlueSquare.jpg
new file mode 100644
index 0000000..81b8a22
--- /dev/null
+++ b/samples/BlueSquares/BlueSquare.jpg
Binary files differ
diff --git a/samples/BlueSquares/BlueSquare.mov b/samples/BlueSquares/BlueSquare.mov
new file mode 100644
index 0000000..2ee3885
--- /dev/null
+++ b/samples/BlueSquares/BlueSquare.mov
Binary files differ
diff --git a/samples/BlueSquares/BlueSquare.mp3 b/samples/BlueSquares/BlueSquare.mp3
new file mode 100644
index 0000000..0b275b2
--- /dev/null
+++ b/samples/BlueSquares/BlueSquare.mp3
Binary files differ
diff --git a/samples/BlueSquares/BlueSquare.pdf b/samples/BlueSquares/BlueSquare.pdf
new file mode 100644
index 0000000..2498719
--- /dev/null
+++ b/samples/BlueSquares/BlueSquare.pdf
Binary files differ
diff --git a/samples/BlueSquares/BlueSquare.png b/samples/BlueSquares/BlueSquare.png
new file mode 100755
index 0000000..91589cd
--- /dev/null
+++ b/samples/BlueSquares/BlueSquare.png
Binary files differ
diff --git a/samples/BlueSquares/BlueSquare.psd b/samples/BlueSquares/BlueSquare.psd
new file mode 100644
index 0000000..1850b8f
--- /dev/null
+++ b/samples/BlueSquares/BlueSquare.psd
Binary files differ
diff --git a/samples/BlueSquares/BlueSquare.tif b/samples/BlueSquares/BlueSquare.tif
new file mode 100644
index 0000000..3ae7b02
--- /dev/null
+++ b/samples/BlueSquares/BlueSquare.tif
Binary files differ
diff --git a/samples/BlueSquares/BlueSquare.wav b/samples/BlueSquares/BlueSquare.wav
new file mode 100644
index 0000000..c9983ff
--- /dev/null
+++ b/samples/BlueSquares/BlueSquare.wav
Binary files differ
diff --git a/samples/build/gcc/XMPSamples.mak b/samples/build/gcc/XMPSamples.mak
new file mode 100644
index 0000000..e1aaf0f
--- /dev/null
+++ b/samples/build/gcc/XMPSamples.mak
@@ -0,0 +1,178 @@
+# ==================================================================================================
+# Copyright 2002-2004 Adobe Systems Incorporated
+# All Rights Reserved.
+#
+# NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+# of the Adobe license agreement accompanying it.
+# ==================================================================================================
+
+# ==================================================================================================
+
+# Define internal use variables.
+
+Error =
+
+Sample = ${NAME}
+
+ifeq "${Sample}" ""
+ Sample = ${name}
+endif
+
+ifeq "${Sample}" ""
+ Error += The sample name must be provided
+endif
+
+TargetOS = ${OS}
+
+ifeq "${TargetOS}" ""
+ TargetOS = ${os}
+endif
+
+ifeq "${TargetOS}" ""
+ TargetOS = ${MACHTYPE}${OSTYPE}
+endif
+
+ifeq "${TargetOS}" "i386linux" # Linux ${MACHTYPE}${OSTYPE} is i386linux.
+ TargetOS = i80386linux
+endif
+
+ifeq "${TargetOS}" "linux"
+ TargetOS = i80386linux
+endif
+
+ifeq "${TargetOS}" "solaris"
+ TargetOS = sparcsolaris
+endif
+
+ifneq "${TargetOS}" "i80386linux"
+ ifneq "${TargetOS}" "sparcsolaris"
+ Error += Invalid target OS "${TargetOS}"
+ endif
+endif
+
+TargetStage = ${STAGE}
+
+ifeq "${TargetStage}" ""
+ TargetStage = ${stage}
+endif
+
+ifeq "${TargetStage}" ""
+ TargetStage = debug
+endif
+
+ifneq "${TargetStage}" "debug"
+ ifneq "${TargetStage}" "release"
+ Error += Invalid target stage "${TargetStage}"
+ endif
+endif
+
+ifeq "${TargetStage}" "debug"
+ LibSuffix = StaticDebug
+endif
+
+ifeq "${TargetStage}" "release"
+ LibSuffix = StaticRelease
+endif
+
+BuildRoot = ../..
+TargetRoot = ${BuildRoot}/target/${TargetOS}/${TargetStage}
+TempRoot = ${BuildRoot}/intermediate/${TargetOS}/${TargetStage}
+
+XMPRoot = ${BuildRoot}/..
+
+LibXMP = ${XMPRoot}/public/libraries/${TargetOS}/${TargetStage}/libXMPCore${LibSuffix}.a
+
+# ==================================================================================================
+
+CC = gcc
+CPP = gcc -x c++
+LD = gcc
+
+CPPFlags = -fexceptions -funsigned-char -fPIC -Wno-multichar -Wno-implicit -Wno-ctor-dtor-privacy
+CPPFlags += -DUNIX_ENV=1 -D_FILE_OFFSET_BITS=64
+
+LDFlags =
+LDLibs = ${LibXMP} -Xlinker -R -Xlinker .
+LDLibs += -lc -lm -lpthread -lstdc++
+
+ifeq "${TargetOS}" "i80386linux"
+ CFlags += -mcpu=i686
+ LDLibs += -lgcc_eh
+endif
+ifeq "${TargetOS}" "sparcsolaris"
+ CFlags += -mtune=ultrasparc
+endif
+
+ifeq "${TargetStage}" "debug"
+ CFlags += -g -O0 -DDEBUG=1 -D_DEBUG=1
+endif
+ifeq "${TargetStage}" "release"
+ CFlags += -O2 -Os -DNDEBUG=1
+endif
+
+# ==================================================================================================
+
+vpath %.cpp\
+ ${BuildRoot}/source:
+
+Includes = \
+ -I${XMPRoot}/public/include
+
+# ==================================================================================================
+
+${TempRoot}/%.o : %.c
+ @echo ""
+ @echo "Compiling $<"
+ ${CC} ${CPPFlags} ${Includes} -c $< -o $@
+
+${TempRoot}/%.o : %.cpp
+ @echo ""
+ @echo "Compiling $<"
+ ${CPP} ${CPPFlags} ${Includes} -c $< -o $@
+
+${TargetRoot}/% : ${TempRoot}/%.o ${TempRoot}/XMPScanner.o
+ @echo ""
+ @echo "Linking $@"
+ ${LD} ${LDFlags} $< ${TempRoot}/XMPScanner.o ${LDLibs} -o $@
+
+# ==================================================================================================
+
+Sample : Sample_ann msg create_dirs ${TargetRoot}/${Sample}
+ @echo ""
+
+Sample_ann :
+ifeq "${Error}" ""
+ @echo ""
+ @echo Building XMP sample ${Sample} for ${TargetOS} ${TargetStage}
+endif
+ rm -f ${TargetRoot}/${Sample}
+
+msg :
+ifneq "${Error}" ""
+ @echo ""
+ @echo "Error: ${Error}"
+ @echo ""
+ @echo "# To build one of the XMP samples:"
+ @echo "# make -f XMPSamples.mak [os=<os>] [stage=<stage>] name=<sample>"
+ @echo "# where"
+ @echo "# os = i80386linux | sparcsolaris"
+ @echo "# stage = debug | release"
+ @echo "#"
+ @echo "# The name argument is the "simple name" of the sample, e.g."
+ @echo "# XMPCoverage or DumpXMP."
+ @echo "#"
+ @echo "# The os and stage arguments can also be uppercase, OS and STAGE."
+ @echo "# If the OS is omitted it will try to default from the OSTYPE and"
+ @echo "# MACHTYPE environment variables. If the stage is omitted it"
+ @echo "# defaults to debug."
+ @echo ""
+ exit 1
+endif
+
+create_dirs :
+ mkdir -p ${TempRoot}
+ mkdir -p ${TargetRoot}
+
+.PHONY : clean
+clean : msg
+ rm -f ${TempRoot}/* ${TargetRoot}/*
diff --git a/samples/build/vsnet/DumpMainXMP.vcproj b/samples/build/vsnet/DumpMainXMP.vcproj
new file mode 100644
index 0000000..d8e3afd
--- /dev/null
+++ b/samples/build/vsnet/DumpMainXMP.vcproj
@@ -0,0 +1,309 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8,00"
+ Name="DumpMainXMP (static)"
+ ProjectGUID="{9C52F46F-E90C-4FE9-83C5-A2C194C91B54}"
+ RootNamespace="DumpMainXMP"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="../../target/windows/debug"
+ IntermediateDirectory="../../intermediate/windows/debug"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="0"
+ BuildLogFile="$(IntDir)\BuildLog.htm"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\source;..\..\..\public\include\"
+ PreprocessorDefinitions="WIN32=1;_WINDOWS=1;WIN_ENV=1;DEBUG=1;_DEBUG=1;XMP_StaticBuild=1"
+ StringPooling="true"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ BufferSecurityCheck="true"
+ DefaultCharIsUnsigned="true"
+ UsePrecompiledHeader="0"
+ ObjectFile="../../intermediate/windows/debug/"
+ ProgramDataBaseFileName="../../intermediate/windows/debug/"
+ XMLDocumentationFileName="$(IntDir)\"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ CompileAs="0"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="XMPCoreStaticDebug.lib XMPFilesStaticDebug.lib"
+ OutputFile="$(OutDir)/DumpMainXMP.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories="../../../public/libraries/windows/debug/"
+ GenerateDebugInformation="true"
+ AssemblyDebug="1"
+ ProgramDatabaseFile="$(TargetDir)$(TargetName).pdb"
+ GenerateMapFile="true"
+ MapFileName="$(TargetDir)$(TargetName).map"
+ SubSystem="0"
+ OptimizeReferences="0"
+ EnableCOMDATFolding="0"
+ TargetMachine="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="../../target/windows/release"
+ IntermediateDirectory="../../intermediate/windows/release"
+ ConfigurationType="1"
+ CharacterSet="2"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ InlineFunctionExpansion="2"
+ FavorSizeOrSpeed="2"
+ AdditionalIncludeDirectories="..\..\source;..\..\..\public\include\"
+ PreprocessorDefinitions="WIN32=1;_WINDOWS=1;WIN_ENV=1;NDEBUG=1;XMP_StaticBuild=1"
+ StringPooling="true"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="0"
+ SmallerTypeCheck="false"
+ RuntimeLibrary="0"
+ DefaultCharIsUnsigned="true"
+ ForceConformanceInForLoopScope="true"
+ UsePrecompiledHeader="0"
+ ObjectFile="../../intermediate/windows/release/"
+ ProgramDataBaseFileName="../../intermediate/windows/release/"
+ WarningLevel="4"
+ WarnAsError="true"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="0"
+ CompileAs="0"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="XMPCoreStaticRelease.lib XMPFilesStaticRelease.lib"
+ OutputFile="$(OutDir)/DumpMainXMP.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories="../../../public/libraries/windows/release/"
+ GenerateDebugInformation="false"
+ AssemblyDebug="0"
+ ProgramDatabaseFile="$(TargetDir)$(TargetName).pdb"
+ GenerateMapFile="true"
+ MapFileName="$(TargetDir)$(TargetName).map"
+ SubSystem="0"
+ OptimizeReferences="0"
+ EnableCOMDATFolding="0"
+ TargetMachine="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\source\DumpMainXMP.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="..\..\..\..\public\include\TXMPFiles.hpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\public\include\TXMPIterator.hpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\public\include\TXMPMeta.hpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\public\include\TXMPUtils.hpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\public\include\XMP.hpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\public\include\XMP.incl_cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\public\include\XMP_Const.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\public\include\XMP_Environment.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\public\include\XMP_Version.h"
+ >
+ </File>
+ <Filter
+ Name="Client Glue"
+ >
+ <File
+ RelativePath="..\..\..\..\public\include\client-glue\TXMPFiles.incl_cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\public\include\client-glue\TXMPIterator.incl_cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\public\include\client-glue\TXMPMeta.incl_cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\public\include\client-glue\TXMPUtils.incl_cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\public\include\client-glue\WXMP_Common.hpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\public\include\client-glue\WXMPFiles.hpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\public\include\client-glue\WXMPIterator.hpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\public\include\client-glue\WXMPMeta.hpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\public\include\client-glue\WXMPUtils.hpp"
+ >
+ </File>
+ </Filter>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/samples/build/vsnet/DumpScannedXMP.vcproj b/samples/build/vsnet/DumpScannedXMP.vcproj
new file mode 100644
index 0000000..9759e2f
--- /dev/null
+++ b/samples/build/vsnet/DumpScannedXMP.vcproj
@@ -0,0 +1,230 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8,00"
+ Name="DumpScannedXMP"
+ ProjectGUID="{5E467275-083F-4C6E-8645-EC3CCA70E3DE}"
+ RootNamespace="DumpScannedXMP"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="../../target/windows/debug"
+ IntermediateDirectory="../../intermediate/windows/debug"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../../../public/include/"
+ PreprocessorDefinitions="WIN32=1;_WINDOWS=1;WIN_ENV=1;DEBUG=1;_DEBUG=1"
+ StringPooling="true"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="1"
+ SmallerTypeCheck="true"
+ RuntimeLibrary="1"
+ DefaultCharIsUnsigned="true"
+ ForceConformanceInForLoopScope="true"
+ UsePrecompiledHeader="0"
+ ObjectFile="../../intermediate/windows/debug/"
+ ProgramDataBaseFileName="../../intermediate/windows/debug/"
+ WarningLevel="4"
+ WarnAsError="false"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ CompileAs="0"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="XMPCoreStaticDebug.lib"
+ OutputFile="$(OutDir)/DumpScannedXMP.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories="../../../public/libraries/windows/debug/"
+ GenerateDebugInformation="true"
+ AssemblyDebug="1"
+ ProgramDatabaseFile="$(TargetDir)$(TargetName).pdb"
+ GenerateMapFile="true"
+ MapFileName="$(TargetDir)$(TargetName).map"
+ SubSystem="0"
+ OptimizeReferences="0"
+ EnableCOMDATFolding="0"
+ TargetMachine="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="../../target/windows/release"
+ IntermediateDirectory="../../intermediate/windows/release"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ InlineFunctionExpansion="2"
+ AdditionalIncludeDirectories="../../../public/include/;"
+ PreprocessorDefinitions="WIN32=1;_WINDOWS=1;WIN_ENV=1;NDEBUG=1"
+ StringPooling="true"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="0"
+ SmallerTypeCheck="false"
+ RuntimeLibrary="0"
+ DefaultCharIsUnsigned="true"
+ ForceConformanceInForLoopScope="true"
+ UsePrecompiledHeader="0"
+ ObjectFile="../../intermediate/windows/release/"
+ ProgramDataBaseFileName="../../intermediate/windows/release/"
+ WarningLevel="4"
+ WarnAsError="true"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="0"
+ CompileAs="0"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="XMPCoreStaticRelease.lib"
+ OutputFile="$(OutDir)/DumpScannedXMP.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories="../../../public/libraries/windows/release/"
+ GenerateDebugInformation="false"
+ AssemblyDebug="0"
+ ProgramDatabaseFile="$(TargetDir)$(TargetName).pdb"
+ GenerateMapFile="true"
+ MapFileName="$(TargetDir)$(TargetName).map"
+ SubSystem="0"
+ OptimizeReferences="0"
+ EnableCOMDATFolding="0"
+ TargetMachine="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\source\DumpScannedXMP.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\source\XMPScanner.cpp"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/samples/build/vsnet/XMPCoreCoverage.vcproj b/samples/build/vsnet/XMPCoreCoverage.vcproj
new file mode 100644
index 0000000..b794bd3
--- /dev/null
+++ b/samples/build/vsnet/XMPCoreCoverage.vcproj
@@ -0,0 +1,226 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8,00"
+ Name="XMPCoreCoverage"
+ ProjectGUID="{6E63FCD8-1D1B-41E6-85CB-79EE9E95E89E}"
+ RootNamespace="XMPCoreCoverage"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="../../target/windows/debug"
+ IntermediateDirectory="../../intermediate/windows/debug"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../../../public/include/"
+ PreprocessorDefinitions="WIN32=1;_WINDOWS=1;WIN_ENV=1;DEBUG=1;_DEBUG=1"
+ StringPooling="true"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="1"
+ SmallerTypeCheck="true"
+ RuntimeLibrary="1"
+ DefaultCharIsUnsigned="true"
+ ForceConformanceInForLoopScope="true"
+ UsePrecompiledHeader="0"
+ ObjectFile="../../intermediate/windows/debug/"
+ ProgramDataBaseFileName="../../intermediate/windows/debug/"
+ WarningLevel="4"
+ WarnAsError="false"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ CompileAs="0"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="XMPCoreStaticDebug.lib"
+ OutputFile="$(OutDir)/XMPCoreCoverage.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories="../../../public/libraries/windows/debug/"
+ GenerateDebugInformation="true"
+ AssemblyDebug="1"
+ ProgramDatabaseFile="$(TargetDir)$(TargetName).pdb"
+ GenerateMapFile="true"
+ MapFileName="$(TargetDir)$(TargetName).map"
+ SubSystem="0"
+ OptimizeReferences="0"
+ EnableCOMDATFolding="0"
+ TargetMachine="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="../../target/windows/release"
+ IntermediateDirectory="../../intermediate/windows/release"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ InlineFunctionExpansion="2"
+ AdditionalIncludeDirectories="../../../public/include/;"
+ PreprocessorDefinitions="WIN32=1;_WINDOWS=1;WIN_ENV=1;NDEBUG=1"
+ StringPooling="true"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="0"
+ SmallerTypeCheck="false"
+ RuntimeLibrary="0"
+ DefaultCharIsUnsigned="true"
+ ForceConformanceInForLoopScope="true"
+ UsePrecompiledHeader="0"
+ ObjectFile="../../intermediate/windows/release/"
+ ProgramDataBaseFileName="../../intermediate/windows/release/"
+ WarningLevel="4"
+ WarnAsError="true"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="0"
+ CompileAs="0"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="XMPCoreStaticRelease.lib"
+ OutputFile="$(OutDir)/XMPCoreCoverage.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories="../../../public/libraries/windows/release/"
+ GenerateDebugInformation="false"
+ AssemblyDebug="0"
+ ProgramDatabaseFile="$(TargetDir)$(TargetName).pdb"
+ GenerateMapFile="true"
+ MapFileName="$(TargetDir)$(TargetName).map"
+ SubSystem="0"
+ OptimizeReferences="0"
+ EnableCOMDATFolding="0"
+ TargetMachine="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\source\XMPCoreCoverage.cpp"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/samples/build/vsnet/XMPFilesCoverage.vcproj b/samples/build/vsnet/XMPFilesCoverage.vcproj
new file mode 100644
index 0000000..412f4ef
--- /dev/null
+++ b/samples/build/vsnet/XMPFilesCoverage.vcproj
@@ -0,0 +1,319 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8,00"
+ Name="XMPFilesCoverage"
+ ProjectGUID="{7179F7FA-1A10-4B1C-9E99-8F8B20E51C7C}"
+ RootNamespace="XMPFilesCoverage"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="../../target/windows/debug"
+ IntermediateDirectory="../../intermediate/windows/debug"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="0"
+ BuildLogFile="$(IntDir)\BuildLog.htm"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\..\public\include\"
+ PreprocessorDefinitions="WIN32=1;_WINDOWS=1;WIN_ENV=1;DEBUG=1;_DEBUG=1"
+ StringPooling="true"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ BufferSecurityCheck="true"
+ DefaultCharIsUnsigned="true"
+ UsePrecompiledHeader="0"
+ ObjectFile="../../intermediate/windows/debug/"
+ ProgramDataBaseFileName="../../intermediate/windows/debug/"
+ XMLDocumentationFileName="$(IntDir)\"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ CompileAs="0"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="XMPCoreStaticDebug.lib XMPFilesStaticDebug.lib"
+ OutputFile="$(OutDir)/XMPFilesCoverage.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories="../../../public/libraries/windows/debug/"
+ GenerateDebugInformation="true"
+ AssemblyDebug="1"
+ ProgramDatabaseFile="$(TargetDir)$(TargetName).pdb"
+ GenerateMapFile="true"
+ MapFileName="$(TargetDir)$(TargetName).map"
+ SubSystem="0"
+ OptimizeReferences="0"
+ EnableCOMDATFolding="0"
+ TargetMachine="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ CommandLine="xcopy /d /i /y ..\..\BlueSquares\*.* ..\..\target\windows\debug\BlueSquares&#x0D;&#x0A;attrib -R ..\..\target\windows\debug\BlueSquares\*.*&#x0D;&#x0A;"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="../../target/windows/release"
+ IntermediateDirectory="../../intermediate/windows/release"
+ ConfigurationType="1"
+ CharacterSet="2"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ InlineFunctionExpansion="2"
+ FavorSizeOrSpeed="2"
+ AdditionalIncludeDirectories="..\..\..\public\include\"
+ PreprocessorDefinitions="WIN32=1;_WINDOWS=1;WIN_ENV=1;NDEBUG=1"
+ StringPooling="true"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="0"
+ SmallerTypeCheck="false"
+ RuntimeLibrary="0"
+ DefaultCharIsUnsigned="true"
+ ForceConformanceInForLoopScope="true"
+ UsePrecompiledHeader="0"
+ ObjectFile="../../intermediate/windows/release/"
+ ProgramDataBaseFileName="../../intermediate/windows/release/"
+ WarningLevel="4"
+ WarnAsError="true"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="0"
+ CompileAs="0"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="XMPCoreStaticRelease.lib XMPFilesStaticRelease.lib"
+ OutputFile="$(OutDir)/XMPFilesCoverage.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories="../../../public/libraries/windows/release/"
+ GenerateDebugInformation="false"
+ AssemblyDebug="0"
+ ProgramDatabaseFile="$(TargetDir)$(TargetName).pdb"
+ GenerateMapFile="true"
+ MapFileName="$(TargetDir)$(TargetName).map"
+ SubSystem="0"
+ OptimizeReferences="0"
+ EnableCOMDATFolding="0"
+ TargetMachine="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ CommandLine="xcopy /d /i /y ..\..\BlueSquares\*.* ..\..\target\windows\release\BlueSquares&#x0D;&#x0A;attrib -R ..\..\target\windows\release\BlueSquares\*.*&#x0D;&#x0A;"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\source\XMPFilesCoverage.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="..\..\..\..\public\include\TXMPFiles.hpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\public\include\TXMPIterator.hpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\public\include\TXMPMeta.hpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\public\include\TXMPUtils.hpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\public\include\XMP.hpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\public\include\XMP.incl_cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\public\include\XMP_Const.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\public\include\XMP_Environment.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\public\include\XMP_Version.h"
+ >
+ </File>
+ <Filter
+ Name="Client Glue"
+ >
+ <File
+ RelativePath="..\..\..\..\public\include\client-glue\TXMPFiles.incl_cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\public\include\client-glue\TXMPIterator.incl_cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\public\include\client-glue\TXMPMeta.incl_cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\public\include\client-glue\TXMPUtils.incl_cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\public\include\client-glue\WXMP_Common.hpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\public\include\client-glue\WXMPFiles.hpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\public\include\client-glue\WXMPIterator.hpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\public\include\client-glue\WXMPMeta.hpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\public\include\client-glue\WXMPUtils.hpp"
+ >
+ </File>
+ </Filter>
+ </Filter>
+ <Filter
+ Name="Build Files"
+ >
+ <File
+ RelativePath="CopyFiles.bat"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/samples/build/vsnet/XMPSamples.sln b/samples/build/vsnet/XMPSamples.sln
new file mode 100644
index 0000000..a4c318a
--- /dev/null
+++ b/samples/build/vsnet/XMPSamples.sln
@@ -0,0 +1,37 @@
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual Studio 2005
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "XMPCoreCoverage", "XMPCoreCoverage.vcproj", "{6E63FCD8-1D1B-41E6-85CB-79EE9E95E89E}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DumpScannedXMP", "DumpScannedXMP.vcproj", "{5E467275-083F-4C6E-8645-EC3CCA70E3DE}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "XMPFilesCoverage", "XMPFilesCoverage.vcproj", "{7179F7FA-1A10-4B1C-9E99-8F8B20E51C7C}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DumpMainXMP (static)", "DumpMainXMP.vcproj", "{9C52F46F-E90C-4FE9-83C5-A2C194C91B54}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {6E63FCD8-1D1B-41E6-85CB-79EE9E95E89E}.Debug|Win32.ActiveCfg = Debug|Win32
+ {6E63FCD8-1D1B-41E6-85CB-79EE9E95E89E}.Debug|Win32.Build.0 = Debug|Win32
+ {6E63FCD8-1D1B-41E6-85CB-79EE9E95E89E}.Release|Win32.ActiveCfg = Release|Win32
+ {6E63FCD8-1D1B-41E6-85CB-79EE9E95E89E}.Release|Win32.Build.0 = Release|Win32
+ {5E467275-083F-4C6E-8645-EC3CCA70E3DE}.Debug|Win32.ActiveCfg = Debug|Win32
+ {5E467275-083F-4C6E-8645-EC3CCA70E3DE}.Debug|Win32.Build.0 = Debug|Win32
+ {5E467275-083F-4C6E-8645-EC3CCA70E3DE}.Release|Win32.ActiveCfg = Release|Win32
+ {5E467275-083F-4C6E-8645-EC3CCA70E3DE}.Release|Win32.Build.0 = Release|Win32
+ {7179F7FA-1A10-4B1C-9E99-8F8B20E51C7C}.Debug|Win32.ActiveCfg = Debug|Win32
+ {7179F7FA-1A10-4B1C-9E99-8F8B20E51C7C}.Debug|Win32.Build.0 = Debug|Win32
+ {7179F7FA-1A10-4B1C-9E99-8F8B20E51C7C}.Release|Win32.ActiveCfg = Release|Win32
+ {7179F7FA-1A10-4B1C-9E99-8F8B20E51C7C}.Release|Win32.Build.0 = Release|Win32
+ {9C52F46F-E90C-4FE9-83C5-A2C194C91B54}.Debug|Win32.ActiveCfg = Debug|Win32
+ {9C52F46F-E90C-4FE9-83C5-A2C194C91B54}.Debug|Win32.Build.0 = Debug|Win32
+ {9C52F46F-E90C-4FE9-83C5-A2C194C91B54}.Release|Win32.ActiveCfg = Release|Win32
+ {9C52F46F-E90C-4FE9-83C5-A2C194C91B54}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/samples/build/xcode/XMPSamples-Common.xcconfig b/samples/build/xcode/XMPSamples-Common.xcconfig
new file mode 100644
index 0000000..53dcdb0
--- /dev/null
+++ b/samples/build/xcode/XMPSamples-Common.xcconfig
@@ -0,0 +1,39 @@
+SAMPLES_ROOT = ${PROJECT_DIR}/../..
+
+SOURCE_ROOT = ${SAMPLES_ROOT}/source
+SRCROOT = ${SOURCE_ROOT}
+XMP_ROOT = ${SAMPLES_ROOT}/../public
+
+PREBINDING = NO
+ZERO_LINK = NO
+
+ARCHS = ppc i386
+MACOSX_DEPLOYMENT_TARGET = 10.3
+SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk
+
+SHARED_PRECOMPS_DIR =
+PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR = NO
+GCC_PRECOMPILE_PREFIX_HEADER = NO
+
+HEADER_SEARCH_PATHS = ${PROJECT_DIR} ${SOURCE_ROOT} ${XMP_ROOT}/include /Developer/Headers/FlatCarbon
+FRAMEWORK_SEARCH_PATHS = ${SDKROOT}/System/Library/Frameworks
+
+COMMON_DEFINES = MAC_ENV=1
+
+GCC_CHAR_IS_UNSIGNED_CHAR = YES
+GCC_ENABLE_PASCAL_STRINGS = NO
+GCC_SHORT_ENUMS = YES
+GCC_ONE_BYTE_BOOL = YES
+GCC_NO_COMMON_BLOCKS = YES
+GCC_FAST_MATH = YES
+
+GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES
+GCC_WARN_ABOUT_RETURN_TYPE = YES
+GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES
+GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES
+GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES
+GCC_WARN_MISSING_PARENTHESES = YES
+GCC_WARN_CHECK_SWITCH_STATEMENTS = YES
+GCC_WARN_UNKNOWN_PRAGMAS = YES
+GCC_WARN_SIGN_COMPARE = YES
+GCC_WARN_ABOUT_MISSING_NEWLINE = YES
diff --git a/samples/build/xcode/XMPSamples-Debug.xcconfig b/samples/build/xcode/XMPSamples-Debug.xcconfig
new file mode 100644
index 0000000..78a602e
--- /dev/null
+++ b/samples/build/xcode/XMPSamples-Debug.xcconfig
@@ -0,0 +1,15 @@
+BUILD_MODE = debug
+LIB_SUFFIX = StaticDebug
+
+OTHER_LDFLAGS = ${XMP_ROOT}/libraries/macintosh/${BUILD_MODE}/libXMPCore${LIB_SUFFIX}.a ${XMP_ROOT}/libraries/macintosh/${BUILD_MODE}/libXMPFiles${LIB_SUFFIX}.a -framework Carbon
+
+OBJROOT = ${SAMPLES_ROOT}/intermediate/macintosh/${BUILD_MODE}
+SYMROOT = ${SAMPLES_ROOT}/target/macintosh/${BUILD_MODE}
+
+CONFIGURATION_BUILD_DIR = ${SYMROOT}
+
+GCC_PREPROCESSOR_DEFINITIONS = ${COMMON_DEFINES} DEBUG=1 _DEBUG=1
+
+GCC_GENERATE_DEBUGGING_SYMBOLS = YES
+GCC_DEBUGGING_SYMBOLS = full
+GCC_OPTIMIZATION_LEVEL = 0
diff --git a/samples/build/xcode/XMPSamples-Release.xcconfig b/samples/build/xcode/XMPSamples-Release.xcconfig
new file mode 100644
index 0000000..87c599a
--- /dev/null
+++ b/samples/build/xcode/XMPSamples-Release.xcconfig
@@ -0,0 +1,15 @@
+BUILD_MODE = release
+LIB_SUFFIX = StaticRelease
+
+OTHER_LDFLAGS = ${XMP_ROOT}/libraries/macintosh/${BUILD_MODE}/libXMPCore${LIB_SUFFIX}.a ${XMP_ROOT}/libraries/macintosh/${BUILD_MODE}/libXMPFiles${LIB_SUFFIX}.a -framework Carbon
+
+OBJROOT = ${SAMPLES_ROOT}/intermediate/macintosh/${BUILD_MODE}
+SYMROOT = ${SAMPLES_ROOT}/target/macintosh/${BUILD_MODE}
+
+CONFIGURATION_BUILD_DIR = ${SYMROOT}
+
+GCC_PREPROCESSOR_DEFINITIONS = ${COMMON_DEFINES} NDEBUG=1
+
+GCC_GENERATE_DEBUGGING_SYMBOLS = NO
+GCC_DEBUGGING_SYMBOLS = used
+GCC_OPTIMIZATION_LEVEL = s
diff --git a/samples/build/xcode/XMPSamples.xcodeproj/project.pbxproj b/samples/build/xcode/XMPSamples.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..4a94bb0
--- /dev/null
+++ b/samples/build/xcode/XMPSamples.xcodeproj/project.pbxproj
@@ -0,0 +1,705 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 42;
+ objects = {
+
+/* Begin PBXAggregateTarget section */
+ DC97291609A3EACA005A68DF /* Build All */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = DC97292709A3EB4F005A68DF /* Build configuration list for PBXAggregateTarget "Build All" */;
+ buildPhases = (
+ );
+ dependencies = (
+ DC97291809A3EAD0005A68DF /* PBXTargetDependency */,
+ DC97291E09A3EB06005A68DF /* PBXTargetDependency */,
+ DC97292009A3EB0C005A68DF /* PBXTargetDependency */,
+ DC97292209A3EB12005A68DF /* PBXTargetDependency */,
+ 018882280B7C941400EECA52 /* PBXTargetDependency */,
+ 018882260B7C941400EECA52 /* PBXTargetDependency */,
+ 018882240B7C941400EECA52 /* PBXTargetDependency */,
+ 018882220B7C941400EECA52 /* PBXTargetDependency */,
+ );
+ name = "Build All";
+ productName = "Build All";
+ };
+/* End PBXAggregateTarget section */
+
+/* Begin PBXBuildFile section */
+ 018881FF0B7C93A300EECA52 /* XMPFilesCoverage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 018881EE0B7C934100EECA52 /* XMPFilesCoverage.cpp */; };
+ 018882000B7C93A300EECA52 /* XMPFilesCoverage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 018881EE0B7C934100EECA52 /* XMPFilesCoverage.cpp */; };
+ 018882040B7C93AB00EECA52 /* XMPScanner.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DC97291309A3E9BF005A68DF /* XMPScanner.cpp */; };
+ 0188820D0B7C93AF00EECA52 /* XMPScanner.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DC97291309A3E9BF005A68DF /* XMPScanner.cpp */; };
+ 018882130B7C93EE00EECA52 /* DumpMainXMP.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 018881ED0B7C934100EECA52 /* DumpMainXMP.cpp */; };
+ 018882140B7C93EF00EECA52 /* DumpMainXMP.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 018881ED0B7C934100EECA52 /* DumpMainXMP.cpp */; };
+ DC97291109A3E9B7005A68DF /* DumpScannedXMP.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DC97291009A3E9B7005A68DF /* DumpScannedXMP.cpp */; };
+ DC97291209A3E9B7005A68DF /* DumpScannedXMP.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DC97291009A3E9B7005A68DF /* DumpScannedXMP.cpp */; };
+ DC97291409A3E9BF005A68DF /* XMPScanner.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DC97291309A3E9BF005A68DF /* XMPScanner.cpp */; };
+ DC97291509A3E9BF005A68DF /* XMPScanner.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DC97291309A3E9BF005A68DF /* XMPScanner.cpp */; };
+ DCE615430951C75C001247EE /* XMPCoreCoverage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCF3A64D087F1D9000FEB713 /* XMPCoreCoverage.cpp */; };
+ DCED0E5D089E7E6E009B80AF /* XMPCoreCoverage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCF3A64D087F1D9000FEB713 /* XMPCoreCoverage.cpp */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ 018882210B7C941400EECA52 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 0188820A0B7C93AF00EECA52;
+ remoteInfo = "DumpMainXMP Release";
+ };
+ 018882230B7C941400EECA52 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 018882010B7C93AB00EECA52;
+ remoteInfo = "DumpMainXMP Debug";
+ };
+ 018882250B7C941400EECA52 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 018881F70B7C936A00EECA52;
+ remoteInfo = "XMPFilesCoverage Release";
+ };
+ 018882270B7C941400EECA52 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 018881EF0B7C935100EECA52;
+ remoteInfo = "XMPFilesCoverage Debug";
+ };
+ DC97291709A3EAD0005A68DF /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = DCED0E5B089E7E6E009B80AF;
+ remoteInfo = "XMPCoverage Debug";
+ };
+ DC97291D09A3EB06005A68DF /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = DCE615410951C75C001247EE;
+ remoteInfo = "XMPCoverage Release";
+ };
+ DC97291F09A3EB0C005A68DF /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = DC9728FD09A3E964005A68DF;
+ remoteInfo = "DumpXMP Debug";
+ };
+ DC97292109A3EB12005A68DF /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = DC97290509A3E969005A68DF;
+ remoteInfo = "DumpXMP Release";
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXFileReference section */
+ 018881ED0B7C934100EECA52 /* DumpMainXMP.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = DumpMainXMP.cpp; sourceTree = "<group>"; };
+ 018881EE0B7C934100EECA52 /* XMPFilesCoverage.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = XMPFilesCoverage.cpp; sourceTree = "<group>"; };
+ 018881F50B7C935100EECA52 /* XMPFilesCoverage */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = XMPFilesCoverage; sourceTree = BUILT_PRODUCTS_DIR; };
+ 018881FD0B7C936A00EECA52 /* XMPFilesCoverage */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = XMPFilesCoverage; sourceTree = BUILT_PRODUCTS_DIR; };
+ 018882080B7C93AB00EECA52 /* DumpMainXMP */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = DumpMainXMP; sourceTree = BUILT_PRODUCTS_DIR; };
+ 018882110B7C93AF00EECA52 /* DumpMainXMP */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = DumpMainXMP; sourceTree = BUILT_PRODUCTS_DIR; };
+ DC97290309A3E964005A68DF /* DumpScannedXMP */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = DumpScannedXMP; sourceTree = BUILT_PRODUCTS_DIR; };
+ DC97290B09A3E969005A68DF /* DumpScannedXMP */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = DumpScannedXMP; sourceTree = BUILT_PRODUCTS_DIR; };
+ DC97291009A3E9B7005A68DF /* DumpScannedXMP.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = DumpScannedXMP.cpp; sourceTree = "<group>"; };
+ DC97291309A3E9BF005A68DF /* XMPScanner.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = XMPScanner.cpp; sourceTree = "<group>"; };
+ DCE400B00951CF710040D71F /* XMPSamples-Common.xcconfig */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.xcconfig; path = "XMPSamples-Common.xcconfig"; sourceTree = "<group>"; };
+ DCE400B10951CF710040D71F /* XMPSamples-Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.xcconfig; path = "XMPSamples-Debug.xcconfig"; sourceTree = "<group>"; };
+ DCE400B20951CF710040D71F /* XMPSamples-Release.xcconfig */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.xcconfig; path = "XMPSamples-Release.xcconfig"; sourceTree = "<group>"; };
+ DCE615470951C75C001247EE /* XMPCoreCoverage */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = XMPCoreCoverage; sourceTree = BUILT_PRODUCTS_DIR; };
+ DCED0E65089E7E6E009B80AF /* XMPCoreCoverage */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = XMPCoreCoverage; sourceTree = BUILT_PRODUCTS_DIR; };
+ DCF3A64D087F1D9000FEB713 /* XMPCoreCoverage.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = XMPCoreCoverage.cpp; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 018881F20B7C935100EECA52 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 018881FA0B7C936A00EECA52 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 018882050B7C93AB00EECA52 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 0188820E0B7C93AF00EECA52 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ DC97290009A3E964005A68DF /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ DC97290809A3E969005A68DF /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ DCE615440951C75C001247EE /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ DCED0E5E089E7E6E009B80AF /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 08FB7794FE84155DC02AAC07 /* XMPCoverage */ = {
+ isa = PBXGroup;
+ children = (
+ 08FB7795FE84155DC02AAC07 /* Source */,
+ DCE4006D0951CC850040D71F /* Build Extras */,
+ 1AB674ADFE9D54B511CA2CBB /* Products */,
+ );
+ name = XMPCoverage;
+ sourceTree = "<group>";
+ };
+ 08FB7795FE84155DC02AAC07 /* Source */ = {
+ isa = PBXGroup;
+ children = (
+ 018881ED0B7C934100EECA52 /* DumpMainXMP.cpp */,
+ 018881EE0B7C934100EECA52 /* XMPFilesCoverage.cpp */,
+ DCF3A64D087F1D9000FEB713 /* XMPCoreCoverage.cpp */,
+ DC97291009A3E9B7005A68DF /* DumpScannedXMP.cpp */,
+ DC97291309A3E9BF005A68DF /* XMPScanner.cpp */,
+ );
+ name = Source;
+ path = ../../source;
+ sourceTree = "<group>";
+ };
+ 1AB674ADFE9D54B511CA2CBB /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ DCED0E65089E7E6E009B80AF /* XMPCoreCoverage */,
+ DCE615470951C75C001247EE /* XMPCoreCoverage */,
+ DC97290309A3E964005A68DF /* DumpScannedXMP */,
+ DC97290B09A3E969005A68DF /* DumpScannedXMP */,
+ 018881F50B7C935100EECA52 /* XMPFilesCoverage */,
+ 018881FD0B7C936A00EECA52 /* XMPFilesCoverage */,
+ 018882080B7C93AB00EECA52 /* DumpMainXMP */,
+ 018882110B7C93AF00EECA52 /* DumpMainXMP */,
+ );
+ name = Products;
+ path = ../..;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ DCE4006D0951CC850040D71F /* Build Extras */ = {
+ isa = PBXGroup;
+ children = (
+ DCE400B00951CF710040D71F /* XMPSamples-Common.xcconfig */,
+ DCE400B10951CF710040D71F /* XMPSamples-Debug.xcconfig */,
+ DCE400B20951CF710040D71F /* XMPSamples-Release.xcconfig */,
+ );
+ name = "Build Extras";
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 018881EF0B7C935100EECA52 /* XMPFilesCoverage Debug */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 018881F30B7C935100EECA52 /* Build configuration list for PBXNativeTarget "XMPFilesCoverage Debug" */;
+ buildPhases = (
+ 018881F00B7C935100EECA52 /* Sources */,
+ 018881F20B7C935100EECA52 /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = "XMPFilesCoverage Debug";
+ productInstallPath = "$(HOME)/bin";
+ productName = XMPCoverage;
+ productReference = 018881F50B7C935100EECA52 /* XMPFilesCoverage */;
+ productType = "com.apple.product-type.tool";
+ };
+ 018881F70B7C936A00EECA52 /* XMPFilesCoverage Release */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 018881FB0B7C936A00EECA52 /* Build configuration list for PBXNativeTarget "XMPFilesCoverage Release" */;
+ buildPhases = (
+ 018881F80B7C936A00EECA52 /* Sources */,
+ 018881FA0B7C936A00EECA52 /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = "XMPFilesCoverage Release";
+ productInstallPath = "$(HOME)/bin";
+ productName = XMPCoverage;
+ productReference = 018881FD0B7C936A00EECA52 /* XMPFilesCoverage */;
+ productType = "com.apple.product-type.tool";
+ };
+ 018882010B7C93AB00EECA52 /* DumpMainXMP Debug */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 018882060B7C93AB00EECA52 /* Build configuration list for PBXNativeTarget "DumpMainXMP Debug" */;
+ buildPhases = (
+ 018882020B7C93AB00EECA52 /* Sources */,
+ 018882050B7C93AB00EECA52 /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = "DumpMainXMP Debug";
+ productInstallPath = "$(HOME)/bin";
+ productName = XMPCoverage;
+ productReference = 018882080B7C93AB00EECA52 /* DumpMainXMP */;
+ productType = "com.apple.product-type.tool";
+ };
+ 0188820A0B7C93AF00EECA52 /* DumpMainXMP Release */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 0188820F0B7C93AF00EECA52 /* Build configuration list for PBXNativeTarget "DumpMainXMP Release" */;
+ buildPhases = (
+ 0188820B0B7C93AF00EECA52 /* Sources */,
+ 0188820E0B7C93AF00EECA52 /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = "DumpMainXMP Release";
+ productInstallPath = "$(HOME)/bin";
+ productName = XMPCoverage;
+ productReference = 018882110B7C93AF00EECA52 /* DumpMainXMP */;
+ productType = "com.apple.product-type.tool";
+ };
+ DC9728FD09A3E964005A68DF /* DumpScannedXMP Debug */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = DC97290109A3E964005A68DF /* Build configuration list for PBXNativeTarget "DumpScannedXMP Debug" */;
+ buildPhases = (
+ DC9728FE09A3E964005A68DF /* Sources */,
+ DC97290009A3E964005A68DF /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = "DumpScannedXMP Debug";
+ productInstallPath = "$(HOME)/bin";
+ productName = XMPCoverage;
+ productReference = DC97290309A3E964005A68DF /* DumpScannedXMP */;
+ productType = "com.apple.product-type.tool";
+ };
+ DC97290509A3E969005A68DF /* DumpScannedXMP Release */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = DC97290909A3E969005A68DF /* Build configuration list for PBXNativeTarget "DumpScannedXMP Release" */;
+ buildPhases = (
+ DC97290609A3E969005A68DF /* Sources */,
+ DC97290809A3E969005A68DF /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = "DumpScannedXMP Release";
+ productInstallPath = "$(HOME)/bin";
+ productName = XMPCoverage;
+ productReference = DC97290B09A3E969005A68DF /* DumpScannedXMP */;
+ productType = "com.apple.product-type.tool";
+ };
+ DCE615410951C75C001247EE /* XMPCoreCoverage Release */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = DCE615450951C75C001247EE /* Build configuration list for PBXNativeTarget "XMPCoreCoverage Release" */;
+ buildPhases = (
+ DCE615420951C75C001247EE /* Sources */,
+ DCE615440951C75C001247EE /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = "XMPCoreCoverage Release";
+ productInstallPath = "$(HOME)/bin";
+ productName = XMPCoverage;
+ productReference = DCE615470951C75C001247EE /* XMPCoreCoverage */;
+ productType = "com.apple.product-type.tool";
+ };
+ DCED0E5B089E7E6E009B80AF /* XMPCoreCoverage Debug */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = DCED0E60089E7E6E009B80AF /* Build configuration list for PBXNativeTarget "XMPCoreCoverage Debug" */;
+ buildPhases = (
+ DCED0E5C089E7E6E009B80AF /* Sources */,
+ DCED0E5E089E7E6E009B80AF /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = "XMPCoreCoverage Debug";
+ productInstallPath = "$(HOME)/bin";
+ productName = XMPCoverage;
+ productReference = DCED0E65089E7E6E009B80AF /* XMPCoreCoverage */;
+ productType = "com.apple.product-type.tool";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 08FB7793FE84155DC02AAC07 /* Project object */ = {
+ isa = PBXProject;
+ buildConfigurationList = DC47BE960871F34F0088D201 /* Build configuration list for PBXProject "XMPSamples" */;
+ hasScannedForEncodings = 1;
+ mainGroup = 08FB7794FE84155DC02AAC07 /* XMPCoverage */;
+ projectDirPath = "";
+ targets = (
+ DC97291609A3EACA005A68DF /* Build All */,
+ DCED0E5B089E7E6E009B80AF /* XMPCoreCoverage Debug */,
+ DCE615410951C75C001247EE /* XMPCoreCoverage Release */,
+ DC9728FD09A3E964005A68DF /* DumpScannedXMP Debug */,
+ DC97290509A3E969005A68DF /* DumpScannedXMP Release */,
+ 018881EF0B7C935100EECA52 /* XMPFilesCoverage Debug */,
+ 018881F70B7C936A00EECA52 /* XMPFilesCoverage Release */,
+ 018882010B7C93AB00EECA52 /* DumpMainXMP Debug */,
+ 0188820A0B7C93AF00EECA52 /* DumpMainXMP Release */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 018881F00B7C935100EECA52 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 018881FF0B7C93A300EECA52 /* XMPFilesCoverage.cpp in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 018881F80B7C936A00EECA52 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 018882000B7C93A300EECA52 /* XMPFilesCoverage.cpp in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 018882020B7C93AB00EECA52 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 018882040B7C93AB00EECA52 /* XMPScanner.cpp in Sources */,
+ 018882130B7C93EE00EECA52 /* DumpMainXMP.cpp in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 0188820B0B7C93AF00EECA52 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 0188820D0B7C93AF00EECA52 /* XMPScanner.cpp in Sources */,
+ 018882140B7C93EF00EECA52 /* DumpMainXMP.cpp in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ DC9728FE09A3E964005A68DF /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ DC97291109A3E9B7005A68DF /* DumpScannedXMP.cpp in Sources */,
+ DC97291409A3E9BF005A68DF /* XMPScanner.cpp in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ DC97290609A3E969005A68DF /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ DC97291209A3E9B7005A68DF /* DumpScannedXMP.cpp in Sources */,
+ DC97291509A3E9BF005A68DF /* XMPScanner.cpp in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ DCE615420951C75C001247EE /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ DCE615430951C75C001247EE /* XMPCoreCoverage.cpp in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ DCED0E5C089E7E6E009B80AF /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ DCED0E5D089E7E6E009B80AF /* XMPCoreCoverage.cpp in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ 018882220B7C941400EECA52 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 0188820A0B7C93AF00EECA52 /* DumpMainXMP Release */;
+ targetProxy = 018882210B7C941400EECA52 /* PBXContainerItemProxy */;
+ };
+ 018882240B7C941400EECA52 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 018882010B7C93AB00EECA52 /* DumpMainXMP Debug */;
+ targetProxy = 018882230B7C941400EECA52 /* PBXContainerItemProxy */;
+ };
+ 018882260B7C941400EECA52 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 018881F70B7C936A00EECA52 /* XMPFilesCoverage Release */;
+ targetProxy = 018882250B7C941400EECA52 /* PBXContainerItemProxy */;
+ };
+ 018882280B7C941400EECA52 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 018881EF0B7C935100EECA52 /* XMPFilesCoverage Debug */;
+ targetProxy = 018882270B7C941400EECA52 /* PBXContainerItemProxy */;
+ };
+ DC97291809A3EAD0005A68DF /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = DCED0E5B089E7E6E009B80AF /* XMPCoreCoverage Debug */;
+ targetProxy = DC97291709A3EAD0005A68DF /* PBXContainerItemProxy */;
+ };
+ DC97291E09A3EB06005A68DF /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = DCE615410951C75C001247EE /* XMPCoreCoverage Release */;
+ targetProxy = DC97291D09A3EB06005A68DF /* PBXContainerItemProxy */;
+ };
+ DC97292009A3EB0C005A68DF /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = DC9728FD09A3E964005A68DF /* DumpScannedXMP Debug */;
+ targetProxy = DC97291F09A3EB0C005A68DF /* PBXContainerItemProxy */;
+ };
+ DC97292209A3EB12005A68DF /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = DC97290509A3E969005A68DF /* DumpScannedXMP Release */;
+ targetProxy = DC97292109A3EB12005A68DF /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin XCBuildConfiguration section */
+ 018881F40B7C935100EECA52 /* Default */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = DCE400B10951CF710040D71F /* XMPSamples-Debug.xcconfig */;
+ buildSettings = {
+ OTHER_LDFLAGS = (
+ "${XMP_ROOT}/libraries/macintosh/${BUILD_MODE}/libXMPCore${LIB_SUFFIX}.a",
+ "${XMP_ROOT}/libraries/macintosh/${BUILD_MODE}/libXMPFiles${LIB_SUFFIX}.a",
+ "-framework",
+ Carbon,
+ "-framework",
+ QuickTime,
+ );
+ PRODUCT_NAME = XMPFilesCoverage;
+ };
+ name = Default;
+ };
+ 018881FC0B7C936A00EECA52 /* Default */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = DCE400B20951CF710040D71F /* XMPSamples-Release.xcconfig */;
+ buildSettings = {
+ OTHER_LDFLAGS = (
+ "${XMP_ROOT}/libraries/macintosh/${BUILD_MODE}/libXMPCore${LIB_SUFFIX}.a",
+ "${XMP_ROOT}/libraries/macintosh/${BUILD_MODE}/libXMPFiles${LIB_SUFFIX}.a",
+ "-framework",
+ Carbon,
+ "-framework",
+ QuickTime,
+ );
+ PRODUCT_NAME = XMPFilesCoverage;
+ };
+ name = Default;
+ };
+ 018882070B7C93AB00EECA52 /* Default */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = DCE400B10951CF710040D71F /* XMPSamples-Debug.xcconfig */;
+ buildSettings = {
+ OTHER_LDFLAGS = (
+ "${XMP_ROOT}/libraries/macintosh/${BUILD_MODE}/libXMPCore${LIB_SUFFIX}.a",
+ "${XMP_ROOT}/libraries/macintosh/${BUILD_MODE}/libXMPFiles${LIB_SUFFIX}.a",
+ "-framework",
+ Carbon,
+ "-framework",
+ QuickTime,
+ );
+ PRODUCT_NAME = DumpMainXMP;
+ };
+ name = Default;
+ };
+ 018882100B7C93AF00EECA52 /* Default */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = DCE400B20951CF710040D71F /* XMPSamples-Release.xcconfig */;
+ buildSettings = {
+ OTHER_LDFLAGS = (
+ "${XMP_ROOT}/libraries/macintosh/${BUILD_MODE}/libXMPCore${LIB_SUFFIX}.a",
+ "${XMP_ROOT}/libraries/macintosh/${BUILD_MODE}/libXMPFiles${LIB_SUFFIX}.a",
+ "-framework",
+ Carbon,
+ "-framework",
+ QuickTime,
+ );
+ PRODUCT_NAME = DumpMainXMP;
+ };
+ name = Default;
+ };
+ DC47BE980871F34F0088D201 /* Default */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = DCE400B00951CF710040D71F /* XMPSamples-Common.xcconfig */;
+ buildSettings = {
+ };
+ name = Default;
+ };
+ DC97290209A3E964005A68DF /* Default */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = DCE400B10951CF710040D71F /* XMPSamples-Debug.xcconfig */;
+ buildSettings = {
+ PRODUCT_NAME = DumpScannedXMP;
+ };
+ name = Default;
+ };
+ DC97290A09A3E969005A68DF /* Default */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = DCE400B20951CF710040D71F /* XMPSamples-Release.xcconfig */;
+ buildSettings = {
+ PRODUCT_NAME = DumpScannedXMP;
+ };
+ name = Default;
+ };
+ DC97292809A3EB4F005A68DF /* Default */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "Build All";
+ };
+ name = Default;
+ };
+ DCE615460951C75C001247EE /* Default */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = DCE400B20951CF710040D71F /* XMPSamples-Release.xcconfig */;
+ buildSettings = {
+ PRODUCT_NAME = XMPCoreCoverage;
+ };
+ name = Default;
+ };
+ DCED0E63089E7E6E009B80AF /* Default */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = DCE400B10951CF710040D71F /* XMPSamples-Debug.xcconfig */;
+ buildSettings = {
+ PRODUCT_NAME = XMPCoreCoverage;
+ };
+ name = Default;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 018881F30B7C935100EECA52 /* Build configuration list for PBXNativeTarget "XMPFilesCoverage Debug" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 018881F40B7C935100EECA52 /* Default */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Default;
+ };
+ 018881FB0B7C936A00EECA52 /* Build configuration list for PBXNativeTarget "XMPFilesCoverage Release" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 018881FC0B7C936A00EECA52 /* Default */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Default;
+ };
+ 018882060B7C93AB00EECA52 /* Build configuration list for PBXNativeTarget "DumpMainXMP Debug" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 018882070B7C93AB00EECA52 /* Default */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Default;
+ };
+ 0188820F0B7C93AF00EECA52 /* Build configuration list for PBXNativeTarget "DumpMainXMP Release" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 018882100B7C93AF00EECA52 /* Default */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Default;
+ };
+ DC47BE960871F34F0088D201 /* Build configuration list for PBXProject "XMPSamples" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ DC47BE980871F34F0088D201 /* Default */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Default;
+ };
+ DC97290109A3E964005A68DF /* Build configuration list for PBXNativeTarget "DumpScannedXMP Debug" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ DC97290209A3E964005A68DF /* Default */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Default;
+ };
+ DC97290909A3E969005A68DF /* Build configuration list for PBXNativeTarget "DumpScannedXMP Release" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ DC97290A09A3E969005A68DF /* Default */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Default;
+ };
+ DC97292709A3EB4F005A68DF /* Build configuration list for PBXAggregateTarget "Build All" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ DC97292809A3EB4F005A68DF /* Default */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Default;
+ };
+ DCE615450951C75C001247EE /* Build configuration list for PBXNativeTarget "XMPCoreCoverage Release" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ DCE615460951C75C001247EE /* Default */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Default;
+ };
+ DCED0E60089E7E6E009B80AF /* Build configuration list for PBXNativeTarget "XMPCoreCoverage Debug" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ DCED0E63089E7E6E009B80AF /* Default */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Default;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 08FB7793FE84155DC02AAC07 /* Project object */;
+}
diff --git a/samples/source/DumpMainXMP.cpp b/samples/source/DumpMainXMP.cpp
new file mode 100644
index 0000000..805b999
--- /dev/null
+++ b/samples/source/DumpMainXMP.cpp
@@ -0,0 +1,158 @@
+// XMP Toolkit sample application to dump the main XMP packet in a file using the XMP File Handler
+// component of the XMP Toolkit. This is preferred over "dumb" packet scanning.
+
+// =================================================================================================
+// Copyright 2002-2005 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include <string>
+#include <time.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdexcept>
+#include <errno.h>
+
+#if WIN_ENV
+ #pragma warning ( disable : 4127 ) // conditional expression is constant
+ #pragma warning ( disable : 4996 ) // '...' was declared deprecated
+#endif
+
+#define TXMP_STRING_TYPE std::string
+#define XMP_INCLUDE_XMPFILES 1
+#include "XMP.hpp"
+#include "XMP.incl_cpp"
+
+using namespace std;
+
+static FILE * sLogFile = stdout;
+
+// =================================================================================================
+
+static void WriteMinorLabel ( FILE * log, const char * title )
+{
+
+ fprintf ( log, "\n// " );
+ for ( size_t i = 0; i < strlen(title); ++i ) fprintf ( log, "-" );
+ fprintf ( log, "--\n// %s :\n\n", title );
+ fflush ( log );
+
+} // WriteMinorLabel
+
+// =================================================================================================
+
+static XMP_Status DumpCallback ( void * refCon, XMP_StringPtr outStr, XMP_StringLen outLen )
+{
+ XMP_Status status = 0;
+ size_t count;
+ FILE * outFile = static_cast < FILE * > ( refCon );
+
+ count = fwrite ( outStr, 1, outLen, outFile );
+ if ( count != outLen ) status = errno;
+ return status;
+
+} // DumpCallback
+
+// =================================================================================================
+
+static void
+ProcessFile ( const char * fileName )
+{
+ bool ok;
+ char buffer [1000];
+
+ SXMPMeta xmpMeta;
+ SXMPFiles xmpFile;
+ XMP_FileFormat format;
+ XMP_OptionBits openFlags, handlerFlags;
+ XMP_PacketInfo xmpPacket;
+
+ sprintf ( buffer, "Dumping main XMP for %s", fileName );
+ WriteMinorLabel ( sLogFile, buffer );
+
+ xmpFile.OpenFile ( fileName, kXMP_UnknownFile, kXMPFiles_OpenForRead );
+ ok = xmpFile.GetFileInfo ( 0, &openFlags, &format, &handlerFlags );
+ if ( ! ok ) return;
+
+ fprintf ( sLogFile, "File info : format = \"%.4s\", handler flags = %.8X\n", &format, handlerFlags );
+ fflush ( sLogFile );
+
+ ok = xmpFile.GetXMP ( &xmpMeta, 0, &xmpPacket );
+ if ( ! ok ) return;
+
+ XMP_Int32 offset = (XMP_Int32)xmpPacket.offset;
+ XMP_Int32 length = xmpPacket.length;
+ fprintf ( sLogFile, "Packet info : offset = %d, length = %d\n", offset, length );
+ fflush ( sLogFile );
+
+ fprintf ( sLogFile, "\nInitial XMP from %s\n", fileName );
+ xmpMeta.DumpObject ( DumpCallback, sLogFile );
+
+ xmpFile.CloseFile();
+
+} // ProcessFile
+
+// =================================================================================================
+
+extern "C" int
+main ( int argc, const char * argv [] )
+{
+
+ if ( ! SXMPMeta::Initialize() ) {
+ printf ( "## SXMPMeta::Initialize failed!\n" );
+ return -1;
+ }
+
+ if ( ! SXMPFiles::Initialize() ) {
+ fprintf ( sLogFile, "## SXMPFiles::Initialize failed!\n" );
+ return -1;
+ }
+
+ if ( argc > 1 ) {
+
+ printf ( "\n" );
+ for ( int i = 1; i < argc; i++ ) ProcessFile ( argv[i] );
+
+ } else {
+
+ char fileNameBuffer[1025];
+
+ while ( true ) {
+
+ printf ( "\nFile: " );
+ fgets( fileNameBuffer, sizeof(fileNameBuffer), stdin );
+ string fileName ( fileNameBuffer );
+
+ if ( fileName.empty() ) break;
+
+ if ( (fileName[fileName.size()-1] == '\n') || (fileName[fileName.size()-1] == '\r') ) {
+ fileName.erase ( fileName.size()-1, 1 ); // Remove eol, allowing for CRLF.
+ if ( (fileName[fileName.size()-1] == '\n') || (fileName[fileName.size()-1] == '\r') ) {
+ fileName.erase ( fileName.size()-1, 1 );
+ }
+ }
+
+ if ( fileName == "." ) break;
+
+ // Dragging an icon on Windows pastes a quoted path.
+ if ( fileName[fileName.size()-1] == '"' ) fileName.erase ( fileName.size()-1, 1 );
+ if ( fileName[0] == '"' ) fileName.erase ( 0, 1 );
+
+ if ( ! fileName.empty() ) {
+ printf ( "\n" );
+ ProcessFile ( fileName.c_str() );
+ }
+
+ }
+
+ }
+
+ SXMPFiles::Terminate();
+ SXMPMeta::Terminate();
+ return 0;
+
+}
diff --git a/samples/source/DumpScannedXMP.cpp b/samples/source/DumpScannedXMP.cpp
new file mode 100644
index 0000000..c8c5f94
--- /dev/null
+++ b/samples/source/DumpScannedXMP.cpp
@@ -0,0 +1,188 @@
+// =================================================================================================
+// Copyright 2002-2005 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include <string>
+#include <time.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdexcept>
+#include <errno.h>
+
+#if WIN_ENV
+ #pragma warning ( disable : 4127 ) // conditional expression is constant
+ #pragma warning ( disable : 4996 ) // '...' was declared deprecated
+#endif
+
+#define TXMP_STRING_TYPE std::string
+
+#include "XMP.hpp"
+#include "XMP.incl_cpp"
+
+#include "XMPScanner.hpp"
+
+using namespace std;
+
+// =================================================================================================
+
+static XMP_Status DumpCallback ( void * refCon, XMP_StringPtr outStr, XMP_StringLen outLen )
+{
+ XMP_Status status = 0;
+ size_t count;
+ FILE * outFile = static_cast < FILE * > ( refCon );
+
+ count = fwrite ( outStr, 1, outLen, outFile );
+ if ( count != outLen ) status = errno;
+ return status;
+
+} // DumpCallback
+
+// =================================================================================================
+
+static void
+ProcessPacket ( const char * fileName,
+ FILE * inFile,
+ size_t offset,
+ size_t length )
+{
+ std::string xmlString;
+ xmlString.append ( length, ' ' );
+ fseek ( inFile, offset, SEEK_SET );
+ fread ( (void*)xmlString.data(), 1, length, inFile );
+
+ char title [1000];
+
+ sprintf ( title, "// Dumping raw input for \"%s\" (%d..%d)", fileName, offset, (offset + length - 1) );
+ printf ( "// " );
+ for ( size_t i = 3; i < strlen(title); ++i ) printf ( "=" );
+ printf ( "\n\n%s\n\n%.*s\n\n", title, length, xmlString.c_str() );
+ fflush ( stdout );
+
+ SXMPMeta xmpObj;
+ try {
+ xmpObj.ParseFromBuffer ( xmlString.c_str(), length );
+ } catch ( ... ) {
+ printf ( "## Parse failed\n\n" );
+ return;
+ }
+
+ xmpObj.DumpObject ( DumpCallback, stdout );
+ fflush ( stdout );
+
+ string xmpString;
+ xmpObj.SerializeToBuffer ( &xmpString, kXMP_OmitPacketWrapper );
+ printf ( "\nPretty serialization, %d bytes :\n\n%s\n", xmpString.size(), xmpString.c_str() );
+ fflush ( stdout );
+
+ xmpObj.SerializeToBuffer ( &xmpString, (kXMP_OmitPacketWrapper | kXMP_UseCompactFormat) );
+ printf ( "Compact serialization, %d bytes :\n\n%s\n", xmpString.size(), xmpString.c_str() );
+ fflush ( stdout );
+
+} // ProcessPacket
+
+// =================================================================================================
+
+static void
+ProcessFile ( const char * fileName )
+{
+ FILE * inFile;
+ size_t fileLen, readCount;
+ size_t snipCount;
+ char buffer [64*1024];
+
+ // ---------------------------------------------------------------------
+ // Use the scanner to find all of the packets then process each of them.
+
+ inFile = fopen ( fileName, "rb" );
+ if ( inFile == 0 ) {
+ printf ( "Can't open \"%s\"\n", fileName );
+ return;
+ }
+
+ fseek ( inFile, 0, SEEK_END );
+ fileLen = ftell ( inFile ); // ! Only handles up to 2GB files.
+ fseek ( inFile, 0, SEEK_SET );
+
+ XMPScanner scanner ( fileLen );
+
+ for ( size_t filePos = 0; true; filePos += readCount ) {
+ readCount = fread ( buffer, 1, sizeof(buffer), inFile );
+ if ( readCount == 0 ) break;
+ scanner.Scan ( buffer, filePos, readCount );
+ }
+
+ snipCount = scanner.GetSnipCount();
+
+ XMPScanner::SnipInfoVector snips (snipCount);
+ scanner.Report ( snips );
+
+ size_t packetCount = 0;
+ for ( size_t s = 0; s < snipCount; ++s ) {
+ if ( snips[s].fState == XMPScanner::eValidPacketSnip ) {
+ ++packetCount;
+ ProcessPacket ( fileName, inFile, (size_t)snips[s].fOffset, (size_t)snips[s].fLength );
+ }
+ }
+ if ( packetCount == 0 ) printf ( " No packets found\n" );
+
+} // ProcessFile
+
+// =================================================================================================
+
+extern "C" int
+main ( int argc, const char * argv [] )
+{
+
+ if ( ! SXMPMeta::Initialize() ) {
+ printf ( "## SXMPMeta::Initialize failed!\n" );
+ return -1;
+ }
+
+ if ( argc > 1 ) {
+
+ printf ( "\n" );
+ for ( int i = 1; i < argc; i++ ) ProcessFile ( argv[i] );
+
+ } else {
+
+ char fileNameBuffer[1025];
+
+ while ( true ) {
+
+ printf ( "\nFile: " );
+ fgets( fileNameBuffer, sizeof(fileNameBuffer), stdin );
+ string fileName ( fileNameBuffer );
+
+ if ( fileName.empty() ) break;
+
+ if ( (fileName[fileName.size()-1] == '\n') || (fileName[fileName.size()-1] == '\r') ) {
+ fileName.erase ( fileName.size()-1, 1 ); // Remove eol, allowing for CRLF.
+ if ( (fileName[fileName.size()-1] == '\n') || (fileName[fileName.size()-1] == '\r') ) {
+ fileName.erase ( fileName.size()-1, 1 );
+ }
+ }
+
+ if ( fileName == "." ) break;
+
+ // Dragging an icon on Windows pastes a quoted path.
+ if ( fileName[fileName.size()-1] == '"' ) fileName.erase ( fileName.size()-1, 1 );
+ if ( fileName[0] == '"' ) fileName.erase ( 0, 1 );
+
+ if ( ! fileName.empty() ) {
+ printf ( "\n" );
+ ProcessFile ( fileName.c_str() );
+ }
+
+ }
+
+ }
+
+ SXMPMeta::Terminate();
+ return 0;
+
+}
diff --git a/samples/source/XMPCoreCoverage.cpp b/samples/source/XMPCoreCoverage.cpp
new file mode 100644
index 0000000..feb6306
--- /dev/null
+++ b/samples/source/XMPCoreCoverage.cpp
@@ -0,0 +1,1955 @@
+#include <string>
+#include <iostream>
+#include <iomanip>
+#include <fstream>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <time.h>
+
+#define TXMP_STRING_TYPE std::string
+
+#include "XMP.hpp"
+#include "XMP.incl_cpp"
+
+using namespace std;
+
+#if WIN_ENV
+ #pragma warning ( disable : 4100 ) // ignore unused variable
+ #pragma warning ( disable : 4127 ) // conditional expression is constant
+ #pragma warning ( disable : 4505 ) // unreferenced local function has been removed
+ #pragma warning ( disable : 4996 ) // '...' was declared deprecated
+#endif
+
+// =================================================================================================
+
+static const char * kNS1 = "ns:test1/";
+static const char * kNS2 = "ns:test2/";
+
+static const char * kRDFCoverage =
+ "<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>"
+ " <rdf:Description rdf:about='Test:XMPCoreCoverage/kRDFCoverage' xmlns:ns1='ns:test1/' xmlns:ns2='ns:test2/'>"
+ ""
+ " <ns1:SimpleProp1>Simple1 value</ns1:SimpleProp1>"
+ " <ns1:SimpleProp2 xml:lang='x-default'>Simple2 value</ns1:SimpleProp2>"
+ ""
+ " <ns1:ArrayProp1>"
+ " <rdf:Bag>"
+ " <rdf:li>Item1.1 value</rdf:li>"
+ " <rdf:li>Item1.2 value</rdf:li>"
+ " </rdf:Bag>"
+ " </ns1:ArrayProp1>"
+ ""
+ " <ns1:ArrayProp2>"
+ " <rdf:Alt>"
+ " <rdf:li xml:lang='x-one'>Item2.1 value</rdf:li>"
+ " <rdf:li xml:lang='x-two'>Item2.2 value</rdf:li>"
+ " </rdf:Alt>"
+ " </ns1:ArrayProp2>"
+ ""
+ " <ns1:ArrayProp3>"
+ " <rdf:Alt>"
+ " <rdf:li xml:lang='x-one'>Item3.1 value</rdf:li>"
+ " <rdf:li>Item3.2 value</rdf:li>"
+ " </rdf:Alt>"
+ " </ns1:ArrayProp3>"
+ ""
+ " <ns1:ArrayProp4>"
+ " <rdf:Alt>"
+ " <rdf:li>Item4.1 value</rdf:li>"
+ " <rdf:li xml:lang='x-two'>Item4.2 value</rdf:li>"
+ " </rdf:Alt>"
+ " </ns1:ArrayProp4>"
+ ""
+ " <ns1:ArrayProp5>"
+ " <rdf:Alt>"
+ " <rdf:li xml:lang='x-xxx'>Item5.1 value</rdf:li>"
+ " <rdf:li xml:lang='x-xxx'>Item5.2 value</rdf:li>"
+ " </rdf:Alt>"
+ " </ns1:ArrayProp5>"
+ ""
+ " <ns1:StructProp rdf:parseType='Resource'>"
+ " <ns2:Field1>Field1 value</ns2:Field1>"
+ " <ns2:Field2>Field2 value</ns2:Field2>"
+ " </ns1:StructProp>"
+ ""
+ " <ns1:QualProp1 rdf:parseType='Resource'>"
+ " <rdf:value>Prop value</rdf:value>"
+ " <ns2:Qual>Qual value</ns2:Qual>"
+ " </ns1:QualProp1>"
+ ""
+ " <ns1:QualProp2 rdf:parseType='Resource'>"
+ " <rdf:value xml:lang='x-default'>Prop value</rdf:value>"
+ " <ns2:Qual>Qual value</ns2:Qual>"
+ " </ns1:QualProp2>"
+ ""
+ " <!-- NOTE: QualProp3 is not quite kosher. Normally a qualifier on a struct is attached to the -->"
+ " <!-- struct node in the XMP tree, and the same for an array. See QualProp4 and QualProp5. But -->"
+ " <!-- for the pseudo-struct of a qualified simple property there is no final struct node that -->"
+ " <!-- can own the qualifier. Instead the qualifier is attached to the value. The alternative -->"
+ " <!-- of attaching the qualifier to the value and all other qualifiers is not compelling. This -->"
+ " <!-- issue only arises for xml:lang, it is the only qualifier that RDF has as an attribute. -->"
+ ""
+ " <ns1:QualProp3 xml:lang='x-default' rdf:parseType='Resource'>"
+ " <rdf:value>Prop value</rdf:value>"
+ " <ns2:Qual>Qual value</ns2:Qual>"
+ " </ns1:QualProp3>"
+ ""
+ " <ns1:QualProp4 xml:lang='x-default' rdf:parseType='Resource'>"
+ " <ns2:Field1>Field1 value</ns2:Field1>"
+ " <ns2:Field2>Field2 value</ns2:Field2>"
+ " </ns1:QualProp4>"
+ ""
+ " <ns1:QualProp5 xml:lang='x-default'>"
+ " <rdf:Bag>"
+ " <rdf:li>Item1.1 value</rdf:li>"
+ " <rdf:li>Item1.2 value</rdf:li>"
+ " </rdf:Bag>"
+ " </ns1:QualProp5>"
+ ""
+ " <ns2:NestedStructProp rdf:parseType='Resource'>"
+ " <ns1:Outer rdf:parseType='Resource'>"
+ " <ns1:Middle rdf:parseType='Resource'>"
+ " <ns1:Inner rdf:parseType='Resource'>"
+ " <ns1:Field1>Field1 value</ns1:Field1>"
+ " <ns2:Field2>Field2 value</ns2:Field2>"
+ " </ns1:Inner>"
+ " </ns1:Middle>"
+ " </ns1:Outer>"
+ " </ns2:NestedStructProp>"
+ ""
+ " </rdf:Description>"
+ "</rdf:RDF>";
+
+static const char * kSimpleRDF =
+ "<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>"
+ " <rdf:Description rdf:about='Test:XMPCoreCoverage/kSimpleRDF' xmlns:ns1='ns:test1/' xmlns:ns2='ns:test2/'>"
+ ""
+ " <ns1:SimpleProp>Simple value</ns1:SimpleProp>"
+ ""
+ " <ns1:ArrayProp>"
+ " <rdf:Bag>"
+ " <rdf:li>Item1 value</rdf:li>"
+ " <rdf:li>Item2 value</rdf:li>"
+ " </rdf:Bag>"
+ " </ns1:ArrayProp>"
+ ""
+ " <ns1:StructProp rdf:parseType='Resource'>"
+ " <ns2:Field1>Field1 value</ns2:Field1>"
+ " <ns2:Field2>Field2 value</ns2:Field2>"
+ " </ns1:StructProp>"
+ ""
+ " <ns1:QualProp rdf:parseType='Resource'>"
+ " <rdf:value>Prop value</rdf:value>"
+ " <ns2:Qual>Qual value</ns2:Qual>"
+ " </ns1:QualProp>"
+ ""
+ " <ns1:AltTextProp>"
+ " <rdf:Alt>"
+ " <rdf:li xml:lang='x-one'>x-one value</rdf:li>"
+ " <rdf:li xml:lang='x-two'>x-two value</rdf:li>"
+ " </rdf:Alt>"
+ " </ns1:AltTextProp>"
+ ""
+ " <ns1:ArrayOfStructProp>"
+ " <rdf:Bag>"
+ " <rdf:li rdf:parseType='Resource'>"
+ " <ns2:Field1>Item-1</ns2:Field1>"
+ " <ns2:Field2>Field 1.2 value</ns2:Field2>"
+ " </rdf:li>"
+ " <rdf:li rdf:parseType='Resource'>"
+ " <ns2:Field1>Item-2</ns2:Field1>"
+ " <ns2:Field2>Field 2.2 value</ns2:Field2>"
+ " </rdf:li>"
+ " </rdf:Bag>"
+ " </ns1:ArrayOfStructProp>"
+ ""
+ " </rdf:Description>"
+ "</rdf:RDF>";
+
+static const char * kNamespaceRDF =
+ "<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>"
+ " <rdf:Description rdf:about='Test:XMPCoreCoverage/kNamespaceRDF' xmlns:ns1='ns:test1/'>"
+ ""
+ " <ns1:NestedStructProp rdf:parseType='Resource'>"
+ " <ns2:Outer rdf:parseType='Resource' xmlns:ns2='ns:test2/' xmlns:ns3='ns:test3/'>"
+ " <ns3:Middle rdf:parseType='Resource' xmlns:ns4='ns:test4/'>"
+ " <ns4:Inner rdf:parseType='Resource' xmlns:ns5='ns:test5/' xmlns:ns6='ns:test6/'>"
+ " <ns5:Field1>Field1 value</ns5:Field1>"
+ " <ns6:Field2>Field2 value</ns6:Field2>"
+ " </ns4:Inner>"
+ " </ns3:Middle>"
+ " </ns2:Outer>"
+ " </ns1:NestedStructProp>"
+ ""
+ " </rdf:Description>"
+ "</rdf:RDF>";
+
+static const char * kXMPMetaRDF =
+ "<x:Outermost xmlns:x='adobe:ns:meta/'>"
+ ""
+ "<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>"
+ " <rdf:Description rdf:about='Test:XMPCoreCoverage/kBogusLeadingRDF' xmlns:ns1='ns:test1/'>"
+ " <ns1:BogusLeadingProp>bogus packet</ns1:BogusLeadingProp>"
+ " </rdf:Description>"
+ "</rdf:RDF>"
+ ""
+ "<x:xmpmeta>"
+ "<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>"
+ " <rdf:Description rdf:about='Test:XMPCoreCoverage/kXMPMetaRDF' xmlns:ns1='ns:test1/'>"
+ " <ns1:XMPMetaProp>xmpmeta packet</ns1:XMPMetaProp>"
+ " </rdf:Description>"
+ "</rdf:RDF>"
+ "</x:xmpmeta>"
+ ""
+ "<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>"
+ " <rdf:Description rdf:about='Test:XMPCoreCoverage/kBogusTrailingRDF' xmlns:ns1='ns:test1/'>"
+ " <ns1:BogusTrailingProp>bogus packet</ns1:BogusTrailingProp>"
+ " </rdf:Description>"
+ "</rdf:RDF>"
+ ""
+ "</x:Outermost>";
+
+static const char * kNewlineRDF =
+ "<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>"
+ " <rdf:Description rdf:about='Test:XMPCoreCoverage/kNewlineRDF' xmlns:ns1='ns:test1/'>"
+ ""
+ " <ns1:HasCR>ASCII &#xD; CR</ns1:HasCR>"
+ " <ns1:HasLF>ASCII &#xA; LF</ns1:HasLF>"
+ " <ns1:HasCRLF>ASCII &#xD;&#xA; CRLF</ns1:HasCRLF>"
+ ""
+ " </rdf:Description>"
+ "</rdf:RDF>";
+
+static const char * kInconsistentRDF =
+ "<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>"
+ " <rdf:Description rdf:about='Test:XMPCoreCoverage/kInconsistentRDF'"
+ " xmlns:pdf='http://ns.adobe.com/pdf/1.3/'"
+ " xmlns:xmp='http://ns.adobe.com/xap/1.0/'"
+ " xmlns:dc='http://purl.org/dc/elements/1.1/'>"
+ ""
+ " <pdf:Author>PDF Author</pdf:Author>"
+ " <xmp:Author>XMP Author</xmp:Author>"
+ ""
+ " <xmp:Authors>"
+ " <rdf:Seq>"
+ " <rdf:li>XMP Authors [1]</rdf:li>"
+ " </rdf:Seq>"
+ " </xmp:Authors>"
+ ""
+ " <dc:creator>"
+ " <rdf:Seq>"
+ " <rdf:li>DC Creator [1]</rdf:li>"
+ " </rdf:Seq>"
+ " </dc:creator>"
+ ""
+ " </rdf:Description>"
+ "</rdf:RDF>";
+
+static const char * kDateTimeRDF =
+ "<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>"
+ " <rdf:Description rdf:about='Test:XMPCoreCoverage/kDateTimeRDF' xmlns:ns1='ns:test1/'>"
+ ""
+ " <ns1:Date1>2003</ns1:Date1>"
+ " <ns1:Date2>2003-12</ns1:Date2>"
+ " <ns1:Date3>2003-12-31</ns1:Date3>"
+ ""
+ " <ns1:Date4>2003-12-31T12:34Z</ns1:Date4>"
+ " <ns1:Date5>2003-12-31T12:34:56Z</ns1:Date5>"
+ ""
+ " <ns1:Date6>2003-12-31T12:34:56.001Z</ns1:Date6>"
+ " <ns1:Date7>2003-12-31T12:34:56.000000001Z</ns1:Date7>"
+ ""
+ " <ns1:Date8>2003-12-31T10:04:56-02:30</ns1:Date8>"
+ " <ns1:Date9>2003-12-31T15:49:56+03:15</ns1:Date9>"
+ ""
+ " </rdf:Description>"
+ "</rdf:RDF>";
+
+// =================================================================================================
+
+#define FoundOrNot(b) ((b) ? "found" : "not found")
+#define YesOrNo(b) ((b) ? "yes" : "no")
+
+// -------------------------------------------------------------------------------------------------
+
+static void WriteMajorLabel ( FILE * log, const char * title )
+{
+
+ fprintf ( log, "\n" );
+ fprintf ( log, "// =============================================================================\n" );
+ fprintf ( log, "// %s.\n", title );
+ fprintf ( log, "// =============================================================================\n" );
+ fflush ( log );
+
+} // WriteMajorLabel
+
+// -------------------------------------------------------------------------------------------------
+
+static void WriteMinorLabel ( FILE * log, const char * title )
+{
+
+ fprintf ( log, "\n// " );
+ for ( size_t i = 0; i < strlen(title); ++i ) fprintf ( log, "-" );
+ fprintf ( log, "--\n// %s :\n\n", title );
+ fflush ( log );
+
+} // WriteMinorLabel
+
+// -------------------------------------------------------------------------------------------------
+
+static XMP_Status DumpToString ( void * refCon, XMP_StringPtr outStr, XMP_StringLen outLen )
+{
+ XMP_Status status = 0;
+ std::string * dumpString = (std::string*)refCon;
+
+ try {
+ dumpString->append ( outStr, outLen );
+ } catch ( ... ) {
+ status = -1;
+ }
+ return status;
+
+} // DumpToString
+
+// -------------------------------------------------------------------------------------------------
+
+static XMP_Status DumpToFile ( void * refCon, XMP_StringPtr outStr, XMP_StringLen outLen )
+{
+ XMP_Status status = 0;
+ size_t count;
+ FILE * outFile = static_cast < FILE * > ( refCon );
+
+ count = fwrite ( outStr, 1, outLen, outFile );
+ if ( count != outLen ) status = errno;
+ fflush ( outFile );
+ return status;
+
+} // DumpToFile
+
+// -------------------------------------------------------------------------------------------------
+
+static void DumpXMPObj ( FILE * log, SXMPMeta & meta, const char * title )
+{
+
+ WriteMinorLabel ( log, title );
+ meta.DumpObject ( DumpToFile, log );
+
+} // DumpXMPObj
+
+// -------------------------------------------------------------------------------------------------
+
+static void VerifyNewlines ( FILE * log, std::string xmp, const char * newline )
+{
+ for ( size_t i = 0; i < xmp.size(); ++i ) {
+ if ( (xmp[i] == '\x0A') || (xmp[i] == '\x0D') ) {
+ if ( strncmp ( &xmp[i], newline, strlen(newline) ) != 0 ) {
+ fprintf ( log, "** Wrong newline at offset %d\n", i );
+ }
+ if ( strlen(newline) == 2 ) ++i;
+ }
+ }
+}
+
+// =================================================================================================
+
+static void DoXMPCoreCoverage ( FILE * log )
+{
+
+ int i;
+ bool ok;
+ std::string tmpStr1, tmpStr2, tmpStr3, tmpStr4;
+ XMP_OptionBits options;
+
+ #if 0
+ { // Use this to be able to move the app window away from debugger windows.
+ string junk;
+ cout << "Move window, type anything to continue";
+ cin >> junk;
+ }
+ #endif
+
+ // --------------------------------------------------------------------------------------------
+
+ #if 0
+
+ WriteMajorLabel ( log, "Test global XMP toolkit options" );
+
+ fprintf ( log, "Initial global options 0x%X\n", SXMPMeta::GetGlobalOptions() );
+ SXMPMeta::SetGlobalOptions ( 0 );
+ fprintf ( log, "Final global options 0x%X\n", SXMPMeta::GetGlobalOptions() );
+
+ #endif
+
+ // --------------------------------------------------------------------------------------------
+
+ WriteMajorLabel ( log, "Dump predefined namespaces and aliases" );
+
+ SXMPMeta::DumpNamespaces ( DumpToFile, log );
+ fprintf ( log, "\n" );
+ SXMPMeta::DumpAliases ( DumpToFile, log );
+
+ // --------------------------------------------------------------------------------------------
+
+ {
+ WriteMajorLabel ( log, "Test simple constructors and parsing, setting the instance ID" );
+
+ SXMPMeta meta1;
+ DumpXMPObj ( log, meta1, "Empty XMP object" );
+ meta1.GetObjectName ( &tmpStr1 );
+ fprintf ( log, "\nEmpty object name = \"%s\"\n", tmpStr1.c_str() );
+ meta1.SetObjectName ( "New object name" );
+ DumpXMPObj ( log, meta1, "Set object name" );
+
+ SXMPMeta meta2 ( kRDFCoverage, strlen ( kRDFCoverage ) );
+ DumpXMPObj ( log, meta2, "Construct and parse from buffer" );
+ meta2.GetObjectName ( &tmpStr1 );
+ fprintf ( log, "\nRDFCoverage object name = \"%s\"\n", tmpStr1.c_str() );
+
+ meta2.SetProperty ( kXMP_NS_XMP_MM, "InstanceID", "meta2:Original" );
+ DumpXMPObj ( log, meta2, "Add instance ID" );
+
+ SXMPMeta meta4;
+ meta4 = meta2.Clone();
+ meta4.SetProperty ( kXMP_NS_XMP_MM, "InstanceID", "meta4:Clone" );
+ DumpXMPObj ( log, meta4, "Clone and add instance ID" );
+
+ #if 0
+
+ WriteMajorLabel ( log, "Test XMPMeta object options" );
+
+ fprintf ( log, "Initial object options 0x%X\n", meta2.GetObjectOptions() );
+ meta2.SetObjectOptions ( <TBD> );
+ fprintf ( log, "Final object options 0x%X\n", meta2.GetObjectOptions() );
+
+ #endif
+
+ }
+
+ // --------------------------------------------------------------------------------------------
+ // Static namespace functions
+ // --------------------------
+
+ WriteMajorLabel ( log, "Test static namespace functions" );
+ fprintf ( log, "\n" );
+
+ tmpStr1.erase();
+ ok = SXMPMeta::RegisterNamespace ( kNS2, "ns2", &tmpStr1 );
+ fprintf ( log, "RegisterNamespace ns2 : %s, %s\n", YesOrNo ( ok ), tmpStr1.c_str() );
+
+ tmpStr1.erase();
+ ok = SXMPMeta::RegisterNamespace ( kNS2, "nsx:", &tmpStr1 );
+ fprintf ( log, "RegisterNamespace nsx : %s, %s\n", YesOrNo ( ok ), tmpStr1.c_str() );
+
+ tmpStr1.erase();
+ ok = SXMPMeta::GetNamespacePrefix ( kNS1, &tmpStr1 );
+ fprintf ( log, "GetNamespacePrefix ns1 : %s, %s\n", FoundOrNot ( ok ), tmpStr1.c_str() );
+
+ tmpStr1.erase();
+ ok = SXMPMeta::GetNamespaceURI ( "ns1", &tmpStr1 );
+ fprintf ( log, "GetNamespaceURI ns1 : %s, %s\n", FoundOrNot ( ok ), tmpStr1.c_str() );
+
+ tmpStr1.erase();
+ ok = SXMPMeta::GetNamespacePrefix ( "bogus", &tmpStr1 );
+ fprintf ( log, "GetNamespacePrefix bogus : %s\n", FoundOrNot ( ok ) );
+
+ tmpStr1.erase();
+ ok = SXMPMeta::GetNamespaceURI ( "bogus", &tmpStr1 );
+ fprintf ( log, "GetNamespaceURI bogus : %s\n", FoundOrNot ( ok ) );
+
+ SXMPMeta::DumpNamespaces ( DumpToFile, log );
+
+ #if 0
+ SXMPMeta::DeleteNamespace ( kNS2 );
+ SXMPMeta::DumpNamespaces ( DumpToFile, log );
+ (void) SXMPMeta::RegisterNamespace ( kNS2, "ns2", 0 );
+ #endif
+
+ // --------------------------------------------------------------------------------------------
+ // Static alias functions
+ // ----------------------
+
+ WriteMajorLabel ( log, "Initial default aliases" );
+ fprintf ( log, "\n" );
+
+ SXMPMeta::DumpAliases ( DumpToFile, log );
+
+ WriteMajorLabel ( log, "Add ns2: to ns1: aliases" );
+ fprintf ( log, "\n" );
+
+ SXMPMeta::RegisterAlias ( kNS2, "SimpleAlias", kNS1, "SimpleActual" );
+
+ SXMPMeta::RegisterAlias ( kNS2, "BagAlias", kNS1, "BagActual" );
+ SXMPMeta::RegisterAlias ( kNS2, "ns2:SeqAlias", kNS1, "SeqActual" );
+ SXMPMeta::RegisterAlias ( kNS2, "AltAlias", kNS1, "AltActual" );
+ SXMPMeta::RegisterAlias ( kNS2, "AltTextAlias", kNS1, "AltTextActual" );
+
+ SXMPMeta::RegisterAlias ( kNS2, "BagItemAlias", kNS1, "BagActual", kXMP_PropValueIsArray );
+ SXMPMeta::RegisterAlias ( kNS2, "SeqItemAlias", kNS1, "ns1:SeqActual", kXMP_PropArrayIsOrdered );
+ SXMPMeta::RegisterAlias ( kNS2, "AltItemAlias", kNS1, "ns1:AltActual", kXMP_PropArrayIsAlternate );
+ SXMPMeta::RegisterAlias ( kNS2, "AltTextItemAlias", kNS1, "ns1:AltTextActual", kXMP_PropArrayIsAltText );
+
+ SXMPMeta::DumpAliases ( DumpToFile, log );
+
+ WriteMajorLabel ( log, "Resolve ns2: to ns1: aliases" );
+ fprintf ( log, "\n" );
+
+ tmpStr1.erase(); tmpStr2.erase();
+ ok = SXMPMeta::ResolveAlias ( kNS1, "SimpleActual", &tmpStr1, &tmpStr2, &options );
+ fprintf ( log, "ResolveAlias ns1:SimpleActual : %s\n", FoundOrNot ( ok ) );
+
+ fprintf ( log, "\n" );
+
+ tmpStr1.erase(); tmpStr2.erase();
+ ok = SXMPMeta::ResolveAlias ( kNS2, "SimpleAlias", &tmpStr1, &tmpStr2, &options );
+ fprintf ( log, "ResolveAlias ns2:SimpleAlias : %s, %s %s, 0x%X\n", FoundOrNot ( ok ), tmpStr1.c_str(), tmpStr2.c_str(), options );
+
+ fprintf ( log, "\n" );
+
+ tmpStr1.erase(); tmpStr2.erase();
+ ok = SXMPMeta::ResolveAlias ( kNS2, "ns2:BagAlias", &tmpStr1, &tmpStr2, &options );
+ fprintf ( log, "ResolveAlias ns2:BagAlias : %s, %s %s, 0x%X\n", FoundOrNot ( ok ), tmpStr1.c_str(), tmpStr2.c_str(), options );
+
+ tmpStr1.erase(); tmpStr2.erase();
+ ok = SXMPMeta::ResolveAlias ( kNS2, "SeqAlias", &tmpStr1, &tmpStr2, &options );
+ fprintf ( log, "ResolveAlias ns2:SeqAlias : %s, %s %s, 0x%X\n", FoundOrNot ( ok ), tmpStr1.c_str(), tmpStr2.c_str(), options );
+
+ tmpStr1.erase(); tmpStr2.erase();
+ ok = SXMPMeta::ResolveAlias ( kNS2, "AltAlias", &tmpStr1, &tmpStr2, &options );
+ fprintf ( log, "ResolveAlias ns2:AltAlias : %s, %s %s, 0x%X\n", FoundOrNot ( ok ), tmpStr1.c_str(), tmpStr2.c_str(), options );
+
+ tmpStr1.erase(); tmpStr2.erase();
+ ok = SXMPMeta::ResolveAlias ( kNS2, "AltTextAlias", &tmpStr1, &tmpStr2, &options );
+ fprintf ( log, "ResolveAlias ns2:AltTextAlias : %s, %s %s, 0x%X\n", FoundOrNot ( ok ), tmpStr1.c_str(), tmpStr2.c_str(), options );
+
+ fprintf ( log, "\n" );
+
+ tmpStr1.erase(); tmpStr2.erase();
+ ok = SXMPMeta::ResolveAlias ( kNS2, "BagItemAlias", &tmpStr1, &tmpStr2, &options );
+ fprintf ( log, "ResolveAlias ns2:BagItemAlias : %s, %s %s, 0x%X\n", FoundOrNot ( ok ), tmpStr1.c_str(), tmpStr2.c_str(), options );
+
+ tmpStr1.erase(); tmpStr2.erase();
+ ok = SXMPMeta::ResolveAlias ( kNS2, "SeqItemAlias", &tmpStr1, &tmpStr2, &options );
+ fprintf ( log, "ResolveAlias ns2:SeqItemAlias : %s, %s %s, 0x%X\n", FoundOrNot ( ok ), tmpStr1.c_str(), tmpStr2.c_str(), options );
+
+ tmpStr1.erase(); tmpStr2.erase();
+ ok = SXMPMeta::ResolveAlias ( kNS2, "AltItemAlias", &tmpStr1, &tmpStr2, &options );
+ fprintf ( log, "ResolveAlias ns2:AltItemAlias : %s, %s %s, 0x%X\n", FoundOrNot ( ok ), tmpStr1.c_str(), tmpStr2.c_str(), options );
+
+ tmpStr1.erase(); tmpStr2.erase();
+ ok = SXMPMeta::ResolveAlias ( kNS2, "AltTextItemAlias", &tmpStr1, &tmpStr2, &options );
+ fprintf ( log, "ResolveAlias ns2:AltTextItemAlias : %s, %s %s, 0x%X\n", FoundOrNot ( ok ), tmpStr1.c_str(), tmpStr2.c_str(), options );
+
+ {
+ SXMPMeta meta;
+
+ WriteMajorLabel ( log, "Test SetProperty through ns2: simple aliases" );
+
+ meta.SetProperty ( kNS2, "SimpleAlias", "Simple value" );
+ meta.SetProperty ( kNS2, "ns2:BagItemAlias", "BagItem value" );
+ meta.SetProperty ( kNS2, "SeqItemAlias", "SeqItem value" );
+ meta.SetProperty ( kNS2, "AltItemAlias", "AltItem value" );
+ meta.SetProperty ( kNS2, "AltTextItemAlias", "AltTextItem value" );
+
+ DumpXMPObj ( log, meta, "Check for aliases and bases" );
+
+ }
+
+ #if 0
+
+ WriteMajorLabel ( log, "Delete some ns2: to ns1: aliases" );
+ fprintf ( log, "\n" );
+
+ SXMPMeta::DeleteAlias ( kNS2, "ns2:SimpleAlias" );
+ SXMPMeta::DeleteAlias ( kNS2, "SeqAlias" );
+ SXMPMeta::DeleteAlias ( kNS2, "AltAlias" );
+ SXMPMeta::DeleteAlias ( kNS2, "SeqItemAlias" );
+ SXMPMeta::DeleteAlias ( kNS2, "AltItemAlias" );
+
+ SXMPMeta::DumpAliases ( DumpToFile, log );
+
+ #endif
+
+ WriteMajorLabel ( log, "Register standard EXIF aliases" );
+ fprintf ( log, "\n" );
+
+ SXMPMeta::RegisterStandardAliases ( kXMP_NS_EXIF );
+
+ SXMPMeta::DumpAliases ( DumpToFile, log );
+
+ // --------------------------------------------------------------------------------------------
+ // Basic set/get methods
+ // ---------------------
+
+ {
+ SXMPMeta meta;
+
+ WriteMajorLabel ( log, "Test SetProperty and related methods" );
+
+ tmpStr1 = "Prop value";
+ meta.SetProperty ( kNS1, "Prop", tmpStr1 );
+ meta.SetProperty ( kNS1, "ns1:XMLProp", "<PropValue/>" );
+ meta.SetProperty ( kNS1, "ns1:URIProp", "URI:value/", kXMP_PropValueIsURI );
+
+ tmpStr1 = "BagItem value";
+ meta.AppendArrayItem ( kNS1, "Bag", kXMP_PropValueIsArray, tmpStr1 );
+ meta.AppendArrayItem ( kNS1, "ns1:Seq", kXMP_PropArrayIsOrdered, "SeqItem value" );
+ meta.AppendArrayItem ( kNS1, "ns1:Alt", kXMP_PropArrayIsAlternate, "AltItem value" );
+
+ tmpStr1 = "Field1 value";
+ meta.SetStructField ( kNS1, "Struct", kNS2, "Field1", tmpStr1 );
+ meta.SetStructField ( kNS1, "ns1:Struct", kNS2, "Field2", "Field2 value" );
+ meta.SetStructField ( kNS1, "ns1:Struct", kNS2, "Field3", "Field3 value" );
+
+ tmpStr1 = "BagItem 3";
+ meta.SetArrayItem ( kNS1, "Bag", 1, tmpStr1 );
+ meta.SetArrayItem ( kNS1, "ns1:Bag", 1, "BagItem 1", kXMP_InsertBeforeItem );
+ meta.SetArrayItem ( kNS1, "ns1:Bag", 1, "BagItem 2", kXMP_InsertAfterItem );
+ meta.AppendArrayItem ( kNS1, "Bag", 0, "BagItem 4" );
+
+ DumpXMPObj ( log, meta, "A few basic Set... calls" );
+
+ tmpStr1.erase();
+ meta.SerializeToBuffer ( &tmpStr1, kXMP_OmitPacketWrapper );
+ fprintf ( log, "\n%s\n", tmpStr1.c_str() );
+
+ fprintf ( log, "CountArrayItems Bag = %d\n", meta.CountArrayItems ( kNS1, "Bag" ) );
+
+ meta.SetProperty ( kNS1, "QualProp1", "Prop value" );
+ meta.SetQualifier ( kNS1, "QualProp1", kNS2, "Qual1", "Qual1 value" );
+ // *** meta.SetProperty ( kNS1, "QualProp1/Qual2", "Qual2 value", kXMP_PropIsQualifier ); invalid
+ meta.SetProperty ( kNS1, "QualProp1/?ns2:Qual3", "Qual3 value" );
+ meta.SetProperty ( kNS1, "QualProp1/?xml:lang", "x-qual" );
+
+ meta.SetProperty ( kNS1, "QualProp2", "Prop value" );
+ meta.SetQualifier ( kNS1, "QualProp2", kXMP_NS_XML, "lang", "en-us" );
+ // *** meta.SetProperty ( kNS1, "QualProp2/xml:lang", "x-field", kXMP_PropIsQualifier ); invalid
+ meta.SetProperty ( kNS1, "QualProp2/@xml:lang", "x-attr" );
+
+ meta.SetProperty ( kNS1, "QualProp3", "Prop value" );
+ meta.SetQualifier ( kNS1, "ns1:QualProp3", kXMP_NS_XML, "xml:lang", "en-us" );
+ meta.SetQualifier ( kNS1, "ns1:QualProp3", kNS2, "ns2:Qual", "Qual value" );
+
+ meta.SetProperty ( kNS1, "QualProp4", "Prop value" );
+ tmpStr1 = "Qual value";
+ meta.SetQualifier ( kNS1, "QualProp4", kNS2, "Qual", tmpStr1 );
+ meta.SetQualifier ( kNS1, "QualProp4", kXMP_NS_XML, "lang", "en-us" );
+
+ DumpXMPObj ( log, meta, "Add some qualifiers" );
+
+ tmpStr1.erase();
+ meta.SerializeToBuffer ( &tmpStr1, kXMP_OmitPacketWrapper );
+ fprintf ( log, "\n%s\n", tmpStr1.c_str() );
+
+ meta.SetProperty ( kNS1, "QualProp1", "new value" );
+ meta.SetProperty ( kNS1, "QualProp2", "new value" );
+ meta.SetProperty ( kNS1, "QualProp3", "new value" );
+ meta.SetProperty ( kNS1, "QualProp4", "new value" );
+ DumpXMPObj ( log, meta, "Change values and keep qualifiers" );
+
+ // ----------------------------------------------------------------------------------------
+
+ WriteMajorLabel ( log, "Test GetProperty and related methods" );
+
+ meta.DeleteProperty ( kNS1, "QualProp1" ); // ! Start with fresh qualifiers.
+ meta.DeleteProperty ( kNS1, "ns1:QualProp2" );
+ meta.DeleteProperty ( kNS1, "ns1:QualProp3" );
+ meta.DeleteProperty ( kNS1, "QualProp4" );
+
+ meta.SetProperty ( kNS1, "QualProp1", "Prop value" );
+ meta.SetQualifier ( kNS1, "QualProp1", kNS2, "Qual1", "Qual1 value" );
+
+ meta.SetProperty ( kNS1, "QualProp2", "Prop value" );
+ meta.SetQualifier ( kNS1, "QualProp2", kXMP_NS_XML, "lang", "en-us" );
+
+ meta.SetProperty ( kNS1, "QualProp3", "Prop value" );
+ meta.SetQualifier ( kNS1, "QualProp3", kXMP_NS_XML, "lang", "en-us" );
+ meta.SetQualifier ( kNS1, "QualProp3", kNS2, "Qual", "Qual value" );
+
+ meta.SetProperty ( kNS1, "QualProp4", "Prop value" );
+ meta.SetQualifier ( kNS1, "QualProp4", kNS2, "Qual", "Qual value" );
+ meta.SetQualifier ( kNS1, "QualProp4", kXMP_NS_XML, "lang", "en-us" );
+
+ DumpXMPObj ( log, meta, "XMP object" );
+ fprintf ( log, "\n" );
+
+ tmpStr1.erase();
+ ok = meta.GetProperty ( kNS1, "Prop", &tmpStr1, &options );
+ fprintf ( log, "GetProperty ns1:Prop : %s, \"%s\", 0x%X\n", FoundOrNot ( ok ), tmpStr1.c_str(), options );
+
+ try {
+ tmpStr1.erase();
+ ok = meta.GetProperty ( 0, "ns1:Prop", &tmpStr1, &options );
+ fprintf ( log, "#ERROR: No exception for GetProperty with no schema URI : %s, \"%s\", 0x%X\n", FoundOrNot ( ok ), tmpStr1.c_str(), options );
+ } catch ( XMP_Error & excep ) {
+ fprintf ( log, "GetProperty with no schema URI - threw XMP_Error #%d : %s\n", excep.GetID(), excep.GetErrMsg() );
+ } catch ( ... ) {
+ fprintf ( log, "GetProperty with no schema URI - threw unknown exception\n" );
+ }
+
+ tmpStr1.erase();
+ ok = meta.GetProperty ( kNS1, "ns1:XMLProp", &tmpStr1, &options );
+ fprintf ( log, "GetProperty ns1:XMLProp : %s, \"%s\", 0x%X\n", FoundOrNot ( ok ), tmpStr1.c_str(), options );
+
+ tmpStr1.erase();
+ ok = meta.GetProperty ( kNS1, "ns1:URIProp", &tmpStr1, &options );
+ fprintf ( log, "GetProperty ns1:URIProp : %s, \"%s\", 0x%X\n", FoundOrNot ( ok ), tmpStr1.c_str(), options );
+
+ fprintf ( log, "\n" );
+
+ tmpStr1.erase();
+ ok = meta.GetArrayItem ( kNS1, "Bag", 2, &tmpStr1, &options );
+ fprintf ( log, "GetArrayItem ns1:Bag[2] : %s, \"%s\", 0x%X\n", FoundOrNot ( ok ), tmpStr1.c_str(), options );
+
+ try {
+ tmpStr1.erase();
+ ok = meta.GetArrayItem ( 0, "ns1:Bag", 1, &tmpStr1, &options );
+ fprintf ( log, "#ERROR: No exception for GetArrayItem with no schema URI : %s, \"%s\", 0x%X\n", FoundOrNot ( ok ), tmpStr1.c_str(), options );
+ } catch ( XMP_Error & excep ) {
+ fprintf ( log, "GetArrayItem with no schema URI - threw XMP_Error #%d : %s\n", excep.GetID(), excep.GetErrMsg() );
+ } catch ( ... ) {
+ fprintf ( log, "GetArrayItem with no schema URI - threw unknown exception\n" );
+ }
+
+ tmpStr1.erase();
+ ok = meta.GetArrayItem ( kNS1, "ns1:Seq", 1, &tmpStr1, &options );
+ fprintf ( log, "GetArrayItem ns1:Seq[1] : %s, \"%s\", 0x%X\n", FoundOrNot ( ok ), tmpStr1.c_str(), options );
+
+ tmpStr1.erase();
+ ok = meta.GetArrayItem ( kNS1, "ns1:Alt", kXMP_ArrayLastItem, &tmpStr1, &options );
+ fprintf ( log, "GetArrayItem ns1:Alt[1] : %s, \"%s\", 0x%X\n", FoundOrNot ( ok ), tmpStr1.c_str(), options );
+
+ fprintf ( log, "\n" );
+
+ tmpStr1.erase();
+ ok = meta.GetStructField ( kNS1, "Struct", kNS2, "Field1", &tmpStr1, &options );
+ fprintf ( log, "GetStructField ns1:Struct/ns2:Field1 : %s, \"%s\", 0x%X\n", FoundOrNot ( ok ), tmpStr1.c_str(), options );
+
+ tmpStr1.erase();
+ ok = meta.GetStructField ( kNS1, "ns1:Struct", kNS2, "ns2:Field2", &tmpStr1, &options );
+ fprintf ( log, "GetStructField ns1:Struct/ns2:Field2 : %s, \"%s\", 0x%X\n", FoundOrNot ( ok ), tmpStr1.c_str(), options );
+
+ tmpStr1.erase();
+ ok = meta.GetStructField ( kNS1, "ns1:Struct", kNS2, "ns2:Field3", &tmpStr1, &options );
+ fprintf ( log, "GetStructField ns1:Struct/ns2:Field3 : %s, \"%s\", 0x%X\n", FoundOrNot ( ok ), tmpStr1.c_str(), options );
+
+ tmpStr1.erase();
+ ok = meta.GetQualifier ( kNS1, "QualProp1", kNS2, "Qual1", &tmpStr1, &options );
+ fprintf ( log, "GetQualifier ns1:QualProp1/?ns2:Qual1 : %s, \"%s\", 0x%X\n", FoundOrNot ( ok ), tmpStr1.c_str(), options );
+
+ try {
+ tmpStr1.erase();
+ ok = meta.GetQualifier ( 0, "ns1:QualProp1", kNS2, "Qual1", &tmpStr1, &options );
+ fprintf ( log, "#ERROR: No exception for GetQualifier with no schema URI : %s, \"%s\", 0x%X\n", FoundOrNot ( ok ), tmpStr1.c_str(), options );
+ } catch ( XMP_Error & excep ) {
+ fprintf ( log, "GetQualifier with no schema URI - threw XMP_Error #%d : %s\n", excep.GetID(), excep.GetErrMsg() );
+ } catch ( ... ) {
+ fprintf ( log, "GetQualifier with no schema URI - threw unknown exception\n" );
+ }
+
+ tmpStr1.erase();
+ ok = meta.GetQualifier ( kNS1, "ns1:QualProp3", kXMP_NS_XML, "xml:lang", &tmpStr1, &options );
+ fprintf ( log, "GetQualifier ns1:QualProp3 : %s, \"%s\", 0x%X\n", FoundOrNot ( ok ), tmpStr1.c_str(), options );
+
+ tmpStr1.erase();
+ ok = meta.GetQualifier ( kNS1, "ns1:QualProp3", kNS2, "ns2:Qual", &tmpStr1, &options );
+ fprintf ( log, "GetQualifier ns1:QualProp3/?ns2:Qual : %s, \"%s\", 0x%X\n", FoundOrNot ( ok ), tmpStr1.c_str(), options );
+
+ fprintf ( log, "\n" );
+
+ tmpStr1 = "junk";
+ ok = meta.GetProperty ( kNS1, "Bag", &tmpStr1, &options );
+ fprintf ( log, "GetProperty ns1:Bag : %s, \"%s\", 0x%X\n", FoundOrNot ( ok ), tmpStr1.c_str(), options );
+
+ tmpStr1 = "junk";
+ ok = meta.GetProperty ( kNS1, "Seq", &tmpStr1, &options );
+ fprintf ( log, "GetProperty ns1:Seq : %s, \"%s\", 0x%X\n", FoundOrNot ( ok ), tmpStr1.c_str(), options );
+
+ tmpStr1 = "junk";
+ ok = meta.GetProperty ( kNS1, "Alt", &tmpStr1, &options );
+ fprintf ( log, "GetProperty ns1:Alt : %s, \"%s\", 0x%X\n", FoundOrNot ( ok ), tmpStr1.c_str(), options );
+
+ tmpStr1 = "junk";
+ ok = meta.GetProperty ( kNS1, "Struct", &tmpStr1, &options );
+ fprintf ( log, "GetProperty ns1:Struct : %s, \"%s\", 0x%X\n", FoundOrNot ( ok ), tmpStr1.c_str(), options );
+
+ fprintf ( log, "\n" );
+
+ try {
+ tmpStr1 = "junk";
+ ok = meta.GetProperty ( "ns:bogus/", "Bogus", &tmpStr1, &options );
+ fprintf ( log, "#ERROR: No exception for GetProperty with bogus schema URI: %s, \"%s\", 0x%X\n", FoundOrNot ( ok ), tmpStr1.c_str(), options );
+ } catch ( XMP_Error & excep ) {
+ fprintf ( log, "GetProperty with bogus schema URI - threw XMP_Error #%d : %s\n", excep.GetID(), excep.GetErrMsg() );
+ } catch ( ... ) {
+ fprintf ( log, "GetProperty with bogus schema URI - threw unknown exception\n" );
+ }
+
+ tmpStr1 = "junk";
+ ok = meta.GetProperty ( kNS1, "Bogus", &tmpStr1, &options );
+ fprintf ( log, "GetProperty ns1:Bogus : %s\n", FoundOrNot ( ok ) );
+
+ tmpStr1 = "junk";
+ ok = meta.GetArrayItem ( kNS1, "Bag", 99, &tmpStr1, &options );
+ fprintf ( log, "GetArrayItem ns1:Bag[99] : %s\n", FoundOrNot ( ok ) );
+
+ tmpStr1 = "junk";
+ ok = meta.GetStructField ( kNS1, "Struct", kNS2, "Bogus", &tmpStr1, &options );
+ fprintf ( log, "GetStructField ns1:Struct/ns2:Bogus : %s\n", FoundOrNot ( ok ) );
+
+ tmpStr1 = "junk";
+ ok = meta.GetQualifier ( kNS1, "Prop", kNS2, "Bogus", &tmpStr1, &options );
+ fprintf ( log, "GetQualifier ns1:Prop/?ns2:Bogus : %s\n", FoundOrNot ( ok ) );
+
+ // ----------------------------------------------------------------------------------------
+
+ WriteMajorLabel ( log, "Test DoesPropertyExist, DeleteProperty, and related methods" );
+
+ DumpXMPObj ( log, meta, "XMP object" );
+ fprintf ( log, "\n" );
+
+ ok = meta.DoesPropertyExist ( kNS1, "Prop" );
+ fprintf ( log, "DoesPropertyExist ns1:Prop : %s\n", YesOrNo ( ok ) );
+
+ try {
+ ok = meta.DoesPropertyExist ( 0, "ns1:Bag" );
+ fprintf ( log, "#ERROR: No exception for DoesPropertyExist with no schema URI: %s\n", YesOrNo ( ok ) );
+ } catch ( XMP_Error & excep ) {
+ fprintf ( log, "DoesPropertyExist with no schema URI - threw XMP_Error #%d : %s\n", excep.GetID(), excep.GetErrMsg() );
+ } catch ( ... ) {
+ fprintf ( log, "DoesPropertyExist with no schema URI - threw unknown exception\n" );
+ }
+
+ ok = meta.DoesPropertyExist ( kNS1, "ns1:Struct" );
+ fprintf ( log, "DoesPropertyExist ns1:Struct : %s\n", YesOrNo ( ok ) );
+
+ fprintf ( log, "\n" );
+
+ ok = meta.DoesArrayItemExist ( kNS1, "Bag", 2 );
+ fprintf ( log, "DoesArrayItemExist ns1:Bag[2] : %s\n", YesOrNo ( ok ) );
+
+ ok = meta.DoesArrayItemExist ( kNS1, "ns1:Seq", kXMP_ArrayLastItem );
+ fprintf ( log, "DoesArrayItemExist ns1:Seq[last] : %s\n", YesOrNo ( ok ) );
+
+ ok = meta.DoesStructFieldExist ( kNS1, "Struct", kNS2, "Field1" );
+ fprintf ( log, "DoesStructFieldExist ns1:Struct/ns2:Field1 : %s\n", YesOrNo ( ok ) );
+
+ ok = meta.DoesQualifierExist ( kNS1, "QualProp1", kNS2, "Qual1" );
+ fprintf ( log, "DoesQualifierExist ns1:QualProp1/?ns2:Qual1 : %s\n", YesOrNo ( ok ) );
+
+ ok = meta.DoesQualifierExist ( kNS1, "QualProp2", kXMP_NS_XML, "lang" );
+ fprintf ( log, "DoesQualifierExist ns1:QualProp2/?xml:lang : %s\n", YesOrNo ( ok ) );
+
+ fprintf ( log, "\n" );
+
+ try {
+ ok = meta.DoesPropertyExist ( "ns:bogus/", "Bogus" );
+ fprintf ( log, "#ERROR: No exception for DoesPropertyExist with bogus schema URI: %s\n", YesOrNo ( ok ) );
+ } catch ( XMP_Error & excep ) {
+ fprintf ( log, "DoesPropertyExist with bogus schema URI - threw XMP_Error #%d : %s\n", excep.GetID(), excep.GetErrMsg() );
+ } catch ( ... ) {
+ fprintf ( log, "DoesPropertyExist with bogus schema URI - threw unknown exception\n" );
+ }
+
+ ok = meta.DoesPropertyExist ( kNS1, "Bogus" );
+ fprintf ( log, "DoesPropertyExist ns1:Bogus : %s\n", YesOrNo ( ok ) );
+
+ ok = meta.DoesArrayItemExist ( kNS1, "Bag", 99 );
+ fprintf ( log, "DoesArrayItemExist ns1:Bag[99] : %s\n", YesOrNo ( ok ) );
+
+ try {
+ ok = meta.DoesArrayItemExist ( 0, "ns1:Bag", kXMP_ArrayLastItem );
+ fprintf ( log, "#ERROR: No exception for DoesArrayItemExist with no schema URI: %s\n", YesOrNo ( ok ) );
+ } catch ( XMP_Error & excep ) {
+ fprintf ( log, "DoesArrayItemExist with no schema URI - threw XMP_Error #%d : %s\n", excep.GetID(), excep.GetErrMsg() );
+ } catch ( ... ) {
+ fprintf ( log, "DoesArrayItemExist with no schema URI - threw unknown exception\n" );
+ }
+
+ ok = meta.DoesStructFieldExist ( kNS1, "Struct", kNS2, "Bogus" );
+ fprintf ( log, "DoesStructFieldExist ns1:Struct/ns2:Bogus : %s\n", YesOrNo ( ok ) );
+
+ ok = meta.DoesQualifierExist ( kNS1, "Prop", kNS2, "Bogus" );
+ fprintf ( log, "DoesQualifierExist ns1:Prop/?ns2:Bogus : %s\n", YesOrNo ( ok ) );
+
+ meta.DeleteProperty ( kNS1, "Prop" );
+ meta.DeleteArrayItem ( kNS1, "Bag", 2 );
+ meta.DeleteStructField ( kNS1, "Struct", kNS2, "Field1" );
+
+ DumpXMPObj ( log, meta, "Delete Prop, Bag[2], and Struct1/Field1" );
+
+ meta.DeleteQualifier ( kNS1, "QualProp1", kNS2, "Qual1" );
+ meta.DeleteQualifier ( kNS1, "QualProp2", kXMP_NS_XML, "lang" );
+ meta.DeleteQualifier ( kNS1, "QualProp3", kNS2, "Qual" );
+ meta.DeleteQualifier ( kNS1, "QualProp4", kXMP_NS_XML, "lang" );
+
+ DumpXMPObj ( log, meta, "Delete QualProp1/?ns2:Qual1, QualProp2/?xml:lang, QualProp3:/ns2:Qual, and QualProp4/?xml:lang" );
+
+ meta.DeleteProperty ( kNS1, "Bag" );
+ meta.DeleteProperty ( kNS1, "Struct" );
+
+ DumpXMPObj ( log, meta, "Delete all of Bag and Struct" );
+
+ }
+
+ // --------------------------------------------------------------------------------------------
+ // Localized text set/get methods
+ // ------------------------------
+
+ {
+ SXMPMeta meta;
+
+ WriteMajorLabel ( log, "Test SetLocalizedText and GetLocalizedText" );
+
+ tmpStr1 = "default value";
+ meta.SetLocalizedText ( kNS1, "AltText", "", "x-default", tmpStr1 );
+ DumpXMPObj ( log, meta, "Set x-default value" );
+
+ meta.SetLocalizedText ( kNS1, "AltText", "en", "en-us", "en-us value" );
+ DumpXMPObj ( log, meta, "Set en/en-us value" );
+
+ meta.SetLocalizedText ( kNS1, "AltText", "en", "en-uk", "en-uk value" );
+ DumpXMPObj ( log, meta, "Set en/en-uk value" );
+
+ fprintf ( log, "\n" );
+
+ tmpStr1.erase(); tmpStr2.erase();
+ ok = meta.GetLocalizedText ( kNS1, "AltText", "en", "en-ca", &tmpStr1, &tmpStr2, &options );
+ fprintf ( log, "GetLocalizedText en/en-ca : %s, \'%s\' \"%s\", 0x%X\n", FoundOrNot ( ok ), tmpStr1.c_str(), tmpStr2.c_str(), options );
+
+ tmpStr1 = "junk";
+ ok = meta.GetProperty ( kNS1, "AltText", &tmpStr1, &options );
+ fprintf ( log, "GetProperty ns1:AltText : %s, \"%s\", 0x%X\n", FoundOrNot ( ok ), tmpStr1.c_str(), options );
+
+ }
+
+ // --------------------------------------------------------------------------------------------
+ // Binary value set/get methods
+ // ----------------------------
+
+ {
+ SXMPMeta meta ( kDateTimeRDF, strlen(kDateTimeRDF) );
+ XMP_DateTime dateValue = { 2000, 1, 2, 3, 4, 5, 0, 0, 0, 0 };
+ bool boolValue;
+ long intValue;
+ double floatValue;
+ char dateName [8];
+
+ WriteMajorLabel ( log, "Test SetProperty... and GetProperty... methods (set/get with binary values)" );
+
+ meta.SetProperty_Bool ( kNS1, "Bool0", false );
+ meta.SetProperty_Bool ( kNS1, "Bool1", true );
+ meta.SetProperty_Int ( kNS1, "Int", 42 );
+ meta.SetProperty_Float ( kNS1, "Float", 4.2 );
+
+ meta.SetProperty_Date ( kNS1, "Date10", dateValue );
+ dateValue.tzSign = 1; dateValue.tzHour = 6; dateValue.tzMinute = 7;
+ meta.SetProperty_Date ( kNS1, "Date11", dateValue );
+ dateValue.tzSign = -1;
+ meta.SetProperty_Date ( kNS1, "Date12", dateValue );
+ dateValue.nanoSecond = 9;
+ meta.SetProperty_Date ( kNS1, "Date13", dateValue );
+
+ DumpXMPObj ( log, meta, "A few basic binary Set... calls" );
+
+ fprintf ( log, "\n" );
+
+ ok = meta.GetProperty_Bool ( kNS1, "Bool0", &boolValue, &options );
+ fprintf ( log, "GetProperty_Bool Bool0 : %s, %d, 0x%X\n", FoundOrNot ( ok ), boolValue, options );
+
+ ok = meta.GetProperty_Bool ( kNS1, "Bool1", &boolValue, &options );
+ fprintf ( log, "GetProperty_Bool Bool1 : %s, %d, 0x%X\n", FoundOrNot ( ok ), boolValue, options );
+
+ ok = meta.GetProperty_Int ( kNS1, "Int", &intValue, &options );
+ fprintf ( log, "GetProperty_Int : %s, %d, 0x%X\n", FoundOrNot ( ok ), intValue, options );
+
+ ok = meta.GetProperty_Float ( kNS1, "Float", &floatValue, &options );
+ fprintf ( log, "GetProperty_Float : %s, %f, 0x%X\n", FoundOrNot ( ok ), floatValue, options );
+
+ fprintf ( log, "\n" );
+
+ for ( i = 1; i < 14; ++i ) {
+ sprintf ( dateName, "Date%d", i );
+ ok = meta.GetProperty_Date ( kNS1, dateName, &dateValue, &options );
+ fprintf ( log, "GetProperty_Date (%s) : %s, %d-%02d-%02d %02d:%02d:%02d %d*%02d:%02d %d, 0x%X\n", dateName, FoundOrNot ( ok ),
+ dateValue.year, dateValue.month, dateValue.day, dateValue.hour, dateValue.minute, dateValue.second,
+ dateValue.tzSign, dateValue.tzHour, dateValue.tzMinute, dateValue.nanoSecond, options );
+ meta.SetProperty_Date ( kNS2, dateName, dateValue );
+ }
+
+ DumpXMPObj ( log, meta, "Get and re-set the dates" );
+
+ }
+
+ // --------------------------------------------------------------------------------------------
+ // Parse and serialize methods
+ // ---------------------------
+
+ WriteMajorLabel ( log, "Test parsing with multiple buffers and various options" );
+
+ {
+ SXMPMeta meta;
+ for ( i = 0; i < (long)strlen(kSimpleRDF) - 10; i += 10 ) {
+ meta.ParseFromBuffer ( &kSimpleRDF[i], 10, kXMP_ParseMoreBuffers );
+ }
+ meta.ParseFromBuffer ( &kSimpleRDF[i], strlen(kSimpleRDF) - i );
+ DumpXMPObj ( log, meta, "Multiple buffer parse" );
+ }
+
+ {
+ SXMPMeta meta;
+ for ( i = 0; i < (long)strlen(kSimpleRDF) - 10; i += 10 ) {
+ meta.ParseFromBuffer ( &kSimpleRDF[i], 10, kXMP_ParseMoreBuffers );
+ }
+ meta.ParseFromBuffer ( &kSimpleRDF[i], (strlen(kSimpleRDF) - i), kXMP_ParseMoreBuffers );
+ meta.ParseFromBuffer ( kSimpleRDF, 0 );
+ DumpXMPObj ( log, meta, "Multiple buffer parse, empty last buffer" );
+ }
+
+ {
+ SXMPMeta meta;
+ for ( i = 0; i < (long)strlen(kSimpleRDF) - 10; i += 10 ) {
+ meta.ParseFromBuffer ( &kSimpleRDF[i], 10, kXMP_ParseMoreBuffers );
+ }
+ meta.ParseFromBuffer ( &kSimpleRDF[i], (strlen(kSimpleRDF) - i), kXMP_ParseMoreBuffers );
+ meta.ParseFromBuffer ( 0, 0 );
+ DumpXMPObj ( log, meta, "Multiple buffer parse, null last buffer" );
+ }
+
+ {
+ SXMPMeta meta;
+ meta.ParseFromBuffer ( kSimpleRDF, strlen(kSimpleRDF), kXMP_RequireXMPMeta );
+ DumpXMPObj ( log, meta, "Parse and require xmpmeta element, which is missing" );
+ }
+
+ {
+ SXMPMeta meta;
+ meta.ParseFromBuffer ( kNamespaceRDF, strlen(kNamespaceRDF) );
+ DumpXMPObj ( log, meta, "Parse RDF with multiple nested namespaces" );
+ }
+
+ {
+ SXMPMeta meta;
+ meta.ParseFromBuffer ( kXMPMetaRDF, strlen(kXMPMetaRDF), kXMP_RequireXMPMeta );
+ DumpXMPObj ( log, meta, "Parse and require xmpmeta element, which is present" );
+ }
+
+ {
+ SXMPMeta meta;
+ meta.ParseFromBuffer ( kInconsistentRDF, strlen(kInconsistentRDF) );
+ DumpXMPObj ( log, meta, "Parse and reconcile inconsistent aliases" );
+ }
+
+ try {
+ SXMPMeta meta;
+ meta.ParseFromBuffer ( kInconsistentRDF, strlen(kInconsistentRDF), kXMP_StrictAliasing );
+ DumpXMPObj ( log, meta, "ERROR: Parse and do not reconcile inconsistent aliases - should have thrown an exception" );
+ } catch ( XMP_Error & excep ) {
+ fprintf ( log, "\nParse and do not reconcile inconsistent aliases - threw XMP_Error #%d : %s\n", excep.GetID(), excep.GetErrMsg() );
+ } catch ( ... ) {
+ fprintf ( log, "\nParse and do not reconcile inconsistent aliases - threw unknown exception\n" );
+ }
+
+ {
+ WriteMajorLabel ( log, "Test CR and LF in values" );
+
+ const char * kValueWithCR = "ASCII \x0D CR";
+ const char * kValueWithLF = "ASCII \x0A LF";
+ const char * kValueWithCRLF = "ASCII \x0D\x0A CRLF";
+
+ SXMPMeta meta ( kNewlineRDF, kXMP_UseNullTermination );
+
+ meta.SetProperty ( kNS2, "HasCR", kValueWithCR );
+ meta.SetProperty ( kNS2, "HasLF", kValueWithLF );
+ meta.SetProperty ( kNS2, "HasCRLF", kValueWithCRLF );
+
+ tmpStr1.erase();
+ meta.SerializeToBuffer ( &tmpStr1, kXMP_OmitPacketWrapper );
+ fprintf ( log, "\n%s\n", tmpStr1.c_str() );
+
+ tmpStr1.erase(); tmpStr2.erase();
+ ok = meta.GetProperty ( kNS1, "HasCR", &tmpStr1, 0 );
+ ok = meta.GetProperty ( kNS2, "HasCR", &tmpStr2, 0 );
+ if ( (tmpStr1 != kValueWithCR) || (tmpStr2 != kValueWithCR) ) fprintf ( log, "\n ## HasCR values are bad\n" );
+
+ tmpStr1.erase(); tmpStr2.erase();
+ ok = meta.GetProperty ( kNS1, "HasLF", &tmpStr1, 0 );
+ ok = meta.GetProperty ( kNS2, "HasLF", &tmpStr2, 0 );
+ if ( (tmpStr1 != kValueWithLF) || (tmpStr2 != kValueWithLF) ) fprintf ( log, "\n ## HasLF values are bad\n" );
+
+ tmpStr1.erase(); tmpStr2.erase();
+ ok = meta.GetProperty ( kNS1, "HasCRLF", &tmpStr1, 0 );
+ ok = meta.GetProperty ( kNS2, "HasCRLF", &tmpStr2, 0 );
+ if ( (tmpStr1 != kValueWithCRLF) || (tmpStr2 != kValueWithCRLF) ) fprintf ( log, "\n ## HasCRLF values are bad\n" );
+ }
+
+ {
+ WriteMajorLabel ( log, "Test serialization with various options" );
+
+ SXMPMeta meta ( kSimpleRDF, strlen(kSimpleRDF) );
+ meta.SetProperty ( kNS2, "Another", "Something in another schema" );
+ meta.SetProperty ( kNS2, "Yet/pdf:More", "Yet more in another schema" );
+
+ DumpXMPObj ( log, meta, "Parse simple RDF, serialize with various options" );
+
+ tmpStr1.erase();
+ meta.SerializeToBuffer ( &tmpStr1 );
+ WriteMinorLabel ( log, "Default serialize" );
+ fprintf ( log, "%s\n", tmpStr1.c_str() ); fflush ( log );
+ VerifyNewlines ( log, tmpStr1, "\x0A" );
+
+ SXMPMeta meta2 ( tmpStr1.c_str(), tmpStr1.size() );
+ DumpXMPObj ( log, meta2, "Reparse default serialization" );
+
+ tmpStr1.erase();
+ meta.SerializeToBuffer ( &tmpStr1, kXMP_OmitPacketWrapper | kXMP_UseCompactFormat );
+ WriteMinorLabel ( log, "Compact RDF, no packet serialize" );
+ fprintf ( log, "%s\n", tmpStr1.c_str() );
+
+ SXMPMeta meta3 ( tmpStr1.c_str(), tmpStr1.size() );
+ DumpXMPObj ( log, meta3, "Reparse compact serialization" );
+
+ {
+ SXMPMeta meta2;
+
+ meta2.SetProperty ( kXMP_NS_PDF, "Author", "PDF Author" );
+
+ tmpStr1.erase();
+ meta2.SerializeToBuffer ( &tmpStr1, kXMP_ReadOnlyPacket | kXMP_WriteAliasComments );
+ WriteMinorLabel ( log, "Read-only serialize with alias comments" );
+ fprintf ( log, "%s\n", tmpStr1.c_str() );
+
+ meta2.SetProperty ( kXMP_NS_PDF, "Actual", "PDF Actual" );
+ meta2.SetProperty ( kXMP_NS_XMP, "Actual", "XMP Actual" );
+
+ tmpStr1.erase();
+ meta2.SerializeToBuffer ( &tmpStr1, kXMP_ReadOnlyPacket | kXMP_WriteAliasComments );
+ WriteMinorLabel ( log, "Read-only serialize with alias comments (more actuals)" );
+ fprintf ( log, "%s\n", tmpStr1.c_str() );
+ }
+
+ tmpStr1.erase();
+ meta.SerializeToBuffer ( &tmpStr1, kXMP_OmitPacketWrapper, 0, "\x0D" );
+ WriteMinorLabel ( log, "CR newline serialize" );
+ fprintf ( log, "%s\n", tmpStr1.c_str() );
+ VerifyNewlines ( log, tmpStr1, "\x0D" );
+
+ tmpStr1.erase();
+ meta.SerializeToBuffer ( &tmpStr1, kXMP_OmitPacketWrapper, 0, "\x0D\x0A" );
+ WriteMinorLabel ( log, "CRLF newline serialize" );
+ fprintf ( log, "%s\n", tmpStr1.c_str() );
+ VerifyNewlines ( log, tmpStr1, "\x0D\x0A" );
+
+ tmpStr1.erase();
+ meta.SerializeToBuffer ( &tmpStr1, kXMP_OmitPacketWrapper, 0, "<->" );
+ WriteMinorLabel ( log, "Alternate newline serialize" );
+ fprintf ( log, "%s\n", tmpStr1.c_str() );
+
+ tmpStr1.erase();
+ meta.SerializeToBuffer ( &tmpStr1, kXMP_OmitPacketWrapper, 0, "", "#", 3 );
+ WriteMinorLabel ( log, "Alternate indent serialize" );
+ fprintf ( log, "%s\n", tmpStr1.c_str() );
+
+ tmpStr1.erase();
+ meta.SerializeToBuffer ( &tmpStr1, 0, 10 );
+ WriteMinorLabel ( log, "Small padding serialize" );
+ fprintf ( log, "%s\n", tmpStr1.c_str() );
+
+ tmpStr1.erase();
+ tmpStr2.erase();
+ meta.SerializeToBuffer ( &tmpStr1 );
+ meta.SerializeToBuffer ( &tmpStr2, kXMP_IncludeThumbnailPad );
+ fprintf ( log, "Thumbnailpad adds %d bytes\n", tmpStr2.size()-tmpStr1.size() );
+
+ tmpStr1.erase();
+ meta.SerializeToBuffer ( &tmpStr1, kXMP_ReadOnlyPacket );
+ size_t minSize = tmpStr1.size();
+ fprintf ( log, "Minimum packet size is %d bytes\n", minSize );
+
+ tmpStr1.erase();
+ meta.SerializeToBuffer ( &tmpStr1, kXMP_ExactPacketLength, minSize+1234 );
+ fprintf ( log, "Minimum+1234 packet size is %d bytes\n", tmpStr1.size() );
+ if ( tmpStr1.size() != (minSize + 1234) ) fprintf ( log, "** Bad packet length **\n" );
+
+ tmpStr1.erase();
+ meta.SerializeToBuffer ( &tmpStr1, kXMP_ExactPacketLength, minSize );
+ fprintf ( log, "Minimum+0 packet size is %d bytes\n", tmpStr1.size() );
+ if ( tmpStr1.size() != minSize ) fprintf ( log, "** Bad packet length **\n" );
+
+ try {
+ tmpStr1.erase();
+ meta.SerializeToBuffer ( &tmpStr1, kXMP_ExactPacketLength, minSize-1 );
+ fprintf ( log, "#ERROR: No exception for minimum-1, size is %d bytes **\n", tmpStr1.size() );
+ } catch ( XMP_Error & excep ) {
+ fprintf ( log, "Serialize in minimum-1 - threw XMP_Error #%d : %s\n", excep.GetID(), excep.GetErrMsg() );
+ } catch ( ... ) {
+ fprintf ( log, "Serialize in minimum-1 - threw unknown exception\n" );
+ }
+
+ // *** UTF-16 and UTF-32 encodings
+
+ }
+
+ // --------------------------------------------------------------------------------------------
+ // Iteration methods
+ // -----------------
+
+ {
+ WriteMajorLabel ( log, "Test iteration methods" );
+
+ SXMPMeta meta ( kRDFCoverage, strlen ( kRDFCoverage ) );
+ XMP_OptionBits opt2;
+
+ meta.SetProperty ( kNS2, "Prop", "Prop value" );
+
+ meta.SetProperty ( kNS2, "Bag", 0, kXMP_PropValueIsArray );
+ meta.SetArrayItem ( kNS2, "Bag", 1, "BagItem 2" );
+ meta.SetArrayItem ( kNS2, "Bag", 1, "BagItem 1", kXMP_InsertBeforeItem );
+ meta.SetArrayItem ( kNS2, "Bag", 2, "BagItem 3", kXMP_InsertAfterItem );
+
+ DumpXMPObj ( log, meta, "Parse \"coverage\" RDF, add Bag items out of order" );
+
+ {
+ SXMPIterator iter ( meta );
+ WriteMinorLabel ( log, "Default iteration" );
+ while ( true ) {
+ tmpStr1.erase(); tmpStr2.erase(); tmpStr3.erase();
+ if ( ! iter.Next ( &tmpStr1, &tmpStr2, &tmpStr3, &options ) ) break;
+ fprintf ( log, " %s %s = \"%s\", 0x%X\n", tmpStr1.c_str(), tmpStr2.c_str(), tmpStr3.c_str(), options );
+ if ( ! (options & kXMP_SchemaNode) ) {
+ tmpStr4.erase();
+ ok = meta.GetProperty ( tmpStr1.c_str(), tmpStr2.c_str(), &tmpStr4, &opt2 );
+ if ( (! ok) || (tmpStr4 != tmpStr3) || (opt2 != options) ) {
+ fprintf ( log, " ** GetProperty failed: %s, \"%s\", 0x%X\n", FoundOrNot(ok), tmpStr4.c_str(), opt2 );
+ }
+ }
+ }
+ }
+
+ {
+ SXMPIterator iter ( meta, kXMP_IterOmitQualifiers );
+ WriteMinorLabel ( log, "Iterate omitting qualifiers" );
+ while ( true ) {
+ tmpStr1.erase(); tmpStr2.erase(); tmpStr3.erase();
+ if ( ! iter.Next ( &tmpStr1, &tmpStr2, &tmpStr3, &options ) ) break;
+ fprintf ( log, " %s %s = \"%s\", 0x%X\n", tmpStr1.c_str(), tmpStr2.c_str(), tmpStr3.c_str(), options );
+ if ( ! (options & kXMP_SchemaNode) ) {
+ tmpStr4.erase();
+ ok = meta.GetProperty ( tmpStr1.c_str(), tmpStr2.c_str(), &tmpStr4, &opt2 );
+ if ( (! ok) || (tmpStr4 != tmpStr3) || (opt2 != options) ) {
+ fprintf ( log, " ** GetProperty failed: %s, \"%s\", 0x%X\n", FoundOrNot(ok), tmpStr4.c_str(), opt2 );
+ }
+ }
+ }
+ }
+
+ {
+ SXMPIterator iter ( meta, kXMP_IterJustLeafName );
+ WriteMinorLabel ( log, "Iterate with just leaf names" );
+ while ( true ) {
+ tmpStr1.erase(); tmpStr2.erase(); tmpStr3.erase();
+ if ( ! iter.Next ( &tmpStr1, &tmpStr2, &tmpStr3, &options ) ) break;
+ fprintf ( log, " %s %s = \"%s\", 0x%X\n", tmpStr1.c_str(), tmpStr2.c_str(), tmpStr3.c_str(), options );
+ }
+ }
+
+ {
+ SXMPIterator iter ( meta, kXMP_IterJustLeafNodes );
+ WriteMinorLabel ( log, "Iterate just the leaf nodes" );
+ while ( true ) {
+ tmpStr1.erase(); tmpStr2.erase(); tmpStr3.erase();
+ if ( ! iter.Next ( &tmpStr1, &tmpStr2, &tmpStr3, &options ) ) break;
+ fprintf ( log, " %s %s = \"%s\", 0x%X\n", tmpStr1.c_str(), tmpStr2.c_str(), tmpStr3.c_str(), options );
+ if ( ! (options & kXMP_SchemaNode) ) {
+ tmpStr4.erase();
+ ok = meta.GetProperty ( tmpStr1.c_str(), tmpStr2.c_str(), &tmpStr4, &opt2 );
+ if ( (! ok) || (tmpStr4 != tmpStr3) || (opt2 != options) ) {
+ fprintf ( log, " ** GetProperty failed: %s, \"%s\", 0x%X\n", FoundOrNot(ok), tmpStr4.c_str(), opt2 );
+ }
+ }
+ }
+ }
+
+ {
+ SXMPIterator iter ( meta, kXMP_IterJustChildren );
+ WriteMinorLabel ( log, "Iterate just the schema nodes" );
+ while ( true ) {
+ tmpStr1.erase(); tmpStr2.erase(); tmpStr3.erase();
+ if ( ! iter.Next ( &tmpStr1, &tmpStr2, &tmpStr3, &options ) ) break;
+ fprintf ( log, " %s %s = \"%s\", 0x%X\n", tmpStr1.c_str(), tmpStr2.c_str(), tmpStr3.c_str(), options );
+ }
+ }
+
+ {
+ SXMPIterator iter ( meta, kNS2 );
+ WriteMinorLabel ( log, "Iterate the ns2: namespace" );
+ while ( true ) {
+ tmpStr1.erase(); tmpStr2.erase(); tmpStr3.erase();
+ if ( ! iter.Next ( &tmpStr1, &tmpStr2, &tmpStr3, &options ) ) break;
+ fprintf ( log, " %s %s = \"%s\", 0x%X\n", tmpStr1.c_str(), tmpStr2.c_str(), tmpStr3.c_str(), options );
+ if ( ! (options & kXMP_SchemaNode) ) {
+ tmpStr4.erase();
+ ok = meta.GetProperty ( tmpStr1.c_str(), tmpStr2.c_str(), &tmpStr4, &opt2 );
+ if ( (! ok) || (tmpStr4 != tmpStr3) || (opt2 != options) ) {
+ fprintf ( log, " ** GetProperty failed: %s, \"%s\", 0x%X\n", FoundOrNot(ok), tmpStr4.c_str(), opt2 );
+ }
+ }
+ }
+ }
+
+ {
+ SXMPIterator iter ( meta, kNS2, "Bag" );
+ WriteMinorLabel ( log, "Start at ns2:Bag" );
+ while ( true ) {
+ tmpStr1.erase(); tmpStr2.erase(); tmpStr3.erase();
+ if ( ! iter.Next ( &tmpStr1, &tmpStr2, &tmpStr3, &options ) ) break;
+ fprintf ( log, " %s %s = \"%s\", 0x%X\n", tmpStr1.c_str(), tmpStr2.c_str(), tmpStr3.c_str(), options );
+ if ( ! (options & kXMP_SchemaNode) ) {
+ tmpStr4.erase();
+ ok = meta.GetProperty ( tmpStr1.c_str(), tmpStr2.c_str(), &tmpStr4, &opt2 );
+ if ( (! ok) || (tmpStr4 != tmpStr3) || (opt2 != options) ) {
+ fprintf ( log, " ** GetProperty failed: %s, \"%s\", 0x%X\n", FoundOrNot(ok), tmpStr4.c_str(), opt2 );
+ }
+ }
+ }
+ }
+
+ {
+ SXMPIterator iter ( meta, kNS2, "NestedStructProp/ns1:Outer" );
+ WriteMinorLabel ( log, "Start at ns2:NestedStructProp/ns1:Outer" );
+ while ( true ) {
+ tmpStr1.erase(); tmpStr2.erase(); tmpStr3.erase();
+ if ( ! iter.Next ( &tmpStr1, &tmpStr2, &tmpStr3, &options ) ) break;
+ fprintf ( log, " %s %s = \"%s\", 0x%X\n", tmpStr1.c_str(), tmpStr2.c_str(), tmpStr3.c_str(), options );
+ if ( ! (options & kXMP_SchemaNode) ) {
+ tmpStr4.erase();
+ ok = meta.GetProperty ( tmpStr1.c_str(), tmpStr2.c_str(), &tmpStr4, &opt2 );
+ if ( (! ok) || (tmpStr4 != tmpStr3) || (opt2 != options) ) {
+ fprintf ( log, " ** GetProperty failed: %s, \"%s\", 0x%X\n", FoundOrNot(ok), tmpStr4.c_str(), opt2 );
+ }
+ }
+ }
+ }
+
+ {
+ SXMPIterator iter ( meta, "ns:empty/" );
+ WriteMinorLabel ( log, "Iterate an empty namespace" );
+ while ( true ) {
+ tmpStr1.erase(); tmpStr2.erase(); tmpStr3.erase();
+ if ( ! iter.Next ( &tmpStr1, &tmpStr2, &tmpStr3, &options ) ) break;
+ fprintf ( log, " %s %s = \"%s\", 0x%X\n", tmpStr1.c_str(), tmpStr2.c_str(), tmpStr3.c_str(), options );
+ if ( ! (options & kXMP_SchemaNode) ) {
+ tmpStr4.erase();
+ ok = meta.GetProperty ( tmpStr1.c_str(), tmpStr2.c_str(), &tmpStr4, &opt2 );
+ if ( (! ok) || (tmpStr4 != tmpStr3) || (opt2 != options) ) {
+ fprintf ( log, " ** GetProperty failed: %s, \"%s\", 0x%X\n", FoundOrNot(ok), tmpStr4.c_str(), opt2 );
+ }
+ }
+ }
+ }
+
+ {
+ SXMPIterator iter ( meta, kNS2, "", kXMP_IterJustChildren | kXMP_IterJustLeafName );
+ WriteMinorLabel ( log, "Iterate the top of the ns2: namespace with just leaf names" );
+ while ( true ) {
+ tmpStr1.erase(); tmpStr2.erase(); tmpStr3.erase();
+ if ( ! iter.Next ( &tmpStr1, &tmpStr2, &tmpStr3, &options ) ) break;
+ fprintf ( log, " %s %s = \"%s\", 0x%X\n", tmpStr1.c_str(), tmpStr2.c_str(), tmpStr3.c_str(), options );
+ }
+ }
+
+ {
+ SXMPIterator iter ( meta, kNS2, "", kXMP_IterJustChildren | kXMP_IterJustLeafNodes );
+ WriteMinorLabel ( log, "Iterate the top of the ns2: namespace visiting just leaf nodes" );
+ while ( true ) {
+ tmpStr1.erase(); tmpStr2.erase(); tmpStr3.erase();
+ if ( ! iter.Next ( &tmpStr1, &tmpStr2, &tmpStr3, &options ) ) break;
+ fprintf ( log, " %s %s = \"%s\", 0x%X\n", tmpStr1.c_str(), tmpStr2.c_str(), tmpStr3.c_str(), options );
+ if ( ! (options & kXMP_SchemaNode) ) {
+ tmpStr4.erase();
+ ok = meta.GetProperty ( tmpStr1.c_str(), tmpStr2.c_str(), &tmpStr4, &opt2 );
+ if ( (! ok) || (tmpStr4 != tmpStr3) || (opt2 != options) ) {
+ fprintf ( log, " ** GetProperty failed: %s, \"%s\", 0x%X\n", FoundOrNot(ok), tmpStr4.c_str(), opt2 );
+ }
+ }
+ }
+ }
+
+ {
+ SXMPIterator iter ( meta, kNS2, "Bag", kXMP_IterJustChildren );
+ WriteMinorLabel ( log, "Iterate just the children of ns2:Bag" );
+ while ( true ) {
+ tmpStr1.erase(); tmpStr2.erase(); tmpStr3.erase();
+ if ( ! iter.Next ( &tmpStr1, &tmpStr2, &tmpStr3, &options ) ) break;
+ fprintf ( log, " %s %s = \"%s\", 0x%X\n", tmpStr1.c_str(), tmpStr2.c_str(), tmpStr3.c_str(), options );
+ if ( ! (options & kXMP_SchemaNode) ) {
+ tmpStr4.erase();
+ ok = meta.GetProperty ( tmpStr1.c_str(), tmpStr2.c_str(), &tmpStr4, &opt2 );
+ if ( (! ok) || (tmpStr4 != tmpStr3) || (opt2 != options) ) {
+ fprintf ( log, " ** GetProperty failed: %s, \"%s\", 0x%X\n", FoundOrNot(ok), tmpStr4.c_str(), opt2 );
+ }
+ }
+ }
+ }
+
+ {
+ SXMPIterator iter ( meta, kNS2, "Bag", kXMP_IterJustChildren | kXMP_IterJustLeafName );
+ WriteMinorLabel ( log, "Iterate just the children of ns2:Bag with just leaf names" );
+ while ( true ) {
+ tmpStr1.erase(); tmpStr2.erase(); tmpStr3.erase();
+ if ( ! iter.Next ( &tmpStr1, &tmpStr2, &tmpStr3, &options ) ) break;
+ fprintf ( log, " %s %s = \"%s\", 0x%X\n", tmpStr1.c_str(), tmpStr2.c_str(), tmpStr3.c_str(), options );
+ }
+ }
+
+ {
+ SXMPIterator iter ( meta, kNS2, "NestedStructProp/ns1:Outer/ns1:Middle", kXMP_IterJustChildren );
+ WriteMinorLabel ( log, "Iterate just the children of ns2:NestedStructProp/ns1:Outer/ns1:Middle" );
+ while ( true ) {
+ tmpStr1.erase(); tmpStr2.erase(); tmpStr3.erase();
+ if ( ! iter.Next ( &tmpStr1, &tmpStr2, &tmpStr3, &options ) ) break;
+ fprintf ( log, " %s %s = \"%s\", 0x%X\n", tmpStr1.c_str(), tmpStr2.c_str(), tmpStr3.c_str(), options );
+ if ( ! (options & kXMP_SchemaNode) ) {
+ tmpStr4.erase();
+ ok = meta.GetProperty ( tmpStr1.c_str(), tmpStr2.c_str(), &tmpStr4, &opt2 );
+ if ( (! ok) || (tmpStr4 != tmpStr3) || (opt2 != options) ) {
+ fprintf ( log, " ** GetProperty failed: %s, \"%s\", 0x%X\n", FoundOrNot(ok), tmpStr4.c_str(), opt2 );
+ }
+ }
+ }
+ }
+
+ {
+ SXMPIterator iter ( meta );
+ WriteMinorLabel ( log, "Skip children of ArrayProp2, and siblings after StructProp" );
+ while ( true ) {
+ tmpStr1.erase(); tmpStr2.erase(); tmpStr3.erase();
+ if ( ! iter.Next ( &tmpStr1, &tmpStr2, &tmpStr3, &options ) ) break;
+ fprintf ( log, " %s %s = \"%s\", 0x%X\n", tmpStr1.c_str(), tmpStr2.c_str(), tmpStr3.c_str(), options );
+ if ( ! (options & kXMP_SchemaNode) ) {
+ tmpStr4.erase();
+ ok = meta.GetProperty ( tmpStr1.c_str(), tmpStr2.c_str(), &tmpStr4, &opt2 );
+ if ( (! ok) || (tmpStr4 != tmpStr3) || (opt2 != options) ) {
+ fprintf ( log, " ** GetProperty failed: %s, \"%s\", 0x%X\n", FoundOrNot(ok), tmpStr4.c_str(), opt2 );
+ }
+ }
+ if ( tmpStr2 == "ns1:ArrayProp2" ) iter.Skip ( kXMP_IterSkipSubtree );
+ if ( tmpStr2 == "ns1:StructProp" ) iter.Skip ( kXMP_IterSkipSiblings );
+ }
+ }
+
+ {
+ SXMPMeta meta;
+
+ meta.SetProperty ( kXMP_NS_PDF, "Author", "PDF Author" );
+ meta.SetProperty ( kXMP_NS_PDF, "PDFProp", "PDF Prop" );
+ meta.SetProperty ( kXMP_NS_XMP, "XMPProp", "XMP Prop" );
+ meta.SetProperty ( kXMP_NS_DC, "DCProp", "DC Prop" );
+
+ SXMPIterator iter1 ( meta );
+ WriteMinorLabel ( log, "Iterate without showing aliases" );
+ while ( true ) {
+ tmpStr1.erase(); tmpStr2.erase(); tmpStr3.erase();
+ if ( ! iter1.Next ( &tmpStr1, &tmpStr2, &tmpStr3, &options ) ) break;
+ fprintf ( log, " %s %s = \"%s\", 0x%X\n", tmpStr1.c_str(), tmpStr2.c_str(), tmpStr3.c_str(), options );
+ if ( ! (options & kXMP_SchemaNode) ) {
+ tmpStr4.erase();
+ options &= kXMP_PropHasAliases; // So the comparison below works.
+ ok = meta.GetProperty ( tmpStr1.c_str(), tmpStr2.c_str(), &tmpStr4, &opt2 );
+ if ( (! ok) || (tmpStr4 != tmpStr3) || (opt2 != options) ) {
+ fprintf ( log, " ** GetProperty failed: %s, \"%s\", 0x%X\n", FoundOrNot(ok), tmpStr4.c_str(), opt2 );
+ }
+ }
+ }
+
+ SXMPIterator iter2 ( meta, kXMP_IterIncludeAliases );
+ WriteMinorLabel ( log, "Iterate showing aliases" );
+ while ( true ) {
+ tmpStr1.erase(); tmpStr2.erase(); tmpStr3.erase();
+ if ( ! iter2.Next ( &tmpStr1, &tmpStr2, &tmpStr3, &options ) ) break;
+ fprintf ( log, " %s %s = \"%s\", 0x%X\n", tmpStr1.c_str(), tmpStr2.c_str(), tmpStr3.c_str(), options );
+ if ( ! (options & kXMP_SchemaNode) ) {
+ tmpStr4.erase();
+ options &= ~(kXMP_PropIsAlias | kXMP_PropHasAliases); // So the comparison below works.
+ ok = meta.GetProperty ( tmpStr1.c_str(), tmpStr2.c_str(), &tmpStr4, &opt2 );
+ if ( (! ok) || (tmpStr4 != tmpStr3) || (opt2 != options) ) {
+ fprintf ( log, " ** GetProperty failed: %s, \"%s\", 0x%X\n", FoundOrNot(ok), tmpStr4.c_str(), opt2 );
+ }
+ }
+ }
+ }
+
+ }
+
+ // --------------------------------------------------------------------------------------------
+ // XPath composition utilities
+ // ---------------------------
+
+ {
+ WriteMajorLabel ( log, "Test XPath composition utilities" );
+
+ SXMPMeta meta ( kSimpleRDF, strlen(kSimpleRDF) );
+ DumpXMPObj ( log, meta, "Parse simple RDF" );
+ fprintf ( log, "\n" );
+
+ tmpStr1.erase();
+ SXMPUtils::ComposeArrayItemPath ( kNS1, "ArrayProp", 2, &tmpStr1 );
+ fprintf ( log, "ComposeArrayItemPath ns1:ArrayProp[2] : %s\n", tmpStr1.c_str() );
+ meta.SetProperty ( kNS1, tmpStr1.c_str(), "new ns1:ArrayProp[2] value" );
+
+ fprintf ( log, "\n" );
+
+ tmpStr1.erase();
+ SXMPUtils::ComposeStructFieldPath ( kNS1, "StructProp", kNS2, "Field3", &tmpStr1 );
+ fprintf ( log, "ComposeStructFieldPath ns1:StructProp/ns2:Field3 : %s\n", tmpStr1.c_str() );
+ meta.SetProperty ( kNS1, tmpStr1.c_str(), "new ns1:StructProp/ns2:Field3 value" );
+
+ tmpStr1.erase();
+ SXMPUtils::ComposeQualifierPath ( kNS1, "QualProp", kNS2, "Qual", &tmpStr1 );
+ fprintf ( log, "ComposeQualifierPath ns1:QualProp/?ns2:Qual : %s\n", tmpStr1.c_str() );
+ meta.SetProperty ( kNS1, tmpStr1.c_str(), "new ns1:QualProp/?ns2:Qual value" );
+
+ fprintf ( log, "\n" );
+
+ tmpStr1.erase();
+ SXMPUtils::ComposeQualifierPath ( kNS1, "AltTextProp", kXMP_NS_XML, "lang", &tmpStr1 );
+ fprintf ( log, "ComposeQualifierPath ns1:AltTextProp/?xml:lang : %s\n", tmpStr1.c_str() );
+ meta.SetProperty ( kNS1, tmpStr1.c_str(), "new ns1:AltTextProp/?xml:lang value" );
+
+ tmpStr1.erase();
+ tmpStr2 = "x-two";
+ SXMPUtils::ComposeLangSelector ( kNS1, "AltTextProp", tmpStr2, &tmpStr1 );
+ fprintf ( log, "ComposeLangSelector ns1:AltTextProp['x-two'] : %s\n", tmpStr1.c_str() );
+ meta.SetProperty ( kNS1, tmpStr1.c_str(), "new ns1:AltTextProp['x-two'] value" );
+
+ fprintf ( log, "\n" );
+
+ fprintf ( log, "Check field selector usage\n" ); fflush ( log );
+
+ tmpStr1.erase();
+ ok = meta.GetProperty ( kNS1, "ArrayOfStructProp[ns2:Field1='Item-2']", &tmpStr1, &options );
+ fprintf ( log, "GetProperty ArrayOfStructProp[ns2:Field1='Item-2'] : %s, \"%s\", 0x%X\n", FoundOrNot ( ok ), tmpStr1.c_str(), options ); fflush ( log );
+
+ tmpStr1.erase();
+ ok = meta.GetProperty ( kNS1, "ArrayOfStructProp[ns2:Field1='Item-2']/ns2:Field2", &tmpStr1, &options );
+ fprintf ( log, "GetProperty ArrayOfStructProp[ns2:Field1='Item-2']/ns2:Field2 : %s, \"%s\", 0x%X\n", FoundOrNot ( ok ), tmpStr1.c_str(), options ); fflush ( log );
+
+ tmpStr1.erase();
+ tmpStr2 = "Item-2";
+ SXMPUtils::ComposeFieldSelector ( kNS1, "ArrayOfStructProp", kNS2, "Field1", tmpStr2, &tmpStr1 );
+ fprintf ( log, "ComposeFieldSelector ns1:ArrayOfStructProp[ns2:Field1=Item-2] : %s\n", tmpStr1.c_str() );
+
+ tmpStr2.erase();
+ SXMPUtils::ComposeStructFieldPath ( kNS1, tmpStr1.c_str(), kNS2, "Field2", &tmpStr2 );
+ fprintf ( log, "ComposeStructFieldPath ns1:ArrayOfStructProp[ns2:Field1=Item-2]/ns2:Field2 : %s\n", tmpStr2.c_str() );
+ meta.SetProperty ( kNS1, tmpStr2.c_str(), "new ns1:ArrayOfStructProp[ns2:Field1=Item-2]/ns2:Field2 value" );
+
+ DumpXMPObj ( log, meta, "Modified simple RDF" );
+
+ }
+
+ // --------------------------------------------------------------------------------------------
+ // Value conversion utilities
+ // --------------------------
+
+ WriteMajorLabel ( log, "Test value conversion utilities" );
+ fprintf ( log, "\n" );
+
+ tmpStr1.erase();
+ SXMPUtils::ConvertFromBool ( true, &tmpStr1 );
+ fprintf ( log, "ConverFromBool true : %s\n", tmpStr1.c_str() );
+ tmpStr1.erase();
+ SXMPUtils::ConvertFromBool ( false, &tmpStr1 );
+ fprintf ( log, "ConverFromBool false : %s\n", tmpStr1.c_str() );
+
+ fprintf ( log, "\n" );
+
+ ok = SXMPUtils::ConvertToBool ( kXMP_TrueStr );
+ fprintf ( log, "ConverToBool kXMP_TrueStr : %d\n", (int)ok );
+ ok = SXMPUtils::ConvertToBool ( kXMP_FalseStr );
+ fprintf ( log, "ConverToBool kXMP_FalseStr : %d\n", (int)ok );
+
+ fprintf ( log, "\n" );
+
+ tmpStr1 = "true";
+ ok = SXMPUtils::ConvertToBool ( tmpStr1 );
+ fprintf ( log, "ConverToBool true : %d\n", (int)ok );
+ ok = SXMPUtils::ConvertToBool ( "TRUE" );
+ fprintf ( log, "ConverToBool TRUE : %d\n", (int)ok );
+ ok = SXMPUtils::ConvertToBool ( "t" );
+ fprintf ( log, "ConverToBool t : %d\n", (int)ok );
+ ok = SXMPUtils::ConvertToBool ( "1" );
+ fprintf ( log, "ConverToBool 1 : %d\n", (int)ok );
+
+ fprintf ( log, "\n" );
+
+ ok = SXMPUtils::ConvertToBool ( "false" );
+ fprintf ( log, "ConverToBool false : %d\n", (int)ok );
+ ok = SXMPUtils::ConvertToBool ( "FALSE" );
+ fprintf ( log, "ConverToBool FALSE : %d\n", (int)ok );
+ ok = SXMPUtils::ConvertToBool ( "f" );
+ fprintf ( log, "ConverToBool f : %d\n", (int)ok );
+ ok = SXMPUtils::ConvertToBool ( "0" );
+ fprintf ( log, "ConverToBool 0 : %d\n", (int)ok );
+
+ fprintf ( log, "\n" );
+
+ tmpStr1.erase();
+ SXMPUtils::ConvertFromInt ( 0, 0, &tmpStr1 );
+ fprintf ( log, "ConverFromInt 0 : %s\n", tmpStr1.c_str() );
+ tmpStr1.erase();
+ SXMPUtils::ConvertFromInt ( 42, 0, &tmpStr1 );
+ fprintf ( log, "ConverFromInt 42 : %s\n", tmpStr1.c_str() );
+ tmpStr1.erase();
+ SXMPUtils::ConvertFromInt ( -42, 0, &tmpStr1 );
+ fprintf ( log, "ConverFromInt -42 : %s\n", tmpStr1.c_str() );
+ tmpStr1.erase();
+ SXMPUtils::ConvertFromInt ( 0x7FFFFFFF, 0, &tmpStr1 );
+ fprintf ( log, "ConverFromInt 0x7FFFFFFF : %s\n", tmpStr1.c_str() );
+ tmpStr1.erase();
+ SXMPUtils::ConvertFromInt ( 0x80000000, 0, &tmpStr1 );
+ fprintf ( log, "ConverFromInt 0x80000000 : %s\n", tmpStr1.c_str() );
+ tmpStr1.erase();
+ SXMPUtils::ConvertFromInt ( 0x7FFFFFFF, "%X", &tmpStr1 );
+ fprintf ( log, "ConverFromInt 0x7FFFFFFF as hex : %s\n", tmpStr1.c_str() );
+ tmpStr1.erase();
+ SXMPUtils::ConvertFromInt ( 0x80000000, "%X", &tmpStr1 );
+ fprintf ( log, "ConverFromInt 0x80000000 as hex : %s\n", tmpStr1.c_str() );
+
+ fprintf ( log, "\n" );
+
+ long int1;
+
+ tmpStr1 = "0";
+ int1 = SXMPUtils::ConvertToInt ( tmpStr1 );
+ fprintf ( log, "ConvertToInt 0 : %d\n", int1 );
+ int1 = SXMPUtils::ConvertToInt ( "42" );
+ fprintf ( log, "ConvertToInt 42 : %d\n", int1 );
+ int1 = SXMPUtils::ConvertToInt ( "-42" );
+ fprintf ( log, "ConvertToInt -42 : %d\n", int1 );
+ int1 = SXMPUtils::ConvertToInt ( "0x7FFFFFFF" );
+ fprintf ( log, "ConvertToInt 0x7FFFFFFF : %d\n", int1 );
+ int1 = SXMPUtils::ConvertToInt ( "0x80000000" );
+ fprintf ( log, "ConvertToInt 0x80000000 : %d\n", int1 );
+ int1 = SXMPUtils::ConvertToInt ( "0x7FFFFFFF" );
+ fprintf ( log, "ConvertToInt 0x7FFFFFFF as hex : %X\n", int1 );
+ int1 = SXMPUtils::ConvertToInt ( "0x80000000" );
+ fprintf ( log, "ConvertToInt 0x80000000 as hex : %X\n", int1 );
+
+ fprintf ( log, "\n" );
+
+ tmpStr1.erase();
+ SXMPUtils::ConvertFromFloat ( 0, 0, &tmpStr1 );
+ fprintf ( log, "ConverFromFloat 0 : %s\n", tmpStr1.c_str() );
+ tmpStr1.erase();
+ SXMPUtils::ConvertFromFloat ( 4.2, 0, &tmpStr1 );
+ fprintf ( log, "ConverFromFloat 4.2 : %s\n", tmpStr1.c_str() );
+ tmpStr1.erase();
+ SXMPUtils::ConvertFromFloat ( -4.2, 0, &tmpStr1 );
+ fprintf ( log, "ConverFromFloat -4.2 : %s\n", tmpStr1.c_str() );
+ tmpStr1.erase();
+ SXMPUtils::ConvertFromFloat ( (int)0x7FFFFFFF, 0, &tmpStr1 );
+ fprintf ( log, "ConverFromFloat 0x7FFFFFFF : %s\n", tmpStr1.c_str() );
+ tmpStr1.erase();
+ SXMPUtils::ConvertFromFloat ( (int)0x80000000, 0, &tmpStr1 );
+ fprintf ( log, "ConverFromFloat 0x80000000 : %s\n", tmpStr1.c_str() );
+ tmpStr1.erase();
+ SXMPUtils::ConvertFromFloat ( (int)0x7FFFFFFF, "%f", &tmpStr1 );
+ fprintf ( log, "ConverFromFloat 0x7FFFFFFF as f : %s\n", tmpStr1.c_str() );
+ tmpStr1.erase();
+ SXMPUtils::ConvertFromFloat ( (int)0x80000000, "%f", &tmpStr1 );
+ fprintf ( log, "ConverFromFloat 0x80000000 as f : %s\n", tmpStr1.c_str() );
+
+ fprintf ( log, "\n" );
+
+ double float1;
+
+ tmpStr1 = "0";
+ float1 = SXMPUtils::ConvertToFloat ( tmpStr1 );
+ fprintf ( log, "ConvertToFloat 0 : %f\n", float1 );
+ float1 = SXMPUtils::ConvertToFloat ( "4.2" );
+ fprintf ( log, "ConvertToFloat 4.2 : %f\n", float1 );
+ float1 = SXMPUtils::ConvertToFloat ( "-4.2" );
+ fprintf ( log, "ConvertToFloat -4.2 : %f\n", float1 );
+
+ fprintf ( log, "\n" );
+
+ XMP_DateTime date1 = { 2000, 1, 31, 12, 34, 56, -1, 8, 0, 0 };
+ XMP_DateTime date2 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+ tmpStr1.erase();
+ SXMPUtils::ConvertFromDate ( date1, &tmpStr1 );
+ fprintf ( log, "ConvertFromDate 2000 Jan 31 12:34:56 PST : %s\n", tmpStr1.c_str() );
+
+ SXMPUtils::ConvertToDate ( tmpStr1, &date2 );
+ fprintf ( log, "ConvertToDate : %d-%02d-%02d %02d:%02d:%02d %d*%02d:%02d %d\n",
+ date2.year, date2.month, date2.day, date2.hour, date2.minute, date2.second,
+ date2.tzSign, date2.tzHour, date2.tzMinute, date2.nanoSecond );
+
+ // --------------------------------------------------------------------------------------------
+ // Date/Time utilities
+ // -------------------
+
+ {
+ WriteMajorLabel ( log, "Test date/time utilities and special values" );
+ fprintf ( log, "\n" );
+
+ XMP_DateTime utcNow = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+ XMP_DateTime localNow = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+ SXMPUtils::SetTimeZone ( &utcNow );
+ fprintf ( log, "SetTimeZone : %d-%02d-%02d %02d:%02d:%02d %d*%02d:%02d %d\n",
+ utcNow.year, utcNow.month, utcNow.day, utcNow.hour, utcNow.minute, utcNow.second,
+ utcNow.tzSign, utcNow.tzHour, utcNow.tzMinute, utcNow.nanoSecond );
+
+ SXMPUtils::CurrentDateTime ( &utcNow );
+ fprintf ( log, "CurrentDateTime : %d-%02d-%02d %02d:%02d:%02d %d*%02d:%02d %d\n",
+ utcNow.year, utcNow.month, utcNow.day, utcNow.hour, utcNow.minute, utcNow.second,
+ utcNow.tzSign, utcNow.tzHour, utcNow.tzMinute, utcNow.nanoSecond );
+
+ localNow = utcNow;
+ SXMPUtils::ConvertToLocalTime ( &localNow );
+ fprintf ( log, "ConvertToLocalTime : %d-%02d-%02d %02d:%02d:%02d %d*%02d:%02d %d\n",
+ localNow.year, localNow.month, localNow.day, localNow.hour, localNow.minute, localNow.second,
+ localNow.tzSign, localNow.tzHour, localNow.tzMinute, localNow.nanoSecond );
+
+ utcNow = localNow;
+ SXMPUtils::ConvertToUTCTime ( &utcNow );
+ fprintf ( log, "ConvertToUTCTime : %d-%02d-%02d %02d:%02d:%02d %d*%02d:%02d %d\n",
+ utcNow.year, utcNow.month, utcNow.day, utcNow.hour, utcNow.minute, utcNow.second,
+ utcNow.tzSign, utcNow.tzHour, utcNow.tzMinute, utcNow.nanoSecond );
+
+ fprintf ( log, "\n" );
+
+ i = SXMPUtils::CompareDateTime ( utcNow, localNow );
+ fprintf ( log, "CompareDateTime with a == b : %d\n", i );
+
+ utcNow.second = 0;
+ localNow.second = 30;
+ i = SXMPUtils::CompareDateTime ( utcNow, localNow );
+ fprintf ( log, "CompareDateTime with a < b : %d\n", i );
+
+ utcNow.second = 59;
+ i = SXMPUtils::CompareDateTime ( utcNow, localNow );
+ fprintf ( log, "CompareDateTime with a > b : %d\n", i );
+
+ }
+
+ // --------------------------------------------------------------------------------------------
+ // Miscellaneous utilities
+ // -----------------------
+
+ {
+ WriteMajorLabel ( log, "Test CatenateArrayItems and SeparateArrayItems" );
+ fprintf ( log, "\n" );
+
+ SXMPMeta meta;
+
+ meta.AppendArrayItem ( kNS1, "Array1", kXMP_PropValueIsArray, "one" );
+ meta.AppendArrayItem ( kNS1, "Array1", 0, "two" );
+ meta.AppendArrayItem ( kNS1, "Array1", kXMP_PropValueIsArray, "3, three" );
+ meta.AppendArrayItem ( kNS1, "Array1", 0, "4; four" );
+
+ DumpXMPObj ( log, meta, "Initial array" );
+ fprintf ( log, "\n" );
+
+ tmpStr1.erase();
+ SXMPUtils::CatenateArrayItems ( meta, kNS1, "Array1", "; ", "\"", kXMP_NoOptions, &tmpStr1 );
+ fprintf ( log, "CatenateArrayItems, no commas : %s\n", tmpStr1.c_str() );
+
+ tmpStr2.erase();
+ SXMPUtils::CatenateArrayItems ( meta, kNS1, "Array1", " ; ", "[]", kXMPUtil_AllowCommas, &tmpStr2 );
+ fprintf ( log, "CatenateArrayItems, allow commas : %s\n", tmpStr2.c_str() );
+
+ SXMPUtils::SeparateArrayItems ( &meta, kNS1, "Array2-1", kXMP_NoOptions, tmpStr1.c_str() );
+ SXMPUtils::SeparateArrayItems ( &meta, kNS1, "Array2-2", kXMPUtil_AllowCommas, tmpStr1.c_str() );
+
+ SXMPUtils::SeparateArrayItems ( &meta, kNS1, "Array3-1", kXMP_PropArrayIsOrdered, tmpStr2 );
+ SXMPUtils::SeparateArrayItems ( &meta, kNS1, "Array3-2", (kXMP_PropArrayIsOrdered | kXMPUtil_AllowCommas), tmpStr2 );
+
+ DumpXMPObj ( log, meta, "Set Array1, cat and split into others" );
+
+ SXMPUtils::SeparateArrayItems ( &meta, kNS1, "Array2-2", kXMP_NoOptions, tmpStr1.c_str() ); // Repeat into existing arrays.
+ SXMPUtils::SeparateArrayItems ( &meta, kNS1, "Array3-2", kXMP_PropArrayIsOrdered, tmpStr2.c_str() );
+
+ }
+
+ // --------------------------------------------------------------------------------------------
+
+ {
+ WriteMajorLabel ( log, "Test RemoveProperties and AppendProperties" );
+
+ SXMPMeta meta1 ( kSimpleRDF, strlen(kSimpleRDF) );
+
+ meta1.SetProperty ( kNS2, "Prop", "value" );
+ DumpXMPObj ( log, meta1, "Parse simple RDF, add ns2:Prop" );
+
+ SXMPUtils::RemoveProperties ( &meta1, kNS1, "ArrayOfStructProp" );
+ DumpXMPObj ( log, meta1, "Remove ns1:ArrayOfStructProp" );
+
+ SXMPUtils::RemoveProperties ( &meta1, kNS1 );
+ DumpXMPObj ( log, meta1, "Remove all of ns1:" );
+
+ meta1.SetProperty ( kXMP_NS_XMP, "CreatorTool", "XMPCoverage" );
+ meta1.SetProperty ( kXMP_NS_XMP, "Nickname", "TXMP test" );
+ DumpXMPObj ( log, meta1, "Set xmp:CreatorTool (internal) and xmp:Nickname (external)" );
+
+ SXMPUtils::RemoveProperties ( &meta1 );
+ DumpXMPObj ( log, meta1, "Remove all external properties" );
+
+ SXMPUtils::RemoveProperties ( &meta1, 0, 0, kXMPUtil_DoAllProperties );
+ DumpXMPObj ( log, meta1, "Remove all properties, including internal" );
+
+ meta1.SetProperty ( kXMP_NS_XMP, "CreatorTool", "XMPCoverage" );
+ meta1.SetProperty ( kXMP_NS_XMP, "Nickname", "TXMP test" );
+ DumpXMPObj ( log, meta1, "Set xmp:CreatorTool and xmp:Nickname again" );
+
+ SXMPMeta meta2 ( kSimpleRDF, strlen(kSimpleRDF) );
+
+ meta2.SetProperty ( kXMP_NS_XMP, "CreatorTool", "new CreatorTool" );
+ meta2.SetProperty ( kXMP_NS_XMP, "Nickname", "new Nickname" );
+ meta2.SetProperty ( kXMP_NS_XMP, "Format", "new Format" );
+ DumpXMPObj ( log, meta2, "Create 2nd XMP object with new values" );
+
+ SXMPUtils::AppendProperties ( meta2, &meta1 );
+ DumpXMPObj ( log, meta1, "Append 2nd to 1st, keeping old values, external only" );
+
+ meta2.SetProperty ( kXMP_NS_XMP, "CreatorTool", "newer CreatorTool" );
+ meta2.SetProperty ( kXMP_NS_XMP, "Nickname", "newer Nickname" );
+ meta2.SetProperty ( kXMP_NS_XMP, "Format", "newer Format" );
+ SXMPUtils::AppendProperties ( meta2, &meta1, kXMPUtil_DoAllProperties );
+ DumpXMPObj ( log, meta1, "Append 2nd to 1st, keeping old values, internal also" );
+
+ meta2.SetProperty ( kXMP_NS_XMP, "CreatorTool", "newest CreatorTool" );
+ meta2.SetProperty ( kXMP_NS_XMP, "Nickname", "newest Nickname" );
+ meta2.SetProperty ( kXMP_NS_XMP, "Format", "newest Format" );
+ SXMPUtils::AppendProperties ( meta2, &meta1, kXMPUtil_ReplaceOldValues );
+ DumpXMPObj ( log, meta1, "Append 2nd to 1st, replacing old values, external only" );
+
+ meta2.SetProperty ( kXMP_NS_XMP, "CreatorTool", "final CreatorTool" );
+ meta2.SetProperty ( kXMP_NS_XMP, "Nickname", "final Nickname" );
+ meta2.SetProperty ( kXMP_NS_XMP, "Format", "final Format" );
+ SXMPUtils::AppendProperties ( meta2, &meta1, (kXMPUtil_ReplaceOldValues | kXMPUtil_DoAllProperties) );
+ DumpXMPObj ( log, meta1, "Append 2nd to 1st, replacing old values, internal also" );
+
+ }
+
+ // --------------------------------------------------------------------------------------------
+
+ {
+ WriteMajorLabel ( log, "Test DuplicateSubtree" );
+
+ SXMPMeta meta1 ( kSimpleRDF, strlen(kSimpleRDF) );
+ SXMPMeta meta2;
+
+ SXMPUtils::DuplicateSubtree ( meta1, &meta2, kNS1, "ArrayOfStructProp" );
+ DumpXMPObj ( log, meta2, "DuplicateSubtree to default destination" );
+
+ #if 1 // The underlying old toolkit does not support changing the schema namespace.
+
+ SXMPUtils::DuplicateSubtree ( meta1, &meta2, kNS1, "ArrayOfStructProp", kNS2, "NewAoS" );
+ DumpXMPObj ( log, meta2, "DuplicateSubtree to different destination" );
+
+ SXMPUtils::DuplicateSubtree ( meta1, &meta1, kNS1, "ArrayOfStructProp", kNS2, "NewAoS" );
+ DumpXMPObj ( log, meta1, "DuplicateSubtree to different destination in same object" );
+
+ #else
+
+ SXMPUtils::DuplicateSubtree ( meta1, &meta2, kNS1, "ArrayOfStructProp", kNS1, "NewAoS" );
+ DumpXMPObj ( log, meta2, "DuplicateSubtree to different destination" );
+
+ SXMPUtils::DuplicateSubtree ( meta1, &meta1, kNS1, "ArrayOfStructProp", kNS1, "NewAoS" );
+ DumpXMPObj ( log, meta1, "DuplicateSubtree to different destination in same object" );
+
+ #endif
+
+ }
+
+ // --------------------------------------------------------------------------------------------
+
+ {
+ WriteMajorLabel ( log, "Test EncodeToBase64 and DecodeFromBase64" );
+ fprintf ( log, "\n" );
+
+ unsigned long m;
+
+ #if UseStringPushBack
+ #define PushBack(s,c) s.push_back ( c )
+ #else
+ #define PushBack(s,c) s.insert ( s.end(), c );
+ #endif
+
+ tmpStr1.erase();
+ for ( i = 0; i < 64; i += 4 ) {
+ m = (i << 18) + ((i+1) << 12) + ((i+2) << 6) + (i+3);
+ PushBack ( tmpStr1, ((char) (m >> 16)) );
+ PushBack ( tmpStr1, ((char) ((m >> 8) & 0xFF)) );
+ PushBack ( tmpStr1, ((char) (m & 0xFF)) );
+ }
+
+ tmpStr2.erase();
+ SXMPUtils::EncodeToBase64 ( tmpStr1, &tmpStr2 );
+ fprintf ( log, "Encoded sequence (should be A-Za-z0-9+/) : %s\n", tmpStr2.c_str() );
+
+ tmpStr3.erase();
+ SXMPUtils::DecodeFromBase64 ( tmpStr2, &tmpStr3 );
+ if ( tmpStr1 != tmpStr3 ) fprintf ( log, "** Error in base 64 round trip\n" );
+
+ }
+
+ // --------------------------------------------------------------------------------------------
+
+ WriteMajorLabel ( log, "XMPCoreCoverage done" );
+ fprintf ( log, "\n" );
+
+} // DoXMPCoreCoverage
+
+// =================================================================================================
+
+extern "C" int main ( int /*argc*/, const char * argv [] )
+{
+ int result = 0;
+
+ char logName[256];
+ int nameLen = strlen ( argv[0] );
+ if ( (nameLen >= 4) && (strcmp ( argv[0]+nameLen-4, ".exe" ) == 0) ) nameLen -= 4;
+ memcpy ( logName, argv[0], nameLen );
+ memcpy ( &logName[nameLen], "Log.txt", 8 ); // Include final null.
+ FILE * log = fopen ( logName, "wb" );
+
+ time_t now = time(0);
+ fprintf ( log, "XMPCoreCoverage starting %s", ctime(&now) );
+
+ XMP_VersionInfo version;
+ SXMPMeta::GetVersionInfo ( &version );
+ fprintf ( log, "Version : %s\n" , version.message );
+
+ try {
+
+ if ( ! SXMPMeta::Initialize() ) {
+ fprintf ( log, "## XMPMeta::Initialize failed!\n" );
+ return -1;
+ }
+ DoXMPCoreCoverage ( log );
+
+ } catch ( XMP_Error & excep ) {
+
+ fprintf ( log, "\nCaught XMP_Error %d : %s\n", excep.GetID(), excep.GetErrMsg() );
+ result = -2;
+
+ } catch ( ... ) {
+
+ fprintf ( log, "## Caught unknown exception\n" );
+ result = -3;
+
+ }
+
+ SXMPMeta::Terminate();
+ now = time(0);
+ fprintf ( log, "XMPCoreCoverage finished %s", ctime(&now) );
+ fprintf ( log, "Final status = %d\n", result );
+ fclose ( log );
+ return result;
+
+}
diff --git a/samples/source/XMPFilesCoverage.cpp b/samples/source/XMPFilesCoverage.cpp
new file mode 100644
index 0000000..768d055
--- /dev/null
+++ b/samples/source/XMPFilesCoverage.cpp
@@ -0,0 +1,322 @@
+#include <vector>
+#include <string>
+#include <stdexcept>
+#include <errno.h>
+#include <time.h>
+
+#define TXMP_STRING_TYPE std::string
+#define XMP_INCLUDE_XMPFILES 1
+#include "XMP.hpp"
+#include "XMP.incl_cpp"
+
+using namespace std;
+
+#if WIN_ENV
+ #pragma warning ( disable : 4100 ) // ignore unused variable
+ #pragma warning ( disable : 4127 ) // conditional expression is constant
+ #pragma warning ( disable : 4505 ) // unreferenced local function has been removed
+ #pragma warning ( disable : 4996 ) // '...' was declared deprecated
+#endif
+
+// -------------------------------------------------------------------------------------------------
+
+FILE * sLogFile = 0;
+
+// -------------------------------------------------------------------------------------------------
+
+static void WriteMinorLabel ( FILE * log, const char * title )
+{
+
+ fprintf ( log, "\n// " );
+ for ( size_t i = 0; i < strlen(title); ++i ) fprintf ( log, "-" );
+ fprintf ( log, "--\n// %s :\n\n", title );
+
+} // WriteMinorLabel
+
+// -------------------------------------------------------------------------------------------------
+
+static XMP_Status DumpToFile ( void * refCon, XMP_StringPtr outStr, XMP_StringLen outLen )
+{
+ XMP_Status status = 0;
+ size_t count;
+ FILE * outFile = static_cast < FILE * > ( refCon );
+
+ count = fwrite ( outStr, 1, outLen, outFile );
+ if ( count != outLen ) status = errno;
+ return status;
+
+} // DumpToFile
+
+// -------------------------------------------------------------------------------------------------
+
+static XMP_Status DumpToString ( void * refCon, XMP_StringPtr outStr, XMP_StringLen outLen )
+{
+ std::string * fullStr = static_cast < std::string * > ( refCon );
+
+ fullStr->append ( outStr, outLen );
+ return 0;
+
+} // DumpToString
+
+// -------------------------------------------------------------------------------------------------
+
+#define DumpOneFormat(fmt) \
+ format = kXMP_ ## fmt ## File; \
+ flags = 0; \
+ ok = SXMPFiles::GetFormatInfo ( format, &flags ); \
+ fprintf ( sLogFile, "kXMP_" #fmt "File = \"%.4s\", %s, flags = 0x%X\n", \
+ &format, (ok ? "smart" : "dumb"), flags );
+
+static void DumpHandlerInfo()
+{
+
+ WriteMinorLabel ( sLogFile, "Dump file format constants and handler flags" );
+
+ bool ok;
+ XMP_FileFormat format;
+ XMP_OptionBits flags;
+
+ DumpOneFormat ( PDF );
+ DumpOneFormat ( PostScript );
+ DumpOneFormat ( EPS );
+
+ DumpOneFormat ( JPEG );
+ DumpOneFormat ( JPEG2K );
+ DumpOneFormat ( TIFF );
+ DumpOneFormat ( GIF );
+ DumpOneFormat ( PNG );
+
+ DumpOneFormat ( MOV );
+ DumpOneFormat ( AVI );
+ DumpOneFormat ( CIN );
+ DumpOneFormat ( WAV );
+ DumpOneFormat ( MP3 );
+ DumpOneFormat ( SES );
+ DumpOneFormat ( CEL );
+ DumpOneFormat ( MPEG );
+ DumpOneFormat ( MPEG2 );
+ DumpOneFormat ( WMAV );
+
+ DumpOneFormat ( HTML );
+ DumpOneFormat ( XML );
+ DumpOneFormat ( Text );
+
+ DumpOneFormat ( Photoshop );
+ DumpOneFormat ( Illustrator );
+ DumpOneFormat ( InDesign );
+ DumpOneFormat ( AEProject );
+ DumpOneFormat ( AEFilterPreset );
+ DumpOneFormat ( EncoreProject );
+ DumpOneFormat ( PremiereProject );
+ DumpOneFormat ( PremiereTitle );
+
+ DumpOneFormat ( Unknown );
+
+} // DumpHandlerInfo
+
+// -------------------------------------------------------------------------------------------------
+
+static void OpenTestFile ( const char * fileName, XMP_OptionBits rwMode, SXMPMeta* xmpMeta, SXMPFiles* xmpFile )
+{
+ bool ok;
+
+ XMP_FileFormat format;
+ XMP_OptionBits openFlags, handlerFlags;
+ XMP_PacketInfo xmpPacket;
+
+ bool isUpdate = ((rwMode & kXMPFiles_OpenForUpdate) != 0);
+
+ static const char * charForms[] = { "UTF-8", "unknown char form", "UTF-16BE", "UTF-16LE", "UTF-32BE", "UTF-32LE" };
+
+ XMP_OptionBits smartFlags = rwMode | kXMPFiles_OpenUseSmartHandler | kXMPFiles_OpenCacheTNail;
+ XMP_OptionBits scanFlags = rwMode | kXMPFiles_OpenUsePacketScanning;
+
+ ok = xmpFile->OpenFile ( fileName, kXMP_UnknownFile, smartFlags );
+ if ( ! ok ) {
+ fprintf ( sLogFile, "Failed to get a smart handler\n" );
+ ok = xmpFile->OpenFile ( fileName, kXMP_UnknownFile, scanFlags );
+ if ( ! ok ) return;
+ }
+
+ ok = xmpFile->GetFileInfo ( 0, &openFlags, &format, &handlerFlags );
+ if ( ! ok ) return;
+
+ fprintf ( sLogFile, "File info : format = \"%.4s\", handler flags = 0x%X, open flags = 0x%X (%s)\n",
+ &format, handlerFlags, openFlags, (isUpdate ? "update" : "read-only") );
+
+ XMP_ThumbnailInfo tnail;
+ ok = xmpFile->GetThumbnail ( &tnail );
+ if ( ! ok ) {
+ fprintf ( sLogFile, "No thumbnail\n" );
+ } else {
+ fprintf ( sLogFile, "Thumbnail info : file format = \"%.4s\", tnail format = %d, tnail size = %d\n",
+ &tnail.fileFormat, tnail.tnailFormat, tnail.tnailSize );
+ fprintf ( sLogFile, " Image width x height, orientation : %d x %d, %d\n",
+ tnail.fullWidth, tnail.fullHeight, tnail.fullOrientation );
+ fprintf ( sLogFile, " TNail width x height, orientation : %d x %d, %d\n",
+ tnail.tnailWidth, tnail.tnailHeight, tnail.tnailOrientation );
+ }
+
+ ok = xmpFile->GetXMP ( xmpMeta, 0, &xmpPacket );
+ if ( ! ok ) {
+ fprintf ( sLogFile, "No XMP\n" );
+ return;
+ }
+
+ fprintf ( sLogFile, "XMP packet info : file offset = %lld, length = %d, pad = %d",
+ xmpPacket.offset, xmpPacket.length, xmpPacket.padSize );
+ fprintf ( sLogFile, ", %s", ((xmpPacket.charForm > 5) ? "bad char form" : charForms[xmpPacket.charForm]) );
+ fprintf ( sLogFile, ", %s\n", (xmpPacket.writeable ? "writeable" : "read-only") );
+
+ fprintf ( sLogFile, "\n" );
+
+ // Remove extaneous properties to make the dump smaller.
+ SXMPUtils::RemoveProperties ( xmpMeta, kXMP_NS_XMP, "Thumbnails", true );
+ SXMPUtils::RemoveProperties ( xmpMeta, kXMP_NS_XMP, "PageInfo", true );
+ SXMPUtils::RemoveProperties ( xmpMeta, "http://ns.adobe.com/xap/1.0/t/pg/", 0, true );
+ SXMPUtils::RemoveProperties ( xmpMeta, "http://ns.adobe.com/xap/1.0/mm/", 0, true );
+ #if 1
+ SXMPUtils::RemoveProperties ( xmpMeta, "http://ns.adobe.com/camera-raw-settings/1.0/", 0, true );
+ SXMPUtils::RemoveProperties ( xmpMeta, "http://ns.adobe.com/tiff/1.0/", 0, true );
+ SXMPUtils::RemoveProperties ( xmpMeta, "http://ns.adobe.com/exif/1.0/", 0, true );
+ SXMPUtils::RemoveProperties ( xmpMeta, "http://ns.adobe.com/exif/1.0/aux/", 0, true );
+ SXMPUtils::RemoveProperties ( xmpMeta, "http://ns.adobe.com/photoshop/1.0/", 0, true );
+ SXMPUtils::RemoveProperties ( xmpMeta, "http://ns.adobe.com/pdf/1.3/", 0, true );
+ #endif
+
+} // OpenTestFile
+
+// -------------------------------------------------------------------------------------------------
+
+#ifndef OnlyReadOnly
+ #define OnlyReadOnly 0
+#endif
+
+static void TestOneFile ( const char * fileName )
+{
+ char buffer [1000];
+ SXMPMeta xmpMeta;
+ SXMPFiles xmpFile;
+ XMP_PacketInfo xmpPacket;
+ std::string roDump, rwDump;
+
+ sprintf ( buffer, "Testing %s", fileName );
+ WriteMinorLabel ( sLogFile, buffer );
+
+ OpenTestFile ( fileName, kXMPFiles_OpenForRead, &xmpMeta, &xmpFile );
+ xmpMeta.DumpObject ( DumpToString, &roDump );
+ xmpFile.CloseFile();
+
+ if ( OnlyReadOnly ) {
+ fprintf ( sLogFile, "Initial XMP from %s\n", fileName );
+ xmpMeta.DumpObject ( DumpToFile, sLogFile );
+ return;
+ }
+
+ OpenTestFile ( fileName, kXMPFiles_OpenForUpdate, &xmpMeta, &xmpFile );
+ xmpMeta.DumpObject ( DumpToString, &rwDump );
+ if ( roDump != rwDump ) {
+ fprintf ( sLogFile, "** Initial read-only and update XMP don't match! **\n\n" );
+ fprintf ( sLogFile, "Read-only XMP\n%s\nUpdate XMP\n%s\n", roDump.c_str(), rwDump.c_str() );
+ }
+
+ fprintf ( sLogFile, "Initial XMP from %s\n", fileName );
+ xmpMeta.DumpObject ( DumpToFile, sLogFile );
+
+ XMP_DateTime now;
+ SXMPUtils::CurrentDateTime ( &now );
+ std::string nowStr;
+ SXMPUtils::ConvertFromDate ( now, &nowStr );
+ if ( xmpMeta.CountArrayItems ( kXMP_NS_XMP, "XMPFileStamps" ) >= 9 ) {
+ xmpMeta.DeleteProperty ( kXMP_NS_XMP, "XMPFileStamps" );
+ }
+ xmpMeta.AppendArrayItem ( kXMP_NS_XMP, "XMPFileStamps", kXMP_PropArrayIsOrdered, "" );
+ xmpMeta.SetProperty ( kXMP_NS_XMP, "XMPFileStamps[last()]", nowStr.c_str() );
+
+ nowStr.insert ( 0, "Updating dc:description at " );
+ xmpMeta.SetLocalizedText ( kXMP_NS_DC, "description", "", "x-default", nowStr.c_str() );
+
+ xmpFile.PutXMP ( xmpMeta );
+ XMP_OptionBits closeOptions = 0;
+ if ( (xmpMeta.CountArrayItems ( kXMP_NS_XMP, "XMPFileStamps" ) & 1) == 0 ) closeOptions |= kXMPFiles_UpdateSafely;
+ xmpFile.CloseFile ( closeOptions );
+
+ fprintf ( sLogFile, "\n" );
+ OpenTestFile ( fileName, kXMPFiles_OpenForRead, &xmpMeta, &xmpFile );
+ fprintf ( sLogFile, "Modified XMP from %s\n", fileName );
+ xmpMeta.DumpObject ( DumpToFile, sLogFile );
+ xmpFile.CloseFile();
+
+ fprintf ( sLogFile, "\nDone testing %s\n", fileName );
+
+} // TestOneFile
+
+// -------------------------------------------------------------------------------------------------
+
+extern "C" int main ( int argc, const char * argv[] )
+{
+ int result = 0;
+
+ char logName[256];
+ int nameLen = strlen ( argv[0] );
+ if ( (nameLen >= 4) && (strcmp ( argv[0]+nameLen-4, ".exe" ) == 0) ) nameLen -= 4;
+ memcpy ( logName, argv[0], nameLen );
+ memcpy ( &logName[nameLen], "Log.txt", 8 ); // Include final null.
+ sLogFile = fopen ( logName, "wb" );
+
+ time_t now = time(0);
+ fprintf ( sLogFile, "XMPFilesCoverage starting %s", ctime(&now) );
+
+ XMP_VersionInfo coreVersion, filesVersion;
+ SXMPMeta::GetVersionInfo ( &coreVersion );
+ SXMPFiles::GetVersionInfo ( &filesVersion );
+ fprintf ( sLogFile, "Version :\n %s\n %s\n", coreVersion.message, filesVersion.message );
+
+ try {
+
+ if ( ! SXMPMeta::Initialize() ) {
+ fprintf ( sLogFile, "## XMPMeta::Initialize failed!\n" );
+ return -1;
+ }
+ if ( ! SXMPFiles::Initialize() ) {
+ fprintf ( sLogFile, "## SXMPFiles::Initialize failed!\n" );
+ return -1;
+ }
+
+ DumpHandlerInfo();
+
+ TestOneFile ( "BlueSquares/BlueSquare.ai" );
+ TestOneFile ( "BlueSquares/BlueSquare.eps" );
+ TestOneFile ( "BlueSquares/BlueSquare.indd" );
+ TestOneFile ( "BlueSquares/BlueSquare.jpg" );
+ TestOneFile ( "BlueSquares/BlueSquare.pdf" );
+ TestOneFile ( "BlueSquares/BlueSquare.psd" );
+ TestOneFile ( "BlueSquares/BlueSquare.tif" );
+ TestOneFile ( "BlueSquares/BlueSquare.avi" );
+ TestOneFile ( "BlueSquares/BlueSquare.mov" );
+ TestOneFile ( "BlueSquares/BlueSquare.mp3" );
+ TestOneFile ( "BlueSquares/BlueSquare.wav" );
+ TestOneFile ( "BlueSquares/BlueSquare.png" );
+
+ } catch ( XMP_Error & excep ) {
+
+ fprintf ( sLogFile, "\nCaught XMP_Error %d : %s\n", excep.GetID(), excep.GetErrMsg() );
+ result = -2;
+
+ } catch ( ... ) {
+
+ fprintf ( sLogFile, "## Caught unknown exception\n" );
+ result = -3;
+
+ }
+
+ SXMPFiles::Terminate();
+ SXMPMeta::Terminate();
+
+ now = time(0);
+ fprintf ( sLogFile, "\nXMPFilesCoverage finished %s", ctime(&now) );
+ fprintf ( sLogFile, "Final status = %d\n", result );
+ fclose ( sLogFile );
+ return result;
+
+} // main
diff --git a/samples/source/XMPScanner.cpp b/samples/source/XMPScanner.cpp
new file mode 100644
index 0000000..6527b0e
--- /dev/null
+++ b/samples/source/XMPScanner.cpp
@@ -0,0 +1,1470 @@
+// =================================================================================================
+// Copyright 2002-2006 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+//
+// Adobe patent application tracking #P435, entitled 'Unique markers to simplify embedding data of
+// one format in a file with a different format', inventors: Sean Parent, Greg Gilley.
+// =================================================================================================
+
+#if WIN_ENV
+ #pragma warning ( disable : 4127 ) // conditional expression is constant
+ #pragma warning ( disable : 4702 ) // unreachable code
+ #pragma warning ( disable : 4786 ) // The VC++ debugger can't handle long symbol names.
+#endif
+
+
+#include "XMPScanner.hpp"
+
+#include <cassert>
+#include <string>
+#include <iostream>
+#include <iomanip>
+#include <fstream>
+#include <cstdlib>
+
+
+#ifndef UseStringPushBack // VC++ 6.x does not provide push_back for strings!
+ #define UseStringPushBack 0
+#endif
+
+
+using namespace std;
+
+
+// *** Consider Boyer-Moore style search for "<?xpacket begin=". It isn't an obvious win, the
+// *** additional code might be slower than scanning every character. Especially if we will
+// *** read every cache line anyway.
+
+
+// =================================================================================================
+// =================================================================================================
+// class PacketMachine
+// ===================
+//
+// This is the packet recognizer state machine. The top of the machine is FindNextPacket, this
+// calls the specific state components and handles transitions. The states are described by an
+// array of RecognizerInfo records, indexed by the RecognizerKind enumeration. Each RecognizerInfo
+// record has a function that does that state's work, the success and failure transition states,
+// and a string literal that is passed to the state function. The literal lets a common MatchChar
+// or MatchString function be used in several places.
+//
+// The state functions are responsible for consuming input to recognize their particular state.
+// This includes intervening nulls for 16 and 32 bit character forms. For the simplicity, things
+// are treated as essentially little endian and the nulls are not actually checked. The opening
+// '<' is found with a byte-by-byte search, then the number of bytes per character is determined
+// by counting the following nulls. From then on, consuming a character means incrementing the
+// buffer pointer by the number of bytes per character. Thus the buffer pointer only points to
+// the "real" bytes. This also means that the pointer can go off the end of the buffer by a
+// variable amount. The amount of overrun is saved so that the pointer can be positioned at the
+// right byte to start the next buffer.
+//
+// The state functions return a TriState value, eTriYes means the pattern was found, eTriNo means
+// the pattern was definitely not found, eTriMaybe means that the end of the buffer was reached
+// while working through the pattern.
+//
+// When eTriYes is returned, the fBufferPtr data member is left pointing to the "real" byte
+// following the last actual byte. Which might not be addressable memory! This also means that
+// a state function can be entered with nothing available in the buffer. When eTriNo is returned,
+// the fBufferPtr data member is left pointing to the byte that caused the failure. The state
+// machine starts over from the failure byte.
+//
+// The state functions must preserve their internal micro-state before returning eTriMaybe, and
+// resume processing when called with the next buffer. The fPosition data member is used to denote
+// how many actual characters have been consumed. The fNullCount data member is used to denote how
+// many nulls are left before the next actual character.
+
+
+// =================================================================================================
+// PacketMachine
+// =============
+
+XMPScanner::PacketMachine::PacketMachine ( SInt64 bufferOffset, const void * bufferOrigin, SInt64 bufferLength ) :
+
+ // Public members
+ fPacketStart ( 0 ),
+ fPacketLength ( 0 ),
+ fBytesAttr ( -1 ),
+ fCharForm ( eChar8Bit ),
+ fAccess ( ' ' ),
+ fBogusPacket ( false ),
+
+ // Private members
+ fBufferOffset ( bufferOffset ),
+ fBufferOrigin ( (const char *) bufferOrigin ),
+ fBufferPtr ( fBufferOrigin ),
+ fBufferLimit ( fBufferOrigin + bufferLength ),
+ fRecognizer ( eLeadInRecognizer ),
+ fPosition ( 0 ),
+ fBytesPerChar ( 1 ),
+ fBufferOverrun ( 0 ),
+ fQuoteChar ( ' ' )
+
+{
+ /*
+ REVIEW NOTES : Should the buffer stuff be in a class?
+ */
+
+ assert ( bufferOrigin != NULL );
+ assert ( bufferLength != 0 );
+
+} // PacketMachine
+
+
+// =================================================================================================
+// ~PacketMachine
+// ==============
+
+XMPScanner::PacketMachine::~PacketMachine ()
+{
+
+ // An empty placeholder.
+
+} // ~PacketMachine
+
+
+// =================================================================================================
+// AssociateBuffer
+// ===============
+
+void
+XMPScanner::PacketMachine::AssociateBuffer ( SInt64 bufferOffset, const void * bufferOrigin, SInt64 bufferLength )
+{
+
+ fBufferOffset = bufferOffset;
+ fBufferOrigin = (const char *) bufferOrigin;
+ fBufferPtr = fBufferOrigin + fBufferOverrun;
+ fBufferLimit = fBufferOrigin + bufferLength;
+
+} // AssociateBuffer
+
+
+// =================================================================================================
+// ResetMachine
+// ============
+
+void
+XMPScanner::PacketMachine::ResetMachine ()
+{
+
+ fRecognizer = eLeadInRecognizer;
+ fPosition = 0;
+ fBufferOverrun = 0;
+ fCharForm = eChar8Bit;
+ fBytesPerChar = 1;
+ fAccess = ' ';
+ fBytesAttr = -1;
+ fBogusPacket = false;
+
+ fAttrName.erase ( fAttrName.begin(), fAttrName.end() );
+ fAttrValue.erase ( fAttrValue.begin(), fAttrValue.end() );
+ fEncodingAttr.erase ( fEncodingAttr.begin(), fEncodingAttr.end() );
+
+} // ResetMachine
+
+
+// =================================================================================================
+// FindLessThan
+// ============
+
+XMPScanner::PacketMachine::TriState
+XMPScanner::PacketMachine::FindLessThan ( PacketMachine * ths, const char * which )
+{
+
+ if ( *which == 'H' ) {
+
+ // --------------------------------------------------------------------------------
+ // We're looking for the '<' of the header. If we fail there is no packet in this
+ // part of the input, so return eTriNo.
+
+ ths->fCharForm = eChar8Bit; // We might have just failed from a bogus 16 or 32 bit case.
+ ths->fBytesPerChar = 1;
+
+ while ( ths->fBufferPtr < ths->fBufferLimit ) { // Don't skip nulls for the header's '<'!
+ if ( *ths->fBufferPtr == '<' ) break;
+ ths->fBufferPtr++;
+ }
+
+ if ( ths->fBufferPtr >= ths->fBufferLimit ) return eTriNo;
+ ths->fBufferPtr++;
+ return eTriYes;
+
+ } else {
+
+ // --------------------------------------------------------------------------------
+ // We're looking for the '<' of the trailer. We're already inside the packet body,
+ // looking for the trailer. So here if we fail we must return eTriMaybe so that we
+ // keep looking for the trailer in the next buffer.
+
+ const int bytesPerChar = ths->fBytesPerChar;
+
+ while ( ths->fBufferPtr < ths->fBufferLimit ) {
+ if ( *ths->fBufferPtr == '<' ) break;
+ ths->fBufferPtr += bytesPerChar;
+ }
+
+ if ( ths->fBufferPtr >= ths->fBufferLimit ) return eTriMaybe;
+ ths->fBufferPtr += bytesPerChar;
+ return eTriYes;
+
+ }
+
+} // FindLessThan
+
+
+// =================================================================================================
+// MatchString
+// ===========
+
+XMPScanner::PacketMachine::TriState
+XMPScanner::PacketMachine::MatchString ( PacketMachine * ths, const char * literal )
+{
+ const int bytesPerChar = ths->fBytesPerChar;
+ const char * litPtr = literal + ths->fPosition;
+ const int charsToGo = strlen ( literal ) - ths->fPosition;
+ int charsDone = 0;
+
+ while ( (charsDone < charsToGo) && (ths->fBufferPtr < ths->fBufferLimit) ) {
+ if ( *litPtr != *ths->fBufferPtr ) return eTriNo;
+ charsDone++;
+ litPtr++;
+ ths->fBufferPtr += bytesPerChar;
+ }
+
+ if ( charsDone == charsToGo ) return eTriYes;
+ ths->fPosition += charsDone;
+ return eTriMaybe;
+
+} // MatchString
+
+
+// =================================================================================================
+// MatchChar
+// =========
+
+XMPScanner::PacketMachine::TriState
+XMPScanner::PacketMachine::MatchChar ( PacketMachine * ths, const char * literal )
+{
+ const int bytesPerChar = ths->fBytesPerChar;
+
+ if ( ths->fBufferPtr >= ths->fBufferLimit ) return eTriMaybe;
+
+ const char currChar = *ths->fBufferPtr;
+ if ( currChar != *literal ) return eTriNo;
+ ths->fBufferPtr += bytesPerChar;
+ return eTriYes;
+
+} // MatchChar
+
+
+// =================================================================================================
+// MatchOpenQuote
+// ==============
+
+XMPScanner::PacketMachine::TriState
+XMPScanner::PacketMachine::MatchOpenQuote ( PacketMachine * ths, const char * /* unused */ )
+{
+ const int bytesPerChar = ths->fBytesPerChar;
+
+ if ( ths->fBufferPtr >= ths->fBufferLimit ) return eTriMaybe;
+
+ const char currChar = *ths->fBufferPtr;
+ if ( (currChar != '\'') && (currChar != '"') ) return eTriNo;
+ ths->fQuoteChar = currChar;
+ ths->fBufferPtr += bytesPerChar;
+ return eTriYes;
+
+} // MatchOpenQuote
+
+
+// =================================================================================================
+// MatchCloseQuote
+// ===============
+
+XMPScanner::PacketMachine::TriState
+XMPScanner::PacketMachine::MatchCloseQuote ( PacketMachine * ths, const char * /* unused */ )
+{
+
+ return MatchChar ( ths, &ths->fQuoteChar );
+
+} // MatchCloseQuote
+
+
+// =================================================================================================
+// CaptureAttrName
+// ===============
+
+XMPScanner::PacketMachine::TriState
+XMPScanner::PacketMachine::CaptureAttrName ( PacketMachine * ths, const char * /* unused */ )
+{
+ const int bytesPerChar = ths->fBytesPerChar;
+ char currChar;
+
+ if ( ths->fPosition == 0 ) { // Get the first character in the name.
+
+ if ( ths->fBufferPtr >= ths->fBufferLimit ) return eTriMaybe;
+
+ currChar = *ths->fBufferPtr;
+ if ( ths->fAttrName.size() == 0 ) {
+ if ( ! ( ( ('a' <= currChar) && (currChar <= 'z') ) ||
+ ( ('A' <= currChar) && (currChar <= 'Z') ) ||
+ (currChar == '_') || (currChar == ':') ) ) {
+ return eTriNo;
+ }
+ }
+
+ ths->fAttrName.erase ( ths->fAttrName.begin(), ths->fAttrName.end() );
+ #if UseStringPushBack
+ ths->fAttrName.push_back ( currChar );
+ #else
+ ths->fAttrName.insert ( ths->fAttrName.end(), currChar );
+ #endif
+ ths->fBufferPtr += bytesPerChar;
+
+ }
+
+ while ( ths->fBufferPtr < ths->fBufferLimit ) { // Get the remainder of the name.
+
+ currChar = *ths->fBufferPtr;
+ if ( ! ( ( ('a' <= currChar) && (currChar <= 'z') ) ||
+ ( ('A' <= currChar) && (currChar <= 'Z') ) ||
+ ( ('0' <= currChar) && (currChar <= '9') ) ||
+ (currChar == '-') || (currChar == '.') || (currChar == '_') || (currChar == ':') ) ) {
+ break;
+ }
+
+ #if UseStringPushBack
+ ths->fAttrName.push_back ( currChar );
+ #else
+ ths->fAttrName.insert ( ths->fAttrName.end(), currChar );
+ #endif
+ ths->fBufferPtr += bytesPerChar;
+
+ }
+
+ if ( ths->fBufferPtr < ths->fBufferLimit ) return eTriYes;
+ ths->fPosition = ths->fAttrName.size(); // The name might span into the next buffer.
+ return eTriMaybe;
+
+} // CaptureAttrName
+
+
+// =================================================================================================
+// CaptureAttrValue
+// ================
+//
+// Recognize the equal sign and the quoted string value, capture the value along the way.
+
+XMPScanner::PacketMachine::TriState
+XMPScanner::PacketMachine::CaptureAttrValue ( PacketMachine * ths, const char * /* unused */ )
+{
+ const int bytesPerChar = ths->fBytesPerChar;
+ char currChar = 0;
+ TriState result = eTriMaybe;
+
+ if ( ths->fBufferPtr >= ths->fBufferLimit ) return eTriMaybe;
+
+ switch ( ths->fPosition ) {
+
+ case 0 : // The name should haved ended at the '=', nulls already skipped.
+
+ if ( ths->fBufferPtr >= ths->fBufferLimit ) return eTriMaybe;
+ if ( *ths->fBufferPtr != '=' ) return eTriNo;
+ ths->fBufferPtr += bytesPerChar;
+ ths->fPosition = 1;
+ // fall through OK because MatchOpenQuote will check the buffer limit and nulls ...
+
+ case 1 : // Look for the open quote.
+
+ result = MatchOpenQuote ( ths, NULL );
+ if ( result != eTriYes ) return result;
+ ths->fPosition = 2;
+ // fall through OK because the buffer limit and nulls are checked below ...
+
+ default : // Look for the close quote, capturing the value along the way.
+
+ assert ( ths->fPosition == 2 );
+
+ const char quoteChar = ths->fQuoteChar;
+
+ while ( ths->fBufferPtr < ths->fBufferLimit ) {
+ currChar = *ths->fBufferPtr;
+ if ( currChar == quoteChar ) break;
+ #if UseStringPushBack
+ ths->fAttrValue.push_back ( currChar );
+ #else
+ ths->fAttrValue.insert ( ths->fAttrValue.end(), currChar );
+ #endif
+ ths->fBufferPtr += bytesPerChar;
+ }
+
+ if ( ths->fBufferPtr >= ths->fBufferLimit ) return eTriMaybe;
+ assert ( currChar == quoteChar );
+ ths->fBufferPtr += bytesPerChar; // Advance past the closing quote.
+ return eTriYes;
+
+ }
+
+} // CaptureAttrValue
+
+
+// =================================================================================================
+// RecordStart
+// ===========
+//
+// Note that this routine looks at bytes, not logical characters. It has to figure out how many
+// bytes per character there are so that the other recognizers can skip intervening nulls.
+
+XMPScanner::PacketMachine::TriState
+XMPScanner::PacketMachine::RecordStart ( PacketMachine * ths, const char * /* unused */ )
+{
+
+ while ( true ) {
+
+ if ( ths->fBufferPtr >= ths->fBufferLimit ) return eTriMaybe;
+
+ const char currByte = *ths->fBufferPtr;
+
+ switch ( ths->fPosition ) {
+
+ case 0 : // Record the length.
+ assert ( ths->fCharForm == eChar8Bit );
+ assert ( ths->fBytesPerChar == 1 );
+ ths->fPacketStart = ths->fBufferOffset + ((ths->fBufferPtr - 1) - ths->fBufferOrigin);
+ ths->fPacketLength = 0;
+ ths->fPosition = 1;
+ // ! OK to fall through here, we didn't consume a byte in this step.
+
+ case 1 : // Look for the first null byte.
+ if ( currByte != 0 ) return eTriYes; // No nulls found.
+ ths->fCharForm = eChar16BitBig; // Assume 16 bit big endian for now.
+ ths->fBytesPerChar = 2;
+ ths->fBufferPtr++;
+ ths->fPosition = 2;
+ break; // ! Don't fall through, have to check for the end of the buffer between each byte.
+
+ case 2 : // One null was found, look for a second.
+ if ( currByte != 0 ) return eTriYes; // Just one null found.
+ ths->fBufferPtr++;
+ ths->fPosition = 3;
+ break;
+
+ case 3 : // Two nulls were found, look for a third.
+ if ( currByte != 0 ) return eTriNo; // Just two nulls is not valid.
+ ths->fCharForm = eChar32BitBig; // Assume 32 bit big endian for now.
+ ths->fBytesPerChar = 4;
+ ths->fBufferPtr++;
+ return eTriYes;
+ break;
+
+ }
+
+ }
+
+} // RecordStart
+
+
+// =================================================================================================
+// RecognizeBOM
+// ============
+//
+// Recognizing the byte order marker is a surprisingly messy thing to do. It can't be done by the
+// normal string matcher, there are no intervening nulls. There are 4 transitions after the opening
+// quote, the closing quote or one of the three encodings. For the actual BOM there are then 1 or 2
+// following bytes that depend on which of the encodings we're in. Not to mention that the buffer
+// might end at any point.
+//
+// The intervening null count done earlier determined 8, 16, or 32 bits per character, but not the
+// big or little endian nature for the 16/32 bit cases. The BOM must be present for the 16 and 32
+// bit cases in order to determine the endian mode. There are six possible byte sequences for the
+// quoted BOM string, ignoring the differences for quoting with ''' versus '"'.
+//
+// Keep in mind that for the 16 and 32 bit cases there will be nulls for the quote. In the table
+// below the symbol <quote> means just the one byte containing the ''' or '"'. The nulls for the
+// quote character are explicitly shown.
+//
+// <quote> <quote> - 1: No BOM, this must be an 8 bit case.
+// <quote> \xEF \xBB \xBF <quote> - 1.12-13: The 8 bit form.
+//
+// <quote> \xFE \xFF \x00 <quote> - 1.22-23: The 16 bit, big endian form
+// <quote> \x00 \xFF \xFE <quote> - 1.32-33: The 16 bit, little endian form.
+//
+// <quote> \x00 \x00 \xFE \xFF \x00 \x00 \x00 <quote> - 1.32.43-45.56-57: The 32 bit, big endian form.
+// <quote> \x00 \x00 \x00 \xFF \xFE \x00 \x00 <quote> - 1.32.43.54-57: The 32 bit, little endian form.
+
+enum {
+ eBOM_8_1 = 0xEF,
+ eBOM_8_2 = 0xBB,
+ eBOM_8_3 = 0xBF,
+ eBOM_Big_1 = 0xFE,
+ eBOM_Big_2 = 0xFF,
+ eBOM_Little_1 = eBOM_Big_2,
+ eBOM_Little_2 = eBOM_Big_1
+};
+
+XMPScanner::PacketMachine::TriState
+XMPScanner::PacketMachine::RecognizeBOM ( PacketMachine * ths, const char * /* unused */ )
+{
+ const int bytesPerChar = ths->fBytesPerChar;
+
+ while ( true ) { // Handle one character at a time, the micro-state (fPosition) changes for each.
+
+ if ( ths->fBufferPtr >= ths->fBufferLimit ) return eTriMaybe;
+
+ const unsigned char currChar = *ths->fBufferPtr; // ! The BOM bytes look like integers bigger than 127.
+
+ switch ( ths->fPosition ) {
+
+ case 0 : // Look for the opening quote.
+ if ( (currChar != '\'') && (currChar != '"') ) return eTriNo;
+ ths->fQuoteChar = currChar;
+ ths->fBufferPtr++;
+ ths->fPosition = 1;
+ break; // ! Don't fall through, have to check for the end of the buffer between each byte.
+
+ case 1 : // Look at the byte immediately following the opening quote.
+ if ( currChar == ths->fQuoteChar ) { // Closing quote, no BOM character, must be 8 bit.
+ if ( ths->fCharForm != eChar8Bit ) return eTriNo;
+ ths->fBufferPtr += bytesPerChar; // Skip the nulls after the closing quote.
+ return eTriYes;
+ } else if ( currChar == eBOM_8_1 ) { // Start of the 8 bit form.
+ if ( ths->fCharForm != eChar8Bit ) return eTriNo;
+ ths->fBufferPtr++;
+ ths->fPosition = 12;
+ } else if ( currChar == eBOM_Big_1 ) { // Start of the 16 bit big endian form.
+ if ( ths->fCharForm != eChar16BitBig ) return eTriNo;
+ ths->fBufferPtr++;
+ ths->fPosition = 22;
+ } else if ( currChar == 0 ) { // Start of the 16 bit little endian or either 32 bit form.
+ if ( ths->fCharForm == eChar8Bit ) return eTriNo;
+ ths->fBufferPtr++;
+ ths->fPosition = 32;
+ } else {
+ return eTriNo;
+ }
+ break;
+
+ case 12 : // Look for the second byte of the 8 bit form.
+ if ( currChar != eBOM_8_2 ) return eTriNo;
+ ths->fPosition = 13;
+ ths->fBufferPtr++;
+ break;
+
+ case 13 : // Look for the third byte of the 8 bit form.
+ if ( currChar != eBOM_8_3 ) return eTriNo;
+ ths->fPosition = 99;
+ ths->fBufferPtr++;
+ break;
+
+ case 22 : // Look for the second byte of the 16 bit big endian form.
+ if ( currChar != eBOM_Big_2 ) return eTriNo;
+ ths->fPosition = 23;
+ ths->fBufferPtr++;
+ break;
+
+ case 23 : // Look for the null before the closing quote of the 16 bit big endian form.
+ if ( currChar != 0 ) return eTriNo;
+ ths->fBufferPtr++;
+ ths->fPosition = 99;
+ break;
+
+ case 32 : // Look at the second byte of the 16 bit little endian or either 32 bit form.
+ if ( currChar == eBOM_Little_1 ) {
+ ths->fPosition = 33;
+ } else if ( currChar == 0 ) {
+ ths->fPosition = 43;
+ } else {
+ return eTriNo;
+ }
+ ths->fBufferPtr++;
+ break;
+
+ case 33 : // Look for the third byte of the 16 bit little endian form.
+ if ( ths->fCharForm != eChar16BitBig ) return eTriNo; // Null count before assumed big endian.
+ if ( currChar != eBOM_Little_2 ) return eTriNo;
+ ths->fCharForm = eChar16BitLittle;
+ ths->fPosition = 99;
+ ths->fBufferPtr++;
+ break;
+
+ case 43 : // Look at the third byte of either 32 bit form.
+ if ( ths->fCharForm != eChar32BitBig ) return eTriNo; // Null count before assumed big endian.
+ if ( currChar == eBOM_Big_1 ) {
+ ths->fPosition = 44;
+ } else if ( currChar == 0 ) {
+ ths->fPosition = 54;
+ } else {
+ return eTriNo;
+ }
+ ths->fBufferPtr++;
+ break;
+
+ case 44 : // Look for the fourth byte of the 32 bit big endian form.
+ if ( currChar != eBOM_Big_2 ) return eTriNo;
+ ths->fPosition = 45;
+ ths->fBufferPtr++;
+ break;
+
+ case 45 : // Look for the first null before the closing quote of the 32 bit big endian form.
+ if ( currChar != 0 ) return eTriNo;
+ ths->fPosition = 56;
+ ths->fBufferPtr++;
+ break;
+
+ case 54 : // Look for the fourth byte of the 32 bit little endian form.
+ ths->fCharForm = eChar32BitLittle;
+ if ( currChar != eBOM_Little_1 ) return eTriNo;
+ ths->fPosition = 55;
+ ths->fBufferPtr++;
+ break;
+
+ case 55 : // Look for the fifth byte of the 32 bit little endian form.
+ if ( currChar != eBOM_Little_2 ) return eTriNo;
+ ths->fPosition = 56;
+ ths->fBufferPtr++;
+ break;
+
+ case 56 : // Look for the next to last null before the closing quote of the 32 bit forms.
+ if ( currChar != 0 ) return eTriNo;
+ ths->fPosition = 57;
+ ths->fBufferPtr++;
+ break;
+
+ case 57 : // Look for the last null before the closing quote of the 32 bit forms.
+ if ( currChar != 0 ) return eTriNo;
+ ths->fPosition = 99;
+ ths->fBufferPtr++;
+ break;
+
+ default : // Look for the closing quote.
+ assert ( ths->fPosition == 99 );
+ if ( currChar != ths->fQuoteChar ) return eTriNo;
+ ths->fBufferPtr += bytesPerChar; // Skip the nulls after the closing quote.
+ return eTriYes;
+ break;
+
+ }
+
+ }
+
+} // RecognizeBOM
+
+
+// =================================================================================================
+// RecordHeadAttr
+// ==============
+
+XMPScanner::PacketMachine::TriState
+XMPScanner::PacketMachine::RecordHeadAttr ( PacketMachine * ths, const char * /* unused */ )
+{
+
+ if ( ths->fAttrName == "encoding" ) {
+
+ assert ( ths->fEncodingAttr.empty() );
+ ths->fEncodingAttr = ths->fAttrValue;
+
+ } else if ( ths->fAttrName == "bytes" ) {
+
+ long value = 0;
+ int count = ths->fAttrValue.size();
+ int i;
+
+ assert ( ths->fBytesAttr == -1 );
+
+ if ( count > 0 ) { // Allow bytes='' to be the same as no bytes attribute.
+
+ for ( i = 0; i < count; i++ ) {
+ const char currChar = ths->fAttrValue[i];
+ if ( ('0' <= currChar) && (currChar <= '9') ) {
+ value = (value * 10) + (currChar - '0');
+ } else {
+ ths->fBogusPacket = true;
+ value = -1;
+ break;
+ }
+ }
+ ths->fBytesAttr = value;
+
+ if ( CharFormIs16Bit ( ths->fCharForm ) ) {
+ if ( (ths->fBytesAttr & 1) != 0 ) ths->fBogusPacket = true;
+ } else if ( CharFormIs32Bit ( ths->fCharForm ) ) {
+ if ( (ths->fBytesAttr & 3) != 0 ) ths->fBogusPacket = true;
+ }
+
+ }
+
+ }
+
+ ths->fAttrName.erase ( ths->fAttrName.begin(), ths->fAttrName.end() );
+ ths->fAttrValue.erase ( ths->fAttrValue.begin(), ths->fAttrValue.end() );
+
+ return eTriYes;
+
+} // RecordHeadAttr
+
+
+// =================================================================================================
+// CaptureAccess
+// =============
+
+XMPScanner::PacketMachine::TriState
+XMPScanner::PacketMachine::CaptureAccess ( PacketMachine * ths, const char * /* unused */ )
+{
+ const int bytesPerChar = ths->fBytesPerChar;
+
+ while ( true ) {
+
+ if ( ths->fBufferPtr >= ths->fBufferLimit ) return eTriMaybe;
+
+ const char currChar = *ths->fBufferPtr;
+
+ switch ( ths->fPosition ) {
+
+ case 0 : // Look for the opening quote.
+ if ( (currChar != '\'') && (currChar != '"') ) return eTriNo;
+ ths->fQuoteChar = currChar;
+ ths->fBufferPtr += bytesPerChar;
+ ths->fPosition = 1;
+ break; // ! Don't fall through, have to check for the end of the buffer between each byte.
+
+ case 1 : // Look for the 'r' or 'w'.
+ if ( (currChar != 'r') && (currChar != 'w') ) return eTriNo;
+ ths->fAccess = currChar;
+ ths->fBufferPtr += bytesPerChar;
+ ths->fPosition = 2;
+ break;
+
+ default : // Look for the closing quote.
+ assert ( ths->fPosition == 2 );
+ if ( currChar != ths->fQuoteChar ) return eTriNo;
+ ths->fBufferPtr += bytesPerChar;
+ return eTriYes;
+ break;
+
+ }
+
+ }
+
+} // CaptureAccess
+
+
+// =================================================================================================
+// RecordTailAttr
+// ==============
+
+XMPScanner::PacketMachine::TriState
+XMPScanner::PacketMachine::RecordTailAttr ( PacketMachine * ths, const char * /* unused */ )
+{
+
+ // There are no known "general" attributes for the packet trailer.
+
+ ths->fAttrName.erase ( ths->fAttrName.begin(), ths->fAttrName.end() );
+ ths->fAttrValue.erase ( ths->fAttrValue.begin(), ths->fAttrValue.end() );
+
+ return eTriYes;
+
+
+} // RecordTailAttr
+
+
+// =================================================================================================
+// CheckPacketEnd
+// ==============
+//
+// Check for trailing padding and record the packet length. We have trailing padding if the bytes
+// attribute is present and has a value greater than the current length.
+
+XMPScanner::PacketMachine::TriState
+XMPScanner::PacketMachine::CheckPacketEnd ( PacketMachine * ths, const char * /* unused */ )
+{
+ const int bytesPerChar = ths->fBytesPerChar;
+
+ if ( ths->fPosition == 0 ) { // First call, decide if there is trailing padding.
+
+ const SInt64 currLength = (ths->fBufferOffset + (ths->fBufferPtr - ths->fBufferOrigin)) - ths->fPacketStart;
+
+ if ( (ths->fBytesAttr != -1) && (ths->fBytesAttr != currLength) ) {
+ if ( ths->fBytesAttr < currLength ) {
+ ths->fBogusPacket = true; // The bytes attribute value is too small.
+ } else {
+ ths->fPosition = (signed long)(ths->fBytesAttr - currLength);
+ if ( (ths->fPosition % ths->fBytesPerChar) != 0 ) {
+ ths->fBogusPacket = true; // The padding is not a multiple of the character size.
+ ths->fPosition = (ths->fPosition / ths->fBytesPerChar) * ths->fBytesPerChar;
+ }
+ }
+ }
+
+ }
+
+ while ( ths->fPosition > 0 ) {
+
+ if ( ths->fBufferPtr >= ths->fBufferLimit ) return eTriMaybe;
+
+ const char currChar = *ths->fBufferPtr;
+
+ if ( (currChar != ' ') && (currChar != '\t') && (currChar != '\n') && (currChar != '\r') ) {
+ ths->fBogusPacket = true; // The padding is not whitespace.
+ break; // Stop the packet here.
+ }
+
+ ths->fPosition -= bytesPerChar;
+ ths->fBufferPtr += bytesPerChar;
+
+ }
+
+ ths->fPacketLength = (ths->fBufferOffset + (ths->fBufferPtr - ths->fBufferOrigin)) - ths->fPacketStart;
+ return eTriYes;
+
+} // CheckPacketEnd
+
+
+// =================================================================================================
+// CheckFinalNulls
+// ===============
+//
+// Do some special case processing for little endian characters. We have to make sure the presumed
+// nulls after the last character actually exist, i.e. that the stream does not end too soon. Note
+// that the prior character scanning has moved the buffer pointer to the address following the last
+// byte of the last character. I.e. we're already past the presumed nulls, so we can't check their
+// content. All we can do is verify that the stream does not end too soon.
+//
+// Doing this check is simple yet subtle. If we're still in the current buffer then the trailing
+// bytes obviously exist. If we're exactly at the end of the buffer then the bytes also exist.
+// The only question is when we're actually past this buffer, partly into the next buffer. This is
+// when "ths->fBufferPtr > ths->fBufferLimit" on entry. For that case we have to wait until we've
+// actually seen enough extra bytes of input.
+//
+// Since the normal buffer processing is already adjusting for this partial character overrun, all
+// that needs to be done here is wait until "ths->fBufferPtr <= ths->fBufferLimit" on entry. In
+// other words, if we're presently too far, ths->fBufferPtr will be adjusted by the amount of the
+// overflow the next time XMPScanner::Scan is called. This might still be too far, so just keep
+// waiting for enough data to pass by.
+//
+// Note that there is a corresponding special case for big endian characters, we must decrement the
+// starting offset by the number of leading nulls. But we don't do that here, we leave it to the
+// outer code. This is because the leading nulls might have been at the exact end of a previous
+// buffer, in which case we have to also decrement the length of that raw data snip.
+
+XMPScanner::PacketMachine::TriState
+XMPScanner::PacketMachine::CheckFinalNulls ( PacketMachine * ths, const char * /* unused */ )
+{
+
+ if ( (ths->fCharForm != eChar8Bit) && CharFormIsLittleEndian ( ths->fCharForm ) ) {
+ if ( ths->fBufferPtr > ths->fBufferLimit ) return eTriMaybe;
+ }
+
+ return eTriYes;
+
+} // CheckFinalNulls
+
+
+// =================================================================================================
+// SetNextRecognizer
+// =================
+
+void
+XMPScanner::PacketMachine::SetNextRecognizer ( RecognizerKind nextRecognizer )
+{
+
+ fRecognizer = nextRecognizer;
+ fPosition = 0;
+
+} // SetNextRecognizer
+
+
+// =================================================================================================
+// FindNextPacket
+// ==============
+
+// *** When we start validating intervening nulls for 2 and 4 bytes characters, throw an exception
+// *** for errors. Don't return eTriNo, that might skip at an optional point.
+
+XMPScanner::PacketMachine::TriState
+XMPScanner::PacketMachine::FindNextPacket ()
+{
+
+ TriState status;
+
+ #define kPacketHead "?xpacket begin="
+ #define kPacketID "W5M0MpCehiHzreSzNTczkc9d"
+ #define kPacketTail "?xpacket end="
+
+ static const RecognizerInfo recognizerTable [eRecognizerCount] = { // ! Would be safer to assign these explicitly.
+
+ // proc successNext failureNext literal
+
+ { NULL, eFailureRecognizer, eFailureRecognizer, NULL}, // eFailureRecognizer
+ { NULL, eSuccessRecognizer, eSuccessRecognizer, NULL}, // eSuccessRecognizer
+
+ { FindLessThan, eHeadStartRecorder, eFailureRecognizer, "H" }, // eLeadInRecognizer
+ { RecordStart, eHeadStartRecognizer, eLeadInRecognizer, NULL }, // eHeadStartRecorder
+ { MatchString, eBOMRecognizer, eLeadInRecognizer, kPacketHead }, // eHeadStartRecognizer
+
+ { RecognizeBOM, eIDTagRecognizer, eLeadInRecognizer, NULL }, // eBOMRecognizer
+
+ { MatchString, eIDOpenRecognizer, eLeadInRecognizer, " id=" }, // eIDTagRecognizer
+ { MatchOpenQuote, eIDValueRecognizer, eLeadInRecognizer, NULL }, // eIDOpenRecognizer
+ { MatchString, eIDCloseRecognizer, eLeadInRecognizer, kPacketID }, // eIDValueRecognizer
+ { MatchCloseQuote, eAttrSpaceRecognizer_1, eLeadInRecognizer, NULL }, // eIDCloseRecognizer
+
+ { MatchChar, eAttrNameRecognizer_1, eHeadEndRecognizer, " " }, // eAttrSpaceRecognizer_1
+ { CaptureAttrName, eAttrValueRecognizer_1, eLeadInRecognizer, NULL }, // eAttrNameRecognizer_1
+ { CaptureAttrValue, eAttrValueRecorder_1, eLeadInRecognizer, NULL }, // eAttrValueRecognizer_1
+ { RecordHeadAttr, eAttrSpaceRecognizer_1, eLeadInRecognizer, NULL }, // eAttrValueRecorder_1
+
+ { MatchString, eBodyRecognizer, eLeadInRecognizer, "?>" }, // eHeadEndRecognizer
+
+ { FindLessThan, eTailStartRecognizer, eBodyRecognizer, "T"}, // eBodyRecognizer
+
+ { MatchString, eAccessValueRecognizer, eBodyRecognizer, kPacketTail }, // eTailStartRecognizer
+ { CaptureAccess, eAttrSpaceRecognizer_2, eBodyRecognizer, NULL }, // eAccessValueRecognizer
+
+ { MatchChar, eAttrNameRecognizer_2, eTailEndRecognizer, " " }, // eAttrSpaceRecognizer_2
+ { CaptureAttrName, eAttrValueRecognizer_2, eBodyRecognizer, NULL }, // eAttrNameRecognizer_2
+ { CaptureAttrValue, eAttrValueRecorder_2, eBodyRecognizer, NULL }, // eAttrValueRecognizer_2
+ { RecordTailAttr, eAttrSpaceRecognizer_2, eBodyRecognizer, NULL }, // eAttrValueRecorder_2
+
+ { MatchString, ePacketEndRecognizer, eBodyRecognizer, "?>" }, // eTailEndRecognizer
+ { CheckPacketEnd, eCloseOutRecognizer, eBodyRecognizer, "" }, // ePacketEndRecognizer
+ { CheckFinalNulls, eSuccessRecognizer, eBodyRecognizer, "" } // eCloseOutRecognizer
+
+ };
+
+ while ( true ) {
+
+ switch ( fRecognizer ) {
+
+ case eFailureRecognizer :
+ return eTriNo;
+
+ case eSuccessRecognizer :
+ return eTriYes;
+
+ default :
+
+ // -------------------------------------------------------------------
+ // For everything else, the normal cases, use the state machine table.
+
+ const RecognizerInfo * thisState = &recognizerTable [fRecognizer];
+
+ status = thisState->proc ( this, thisState->literal );
+
+ switch ( status ) {
+
+ case eTriNo :
+ SetNextRecognizer ( thisState->failureNext );
+ continue;
+
+ case eTriYes :
+ SetNextRecognizer ( thisState->successNext );
+ continue;
+
+ case eTriMaybe :
+ fBufferOverrun = (unsigned char)(fBufferPtr - fBufferLimit);
+ return eTriMaybe; // Keep this recognizer intact, to be resumed later.
+
+ }
+
+ } // switch ( fRecognizer ) { ...
+
+ } // while ( true ) { ...
+
+} // FindNextPacket
+
+
+// =================================================================================================
+// =================================================================================================
+// class InternalSnip
+// ==================
+
+
+// =================================================================================================
+// InternalSnip
+// ============
+
+XMPScanner::InternalSnip::InternalSnip ( SInt64 offset, SInt64 length )
+{
+
+ fInfo.fOffset = offset;
+ fInfo.fLength = length;
+
+} // InternalSnip
+
+
+// =================================================================================================
+// InternalSnip
+// ============
+
+XMPScanner::InternalSnip::InternalSnip ( const InternalSnip & rhs ) :
+ fInfo ( rhs.fInfo ),
+ fMachine ( NULL )
+{
+
+ assert ( rhs.fMachine.get() == NULL ); // Don't copy a snip with a machine.
+ assert ( (rhs.fInfo.fEncodingAttr == 0) || (*rhs.fInfo.fEncodingAttr == 0) ); // Don't copy a snip with an encoding.
+
+} // InternalSnip
+
+
+// =================================================================================================
+// ~InternalSnip
+// =============
+
+XMPScanner::InternalSnip::~InternalSnip ()
+{
+} // ~InternalSnip
+
+
+
+// =================================================================================================
+// =================================================================================================
+// class XMPScanner
+// ================
+
+
+// =================================================================================================
+// DumpSnipList
+// ============
+
+static const char * snipStateName [6] = { "not-seen", "pending", "raw-data", "good-packet", "partial", "bad-packet" };
+
+void
+XMPScanner::DumpSnipList ( const char * title )
+{
+#if 1
+ InternalSnipIterator currPos = fInternalSnips.begin();
+ InternalSnipIterator endPos = fInternalSnips.end();
+
+ cout << endl << title << " snip list: " << fInternalSnips.size() << endl;
+
+ for ( ; currPos != endPos; ++currPos ) {
+ SnipInfo * currSnip = &currPos->fInfo;
+ cout << '\t' << currSnip << ' ' << snipStateName[currSnip->fState] << ' '
+ << currSnip->fOffset << ".." << (currSnip->fOffset + currSnip->fLength - 1)
+ << ' ' << currSnip->fLength << ' ' << endl;
+ }
+#endif
+} // DumpSnipList
+
+
+// =================================================================================================
+// PrevSnip and NextSnip
+// =====================
+
+XMPScanner::InternalSnipIterator
+XMPScanner::PrevSnip ( InternalSnipIterator snipPos )
+{
+
+ InternalSnipIterator prev = snipPos;
+ return --prev;
+
+} // PrevSnip
+
+XMPScanner::InternalSnipIterator
+XMPScanner::NextSnip ( InternalSnipIterator snipPos )
+{
+
+ InternalSnipIterator next = snipPos;
+ return ++next;
+
+} // NextSnip
+
+
+// =================================================================================================
+// XMPScanner
+// ==========
+//
+// Initialize the scanner object with one "not seen" snip covering the whole stream.
+
+XMPScanner::XMPScanner ( SInt64 streamLength ) :
+
+ fStreamLength ( streamLength )
+
+{
+ InternalSnip rootSnip ( 0, streamLength );
+
+ if ( streamLength > 0 ) fInternalSnips.push_front ( rootSnip ); // Be nice for empty files.
+ // DumpSnipList ( "New XMPScanner" );
+
+} // XMPScanner
+
+
+// =================================================================================================
+// ~XMPScanner
+// ===========
+
+XMPScanner::~XMPScanner()
+{
+
+} // ~XMPScanner
+
+
+// =================================================================================================
+// GetSnipCount
+// ============
+
+long
+XMPScanner::GetSnipCount ()
+{
+
+ return fInternalSnips.size();
+
+} // GetSnipCount
+
+
+// =================================================================================================
+// StreamAllScanned
+// ================
+
+bool
+XMPScanner::StreamAllScanned ()
+{
+ InternalSnipIterator currPos = fInternalSnips.begin();
+ InternalSnipIterator endPos = fInternalSnips.end();
+
+ for ( ; currPos != endPos; ++currPos ) {
+ if ( currPos->fInfo.fState == eNotSeenSnip ) return false;
+ }
+ return true;
+
+} // StreamAllScanned
+
+
+// =================================================================================================
+// SplitInternalSnip
+// =================
+//
+// Split the given snip into up to 3 pieces. The new pieces are inserted before and after this one
+// in the snip list. The relOffset is the first byte to be kept, it is relative to this snip. If
+// the preceeding or following snips have the same state as this one, just shift the boundaries.
+// I.e. move the contents from one snip to the other, don't create a new snip.
+
+// *** To be thread safe we ought to lock the entire list during manipulation. Let data scanning
+// *** happen in parallel, serialize all mucking with the list.
+
+void
+XMPScanner::SplitInternalSnip ( InternalSnipIterator snipPos, SInt64 relOffset, SInt64 newLength )
+{
+
+ assert ( (relOffset + newLength) > relOffset ); // Check for overflow.
+ assert ( (relOffset + newLength) <= snipPos->fInfo.fLength );
+
+ // -----------------------------------
+ // First deal with the low offset end.
+
+ if ( relOffset > 0 ) {
+
+ InternalSnipIterator prevPos;
+ if ( snipPos != fInternalSnips.begin() ) prevPos = PrevSnip ( snipPos );
+
+ if ( (snipPos != fInternalSnips.begin()) && (snipPos->fInfo.fState == prevPos->fInfo.fState) ) {
+ prevPos->fInfo.fLength += relOffset; // Adjust the preceeding snip.
+ } else {
+ InternalSnip headExcess ( snipPos->fInfo.fOffset, relOffset );
+ headExcess.fInfo.fState = snipPos->fInfo.fState;
+ headExcess.fInfo.fOutOfOrder = snipPos->fInfo.fOutOfOrder;
+ fInternalSnips.insert ( snipPos, headExcess ); // Insert the head piece before the middle piece.
+ }
+
+ snipPos->fInfo.fOffset += relOffset; // Adjust the remainder of this snip.
+ snipPos->fInfo.fLength -= relOffset;
+
+ }
+
+ // ----------------------------------
+ // Now deal with the high offset end.
+
+ if ( newLength < snipPos->fInfo.fLength ) {
+
+ InternalSnipIterator nextPos = NextSnip ( snipPos );
+ const SInt64 tailLength = snipPos->fInfo.fLength - newLength;
+
+ if ( (nextPos != fInternalSnips.end()) && (snipPos->fInfo.fState == nextPos->fInfo.fState) ) {
+ nextPos->fInfo.fOffset -= tailLength; // Adjust the following snip.
+ nextPos->fInfo.fLength += tailLength;
+ } else {
+ InternalSnip tailExcess ( (snipPos->fInfo.fOffset + newLength), tailLength );
+ tailExcess.fInfo.fState = snipPos->fInfo.fState;
+ tailExcess.fInfo.fOutOfOrder = snipPos->fInfo.fOutOfOrder;
+ fInternalSnips.insert ( nextPos, tailExcess ); // Insert the tail piece after the middle piece.
+ }
+
+ snipPos->fInfo.fLength = newLength;
+
+ }
+
+} // SplitInternalSnip
+
+
+// =================================================================================================
+// MergeInternalSnips
+// ==================
+
+XMPScanner::InternalSnipIterator
+XMPScanner::MergeInternalSnips ( InternalSnipIterator firstPos, InternalSnipIterator secondPos )
+{
+
+ firstPos->fInfo.fLength += secondPos->fInfo.fLength;
+ fInternalSnips.erase ( secondPos );
+ return firstPos;
+
+} // MergeInternalSnips
+
+
+// =================================================================================================
+// Scan
+// ====
+
+void
+XMPScanner::Scan ( const void * bufferOrigin, SInt64 bufferOffset, SInt64 bufferLength )
+{
+ SInt64 relOffset;
+
+ #if 0
+ cout << "Scan: @ " << bufferOrigin << ", " << bufferOffset << ", " << bufferLength << endl;
+ #endif
+
+ if ( bufferLength == 0 ) return;
+
+ // ----------------------------------------------------------------
+ // These comparisons are carefully done to avoid overflow problems.
+
+ if ( (bufferOffset >= fStreamLength) ||
+ (bufferLength > (fStreamLength - bufferOffset)) ||
+ (bufferOrigin == 0) ) {
+ throw ScanError ( "Bad origin, offset, or length" );
+ }
+
+ // ----------------------------------------------------------------------------------------------
+ // This buffer must be within a not-seen snip. Find it and split it. The first snip whose whose
+ // end is beyond the buffer must be the enclosing one.
+
+ // *** It would be friendly for rescans for out of order problems to accept any buffer postion.
+
+ const SInt64 endOffset = bufferOffset + bufferLength - 1;
+ InternalSnipIterator snipPos = fInternalSnips.begin();
+
+ while ( endOffset > (snipPos->fInfo.fOffset + snipPos->fInfo.fLength - 1) ) ++ snipPos;
+ if ( snipPos->fInfo.fState != eNotSeenSnip ) throw ScanError ( "Already seen" );
+
+ relOffset = bufferOffset - snipPos->fInfo.fOffset;
+ if ( (relOffset + bufferLength) > snipPos->fInfo.fLength ) throw ScanError ( "Not within existing snip" );
+
+ SplitInternalSnip ( snipPos, relOffset, bufferLength ); // *** If sequential & prev is partial, just tack on,
+
+ // --------------------------------------------------------
+ // Merge this snip with the preceeding snip if appropriate.
+
+ // *** When out of order I/O is supported we have to do something about buffers who's predecessor is not seen.
+
+ if ( snipPos->fInfo.fOffset > 0 ) {
+ InternalSnipIterator prevPos = PrevSnip ( snipPos );
+ if ( prevPos->fInfo.fState == ePartialPacketSnip ) snipPos = MergeInternalSnips ( prevPos, snipPos );
+ }
+
+ // ----------------------------------
+ // Look for packets within this snip.
+
+ snipPos->fInfo.fState = ePendingSnip;
+ PacketMachine* thisMachine = snipPos->fMachine.get();
+ // DumpSnipList ( "Before scan" );
+
+ if ( thisMachine != 0 ) {
+ thisMachine->AssociateBuffer ( bufferOffset, bufferOrigin, bufferLength );
+ } else {
+ // *** snipPos->fMachine.reset ( new PacketMachine ( bufferOffset, bufferOrigin, bufferLength ) ); VC++ lacks reset
+ #if 0
+ snipPos->fMachine = auto_ptr<PacketMachine> ( new PacketMachine ( bufferOffset, bufferOrigin, bufferLength ) );
+ #else
+ {
+ // Some versions of gcc complain about the assignment operator above. This avoids the gcc bug.
+ PacketMachine * pm = new PacketMachine ( bufferOffset, bufferOrigin, bufferLength );
+ auto_ptr<PacketMachine> ap ( pm );
+ snipPos->fMachine = ap;
+ }
+ #endif
+ thisMachine = snipPos->fMachine.get();
+ }
+
+ bool bufferDone = false;
+ while ( ! bufferDone ) {
+
+ PacketMachine::TriState foundPacket = thisMachine->FindNextPacket();
+
+ if ( foundPacket == PacketMachine::eTriNo ) {
+
+ // -----------------------------------------------------------------------
+ // No packet, mark the snip as raw data and get rid of the packet machine.
+ // We're done with this buffer.
+
+ snipPos->fInfo.fState = eRawInputSnip;
+ #if 0
+ snipPos->fMachine = auto_ptr<PacketMachine>(); // *** snipPos->fMachine.reset(); VC++ lacks reset
+ #else
+ {
+ // Some versions of gcc complain about the assignment operator above. This avoids the gcc bug.
+ auto_ptr<PacketMachine> ap ( 0 );
+ snipPos->fMachine = ap;
+ }
+ #endif
+ bufferDone = true;
+
+ } else {
+
+ // ---------------------------------------------------------------------------------------------
+ // Either a full or partial packet. First trim any excess off of the front as a raw input snip.
+ // If this is a partial packet mark the snip and keep the packet machine to be resumed later.
+ // We're done with this buffer, the partial packet by definition extends to the end. If this is
+ // a complete packet first extract the additional information from the packet machine. If there
+ // is leftover data split the snip and transfer the packet machine to the new trailing snip.
+
+ if ( thisMachine->fPacketStart > snipPos->fInfo.fOffset ) {
+
+ // There is data at the front of the current snip that must be trimmed.
+ SnipState savedState = snipPos->fInfo.fState;
+ snipPos->fInfo.fState = eRawInputSnip; // ! So it gets propagated to the trimmed front part.
+ relOffset = thisMachine->fPacketStart - snipPos->fInfo.fOffset;
+ SplitInternalSnip ( snipPos, relOffset, (snipPos->fInfo.fLength - relOffset) );
+ snipPos->fInfo.fState = savedState;
+
+ }
+
+ if ( foundPacket == PacketMachine::eTriMaybe ) {
+
+ // We have only found a partial packet.
+ snipPos->fInfo.fState = ePartialPacketSnip;
+ bufferDone = true;
+
+ } else {
+
+ // We have found a complete packet. Extract all the info for it and split any trailing data.
+
+ InternalSnipIterator packetSnip = snipPos;
+ SnipState packetState = eValidPacketSnip;
+
+ if ( thisMachine->fBogusPacket ) packetState = eBadPacketSnip;
+
+ packetSnip->fInfo.fAccess = thisMachine->fAccess;
+ packetSnip->fInfo.fCharForm = thisMachine->fCharForm;
+ packetSnip->fInfo.fBytesAttr = thisMachine->fBytesAttr;
+ packetSnip->fInfo.fEncodingAttr = thisMachine->fEncodingAttr.c_str();
+ thisMachine->fEncodingAttr.erase ( thisMachine->fEncodingAttr.begin(), thisMachine->fEncodingAttr.end() );
+
+ if ( (thisMachine->fCharForm != eChar8Bit) && CharFormIsBigEndian ( thisMachine->fCharForm ) ) {
+
+ // ------------------------------------------------------------------------------
+ // Handle a special case for big endian characters. The packet machine works as
+ // though things were little endian. The packet starting offset points to the
+ // byte containing the opening '<', and the length includes presumed nulls that
+ // follow the last "real" byte. If the characters are big endian we now have to
+ // decrement the starting offset of the packet, and also decrement the length of
+ // the previous snip.
+ //
+ // Note that we can't do this before the head trimming above in general. The
+ // nulls might have been exactly at the end of a buffer and already in the
+ // previous snip. We are doing this before trimming the tail from the raw snip
+ // containing the packet. We adjust the raw snip's size because it ends with
+ // the input buffer. We don't adjust the packet's size, it is already correct.
+ //
+ // The raw snip (the one before the packet) might entirely disappear. A simple
+ // example of this is when the packet is at the start of the file.
+
+ assert ( packetSnip != fInternalSnips.begin() ); // Leading nulls were trimmed!
+
+ if ( packetSnip != fInternalSnips.begin() ) { // ... but let's program defensibly.
+
+ InternalSnipIterator prevSnip = PrevSnip ( packetSnip );
+ const unsigned int nullsToAdd = ( CharFormIs16Bit ( thisMachine->fCharForm ) ? 1 : 3 );
+
+ assert ( nullsToAdd <= prevSnip->fInfo.fLength );
+ prevSnip->fInfo.fLength -= nullsToAdd;
+ if ( prevSnip->fInfo.fLength == 0 ) (void) fInternalSnips.erase ( prevSnip );
+
+ packetSnip->fInfo.fOffset -= nullsToAdd;
+ packetSnip->fInfo.fLength += nullsToAdd;
+ thisMachine->fPacketStart -= nullsToAdd;
+
+ }
+
+ }
+
+ if ( thisMachine->fPacketLength == snipPos->fInfo.fLength ) {
+
+ // This packet ends exactly at the end of the current snip.
+ #if 0
+ snipPos->fMachine = auto_ptr<PacketMachine>(); // *** snipPos->fMachine.reset(); VC++ lacks reset
+ #else
+ {
+ // Some versions of gcc complain about the assignment operator above. This avoids the gcc bug.
+ auto_ptr<PacketMachine> ap ( 0 );
+ snipPos->fMachine = ap;
+ }
+ #endif
+ bufferDone = true;
+
+ } else {
+
+ // There is trailing data to split from the just found packet.
+ SplitInternalSnip ( snipPos, 0, thisMachine->fPacketLength );
+
+ InternalSnipIterator tailPos = NextSnip ( snipPos );
+
+ tailPos->fMachine = snipPos->fMachine; // auto_ptr assignment - taking ownership
+ thisMachine->ResetMachine ();
+
+ snipPos = tailPos;
+
+ }
+
+ packetSnip->fInfo.fState = packetState; // Do this last to avoid messing up the tail split.
+ // DumpSnipList ( "Found a packet" );
+
+
+ }
+
+ }
+
+ }
+
+ // --------------------------------------------------------
+ // Merge this snip with the preceeding snip if appropriate.
+
+ // *** When out of order I/O is supported we have to check the following snip too.
+
+ if ( (snipPos->fInfo.fOffset > 0) && (snipPos->fInfo.fState == eRawInputSnip) ) {
+ InternalSnipIterator prevPos = PrevSnip ( snipPos );
+ if ( prevPos->fInfo.fState == eRawInputSnip ) snipPos = MergeInternalSnips ( prevPos, snipPos );
+ }
+
+ // DumpSnipList ( "After scan" );
+
+} // Scan
+
+
+// =================================================================================================
+// Report
+// ======
+
+void
+XMPScanner::Report ( SnipInfoVector& snips )
+{
+ const int count = fInternalSnips.size();
+ InternalSnipIterator snipPos = fInternalSnips.begin();
+
+ int s;
+
+ // DumpSnipList ( "Report" );
+
+ snips.erase ( snips.begin(), snips.end() ); // ! Should use snips.clear, but VC++ doesn't have it.
+ snips.reserve ( count );
+
+ for ( s = 0; s < count; s += 1 ) {
+ snips.push_back ( SnipInfo ( snipPos->fInfo.fState, snipPos->fInfo.fOffset, snipPos->fInfo.fLength ) );
+ snips[s] = snipPos->fInfo; // Pick up all of the fields.
+ ++ snipPos;
+ }
+
+} // Report
diff --git a/samples/source/XMPScanner.hpp b/samples/source/XMPScanner.hpp
new file mode 100644
index 0000000..7f92853
--- /dev/null
+++ b/samples/source/XMPScanner.hpp
@@ -0,0 +1,332 @@
+#ifndef __XMPScanner_hpp__
+#define __XMPScanner_hpp__
+
+// =================================================================================================
+// Copyright 2002-2005 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+//
+// Adobe patent application tracking #P435, entitled 'Unique markers to simplify embedding data of
+// one format in a file with a different format', inventors: Sean Parent, Greg Gilley.
+// =================================================================================================
+
+#include <list>
+#include <vector>
+#include <string>
+#include <memory>
+#include <stdexcept>
+
+
+// =================================================================================================
+// The XMPScanner class is used to scan a stream of input for XMP packets. A scanner object is
+// constructed then fed the input through a series of calls to Scan. Report may be called at any
+// time to get the current knowledge of the input.
+//
+// A packet starts when a valid header is found and ends when a valid trailer is found. If the
+// header contains a "bytes" attribute, additional whitespace must follow.
+//
+// *** RESTRICTIONS: The current implementation of the scanner has the the following restrictions:
+// - The input must be presented in order.
+// - Not fully thread safe, don't make concurrent calls to the same XMPScanner object.
+// =================================================================================================
+
+class XMPScanner {
+public:
+
+ // =============================================================================================
+ // The entire input stream is represented as a series of snips. Each snip defines one portion
+ // of the input stream that either has not been seen, has been seen and contains no packets, is
+ // exactly one packet, or contains the start of an unfinished packet. Adjacent snips with the
+ // same state are merged, so the number of snips is always minimal.
+ //
+ // A newly constructed XMPScanner object has one snip covering the whole input with a state
+ // of "not seen". A block of input that contains a full XMP packet is split into 3 parts: a
+ // (possibly empty) raw input snip, the packet, and another (possibly empty) raw input snip. A
+ // block of input that contains the start of an XMP packet is split into two snips, a (possibly
+ // empty) raw input snip and the packet start; the following snip must be a "not seen" snip.
+ //
+ // It is possible to have ill-formed packets. These have a syntactically valid header and
+ // trailer, but some semantic error. For example, if the "bytes" attribute length does not span
+ // to the end of the trailer, or if the following packet begins within trailing padding.
+
+ typedef unsigned char UInt8;
+ typedef unsigned long UInt32;
+ typedef long long SInt64;
+
+ enum {
+ eNotSeenSnip, // This snip has not been seen yet.
+ ePendingSnip, // This snip is an input buffer being processed.
+ eRawInputSnip, // This snip is raw input, it doesn't contain any part of an XMP packet.
+ eValidPacketSnip, // This snip is a complete, valid XMP packet.
+ ePartialPacketSnip, // This snip contains the start of a possible XMP packet.
+ eBadPacketSnip // This snip contains a complete, but semantically incorrect XMP packet.
+ };
+ typedef UInt8 SnipState;
+
+ enum { // The values allow easy testing for 16/32 bit and big/little endian.
+ eChar8Bit = 0,
+ eChar16BitBig = 2,
+ eChar16BitLittle = 3,
+ eChar32BitBig = 4,
+ eChar32BitLittle = 5
+ };
+ typedef UInt8 CharacterForm;
+
+ enum {
+ eChar16BitMask = 2, // These constant shouldn't be used directly, they are mainly
+ eChar32BitMask = 4, // for the CharFormIsXyz macros below.
+ eCharLittleEndianMask = 1
+ };
+
+ #define CharFormIs16Bit(f) ( ((int)(f) & XMPScanner::eChar16BitMask) != 0 )
+ #define CharFormIs32Bit(f) ( ((int)(f) & XMPScanner::eChar32BitMask) != 0 )
+
+ #define CharFormIsBigEndian(f) ( ((int)(f) & XMPScanner::eCharLittleEndianMask) == 0 )
+ #define CharFormIsLittleEndian(f) ( ((int)(f) & XMPScanner::eCharLittleEndianMask) != 0 )
+
+ struct SnipInfo {
+
+ SInt64 fOffset; // The byte offset of this snip within the input stream.
+ SInt64 fLength; // The length in bytes of this snip.
+ SnipState fState; // The state of this snip.
+ bool fOutOfOrder; // If true, this snip was seen before the one in front of it.
+ char fAccess; // The read-only/read-write access from the end attribute.
+ CharacterForm fCharForm; // How the packet is divided into characters.
+ const char * fEncodingAttr; // The value of the encoding attribute, if any, with nulls removed.
+ SInt64 fBytesAttr; // The value of the bytes attribute, -1 if not present.
+
+ SnipInfo() :
+ fOffset ( 0 ),
+ fLength ( 0 ),
+ fState ( eNotSeenSnip ),
+ fOutOfOrder ( false ),
+ fAccess ( ' ' ),
+ fCharForm ( eChar8Bit ),
+ fEncodingAttr ( "" ),
+ fBytesAttr( -1 )
+ { }
+
+ SnipInfo ( SnipState state, SInt64 offset, SInt64 length ) :
+ fOffset ( offset ),
+ fLength ( length ),
+ fState ( state ),
+ fOutOfOrder ( false ),
+ fAccess ( ' ' ),
+ fCharForm ( eChar8Bit ),
+ fEncodingAttr ( "" ),
+ fBytesAttr( -1 )
+ { }
+
+ };
+
+ typedef std::vector<SnipInfo> SnipInfoVector;
+
+ XMPScanner ( SInt64 streamLength );
+ // Constructs a new XMPScanner object for a stream with the given length.
+
+ ~XMPScanner();
+
+ long GetSnipCount();
+ // Returns the number of snips that the stream has been divided into.
+
+ bool StreamAllScanned();
+ // Returns true if all of the stream has been seen.
+
+ void Scan ( const void * bufferOrigin, SInt64 bufferOffset, SInt64 bufferLength );
+ // Scans the given part of the input, incorporating it in to the known snips.
+ // The bufferOffset is the offset of this block of input relative to the entire stream.
+ // The bufferLength is the length in bytes of this block of input.
+
+ void Report ( SnipInfoVector & snips );
+ // Produces a report of what is known about the input stream.
+
+ class ScanError : public std::logic_error {
+ public:
+ ScanError() throw() : std::logic_error ( "" ) {}
+ explicit ScanError ( const char * message ) throw() : std::logic_error ( message ) {}
+ virtual ~ScanError() throw() {}
+ };
+
+private: // XMPScanner
+
+ class PacketMachine;
+
+ class InternalSnip {
+ public:
+
+ SnipInfo fInfo; // The public info about this snip.
+ std::auto_ptr<PacketMachine> fMachine; // The state machine for "active" snips.
+
+ InternalSnip() {}; // Let everything default.
+ InternalSnip ( SInt64 offset, SInt64 length );
+ InternalSnip ( const InternalSnip & );
+ ~InternalSnip();
+
+ }; // InternalSnip
+
+ typedef std::list<InternalSnip> InternalSnipList;
+ typedef InternalSnipList::iterator InternalSnipIterator;
+
+ class PacketMachine {
+ public:
+
+ SInt64 fPacketStart; // Byte offset relative to the entire stream.
+ SInt64 fPacketLength; // Length in bytes to the end of the trailer processing instruction.
+ SInt64 fBytesAttr; // The value of the bytes attribute, -1 if not present.
+ std::string fEncodingAttr; // The value of the encoding attribute, if any, with nulls removed.
+ CharacterForm fCharForm; // How the packet is divided into characters.
+ char fAccess; // The read-only/read-write access from the end attribute.
+ bool fBogusPacket; // True if the packet has an error such as a bad "bytes" attribute value.
+
+ void ResetMachine();
+
+ enum TriState {
+ eTriNo,
+ eTriMaybe,
+ eTriYes
+ };
+
+ TriState FindNextPacket();
+
+ void AssociateBuffer ( SInt64 bufferOffset, const void * bufferOrigin, SInt64 bufferLength );
+
+ PacketMachine ( SInt64 bufferOffset, const void * bufferOrigin, SInt64 bufferLength );
+ ~PacketMachine();
+
+ private: // PacketMachine
+
+ PacketMachine() {}; // ! Hide the default constructor.
+
+ enum RecognizerKind {
+
+ eFailureRecognizer, // Not really recognizers, special states to end one buffer's processing.
+ eSuccessRecognizer,
+
+ eLeadInRecognizer, // Anything up to the next '<'.
+ eHeadStartRecorder, // Save the starting offset, count intervening nulls.
+ eHeadStartRecognizer, // The literal string "?xpacket begin=".
+
+ eBOMRecognizer, // Recognize and record the quoted byte order marker.
+
+ eIDTagRecognizer, // The literal string " id=".
+ eIDOpenRecognizer, // The opening quote for the ID.
+ eIDValueRecognizer, // The literal string "W5M0MpCehiHzreSzNTczkc9d".
+ eIDCloseRecognizer, // The closing quote for the ID.
+
+ eAttrSpaceRecognizer_1, // The space before an attribute.
+ eAttrNameRecognizer_1, // The name of an attribute.
+ eAttrValueRecognizer_1, // The equal sign and quoted string value for an attribute.
+ eAttrValueRecorder_1, // Record the value of an attribute.
+
+ eHeadEndRecognizer, // The string literal "?>".
+
+ eBodyRecognizer, // The packet body, anything up to the next '<'.
+
+ eTailStartRecognizer, // The string literal "?xpacket end=".
+ eAccessValueRecognizer, // Recognize and record the quoted r/w access mode.
+
+ eAttrSpaceRecognizer_2, // The space before an attribute.
+ eAttrNameRecognizer_2, // The name of an attribute.
+ eAttrValueRecognizer_2, // The equal sign and quoted string value for an attribute.
+ eAttrValueRecorder_2, // Record the value of an attribute.
+
+ eTailEndRecognizer, // The string literal "?>".
+ ePacketEndRecognizer, // Look for trailing padding, check and record the packet size.
+ eCloseOutRecognizer, // Look for final nulls for little endian multibyte characters.
+
+ eRecognizerCount
+
+ };
+
+ SInt64 fBufferOffset; // The offset of the data buffer within the input stream.
+ const char * fBufferOrigin; // The starting address of the data buffer for this snip.
+ const char * fBufferPtr; // The current postion in the data buffer.
+ const char * fBufferLimit; // The address one past the last byte in the data buffer.
+
+ RecognizerKind fRecognizer; // Which recognizer is currently active.
+ signed long fPosition; // The internal position within a string literal, etc.
+ unsigned char fBytesPerChar; // The number of bytes per logical character, 1, 2, or 4.
+ unsigned char fBufferOverrun; // Non-zero if suspended while skipping intervening nulls.
+ char fQuoteChar; // The kind of quote seen at the start of a quoted value.
+ std::string fAttrName; // The name for an arbitrary attribute (other than "begin" and "id").
+ std::string fAttrValue; // The value for an arbitrary attribute (other than "begin" and "id").
+
+ void SetNextRecognizer ( RecognizerKind nextRecognizer );
+
+ typedef TriState (* RecognizerProc) ( PacketMachine *, const char * );
+
+ static TriState
+ FindLessThan ( PacketMachine * ths, const char * which );
+
+ static TriState
+ MatchString ( PacketMachine * ths, const char * literal );
+
+ static TriState
+ MatchChar ( PacketMachine * ths, const char * literal );
+
+ static TriState
+ MatchOpenQuote ( PacketMachine * ths, const char * /* unused */ );
+
+ static TriState
+ MatchCloseQuote ( PacketMachine * ths, const char * /* unused */ );
+
+ static TriState
+ CaptureAttrName ( PacketMachine * ths, const char * /* unused */ );
+
+ static TriState
+ CaptureAttrValue ( PacketMachine * ths, const char * /* unused */ );
+
+ static TriState
+ RecordStart ( PacketMachine * ths, const char * /* unused */ );
+
+ static TriState
+ RecognizeBOM ( PacketMachine * ths, const char * /* unused */ );
+
+ static TriState
+ RecordHeadAttr ( PacketMachine * ths, const char * /* unused */ );
+
+ static TriState
+ CaptureAccess ( PacketMachine * ths, const char * /* unused */ );
+
+ static TriState
+ RecordTailAttr ( PacketMachine * ths, const char * /* unused */ );
+
+ static TriState
+ CheckPacketEnd ( PacketMachine * ths, const char * /* unused */ );
+
+ static TriState
+ CheckFinalNulls ( PacketMachine * ths, const char * /* unused */ );
+
+ struct RecognizerInfo {
+ RecognizerProc proc;
+ RecognizerKind successNext;
+ RecognizerKind failureNext;
+ const char * literal;
+ };
+
+ }; // PacketMachine
+
+ SInt64 fStreamLength;
+ InternalSnipList fInternalSnips;
+
+ void
+ SplitInternalSnip ( InternalSnipIterator snipPos, SInt64 relOffset, SInt64 newLength );
+
+ InternalSnipIterator
+ MergeInternalSnips ( InternalSnipIterator firstPos, InternalSnipIterator secondPos );
+
+ void
+ DumpSnipList ( const char * title );
+
+ InternalSnipIterator
+ PrevSnip ( InternalSnipIterator snipPos );
+
+ InternalSnipIterator
+ NextSnip ( InternalSnipIterator snipPos );
+
+}; // XMPScanner
+
+
+#endif // __XMPScanner_hpp__
diff --git a/source/XMPCore/ExpatAdapter.cpp b/source/XMPCore/ExpatAdapter.cpp
new file mode 100644
index 0000000..d383c98
--- /dev/null
+++ b/source/XMPCore/ExpatAdapter.cpp
@@ -0,0 +1,465 @@
+// =================================================================================================
+// Copyright 2005-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "XMP_Environment.h" // ! Must be the first #include!
+#include "XMPCore_Impl.hpp"
+
+#include "ExpatAdapter.hpp"
+#include "XMPMeta.hpp"
+
+#include <string.h>
+
+using namespace std;
+
+#if XMP_WinBuild
+ #pragma warning ( disable : 4996 ) // '...' was declared deprecated
+#endif
+
+// *** Set memory handlers.
+
+#ifndef DumpXMLParseEvents
+ #define DumpXMLParseEvents 0
+#endif
+
+#define FullNameSeparator '@'
+
+// =================================================================================================
+
+static void StartNamespaceDeclHandler ( void * userData, XMP_StringPtr prefix, XMP_StringPtr uri );
+static void EndNamespaceDeclHandler ( void * userData, XMP_StringPtr prefix );
+
+static void StartElementHandler ( void * userData, XMP_StringPtr name, XMP_StringPtr* attrs );
+static void EndElementHandler ( void * userData, XMP_StringPtr name );
+
+static void CharacterDataHandler ( void * userData, XMP_StringPtr cData, int len );
+static void StartCdataSectionHandler ( void * userData );
+static void EndCdataSectionHandler ( void * userData );
+
+static void ProcessingInstructionHandler ( void * userData, XMP_StringPtr target, XMP_StringPtr data );
+static void CommentHandler ( void * userData, XMP_StringPtr comment );
+
+static void DefaultHandler ( void * userData, XMP_StringPtr data, int len );
+
+// =================================================================================================
+// =================================================================================================
+
+ExpatAdapter::ExpatAdapter() : parser(0), nesting(0)
+{
+
+ #if XMP_DebugBuild & DumpXMLParseEvents
+ if ( this->parseLog == 0 ) this->parseLog = stdout;
+ #endif
+
+ this->parser = XML_ParserCreateNS ( 0, FullNameSeparator );
+ if ( this->parser == 0 ) XMP_Throw ( "Failure creating Expat parser", kXMPErr_ExternalFailure );
+
+ XML_SetUserData ( this->parser, this );
+
+ XML_SetNamespaceDeclHandler ( this->parser, StartNamespaceDeclHandler, EndNamespaceDeclHandler );
+ XML_SetElementHandler ( this->parser, StartElementHandler, EndElementHandler );
+
+ XML_SetCharacterDataHandler ( this->parser, CharacterDataHandler );
+ XML_SetCdataSectionHandler ( this->parser, StartCdataSectionHandler, EndCdataSectionHandler );
+
+ XML_SetProcessingInstructionHandler ( this->parser, ProcessingInstructionHandler );
+ XML_SetCommentHandler ( this->parser, CommentHandler );
+
+ // ??? XML_SetDefaultHandlerExpand ( this->parser, DefaultHandler );
+
+ this->parseStack.push_back ( &this->tree ); // Push the XML root node.
+
+} // ExpatAdapter::ExpatAdapter
+
+// =================================================================================================
+
+ExpatAdapter::~ExpatAdapter()
+{
+
+ if ( this->parser != 0 ) XML_ParserFree ( this->parser );
+ this->parser = 0;
+
+} // ExpatAdapter::~ExpatAdapter
+
+// =================================================================================================
+
+#if XMP_DebugBuild
+ static XMP_VarString sExpatMessage;
+#endif
+
+static const char * kOneSpace = " ";
+
+void ExpatAdapter::ParseBuffer ( const void * buffer, size_t length, bool last )
+{
+ enum XML_Status status;
+
+ if ( length == 0 ) { // Expat does not like empty buffers.
+ if ( ! last ) return;
+ buffer = kOneSpace;
+ length = 1;
+ }
+
+ status = XML_Parse ( this->parser, (const char *)buffer, length, last );
+
+ if ( status != XML_STATUS_OK ) {
+
+ XMP_StringPtr errMsg = "XML parsing failure";
+
+ #if 0 // XMP_DebugBuild // Disable for now to make test output uniform. Restore later with thread safety.
+
+ // *** This is a good candidate for a callback error notification mechanism.
+ // *** This code is not thread safe, the sExpatMessage isn't locked. But that's OK for debug usage.
+
+ enum XML_Error expatErr = XML_GetErrorCode ( this->parser );
+ const char * expatMsg = XML_ErrorString ( expatErr );
+ int errLine = XML_GetCurrentLineNumber ( this->parser );
+
+ char msgBuffer[1000];
+ // AUDIT: Use of sizeof(msgBuffer) for snprintf length is safe.
+ snprintf ( msgBuffer, sizeof(msgBuffer), "# Expat error %d at line %d, \"%s\"", expatErr, errLine, expatMsg );
+ sExpatMessage = msgBuffer;
+ errMsg = sExpatMessage.c_str();
+
+ #if DumpXMLParseEvents
+ if ( this->parseLog != 0 ) fprintf ( this->parseLog, "%s\n", errMsg, expatErr, errLine, expatMsg );
+ #endif
+
+ #endif
+
+ XMP_Throw ( errMsg, kXMPErr_BadXML );
+
+ }
+
+} // ExpatAdapter::ParseBuffer
+
+// =================================================================================================
+// =================================================================================================
+
+#if XMP_DebugBuild & DumpXMLParseEvents
+
+ static inline void PrintIndent ( FILE * file, size_t nesting )
+ {
+ for ( ; nesting > 0; --nesting ) fprintf ( file, " " );
+ }
+
+#endif
+
+// =================================================================================================
+
+static void SetQualName ( XMP_StringPtr fullName, XML_Node * node )
+{
+ // Expat delivers the full name as a catenation of namespace URI, separator, and local name.
+
+ // As a compatibility hack, an "about" or "ID" attribute of an rdf:Description element is
+ // changed to "rdf:about" or rdf:ID. Easier done here than in the RDF recognizer.
+
+ // As a bug fix hack, change a URI of "http://purl.org/dc/1.1/" to ""http://purl.org/dc/elements/1.1/.
+ // Early versions of Flash that put XMP in SWF used a bad URI for the dc: namespace.
+
+ // ! This code presumes the RDF namespace prefix is "rdf".
+
+ size_t sepPos = strlen(fullName);
+ for ( --sepPos; sepPos > 0; --sepPos ) {
+ if ( fullName[sepPos] == FullNameSeparator ) break;
+ }
+
+ if ( fullName[sepPos] == FullNameSeparator ) {
+
+ XMP_StringPtr prefix;
+ XMP_StringPtr localPart = fullName + sepPos + 1;
+
+ node->ns.assign ( fullName, sepPos );
+ if ( node->ns == "http://purl.org/dc/1.1/" ) node->ns = "http://purl.org/dc/elements/1.1/";
+ bool found = XMPMeta::GetNamespacePrefix ( node->ns.c_str(), &prefix, &voidStringLen );
+ if ( ! found ) XMP_Throw ( "Unknown URI in Expat full name", kXMPErr_ExternalFailure );
+
+ node->name = prefix;
+ node->name += localPart;
+
+ } else {
+
+ node->name = fullName; // The name is not in a namespace.
+
+ if ( node->parent->name == "rdf:Description" ) {
+ if ( node->name == "about" ) {
+ node->ns = kXMP_NS_RDF;
+ node->name = "rdf:about";
+ } else if ( node->name == "ID" ) {
+ node->ns = kXMP_NS_RDF;
+ node->name = "rdf:ID";
+ }
+ }
+
+ }
+
+} // SetQualName
+
+// =================================================================================================
+
+static void StartNamespaceDeclHandler ( void * userData, XMP_StringPtr prefix, XMP_StringPtr uri )
+{
+ IgnoreParam(userData);
+
+ // As a bug fix hack, change a URI of "http://purl.org/dc/1.1/" to ""http://purl.org/dc/elements/1.1/.
+ // Early versions of Flash that put XMP in SWF used a bad URI for the dc: namespace.
+
+ #if XMP_DebugBuild & DumpXMLParseEvents // Avoid unused variable warning.
+ ExpatAdapter * thiz = (ExpatAdapter*)userData;
+ #endif
+
+ if ( prefix == 0 ) prefix = "_dflt_"; // Have default namespace.
+ if ( uri == 0 ) return; // Ignore, have xmlns:pre="", no URI to register.
+
+ #if XMP_DebugBuild & DumpXMLParseEvents
+ if ( thiz->parseLog != 0 ) {
+ PrintIndent ( thiz->parseLog, thiz->nesting );
+ fprintf ( thiz->parseLog, "StartNamespace: %s - \"%s\"\n", prefix, uri );
+ }
+ #endif
+
+ if ( XMP_LitMatch ( uri, "http://purl.org/dc/1.1/" ) ) uri = "http://purl.org/dc/elements/1.1/";
+ (void) XMPMeta::RegisterNamespace ( uri, prefix, &voidStringPtr, &voidStringLen );
+
+} // StartNamespaceDeclHandler
+
+// =================================================================================================
+
+static void EndNamespaceDeclHandler ( void * userData, XMP_StringPtr prefix )
+{
+ IgnoreParam(userData);
+
+ #if XMP_DebugBuild & DumpXMLParseEvents // Avoid unused variable warning.
+ ExpatAdapter * thiz = (ExpatAdapter*)userData;
+ #endif
+
+ if ( prefix == 0 ) prefix = "_dflt_"; // Have default namespace.
+
+ #if XMP_DebugBuild & DumpXMLParseEvents
+ if ( thiz->parseLog != 0 ) {
+ PrintIndent ( thiz->parseLog, thiz->nesting );
+ fprintf ( thiz->parseLog, "EndNamespace: %s\n", prefix );
+ }
+ #endif
+
+ // ! Nothing to do, Expat has done all of the XML processing.
+
+} // EndNamespaceDeclHandler
+
+// =================================================================================================
+
+static void StartElementHandler ( void * userData, XMP_StringPtr name, XMP_StringPtr* attrs )
+{
+ XMP_Assert ( attrs != 0 );
+ ExpatAdapter * thiz = (ExpatAdapter*)userData;
+
+ size_t attrCount = 0;
+ for ( XMP_StringPtr* a = attrs; *a != 0; ++a ) ++attrCount;
+ if ( (attrCount & 1) != 0 ) XMP_Throw ( "Expat attribute info has odd length", kXMPErr_ExternalFailure );
+ attrCount = attrCount/2; // They are name/value pairs.
+
+ #if XMP_DebugBuild & DumpXMLParseEvents
+ if ( thiz->parseLog != 0 ) {
+ PrintIndent ( thiz->parseLog, thiz->nesting );
+ fprintf ( thiz->parseLog, "StartElement: %s, %d attrs", name, attrCount );
+ for ( XMP_StringPtr* attr = attrs; *attr != 0; attr += 2 ) {
+ XMP_StringPtr attrName = *attr;
+ XMP_StringPtr attrValue = *(attr+1);
+ fprintf ( thiz->parseLog, ", %s = \"%s\"", attrName, attrValue );
+ }
+ fprintf ( thiz->parseLog, "\n" );
+ }
+ #endif
+
+ XML_Node * parentNode = thiz->parseStack.back();
+ XML_Node * elemNode = new XML_Node ( parentNode, "", kElemNode );
+
+ SetQualName ( name, elemNode );
+
+ for ( XMP_StringPtr* attr = attrs; *attr != 0; attr += 2 ) {
+
+ XMP_StringPtr attrName = *attr;
+ XMP_StringPtr attrValue = *(attr+1);
+ XML_Node * attrNode = new XML_Node ( elemNode, "", kAttrNode );
+
+ SetQualName ( attrName, attrNode );
+ attrNode->value = attrValue;
+ if ( attrNode->name == "xml:lang" ) NormalizeLangValue ( &attrNode->value );
+ elemNode->attrs.push_back ( attrNode );
+
+ }
+
+ parentNode->content.push_back ( elemNode );
+ thiz->parseStack.push_back ( elemNode );
+
+ if ( (elemNode->name == "rdf:RDF") || (elemNode->name == "pxmp:XMP_Packet") ) {
+ thiz->rootNode = elemNode;
+ ++thiz->rootCount;
+ }
+
+ ++thiz->nesting;
+
+} // StartElementHandler
+
+// =================================================================================================
+
+static void EndElementHandler ( void * userData, XMP_StringPtr name )
+{
+ IgnoreParam(name);
+
+ ExpatAdapter * thiz = (ExpatAdapter*)userData;
+
+ --thiz->nesting;
+ (void) thiz->parseStack.pop_back();
+
+ #if XMP_DebugBuild & DumpXMLParseEvents
+ if ( thiz->parseLog != 0 ) {
+ PrintIndent ( thiz->parseLog, thiz->nesting );
+ fprintf ( thiz->parseLog, "EndElement: %s\n", name );
+ }
+ #endif
+
+} // EndElementHandler
+
+// =================================================================================================
+
+static void CharacterDataHandler ( void * userData, XMP_StringPtr cData, int len )
+{
+ ExpatAdapter * thiz = (ExpatAdapter*)userData;
+
+ if ( (cData == 0) || (len == 0) ) { cData = ""; len = 0; }
+
+ #if XMP_DebugBuild & DumpXMLParseEvents
+ if ( thiz->parseLog != 0 ) {
+ PrintIndent ( thiz->parseLog, thiz->nesting );
+ fprintf ( thiz->parseLog, "CharContent: \"" );
+ for ( ; len > 0; --len, ++cData ) fprintf ( thiz->parseLog, "%c", *cData );
+ fprintf ( thiz->parseLog, "\"\n" );
+ }
+ #endif
+
+ XML_Node * parentNode = thiz->parseStack.back();
+ XML_Node * cDataNode = new XML_Node ( parentNode, "", kCDataNode );
+
+ cDataNode->value.assign ( cData, len );
+ parentNode->content.push_back ( cDataNode );
+
+} // CharacterDataHandler
+
+// =================================================================================================
+
+static void StartCdataSectionHandler ( void * userData )
+{
+ IgnoreParam(userData);
+
+ #if XMP_DebugBuild & DumpXMLParseEvents // Avoid unused variable warning.
+ ExpatAdapter * thiz = (ExpatAdapter*)userData;
+ #endif
+
+ #if XMP_DebugBuild & DumpXMLParseEvents
+ if ( thiz->parseLog != 0 ) {
+ PrintIndent ( thiz->parseLog, thiz->nesting );
+ fprintf ( thiz->parseLog, "StartCDATA\n" );
+ }
+ #endif
+
+ // *** Since markup isn't recognized inside CDATA, this affects XMP's double escaping.
+
+} // StartCdataSectionHandler
+
+// =================================================================================================
+
+static void EndCdataSectionHandler ( void * userData )
+{
+ IgnoreParam(userData);
+
+ #if XMP_DebugBuild & DumpXMLParseEvents // Avoid unused variable warning.
+ ExpatAdapter * thiz = (ExpatAdapter*)userData;
+ #endif
+
+ #if XMP_DebugBuild & DumpXMLParseEvents
+ if ( thiz->parseLog != 0 ) {
+ PrintIndent ( thiz->parseLog, thiz->nesting );
+ fprintf ( thiz->parseLog, "EndCDATA\n" );
+ }
+ #endif
+
+} // EndCdataSectionHandler
+
+// =================================================================================================
+
+static void ProcessingInstructionHandler ( void * userData, XMP_StringPtr target, XMP_StringPtr data )
+{
+ XMP_Assert ( target != 0 );
+ ExpatAdapter * thiz = (ExpatAdapter*)userData;
+
+ if ( ! XMP_LitMatch ( target, "xpacket" ) ) return; // Ignore all PIs except the XMP packet wrapper.
+ if ( data == 0 ) data = "";
+
+ #if XMP_DebugBuild & DumpXMLParseEvents
+ if ( thiz->parseLog != 0 ) {
+ PrintIndent ( thiz->parseLog, thiz->nesting );
+ fprintf ( thiz->parseLog, "PI: %s - \"%s\"\n", target, data );
+ }
+ #endif
+
+ XML_Node * parentNode = thiz->parseStack.back();
+ XML_Node * piNode = new XML_Node ( parentNode, target, kPINode );
+
+ piNode->value.assign ( data );
+ parentNode->content.push_back ( piNode );
+
+} // ProcessingInstructionHandler
+
+// =================================================================================================
+
+static void CommentHandler ( void * userData, XMP_StringPtr comment )
+{
+ IgnoreParam(userData);
+
+ #if XMP_DebugBuild & DumpXMLParseEvents // Avoid unused variable warning.
+ ExpatAdapter * thiz = (ExpatAdapter*)userData;
+ #endif
+
+ if ( comment == 0 ) comment = "";
+
+ #if XMP_DebugBuild & DumpXMLParseEvents
+ if ( thiz->parseLog != 0 ) {
+ PrintIndent ( thiz->parseLog, thiz->nesting );
+ fprintf ( thiz->parseLog, "Comment: \"%s\"\n", comment );
+ }
+ #endif
+
+ // ! Comments are ignored.
+
+} // CommentHandler
+
+// =================================================================================================
+
+static void DefaultHandler ( void * userData, XMP_StringPtr data, int len )
+{
+ IgnoreParam(userData);
+
+ #if XMP_DebugBuild & DumpXMLParseEvents // Avoid unused variable warning.
+ ExpatAdapter * thiz = (ExpatAdapter*)userData;
+ #endif
+
+ if ( (data == 0) || (len == 0) ) { data = ""; len = 0; }
+
+ #if XMP_DebugBuild & DumpXMLParseEvents
+ if ( thiz->parseLog != 0 ) {
+ PrintIndent ( thiz->parseLog, thiz->nesting );
+ fprintf ( thiz->parseLog, ">>default<<: \"" );
+ for ( ; len > 0; --len, ++data ) fprintf ( thiz->parseLog, "%c", *data );
+ fprintf ( thiz->parseLog, "\"\n" );
+ }
+ #endif
+
+ // *** Ignore for now. Complain if not whitespace?
+
+} // DefaultHandler
+
+// =================================================================================================
diff --git a/source/XMPCore/ExpatAdapter.hpp b/source/XMPCore/ExpatAdapter.hpp
new file mode 100644
index 0000000..ffe23b3
--- /dev/null
+++ b/source/XMPCore/ExpatAdapter.hpp
@@ -0,0 +1,38 @@
+#ifndef __ExpatAdapter_hpp__
+#define __ExpatAdapter_hpp__
+
+// =================================================================================================
+// Copyright 2005-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "XMP_Environment.h" // ! Must be the first #include!
+#include "XMLParserAdapter.hpp"
+
+#if UsePublicExpat
+ #include "expat.h"
+#endif
+
+// =================================================================================================
+// Derived XML parser adapter for Expat.
+// =================================================================================================
+
+class ExpatAdapter : public XMLParserAdapter {
+public:
+
+ XML_Parser parser;
+ size_t nesting;
+
+ ExpatAdapter();
+ virtual ~ExpatAdapter();
+
+ void ParseBuffer ( const void * buffer, size_t length, bool last );
+
+};
+
+// =================================================================================================
+
+#endif // __ExpatAdapter_hpp__
diff --git a/source/XMPCore/ParseRDF.cpp b/source/XMPCore/ParseRDF.cpp
new file mode 100644
index 0000000..575b617
--- /dev/null
+++ b/source/XMPCore/ParseRDF.cpp
@@ -0,0 +1,1344 @@
+// =================================================================================================
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "XMP_Environment.h" // ! This must be the first include!
+#include "XMPCore_Impl.hpp"
+
+#include <cstring>
+
+#if DEBUG
+ #include <iostream>
+#endif
+
+using namespace std;
+
+#if XMP_WinBuild
+ #pragma warning ( disable : 4189 ) // local variable is initialized but not referenced
+ #pragma warning ( disable : 4505 ) // unreferenced local function has been removed
+#endif
+
+// =================================================================================================
+
+// *** This might be faster and use less memory as a state machine. A big advantage of building an
+// *** XML tree though is easy lookahead during the recursive descent processing.
+
+// *** It would be nice to give a line number or byte offset in the exception messages.
+
+
+// 7 RDF/XML Grammar (from http://www.w3.org/TR/rdf-syntax-grammar/#section-Infoset-Grammar)
+//
+// 7.1 Grammar summary
+//
+// 7.2.2 coreSyntaxTerms
+// rdf:RDF | rdf:ID | rdf:about | rdf:parseType | rdf:resource | rdf:nodeID | rdf:datatype
+//
+// 7.2.3 syntaxTerms
+// coreSyntaxTerms | rdf:Description | rdf:li
+//
+// 7.2.4 oldTerms
+// rdf:aboutEach | rdf:aboutEachPrefix | rdf:bagID
+//
+// 7.2.5 nodeElementURIs
+// anyURI - ( coreSyntaxTerms | rdf:li | oldTerms )
+//
+// 7.2.6 propertyElementURIs
+// anyURI - ( coreSyntaxTerms | rdf:Description | oldTerms )
+//
+// 7.2.7 propertyAttributeURIs
+// anyURI - ( coreSyntaxTerms | rdf:Description | rdf:li | oldTerms )
+//
+// 7.2.8 doc
+// root ( document-element == RDF, children == list ( RDF ) )
+//
+// 7.2.9 RDF
+// start-element ( URI == rdf:RDF, attributes == set() )
+// nodeElementList
+// end-element()
+//
+// 7.2.10 nodeElementList
+// ws* ( nodeElement ws* )*
+//
+// 7.2.11 nodeElement
+// start-element ( URI == nodeElementURIs,
+// attributes == set ( ( idAttr | nodeIdAttr | aboutAttr )?, propertyAttr* ) )
+// propertyEltList
+// end-element()
+//
+// 7.2.12 ws
+// A text event matching white space defined by [XML] definition White Space Rule [3] S in section Common Syntactic Constructs.
+//
+// 7.2.13 propertyEltList
+// ws* ( propertyElt ws* )*
+//
+// 7.2.14 propertyElt
+// resourcePropertyElt | literalPropertyElt | parseTypeLiteralPropertyElt |
+// parseTypeResourcePropertyElt | parseTypeCollectionPropertyElt | parseTypeOtherPropertyElt | emptyPropertyElt
+//
+// 7.2.15 resourcePropertyElt
+// start-element ( URI == propertyElementURIs, attributes == set ( idAttr? ) )
+// ws* nodeElement ws*
+// end-element()
+//
+// 7.2.16 literalPropertyElt
+// start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, datatypeAttr?) )
+// text()
+// end-element()
+//
+// 7.2.17 parseTypeLiteralPropertyElt
+// start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, parseLiteral ) )
+// literal
+// end-element()
+//
+// 7.2.18 parseTypeResourcePropertyElt
+// start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, parseResource ) )
+// propertyEltList
+// end-element()
+//
+// 7.2.19 parseTypeCollectionPropertyElt
+// start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, parseCollection ) )
+// nodeElementList
+// end-element()
+//
+// 7.2.20 parseTypeOtherPropertyElt
+// start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, parseOther ) )
+// propertyEltList
+// end-element()
+//
+// 7.2.21 emptyPropertyElt
+// start-element ( URI == propertyElementURIs,
+// attributes == set ( idAttr?, ( resourceAttr | nodeIdAttr )?, propertyAttr* ) )
+// end-element()
+//
+// 7.2.22 idAttr
+// attribute ( URI == rdf:ID, string-value == rdf-id )
+//
+// 7.2.23 nodeIdAttr
+// attribute ( URI == rdf:nodeID, string-value == rdf-id )
+//
+// 7.2.24 aboutAttr
+// attribute ( URI == rdf:about, string-value == URI-reference )
+//
+// 7.2.25 propertyAttr
+// attribute ( URI == propertyAttributeURIs, string-value == anyString )
+//
+// 7.2.26 resourceAttr
+// attribute ( URI == rdf:resource, string-value == URI-reference )
+//
+// 7.2.27 datatypeAttr
+// attribute ( URI == rdf:datatype, string-value == URI-reference )
+//
+// 7.2.28 parseLiteral
+// attribute ( URI == rdf:parseType, string-value == "Literal")
+//
+// 7.2.29 parseResource
+// attribute ( URI == rdf:parseType, string-value == "Resource")
+//
+// 7.2.30 parseCollection
+// attribute ( URI == rdf:parseType, string-value == "Collection")
+//
+// 7.2.31 parseOther
+// attribute ( URI == rdf:parseType, string-value == anyString - ("Resource" | "Literal" | "Collection") )
+//
+// 7.2.32 URI-reference
+// An RDF URI Reference.
+//
+// 7.2.33 literal
+// Any XML element content that is allowed according to [XML] definition Content of Elements Rule [43] content
+// in section 3.1 Start-Tags, End-Tags, and Empty-Element Tags.
+//
+// 7.2.34 rdf-id
+// An attribute string-value matching any legal [XML-NS] token NCName.
+
+
+// =================================================================================================
+// Primary Parsing Functions
+// =========================
+//
+// Each of these 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.
+
+static void
+RDF_RDF ( XMP_Node * xmpTree, const XML_Node & xmlNode );
+
+static void
+RDF_NodeElementList ( XMP_Node * xmpParent, const XML_Node & xmlParent, bool isTopLevel );
+
+static void
+RDF_NodeElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel );
+
+static void
+RDF_NodeElementAttrs ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel );
+
+static void
+RDF_PropertyElementList ( XMP_Node * xmpParent, const XML_Node & xmlParent, bool isTopLevel );
+enum { kIsTopLevel = true, kNotTopLevel = false };
+
+static void
+RDF_PropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel );
+
+static void
+RDF_ResourcePropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel );
+
+static void
+RDF_LiteralPropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel );
+
+static void
+RDF_ParseTypeLiteralPropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel );
+
+static void
+RDF_ParseTypeResourcePropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel );
+
+static void
+RDF_ParseTypeCollectionPropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel );
+
+static void
+RDF_ParseTypeOtherPropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel );
+
+static void
+RDF_EmptyPropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel );
+
+
+// =================================================================================================
+
+typedef XMP_Uns8 RDFTermKind;
+
+// *** Logic might be safer with just masks.
+
+enum {
+ kRDFTerm_Other = 0,
+ kRDFTerm_RDF = 1, // Start of coreSyntaxTerms.
+ kRDFTerm_ID = 2,
+ kRDFTerm_about = 3,
+ kRDFTerm_parseType = 4,
+ kRDFTerm_resource = 5,
+ kRDFTerm_nodeID = 6,
+ kRDFTerm_datatype = 7, // End of coreSyntaxTerms.
+ kRDFTerm_Description = 8, // Start of additions for syntaxTerms.
+ kRDFTerm_li = 9, // End of of additions for syntaxTerms.
+ kRDFTerm_aboutEach = 10, // Start of oldTerms.
+ kRDFTerm_aboutEachPrefix = 11,
+ kRDFTerm_bagID = 12, // End of oldTerms.
+
+ kRDFTerm_FirstCore = kRDFTerm_RDF,
+ kRDFTerm_LastCore = kRDFTerm_datatype,
+ kRDFTerm_FirstSyntax = kRDFTerm_FirstCore, // ! Yes, the syntax terms include the core terms.
+ kRDFTerm_LastSyntax = kRDFTerm_li,
+ kRDFTerm_FirstOld = kRDFTerm_aboutEach,
+ kRDFTerm_LastOld = kRDFTerm_bagID
+};
+
+enum {
+ kRDFMask_Other = 1 << kRDFTerm_Other,
+ kRDFMask_RDF = 1 << kRDFTerm_RDF,
+ kRDFMask_ID = 1 << kRDFTerm_ID,
+ kRDFMask_about = 1 << kRDFTerm_about,
+ kRDFMask_parseType = 1 << kRDFTerm_parseType,
+ kRDFMask_resource = 1 << kRDFTerm_resource,
+ kRDFMask_nodeID = 1 << kRDFTerm_nodeID,
+ kRDFMask_datatype = 1 << kRDFTerm_datatype,
+ kRDFMask_Description = 1 << kRDFTerm_Description,
+ kRDFMask_li = 1 << kRDFTerm_li,
+ kRDFMask_aboutEach = 1 << kRDFTerm_aboutEach,
+ kRDFMask_aboutEachPrefix = 1 << kRDFTerm_aboutEachPrefix,
+ kRDFMask_bagID = 1 << kRDFTerm_bagID
+};
+
+enum {
+ kRDF_HasValueElem = 0x10000000UL // ! Contains rdf:value child. Must fit within kXMP_ImplReservedMask!
+};
+
+// -------------------------------------------------------------------------------------------------
+// GetRDFTermKind
+// --------------
+
+static RDFTermKind
+GetRDFTermKind ( const XMP_VarString & name )
+{
+ RDFTermKind term = kRDFTerm_Other;
+
+ // Arranged to hopefully minimize the parse time for large XMP.
+
+ if ( (name.size() > 4) && (strncmp ( name.c_str(), "rdf:", 4 ) == 0) ) {
+
+ if ( name == "rdf:li" ) {
+ term = kRDFTerm_li;
+ } else if ( name == "rdf:parseType" ) {
+ term = kRDFTerm_parseType;
+ } else if ( name == "rdf:Description" ) {
+ term = kRDFTerm_Description;
+ } else if ( name == "rdf:about" ) {
+ term = kRDFTerm_about;
+ } else if ( name == "rdf:resource" ) {
+ term = kRDFTerm_resource;
+ } else if ( name == "rdf:RDF" ) {
+ term = kRDFTerm_RDF;
+ } else if ( name == "rdf:ID" ) {
+ term = kRDFTerm_ID;
+ } else if ( name == "rdf:nodeID" ) {
+ term = kRDFTerm_nodeID;
+ } else if ( name == "rdf:datatype" ) {
+ term = kRDFTerm_datatype;
+ } else if ( name == "rdf:aboutEach" ) {
+ term = kRDFTerm_aboutEach;
+ } else if ( name == "rdf:aboutEachPrefix" ) {
+ term = kRDFTerm_aboutEachPrefix;
+ } else if ( name == "rdf:bagID" ) {
+ term = kRDFTerm_bagID;
+ }
+
+ }
+
+ return term;
+
+} // GetRDFTermKind
+
+
+// =================================================================================================
+
+
+// -------------------------------------------------------------------------------------------------
+// IsCoreSyntaxTerm
+// ----------------
+//
+// 7.2.2 coreSyntaxTerms
+// rdf:RDF | rdf:ID | rdf:about | rdf:parseType | rdf:resource | rdf:nodeID | rdf:datatype
+
+static bool
+IsCoreSyntaxTerm ( RDFTermKind term )
+{
+
+ if ( (kRDFTerm_FirstCore <= term) && (term <= kRDFTerm_LastCore) ) return true;
+ return false;
+
+} // IsCoreSyntaxTerm
+
+// -------------------------------------------------------------------------------------------------
+// IsSyntaxTerm
+// ------------
+//
+// 7.2.3 syntaxTerms
+// coreSyntaxTerms | rdf:Description | rdf:li
+
+static bool
+IsSyntaxTerm ( RDFTermKind term )
+{
+
+ if ( (kRDFTerm_FirstSyntax <= term) && (term <= kRDFTerm_LastSyntax) ) return true;
+ return false;
+
+} // IsSyntaxTerm
+
+// -------------------------------------------------------------------------------------------------
+// IsOldTerm
+// ---------
+//
+// 7.2.4 oldTerms
+// rdf:aboutEach | rdf:aboutEachPrefix | rdf:bagID
+
+static bool
+IsOldTerm ( RDFTermKind term )
+{
+
+ if ( (kRDFTerm_FirstOld <= term) && (term <= kRDFTerm_LastOld) ) return true;
+ return false;
+
+} // IsOldTerm
+
+// -------------------------------------------------------------------------------------------------
+// IsNodeElementName
+// -----------------
+//
+// 7.2.5 nodeElementURIs
+// anyURI - ( coreSyntaxTerms | rdf:li | oldTerms )
+
+static bool
+IsNodeElementName ( RDFTermKind term )
+{
+
+ if ( (term == kRDFTerm_li) || IsOldTerm ( term ) ) return false;
+ return (! IsCoreSyntaxTerm ( term ));
+
+} // IsNodeElementName
+
+// -------------------------------------------------------------------------------------------------
+// IsPropertyElementName
+// ---------------------
+//
+// 7.2.6 propertyElementURIs
+// anyURI - ( coreSyntaxTerms | rdf:Description | oldTerms )
+
+static bool
+IsPropertyElementName ( RDFTermKind term )
+{
+
+ if ( (term == kRDFTerm_Description) || IsOldTerm ( term ) ) return false;
+ return (! IsCoreSyntaxTerm ( term ));
+
+} // IsPropertyElementName
+
+// -------------------------------------------------------------------------------------------------
+// IsPropertyAttributeName
+// -----------------------
+//
+// 7.2.7 propertyAttributeURIs
+// anyURI - ( coreSyntaxTerms | rdf:Description | rdf:li | oldTerms )
+
+static bool
+IsPropertyAttributeName ( RDFTermKind term )
+{
+
+ if ( (term == kRDFTerm_Description) || (term == kRDFTerm_li) || IsOldTerm ( term ) ) return false;
+ return (! IsCoreSyntaxTerm ( term ));
+
+} // IsPropertyAttributeName
+
+
+// =================================================================================================
+// AddChildNode
+// ============
+
+static XMP_Node *
+AddChildNode ( XMP_Node * xmpParent, const XML_Node & xmlNode, const XMP_StringPtr value, bool isTopLevel )
+{
+ #if 0
+ cout << "AddChildNode, parent = " << xmpParent->name << ", child = " << xmlNode.name;
+ cout << ", value = \"" << value << '"';
+ if ( isTopLevel ) cout << ", top level";
+ cout << endl;
+ #endif
+
+ if ( xmlNode.ns.empty() ) {
+ XMP_Throw ( "XML namespace required for all elements and attributes", kXMPErr_BadRDF );
+ }
+
+ XMP_StringPtr childName = xmlNode.name.c_str();
+ const bool isArrayItem = (xmlNode.name == "rdf:li");
+ const bool isValueNode = (xmlNode.name == "rdf:value");
+ XMP_OptionBits childOptions = 0;
+
+ if ( isTopLevel ) {
+
+ // Lookup the schema node, adjust the XMP parent pointer.
+ XMP_Assert ( xmpParent->parent == 0 ); // Incoming parent must be the tree root.
+ XMP_Node * schemaNode = FindSchemaNode ( xmpParent, xmlNode.ns.c_str(), kXMP_CreateNodes );
+ if ( schemaNode->options & kXMP_NewImplicitNode ) schemaNode->options ^= kXMP_NewImplicitNode; // Clear the implicit node bit.
+ // *** Should use "opt &= ~flag" (no conditional), need runtime check for proper 32 bit code.
+ xmpParent = schemaNode;
+
+ // If this is an alias set the isAlias flag in the node and the hasAliases flag in the tree.
+ if ( sRegisteredAliasMap->find ( xmlNode.name ) != sRegisteredAliasMap->end() ) {
+ childOptions |= kXMP_PropIsAlias;
+ schemaNode->parent->options |= kXMP_PropHasAliases;
+ }
+
+ }
+
+ // Make sure that this is not a duplicate of a named node.
+ if ( ! (isArrayItem | isValueNode) ) {
+ if ( FindChildNode ( xmpParent, childName, kXMP_ExistingOnly ) != 0 ) {
+ XMP_Throw ( "Duplicate property or field node", kXMPErr_BadXMP );
+ }
+
+ }
+
+ // Add the new child to the XMP parent node.
+ XMP_Node * newChild = new XMP_Node ( xmpParent, childName, value, childOptions );
+ if ( (! isValueNode) || xmpParent->children.empty() ) {
+ xmpParent->children.push_back ( newChild );
+ } else {
+ xmpParent->children.insert ( xmpParent->children.begin(), newChild );
+ }
+ if ( isValueNode ) {
+ if ( isTopLevel || (! (xmpParent->options & kXMP_PropValueIsStruct)) ) XMP_Throw ( "Misplaced rdf:value element", kXMPErr_BadRDF );
+ xmpParent->options |= kRDF_HasValueElem;
+ }
+
+ if ( isArrayItem ) {
+ if ( ! (xmpParent->options & kXMP_PropValueIsArray) ) XMP_Throw ( "Misplaced rdf:li element", kXMPErr_BadRDF );
+ newChild->name = kXMP_ArrayItemName;
+ #if 0 // *** XMP_DebugBuild
+ newChild->_namePtr = newChild->name.c_str();
+ #endif
+ }
+
+ return newChild;
+
+} // AddChildNode
+
+
+// =================================================================================================
+// AddQualifierNode
+// ================
+
+static XMP_Node *
+AddQualifierNode ( XMP_Node * xmpParent, const XMP_VarString & name, const XMP_VarString & value )
+{
+
+ #if 0
+ cout << "AddQualifierNode, parent = " << xmpParent->name << ", name = " << name;
+ cout << ", value = \"" << value << '"' << endl;
+ #endif
+
+ const bool isLang = (name == "xml:lang");
+ const bool isType = (name == "rdf:type");
+
+ XMP_Node * newQual = 0;
+
+ newQual = new XMP_Node ( xmpParent, name, value, kXMP_PropIsQualifier );
+
+ if ( ! (isLang | isType) ) {
+ xmpParent->qualifiers.push_back ( newQual );
+ } else if ( isLang ) {
+ if ( xmpParent->qualifiers.empty() ) {
+ xmpParent->qualifiers.push_back ( newQual );
+ } else {
+ xmpParent->qualifiers.insert ( xmpParent->qualifiers.begin(), newQual );
+ }
+ xmpParent->options |= kXMP_PropHasLang;
+ } else {
+ XMP_Assert ( isType );
+ if ( xmpParent->qualifiers.empty() ) {
+ xmpParent->qualifiers.push_back ( newQual );
+ } else {
+ size_t offset = 0;
+ if ( XMP_PropHasLang ( xmpParent->options ) ) offset = 1;
+ xmpParent->qualifiers.insert ( xmpParent->qualifiers.begin()+offset, newQual );
+ }
+ xmpParent->options |= kXMP_PropHasType;
+ }
+
+ xmpParent->options |= kXMP_PropHasQualifiers; // ! Don't set for the pxmp:compact.
+
+ return newQual;
+
+} // AddQualifierNode
+
+
+// =================================================================================================
+// AddQualifierNode
+// ================
+
+static XMP_Node *
+AddQualifierNode ( XMP_Node * xmpParent, const XML_Node & attr )
+{
+ if ( attr.ns.empty() ) {
+ XMP_Throw ( "XML namespace required for all elements and attributes", kXMPErr_BadRDF );
+ }
+
+ return AddQualifierNode ( xmpParent, attr.name, attr.value );
+
+} // AddQualifierNode
+
+
+// =================================================================================================
+// FixupQualifiedNode
+// ==================
+//
+// The parent is an RDF pseudo-struct containing an rdf:value field. Fix the XMP data model. The
+// rdf:value node must be the first child, the other children are qualifiers. The form, value, and
+// children of the rdf:value node are the real ones. The rdf:value node's qualifiers must be added
+// to the others.
+
+static void
+FixupQualifiedNode ( XMP_Node * xmpParent )
+{
+ size_t qualNum, qualLim;
+ size_t childNum, childLim;
+
+ XMP_Enforce ( (xmpParent->options & kXMP_PropValueIsStruct) && (! xmpParent->children.empty()) );
+
+ XMP_Node * valueNode = xmpParent->children[0];
+ XMP_Enforce ( valueNode->name == "rdf:value" );
+
+ xmpParent->qualifiers.reserve ( xmpParent->qualifiers.size() + xmpParent->children.size() + valueNode->qualifiers.size() );
+
+ // Move the qualifiers on the value node to the parent. Make sure an xml:lang qualifier stays at
+ // the front. Check for duplicate names between the value node's qualifiers and the parent's
+ // children. The parent's children are about to become qualifiers. Check here, between the
+ // groups. Intra-group duplicates are caught by AddChildNode.
+
+ qualNum = 0;
+ qualLim = valueNode->qualifiers.size();
+
+ if ( valueNode->options & kXMP_PropHasLang ) {
+
+ if ( xmpParent->options & kXMP_PropHasLang ) XMP_Throw ( "Redundant xml:lang for rdf:value element", kXMPErr_BadXMP );
+
+ XMP_Node * langQual = valueNode->qualifiers[0];
+
+ XMP_Assert ( langQual->name == "xml:lang" );
+ langQual->parent = xmpParent;
+ xmpParent->options |= kXMP_PropHasLang;
+
+ if ( xmpParent->qualifiers.empty() ) {
+ xmpParent->qualifiers.push_back ( langQual ); // *** Should use utilities to add qual & set parent.
+ } else {
+ xmpParent->qualifiers.insert ( xmpParent->qualifiers.begin(), langQual );
+ }
+ valueNode->qualifiers[0] = 0; // We just moved it to the parent.
+
+ qualNum = 1; // Start the remaining copy after the xml:lang qualifier.
+
+ }
+
+ for ( ; qualNum != qualLim; ++qualNum ) {
+
+ XMP_Node * currQual = valueNode->qualifiers[qualNum];
+ if ( FindChildNode ( xmpParent, currQual->name.c_str(), kXMP_ExistingOnly ) != 0 ) {
+ XMP_Throw ( "Duplicate qualifier node", kXMPErr_BadXMP );
+ }
+
+ currQual->parent = xmpParent;
+ xmpParent->qualifiers.push_back ( currQual );
+ valueNode->qualifiers[qualNum] = 0; // We just moved it to the parent.
+
+ }
+
+ valueNode->qualifiers.clear(); // ! There should be nothing but null pointers.
+
+ // Change the parent's other children into qualifiers. This loop starts at 1, child 0 is the
+ // rdf:value node. Put xml:lang at the front, append all others.
+
+ for ( childNum = 1, childLim = xmpParent->children.size(); childNum != childLim; ++childNum ) {
+
+ XMP_Node * currQual = xmpParent->children[childNum];
+
+ bool isLang = (currQual->name == "xml:lang");
+
+ currQual->options |= kXMP_PropIsQualifier;
+ currQual->parent = xmpParent;
+
+ if ( isLang ) {
+ if ( xmpParent->options & kXMP_PropHasLang ) XMP_Throw ( "Duplicate xml:lang qualifier", kXMPErr_BadXMP );
+ xmpParent->options |= kXMP_PropHasLang;
+ } else if ( currQual->name == "rdf:type" ) {
+ xmpParent->options |= kXMP_PropHasType;
+ }
+
+ if ( (! isLang) || xmpParent->qualifiers.empty() ) {
+ xmpParent->qualifiers.push_back ( currQual );
+ } else {
+ xmpParent->qualifiers.insert ( xmpParent->qualifiers.begin(), currQual );
+ }
+ xmpParent->children[childNum] = 0; // We just moved it to the qualifers.
+
+ }
+
+ if ( ! xmpParent->qualifiers.empty() ) xmpParent->options |= kXMP_PropHasQualifiers;
+
+ // Move the options and value last, other checks need the parent's original options. Move the
+ // value node's children to be the parent's children. Delete the now useless value node.
+
+ XMP_Assert ( xmpParent->options & (kXMP_PropValueIsStruct | kRDF_HasValueElem) );
+ xmpParent->options &= ~ (kXMP_PropValueIsStruct | kRDF_HasValueElem);
+ xmpParent->options |= valueNode->options;
+
+ xmpParent->value.swap ( valueNode->value );
+ #if 0 // *** XMP_DebugBuild
+ xmpParent->_valuePtr = xmpParent->value.c_str();
+ #endif
+
+ xmpParent->children[0] = 0; // ! Remove the value node itself before the swap.
+ xmpParent->children.swap ( valueNode->children );
+
+ for ( size_t childNum = 0, childLim = xmpParent->children.size(); childNum != childLim; ++childNum ) {
+ XMP_Node * currChild = xmpParent->children[childNum];
+ currChild->parent = xmpParent;
+ }
+
+ delete valueNode;
+
+} // FixupQualifiedNode
+
+
+// =================================================================================================
+// ProcessRDF
+// ==========
+//
+// Parse the XML tree of the RDF and build the corresponding XMP tree.
+
+// *** Throw an exception if no XMP is found? By option?
+// *** Do parsing exceptions cause the partial tree to be deleted?
+
+void ProcessRDF ( XMP_Node * xmpTree, const XML_Node & rdfNode, XMP_OptionBits options )
+{
+ IgnoreParam(options);
+
+ RDF_RDF ( xmpTree, rdfNode );
+
+} // ProcessRDF
+
+
+// =================================================================================================
+// RDF_RDF
+// =======
+//
+// 7.2.9 RDF
+// start-element ( URI == rdf:RDF, attributes == set() )
+// nodeElementList
+// end-element()
+//
+// The top level rdf:RDF node. It can only have xmlns attributes, which have already been removed
+// during construction of the XML tree.
+
+static void
+RDF_RDF ( XMP_Node * xmpTree, const XML_Node & xmlNode )
+{
+
+ if ( ! xmlNode.attrs.empty() ) XMP_Throw ( "Invalid attributes of rdf:RDF element", kXMPErr_BadRDF );
+ RDF_NodeElementList ( xmpTree, xmlNode, kIsTopLevel );
+
+} // RDF_RDF
+
+
+// =================================================================================================
+// RDF_NodeElementList
+// ===================
+//
+// 7.2.10 nodeElementList
+// ws* ( nodeElement ws* )*
+
+static void
+RDF_NodeElementList ( XMP_Node * xmpParent, const XML_Node & xmlParent, bool isTopLevel )
+{
+ XMP_Assert ( isTopLevel );
+
+ XML_cNodePos currChild = xmlParent.content.begin(); // *** Change these loops to the indexed pattern.
+ XML_cNodePos endChild = xmlParent.content.end();
+
+ for ( ; currChild != endChild; ++currChild ) {
+ if ( IsWhitespaceNode ( **currChild ) ) continue;
+ RDF_NodeElement ( xmpParent, **currChild, isTopLevel );
+ }
+
+} // RDF_NodeElementList
+
+
+// =================================================================================================
+// RDF_NodeElement
+// ===============
+//
+// 7.2.5 nodeElementURIs
+// anyURI - ( coreSyntaxTerms | rdf:li | oldTerms )
+//
+// 7.2.11 nodeElement
+// start-element ( URI == nodeElementURIs,
+// attributes == set ( ( idAttr | nodeIdAttr | aboutAttr )?, propertyAttr* ) )
+// propertyEltList
+// end-element()
+//
+// A node element URI is rdf:Description or anything else that is not an RDF term.
+
+static void
+RDF_NodeElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel )
+{
+ RDFTermKind nodeTerm = GetRDFTermKind ( xmlNode.name );
+ if ( (nodeTerm != kRDFTerm_Description) && (nodeTerm != kRDFTerm_Other) ) {
+ XMP_Throw ( "Node element must be rdf:Description or typedNode", kXMPErr_BadRDF );
+ }
+
+ if ( isTopLevel && (nodeTerm == kRDFTerm_Other) ) {
+ XMP_Throw ( "Top level typedNode not allowed", kXMPErr_BadXMP );
+ } else {
+ RDF_NodeElementAttrs ( xmpParent, xmlNode, isTopLevel );
+ RDF_PropertyElementList ( xmpParent, xmlNode, isTopLevel );
+ }
+
+} // RDF_NodeElement
+
+
+// =================================================================================================
+// RDF_NodeElementAttrs
+// ====================
+//
+// 7.2.7 propertyAttributeURIs
+// anyURI - ( coreSyntaxTerms | rdf:Description | rdf:li | oldTerms )
+//
+// 7.2.11 nodeElement
+// start-element ( URI == nodeElementURIs,
+// attributes == set ( ( idAttr | nodeIdAttr | aboutAttr )?, propertyAttr* ) )
+// propertyEltList
+// end-element()
+//
+// Process the attribute list for an RDF node element. A property attribute URI is anything other
+// than an RDF term. The rdf:ID and rdf:nodeID attributes are simply ignored, as are rdf:about
+// attributes on inner nodes.
+
+static const XMP_OptionBits kExclusiveAttrMask = (kRDFMask_ID | kRDFMask_nodeID | kRDFMask_about);
+
+static void
+RDF_NodeElementAttrs ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel )
+{
+ XMP_OptionBits exclusiveAttrs = 0; // Used to detect attributes that are mutually exclusive.
+
+ XML_cNodePos currAttr = xmlNode.attrs.begin();
+ XML_cNodePos endAttr = xmlNode.attrs.end();
+
+ for ( ; currAttr != endAttr; ++currAttr ) {
+
+ RDFTermKind attrTerm = GetRDFTermKind ( (*currAttr)->name );
+
+ switch ( attrTerm ) {
+
+ case kRDFTerm_ID :
+ case kRDFTerm_nodeID :
+ case kRDFTerm_about :
+
+ if ( exclusiveAttrs & kExclusiveAttrMask ) XMP_Throw ( "Mutally exclusive about, ID, nodeID attributes", kXMPErr_BadRDF );
+ exclusiveAttrs |= (1 << attrTerm);
+
+ if ( isTopLevel && (attrTerm == kRDFTerm_about) ) {
+ // This is the rdf:about attribute on a top level node. Set the XMP tree name if
+ // it doesn't have a name yet. Make sure this name matches the XMP tree name.
+ XMP_Assert ( xmpParent->parent == 0 ); // Must be the tree root node.
+ if ( ! xmpParent->name.empty() ) {
+ if ( xmpParent->name != (*currAttr)->value ) XMP_Throw ( "Mismatched top level rdf:about values", kXMPErr_BadXMP );
+ } else {
+ xmpParent->name = (*currAttr)->value;
+ #if 0 // *** XMP_DebugBuild
+ xmpParent->_namePtr = xmpParent->name.c_str();
+ #endif
+ }
+ }
+
+ break;
+
+ case kRDFTerm_Other :
+ AddChildNode ( xmpParent, **currAttr, (*currAttr)->value.c_str(), isTopLevel );
+ break;
+
+ default :
+ XMP_Throw ( "Invalid nodeElement attribute", kXMPErr_BadRDF );
+
+ }
+
+ }
+
+} // RDF_NodeElementAttrs
+
+
+// =================================================================================================
+// RDF_PropertyElementList
+// =======================
+//
+// 7.2.13 propertyEltList
+// ws* ( propertyElt ws* )*
+
+static void
+RDF_PropertyElementList ( XMP_Node * xmpParent, const XML_Node & xmlParent, bool isTopLevel )
+{
+ XML_cNodePos currChild = xmlParent.content.begin();
+ XML_cNodePos endChild = xmlParent.content.end();
+
+ for ( ; currChild != endChild; ++currChild ) {
+ if ( IsWhitespaceNode ( **currChild ) ) continue;
+ if ( (*currChild)->kind != kElemNode ) {
+ XMP_Throw ( "Expected property element node not found", kXMPErr_BadRDF );
+ }
+ RDF_PropertyElement ( xmpParent, **currChild, isTopLevel );
+ }
+
+} // RDF_PropertyElementList
+
+
+// =================================================================================================
+// RDF_PropertyElement
+// ===================
+//
+// 7.2.14 propertyElt
+// resourcePropertyElt | literalPropertyElt | parseTypeLiteralPropertyElt |
+// parseTypeResourcePropertyElt | parseTypeCollectionPropertyElt | parseTypeOtherPropertyElt | emptyPropertyElt
+//
+// 7.2.15 resourcePropertyElt
+// start-element ( URI == propertyElementURIs, attributes == set ( idAttr? ) )
+// ws* nodeElement ws*
+// end-element()
+//
+// 7.2.16 literalPropertyElt
+// start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, datatypeAttr?) )
+// text()
+// end-element()
+//
+// 7.2.17 parseTypeLiteralPropertyElt
+// start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, parseLiteral ) )
+// literal
+// end-element()
+//
+// 7.2.18 parseTypeResourcePropertyElt
+// start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, parseResource ) )
+// propertyEltList
+// end-element()
+//
+// 7.2.19 parseTypeCollectionPropertyElt
+// start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, parseCollection ) )
+// nodeElementList
+// end-element()
+//
+// 7.2.20 parseTypeOtherPropertyElt
+// start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, parseOther ) )
+// propertyEltList
+// end-element()
+//
+// 7.2.21 emptyPropertyElt
+// start-element ( URI == propertyElementURIs,
+// attributes == set ( idAttr?, ( resourceAttr | nodeIdAttr )?, propertyAttr* ) )
+// end-element()
+//
+// The various property element forms are not distinguished by the XML element name, but by their
+// attributes for the most part. The exceptions are resourcePropertyElt and literalPropertyElt. They
+// are distinguished by their XML element content.
+//
+// NOTE: The RDF syntax does not explicitly include the xml:lang attribute although it can appear in
+// many of these. We have to allow for it in the attibute counts below.
+
+static void
+RDF_PropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel )
+{
+ RDFTermKind nodeTerm = GetRDFTermKind ( xmlNode.name );
+ if ( ! IsPropertyElementName ( nodeTerm ) ) XMP_Throw ( "Invalid property element name", kXMPErr_BadRDF );
+
+ if ( xmlNode.attrs.size() > 3 ) {
+
+ // Only an emptyPropertyElt can have more than 3 attributes.
+ RDF_EmptyPropertyElement ( xmpParent, xmlNode, isTopLevel );
+
+ } else {
+
+ // Look through the attributes for one that isn't rdf:ID or xml:lang, it will usually tell
+ // what we should be dealing with. The called routines must verify their specific syntax!
+
+ XML_cNodePos currAttr = xmlNode.attrs.begin();
+ XML_cNodePos endAttr = xmlNode.attrs.end();
+ XMP_VarString * attrName = 0;
+
+ for ( ; currAttr != endAttr; ++currAttr ) {
+ attrName = &((*currAttr)->name);
+ if ( (*attrName != "xml:lang") && (*attrName != "rdf:ID") ) break;
+ }
+
+ if ( currAttr != endAttr ) {
+
+ XMP_Assert ( attrName != 0 );
+ XMP_VarString& attrValue = (*currAttr)->value;
+
+ if ( *attrName == "rdf:datatype" ) {
+ RDF_LiteralPropertyElement ( xmpParent, xmlNode, isTopLevel );
+ } else if ( *attrName != "rdf:parseType" ) {
+ RDF_EmptyPropertyElement ( xmpParent, xmlNode, isTopLevel );
+ } else if ( attrValue == "Literal" ) {
+ RDF_ParseTypeLiteralPropertyElement ( xmpParent, xmlNode, isTopLevel );
+ } else if ( attrValue == "Resource" ) {
+ RDF_ParseTypeResourcePropertyElement ( xmpParent, xmlNode, isTopLevel );
+ } else if ( attrValue == "Collection" ) {
+ RDF_ParseTypeCollectionPropertyElement ( xmpParent, xmlNode, isTopLevel );
+ } else {
+ RDF_ParseTypeOtherPropertyElement ( xmpParent, xmlNode, isTopLevel );
+ }
+
+ } else {
+
+ // Only rdf:ID and xml:lang, could be a resourcePropertyElt, a literalPropertyElt, or an.
+ // emptyPropertyElt. Look at the child XML nodes to decide which.
+
+ if ( xmlNode.content.empty() ) {
+
+ RDF_EmptyPropertyElement ( xmpParent, xmlNode, isTopLevel );
+
+ } else {
+
+ XML_cNodePos currChild = xmlNode.content.begin();
+ XML_cNodePos endChild = xmlNode.content.end();
+
+ for ( ; currChild != endChild; ++currChild ) {
+ if ( (*currChild)->kind != kCDataNode ) break;
+ }
+
+ if ( currChild == endChild ) {
+ RDF_LiteralPropertyElement ( xmpParent, xmlNode, isTopLevel );
+ } else {
+ RDF_ResourcePropertyElement ( xmpParent, xmlNode, isTopLevel );
+ }
+
+ }
+
+ }
+
+ }
+
+} // RDF_PropertyElement
+
+
+// =================================================================================================
+// RDF_ResourcePropertyElement
+// ===========================
+//
+// 7.2.15 resourcePropertyElt
+// start-element ( URI == propertyElementURIs, attributes == set ( idAttr? ) )
+// ws* nodeElement ws*
+// end-element()
+//
+// This handles structs using an rdf:Description node, arrays using rdf:Bag/Seq/Alt, and typedNodes.
+// It also catches and cleans up qualified properties written with rdf:Description and rdf:value.
+
+static void
+RDF_ResourcePropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel )
+{
+ if ( isTopLevel && (xmlNode.name == "iX:changes") ) return; // Strip old "punchcard" chaff.
+
+ XMP_Node * newCompound = AddChildNode ( xmpParent, xmlNode, "", isTopLevel );
+
+ XML_cNodePos currAttr = xmlNode.attrs.begin();
+ XML_cNodePos endAttr = xmlNode.attrs.end();
+
+ for ( ; currAttr != endAttr; ++currAttr ) {
+ XMP_VarString & attrName = (*currAttr)->name;
+ if ( attrName == "xml:lang" ) {
+ AddQualifierNode ( newCompound, **currAttr );
+ } else if ( attrName == "rdf:ID" ) {
+ continue; // Ignore all rdf:ID attributes.
+ } else {
+ XMP_Throw ( "Invalid attribute for resource property element", kXMPErr_BadRDF );
+ }
+ }
+
+ XML_cNodePos currChild = xmlNode.content.begin();
+ XML_cNodePos endChild = xmlNode.content.end();
+
+ for ( ; currChild != endChild; ++currChild ) {
+ if ( ! IsWhitespaceNode ( **currChild ) ) break;
+ }
+ if ( currChild == endChild ) XMP_Throw ( "Missing child of resource property element", kXMPErr_BadRDF );
+ if ( (*currChild)->kind != kElemNode ) XMP_Throw ( "Children of resource property element must be XML elements", kXMPErr_BadRDF );
+
+ if ( (*currChild)->name == "rdf:Bag" ) {
+ newCompound->options |= kXMP_PropValueIsArray;
+ } else if ( (*currChild)->name == "rdf:Seq" ) {
+ newCompound->options |= kXMP_PropValueIsArray | kXMP_PropArrayIsOrdered;
+ } else if ( (*currChild)->name == "rdf:Alt" ) {
+ newCompound->options |= kXMP_PropValueIsArray | kXMP_PropArrayIsOrdered | kXMP_PropArrayIsAlternate;
+ } else {
+ newCompound->options |= kXMP_PropValueIsStruct;
+ if ( (*currChild)->name != "rdf:Description" ) {
+ XMP_VarString typeName ( (*currChild)->ns );
+ size_t colonPos = (*currChild)->name.find_first_of(':');
+ if ( colonPos == XMP_VarString::npos ) XMP_Throw ( "All XML elements must be in a namespace", kXMPErr_BadXMP );
+ typeName.append ( (*currChild)->name, colonPos, XMP_VarString::npos );
+ AddQualifierNode ( newCompound, XMP_VarString("rdf:type"), typeName );
+ }
+ }
+
+ RDF_NodeElement ( newCompound, **currChild, kNotTopLevel );
+ if ( newCompound->options & kRDF_HasValueElem ) {
+ FixupQualifiedNode ( newCompound );
+ } else if ( newCompound->options & kXMP_PropArrayIsAlternate ) {
+ DetectAltText ( newCompound );
+ }
+
+ for ( ++currChild; currChild != endChild; ++currChild ) {
+ if ( ! IsWhitespaceNode ( **currChild ) ) XMP_Throw ( "Invalid child of resource property element", kXMPErr_BadRDF );
+ }
+
+} // RDF_ResourcePropertyElement
+
+
+// =================================================================================================
+// RDF_LiteralPropertyElement
+// ==========================
+//
+// 7.2.16 literalPropertyElt
+// start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, datatypeAttr?) )
+// text()
+// end-element()
+//
+// Add a leaf node with the text value and qualifiers for the attributes.
+
+static void
+RDF_LiteralPropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel )
+{
+ XMP_Node * newChild = AddChildNode ( xmpParent, xmlNode, "", isTopLevel );
+
+ XML_cNodePos currAttr = xmlNode.attrs.begin();
+ XML_cNodePos endAttr = xmlNode.attrs.end();
+
+ for ( ; currAttr != endAttr; ++currAttr ) {
+ XMP_VarString & attrName = (*currAttr)->name;
+ if ( attrName == "xml:lang" ) {
+ AddQualifierNode ( newChild, **currAttr );
+ } else if ( (attrName == "rdf:ID") || (attrName == "rdf:datatype") ) {
+ continue; // Ignore all rdf:ID and rdf:datatype attributes.
+ } else {
+ XMP_Throw ( "Invalid attribute for literal property element", kXMPErr_BadRDF );
+ }
+ }
+
+ XML_cNodePos currChild = xmlNode.content.begin();
+ XML_cNodePos endChild = xmlNode.content.end();
+ size_t textSize = 0;
+
+ for ( ; currChild != endChild; ++currChild ) {
+ if ( (*currChild)->kind != kCDataNode ) XMP_Throw ( "Invalid child of literal property element", kXMPErr_BadRDF );
+ textSize += (*currChild)->value.size();
+ }
+
+ newChild->value.reserve ( textSize );
+
+ for ( currChild = xmlNode.content.begin(); currChild != endChild; ++currChild ) {
+ newChild->value += (*currChild)->value;
+ }
+
+ #if 0 // *** XMP_DebugBuild
+ newChild->_valuePtr = newChild->value.c_str();
+ #endif
+
+} // RDF_LiteralPropertyElement
+
+
+// =================================================================================================
+// RDF_ParseTypeLiteralPropertyElement
+// ===================================
+//
+// 7.2.17 parseTypeLiteralPropertyElt
+// start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, parseLiteral ) )
+// literal
+// end-element()
+
+static void
+RDF_ParseTypeLiteralPropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel )
+{
+ IgnoreParam(xmpParent); IgnoreParam(xmlNode); IgnoreParam(isTopLevel);
+
+ XMP_Throw ( "ParseTypeLiteral property element not allowed", kXMPErr_BadXMP );
+
+} // RDF_ParseTypeLiteralPropertyElement
+
+
+// =================================================================================================
+// RDF_ParseTypeResourcePropertyElement
+// ====================================
+//
+// 7.2.18 parseTypeResourcePropertyElt
+// start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, parseResource ) )
+// propertyEltList
+// end-element()
+//
+// Add a new struct node with a qualifier for the possible rdf:ID attribute. Then process the XML
+// child nodes to get the struct fields.
+
+static void
+RDF_ParseTypeResourcePropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel )
+{
+
+ XMP_Node * newStruct = AddChildNode ( xmpParent, xmlNode, "", isTopLevel );
+ newStruct->options |= kXMP_PropValueIsStruct;
+
+ XML_cNodePos currAttr = xmlNode.attrs.begin();
+ XML_cNodePos endAttr = xmlNode.attrs.end();
+
+ for ( ; currAttr != endAttr; ++currAttr ) {
+ XMP_VarString & attrName = (*currAttr)->name;
+ if ( attrName == "rdf:parseType" ) {
+ continue; // ! The caller ensured the value is "Resource".
+ } else if ( attrName == "xml:lang" ) {
+ AddQualifierNode ( newStruct, **currAttr );
+ } else if ( attrName == "rdf:ID" ) {
+ continue; // Ignore all rdf:ID attributes.
+ } else {
+ XMP_Throw ( "Invalid attribute for ParseTypeResource property element", kXMPErr_BadRDF );
+ }
+ }
+
+ RDF_PropertyElementList ( newStruct, xmlNode, kNotTopLevel );
+
+ if ( newStruct->options & kRDF_HasValueElem ) FixupQualifiedNode ( newStruct );
+
+ // *** Need to look for arrays using rdf:Description and rdf:type.
+
+} // RDF_ParseTypeResourcePropertyElement
+
+
+// =================================================================================================
+// RDF_ParseTypeCollectionPropertyElement
+// ======================================
+//
+// 7.2.19 parseTypeCollectionPropertyElt
+// start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, parseCollection ) )
+// nodeElementList
+// end-element()
+
+static void
+RDF_ParseTypeCollectionPropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel )
+{
+ IgnoreParam(xmpParent); IgnoreParam(xmlNode); IgnoreParam(isTopLevel);
+
+ XMP_Throw ( "ParseTypeCollection property element not allowed", kXMPErr_BadXMP );
+
+} // RDF_ParseTypeCollectionPropertyElement
+
+
+// =================================================================================================
+// RDF_ParseTypeOtherPropertyElement
+// =================================
+//
+// 7.2.20 parseTypeOtherPropertyElt
+// start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, parseOther ) )
+// propertyEltList
+// end-element()
+
+static void
+RDF_ParseTypeOtherPropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel )
+{
+ IgnoreParam(xmpParent); IgnoreParam(xmlNode); IgnoreParam(isTopLevel);
+
+ XMP_Throw ( "ParseTypeOther property element not allowed", kXMPErr_BadXMP );
+
+} // RDF_ParseTypeOtherPropertyElement
+
+
+// =================================================================================================
+// RDF_EmptyPropertyElement
+// ========================
+//
+// 7.2.21 emptyPropertyElt
+// start-element ( URI == propertyElementURIs,
+// attributes == set ( idAttr?, ( resourceAttr | nodeIdAttr )?, propertyAttr* ) )
+// end-element()
+//
+// <ns:Prop1/> <!-- a simple property with an empty value -->
+// <ns:Prop2 rdf:resource="http://www.adobe.com/"/> <!-- a URI value -->
+// <ns:Prop3 rdf:value="..." ns:Qual="..."/> <!-- a simple qualified property -->
+// <ns:Prop4 ns:Field1="..." ns:Field2="..."/> <!-- a struct with simple fields -->
+//
+// An emptyPropertyElt is an element with no contained content, just a possibly empty set of
+// attributes. An emptyPropertyElt can represent three special cases of simple XMP properties: a
+// simple property with an empty value (ns:Prop1), a simple property whose value is a URI
+// (ns:Prop2), or a simple property with simple qualifiers (ns:Prop3). An emptyPropertyElt can also
+// represent an XMP struct whose fields are all simple and unqualified (ns:Prop4).
+//
+// It is an error to use both rdf:value and rdf:resource - that can lead to invalid RDF in the
+// verbose form written using a literalPropertyElt.
+//
+// The XMP mapping for an emptyPropertyElt is a bit different from generic RDF, partly for
+// design reasons and partly for historical reasons. The XMP mapping rules are:
+// 1. If there is an rdf:value attribute then this is a simple property with a text value.
+// All other attributes are qualifiers.
+// 2. If there is an rdf:resource attribute then this is a simple property with a URI value.
+// All other attributes are qualifiers.
+// 3. If there are no attributes other than xml:lang, rdf:ID, or rdf:nodeID then this is a simple
+// property with an empty value.
+// 4. Otherwise this is a struct, the attributes other than xml:lang, rdf:ID, or rdf:nodeID are fields.
+
+static void
+RDF_EmptyPropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel )
+{
+ bool hasPropertyAttrs = false;
+ bool hasResourceAttr = false;
+ bool hasNodeIDAttr = false;
+ bool hasValueAttr = false;
+
+ const XML_Node * valueNode = 0; // ! Can come from rdf:value or rdf:resource.
+
+ if ( ! xmlNode.content.empty() ) XMP_Throw ( "Nested content not allowed with rdf:resource or property attributes", kXMPErr_BadRDF );
+
+ // First figure out what XMP this maps to and remember the XML node for a simple value.
+
+ XML_cNodePos currAttr = xmlNode.attrs.begin();
+ XML_cNodePos endAttr = xmlNode.attrs.end();
+
+ for ( ; currAttr != endAttr; ++currAttr ) {
+
+ RDFTermKind attrTerm = GetRDFTermKind ( (*currAttr)->name );
+
+ switch ( attrTerm ) {
+
+ case kRDFTerm_ID :
+ // Nothing to do.
+ break;
+
+ case kRDFTerm_resource :
+ if ( hasNodeIDAttr ) XMP_Throw ( "Empty property element can't have both rdf:resource and rdf:nodeID", kXMPErr_BadRDF );
+ if ( hasValueAttr ) XMP_Throw ( "Empty property element can't have both rdf:value and rdf:resource", kXMPErr_BadXMP );
+ hasResourceAttr = true;
+ if ( ! hasValueAttr ) valueNode = *currAttr;
+ break;
+
+ case kRDFTerm_nodeID :
+ if ( hasResourceAttr ) XMP_Throw ( "Empty property element can't have both rdf:resource and rdf:nodeID", kXMPErr_BadRDF );
+ hasNodeIDAttr = true;
+ break;
+
+ case kRDFTerm_Other :
+ if ( (*currAttr)->name == "rdf:value" ) {
+ if ( hasResourceAttr ) XMP_Throw ( "Empty property element can't have both rdf:value and rdf:resource", kXMPErr_BadXMP );
+ hasValueAttr = true;
+ valueNode = *currAttr;
+ } else if ( (*currAttr)->name != "xml:lang" ) {
+ hasPropertyAttrs = true;
+ }
+ break;
+
+ default :
+ XMP_Throw ( "Unrecognized attribute of empty property element", kXMPErr_BadRDF );
+ break;
+
+ }
+
+ }
+
+ // Create the right kind of child node and visit the attributes again to add the fields or qualifiers.
+ // ! Because of implementation vagaries, the xmpParent is the tree root for top level properties.
+ // ! The schema is found, created if necessary, by AddChildNode.
+
+ XMP_Node * childNode = AddChildNode ( xmpParent, xmlNode, "", isTopLevel );
+ bool childIsStruct = false;
+
+ if ( hasValueAttr | hasResourceAttr ) {
+ childNode->value = valueNode->value;
+ if ( ! hasValueAttr ) childNode->options |= kXMP_PropValueIsURI; // ! Might have both rdf:value and rdf:resource.
+ } else if ( hasPropertyAttrs ) {
+ childNode->options |= kXMP_PropValueIsStruct;
+ childIsStruct = true;
+ }
+
+ currAttr = xmlNode.attrs.begin();
+ endAttr = xmlNode.attrs.end();
+
+ for ( ; currAttr != endAttr; ++currAttr ) {
+
+ if ( *currAttr == valueNode ) continue; // Skip the rdf:value or rdf:resource attribute holding the value.
+ RDFTermKind attrTerm = GetRDFTermKind ( (*currAttr)->name );
+
+ switch ( attrTerm ) {
+
+ case kRDFTerm_ID :
+ case kRDFTerm_nodeID :
+ break; // Ignore all rdf:ID and rdf:nodeID attributes.w
+
+ case kRDFTerm_resource :
+ AddQualifierNode ( childNode, **currAttr );
+ break;
+
+ case kRDFTerm_Other :
+ if ( (! childIsStruct) || (*currAttr)->name == "xml:lang" ) {
+ AddQualifierNode ( childNode, **currAttr );
+ } else {
+ AddChildNode ( childNode, **currAttr, (*currAttr)->value.c_str(), false );
+ }
+ break;
+
+ default :
+ XMP_Throw ( "Unrecognized attribute of empty property element", kXMPErr_BadRDF );
+ break;
+
+ }
+
+ }
+
+} // RDF_EmptyPropertyElement
+
+
+// =================================================================================================
diff --git a/source/XMPCore/WXMPIterator.cpp b/source/XMPCore/WXMPIterator.cpp
new file mode 100644
index 0000000..b52fa0d
--- /dev/null
+++ b/source/XMPCore/WXMPIterator.cpp
@@ -0,0 +1,186 @@
+// =================================================================================================
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "XMP_Environment.h" // ! This must be the first include!
+#include "XMPCore_Impl.hpp"
+
+#include "XMPIterator.hpp"
+#include "client-glue/WXMPIterator.hpp"
+
+#if XMP_WinBuild
+ #pragma warning ( disable : 4101 ) // unreferenced local variable
+ #pragma warning ( disable : 4189 ) // local variable is initialized but not referenced
+ #pragma warning ( disable : 4800 ) // forcing value to bool 'true' or 'false' (performance warning)
+ #if XMP_DebugBuild
+ #pragma warning ( disable : 4297 ) // function assumed not to throw an exception but does
+ #endif
+#endif
+
+#if __cplusplus
+extern "C" {
+#endif
+
+// =================================================================================================
+// CTor/DTor Wrappers
+// ==================
+
+void
+WXMPIterator_PropCTor_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_OptionBits options,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPIterator_PropCTor_1" )
+
+ if ( schemaNS == 0 ) schemaNS = "";
+ if ( propName == 0 ) propName = "";
+
+ const XMPMeta & xmpObj = WtoXMPMeta_Ref ( xmpRef );
+ XMPIterator * iter = new XMPIterator ( xmpObj, schemaNS, propName, options );
+ ++iter->clientRefs;
+ XMP_Assert ( iter->clientRefs == 1 );
+ wResult->ptrResult = XMPIteratorRef ( iter );
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPIterator_TableCTor_1 ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_OptionBits options,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPIterator_TableCTor_1" )
+
+ if ( schemaNS == 0 ) schemaNS = "";
+ if ( propName == 0 ) propName = "";
+
+ XMPIterator * iter = new XMPIterator ( schemaNS, propName, options );
+ ++iter->clientRefs;
+ XMP_Assert ( iter->clientRefs == 1 );
+ wResult->ptrResult = XMPIteratorRef ( iter );
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPIterator_IncrementRefCount_1 ( XMPIteratorRef iterRef )
+{
+ WXMP_Result * wResult = &void_wResult; // ! Needed to "fool" the EnterWrapper macro.
+ XMP_ENTER_WRAPPER ( "WXMPIterator_IncrementRefCount_1" )
+
+ XMPIterator * thiz = (XMPIterator*)iterRef;
+
+ ++thiz->clientRefs;
+ XMP_Assert ( thiz->clientRefs > 1 );
+
+ XMP_EXIT_WRAPPER_NO_THROW
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPIterator_DecrementRefCount_1 ( XMPIteratorRef iterRef )
+{
+ WXMP_Result * wResult = &void_wResult; // ! Needed to "fool" the EnterWrapper macro.
+ XMP_ENTER_WRAPPER ( "WXMPIterator_DecrementRefCount_1" )
+
+ XMPIterator * thiz = (XMPIterator*)iterRef;
+
+ XMP_Assert ( thiz->clientRefs > 0 );
+ --thiz->clientRefs;
+ if ( thiz->clientRefs <= 0 ) delete ( thiz );
+
+ XMP_EXIT_WRAPPER_NO_THROW
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPIterator_Unlock_1 ( XMP_OptionBits options )
+{
+ WXMP_Result * wResult = &void_wResult; // ! Needed to "fool" the EnterWrapper macro.
+ XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPIterator_Unlock_1" )
+
+ XMPIterator::Unlock ( options );
+
+ XMP_EXIT_WRAPPER_NO_THROW
+}
+
+// =================================================================================================
+// Class Method Wrappers
+// =====================
+
+void
+WXMPIterator_Next_1 ( XMPIteratorRef iterRef,
+ XMP_StringPtr * schemaNS,
+ XMP_StringLen * nsSize,
+ XMP_StringPtr * propPath,
+ XMP_StringLen * pathSize,
+ XMP_StringPtr * propValue,
+ XMP_StringLen * valueSize,
+ XMP_OptionBits * propOptions,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPIterator_Next_1" )
+
+ if ( schemaNS == 0 ) schemaNS = &voidStringPtr;
+ if ( nsSize == 0 ) nsSize = &voidStringLen;
+ if ( propPath == 0 ) propPath = &voidStringPtr;
+ if ( pathSize == 0 ) pathSize = &voidStringLen;
+ if ( propValue == 0 ) propValue = &voidStringPtr;
+ if ( valueSize == 0 ) valueSize = &voidStringLen;
+ if ( propOptions == 0 ) propOptions = &voidOptionBits;
+
+ XMPIterator * iter = WtoXMPIterator_Ptr ( iterRef );
+ XMP_Bool found = iter->Next ( schemaNS, nsSize, propPath, pathSize, propValue, valueSize, propOptions );
+ wResult->int32Result = found;
+
+ XMP_EXIT_WRAPPER_KEEP_LOCK ( found )
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPIterator_Skip_1 ( XMPIteratorRef iterRef,
+ XMP_OptionBits options,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPIterator_Skip_1" )
+
+ XMPIterator * iter = WtoXMPIterator_Ptr ( iterRef );
+ iter->Skip ( options );
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPUtils_UnlockIter_1 ( XMPIteratorRef iterRef,
+ XMP_OptionBits options )
+{
+ WXMP_Result * wResult = &void_wResult; // ! Needed to "fool" the EnterWrapper macro.
+ XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPUtils_UnlockIter_1" )
+
+ XMPIterator * iter = WtoXMPIterator_Ptr ( iterRef );
+ iter->UnlockIter ( options );
+
+ XMP_EXIT_WRAPPER_NO_THROW
+}
+
+// =================================================================================================
+
+#if __cplusplus
+} /* extern "C" */
+#endif
diff --git a/source/XMPCore/WXMPMeta.cpp b/source/XMPCore/WXMPMeta.cpp
new file mode 100644
index 0000000..937409a
--- /dev/null
+++ b/source/XMPCore/WXMPMeta.cpp
@@ -0,0 +1,1285 @@
+// =================================================================================================
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "XMP_Environment.h" // ! This must be the first include!
+#include "XMPCore_Impl.hpp"
+
+#include "XMPMeta.hpp"
+#include "client-glue/WXMPMeta.hpp"
+
+#if XMP_WinBuild
+ #pragma warning ( disable : 4101 ) // unreferenced local variable
+ #pragma warning ( disable : 4189 ) // local variable is initialized but not referenced
+ #pragma warning ( disable : 4702 ) // unreachable code
+ #pragma warning ( disable : 4800 ) // forcing value to bool 'true' or 'false' (performance warning)
+ #if XMP_DebugBuild
+ #pragma warning ( disable : 4297 ) // function assumed not to throw an exception but does
+ #endif
+#endif
+
+#if __cplusplus
+extern "C" {
+#endif
+
+// =================================================================================================
+// Init/Term Wrappers
+// ==================
+
+/* class static */ void
+WXMPMeta_GetVersionInfo_1 ( XMP_VersionInfo * info )
+{
+ WXMP_Result * wResult = &void_wResult; // ! Needed to "fool" the EnterWrapper macro.
+ XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPMeta_GetVersionInfo_1" )
+
+ XMPMeta::GetVersionInfo ( info );
+
+ XMP_EXIT_WRAPPER_NO_THROW
+}
+
+// -------------------------------------------------------------------------------------------------
+
+/* class static */ void
+WXMPMeta_Initialize_1 ( WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPMeta_Initialize_1" )
+
+ bool ok = XMPMeta::Initialize();
+ wResult->int32Result = ok;
+
+ XMP_EXIT_WRAPPER
+}
+// -------------------------------------------------------------------------------------------------
+
+/* class static */ void
+WXMPMeta_Terminate_1()
+{
+ WXMP_Result * wResult = &void_wResult; // ! Needed to "fool" the EnterWrapper macro.
+ XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPMeta_Terminate_1" )
+
+ XMPMeta::Terminate();
+
+ XMP_EXIT_WRAPPER_NO_THROW
+}
+
+// =================================================================================================
+// CTor/DTor Wrappers
+// ==================
+
+void
+WXMPMeta_CTor_1 ( WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPMeta_CTor_1" )
+
+ XMPMeta * xmpObj = new XMPMeta();
+ ++xmpObj->clientRefs;
+ XMP_Assert ( xmpObj->clientRefs == 1 );
+ wResult->ptrResult = XMPMetaRef ( xmpObj );
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_IncrementRefCount_1 ( XMPMetaRef xmpRef )
+{
+ WXMP_Result * wResult = &void_wResult; // ! Needed to "fool" the EnterWrapper macro.
+ XMP_ENTER_WRAPPER ( "WXMPMeta_IncrementRefCount_1" )
+
+ XMPMeta * thiz = (XMPMeta*)xmpRef;
+
+ ++thiz->clientRefs;
+ XMP_Assert ( thiz->clientRefs > 0 );
+
+ XMP_EXIT_WRAPPER_NO_THROW
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_DecrementRefCount_1 ( XMPMetaRef xmpRef )
+{
+ WXMP_Result * wResult = &void_wResult; // ! Needed to "fool" the EnterWrapper macro.
+ XMP_ENTER_WRAPPER ( "WXMPMeta_DecrementRefCount_1" )
+
+ XMPMeta * thiz = (XMPMeta*)xmpRef;
+
+ XMP_Assert ( thiz->clientRefs > 0 );
+ --thiz->clientRefs;
+ if ( thiz->clientRefs <= 0 ) delete ( thiz );
+
+ XMP_EXIT_WRAPPER_NO_THROW
+}
+
+// =================================================================================================
+// Class Static Wrappers
+// =====================
+//
+// These are DLL-entry wrappers for class-static functions. They all follow a simple pattern:
+//
+// try
+// acquire toolbox lock
+// validate parameters
+// call through to the implementation
+// retain toolbox lock if necessary
+// catch anything and return an appropriate BIBError object
+// return null (no error if we get to here)
+//
+// The toolbox lock is acquired through a local wrapper object that automatically unlocks when the
+// try-block is exited. The lock must be retained if the function is returning a string result. The
+// output string is owned by the toolkit, the client must copy the string then release the lock.
+// The lock used here is the overall toolkit lock. For simplicity at this time the lock is a simple
+// mutual exclusion lock, we do not allow multiple concurrent readers.
+//
+// The one exception to this model is UnlockToolkit. It does not acquire the toolkit lock since this
+// is the function the client calls to release the lock after copying an output string!
+//
+// =================================================================================================
+
+/* class static */ void
+WXMPMeta_GetGlobalOptions_1 ( WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPMeta_GetGlobalOptions_1" )
+
+ XMP_OptionBits options = XMPMeta::GetGlobalOptions();
+ wResult->int32Result = options;
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+/* class static */ void
+WXMPMeta_SetGlobalOptions_1 ( XMP_OptionBits options,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPMeta_SetGlobalOptions_1" )
+
+ XMPMeta::SetGlobalOptions ( options );
+
+ XMP_EXIT_WRAPPER
+}
+// -------------------------------------------------------------------------------------------------
+
+/* class static */ void
+WXMPMeta_DumpNamespaces_1 ( XMP_TextOutputProc outProc,
+ void * refCon,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPMeta_DumpNamespaces_1" )
+
+ if ( outProc == 0 ) XMP_Throw ( "Null client output routine", kXMPErr_BadParam );
+
+ XMP_Status status = XMPMeta::DumpNamespaces ( outProc, refCon );
+ wResult->int32Result = status;
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+/* class static */ void
+WXMPMeta_DumpAliases_1 ( XMP_TextOutputProc outProc,
+ void * refCon,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPMeta_DumpAliases_1" )
+
+ if ( outProc == 0 ) XMP_Throw ( "Null client output routine", kXMPErr_BadParam );
+
+ XMP_Status status = XMPMeta::DumpAliases ( outProc, refCon );
+ wResult->int32Result = status;
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+/* class static */ void
+WXMPMeta_Unlock_1 ( XMP_OptionBits options )
+{
+ WXMP_Result * wResult = &void_wResult; // ! Needed to "fool" the EnterWrapper macro.
+ XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPMeta_Unlock_1" )
+
+ XMPMeta::Unlock ( options );
+
+ XMP_EXIT_WRAPPER_NO_THROW
+}
+
+// -------------------------------------------------------------------------------------------------
+
+/* class static */ void
+WXMPMeta_RegisterNamespace_1 ( XMP_StringPtr namespaceURI,
+ XMP_StringPtr suggestedPrefix,
+ XMP_StringPtr * registeredPrefix,
+ XMP_StringLen * prefixSize,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPMeta_RegisterNamespace_1" )
+
+ if ( (namespaceURI == 0) || (*namespaceURI == 0) ) XMP_Throw ( "Empty namespace URI", kXMPErr_BadSchema );
+ if ( (suggestedPrefix == 0) || (*suggestedPrefix == 0) ) XMP_Throw ( "Empty suggested prefix", kXMPErr_BadSchema );
+
+ if ( registeredPrefix == 0 ) registeredPrefix = &voidStringPtr;
+ if ( prefixSize == 0 ) prefixSize = &voidStringLen;
+
+ bool prefixMatch = XMPMeta::RegisterNamespace ( namespaceURI, suggestedPrefix, registeredPrefix, prefixSize );
+ wResult->int32Result = prefixMatch;
+
+ XMP_EXIT_WRAPPER_KEEP_LOCK ( true ) // ! Always keep the lock, a string is always returned!
+}
+
+// -------------------------------------------------------------------------------------------------
+
+/* class static */ void
+WXMPMeta_GetNamespacePrefix_1 ( XMP_StringPtr namespaceURI,
+ XMP_StringPtr * namespacePrefix,
+ XMP_StringLen * prefixSize,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPMeta_GetNamespacePrefix_1" )
+
+ if ( (namespaceURI == 0) || (*namespaceURI == 0) ) XMP_Throw ( "Empty namespace URI", kXMPErr_BadSchema );
+
+ if ( namespacePrefix == 0 ) namespacePrefix = &voidStringPtr;
+ if ( prefixSize == 0 ) prefixSize = &voidStringLen;
+
+ bool found = XMPMeta::GetNamespacePrefix ( namespaceURI, namespacePrefix, prefixSize );
+ wResult->int32Result = found;
+
+ XMP_EXIT_WRAPPER_KEEP_LOCK ( found )
+}
+
+// -------------------------------------------------------------------------------------------------
+
+/* class static */ void
+WXMPMeta_GetNamespaceURI_1 ( XMP_StringPtr namespacePrefix,
+ XMP_StringPtr * namespaceURI,
+ XMP_StringLen * uriSize,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPMeta_GetNamespaceURI_1" )
+
+ if ( (namespacePrefix == 0) || (*namespacePrefix == 0) ) XMP_Throw ( "Empty namespace prefix", kXMPErr_BadSchema );
+
+ if ( namespaceURI == 0 ) namespaceURI = &voidStringPtr;
+ if ( uriSize == 0 ) uriSize = &voidStringLen;
+
+ bool found = XMPMeta::GetNamespaceURI ( namespacePrefix, namespaceURI, uriSize );
+ wResult->int32Result = found;
+
+ XMP_EXIT_WRAPPER_KEEP_LOCK ( found )
+}
+
+// -------------------------------------------------------------------------------------------------
+
+/* class static */ void
+WXMPMeta_DeleteNamespace_1 ( XMP_StringPtr namespaceURI,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPMeta_DeleteNamespace_1" )
+
+ if ( (namespaceURI == 0) || (*namespaceURI == 0) ) XMP_Throw ( "Empty namespace URI", kXMPErr_BadSchema );
+
+ XMPMeta::DeleteNamespace ( namespaceURI );
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+/* class static */ void
+WXMPMeta_RegisterAlias_1 ( XMP_StringPtr aliasNS,
+ XMP_StringPtr aliasProp,
+ XMP_StringPtr actualNS,
+ XMP_StringPtr actualProp,
+ XMP_OptionBits arrayForm,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPMeta_RegisterAlias_1" )
+
+ if ( (aliasNS == 0) || (*aliasNS == 0) ) XMP_Throw ( "Empty alias namespace URI", kXMPErr_BadSchema );
+ if ( (aliasProp == 0) || (*aliasProp == 0) ) XMP_Throw ( "Empty alias property name", kXMPErr_BadXPath );
+ if ( (actualNS == 0) || (*actualNS == 0) ) XMP_Throw ( "Empty actual namespace URI", kXMPErr_BadSchema );
+ if ( (actualProp == 0) || (*actualProp == 0) ) XMP_Throw ( "Empty actual property name", kXMPErr_BadXPath );
+
+ XMPMeta::RegisterAlias ( aliasNS, aliasProp, actualNS, actualProp, arrayForm );
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+/* class static */ void
+WXMPMeta_ResolveAlias_1 ( XMP_StringPtr aliasNS,
+ XMP_StringPtr aliasProp,
+ XMP_StringPtr * actualNS,
+ XMP_StringLen * nsSize,
+ XMP_StringPtr * actualProp,
+ XMP_StringLen * propSize,
+ XMP_OptionBits * arrayForm,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPMeta_ResolveAlias_1" )
+
+ if ( (aliasNS == 0) || (*aliasNS == 0) ) XMP_Throw ( "Empty alias namespace URI", kXMPErr_BadSchema );
+ if ( (aliasProp == 0) || (*aliasProp == 0) ) XMP_Throw ( "Empty alias property name", kXMPErr_BadXPath );
+
+ if ( actualNS == 0 ) actualNS = &voidStringPtr;
+ if ( nsSize == 0 ) nsSize = &voidStringLen;
+ if ( actualProp == 0 ) actualProp = &voidStringPtr;
+ if ( propSize == 0 ) propSize = &voidStringLen;
+ if ( arrayForm == 0 ) arrayForm = &voidOptionBits;
+
+ bool found = XMPMeta::ResolveAlias ( aliasNS, aliasProp, actualNS, nsSize, actualProp, propSize, arrayForm );
+ wResult->int32Result = found;
+
+ XMP_EXIT_WRAPPER_KEEP_LOCK ( found )
+}
+
+// -------------------------------------------------------------------------------------------------
+
+/* class static */ void
+WXMPMeta_DeleteAlias_1 ( XMP_StringPtr aliasNS,
+ XMP_StringPtr aliasProp,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPMeta_DeleteAlias_1" )
+
+ if ( (aliasNS == 0) || (*aliasNS == 0) ) XMP_Throw ( "Empty alias namespace URI", kXMPErr_BadSchema );
+ if ( (aliasProp == 0) || (*aliasProp == 0) ) XMP_Throw ( "Empty alias property name", kXMPErr_BadXPath );
+
+ XMPMeta::DeleteAlias ( aliasNS, aliasProp );
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+/* class static */ void
+WXMPMeta_RegisterStandardAliases_1 ( XMP_StringPtr schemaNS,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPMeta_RegisterStandardAliases_1" )
+
+ if ( schemaNS == 0 ) schemaNS = "";
+
+ XMPMeta::RegisterStandardAliases ( schemaNS );
+
+ XMP_EXIT_WRAPPER
+}
+
+// =================================================================================================
+// Class Method Wrappers
+// =====================
+//
+// These are DLL-entry wrappers for the methods. They all follow a simple pattern:
+//
+// validate parameters
+// try
+// acquire object lock
+// call through to the implementation
+// retain object lock if necessary
+// catch anything and return an appropriate BIBError object
+// return null (no error if we get to here)
+//
+// The object lock is acquired through a local wrapper object that automatically unlocks when the
+// try-block is exited. The lock must be retained if the function is returning a string result. The
+// output string is owned by the object, the client must copy the string then release the lock. The
+// lock used here is the per-object lock. For simplicity at this time the lock is a simple mutual
+// exclusion lock, we do not allow multiple concurrent readers.
+//
+// The one exception to this model is UnlockObject. It does not acquire the object lock since this
+// is the function the client calls to release the lock after copying an output string!
+//
+// =================================================================================================
+
+void
+WXMPMeta_GetProperty_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr * propValue,
+ XMP_StringLen * valueSize,
+ XMP_OptionBits * options,
+ WXMP_Result * wResult ) /* const */
+{
+ XMP_ENTER_WRAPPER ( "WXMPMeta_GetProperty_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath );
+
+ if ( propValue == 0 ) propValue = &voidStringPtr;
+ if ( valueSize == 0 ) valueSize = &voidStringLen;
+ if ( options == 0 ) options = &voidOptionBits;
+
+ const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef );
+ bool found = meta.GetProperty ( schemaNS, propName, propValue, valueSize, options );
+ wResult->int32Result = found;
+
+ XMP_EXIT_WRAPPER_KEEP_LOCK ( found )
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_GetArrayItem_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex,
+ XMP_StringPtr * itemValue,
+ XMP_StringLen * valueSize,
+ XMP_OptionBits * options,
+ WXMP_Result * wResult ) /* const */
+{
+ XMP_ENTER_WRAPPER ( "WXMPMeta_GetArrayItem_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (arrayName == 0) || (*arrayName == 0) ) XMP_Throw ( "Empty array name", kXMPErr_BadXPath );
+
+ if ( itemValue == 0 ) itemValue = &voidStringPtr;
+ if ( valueSize == 0 ) valueSize = &voidStringLen;
+ if ( options == 0 ) options = &voidOptionBits;
+
+ const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef );
+ bool found = meta.GetArrayItem ( schemaNS, arrayName, itemIndex, itemValue, valueSize, options );
+ wResult->int32Result = found;
+
+ XMP_EXIT_WRAPPER_KEEP_LOCK ( found )
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_GetStructField_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ XMP_StringPtr * fieldValue,
+ XMP_StringLen * valueSize,
+ XMP_OptionBits * options,
+ WXMP_Result * wResult ) /* const */
+{
+ XMP_ENTER_WRAPPER ( "WXMPMeta_GetStructField_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (structName == 0) || (*structName == 0) ) XMP_Throw ( "Empty struct name", kXMPErr_BadXPath );
+ if ( (fieldNS == 0) || (*fieldNS == 0) ) XMP_Throw ( "Empty field namespace URI", kXMPErr_BadSchema );
+ if ( (fieldName == 0) || (*fieldName == 0) ) XMP_Throw ( "Empty field name", kXMPErr_BadXPath );
+
+ if ( fieldValue == 0 ) fieldValue = &voidStringPtr;
+ if ( valueSize == 0 ) valueSize = &voidStringLen;
+ if ( options == 0 ) options = &voidOptionBits;
+
+ const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef );
+ bool found = meta.GetStructField ( schemaNS, structName, fieldNS, fieldName, fieldValue, valueSize, options );
+ wResult->int32Result = found;
+
+ XMP_EXIT_WRAPPER_KEEP_LOCK ( found )
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_GetQualifier_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName,
+ XMP_StringPtr * qualValue,
+ XMP_StringLen * valueSize,
+ XMP_OptionBits * options,
+ WXMP_Result * wResult ) /* const */
+{
+ XMP_ENTER_WRAPPER ( "WXMPMeta_GetQualifier_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath );
+ if ( (qualNS == 0) || (*qualNS == 0) ) XMP_Throw ( "Empty qualifier namespace URI", kXMPErr_BadSchema );
+ if ( (qualName == 0) || (*qualName == 0) ) XMP_Throw ( "Empty qualifier name", kXMPErr_BadXPath );
+
+ if ( qualValue == 0 ) qualValue = &voidStringPtr;
+ if ( valueSize == 0 ) valueSize = &voidStringLen;
+ if ( options == 0 ) options = &voidOptionBits;
+
+ const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef );
+ bool found = meta.GetQualifier ( schemaNS, propName, qualNS, qualName, qualValue, valueSize, options );
+ wResult->int32Result = found;
+
+ XMP_EXIT_WRAPPER_KEEP_LOCK ( found )
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_SetProperty_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr propValue,
+ XMP_OptionBits options,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPMeta_SetProperty_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath );
+
+ XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef );
+ meta->SetProperty ( schemaNS, propName, propValue, options );
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_SetArrayItem_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex,
+ XMP_StringPtr itemValue,
+ XMP_OptionBits options,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPMeta_SetArrayItem_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (arrayName == 0) || (*arrayName == 0) ) XMP_Throw ( "Empty array name", kXMPErr_BadXPath );
+
+ XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef );
+ meta->SetArrayItem ( schemaNS, arrayName, itemIndex, itemValue, options );
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_AppendArrayItem_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_OptionBits arrayOptions,
+ XMP_StringPtr itemValue,
+ XMP_OptionBits options,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPMeta_AppendArrayItem_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (arrayName == 0) || (*arrayName == 0) ) XMP_Throw ( "Empty array name", kXMPErr_BadXPath );
+
+ XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef );
+ meta->AppendArrayItem ( schemaNS, arrayName, arrayOptions, itemValue, options );
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_SetStructField_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ XMP_StringPtr fieldValue,
+ XMP_OptionBits options,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPMeta_SetStructField_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (structName == 0) || (*structName == 0) ) XMP_Throw ( "Empty struct name", kXMPErr_BadXPath );
+ if ( (fieldNS == 0) || (*fieldNS == 0) ) XMP_Throw ( "Empty field namespace URI", kXMPErr_BadSchema );
+ if ( (fieldName == 0) || (*fieldName == 0) ) XMP_Throw ( "Empty field name", kXMPErr_BadXPath );
+
+ XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef );
+ meta->SetStructField ( schemaNS, structName, fieldNS, fieldName, fieldValue, options );
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_SetQualifier_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName,
+ XMP_StringPtr qualValue,
+ XMP_OptionBits options,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPMeta_SetQualifier_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath );
+ if ( (qualNS == 0) || (*qualNS == 0) ) XMP_Throw ( "Empty qualifier namespace URI", kXMPErr_BadSchema );
+ if ( (qualName == 0) || (*qualName == 0) ) XMP_Throw ( "Empty qualifier name", kXMPErr_BadXPath );
+
+ XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef );
+ meta->SetQualifier ( schemaNS, propName, qualNS, qualName, qualValue, options );
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_DeleteProperty_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPMeta_DeleteProperty_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath );
+
+ XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef );
+ meta->DeleteProperty ( schemaNS, propName );
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_DeleteArrayItem_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPMeta_DeleteArrayItem_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (arrayName == 0) || (*arrayName == 0) ) XMP_Throw ( "Empty array name", kXMPErr_BadXPath );
+
+ XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef );
+ meta->DeleteArrayItem ( schemaNS, arrayName, itemIndex );
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_DeleteStructField_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPMeta_DeleteStructField_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (structName == 0) || (*structName == 0) ) XMP_Throw ( "Empty struct name", kXMPErr_BadXPath );
+ if ( (fieldNS == 0) || (*fieldNS == 0) ) XMP_Throw ( "Empty field namespace URI", kXMPErr_BadSchema );
+ if ( (fieldName == 0) || (*fieldName == 0) ) XMP_Throw ( "Empty field name", kXMPErr_BadXPath );
+
+ XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef );
+ meta->DeleteStructField ( schemaNS, structName, fieldNS, fieldName );
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_DeleteQualifier_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPMeta_DeleteQualifier_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath );
+ if ( (qualNS == 0) || (*qualNS == 0) ) XMP_Throw ( "Empty qualifier namespace URI", kXMPErr_BadSchema );
+ if ( (qualName == 0) || (*qualName == 0) ) XMP_Throw ( "Empty qualifier name", kXMPErr_BadXPath );
+
+ XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef );
+ meta->DeleteQualifier ( schemaNS, propName, qualNS, qualName );
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_DoesPropertyExist_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ WXMP_Result * wResult ) /* const */
+{
+ XMP_ENTER_WRAPPER ( "WXMPMeta_DoesPropertyExist_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath );
+
+ const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef );
+ bool found = meta.DoesPropertyExist ( schemaNS, propName );
+ wResult->int32Result = found;
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_DoesArrayItemExist_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex,
+ WXMP_Result * wResult ) /* const */
+{
+ XMP_ENTER_WRAPPER ( "WXMPMeta_DoesArrayItemExist_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (arrayName == 0) || (*arrayName == 0) ) XMP_Throw ( "Empty array name", kXMPErr_BadXPath );
+
+ const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef );
+ bool found = meta.DoesArrayItemExist ( schemaNS, arrayName, itemIndex );
+ wResult->int32Result = found;
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_DoesStructFieldExist_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ WXMP_Result * wResult ) /* const */
+{
+ XMP_ENTER_WRAPPER ( "WXMPMeta_DoesStructFieldExist_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (structName == 0) || (*structName == 0) ) XMP_Throw ( "Empty struct name", kXMPErr_BadXPath );
+ if ( (fieldNS == 0) || (*fieldNS == 0) ) XMP_Throw ( "Empty field namespace URI", kXMPErr_BadSchema );
+ if ( (fieldName == 0) || (*fieldName == 0) ) XMP_Throw ( "Empty field name", kXMPErr_BadXPath );
+
+ const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef );
+ bool found = meta.DoesStructFieldExist ( schemaNS, structName, fieldNS, fieldName );
+ wResult->int32Result = found;
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_DoesQualifierExist_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName,
+ WXMP_Result * wResult ) /* const */
+{
+ XMP_ENTER_WRAPPER ( "WXMPMeta_DoesQualifierExist_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath );
+ if ( (qualNS == 0) || (*qualNS == 0) ) XMP_Throw ( "Empty qualifier namespace URI", kXMPErr_BadSchema );
+ if ( (qualName == 0) || (*qualName == 0) ) XMP_Throw ( "Empty qualifier name", kXMPErr_BadXPath );
+
+ const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef );
+ bool found = meta.DoesQualifierExist ( schemaNS, propName, qualNS, qualName );
+ wResult->int32Result = found;
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_GetLocalizedText_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_StringPtr genericLang,
+ XMP_StringPtr specificLang,
+ XMP_StringPtr * actualLang,
+ XMP_StringLen * langSize,
+ XMP_StringPtr * itemValue,
+ XMP_StringLen * valueSize,
+ XMP_OptionBits * options,
+ WXMP_Result * wResult ) /* const */
+{
+ XMP_ENTER_WRAPPER ( "WXMPMeta_GetLocalizedText_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (arrayName == 0) || (*arrayName == 0) ) XMP_Throw ( "Empty array name", kXMPErr_BadXPath );
+ if ( genericLang == 0 ) genericLang = "";
+ if ( (specificLang == 0) ||(*specificLang == 0) ) XMP_Throw ( "Empty specific language", kXMPErr_BadParam );
+
+ if ( actualLang == 0 ) actualLang = &voidStringPtr;
+ if ( langSize == 0 ) langSize = &voidStringLen;
+ if ( itemValue == 0 ) itemValue = &voidStringPtr;
+ if ( valueSize == 0 ) valueSize = &voidStringLen;
+ if ( options == 0 ) options = &voidOptionBits;
+
+ const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef );
+ bool found = meta.GetLocalizedText ( schemaNS, arrayName, genericLang, specificLang,
+ actualLang, langSize, itemValue, valueSize, options );
+ wResult->int32Result = found;
+
+ XMP_EXIT_WRAPPER_KEEP_LOCK ( found )
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_SetLocalizedText_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_StringPtr genericLang,
+ XMP_StringPtr specificLang,
+ XMP_StringPtr itemValue,
+ XMP_OptionBits options,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPMeta_SetLocalizedText_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (arrayName == 0) || (*arrayName == 0) ) XMP_Throw ( "Empty array name", kXMPErr_BadXPath );
+ if ( genericLang == 0 ) genericLang = "";
+ if ( (specificLang == 0) ||(*specificLang == 0) ) XMP_Throw ( "Empty specific language", kXMPErr_BadParam );
+ if ( itemValue == 0 ) itemValue = "";
+
+ XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef );
+ meta->SetLocalizedText ( schemaNS, arrayName, genericLang, specificLang, itemValue, options );
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_GetProperty_Bool_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_Bool * propValue,
+ XMP_OptionBits * options,
+ WXMP_Result * wResult ) /* const */
+{
+ XMP_ENTER_WRAPPER ( "WXMPMeta_GetProperty_Bool_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath );
+
+ if ( propValue == 0 ) propValue = &voidByte;
+ if ( options == 0 ) options = &voidOptionBits;
+
+ const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef );
+ bool value;
+ bool found = meta.GetProperty_Bool ( schemaNS, propName, &value, options );
+ if ( propValue != 0 ) *propValue = value;
+ wResult->int32Result = found;
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_GetProperty_Int_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_Int32 * propValue,
+ XMP_OptionBits * options,
+ WXMP_Result * wResult ) /* const */
+{
+ XMP_ENTER_WRAPPER ( "WXMPMeta_GetProperty_Int_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath );
+
+ if ( propValue == 0 ) propValue = &voidInt32;
+ if ( options == 0 ) options = &voidOptionBits;
+
+ const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef );
+ bool found = meta.GetProperty_Int ( schemaNS, propName, propValue, options );
+ wResult->int32Result = found;
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_GetProperty_Int64_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_Int64 * propValue,
+ XMP_OptionBits * options,
+ WXMP_Result * wResult ) /* const */
+{
+ XMP_ENTER_WRAPPER ( "WXMPMeta_GetProperty_Int64_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath );
+
+ if ( propValue == 0 ) propValue = &voidInt64;
+ if ( options == 0 ) options = &voidOptionBits;
+
+ const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef );
+ bool found = meta.GetProperty_Int64 ( schemaNS, propName, propValue, options );
+ wResult->int32Result = found;
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_GetProperty_Float_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ double * propValue,
+ XMP_OptionBits * options,
+ WXMP_Result * wResult ) /* const */
+{
+ XMP_ENTER_WRAPPER ( "WXMPMeta_GetProperty_Float_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath );
+
+ if ( propValue == 0 ) propValue = &voidDouble;
+ if ( options == 0 ) options = &voidOptionBits;
+
+ const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef );
+ bool found = meta.GetProperty_Float ( schemaNS, propName, propValue, options );
+ wResult->int32Result = found;
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_GetProperty_Date_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_DateTime * propValue,
+ XMP_OptionBits * options,
+ WXMP_Result * wResult ) /* const */
+{
+ XMP_ENTER_WRAPPER ( "WXMPMeta_GetProperty_Date_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath );
+
+ if ( propValue == 0 ) propValue = &voidDateTime;
+ if ( options == 0 ) options = &voidOptionBits;
+
+ const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef );
+ bool found = meta.GetProperty_Date ( schemaNS, propName, propValue, options );
+ wResult->int32Result = found;
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_SetProperty_Bool_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_Bool propValue,
+ XMP_OptionBits options,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPMeta_SetProperty_Bool_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath );
+
+ XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef );
+ meta->SetProperty_Bool ( schemaNS, propName, propValue, options );
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_SetProperty_Int_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_Int32 propValue,
+ XMP_OptionBits options,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPMeta_SetProperty_Int_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath );
+
+ XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef );
+ meta->SetProperty_Int ( schemaNS, propName, propValue, options );
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_SetProperty_Int64_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_Int64 propValue,
+ XMP_OptionBits options,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPMeta_SetProperty_Int64_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath );
+
+ XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef );
+ meta->SetProperty_Int64 ( schemaNS, propName, propValue, options );
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_SetProperty_Float_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ double propValue,
+ XMP_OptionBits options,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPMeta_SetProperty_Float_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath );
+
+ XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef );
+ meta->SetProperty_Float ( schemaNS, propName, propValue, options );
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_SetProperty_Date_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ const XMP_DateTime & propValue,
+ XMP_OptionBits options,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPMeta_SetProperty_Date_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath );
+
+ XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef );
+ meta->SetProperty_Date ( schemaNS, propName, propValue, options );
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_DumpObject_1 ( XMPMetaRef xmpRef,
+ XMP_TextOutputProc outProc,
+ void * refCon,
+ WXMP_Result * wResult ) /* const */
+{
+ XMP_ENTER_WRAPPER ( "WXMPMeta_DumpObject_1" )
+
+ if ( outProc == 0 ) XMP_Throw ( "Null client output routine", kXMPErr_BadParam );
+
+ const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef );
+ XMP_Status status = meta.DumpObject ( outProc, refCon );
+ wResult->int32Result = status;
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_Clone_1 ( XMPMetaRef xmpRef,
+ XMP_OptionBits options,
+ WXMP_Result * wResult ) /* const */
+{
+ XMP_ENTER_WRAPPER ( "WXMPMeta_Clone_1" )
+
+ const XMPMeta & xOriginal = WtoXMPMeta_Ref ( xmpRef );
+ XMPMeta * xClone = xOriginal.Clone ( options );
+ XMP_Assert ( xClone->clientRefs == 0 ); // ! Gets incremented in TXMPMeta::Clone.
+ wResult->ptrResult = xClone;
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_CountArrayItems_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ WXMP_Result * wResult ) /* const */
+{
+ XMP_ENTER_WRAPPER ( "WXMPMeta_CountArrayItems_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (arrayName == 0) || (*arrayName == 0) ) XMP_Throw ( "Empty array name", kXMPErr_BadXPath );
+
+ const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef );
+ XMP_Index count = meta.CountArrayItems ( schemaNS, arrayName );
+ wResult->int32Result = count;
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_UnlockObject_1 ( XMPMetaRef xmpRef,
+ XMP_OptionBits options ) /* const */
+{
+ WXMP_Result * wResult = &void_wResult; // ! Needed to "fool" the EnterWrapper macro.
+ XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPMeta_UnlockObject_1" )
+
+ const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef );
+ meta.UnlockObject ( options );
+
+ XMP_EXIT_WRAPPER_NO_THROW
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_GetObjectName_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr * namePtr,
+ XMP_StringLen * nameLen,
+ WXMP_Result * wResult ) /* const */
+{
+ XMP_ENTER_WRAPPER ( "WXMPMeta_GetObjectName_1" )
+
+ if ( namePtr == 0 ) namePtr = &voidStringPtr;
+ if ( nameLen == 0 ) nameLen = &voidStringLen;
+
+ const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef );
+ meta.GetObjectName ( namePtr, nameLen );
+
+ XMP_EXIT_WRAPPER_KEEP_LOCK ( true ) // ! Always keep the lock, a string is always returned!
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_SetObjectName_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr name,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPMeta_SetObjectName_1" )
+
+ if ( name == 0 ) name = "";
+
+ XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef );
+ meta->SetObjectName ( name );
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_GetObjectOptions_1 ( XMPMetaRef xmpRef,
+ WXMP_Result * wResult ) /* const */
+{
+ XMP_ENTER_WRAPPER ( "WXMPMeta_GetObjectOptions_1" )
+
+ const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef );
+ XMP_OptionBits options = meta.GetObjectOptions();
+ wResult->int32Result = options;
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_SetObjectOptions_1 ( XMPMetaRef xmpRef,
+ XMP_OptionBits options,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPMeta_SetObjectOptions_1" )
+
+ XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef );
+ meta->SetObjectOptions ( options );
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_ParseFromBuffer_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr buffer,
+ XMP_StringLen bufferSize,
+ XMP_OptionBits options,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPMeta_ParseFromBuffer_1" )
+
+ XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef );
+ meta->ParseFromBuffer ( buffer, bufferSize, options );
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_SerializeToBuffer_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr * rdfString,
+ XMP_StringLen * rdfSize,
+ XMP_OptionBits options,
+ XMP_StringLen padding,
+ XMP_StringPtr newline,
+ XMP_StringPtr indent,
+ XMP_Index baseIndent,
+ WXMP_Result * wResult ) /* const */
+{
+ XMP_ENTER_WRAPPER ( "WXMPMeta_SerializeToBuffer_1" )
+
+ if ( rdfString == 0 ) rdfString = &voidStringPtr;
+ if ( rdfSize == 0 ) rdfSize = &voidStringLen;
+
+ if ( newline == 0 ) newline = "";
+ if ( indent == 0 ) indent = "";
+
+ const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef );
+ meta.SerializeToBuffer ( rdfString, rdfSize, options, padding, newline, indent, baseIndent );
+
+ XMP_EXIT_WRAPPER_KEEP_LOCK ( true ) // ! Always keep the lock, a string is always returned!
+}
+
+// =================================================================================================
+
+#if __cplusplus
+} /* extern "C" */
+#endif
diff --git a/source/XMPCore/WXMPUtils.cpp b/source/XMPCore/WXMPUtils.cpp
new file mode 100644
index 0000000..1ab33f3
--- /dev/null
+++ b/source/XMPCore/WXMPUtils.cpp
@@ -0,0 +1,624 @@
+// =================================================================================================
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+// *** Should change "type * inParam" to "type & inParam"
+
+#include "XMP_Environment.h" // ! This must be the first include!
+#include "XMPCore_Impl.hpp"
+
+#include "XMPUtils.hpp"
+#include "client-glue/WXMPUtils.hpp"
+
+#if XMP_WinBuild
+ #pragma warning ( disable : 4101 ) // unreferenced local variable
+ #pragma warning ( disable : 4189 ) // local variable is initialized but not referenced
+ #pragma warning ( disable : 4800 ) // forcing value to bool 'true' or 'false' (performance warning)
+ #if XMP_DebugBuild
+ #pragma warning ( disable : 4297 ) // function assumed not to throw an exception but does
+ #endif
+#endif
+
+#if __cplusplus
+extern "C" {
+#endif
+
+// =================================================================================================
+// Class Static Wrappers
+// =====================
+
+void
+WXMPUtils_Unlock_1 ( XMP_OptionBits options )
+{
+ WXMP_Result * wResult = &void_wResult; // ! Needed to "fool" the EnterWrapper macro.
+ XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPUtils_Unlock_1" )
+
+ XMPUtils::Unlock ( options );
+
+ XMP_EXIT_WRAPPER_NO_THROW
+}
+
+// =================================================================================================
+
+void
+WXMPUtils_ComposeArrayItemPath_1 ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex,
+ XMP_StringPtr * fullPath,
+ XMP_StringLen * pathSize,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPUtils_ComposeArrayItemPath_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (arrayName == 0) || (*arrayName == 0) ) XMP_Throw ( "Empty array name", kXMPErr_BadXPath );
+
+ if ( fullPath == 0 ) fullPath = &voidStringPtr;
+ if ( pathSize == 0 ) pathSize = &voidStringLen;
+
+ XMPUtils::ComposeArrayItemPath ( schemaNS, arrayName, itemIndex, fullPath, pathSize );
+
+ XMP_EXIT_WRAPPER_KEEP_LOCK ( true )
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPUtils_ComposeStructFieldPath_1 ( XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ XMP_StringPtr * fullPath,
+ XMP_StringLen * pathSize,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPUtils_ComposeStructFieldPath_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (structName == 0) || (*structName == 0) ) XMP_Throw ( "Empty struct name", kXMPErr_BadXPath );
+ if ( (fieldNS == 0) || (*fieldNS == 0) ) XMP_Throw ( "Empty field namespace URI", kXMPErr_BadSchema );
+ if ( (fieldName == 0) || (*fieldName == 0) ) XMP_Throw ( "Empty field name", kXMPErr_BadXPath );
+
+ if ( fullPath == 0 ) fullPath = &voidStringPtr;
+ if ( pathSize == 0 ) pathSize = &voidStringLen;
+
+ XMPUtils::ComposeStructFieldPath ( schemaNS, structName, fieldNS, fieldName, fullPath, pathSize );
+
+ XMP_EXIT_WRAPPER_KEEP_LOCK ( true )
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPUtils_ComposeQualifierPath_1 ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName,
+ XMP_StringPtr * fullPath,
+ XMP_StringLen * pathSize,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPUtils_ComposeQualifierPath_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath );
+ if ( (qualNS == 0) || (*qualNS == 0) ) XMP_Throw ( "Empty qualifier namespace URI", kXMPErr_BadSchema );
+ if ( (qualName == 0) || (*qualName == 0) ) XMP_Throw ( "Empty qualifier name", kXMPErr_BadXPath );
+
+ if ( fullPath == 0 ) fullPath = &voidStringPtr;
+ if ( pathSize == 0 ) pathSize = &voidStringLen;
+
+ XMPUtils::ComposeQualifierPath ( schemaNS, propName, qualNS, qualName, fullPath, pathSize );
+
+ XMP_EXIT_WRAPPER_KEEP_LOCK ( true )
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPUtils_ComposeLangSelector_1 ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_StringPtr langName,
+ XMP_StringPtr * fullPath,
+ XMP_StringLen * pathSize,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPUtils_ComposeLangSelector_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (arrayName == 0) || (*arrayName == 0) ) XMP_Throw ( "Empty array name", kXMPErr_BadXPath );
+ if ( (langName == 0) || (*langName == 0) ) XMP_Throw ( "Empty language name", kXMPErr_BadParam );
+
+ if ( fullPath == 0 ) fullPath = &voidStringPtr;
+ if ( pathSize == 0 ) pathSize = &voidStringLen;
+
+ XMPUtils::ComposeLangSelector ( schemaNS, arrayName, langName, fullPath, pathSize );
+
+ XMP_EXIT_WRAPPER_KEEP_LOCK ( true )
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPUtils_ComposeFieldSelector_1 ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ XMP_StringPtr fieldValue,
+ XMP_StringPtr * fullPath,
+ XMP_StringLen * pathSize,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPUtils_ComposeFieldSelector_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (arrayName == 0) || (*arrayName == 0) ) XMP_Throw ( "Empty array name", kXMPErr_BadXPath );
+ if ( (fieldNS == 0) || (*fieldNS == 0) ) XMP_Throw ( "Empty field namespace URI", kXMPErr_BadSchema );
+ if ( (fieldName == 0) || (*fieldName == 0) ) XMP_Throw ( "Empty field name", kXMPErr_BadXPath );
+ if ( fieldValue == 0 ) fieldValue = "";
+
+ if ( fullPath == 0 ) fullPath = &voidStringPtr;
+ if ( pathSize == 0 ) pathSize = &voidStringLen;
+
+ XMPUtils::ComposeFieldSelector ( schemaNS, arrayName, fieldNS, fieldName, fieldValue, fullPath, pathSize );
+
+ XMP_EXIT_WRAPPER_KEEP_LOCK ( true )
+}
+
+// =================================================================================================
+
+void
+WXMPUtils_ConvertFromBool_1 ( XMP_Bool binValue,
+ XMP_StringPtr * strValue,
+ XMP_StringLen * strSize,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPUtils_ConvertFromBool_1" )
+
+ if ( strValue == 0 ) strValue = &voidStringPtr;
+ if ( strSize == 0 ) strSize = &voidStringLen;
+
+ XMPUtils::ConvertFromBool ( binValue, strValue, strSize );
+
+ XMP_EXIT_WRAPPER_KEEP_LOCK ( true )
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPUtils_ConvertFromInt_1 ( XMP_Int32 binValue,
+ XMP_StringPtr format,
+ XMP_StringPtr * strValue,
+ XMP_StringLen * strSize,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPUtils_ConvertFromInt_1" )
+
+ if ( format == 0 ) format = "";
+
+ if ( strValue == 0 ) strValue = &voidStringPtr;
+ if ( strSize == 0 ) strSize = &voidStringLen;
+
+ XMPUtils::ConvertFromInt ( binValue, format, strValue, strSize );
+
+ XMP_EXIT_WRAPPER_KEEP_LOCK ( true )
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPUtils_ConvertFromInt64_1 ( XMP_Int64 binValue,
+ XMP_StringPtr format,
+ XMP_StringPtr * strValue,
+ XMP_StringLen * strSize,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPUtils_ConvertFromInt64_1" )
+
+ if ( format == 0 ) format = "";
+
+ if ( strValue == 0 ) strValue = &voidStringPtr;
+ if ( strSize == 0 ) strSize = &voidStringLen;
+
+ XMPUtils::ConvertFromInt64 ( binValue, format, strValue, strSize );
+
+ XMP_EXIT_WRAPPER_KEEP_LOCK ( true )
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPUtils_ConvertFromFloat_1 ( double binValue,
+ XMP_StringPtr format,
+ XMP_StringPtr * strValue,
+ XMP_StringLen * strSize,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPUtils_ConvertFromFloat_1" )
+
+ if ( format == 0 ) format = "";
+
+ if ( strValue == 0 ) strValue = &voidStringPtr;
+ if ( strSize == 0 ) strSize = &voidStringLen;
+
+ XMPUtils::ConvertFromFloat ( binValue, format, strValue, strSize );
+
+ XMP_EXIT_WRAPPER_KEEP_LOCK ( true )
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPUtils_ConvertFromDate_1 ( const XMP_DateTime & binValue,
+ XMP_StringPtr * strValue,
+ XMP_StringLen * strSize,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPUtils_ConvertFromDate_1" )
+
+ if ( strValue == 0 ) strValue = &voidStringPtr;
+ if ( strSize == 0 ) strSize = &voidStringLen;
+
+ XMPUtils::ConvertFromDate( binValue, strValue, strSize );
+
+ XMP_EXIT_WRAPPER_KEEP_LOCK ( true )
+}
+
+// =================================================================================================
+
+void
+WXMPUtils_ConvertToBool_1 ( XMP_StringPtr strValue,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPUtils_ConvertToBool_1" )
+
+ if ( (strValue == 0) || (*strValue == 0) ) XMP_Throw ( "Empty string value", kXMPErr_BadParam);
+ XMP_Bool result = XMPUtils::ConvertToBool ( strValue );
+ wResult->int32Result = result;
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPUtils_ConvertToInt_1 ( XMP_StringPtr strValue,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPUtils_ConvertToInt_1" )
+
+ if ( (strValue == 0) || (*strValue == 0) ) XMP_Throw ( "Empty string value", kXMPErr_BadParam);
+ XMP_Int32 result = XMPUtils::ConvertToInt ( strValue );
+ wResult->int32Result = result;
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPUtils_ConvertToInt64_1 ( XMP_StringPtr strValue,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPUtils_ConvertToInt64_1" )
+
+ if ( (strValue == 0) || (*strValue == 0) ) XMP_Throw ( "Empty string value", kXMPErr_BadParam);
+ XMP_Int64 result = XMPUtils::ConvertToInt64 ( strValue );
+ wResult->int64Result = result;
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPUtils_ConvertToFloat_1 ( XMP_StringPtr strValue,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPUtils_ConvertToFloat_1")
+
+ if ( (strValue == 0) || (*strValue == 0) ) XMP_Throw ( "Empty string value", kXMPErr_BadParam);
+ double result = XMPUtils::ConvertToFloat ( strValue );
+ wResult->floatResult = result;
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPUtils_ConvertToDate_1 ( XMP_StringPtr strValue,
+ XMP_DateTime * binValue,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPUtils_ConvertToDate_1" )
+
+ if ( binValue == 0 ) XMP_Throw ( "Null output date", kXMPErr_BadParam); // ! Pointer is from the client.
+ XMPUtils::ConvertToDate ( strValue, binValue );
+
+ XMP_EXIT_WRAPPER
+}
+
+// =================================================================================================
+
+void
+WXMPUtils_CurrentDateTime_1 ( XMP_DateTime * time,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPUtils_CurrentDateTime_1" )
+
+ if ( time == 0 ) XMP_Throw ( "Null output date", kXMPErr_BadParam);
+ XMPUtils::CurrentDateTime ( time );
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPUtils_SetTimeZone_1 ( XMP_DateTime * time,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPUtils_SetTimeZone_1" )
+
+ if ( time == 0 ) XMP_Throw ( "Null output date", kXMPErr_BadParam);
+ XMPUtils::SetTimeZone ( time );
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPUtils_ConvertToUTCTime_1 ( XMP_DateTime * time,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPUtils_ConvertToUTCTime_1" )
+
+ if ( time == 0 ) XMP_Throw ( "Null output date", kXMPErr_BadParam);
+ XMPUtils::ConvertToUTCTime ( time );
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPUtils_ConvertToLocalTime_1 ( XMP_DateTime * time,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPUtils_ConvertToLocalTime_1" )
+
+ if ( time == 0 ) XMP_Throw ( "Null output date", kXMPErr_BadParam);
+ XMPUtils::ConvertToLocalTime ( time );
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPUtils_CompareDateTime_1 ( const XMP_DateTime & left,
+ const XMP_DateTime & right,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPUtils_CompareDateTime_1" )
+
+ int result = XMPUtils::CompareDateTime ( left, right );
+ wResult->int32Result = result;
+
+ XMP_EXIT_WRAPPER
+}
+
+// =================================================================================================
+
+void
+WXMPUtils_EncodeToBase64_1 ( XMP_StringPtr rawStr,
+ XMP_StringLen rawLen,
+ XMP_StringPtr * encodedStr,
+ XMP_StringLen * encodedLen,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPUtils_EncodeToBase64_1" )
+
+ if ( encodedStr == 0 ) encodedStr = &voidStringPtr;
+ if ( encodedLen == 0 ) encodedLen = &voidStringLen;
+
+ XMPUtils::EncodeToBase64 ( rawStr, rawLen, encodedStr, encodedLen );
+
+ XMP_EXIT_WRAPPER_KEEP_LOCK ( true )
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPUtils_DecodeFromBase64_1 ( XMP_StringPtr encodedStr,
+ XMP_StringLen encodedLen,
+ XMP_StringPtr * rawStr,
+ XMP_StringLen * rawLen,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPUtils_DecodeFromBase64_1" )
+
+ if ( rawStr == 0 ) rawStr = &voidStringPtr;
+ if ( rawLen == 0 ) rawLen = &voidStringLen;
+
+ XMPUtils::DecodeFromBase64 ( encodedStr, encodedLen, rawStr, rawLen );
+
+ XMP_EXIT_WRAPPER_KEEP_LOCK ( true )
+}
+
+// =================================================================================================
+
+void
+WXMPUtils_PackageForJPEG_1 ( XMPMetaRef wxmpObj,
+ XMP_StringPtr * stdStr,
+ XMP_StringLen * stdLen,
+ XMP_StringPtr * extStr,
+ XMP_StringLen * extLen,
+ XMP_StringPtr * digestStr,
+ XMP_StringLen * digestLen,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPUtils_PackageForJPEG_1" )
+
+ if ( stdStr == 0 ) stdStr = &voidStringPtr;
+ if ( stdLen == 0 ) stdLen = &voidStringLen;
+ if ( extStr == 0 ) extStr = &voidStringPtr;
+ if ( extLen == 0 ) extLen = &voidStringLen;
+ if ( digestStr == 0 ) digestStr = &voidStringPtr;
+ if ( digestLen == 0 ) digestLen = &voidStringLen;
+
+ const XMPMeta & xmpObj = WtoXMPMeta_Ref ( wxmpObj );
+ XMPUtils::PackageForJPEG ( xmpObj, stdStr, stdLen, extStr, extLen, digestStr, digestLen );
+
+ XMP_EXIT_WRAPPER_KEEP_LOCK ( true )
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPUtils_MergeFromJPEG_1 ( XMPMetaRef wfullXMP,
+ XMPMetaRef wextendedXMP,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPUtils_MergeFromJPEG_1" )
+
+ if ( wfullXMP == 0 ) XMP_Throw ( "Output XMP pointer is null", kXMPErr_BadParam );
+
+ XMPMeta * fullXMP = WtoXMPMeta_Ptr ( wfullXMP );
+ const XMPMeta & extendedXMP = WtoXMPMeta_Ref ( wextendedXMP );
+ XMPUtils::MergeFromJPEG ( fullXMP, extendedXMP );
+
+ XMP_EXIT_WRAPPER
+}
+
+// =================================================================================================
+
+void
+WXMPUtils_CatenateArrayItems_1 ( XMPMetaRef wxmpObj,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_StringPtr separator,
+ XMP_StringPtr quotes,
+ XMP_OptionBits options,
+ XMP_StringPtr * catedStr,
+ XMP_StringLen * catedLen,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPUtils_CatenateArrayItems_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (arrayName == 0) || (*arrayName == 0) ) XMP_Throw ( "Empty array name", kXMPErr_BadXPath );
+
+ if ( separator == 0 ) separator = "; ";
+ if ( quotes == 0 ) quotes = "\"";
+
+ if ( catedStr == 0 ) catedStr = &voidStringPtr;
+ if ( catedLen == 0 ) catedLen = &voidStringLen;
+
+ const XMPMeta & xmpObj = WtoXMPMeta_Ref ( wxmpObj );
+ XMPUtils::CatenateArrayItems ( xmpObj, schemaNS, arrayName, separator, quotes, options, catedStr, catedLen );
+
+ XMP_EXIT_WRAPPER_KEEP_LOCK ( true )
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPUtils_SeparateArrayItems_1 ( XMPMetaRef wxmpObj,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_OptionBits options,
+ XMP_StringPtr catedStr,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPUtils_SeparateArrayItems_1" )
+
+ if ( wxmpObj == 0 ) XMP_Throw ( "Output XMP pointer is null", kXMPErr_BadParam );
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (arrayName == 0) || (*arrayName == 0) ) XMP_Throw ( "Empty array name", kXMPErr_BadXPath );
+ if ( catedStr == 0 ) catedStr = "";
+
+ XMPMeta * xmpObj = WtoXMPMeta_Ptr ( wxmpObj );
+ XMPUtils::SeparateArrayItems ( xmpObj, schemaNS, arrayName, options, catedStr );
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPUtils_RemoveProperties_1 ( XMPMetaRef wxmpObj,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_OptionBits options,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPUtils_RemoveProperties_1" )
+
+ if ( wxmpObj == 0 ) XMP_Throw ( "Output XMP pointer is null", kXMPErr_BadParam );
+ if ( schemaNS == 0 ) schemaNS = "";
+ if ( propName == 0 ) propName = "";
+
+ XMPMeta * xmpObj = WtoXMPMeta_Ptr ( wxmpObj );
+ XMPUtils::RemoveProperties ( xmpObj, schemaNS, propName, options );
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPUtils_AppendProperties_1 ( XMPMetaRef wSource,
+ XMPMetaRef wDest,
+ XMP_OptionBits options,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPUtils_AppendProperties_1" )
+
+ if ( wDest == 0 ) XMP_Throw ( "Output XMP pointer is null", kXMPErr_BadParam );
+
+ const XMPMeta & source = WtoXMPMeta_Ref ( wSource );
+ XMPMeta * dest = WtoXMPMeta_Ptr ( wDest );
+ XMPUtils::AppendProperties ( source, dest, options );
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPUtils_DuplicateSubtree_1 ( XMPMetaRef wSource,
+ XMPMetaRef wDest,
+ XMP_StringPtr sourceNS,
+ XMP_StringPtr sourceRoot,
+ XMP_StringPtr destNS,
+ XMP_StringPtr destRoot,
+ XMP_OptionBits options,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPUtils_DuplicateSubtree_1" )
+
+ if ( wDest == 0 ) XMP_Throw ( "Output XMP pointer is null", kXMPErr_BadParam );
+ if ( (sourceNS == 0) || (*sourceNS == 0) ) XMP_Throw ( "Empty source schema URI", kXMPErr_BadSchema );
+ if ( (sourceRoot == 0) || (*sourceRoot == 0) ) XMP_Throw ( "Empty source root name", kXMPErr_BadXPath );
+ if ( destNS == 0 ) destNS = sourceNS;
+ if ( destRoot == 0 ) destRoot = sourceRoot;
+
+ const XMPMeta & source = WtoXMPMeta_Ref ( wSource );
+ XMPMeta * dest = WtoXMPMeta_Ptr ( wDest );
+ XMPUtils::DuplicateSubtree ( source, dest, sourceNS, sourceRoot, destNS, destRoot, options );
+
+ XMP_EXIT_WRAPPER
+}
+
+// =================================================================================================
+
+#if __cplusplus
+} /* extern "C" */
+#endif
diff --git a/source/XMPCore/XMLParserAdapter.hpp b/source/XMPCore/XMLParserAdapter.hpp
new file mode 100644
index 0000000..2d78779
--- /dev/null
+++ b/source/XMPCore/XMLParserAdapter.hpp
@@ -0,0 +1,53 @@
+#ifndef __XMLParserAdapter_hpp__
+#define __XMLParserAdapter_hpp__
+
+// =================================================================================================
+// Copyright 2005-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "XMP_Environment.h" // ! Must be the first #include!
+#include "XMPCore_Impl.hpp"
+
+// =================================================================================================
+// Abstract base class for XML parser adapters used by the XMP toolkit.
+// =================================================================================================
+
+enum { kXMLPendingInputMax = 16 };
+
+class XMLParserAdapter {
+public:
+
+ XMLParserAdapter()
+ : tree(0,"",kRootNode), rootNode(0), rootCount(0), charEncoding(XMP_OptionBits(-1)), pendingCount(0)
+ {
+ #if XMP_DebugBuild
+ parseLog = 0;
+ #endif
+ };
+
+ virtual ~XMLParserAdapter() {};
+
+ virtual void ParseBuffer ( const void * buffer, size_t length, bool last ) = 0;
+
+ XML_Node tree;
+ XML_NodeVector parseStack;
+ XML_Node * rootNode;
+ size_t rootCount;
+
+ XMP_OptionBits charEncoding;
+ size_t pendingCount;
+ unsigned char pendingInput[kXMLPendingInputMax]; // Buffered input for character encoding checks.
+
+ #if XMP_DebugBuild
+ FILE * parseLog;
+ #endif
+
+};
+
+// =================================================================================================
+
+#endif // __XMLParserAdapter_hpp__
diff --git a/source/XMPCore/XMPCore_Impl.cpp b/source/XMPCore/XMPCore_Impl.cpp
new file mode 100644
index 0000000..32687ee
--- /dev/null
+++ b/source/XMPCore/XMPCore_Impl.cpp
@@ -0,0 +1,1507 @@
+// =================================================================================================
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "XMP_Environment.h" // ! This must be the first include!
+#include "XMP_Version.h"
+#include "XMPCore_Impl.hpp"
+#include "XMPMeta.hpp" // *** For use of GetNamespacePrefix in FindSchemaNode.
+
+#include "UnicodeInlines.incl_cpp"
+
+#include <algorithm>
+
+using namespace std;
+
+#if XMP_WinBuild
+ #pragma warning ( disable : 4290 ) // C++ exception specification ignored except ... not __declspec(nothrow)
+ #pragma warning ( disable : 4800 ) // forcing value to bool 'true' or 'false' (performance warning)
+#endif
+
+// *** Add debug codegen checks, e.g. that typical masking operations really work
+// *** Make option constants 0x...UL.
+
+// Internal code should be using #if with XMP_MacBuild, XMP_WinBuild, or XMP_UNIXBuild.
+// This is a sanity check in case of accidental use of *_ENV. Some clients use the poor
+// practice of defining the *_ENV macro with an empty value.
+#if defined ( MAC_ENV )
+ #if ! MAC_ENV
+ #error "MAC_ENV must be defined so that \"#if MAC_ENV\" is true"
+ #endif
+#elif defined ( WIN_ENV )
+ #if ! WIN_ENV
+ #error "WIN_ENV must be defined so that \"#if WIN_ENV\" is true"
+ #endif
+#elif defined ( UNIX_ENV )
+ #if ! UNIX_ENV
+ #error "UNIX_ENV must be defined so that \"#if UNIX_ENV\" is true"
+ #endif
+#endif
+
+// =================================================================================================
+// Static Variables
+// ================
+
+XMP_Int32 sXMP_InitCount = 0;
+
+XMP_StringMap * sNamespaceURIToPrefixMap = 0;
+XMP_StringMap * sNamespacePrefixToURIMap = 0;
+
+XMP_AliasMap * sRegisteredAliasMap = 0; // Needed by XMPIterator.
+
+XMP_VarString * sOutputNS = 0;
+XMP_VarString * sOutputStr = 0;
+XMP_VarString * sExceptionMessage = 0;
+
+XMP_Mutex sXMPCoreLock;
+int sLockCount = 0;
+
+#if TraceXMPCalls
+ FILE * xmpOut = stderr;
+#endif
+
+void * voidVoidPtr = 0; // Used to backfill null output parameters.
+XMP_StringPtr voidStringPtr = 0;
+XMP_StringLen voidStringLen = 0;
+XMP_OptionBits voidOptionBits = 0;
+XMP_Uns8 voidByte = 0;
+bool voidBool = 0;
+XMP_Int32 voidInt32 = 0;
+XMP_Int64 voidInt64 = 0;
+double voidDouble = 0.0;
+XMP_DateTime voidDateTime;
+WXMP_Result void_wResult;
+
+// =================================================================================================
+// Mutex Utilities
+// ===============
+
+// ! Note that the mutex need not be "recursive", allowing the same thread to acquire it multiple
+// ! times. There is a single XMP lock which is acquired in the wrapper classes. Internal calls
+// ! never go back out to the wrappers.
+
+#if XMP_MacBuild
+
+ bool XMP_InitMutex ( XMP_Mutex * mutex ) {
+ OSStatus err = MPCreateCriticalRegion ( mutex );
+ return (err == noErr );
+ }
+
+ void XMP_TermMutex ( XMP_Mutex & mutex ) {
+ (void) MPDeleteCriticalRegion ( mutex );
+ }
+
+ void XMP_EnterCriticalRegion ( XMP_Mutex & mutex ) {
+ OSStatus err = MPEnterCriticalRegion ( mutex, kDurationForever );
+ if ( err != noErr ) XMP_Throw ( "XMP_EnterCriticalRegion - MPEnterCriticalRegion failure", kXMPErr_ExternalFailure );
+ }
+
+ void XMP_ExitCriticalRegion ( XMP_Mutex & mutex ) {
+ OSStatus err = MPExitCriticalRegion ( mutex );
+ if ( err != noErr ) XMP_Throw ( "XMP_ExitCriticalRegion - MPExitCriticalRegion failure", kXMPErr_ExternalFailure );
+ }
+
+#elif XMP_WinBuild
+
+ bool XMP_InitMutex ( XMP_Mutex * mutex ) {
+ InitializeCriticalSection ( mutex );
+ return true;
+ }
+
+ void XMP_TermMutex ( XMP_Mutex & mutex ) {
+ DeleteCriticalSection ( &mutex );
+ }
+
+ void XMP_EnterCriticalRegion ( XMP_Mutex & mutex ) {
+ EnterCriticalSection ( &mutex );
+ }
+
+ void XMP_ExitCriticalRegion ( XMP_Mutex & mutex ) {
+ LeaveCriticalSection ( &mutex );
+ }
+
+#elif XMP_UNIXBuild
+
+ // ! Would be nice to specify PTHREAD_MUTEX_ERRORCHECK, but the POSIX documentation is useless.
+ // ! Would be OK but overkill to specify PTHREAD_MUTEX_RECURSIVE.
+
+ bool XMP_InitMutex ( XMP_Mutex * mutex ) {
+ int err = pthread_mutex_init ( mutex, 0 );
+ return (err == 0 );
+ }
+
+ void XMP_TermMutex ( XMP_Mutex & mutex ) {
+ (void) pthread_mutex_destroy ( &mutex );
+ }
+
+ void XMP_EnterCriticalRegion ( XMP_Mutex & mutex ) {
+ int err = pthread_mutex_lock ( &mutex );
+ if ( err != 0 ) XMP_Throw ( "XMP_EnterCriticalRegion - pthread_mutex_lock failure", kXMPErr_ExternalFailure );
+ }
+
+ void XMP_ExitCriticalRegion ( XMP_Mutex & mutex ) {
+ int err = pthread_mutex_unlock ( &mutex );
+ if ( err != 0 ) XMP_Throw ( "XMP_ExitCriticalRegion - pthread_mutex_unlock failure", kXMPErr_ExternalFailure );
+ }
+
+#endif
+
+// =================================================================================================
+// Local Utilities
+// ===============
+
+// -------------------------------------------------------------------------------------------------
+// VerifyXPathRoot
+// ---------------
+//
+// Set up the first 2 components of the expanded XPath. Normalizes the various cases of using the
+// full schema URI and/or a qualified root property name. Returns true for normal processing. If
+// allowUnknownSchemaNS is true and the schema namespace is not registered, false is returned. If
+// allowUnknownSchemaNS is false and the schema namespace is not registered, an exception is thrown.
+
+// *** Should someday check the full syntax.
+
+static void
+VerifyXPathRoot ( XMP_StringPtr schemaURI,
+ XMP_StringPtr propName,
+ XMP_ExpandedXPath * expandedXPath )
+{
+ // Do some basic checks on the URI and name. Try to lookup the URI. See if the name is qualified.
+
+ XMP_Assert ( (schemaURI != 0) && (propName != 0) && (*propName != 0) );
+ XMP_Assert ( (expandedXPath != 0) && (expandedXPath->empty()) );
+
+ if ( *schemaURI == 0 ) XMP_Throw ( "Schema namespace URI is required", kXMPErr_BadSchema );
+
+ if ( (*propName == '?') || (*propName == '@') ) {
+ XMP_Throw ( "Top level name must not be a qualifier", kXMPErr_BadXPath );
+ }
+ for ( XMP_StringPtr ch = propName; *ch != 0; ++ch ) {
+ if ( (*ch == '/') || (*ch == '[') ) {
+ XMP_Throw ( "Top level name must be simple", kXMPErr_BadXPath );
+ }
+ }
+
+ XMP_StringMapPos uriPos = sNamespaceURIToPrefixMap->find ( XMP_VarString ( schemaURI ) );
+ if ( uriPos == sNamespaceURIToPrefixMap->end() ) {
+ XMP_Throw ( "Unregistered schema namespace URI", kXMPErr_BadSchema );
+ }
+
+ XMP_StringPtr colonPos = propName;
+ while ( (*colonPos != 0) && (*colonPos != ':') ) ++colonPos;
+ VerifySimpleXMLName ( propName, colonPos ); // Verify the part before any colon.
+
+ // Verify the various URI and prefix combinations. Initialize the expanded XPath.
+
+ if ( *colonPos == 0 ) {
+
+ // The propName is unqualified, use the schemaURI and associated prefix.
+
+ expandedXPath->push_back ( XPathStepInfo ( schemaURI, kXMP_SchemaNode ) );
+ expandedXPath->push_back ( XPathStepInfo ( uriPos->second, 0 ) );
+ (*expandedXPath)[kRootPropStep].step += propName;
+
+ } else {
+
+ // The propName is qualified. Make sure the prefix is legit. Use the associated URI and qualified name.
+
+ size_t prefixLen = colonPos - propName + 1; // ! Include the colon.
+ VerifySimpleXMLName ( colonPos+1, colonPos+strlen(colonPos) );
+
+ XMP_VarString prefix ( propName, prefixLen );
+ XMP_StringMapPos prefixPos = sNamespacePrefixToURIMap->find ( prefix );
+ if ( prefixPos == sNamespacePrefixToURIMap->end() ) {
+ XMP_Throw ( "Unknown schema namespace prefix", kXMPErr_BadSchema );
+ }
+ if ( prefix != uriPos->second ) {
+ XMP_Throw ( "Schema namespace URI and prefix mismatch", kXMPErr_BadSchema );
+ }
+
+ expandedXPath->push_back ( XPathStepInfo ( schemaURI, kXMP_SchemaNode ) );
+ expandedXPath->push_back ( XPathStepInfo ( propName, 0 ) );
+
+ }
+
+} // VerifyXPathRoot
+
+// -------------------------------------------------------------------------------------------------
+// VerifyQualName
+// --------------
+
+static void
+VerifyQualName ( XMP_StringPtr qualName, XMP_StringPtr nameEnd )
+{
+ if ( qualName >= nameEnd ) XMP_Throw ( "Empty qualified name", kXMPErr_BadXPath );
+
+ XMP_StringPtr colonPos = qualName;
+ while ( (colonPos < nameEnd) && (*colonPos != ':') ) ++colonPos;
+ if ( (colonPos == qualName) || (colonPos >= nameEnd) ) XMP_Throw ( "Ill-formed qualified name", kXMPErr_BadXPath );
+
+ VerifySimpleXMLName ( qualName, colonPos );
+ VerifySimpleXMLName ( colonPos+1, nameEnd );
+
+ size_t prefixLen = colonPos - qualName + 1; // ! Include the colon.
+ XMP_VarString prefix ( qualName, prefixLen );
+ XMP_StringMapPos prefixPos = sNamespacePrefixToURIMap->find ( prefix );
+ if ( prefixPos == sNamespacePrefixToURIMap->end() ) {
+ XMP_Throw ( "Unknown namespace prefix for qualified name", kXMPErr_BadXPath );
+ }
+
+} // VerifyQualName
+
+// -------------------------------------------------------------------------------------------------
+// FindIndexedItem
+// ---------------
+//
+// [index] An element of an array.
+//
+// Support the implicit creation of a new last item.
+
+static XMP_Index
+FindIndexedItem ( XMP_Node * arrayNode, const XMP_VarString & indexStep, bool createNodes )
+{
+ XMP_Index index = 0;
+ size_t chLim = indexStep.size() - 1;
+
+ XMP_Assert ( (chLim >= 2) && (indexStep[0] == '[') && (indexStep[chLim] == ']') );
+
+ for ( size_t chNum = 1; chNum != chLim; ++chNum ) {
+ XMP_Assert ( ('0' <= indexStep[chNum]) && (indexStep[chNum] <= '9') );
+ index = (index * 10) + (indexStep[chNum] - '0');
+ if ( index < 0 ) {
+ XMP_Throw ( "Array index overflow", kXMPErr_BadXPath ); // ! Overflow, not truly negative.
+ }
+ }
+
+ --index; // Change to a C-style, zero based index.
+ if ( index < 0 ) XMP_Throw ( "Array index must be larger than zero", kXMPErr_BadXPath );
+
+ if ( (index == (XMP_Index)arrayNode->children.size()) && createNodes ) { // Append a new last+1 node.
+ XMP_Node * newItem = new XMP_Node ( arrayNode, kXMP_ArrayItemName, kXMP_NewImplicitNode );
+ arrayNode->children.push_back ( newItem );
+ }
+
+ // ! Don't throw here for a too large index. SetProperty will throw, GetProperty will not.
+ if ( index >= (XMP_Index)arrayNode->children.size() ) index = -1;
+ return index;
+
+} // FindIndexedItem
+
+// -------------------------------------------------------------------------------------------------
+// SplitNameAndValue
+// -----------------
+//
+// Split the name and value parts for field and qualifier selectors:
+//
+// [qualName="value"] An element in an array of structs, chosen by a field value.
+// [?qualName="value"] An element in an array, chosen by a qualifier value.
+//
+// The value portion is a string quoted by ''' or '"'. The value may contain any character including
+// a doubled quoting character. The value may be empty.
+
+static void
+SplitNameAndValue ( const XMP_VarString & selStep, XMP_VarString * nameStr, XMP_VarString * valueStr )
+{
+ XMP_StringPtr partBegin = selStep.c_str();
+ XMP_StringPtr partEnd;
+
+ const XMP_StringPtr valueEnd = partBegin + (selStep.size() - 2);
+ const char quote = *valueEnd;
+
+ XMP_Assert ( (*partBegin == '[') && (*(valueEnd+1) == ']') );
+ XMP_Assert ( (selStep.size() >= 6) && ((quote == '"') || (quote == '\'')) );
+
+ // Extract the name part.
+
+ ++partBegin; // Skip the opening '['.
+ if ( *partBegin == '?' ) ++partBegin;
+ for ( partEnd = partBegin+1; *partEnd != '='; ++partEnd ) {};
+
+ nameStr->assign ( partBegin, (partEnd - partBegin) );
+
+ // Extract the value part, reducing doubled quotes.
+
+ XMP_Assert ( *(partEnd+1) == quote );
+
+ partBegin = partEnd + 2;
+ valueStr->erase();
+ valueStr->reserve ( valueEnd - partBegin ); // Maximum length, don't optimize doubled quotes.
+
+ for ( partEnd = partBegin; partEnd < valueEnd; ++partEnd ) {
+ if ( (*partEnd == quote) && (*(partEnd+1) == quote) ) {
+ ++partEnd;
+ valueStr->append ( partBegin, (partEnd - partBegin) );
+ partBegin = partEnd+1; // ! Loop will increment partEnd again.
+ }
+ }
+
+ valueStr->append ( partBegin, (partEnd - partBegin) ); // ! The loop does not add the last part.
+
+} // SplitNameAndValue
+
+// -------------------------------------------------------------------------------------------------
+// LookupQualSelector
+// ------------------
+//
+// [?qualName="value"] An element in an array, chosen by a qualifier value.
+//
+// Note that we don't create implicit nodes for qualifier selectors, so no CreateNodes parameter.
+
+static XMP_Index
+LookupQualSelector ( XMP_Node * arrayNode, const XMP_VarString & qualName, XMP_VarString & qualValue )
+{
+ XMP_Index index;
+
+ if ( qualName == "xml:lang" ) {
+
+ // *** Should check that the value is legit RFC 1766/3066.
+ NormalizeLangValue ( &qualValue );
+ index = LookupLangItem ( arrayNode, qualValue ) ;
+
+ } else {
+
+ XMP_Index itemLim;
+ for ( index = 0, itemLim = arrayNode->children.size(); index != itemLim; ++index ) {
+
+ const XMP_Node * currItem = arrayNode->children[index];
+ XMP_Assert ( currItem->parent == arrayNode );
+
+ size_t q, qualLim;
+ for ( q = 0, qualLim = currItem->qualifiers.size(); q != qualLim; ++q ) {
+ const XMP_Node * currQual = currItem->qualifiers[q];
+ XMP_Assert ( currQual->parent == currItem );
+ if ( currQual->name != qualName ) continue;
+ if ( currQual->value == qualValue ) break; // Exit qual loop.
+ }
+ if ( q != qualLim ) break; // Exit child loop, found an item with a matching qualifier.
+
+ }
+ if ( index == itemLim ) index = -1;
+
+ }
+
+ return index;
+
+} // LookupQualSelector
+
+// -------------------------------------------------------------------------------------------------
+// FollowXPathStep
+// ---------------
+//
+// After processing by ExpandXPath, a step can be of these forms:
+// qualName A top level property or struct field.
+// [index] An element of an array.
+// [last()] The last element of an array.
+// [qualName="value"] An element in an array of structs, chosen by a field value.
+// [?qualName="value"] An element in an array, chosen by a qualifier value.
+// ?qualName A general qualifier.
+//
+// Find the appropriate child node, resolving aliases, and optionally creating nodes.
+
+static XMP_Node *
+FollowXPathStep ( XMP_Node * parentNode,
+ const XMP_ExpandedXPath & fullPath,
+ size_t stepNum,
+ bool createNodes,
+ XMP_NodePtrPos * ptrPos,
+ bool aliasedArrayItem = false )
+{
+ XMP_Node * nextNode = 0;
+ const XPathStepInfo & nextStep = fullPath[stepNum];
+ XMP_Index index = 0;
+ XMP_OptionBits stepKind = nextStep.options & kXMP_StepKindMask;
+
+ XMP_Assert ( (kXMP_StructFieldStep <= stepKind) && (stepKind <= kXMP_FieldSelectorStep) );
+
+ if ( stepKind == kXMP_StructFieldStep ) {
+
+ nextNode = FindChildNode ( parentNode, nextStep.step.c_str(), createNodes, ptrPos );
+
+ } else if ( stepKind == kXMP_QualifierStep ) {
+
+ XMP_StringPtr qualStep = nextStep.step.c_str();
+ XMP_Assert ( *qualStep == '?' );
+ ++qualStep;
+ nextNode = FindQualifierNode ( parentNode, qualStep, createNodes, ptrPos );
+
+ } else {
+
+ // This is an array indexing step. First get the index, then get the node.
+
+ if ( ! (parentNode->options & kXMP_PropValueIsArray) ) {
+ XMP_Throw ( "Indexing applied to non-array", kXMPErr_BadXPath );
+ }
+
+ if ( stepKind == kXMP_ArrayIndexStep ) {
+ index = FindIndexedItem ( parentNode, nextStep.step, createNodes );
+ } else if ( stepKind == kXMP_ArrayLastStep ) {
+ index = parentNode->children.size() - 1;
+ } else if ( stepKind == kXMP_FieldSelectorStep ) {
+ XMP_VarString fieldName, fieldValue;
+ SplitNameAndValue ( nextStep.step, &fieldName, &fieldValue );
+ index = LookupFieldSelector ( parentNode, fieldName.c_str(), fieldValue.c_str() );
+ } else if ( stepKind == kXMP_QualSelectorStep ) {
+ XMP_VarString qualName, qualValue;
+ SplitNameAndValue ( nextStep.step, &qualName, &qualValue );
+ index = LookupQualSelector ( parentNode, qualName, qualValue );
+ } else {
+ XMP_Throw ( "Unknown array indexing step in FollowXPathStep", kXMPErr_InternalFailure );
+ }
+
+ if ( (0 <= index) && (index <= (XMP_Index)parentNode->children.size()) ) nextNode = parentNode->children[index];
+
+ if ( (index == -1) && createNodes && aliasedArrayItem && (stepKind == kXMP_QualSelectorStep) ) {
+
+ // An ugly special case without an obvious better place to be. We have an alias to the
+ // x-default item of an alt-text array. A simple reference via SetProperty must create
+ // the x-default item if it does not yet exist.
+
+ XMP_Assert ( parentNode->options & kXMP_PropArrayIsAltText );
+ XMP_Assert ( (stepNum == 2) && (nextStep.step == "[?xml:lang=\"x-default\"]") );
+
+ nextNode = new XMP_Node ( parentNode, kXMP_ArrayItemName,
+ (kXMP_PropHasQualifiers | kXMP_PropHasLang | kXMP_NewImplicitNode) );
+
+ XMP_Node * langQual = new XMP_Node ( nextNode, "xml:lang", "x-default", kXMP_PropIsQualifier );
+ nextNode->qualifiers.push_back ( langQual );
+
+ if ( parentNode->children.empty() ) {
+ parentNode->children.push_back ( nextNode );
+ } else {
+ parentNode->children.insert ( parentNode->children.begin(), nextNode );
+ }
+
+ index = 0; // ! C-style index! The x-default item is always first.
+
+ }
+
+ if ( (nextNode != 0) && (ptrPos != 0) ) *ptrPos = parentNode->children.begin() + index;
+
+ }
+
+ if ( (nextNode != 0) && (nextNode->options & kXMP_NewImplicitNode) ) {
+ nextNode->options |= (nextStep.options & kXMP_PropArrayFormMask);
+ }
+
+ XMP_Assert ( (ptrPos == 0) || (nextNode == 0) || (nextNode == **ptrPos) );
+ XMP_Assert ( (nextNode != 0) || (! createNodes) );
+ return nextNode;
+
+} // FollowXPathStep
+
+// -------------------------------------------------------------------------------------------------
+// CheckImplicitStruct
+// -------------------
+
+static inline void
+CheckImplicitStruct ( XMP_Node * node,
+ const XMP_ExpandedXPath & expandedXPath,
+ size_t stepNum,
+ size_t stepLim )
+{
+
+ if ( (stepNum < stepLim) &&
+ ((node->options & kXMP_PropCompositeMask) == 0) &&
+ (GetStepKind ( expandedXPath[stepNum].options ) == kXMP_StructFieldStep) ) {
+
+ node->options |= kXMP_PropValueIsStruct;
+
+ }
+
+} // CheckImplicitStruct
+
+// -------------------------------------------------------------------------------------------------
+// DeleteSubtree
+// -------------
+
+// *** Might be useful elsewhere?
+
+static void
+DeleteSubtree ( XMP_NodePtrPos rootNodePos )
+{
+ XMP_Node * rootNode = *rootNodePos;
+ XMP_Node * rootParent = rootNode->parent;
+
+ if ( ! (rootNode->options & kXMP_PropIsQualifier) ) {
+
+ rootParent->children.erase ( rootNodePos );
+
+ } else {
+
+ rootParent->qualifiers.erase ( rootNodePos );
+
+ XMP_Assert ( rootParent->options & kXMP_PropHasQualifiers);
+ if ( rootParent->qualifiers.empty() ) rootParent->options ^= kXMP_PropHasQualifiers;
+
+ if ( rootNode->name == "xml:lang" ) {
+ XMP_Assert ( rootParent->options & kXMP_PropHasLang);
+ rootParent->options ^= kXMP_PropHasLang;
+ } else if ( rootNode->name == "rdf:type" ) {
+ XMP_Assert ( rootParent->options & kXMP_PropHasType);
+ rootParent->options ^= kXMP_PropHasType;
+ }
+
+ }
+
+ delete rootNode;
+
+} // DeleteSubtree
+
+// =================================================================================================
+// =================================================================================================
+
+// =================================================================================================
+// VerifySetOptions
+// ================
+//
+// Normalize and verify the option flags for SetProperty and similar functions. The allowed options
+// here are just those that apply to the property, that would be kept in the XMP_Node. Others that
+// affect the selection of the node or other processing must be removed by now. These are:
+// kXMP_InsertBeforeItem
+// kXMP_InsertAfterItem
+// kXMP_KeepQualifiers
+// kXMPUtil_AllowCommas
+
+enum {
+ kXMP_AllSetOptionsMask = (kXMP_PropValueIsURI |
+ kXMP_PropValueIsStruct |
+ kXMP_PropValueIsArray |
+ kXMP_PropArrayIsOrdered |
+ kXMP_PropArrayIsAlternate |
+ kXMP_PropArrayIsAltText |
+ kXMP_DeleteExisting)
+};
+
+XMP_OptionBits
+VerifySetOptions ( XMP_OptionBits options, XMP_StringPtr propValue )
+{
+
+ if ( options & kXMP_PropArrayIsAltText ) options |= kXMP_PropArrayIsAlternate;
+ if ( options & kXMP_PropArrayIsAlternate ) options |= kXMP_PropArrayIsOrdered;
+ if ( options & kXMP_PropArrayIsOrdered ) options |= kXMP_PropValueIsArray;
+
+ if ( options & ~kXMP_AllSetOptionsMask ) {
+ XMP_Throw ( "Unrecognized option flags", kXMPErr_BadOptions );
+ }
+
+ if ( (options & kXMP_PropValueIsStruct) && (options & kXMP_PropValueIsArray) ) {
+ XMP_Throw ( "IsStruct and IsArray options are mutually exclusive", kXMPErr_BadOptions );
+ }
+
+ if ( (options & kXMP_PropValueOptionsMask) && (options & kXMP_PropCompositeMask) ) {
+ XMP_Throw ( "Structs and arrays can't have \"value\" options", kXMPErr_BadOptions );
+ }
+
+ if ( (propValue != 0) && (options & kXMP_PropCompositeMask) ) {
+ XMP_Throw ( "Structs and arrays can't have string values", kXMPErr_BadOptions );
+ }
+
+ return options;
+
+} // VerifySetOptions
+
+// =================================================================================================
+// ComposeXPath
+// ============
+//
+// Compose the canonical string form of an expanded XPath expression.
+
+extern void
+ComposeXPath ( const XMP_ExpandedXPath & expandedXPath,
+ XMP_VarString * stringXPath )
+{
+ *stringXPath = expandedXPath[kRootPropStep].step;
+
+ for ( size_t index = kRootPropStep+1; index < expandedXPath.size(); ++index ) {
+ const XPathStepInfo & currStep = expandedXPath[index];
+
+ switch ( currStep.options & kXMP_StepKindMask ) {
+
+ case kXMP_StructFieldStep :
+ case kXMP_QualifierStep :
+ *stringXPath += '/';
+ *stringXPath += currStep.step;
+ break;
+
+ case kXMP_ArrayIndexStep :
+ case kXMP_ArrayLastStep :
+ case kXMP_QualSelectorStep :
+ case kXMP_FieldSelectorStep :
+ *stringXPath += currStep.step;
+ break;
+
+ default:
+ XMP_Throw ( "Unexpected", kXMPErr_InternalFailure );
+
+ }
+
+ }
+
+} // ComposeXPath
+
+// =================================================================================================
+// ExpandXPath
+// ===========
+//
+// Split an XPath expression apart at the conceptual steps, adding the root namespace prefix to the
+// first property component. The schema URI is put in the first (0th) slot in the expanded XPath.
+// Check if the top level component is an alias, but don't resolve it.
+//
+// In the most verbose case steps are separated by '/', and each step can be of these forms:
+//
+// qualName A top level property or struct field.
+// *[index] An element of an array.
+// *[last()] The last element of an array.
+// *[fieldName="value"] An element in an array of structs, chosen by a field value.
+// *[@xml:lang="value"] An element in an alt-text array, chosen by the xml:lang qualifier.
+// *[?qualName="value"] An element in an array, chosen by a qualifier value.
+// @xml:lang An xml:lang qualifier.
+// ?qualName A general qualifier.
+//
+// The logic is complicated though by shorthand for arrays, the separating '/' and leading '*'
+// are optional. These are all equivalent: array/*[2] array/[2] array*[2] array[2]
+// All of these are broken into the 2 steps "array" and "[2]".
+//
+// The value portion in the array selector forms is a string quoted by ''' or '"'. The value
+// may contain any character including a doubled quoting character. The value may be empty.
+//
+// The syntax isn't checked, but an XML name begins with a letter or '_', and contains letters,
+// digits, '.', '-', '_', and a bunch of special non-ASCII Unicode characters. An XML qualified
+// name is a pair of names separated by a colon.
+
+void
+ExpandXPath ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propPath,
+ XMP_ExpandedXPath * expandedXPath )
+{
+ XMP_Assert ( (schemaNS != 0) && (propPath != 0) && (*propPath != 0) && (expandedXPath != 0) );
+
+ XMP_StringPtr stepBegin, stepEnd;
+ XMP_StringPtr qualName, nameEnd;
+ XMP_VarString currStep;
+
+ size_t resCount = 2; // Guess at the number of steps. At least 2, plus 1 for each '/' or '['.
+ for ( stepEnd = propPath; *stepEnd != 0; ++stepEnd ) {
+ if ( (*stepEnd == '/') || (*stepEnd == '[') ) ++resCount;
+ }
+
+ expandedXPath->clear();
+ expandedXPath->reserve ( resCount );
+
+ // -------------------------------------------------------------------------------------------
+ // Pull out the first component and do some special processing on it: add the schema namespace
+ // prefix and see if it is an alias. The start must be a qualName.
+
+ stepBegin = propPath;
+ stepEnd = stepBegin;
+ while ( (*stepEnd != 0) && (*stepEnd != '/') && (*stepEnd != '[') && (*stepEnd != '*') ) ++stepEnd;
+ if ( stepEnd == stepBegin ) XMP_Throw ( "Empty initial XPath step", kXMPErr_BadXPath );
+ currStep.assign ( stepBegin, (stepEnd - stepBegin) );
+
+ VerifyXPathRoot ( schemaNS, currStep.c_str(), expandedXPath );
+
+ XMP_OptionBits stepFlags = kXMP_StructFieldStep;
+ if ( sRegisteredAliasMap->find ( (*expandedXPath)[kRootPropStep].step ) != sRegisteredAliasMap->end() ) {
+ stepFlags |= kXMP_StepIsAlias;
+ }
+ (*expandedXPath)[kRootPropStep].options |= stepFlags;
+
+ // -----------------------------------------------------
+ // Now continue to process the rest of the XPath string.
+
+ while ( *stepEnd != 0 ) {
+
+ stepBegin = stepEnd;
+ if ( *stepBegin == '/' ) ++stepBegin;
+ if ( *stepBegin == '*' ) {
+ ++stepBegin;
+ if ( *stepBegin != '[' ) XMP_Throw ( "Missing '[' after '*'", kXMPErr_BadXPath );
+ }
+ stepEnd = stepBegin;
+
+ if ( *stepBegin != '[' ) {
+
+ // A struct field or qualifier.
+ qualName = stepBegin;
+ while ( (*stepEnd != 0) && (*stepEnd != '/') && (*stepEnd != '[') && (*stepEnd != '*') ) ++stepEnd;
+ nameEnd = stepEnd;
+ stepFlags = kXMP_StructFieldStep; // ! Touch up later, also changing '@' to '?'.
+
+ } else {
+
+ // One of the array forms.
+
+ ++stepEnd; // Look at the character after the leading '['.
+
+ if ( ('0' <= *stepEnd) && (*stepEnd <= '9') ) {
+
+ // A numeric (decimal integer) array index.
+ while ( (*stepEnd != 0) && ('0' <= *stepEnd) && (*stepEnd <= '9') ) ++stepEnd;
+ if ( *stepEnd != ']' ) XMP_Throw ( "Missing ']' for integer array index", kXMPErr_BadXPath );
+ stepFlags = kXMP_ArrayIndexStep;
+
+ } else {
+
+ // Could be "[last()]" or one of the selector forms. Find the ']' or '='.
+
+ while ( (*stepEnd != 0) && (*stepEnd != ']') && (*stepEnd != '=') ) ++stepEnd;
+ if ( *stepEnd == 0 ) XMP_Throw ( "Missing ']' or '=' for array index", kXMPErr_BadXPath );
+
+ if ( *stepEnd == ']' ) {
+
+ if ( strncmp ( "[last()", stepBegin, (stepEnd - stepBegin) ) != 0 ) {
+ XMP_Throw ( "Invalid non-numeric array index", kXMPErr_BadXPath );
+ }
+ stepFlags = kXMP_ArrayLastStep;
+
+ } else {
+
+ qualName = stepBegin+1;
+ nameEnd = stepEnd;
+ ++stepEnd; // Absorb the '=', remember the quote.
+ const char quote = *stepEnd;
+ if ( (quote != '\'') && (quote != '"') ) {
+ XMP_Throw ( "Invalid quote in array selector", kXMPErr_BadXPath );
+ }
+
+ ++stepEnd; // Absorb the leading quote.
+ while ( *stepEnd != 0 ) {
+ if ( *stepEnd == quote ) {
+ if ( *(stepEnd+1) != quote ) break;
+ ++stepEnd;
+ }
+ ++stepEnd;
+ }
+ if ( *stepEnd == 0 ) {
+ XMP_Throw ( "No terminating quote for array selector", kXMPErr_BadXPath );
+ }
+ ++stepEnd; // Absorb the trailing quote.
+
+ stepFlags = kXMP_FieldSelectorStep; // ! Touch up later, also changing '@' to '?'.
+
+ }
+
+ }
+
+ if ( *stepEnd != ']' ) XMP_Throw ( "Missing ']' for array index", kXMPErr_BadXPath );
+ ++stepEnd;
+
+ }
+
+ if ( stepEnd == stepBegin ) XMP_Throw ( "Empty XPath step", kXMPErr_BadXPath );
+ currStep.assign ( stepBegin, (stepEnd - stepBegin) );
+
+ if ( GetStepKind ( stepFlags ) == kXMP_StructFieldStep ) {
+
+ if ( currStep[0] == '@' ) {
+ currStep[0] = '?';
+ if ( currStep != "?xml:lang" ) XMP_Throw ( "Only xml:lang allowed with '@'", kXMPErr_BadXPath );
+ }
+ if ( currStep[0] == '?' ) {
+ ++qualName;
+ stepFlags = kXMP_QualifierStep;
+ }
+ VerifyQualName ( qualName, nameEnd );
+
+ } else if ( GetStepKind ( stepFlags ) == kXMP_FieldSelectorStep ) {
+
+ if ( currStep[1] == '@' ) {
+ currStep[1] = '?';
+ if ( strncmp ( currStep.c_str(), "[?xml:lang=", 11 ) != 0 ) {
+ XMP_Throw ( "Only xml:lang allowed with '@'", kXMPErr_BadXPath );
+ }
+ }
+ if ( currStep[1] == '?' ) {
+ ++qualName;
+ stepFlags = kXMP_QualSelectorStep;
+ }
+ VerifyQualName ( qualName, nameEnd );
+
+ }
+
+ expandedXPath->push_back ( XPathStepInfo ( currStep, stepFlags ) );
+
+ }
+
+} // ExpandXPath
+
+// =================================================================================================
+// FindSchemaNode
+// ==============
+//
+// Find or create a schema node. Returns a pointer to the node, and optionally an iterator for the
+// node's position in the top level vector of schema nodes. The iterator is unchanged if no schema
+// node (null) is returned.
+
+XMP_Node *
+FindSchemaNode ( XMP_Node * xmpTree,
+ XMP_StringPtr nsURI,
+ bool createNodes,
+ XMP_NodePtrPos * ptrPos /* = 0 */ )
+{
+ XMP_Node * schemaNode = 0;
+
+ XMP_Assert ( xmpTree->parent == 0 );
+
+ for ( size_t schemaNum = 0, schemaLim = xmpTree->children.size(); schemaNum != schemaLim; ++schemaNum ) {
+ XMP_Node * currSchema = xmpTree->children[schemaNum];
+ XMP_Assert ( currSchema->parent == xmpTree );
+ if ( currSchema->name == nsURI ) {
+ schemaNode = currSchema;
+ if ( ptrPos != 0 ) *ptrPos = xmpTree->children.begin() + schemaNum;
+ break;
+ }
+ }
+
+ if ( (schemaNode == 0) && createNodes ) {
+
+ schemaNode = new XMP_Node ( xmpTree, nsURI, (kXMP_SchemaNode | kXMP_NewImplicitNode) );
+ XMP_StringPtr prefixPtr;
+ XMP_StringLen prefixLen;
+ bool found = XMPMeta::GetNamespacePrefix ( nsURI, &prefixPtr, &prefixLen ); // *** Use map directly?
+ XMP_Assert ( found );
+
+ schemaNode->value.assign ( prefixPtr, prefixLen );
+ xmpTree->children.push_back ( schemaNode );
+ if ( ptrPos != 0 ) *ptrPos = xmpTree->children.end() - 1;
+
+ #if 0 // *** XMP_DebugBuild
+ schemaNode->_valuePtr = schemaNode->value.c_str();
+ #endif
+
+ }
+
+ XMP_Assert ( (ptrPos == 0) || (schemaNode == 0) || (schemaNode == **ptrPos) );
+ XMP_Assert ( (schemaNode != 0) || (! createNodes) );
+ return schemaNode;
+
+} // FindSchemaNode
+
+// =================================================================================================
+// FindChildNode
+// =============
+//
+// Find or create a child node under a given parent node. Returns a pointer to the child node, and
+// optionally an iterator for the node's position in the parent's vector of children. The iterator
+// is unchanged if no child node (null) is returned.
+
+XMP_Node *
+FindChildNode ( XMP_Node * parent,
+ XMP_StringPtr childName,
+ bool createNodes,
+ XMP_NodePtrPos * ptrPos /* = 0 */ )
+{
+ XMP_Node * childNode = 0;
+
+ if ( ! (parent->options & (kXMP_SchemaNode | kXMP_PropValueIsStruct)) ) {
+ if ( ! (parent->options & kXMP_NewImplicitNode) ) {
+ XMP_Throw ( "Named children only allowed for schemas and structs", kXMPErr_BadXPath );
+ }
+ if ( parent->options & kXMP_PropValueIsArray ) {
+ XMP_Throw ( "Named children not allowed for arrays", kXMPErr_BadXPath );
+ }
+ if ( ! createNodes ) { // *** Should be assert? If !createNodes, why is the parent a new implicit node?
+ XMP_Throw ( "Parent is new implicit node, but createNodes is false", kXMPErr_InternalFailure );
+ }
+ parent->options |= kXMP_PropValueIsStruct;
+ }
+
+ for ( size_t childNum = 0, childLim = parent->children.size(); childNum != childLim; ++childNum ) {
+ XMP_Node * currChild = parent->children[childNum];
+ XMP_Assert ( currChild->parent == parent );
+ if ( currChild->name == childName ) {
+ childNode = currChild;
+ if ( ptrPos != 0 ) *ptrPos = parent->children.begin() + childNum;
+ break;
+ }
+ }
+
+ if ( (childNode == 0) && createNodes ) {
+ childNode = new XMP_Node ( parent, childName, kXMP_NewImplicitNode );
+ parent->children.push_back ( childNode );
+ if ( ptrPos != 0 ) *ptrPos = parent->children.end() - 1;
+ }
+
+ XMP_Assert ( (ptrPos == 0) || (childNode == 0) || (childNode == **ptrPos) );
+ XMP_Assert ( (childNode != 0) || (! createNodes) );
+ return childNode;
+
+} // FindChildNode
+
+// =================================================================================================
+// FindQualifierNode
+// =================
+//
+// Find or create a qualifier node under a given parent node. Returns a pointer to the qualifier node,
+// and optionally an iterator for the node's position in the parent's vector of qualifiers. The iterator
+// is unchanged if no qualifier node (null) is returned.
+//
+// ! On entry, the qualName parameter must not have the leading '?' from the XPath step.
+
+XMP_Node *
+FindQualifierNode ( XMP_Node * parent,
+ XMP_StringPtr qualName,
+ bool createNodes,
+ XMP_NodePtrPos * ptrPos /* = 0 */ ) // *** Require ptrPos internally & remove checks?
+{
+ XMP_Node * qualNode = 0;
+
+ XMP_Assert ( *qualName != '?' );
+
+ for ( size_t qualNum = 0, qualLim = parent->qualifiers.size(); qualNum != qualLim; ++qualNum ) {
+ XMP_Node * currQual = parent->qualifiers[qualNum];
+ XMP_Assert ( currQual->parent == parent );
+ if ( currQual->name == qualName ) {
+ qualNode = currQual;
+ if ( ptrPos != 0 ) *ptrPos = parent->qualifiers.begin() + qualNum;
+ break;
+ }
+ }
+
+ if ( (qualNode == 0) && createNodes ) {
+
+ qualNode = new XMP_Node ( parent, qualName, (kXMP_PropIsQualifier | kXMP_NewImplicitNode) );
+ parent->options |= kXMP_PropHasQualifiers;
+
+ const bool isLang = XMP_LitMatch ( qualName, "xml:lang" );
+ const bool isType = XMP_LitMatch ( qualName, "rdf:type" );
+ const bool isSpecial = isLang | isType;
+
+ if ( isLang ) {
+ parent->options |= kXMP_PropHasLang;
+ } else if ( isType ) {
+ parent->options |= kXMP_PropHasType;
+ }
+
+ if ( parent->qualifiers.empty() || (! isSpecial) ) {
+ parent->qualifiers.push_back ( qualNode );
+ if ( ptrPos != 0 ) *ptrPos = parent->qualifiers.end() - 1;
+ } else {
+ XMP_NodePtrPos insertPos = parent->qualifiers.begin(); // ! Lang goes first, type after.
+ if ( isType && (parent->options & kXMP_PropHasLang) ) ++insertPos; // *** Does insert at end() work?
+ insertPos = parent->qualifiers.insert ( insertPos, qualNode );
+ if ( ptrPos != 0 ) *ptrPos = insertPos;
+ }
+
+ }
+
+ XMP_Assert ( (ptrPos == 0) || (qualNode == 0) || (qualNode == **ptrPos) );
+ XMP_Assert ( (qualNode != 0) || (! createNodes) );
+ return qualNode;
+
+} // FindQualifierNode
+
+// =================================================================================================
+// LookupFieldSelector
+// ===================
+//
+// [fieldName="value"] An element in an array of structs, chosen by a field value.
+//
+// Note that we don't create implicit nodes for field selectors, so no CreateNodes parameter.
+
+XMP_Index
+LookupFieldSelector ( const XMP_Node * arrayNode, XMP_StringPtr fieldName, XMP_StringPtr fieldValue )
+{
+ XMP_Index index, itemLim;
+
+ for ( index = 0, itemLim = arrayNode->children.size(); index != itemLim; ++index ) {
+
+ const XMP_Node * currItem = arrayNode->children[index];
+ XMP_Assert ( currItem->parent == arrayNode );
+
+ if ( ! (currItem->options & kXMP_PropValueIsStruct) ) {
+ XMP_Throw ( "Field selector must be used on array of struct", kXMPErr_BadXPath );
+ }
+
+ size_t f, fieldLim;
+ for ( f = 0, fieldLim = currItem->children.size(); f != fieldLim; ++f ) {
+ const XMP_Node * currField = currItem->children[f];
+ XMP_Assert ( currField->parent == currItem );
+ if ( currField->name != fieldName ) continue;
+ if ( currField->value == fieldValue ) break; // Exit qual loop.
+ }
+ if ( f != fieldLim ) break; // Exit child loop, found an item with a matching qualifier.
+
+ }
+
+ if ( index == itemLim ) index = -1;
+ return index;
+
+} // LookupFieldSelector
+
+// =================================================================================================
+// LookupLangItem
+// ==============
+//
+// ! Assumes that the language value is already normalized.
+
+XMP_Index
+LookupLangItem ( const XMP_Node * arrayNode, XMP_VarString & lang )
+{
+ if ( ! (arrayNode->options & kXMP_PropValueIsArray) ) { // *** Check for alt-text?
+ XMP_Throw ( "Language item must be used on array", kXMPErr_BadXPath );
+ }
+
+ XMP_Index index = 0;
+ XMP_Index itemLim = arrayNode->children.size();
+
+ for ( ; index != itemLim; ++index ) {
+ const XMP_Node * currItem = arrayNode->children[index];
+ XMP_Assert ( currItem->parent == arrayNode );
+ if ( currItem->qualifiers.empty() || (currItem->qualifiers[0]->name != "xml:lang") ) continue;
+ if ( currItem->qualifiers[0]->value == lang ) break;
+ }
+
+ if ( index == itemLim ) index = -1;
+ return index;
+
+} // LookupLangItem
+
+// =================================================================================================
+// FindNode
+// ========
+//
+// Follow an expanded path expression to find or create a node. Returns a pointer to the node, and
+// optionally an iterator for the node's position in the parent's vector of children or qualifiers.
+// The iterator is unchanged if no child node (null) is returned.
+
+XMP_Node *
+FindNode ( XMP_Node * xmpTree,
+ const XMP_ExpandedXPath & expandedXPath,
+ bool createNodes,
+ XMP_OptionBits leafOptions /* = 0 */,
+ XMP_NodePtrPos * ptrPos /* = 0 */ )
+{
+ XMP_Node * currNode = 0;
+ XMP_NodePtrPos currPos;
+ XMP_NodePtrPos newSubPos; // Root of implicitly created subtree. Valid only if leaf is new.
+ bool leafIsNew = false;
+
+ XMP_Assert ( (leafOptions == 0) || createNodes );
+
+ if ( expandedXPath.empty() ) XMP_Throw ( "Empty XPath", kXMPErr_BadXPath );
+
+ size_t stepNum = 1; // By default start calling FollowXPathStep for the top level property step.
+ size_t stepLim = expandedXPath.size();
+
+ // The start of processing deals with the schema node and top level alias. If the top level step
+ // is not an alias, lookup the expanded path's schema URI. Otherwise, lookup the expanded path
+ // for the actual. While tempting, don't substitute the actual's path into the local one, don't
+ // risk messing with the caller's use of that. Also don't call FindNode recursively, we need to
+ // keep track of the root of the implicitly created subtree as we move down the path.
+
+ if ( ! (expandedXPath[kRootPropStep].options & kXMP_StepIsAlias) ) {
+
+ currNode = FindSchemaNode ( xmpTree, expandedXPath[kSchemaStep].step.c_str(), createNodes, &currPos );
+ if ( currNode == 0 ) return 0;
+
+ if ( currNode->options & kXMP_NewImplicitNode ) {
+ currNode->options ^= kXMP_NewImplicitNode; // Clear the implicit node bit.
+ if ( ! leafIsNew ) newSubPos = currPos; // Save the top most implicit node.
+ leafIsNew = true; // If any parent is new, the leaf will be new also.
+ }
+
+ } else {
+
+ stepNum = 2; // ! Continue processing the original path at the second level step.
+
+ XMP_AliasMapPos aliasPos = sRegisteredAliasMap->find ( expandedXPath[kRootPropStep].step );
+ XMP_Assert ( aliasPos != sRegisteredAliasMap->end() );
+
+ currNode = FindSchemaNode ( xmpTree, aliasPos->second[kSchemaStep].step.c_str(), createNodes, &currPos );
+ if ( currNode == 0 ) goto EXIT;
+ if ( currNode->options & kXMP_NewImplicitNode ) {
+ currNode->options ^= kXMP_NewImplicitNode; // Clear the implicit node bit.
+ if ( ! leafIsNew ) newSubPos = currPos; // Save the top most implicit node.
+ leafIsNew = true; // If any parent is new, the leaf will be new also.
+ }
+
+ currNode = FollowXPathStep ( currNode, aliasPos->second, 1, createNodes, &currPos );
+ if ( currNode == 0 ) goto EXIT;
+ if ( currNode->options & kXMP_NewImplicitNode ) {
+ currNode->options ^= kXMP_NewImplicitNode; // Clear the implicit node bit.
+ CheckImplicitStruct ( currNode, expandedXPath, 2, stepLim );
+ if ( ! leafIsNew ) newSubPos = currPos; // Save the top most implicit node.
+ leafIsNew = true; // If any parent is new, the leaf will be new also.
+ }
+
+ XMP_OptionBits arrayForm = aliasPos->second[kRootPropStep].options & kXMP_PropArrayFormMask;
+ XMP_Assert ( (arrayForm == 0) || (arrayForm & kXMP_PropValueIsArray) );
+ XMP_Assert ( (arrayForm == 0) ? (aliasPos->second.size() == 2) : (aliasPos->second.size() == 3) );
+
+ if ( arrayForm != 0 ) {
+ currNode = FollowXPathStep ( currNode, aliasPos->second, 2, createNodes, &currPos, true );
+ if ( currNode == 0 ) goto EXIT;
+ if ( currNode->options & kXMP_NewImplicitNode ) {
+ currNode->options ^= kXMP_NewImplicitNode; // Clear the implicit node bit.
+ CheckImplicitStruct ( currNode, expandedXPath, 2, stepLim );
+ if ( ! leafIsNew ) newSubPos = currPos; // Save the top most implicit node.
+ leafIsNew = true; // If any parent is new, the leaf will be new also.
+ }
+ }
+
+ }
+
+ // Now follow the remaining steps of the original XPath.
+
+ // *** ??? Change all the num/lim loops back to num<lim? Probably safer.
+
+ try {
+ for ( ; stepNum < stepLim; ++stepNum ) {
+ currNode = FollowXPathStep ( currNode, expandedXPath, stepNum, createNodes, &currPos );
+ if ( currNode == 0 ) goto EXIT;
+ if ( currNode->options & kXMP_NewImplicitNode ) {
+ currNode->options ^= kXMP_NewImplicitNode; // Clear the implicit node bit.
+ CheckImplicitStruct ( currNode, expandedXPath, stepNum+1, stepLim );
+ if ( ! leafIsNew ) newSubPos = currPos; // Save the top most implicit node.
+ leafIsNew = true; // If any parent is new, the leaf will be new also.
+ }
+ }
+ } catch ( ... ) {
+ if ( leafIsNew ) DeleteSubtree ( newSubPos );
+ throw;
+ }
+
+ // Done. Delete the implicitly created subtree if the eventual node was not found.
+
+EXIT:
+
+ XMP_Assert ( (currNode == 0) || (currNode == *currPos) );
+ XMP_Assert ( (currNode != 0) || (! createNodes) );
+
+ if ( leafIsNew ) {
+ if ( currNode != 0 ) {
+ currNode->options |= leafOptions;
+ } else {
+ DeleteSubtree ( newSubPos );
+ }
+ }
+
+ if ( (currNode != 0) && (ptrPos != 0) ) *ptrPos = currPos;
+ return currNode;
+
+} // FindNode
+
+// =================================================================================================
+// CloneOffspring
+// ==============
+
+void
+CloneOffspring ( const XMP_Node * origParent, XMP_Node * cloneParent )
+{
+ size_t qualCount = origParent->qualifiers.size();
+ size_t childCount = origParent->children.size();
+
+ if ( qualCount > 0 ) {
+
+ cloneParent->qualifiers.reserve ( qualCount );
+
+ for ( size_t qualNum = 0, qualLim = qualCount; qualNum != qualLim; ++qualNum ) {
+ const XMP_Node * origQual = origParent->qualifiers[qualNum];
+ XMP_Node * cloneQual = new XMP_Node ( cloneParent, origQual->name, origQual->value, origQual->options );
+ CloneOffspring ( origQual, cloneQual );
+ cloneParent->qualifiers.push_back ( cloneQual );
+ }
+
+ }
+
+ if ( childCount > 0 ) {
+
+ cloneParent->children.reserve ( childCount );
+
+ for ( size_t childNum = 0, childLim = childCount; childNum != childLim; ++childNum ) {
+ const XMP_Node * origChild = origParent->children[childNum];
+ XMP_Node * cloneChild = new XMP_Node ( cloneParent, origChild->name, origChild->value, origChild->options );
+ CloneOffspring ( origChild, cloneChild );
+ cloneParent->children.push_back ( cloneChild );
+ }
+
+ }
+
+} // CloneOffspring
+
+// =================================================================================================
+// CloneSubtree
+// ============
+
+XMP_Node *
+CloneSubtree ( const XMP_Node * origRoot, XMP_Node * cloneParent )
+{
+ #if XMP_DebugBuild
+ if ( cloneParent->parent == 0 ) {
+ XMP_Assert ( origRoot->options & kXMP_SchemaNode );
+ XMP_Assert ( FindConstSchema ( cloneParent, origRoot->name.c_str() ) == 0 );
+ } else {
+ XMP_Assert ( ! (origRoot->options & kXMP_SchemaNode) );
+ if ( cloneParent->options & kXMP_PropValueIsStruct ) { // Might be an array.
+ XMP_Assert ( FindConstChild ( cloneParent, origRoot->name.c_str() ) == 0 );
+ }
+ }
+ #endif
+
+ XMP_Node * cloneRoot = new XMP_Node ( cloneParent, origRoot->name, origRoot->value, origRoot->options );
+ CloneOffspring ( origRoot, cloneRoot ) ;
+ cloneParent->children.push_back ( cloneRoot );
+
+ return cloneRoot;
+
+} // CloneSubtree
+
+// =================================================================================================
+// CompareSubtrees
+// ===============
+//
+// Compare 2 subtrees for semantic equality. The comparison includes value, qualifiers, and form.
+// Schemas, top level properties, struct fields, and qualifiers are allowed to have differing order,
+// the appropriate right node is found from the left node's name. Alt-text arrays are allowed to be
+// in differing language order, other arrays are compared in order.
+
+// *** Might someday consider sorting unordered arrays.
+// *** Should expose this through XMPUtils.
+
+bool
+CompareSubtrees ( const XMP_Node & leftNode, const XMP_Node & rightNode )
+{
+ // Don't compare the names here, we want to allow the outermost roots to have different names.
+ if ( (leftNode.value != rightNode.value) ||
+ (leftNode.options != rightNode.options) ||
+ (leftNode.children.size() != rightNode.children.size()) ||
+ (leftNode.qualifiers.size() != rightNode.qualifiers.size()) ) return false;
+
+ // Compare the qualifiers, allowing them to be out of order.
+ for ( size_t qualNum = 0, qualLim = leftNode.qualifiers.size(); qualNum != qualLim; ++qualNum ) {
+ const XMP_Node * leftQual = leftNode.qualifiers[qualNum];
+ const XMP_Node * rightQual = FindConstQualifier ( &rightNode, leftQual->name.c_str() );
+ if ( (rightQual == 0) || (! CompareSubtrees ( *leftQual, *rightQual )) ) return false;
+ }
+
+ if ( (leftNode.parent == 0) || (leftNode.options & (kXMP_SchemaNode | kXMP_PropValueIsStruct)) ) {
+
+ // The parent node is a tree root, a schema, or a struct.
+ for ( size_t childNum = 0, childLim = leftNode.children.size(); childNum != childLim; ++childNum ) {
+ const XMP_Node * leftChild = leftNode.children[childNum];
+ const XMP_Node * rightChild = FindConstChild ( &rightNode, leftChild->name.c_str() );
+ if ( (rightChild == 0) || (! CompareSubtrees ( *leftChild, *rightChild )) ) return false;
+ }
+
+ } else if ( leftNode.options & kXMP_PropArrayIsAltText ) {
+
+ // The parent node is an alt-text array.
+ for ( size_t childNum = 0, childLim = leftNode.children.size(); childNum != childLim; ++childNum ) {
+ const XMP_Node * leftChild = leftNode.children[childNum];
+ XMP_Assert ( (! leftChild->qualifiers.empty()) && (leftChild->qualifiers[0]->name == "xml:lang") );
+ XMP_Index rightIndex = LookupLangItem ( &rightNode, leftChild->qualifiers[0]->value );
+ if ( rightIndex == -1 ) return false;
+ const XMP_Node * rightChild = rightNode.children[rightIndex];
+ if ( ! CompareSubtrees ( *leftChild, *rightChild ) ) return false;
+ }
+
+ } else {
+
+ // The parent must be simple or some other (not alt-text) kind of array.
+ XMP_Assert ( (! (leftNode.options & kXMP_PropCompositeMask)) || (leftNode.options & kXMP_PropValueIsArray) );
+ for ( size_t childNum = 0, childLim = leftNode.children.size(); childNum != childLim; ++childNum ) {
+ const XMP_Node * leftChild = leftNode.children[childNum];
+ const XMP_Node * rightChild = rightNode.children[childNum];
+ if ( ! CompareSubtrees ( *leftChild, *rightChild ) ) return false;
+ }
+
+ }
+
+ return true;
+
+} // CompareSubtrees
+
+// =================================================================================================
+// DeleteEmptySchema
+// =================
+
+void
+DeleteEmptySchema ( XMP_Node * schemaNode )
+{
+
+ if ( XMP_NodeIsSchema ( schemaNode->options ) && schemaNode->children.empty() ) {
+
+ XMP_Node * xmpTree = schemaNode->parent;
+
+ size_t schemaNum = 0;
+ size_t schemaLim = xmpTree->children.size();
+ while ( (schemaNum < schemaLim) && (xmpTree->children[schemaNum] != schemaNode) ) ++schemaNum;
+ XMP_Assert ( schemaNum < schemaLim );
+
+ XMP_NodePtrPos schemaPos = xmpTree->children.begin() + schemaNum;
+ XMP_Assert ( *schemaPos == schemaNode );
+
+ xmpTree->children.erase ( schemaPos );
+ delete schemaNode;
+
+ }
+
+} // DeleteEmptySchema
+
+// =================================================================================================
+// NormalizeLangValue
+// ==================
+//
+// Normalize an xml:lang value so that comparisons are effectively case insensitive as required by
+// RFC 3066 (which superceeds RFC 1766). The normalization rules:
+//
+// - The primary subtag is lower case, the suggested practice of ISO 639.
+// - All 2 letter secondary subtags are upper case, the suggested practice of ISO 3166.
+// - All other subtags are lower case.
+
+void
+NormalizeLangValue ( XMP_VarString * value )
+{
+ char * tagStart;
+ char * tagEnd;
+
+ // Find and process the primary subtag.
+
+ tagStart = (char*) value->c_str();
+ for ( tagEnd = tagStart; (*tagEnd != 0) && (*tagEnd != '-'); ++tagEnd ) {
+ if ( ('A' <= *tagEnd) && (*tagEnd <= 'Z') ) *tagEnd += 0x20;
+ }
+
+ // Find and process the secondary subtag.
+
+ tagStart = tagEnd;
+ if ( *tagStart == '-' ) ++tagStart;
+ for ( tagEnd = tagStart; (*tagEnd != 0) && (*tagEnd != '-'); ++tagEnd ) {
+ if ( ('A' <= *tagEnd) && (*tagEnd <= 'Z') ) *tagEnd += 0x20;
+ }
+ if ( tagEnd == tagStart+2 ) {
+ if ( ('a' <= *tagStart) && (*tagStart <= 'z') ) *tagStart -= 0x20;
+ ++tagStart;
+ if ( ('a' <= *tagStart) && (*tagStart <= 'z') ) *tagStart -= 0x20;
+ }
+
+ // Find and process the remaining subtags.
+
+ while ( true ) {
+ tagStart = tagEnd;
+ if ( *tagStart == '-' ) ++tagStart;
+ if ( *tagStart == 0 ) break;
+ for ( tagEnd = tagStart; (*tagEnd != 0) && (*tagEnd != '-'); ++tagEnd ) {
+ if ( ('A' <= *tagEnd) && (*tagEnd <= 'Z') ) *tagEnd += 0x20;
+ }
+ }
+
+} // NormalizeLangValue
+
+// =================================================================================================
+// NormalizeLangArray
+// ==================
+//
+// Make sure the x-default item is first. Touch up "single value" 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 'x-default' item, so we copy that value to the other item.
+
+void
+NormalizeLangArray ( XMP_Node * array )
+{
+ XMP_Assert ( XMP_ArrayIsAltText(array->options) );
+
+ size_t itemNum;
+ size_t itemLim = array->children.size();
+ bool hasDefault = false;
+
+ for ( itemNum = 0; itemNum < itemLim; ++itemNum ) {
+
+ if ( array->children[itemNum]->qualifiers.empty() ||
+ (array->children[itemNum]->qualifiers[0]->name != "xml:lang") ) {
+ XMP_Throw ( "AltText array items must have an xml:lang qualifier", kXMPErr_BadXMP );
+ }
+
+ if ( array->children[itemNum]->qualifiers[0]->value == "x-default" ) {
+ hasDefault = true;
+ break;
+ }
+
+ }
+
+ if ( hasDefault ) {
+
+ if ( itemNum != 0 ) {
+ XMP_Node * temp = array->children[0];
+ array->children[0] = array->children[itemNum];
+ array->children[itemNum] = temp;
+ }
+
+ if ( itemLim == 2 ) array->children[1]->value = array->children[0]->value;
+
+ }
+
+} // NormalizeLangArray
+
+// =================================================================================================
+// DetectAltText
+// =============
+//
+// See if an array is an alt-text array. If so, make sure the x-default item is first.
+
+void
+DetectAltText ( XMP_Node * xmpParent )
+{
+ XMP_Assert ( XMP_ArrayIsAlternate(xmpParent->options) );
+
+ size_t itemNum, itemLim;
+
+ for ( itemNum = 0, itemLim = xmpParent->children.size(); itemNum < itemLim; ++itemNum ) {
+ XMP_OptionBits currOptions = xmpParent->children[itemNum]->options;
+ if ( (currOptions & kXMP_PropCompositeMask) || (! (currOptions & kXMP_PropHasLang)) ) break;
+ }
+
+ if ( (itemLim != 0) && (itemNum == itemLim) ) {
+ xmpParent->options |= kXMP_PropArrayIsAltText;
+ NormalizeLangArray ( xmpParent );
+ }
+
+} // DetectAltText
+
+// =================================================================================================
+// IsWhitespaceNode
+// ================
+//
+// Return true if this is a character data node that contains only XML whitespace.
+
+// ! For now only recognize ASCII space, tab, CR, and LF.
+
+bool
+IsWhitespaceNode ( const XML_Node & xmlNode )
+{
+ if ( xmlNode.kind != kCDataNode ) return false;
+
+ for ( size_t i = 0; i < xmlNode.value.size(); ++i ) {
+ unsigned char ch = xmlNode.value[i];
+ if ( IsWhitespaceChar ( ch ) ) continue;
+ // *** Add checks for other whitespace characters.
+ return false; // All the checks failed, this isn't whitespace.
+ }
+
+ return true;
+
+} // IsWhitespaceNode
+
+// =================================================================================================
+// SortNamedNodes
+// ==============
+//
+// Sort the pointers in an XMP_NodeOffspring vector by name.
+
+static inline bool Compare ( const XMP_Node * left, const XMP_Node * right )
+{
+ return (left->name < right->name);
+}
+
+void
+SortNamedNodes ( XMP_NodeOffspring & nodeVector )
+{
+ sort ( nodeVector.begin(), nodeVector.end(), Compare );
+} // SortNamedNodes
+
+// =================================================================================================
diff --git a/source/XMPCore/XMPCore_Impl.hpp b/source/XMPCore/XMPCore_Impl.hpp
new file mode 100644
index 0000000..5afc577
--- /dev/null
+++ b/source/XMPCore/XMPCore_Impl.hpp
@@ -0,0 +1,631 @@
+#ifndef __XMPCore_Impl_hpp__
+#define __XMPCore_Impl_hpp__
+
+// =================================================================================================
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "XMP_Environment.h" // ! Must be the first #include!
+#include "XMP_Const.h"
+#include "XMP_BuildInfo.h"
+
+#ifndef UsePublicExpat
+ #define UsePublicExpat 1
+#endif
+
+#include "client-glue/WXMPMeta.hpp"
+
+#include <vector>
+#include <string>
+#include <map>
+
+#include <cassert>
+
+#if XMP_MacBuild
+ #include <Multiprocessing.h>
+#elif XMP_WinBuild
+ #include <Windows.h>
+#elif XMP_UNIXBuild
+ #include <pthread.h>
+#endif
+
+// =================================================================================================
+// Primary internal types
+
+class XMP_Node;
+class XML_Node;
+class XPathStepInfo;
+
+typedef std::vector<XMP_Node*> XMP_NodeOffspring;
+typedef XMP_NodeOffspring::iterator XMP_NodePtrPos;
+
+typedef std::string XMP_VarString;
+typedef XMP_VarString::iterator XMP_VarStringPos;
+typedef XMP_VarString::const_iterator XMP_cVarStringPos;
+
+typedef std::pair < XMP_VarString, XMP_VarString > XMP_StringPair;
+
+typedef std::map < XMP_VarString, XMP_VarString > XMP_StringMap;
+typedef XMP_StringMap::iterator XMP_StringMapPos;
+typedef XMP_StringMap::const_iterator XMP_cStringMapPos;
+
+typedef std::vector < XPathStepInfo > XMP_ExpandedXPath;
+typedef XMP_ExpandedXPath::iterator XMP_ExpandedXPathPos;
+typedef XMP_ExpandedXPath::const_iterator XMP_cExpandedXPathPos;
+
+typedef std::map < XMP_VarString, XMP_ExpandedXPath > XMP_AliasMap; // Alias name to actual path.
+typedef XMP_AliasMap::iterator XMP_AliasMapPos;
+typedef XMP_AliasMap::const_iterator XMP_cAliasMapPos;
+
+// =================================================================================================
+// General global variables and macros
+
+extern XMP_Int32 sXMP_InitCount;
+
+extern XMP_AliasMap * sRegisteredAliasMap;
+
+extern XMP_StringMap * sNamespaceURIToPrefixMap;
+extern XMP_StringMap * sNamespacePrefixToURIMap;
+
+extern XMP_VarString * sOutputNS;
+extern XMP_VarString * sOutputStr;
+
+extern void * voidVoidPtr; // Used to backfill null output parameters.
+extern XMP_StringPtr voidStringPtr;
+extern XMP_StringLen voidStringLen;
+extern XMP_OptionBits voidOptionBits;
+extern XMP_Bool voidByte;
+extern bool voidBool;
+extern XMP_Int32 voidInt32;
+extern XMP_Int64 voidInt64;
+extern double voidDouble;
+extern XMP_DateTime voidDateTime;
+extern WXMP_Result void_wResult;
+
+#define kHexDigits "0123456789ABCDEF"
+
+#define XMP_LitMatch(s,l) (std::strcmp((s),(l)) == 0)
+#define XMP_LitNMatch(s,l,n) (std::strncmp((s),(l),(n)) == 0)
+ // *** Use the above macros!
+
+#define kTab ((char)0x09)
+#define kLF ((char)0x0A)
+#define kCR ((char)0x0D)
+
+#if XMP_WinBuild
+ #define snprintf _snprintf
+#endif
+
+#define WtoXMPMeta_Ref(xmpRef) *((const XMPMeta *)(xmpRef))
+#define WtoXMPMeta_Ptr(xmpRef) (((xmpRef) == 0) ? 0 : (XMPMeta *)(xmpRef))
+
+#define WtoXMPIterator_Ref(iterRef) *((const XMPIterator *)(iterRef))
+#define WtoXMPIterator_Ptr(iterRef) (((iterRef) == 0) ? 0 : (XMPIterator *)(iterRef))
+
+#define IgnoreParam(p) voidVoidPtr = (void*)&p
+
+// =================================================================================================
+// Version info
+
+#if XMP_DebugBuild
+ #define kXMPCore_DebugFlag 1
+#else
+ #define kXMPCore_DebugFlag 0
+#endif
+
+#define kXMPCore_VersionNumber ( (kXMPCore_DebugFlag << 31) | \
+ (XMP_API_VERSION_MAJOR << 24) | \
+ (XMP_API_VERSION_MINOR << 16) | \
+ (XMP_API_VERSION_MICRO << 8) )
+
+ #define kXMPCoreName "XMP Core"
+ #define kXMPCore_VersionMessage kXMPCoreName " " XMP_API_VERSION_STRING
+// =================================================================================================
+// Support for asserts
+
+#define _MakeStr(p) #p
+#define _NotifyMsg(n,c,f,l) #n " failed: " #c " in " f " at line " _MakeStr(l)
+
+#if ! XMP_DebugBuild
+ #define XMP_Assert(c) ((void) 0)
+#else
+ #define XMP_Assert(c) assert ( c )
+#endif
+
+ #define XMP_Enforce(c) \
+ if ( ! (c) ) { \
+ const char * assert_msg = _NotifyMsg ( XMP_Enforce, (c), __FILE__, __LINE__ ); \
+ XMP_Throw ( assert_msg , kXMPErr_EnforceFailure ); \
+ }
+// =================================================================================================
+// Support for exceptions and thread locking
+
+#ifndef TraceXMPCalls
+ #define TraceXMPCalls 0
+#endif
+
+#if ! TraceXMPCalls
+
+ #define AnnounceThrow(msg) /* Do nothing. */
+ #define AnnounceCatch(msg) /* Do nothing. */
+
+ #define AnnounceEntry(proc) /* Do nothing. */
+ #define AnnounceNoLock(proc) /* Do nothing. */
+ #define AnnounceExit() /* Do nothing. */
+
+ #define ReportLock() ++sLockCount
+ #define ReportUnlock() --sLockCount
+ #define ReportKeepLock() /* Do nothing. */
+
+#else
+
+ extern FILE * xmpCoreOut;
+
+ #define AnnounceThrow(msg) \
+ fprintf ( xmpCoreOut, "XMP_Throw: %s\n", msg ); fflush ( xmpOut )
+ #define AnnounceCatch(msg) \
+ fprintf ( xmpCoreOut, "Catch in %s: %s\n", procName, msg ); fflush ( xmpOut )
+
+ #define AnnounceEntry(proc) \
+ const char * procName = proc; \
+ fprintf ( xmpCoreOut, "Entering %s\n", procName ); fflush ( xmpOut )
+ #define AnnounceNoLock(proc) \
+ const char * procName = proc; \
+ fprintf ( xmpCoreOut, "Entering %s (no lock)\n", procName ); fflush ( xmpOut )
+ #define AnnounceExit() \
+ fprintf ( xmpCoreOut, "Exiting %s\n", procName ); fflush ( xmpOut )
+
+ #define ReportLock() \
+ ++sLockCount; fprintf ( xmpCoreOut, " Auto lock, count = %d\n", sLockCount ); fflush ( xmpOut )
+ #define ReportUnlock() \
+ --sLockCount; fprintf ( xmpCoreOut, " Auto unlock, count = %d\n", sLockCount ); fflush ( xmpOut )
+ #define ReportKeepLock() \
+ fprintf ( xmpCoreOut, " Keeping lock, count = %d\n", sLockCount ); fflush ( xmpOut )
+
+#endif
+
+#define XMP_Throw(msg,id) { AnnounceThrow ( msg ); throw XMP_Error ( id, msg ); }
+
+// -------------------------------------------------------------------------------------------------
+
+#if XMP_MacBuild
+ typedef MPCriticalRegionID XMP_Mutex;
+#elif XMP_WinBuild
+ typedef CRITICAL_SECTION XMP_Mutex;
+#elif XMP_UNIXBuild
+ typedef pthread_mutex_t XMP_Mutex;
+#endif
+
+extern XMP_Mutex sXMPCoreLock;
+extern int sLockCount; // Keep signed to catch unlock errors.
+extern XMP_VarString * sExceptionMessage;
+
+extern bool XMP_InitMutex ( XMP_Mutex * mutex );
+extern void XMP_TermMutex ( XMP_Mutex & mutex );
+
+extern void XMP_EnterCriticalRegion ( XMP_Mutex & mutex );
+extern void XMP_ExitCriticalRegion ( XMP_Mutex & mutex );
+
+class XMP_AutoMutex {
+public:
+ XMP_AutoMutex() : mutex(&sXMPCoreLock) { XMP_EnterCriticalRegion ( *mutex ); ReportLock(); };
+ ~XMP_AutoMutex() { if ( mutex != 0 ) { ReportUnlock(); XMP_ExitCriticalRegion ( *mutex ); mutex = 0; } };
+ void KeepLock() { ReportKeepLock(); mutex = 0; };
+private:
+ XMP_Mutex * mutex;
+};
+
+// *** Switch to XMPEnterObjectWrapper & XMPEnterStaticWrapper, to allow for per-object locks.
+
+// ! Don't do the initialization check (sXMP_InitCount > 0) for the no-lock case. That macro is used
+// ! by WXMPMeta_Initialize_1.
+
+#define XMP_ENTER_WRAPPER_NO_LOCK(proc) \
+ AnnounceNoLock ( proc ); \
+ XMP_Assert ( (0 <= sLockCount) && (sLockCount <= 1) ); \
+ try { \
+ wResult->errMessage = 0;
+
+#define XMP_ENTER_WRAPPER(proc) \
+ AnnounceEntry ( proc ); \
+ XMP_Assert ( sXMP_InitCount > 0 ); \
+ XMP_Assert ( (0 <= sLockCount) && (sLockCount <= 1) ); \
+ try { \
+ XMP_AutoMutex mutex; \
+ wResult->errMessage = 0;
+
+#define XMP_EXIT_WRAPPER \
+ XMP_CATCH_EXCEPTIONS \
+ AnnounceExit();
+
+#define XMP_EXIT_WRAPPER_KEEP_LOCK(keep) \
+ if ( keep ) mutex.KeepLock(); \
+ XMP_CATCH_EXCEPTIONS \
+ AnnounceExit();
+
+#define XMP_EXIT_WRAPPER_NO_THROW \
+ } catch ( ... ) { \
+ AnnounceCatch ( "no-throw catch-all" ); \
+ /* Do nothing. */ \
+ } \
+ AnnounceExit();
+
+#define XMP_CATCH_EXCEPTIONS \
+ } catch ( XMP_Error & xmpErr ) { \
+ wResult->int32Result = xmpErr.GetID(); \
+ wResult->ptrResult = (void*)"XMP"; \
+ wResult->errMessage = xmpErr.GetErrMsg(); \
+ if ( wResult->errMessage == 0 ) wResult->errMessage = ""; \
+ AnnounceCatch ( wResult->errMessage ); \
+ } catch ( std::exception & stdErr ) { \
+ wResult->int32Result = kXMPErr_StdException; \
+ wResult->errMessage = stdErr.what(); \
+ if ( wResult->errMessage == 0 ) wResult->errMessage = ""; \
+ AnnounceCatch ( wResult->errMessage ); \
+ } catch ( ... ) { \
+ wResult->int32Result = kXMPErr_UnknownException; \
+ wResult->errMessage = "Caught unknown exception"; \
+ AnnounceCatch ( wResult->errMessage ); \
+ }
+
+#if XMP_DebugBuild
+ #define RELEASE_NO_THROW /* empty */
+#else
+ #define RELEASE_NO_THROW throw()
+#endif
+
+// =================================================================================================
+// ExpandXPath, FindNode, and related support
+
+// *** Normalize the use of "const xx &" for input params
+
+#define kXMP_ArrayItemName "[]"
+
+#define kXMP_CreateNodes true
+#define kXMP_ExistingOnly false
+
+#define FindConstSchema(t,u) FindSchemaNode ( const_cast<XMP_Node*>(t), u, kXMP_ExistingOnly, 0 )
+#define FindConstChild(p,c) FindChildNode ( const_cast<XMP_Node*>(p), c, kXMP_ExistingOnly, 0 )
+#define FindConstQualifier(p,c) FindQualifierNode ( const_cast<XMP_Node*>(p), c, kXMP_ExistingOnly, 0 )
+#define FindConstNode(t,p) FindNode ( const_cast<XMP_Node*>(t), p, kXMP_ExistingOnly, 0 )
+
+extern XMP_OptionBits
+VerifySetOptions ( XMP_OptionBits options, XMP_StringPtr propValue );
+
+extern void
+ComposeXPath ( const XMP_ExpandedXPath & expandedXPath,
+ XMP_VarString * stringXPath );
+
+extern void
+ExpandXPath ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propPath,
+ XMP_ExpandedXPath * expandedXPath );
+
+extern XMP_Node *
+FindSchemaNode ( XMP_Node * xmpTree,
+ XMP_StringPtr nsURI,
+ bool createNodes,
+ XMP_NodePtrPos * ptrPos = 0 );
+
+extern XMP_Node *
+FindChildNode ( XMP_Node * parent,
+ XMP_StringPtr childName,
+ bool createNodes,
+ XMP_NodePtrPos * ptrPos = 0 );
+
+extern XMP_Node *
+FindQualifierNode ( XMP_Node * parent,
+ XMP_StringPtr qualName,
+ bool createNodes,
+ XMP_NodePtrPos * ptrPos = 0 );
+
+extern XMP_Node *
+FindNode ( XMP_Node * xmpTree,
+ const XMP_ExpandedXPath & expandedXPath,
+ bool createNodes,
+ XMP_OptionBits leafOptions = 0,
+ XMP_NodePtrPos * ptrPos = 0 );
+
+extern XMP_Index
+LookupLangItem ( const XMP_Node * arrayNode, XMP_VarString & lang ); // ! Lang must be normalized!
+
+extern XMP_Index
+LookupFieldSelector ( const XMP_Node * arrayNode, XMP_StringPtr fieldName, XMP_StringPtr fieldValue );
+
+extern void
+CloneOffspring ( const XMP_Node * origParent, XMP_Node * cloneParent );
+
+extern XMP_Node *
+CloneSubtree ( const XMP_Node * origRoot, XMP_Node * cloneParent );
+
+extern bool
+CompareSubtrees ( const XMP_Node & leftNode, const XMP_Node & rightNode );
+
+extern void
+DeleteEmptySchema ( XMP_Node * schemaNode );
+
+extern void
+NormalizeLangValue ( XMP_VarString * value );
+
+extern void
+NormalizeLangArray ( XMP_Node * array );
+
+extern void
+DetectAltText ( XMP_Node * xmpParent );
+
+#define IsWhitespaceChar(ch) ( ((ch) == ' ') || ((ch) == 0x09) || ((ch) == 0x0A) || ((ch) == 0x0D) )
+
+extern bool
+IsWhitespaceNode ( const XML_Node & xmlNode );
+
+extern void
+SortNamedNodes ( XMP_NodeOffspring & nodeVector );
+
+static inline bool
+IsPathPrefix ( XMP_StringPtr fullPath, XMP_StringPtr prefix )
+{
+ bool isPrefix = false;
+ XMP_StringLen prefixLen = std::strlen(prefix);
+ if ( XMP_LitNMatch ( prefix, fullPath, prefixLen ) ) {
+ char separator = fullPath[prefixLen];
+ if ( (separator == 0) || (separator == '/') ||
+ (separator == '[') || (separator == '*') ) isPrefix = true;
+ }
+ return isPrefix;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+class XPathStepInfo {
+public:
+ XMP_VarString step;
+ XMP_OptionBits options;
+ XPathStepInfo ( XMP_StringPtr _step, XMP_OptionBits _options ) : step(_step), options(_options) {};
+ XPathStepInfo ( XMP_VarString _step, XMP_OptionBits _options ) : step(_step), options(_options) {};
+private:
+ XPathStepInfo() : options(0) {}; // ! Hide the default constructor.
+};
+
+enum { kSchemaStep = 0, kRootPropStep = 1, kAliasIndexStep = 2 };
+
+enum { // Bits for XPathStepInfo options. // *** Add mask check to init code.
+ kXMP_StepKindMask = 0x0F, // ! The step kinds are mutually exclusive numbers.
+ kXMP_StructFieldStep = 0x01, // Also for top level nodes (schema "fields").
+ kXMP_QualifierStep = 0x02, // ! Order is significant to separate struct/qual from array kinds!
+ kXMP_ArrayIndexStep = 0x03, // ! The kinds must not overlay array form bits!
+ kXMP_ArrayLastStep = 0x04,
+ kXMP_QualSelectorStep = 0x05,
+ kXMP_FieldSelectorStep = 0x06,
+ kXMP_StepIsAlias = 0x10
+};
+
+#define GetStepKind(f) ((f) & kXMP_StepKindMask)
+
+#define kXMP_NewImplicitNode kXMP_InsertAfterItem
+
+// =================================================================================================
+// XMP_Node details
+
+#if 0 // Pattern for iterating over the children or qualifiers:
+ for ( size_t xxNum = 0, xxLim = _node_->_offspring_.size(); xxNum < xxLim; ++xxNum ) {
+ const XMP_Node * _curr_ = _node_->_offspring_[xxNum];
+ }
+#endif
+
+class XMP_Node {
+public:
+
+ XMP_OptionBits options;
+ XMP_VarString name, value;
+ XMP_Node * parent;
+ XMP_NodeOffspring children;
+ XMP_NodeOffspring qualifiers;
+ #if XMP_DebugBuild
+ // *** XMP_StringPtr _namePtr, _valuePtr; // *** Not working, need operator=?
+ #endif
+
+ XMP_Node ( XMP_Node * _parent, XMP_StringPtr _name, XMP_OptionBits _options )
+ : options(_options), name(_name), parent(_parent)
+ {
+ #if XMP_DebugBuild
+ XMP_Assert ( (name.find ( ':' ) != XMP_VarString::npos) || (name == kXMP_ArrayItemName) ||
+ (options & kXMP_SchemaNode) || (parent == 0) );
+ // *** _namePtr = name.c_str();
+ // *** _valuePtr = value.c_str();
+ #endif
+ };
+
+ XMP_Node ( XMP_Node * _parent, const XMP_VarString & _name, XMP_OptionBits _options )
+ : options(_options), name(_name), parent(_parent)
+ {
+ #if XMP_DebugBuild
+ XMP_Assert ( (name.find ( ':' ) != XMP_VarString::npos) || (name == kXMP_ArrayItemName) ||
+ (options & kXMP_SchemaNode) || (parent == 0) );
+ // *** _namePtr = name.c_str();
+ // *** _valuePtr = value.c_str();
+ #endif
+ };
+
+ XMP_Node ( XMP_Node * _parent, XMP_StringPtr _name, XMP_StringPtr _value, XMP_OptionBits _options )
+ : options(_options), name(_name), value(_value), parent(_parent)
+ {
+ #if XMP_DebugBuild
+ XMP_Assert ( (name.find ( ':' ) != XMP_VarString::npos) || (name == kXMP_ArrayItemName) ||
+ (options & kXMP_SchemaNode) || (parent == 0) );
+ // *** _namePtr = name.c_str();
+ // *** _valuePtr = value.c_str();
+ #endif
+ };
+
+ XMP_Node ( XMP_Node * _parent, const XMP_VarString & _name, const XMP_VarString & _value, XMP_OptionBits _options )
+ : options(_options), name(_name), value(_value), parent(_parent)
+ {
+ #if XMP_DebugBuild
+ XMP_Assert ( (name.find ( ':' ) != XMP_VarString::npos) || (name == kXMP_ArrayItemName) ||
+ (options & kXMP_SchemaNode) || (parent == 0) );
+ // *** _namePtr = name.c_str();
+ // *** _valuePtr = value.c_str();
+ #endif
+ };
+
+ void RemoveChildren()
+ {
+ for ( size_t i = 0, vLim = children.size(); i < vLim; ++i ) {
+ if ( children[i] != 0 ) delete children[i];
+ }
+ children.clear();
+ }
+
+ void RemoveQualifiers()
+ {
+ for ( size_t i = 0, vLim = qualifiers.size(); i < vLim; ++i ) {
+ if ( qualifiers[i] != 0 ) delete qualifiers[i];
+ }
+ qualifiers.clear();
+ }
+
+ void ClearNode()
+ {
+ options = 0;
+ name.erase();
+ value.erase();
+ this->RemoveChildren();
+ this->RemoveQualifiers();
+ }
+
+ virtual ~XMP_Node() { RemoveChildren(); RemoveQualifiers(); };
+
+private:
+ XMP_Node() : options(0), parent(0) // ! Make sure parent pointer is always set.
+ {
+ #if XMP_DebugBuild
+ // *** _namePtr = name.c_str();
+ // *** _valuePtr = value.c_str();
+ #endif
+ };
+
+};
+
+class XMP_AutoNode { // Used to hold a child during subtree construction.
+public:
+ XMP_Node * nodePtr;
+ XMP_AutoNode() : nodePtr(0) {};
+ ~XMP_AutoNode() { if ( nodePtr != 0 ) delete ( nodePtr ); nodePtr = 0; };
+ XMP_AutoNode ( XMP_Node * _parent, XMP_StringPtr _name, XMP_OptionBits _options )
+ : nodePtr ( new XMP_Node ( _parent, _name, _options ) ) {};
+ XMP_AutoNode ( XMP_Node * _parent, const XMP_VarString & _name, XMP_OptionBits _options )
+ : nodePtr ( new XMP_Node ( _parent, _name, _options ) ) {};
+ XMP_AutoNode ( XMP_Node * _parent, XMP_StringPtr _name, XMP_StringPtr _value, XMP_OptionBits _options )
+ : nodePtr ( new XMP_Node ( _parent, _name, _value, _options ) ) {};
+ XMP_AutoNode ( XMP_Node * _parent, const XMP_VarString & _name, const XMP_VarString & _value, XMP_OptionBits _options )
+ : nodePtr ( new XMP_Node ( _parent, _name, _value, _options ) ) {};
+};
+
+// =================================================================================================
+// XML_Node details
+
+// The XML_Nodes are used only during the XML/RDF parsing process. This presently uses an XML parser
+// to create an XML tree, then a recursive descent RDF recognizer to build the corresponding XMP.
+// This makes it easier to swap XML parsers and provides a clean separation of XML and RDF issues.
+// The overall parsing would be faster and use less memory if the RDF recognition were done on the
+// fly using a state machine. But it was much easier to write the recursive descent version. The
+// current implementation is pretty fast in absolute terms, so being faster might not be crucial.
+
+// Like the XMP tree, the XML tree contains vectors of pointers for down links, and offspring have
+// a pointer to their parent. Unlike the XMP tree, this is an exact XML document tree. There are no
+// introduced top level namespace nodes or rearrangement of the nodes..
+
+// The exact state of namespaces can vary during the XML parsing, depending on the parser in use.
+// By the time the RDF recognition is done though, the namespaces must be normalized. All of the
+// used namespaces must be registered, this is done automatically if necessary. All of the "live"
+// namespace prefixes will be unique. The ns field of an XML_Node is the namespace URI, the name
+// field contains a qualified name (prefix:local). This includes default namespace mapping, the
+// URI and prefix will be missing only for elements and attributes in no namespace.
+
+class XML_Node;
+enum { kRootNode = 0, kElemNode = 1, kAttrNode = 2, kCDataNode = 3, kPINode = 4 };
+
+typedef std::vector<XML_Node*> XML_NodeVector;
+typedef XML_NodeVector::iterator XML_NodePos;
+typedef XML_NodeVector::const_iterator XML_cNodePos;
+
+#if 0 // Pattern for iterating over the children or attributes:
+ for ( size_t xxNum = 0, xxLim = _node_->_offspring_.size(); xxNum < xxLim; ++xxNum ) {
+ const XML_Node * _curr_ = _node_->_offspring_[xxNum];
+ }
+#endif
+
+class XML_Node {
+public:
+
+ XMP_Uns8 kind;
+ XMP_VarString ns, name, value;
+ XML_Node * parent;
+ XML_NodeVector attrs;
+ XML_NodeVector content;
+ #if 0 // *** XMP_DebugBuild
+ XMP_StringPtr _namePtr, _valuePtr; // *** Not working, need operator=?
+ #endif
+
+ XML_Node ( XML_Node * _parent, XMP_StringPtr _name, XMP_Uns8 _kind )
+ : kind(_kind), name(_name), parent(_parent)
+ {
+ #if 0 // *** XMP_DebugBuild
+ _namePtr = name.c_str();
+ _valuePtr = value.c_str();
+ #endif
+ };
+
+ XML_Node ( XML_Node * _parent, const XMP_VarString & _name, XMP_Uns8 _kind )
+ : kind(_kind), name(_name), parent(_parent)
+ {
+ #if 0 // *** XMP_DebugBuild
+ _namePtr = name.c_str();
+ _valuePtr = value.c_str();
+ #endif
+ };
+
+ void RemoveAttrs()
+ {
+ for ( size_t i = 0, vLim = attrs.size(); i < vLim; ++i ) delete attrs[i];
+ attrs.clear();
+ }
+
+ void RemoveContent()
+ {
+ for ( size_t i = 0, vLim = content.size(); i < vLim; ++i ) delete content[i];
+ content.clear();
+ }
+
+ void ClearNode()
+ {
+ kind = 0;
+ ns.erase();
+ name.erase();
+ value.erase();
+ this->RemoveAttrs();
+ this->RemoveContent();
+ }
+
+ virtual ~XML_Node() { RemoveAttrs(); RemoveContent(); }
+
+private:
+ XML_Node() : kind(0), parent(0) // ! Make sure parent pointer is always set.
+ {
+ #if 0 // *** XMP_DebugBuild
+ _namePtr = name.c_str();
+ _valuePtr = value.c_str();
+ #endif
+ };
+
+};
+
+extern void ProcessRDF ( XMP_Node * xmpTree, const XML_Node & xmlTree, XMP_OptionBits options );
+
+// =================================================================================================
+
+#endif // __XMPCore_Impl_hpp__
diff --git a/source/XMPCore/XMPIterator.cpp b/source/XMPCore/XMPIterator.cpp
new file mode 100644
index 0000000..8032bfa
--- /dev/null
+++ b/source/XMPCore/XMPIterator.cpp
@@ -0,0 +1,735 @@
+// =================================================================================================
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "XMP_Environment.h" // ! This must be the first include!
+#include "XMPCore_Impl.hpp"
+
+#include "XMPIterator.hpp"
+
+#include <string>
+#include <stdio.h> // For snprintf.
+
+#if XMP_WinBuild
+ #pragma warning ( disable : 4702 ) // unreachable code
+ #pragma warning ( disable : 4800 ) // forcing value to bool 'true' or 'false' (performance warning)
+ #pragma warning ( disable : 4996 ) // '...' was declared deprecated
+#endif
+
+// =================================================================================================
+// Support Routines
+// =================================================================================================
+
+
+#ifndef TraceIterators
+ #define TraceIterators 0
+#endif
+
+#if TraceIterators
+ static const char * sStageNames[] = { "before", "self", "qualifiers", "children" };
+#endif
+
+static XMP_Node * sDummySchema = 0; // ! Used for some ugliness with aliases.
+
+// -------------------------------------------------------------------------------------------------
+// AddSchemaProps
+// --------------
+//
+// Add the top level properties to the IterNode for a schema.
+
+static void
+AddSchemaProps ( IterInfo & info, IterNode & iterSchema, const XMP_Node * xmpSchema )
+{
+ info = info; // Avoid unused parameter warning.
+ #if TraceIterators
+ printf ( " Adding properties of %s\n", xmpSchema->name.c_str() );
+ #endif
+
+ for ( size_t propNum = 0, propLim = xmpSchema->children.size(); propNum != propLim; ++propNum ) {
+ const XMP_Node * xmpProp = xmpSchema->children[propNum];
+ // *** set the has-aliases bit when appropriate
+ iterSchema.children.push_back ( IterNode ( xmpProp->options, xmpProp->name, 0 ) );
+ #if TraceIterators
+ printf ( " %s\n", xmpProp->name.c_str() );
+ #endif
+ }
+
+} // AddSchemaProps
+
+// -------------------------------------------------------------------------------------------------
+// AddSchemaAliases
+// ----------------
+//
+// Add the aliases to the IterNode for a schema, if the corresponding actual exists.
+
+static void
+AddSchemaAliases ( IterInfo & info, IterNode & iterSchema, XMP_StringPtr schemaURI )
+{
+
+ // We're showing the aliases also. Look them up by their namespace prefix. Yes, the alias map is
+ // sorted so we could process just that portion. But that takes more code and the extra speed
+ // isn't worth it. (Plus this way we avoid a dependence on the map implementation.) Lookup the
+ // XMP node from the alias, to make sure the actual exists.
+
+ #if TraceIterators
+ printf ( " Adding aliases\n", schemaURI );
+ #endif
+
+ XMP_StringPtr nsPrefix;
+ XMP_StringLen nsLen;
+ bool found = XMPMeta::GetNamespacePrefix ( schemaURI, &nsPrefix, &nsLen );
+ if ( ! found ) XMP_Throw ( "Unknown iteration namespace", kXMPErr_BadSchema );
+
+ XMP_AliasMapPos currAlias = sRegisteredAliasMap->begin();
+ XMP_AliasMapPos endAlias = sRegisteredAliasMap->end();
+
+ for ( ; currAlias != endAlias; ++currAlias ) {
+ if ( XMP_LitNMatch ( currAlias->first.c_str(), nsPrefix, nsLen ) ) {
+ const XMP_Node * actualProp = FindConstNode ( &info.xmpObj->tree, currAlias->second );
+ if ( actualProp != 0 ) {
+ iterSchema.children.push_back ( IterNode ( (actualProp->options | kXMP_PropIsAlias), currAlias->first, 0 ) );
+ #if TraceIterators
+ printf ( " %s => %s\n", currAlias->first.c_str(), actualProp->name.c_str() );
+ #endif
+ }
+ }
+ }
+
+} // AddSchemaAliases
+
+// -------------------------------------------------------------------------------------------------
+// AddNodeOffspring
+// ----------------
+//
+// Add the immediate children and qualifiers to an IterNode.
+
+static void
+AddNodeOffspring ( IterInfo & info, IterNode & iterParent, const XMP_Node * xmpParent )
+{
+ XMP_VarString currPath ( iterParent.fullPath );
+ size_t leafOffset = iterParent.fullPath.size();
+
+ if ( (! xmpParent->qualifiers.empty()) && (! (info.options & kXMP_IterOmitQualifiers)) ) {
+
+ #if TraceIterators
+ printf ( " Adding qualifiers of %s\n", currPath.c_str() );
+ #endif
+
+ currPath += "/?"; // All qualifiers are named and use paths like "Prop/?Qual".
+ leafOffset += 2;
+
+ for ( size_t qualNum = 0, qualLim = xmpParent->qualifiers.size(); qualNum != qualLim; ++qualNum ) {
+ const XMP_Node * xmpQual = xmpParent->qualifiers[qualNum];
+ currPath += xmpQual->name;
+ iterParent.qualifiers.push_back ( IterNode ( xmpQual->options, currPath, leafOffset ) );
+ currPath.erase ( leafOffset );
+ #if TraceIterators
+ printf ( " %s\n", xmpQual->name.c_str() );
+ #endif
+ }
+
+ leafOffset -= 2;
+ currPath.erase ( leafOffset );
+
+ }
+
+ if ( ! xmpParent->children.empty() ) {
+
+ #if TraceIterators
+ printf ( " Adding children of %s\n", currPath.c_str() );
+ #endif
+
+ XMP_Assert ( xmpParent->options & kXMP_PropCompositeMask );
+
+ if ( xmpParent->options & kXMP_PropValueIsStruct ) {
+ currPath += '/';
+ leafOffset += 1;
+ }
+
+ for ( size_t childNum = 0, childLim = xmpParent->children.size(); childNum != childLim; ++childNum ) {
+ const XMP_Node * xmpChild = xmpParent->children[childNum];
+ if ( ! (xmpParent->options & kXMP_PropValueIsArray) ) {
+ currPath += xmpChild->name;
+ } else {
+ char buffer [32]; // AUDIT: Using sizeof(buffer) below for snprintf length is safe.
+ snprintf ( buffer, sizeof(buffer), "[%d]", childNum+1 ); // ! XPath indices are one-based.
+ currPath += buffer;
+ }
+ iterParent.children.push_back ( IterNode ( xmpChild->options, currPath, leafOffset ) );
+ currPath.erase ( leafOffset );
+ #if TraceIterators
+ printf ( " %s\n", (iterParent.children.back().fullPath.c_str() + leafOffset) );
+ #endif
+ }
+
+ }
+
+} // AddNodeOffspring
+
+// -------------------------------------------------------------------------------------------------
+// SetCurrSchema
+// -------------
+
+static inline void
+SetCurrSchema ( IterInfo & info, XMP_StringPtr schemaName )
+{
+
+ info.currSchema = schemaName;
+ #if 0 // *** XMP_DebugBuild
+ info._schemaPtr = info.currSchema.c_str();
+ #endif
+
+} // SetCurrSchema
+
+static inline void
+SetCurrSchema ( IterInfo & info, XMP_VarString & schemaName )
+{
+
+ info.currSchema = schemaName;
+ #if 0 // *** XMP_DebugBuild
+ info._schemaPtr = info.currSchema.c_str();
+ #endif
+
+} // SetCurrSchema
+
+// -------------------------------------------------------------------------------------------------
+// AdvanceIterPos
+// --------------
+//
+// Adjust currPos and possibly endPos for the next step in a pre-order depth-first traversal. The
+// current node has just been visited, move on to its qualifiers, children, then siblings, or back
+// up to an ancestor. AdvanceIterPos either moves to a property or qualifier node that can be
+// visited, or to the end of the entire iteration.
+
+static void
+AdvanceIterPos ( IterInfo & info )
+{
+ // -------------------------------------------------------------------------------------------
+ // Keep looking until we find a node to visit or the end of everything. The first time through
+ // the current node will exist, we just visited it. But we have to keep looking if the current
+ // node was the last of its siblings or is an empty schema.
+
+ // ! It is possible that info.currPos == info.endPos on entry. Don't dereference info.currPos yet!
+
+ while ( true ) {
+
+ if ( info.currPos == info.endPos ) {
+
+ // ------------------------------------------------------------------------------------
+ // At the end of a set of siblings, move up to an ancestor. We've either just finished
+ // the qualifiers and will move to the children, or have just finished the children and
+ // will move on to the next sibling.
+
+ if ( info.ancestors.empty() ) break; // We're at the end of the schema list.
+
+ IterPosPair & parent = info.ancestors.back();
+ info.currPos = parent.first;
+ info.endPos = parent.second;
+ info.ancestors.pop_back();
+
+ #if TraceIterators
+ printf ( " Moved up to %s, stage = %s\n",
+ info.currPos->fullPath.c_str(), sStageNames[info.currPos->visitStage] );
+ #endif
+
+ } else {
+
+ // -------------------------------------------------------------------------------------------
+ // Decide what to do with this iteration node based on its state. Don't use a switch statment,
+ // some of the cases want to break from the loop. A break in a switch just exits the case.
+
+ #if TraceIterators
+ printf ( " Moving from %s, stage = %s\n",
+ info.currPos->fullPath.c_str(), sStageNames[info.currPos->visitStage] );
+ #endif
+
+ if ( info.currPos->visitStage == kIter_BeforeVisit ) { // Visit this node now.
+ if ( info.currPos->options & kXMP_SchemaNode ) SetCurrSchema ( info, info.currPos->fullPath );
+ break;
+ }
+
+ if ( info.currPos->visitStage == kIter_VisitSelf ) { // Just finished visiting the value portion.
+ info.currPos->visitStage = kIter_VisitQualifiers; // Start visiting the qualifiers.
+ if ( ! info.currPos->qualifiers.empty() ) {
+ info.ancestors.push_back ( IterPosPair ( info.currPos, info.endPos ) );
+ info.endPos = info.currPos->qualifiers.end(); // ! Set the parent's endPos before changing currPos!
+ info.currPos = info.currPos->qualifiers.begin();
+ break;
+ }
+ }
+
+ if ( info.currPos->visitStage == kIter_VisitQualifiers ) { // Just finished visiting the qualifiers.
+ info.currPos->qualifiers.clear();
+ info.currPos->visitStage = kIter_VisitChildren; // Start visiting the children.
+ if ( ! info.currPos->children.empty() ) {
+ info.ancestors.push_back ( IterPosPair ( info.currPos, info.endPos ) );
+ info.endPos = info.currPos->children.end(); // ! Set the parent's endPos before changing currPos!
+ info.currPos = info.currPos->children.begin();
+ break;
+ }
+ }
+
+ if ( info.currPos->visitStage == kIter_VisitChildren ) { // Just finished visiting the children.
+ info.currPos->children.clear();
+ ++info.currPos; // Move to the next sibling.
+ continue;
+ }
+
+ #if TraceIterators
+ if ( info.currPos != info.endPos ) {
+ printf ( " Moved to %s, stage = %s\n",
+ info.currPos->fullPath.c_str(), sStageNames[info.currPos->visitStage] );
+ }
+ #endif
+
+ }
+
+ } // Loop to find the next node.
+
+ XMP_Assert ( (info.currPos == info.endPos) || (info.currPos->visitStage == kIter_BeforeVisit) );
+
+} // AdvanceIterPos
+
+// -------------------------------------------------------------------------------------------------
+// GetNextXMPNode
+// --------------
+//
+// Used by XMPIterator::Next to obtain the next XMP node, ignoring the kXMP_IterJustLeafNodes flag.
+// This isolates some messy code, allowing a clean loop in Next if kXMP_IterJustLeafNodes is set.
+
+static const XMP_Node *
+GetNextXMPNode ( IterInfo & info )
+{
+ const XMP_Node * xmpNode = 0;
+
+ // ----------------------------------------------------------------------------------------------
+ // On entry currPos points to an iteration node whose state is either before-visit or visit-self.
+ // If it is before-visit then we will return that node's value part now. If it is visit-self it
+ // means the previous iteration returned the value portion of that node, so we can advance to the
+ // next node in the iteration tree. Then we find the corresponding XMP node, allowing for the XMP
+ // tree to have been modified since that part of the iteration tree was constructed.
+
+ // ! NOTE: Supporting aliases throws in some nastiness with schemas. There might not be any XMP
+ // ! node for the schema, but we still have to visit it because of possible aliases. The static
+ // ! sDummySchema is returned if there is no real schema node.
+
+ if ( info.currPos->visitStage != kIter_BeforeVisit ) AdvanceIterPos ( info );
+
+ bool isSchemaNode = false;
+ XMP_ExpandedXPath expPath; // Keep outside the loop to avoid constant construct/destruct.
+
+ while ( info.currPos != info.endPos ) {
+
+ isSchemaNode = XMP_NodeIsSchema ( info.currPos->options );
+ if ( isSchemaNode ) {
+ SetCurrSchema ( info, info.currPos->fullPath );
+ xmpNode = FindConstSchema ( &info.xmpObj->tree, info.currPos->fullPath.c_str() );
+ if ( xmpNode == 0 ) xmpNode = sDummySchema;
+ } else {
+ ExpandXPath ( info.currSchema.c_str(), info.currPos->fullPath.c_str(), &expPath );
+ xmpNode = FindConstNode ( &info.xmpObj->tree, expPath );
+ }
+ if ( xmpNode != 0 ) break; // Exit the loop, we found a live XMP node.
+
+ info.currPos->visitStage = kIter_VisitChildren; // Make AdvanceIterPos move to the next sibling.
+ info.currPos->children.clear();
+ info.currPos->qualifiers.clear();
+ AdvanceIterPos ( info );
+
+ }
+
+ if ( info.currPos == info.endPos ) return 0;
+
+ // -------------------------------------------------------------------------------------------
+ // Now we've got the iteration node and corresponding XMP node. Add the iteration children for
+ // structs and arrays. The children of schema were added when the iterator was constructed.
+
+ XMP_Assert ( info.currPos->visitStage == kIter_BeforeVisit );
+
+ if ( info.currPos->visitStage == kIter_BeforeVisit ) {
+ if ( (! isSchemaNode) && (! (info.options & kXMP_IterJustChildren)) ) {
+ AddNodeOffspring ( info, *info.currPos, xmpNode );
+ }
+ info.currPos->visitStage = kIter_VisitSelf;
+ }
+
+ return xmpNode;
+
+} // GetNextXMPNode
+
+// =================================================================================================
+// Init/Term
+// =================================================================================================
+
+// -------------------------------------------------------------------------------------------------
+// Initialize
+// ----------
+
+/* class static */ bool
+XMPIterator::Initialize()
+{
+ sDummySchema = new XMP_Node ( 0, "dummy:schema/", kXMP_SchemaNode);
+ return true;
+
+} // Initialize
+
+// -------------------------------------------------------------------------------------------------
+// Terminate
+// ----------
+
+/* class static */ void
+XMPIterator::Terminate() RELEASE_NO_THROW
+{
+ delete ( sDummySchema );
+ sDummySchema = 0;
+ return;
+
+} // Terminate
+
+// -------------------------------------------------------------------------------------------------
+// Unlock
+// ------
+
+void
+XMPIterator::Unlock ( XMP_OptionBits options )
+{
+ options = options; // Avoid unused parameter warning.
+
+ XMPMeta::Unlock ( 0 );
+
+} // Unlock
+
+// =================================================================================================
+// Constructors
+// =================================================================================================
+
+// -------------------------------------------------------------------------------------------------
+// XMPIterator
+// -----------
+//
+// Constructor for iterations over the nodes in an XMPMeta object. This builds a tree of iteration
+// nodes that caches the existing node names of the XMPMeta object. The iteration tree is a partial
+// replica of the XMPMeta tree. The initial iteration tree normally has just the root node, all of
+// the schema nodes for a full object iteration. Lower level nodes (children and qualifiers) are
+// added when the parent is visited. If the kXMP_IterJustChildren option is passed then the initial
+// iterator includes the children and the parent is marked as done. The iteration tree nodes are
+// pruned when they are no longer needed.
+
+XMPIterator::XMPIterator ( const XMPMeta & xmpObj,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_OptionBits options ) : info(IterInfo(options,&xmpObj)), clientRefs(0)
+{
+ if ( (options & kXMP_IterClassMask) != kXMP_IterProperties ) {
+ XMP_Throw ( "Unsupported iteration kind", kXMPErr_BadOptions );
+ }
+
+ // *** Lock the XMPMeta object if we ever stop using a full DLL lock.
+
+ if ( *propName != 0 ) {
+
+ // An iterator rooted at a specific node.
+
+ #if TraceIterators
+ printf ( "\nNew XMP property iterator for \"%s\", options = %X\n Schema = %s, root = %s\n",
+ xmpObj.tree.name.c_str(), options, schemaNS, propName );
+ #endif
+
+ XMP_ExpandedXPath propPath;
+ ExpandXPath ( schemaNS, propName, &propPath );
+ XMP_Node * propNode = FindConstNode ( &xmpObj.tree, propPath ); // If not found get empty iteration.
+
+ if ( propNode != 0 ) {
+
+ XMP_VarString rootName ( propPath[1].step ); // The schema is [0].
+ for ( size_t i = 2; i < propPath.size(); ++i ) {
+ XMP_OptionBits stepKind = GetStepKind ( propPath[i].options );
+ if ( stepKind <= kXMP_QualifierStep ) rootName += '/';
+ rootName += propPath[i].step;
+ }
+
+ propName = rootName.c_str();
+ size_t leafOffset = rootName.size();
+ while ( (leafOffset > 0) && (propName[leafOffset] != '/') && (propName[leafOffset] != '[') ) --leafOffset;
+ if ( propName[leafOffset] == '/' ) ++leafOffset;
+
+ info.tree.children.push_back ( IterNode ( propNode->options, propName, leafOffset ) );
+ SetCurrSchema ( info, propPath[kSchemaStep].step.c_str() );
+ if ( info.options & kXMP_IterJustChildren ) {
+ AddNodeOffspring ( info, info.tree.children.back(), propNode );
+ }
+
+ }
+
+ } else if ( *schemaNS != 0 ) {
+
+ // An iterator for all properties in one schema.
+
+ #if TraceIterators
+ printf ( "\nNew XMP schema iterator for \"%s\", options = %X\n Schema = %s\n",
+ xmpObj.tree.name.c_str(), options, schemaNS );
+ #endif
+
+ info.tree.children.push_back ( IterNode ( kXMP_SchemaNode, schemaNS, 0 ) );
+ IterNode & iterSchema = info.tree.children.back();
+
+ XMP_Node * xmpSchema = FindConstSchema ( &xmpObj.tree, schemaNS );
+ if ( xmpSchema != 0 ) AddSchemaProps ( info, iterSchema, xmpSchema );
+
+ if ( info.options & kXMP_IterIncludeAliases ) AddSchemaAliases ( info, iterSchema, schemaNS );
+
+ if ( iterSchema.children.empty() ) {
+ info.tree.children.pop_back(); // No properties, remove the schema node.
+ } else {
+ SetCurrSchema ( info, schemaNS );
+ }
+
+ } else {
+
+ // An iterator for all properties in all schema. First add schema that exist (have children),
+ // adding aliases from them if appropriate. Then add schema that have no actual properties
+ // but do have aliases to existing properties, if we're including aliases in the iteration.
+
+ #if TraceIterators
+ printf ( "\nNew XMP tree iterator for \"%s\", options = %X\n",
+ xmpObj.tree.name.c_str(), options );
+ #endif
+
+ // First pick up the schema that exist.
+
+ for ( size_t schemaNum = 0, schemaLim = xmpObj.tree.children.size(); schemaNum != schemaLim; ++schemaNum ) {
+
+ const XMP_Node * xmpSchema = xmpObj.tree.children[schemaNum];
+ info.tree.children.push_back ( IterNode ( kXMP_SchemaNode, xmpSchema->name, 0 ) );
+ IterNode & iterSchema = info.tree.children.back();
+
+ if ( ! (info.options & kXMP_IterJustChildren) ) {
+ AddSchemaProps ( info, iterSchema, xmpSchema );
+ if ( info.options & kXMP_IterIncludeAliases ) AddSchemaAliases ( info, iterSchema, xmpSchema->name.c_str() );
+ if ( iterSchema.children.empty() ) info.tree.children.pop_back(); // No properties, remove the schema node.
+ }
+
+ }
+
+ if ( info.options & kXMP_IterIncludeAliases ) {
+
+ // Add the schema that only have aliases. The most convenient, and safest way, is to go
+ // through the registered namespaces, see if it exists, and let AddSchemaAliases do its
+ // thing if not. Don't combine with the above loop, it is nicer to have the "real" stuff
+ // be in storage order (not subject to the namespace map order).
+
+ // ! We don't do the kXMP_IterJustChildren handing in the same way here as above. The
+ // ! existing schema (presumably) have actual children. We need to call AddSchemaAliases
+ // ! here to determine if the namespace has any aliases to existing properties. We then
+ // ! strip the children if necessary.
+
+ XMP_cStringMapPos currNS = sNamespaceURIToPrefixMap->begin();
+ XMP_cStringMapPos endNS = sNamespaceURIToPrefixMap->end();
+ for ( ; currNS != endNS; ++currNS ) {
+ XMP_StringPtr schemaName = currNS->first.c_str();
+ if ( FindConstSchema ( &xmpObj.tree, schemaName ) != 0 ) continue;
+ info.tree.children.push_back ( IterNode ( kXMP_SchemaNode, schemaName, 0 ) );
+ IterNode & iterSchema = info.tree.children.back();
+ AddSchemaAliases ( info, iterSchema, schemaName );
+ if ( iterSchema.children.empty() ) {
+ info.tree.children.pop_back(); // No aliases, remove the schema node.
+ } else if ( info.options & kXMP_IterJustChildren ) {
+ iterSchema.children.clear(); // Get rid of the children.
+ }
+ }
+
+ }
+
+ }
+
+ // Set the current iteration position to the first node to be visited.
+
+ info.currPos = info.tree.children.begin();
+ info.endPos = info.tree.children.end();
+
+ if ( (info.options & kXMP_IterJustChildren) && (info.currPos != info.endPos) && (*schemaNS != 0) ) {
+ info.currPos->visitStage = kIter_VisitSelf;
+ }
+
+ #if TraceIterators
+ if ( info.currPos == info.endPos ) {
+ printf ( " ** Empty iteration **\n" );
+ } else {
+ printf ( " Initial node %s, stage = %s, iterator @ %.8X\n",
+ info.currPos->fullPath.c_str(), sStageNames[info.currPos->visitStage], this );
+ }
+ #endif
+
+} // XMPIterator for XMPMeta objects
+
+// -------------------------------------------------------------------------------------------------
+// XMPIterator
+// -----------
+//
+// Constructor for iterations over global tables such as registered namespaces or aliases.
+
+XMPIterator::XMPIterator ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_OptionBits options ) : info(IterInfo(options,0)), clientRefs(0)
+{
+
+ XMP_Throw ( "Unimplemented XMPIterator constructor for global tables", kXMPErr_Unimplemented );
+ void * p; p = &schemaNS; p = &propName; p = &options; // Avoid unused param warnings.
+
+} // XMPIterator for global tables
+
+// -------------------------------------------------------------------------------------------------
+// ~XMPIterator
+// -----------
+
+XMPIterator::~XMPIterator() RELEASE_NO_THROW
+{
+ XMP_Assert ( this->clientRefs <= 0 );
+ // Let everything else default.
+
+} // ~XMPIterator
+
+// =================================================================================================
+// Iteration Methods
+// =================================================================================================
+
+// -------------------------------------------------------------------------------------------------
+// Next
+// ----
+//
+// Do a preorder traversal of the cached nodes.
+
+// *** Need to document the relationships between currPos, endPos, and visitStage.
+
+bool
+XMPIterator::Next ( XMP_StringPtr * schemaNS,
+ XMP_StringLen * nsSize,
+ XMP_StringPtr * propPath,
+ XMP_StringLen * pathSize,
+ XMP_StringPtr * propValue,
+ XMP_StringLen * valueSize,
+ XMP_OptionBits * propOptions )
+{
+ // *** Lock the XMPMeta object if we ever stop using a full DLL lock.
+
+ // ! NOTE: Supporting aliases throws in some nastiness with schemas. There might not be any XMP
+ // ! node for the schema, but we still have to visit it because of possible aliases.
+
+ if ( info.currPos == info.endPos ) return false; // Happens at the start of an empty iteration.
+
+ #if TraceIterators
+ printf ( "Next iteration from %s, stage = %s, iterator @ %.8X\n",
+ info.currPos->fullPath.c_str(), sStageNames[info.currPos->visitStage], this );
+ #endif
+
+ const XMP_Node * xmpNode = GetNextXMPNode ( info );
+ if ( xmpNode == 0 ) return false;
+ bool isSchemaNode = XMP_NodeIsSchema ( info.currPos->options );
+
+ if ( info.options & kXMP_IterJustLeafNodes ) {
+ while ( isSchemaNode || (! xmpNode->children.empty()) ) {
+ info.currPos->visitStage = kIter_VisitQualifiers; // Skip to this node's children.
+ xmpNode = GetNextXMPNode ( info );
+ if ( xmpNode == 0 ) return false;
+ isSchemaNode = XMP_NodeIsSchema ( info.currPos->options );
+ }
+ }
+
+ *schemaNS = info.currSchema.c_str();
+ *nsSize = info.currSchema.size();
+
+ *propOptions = info.currPos->options;
+
+ *propPath = "";
+ *pathSize = 0;
+ *propValue = "";
+ *valueSize = 0;
+
+ if ( ! (*propOptions & kXMP_SchemaNode) ) {
+
+ *propPath = info.currPos->fullPath.c_str();
+ *pathSize = info.currPos->fullPath.size();
+ if ( info.options & kXMP_IterJustLeafName ) {
+ *propPath += info.currPos->leafOffset;
+ *pathSize -= info.currPos->leafOffset;
+ }
+
+ if ( ! (*propOptions & kXMP_PropCompositeMask) ) {
+ *propValue = xmpNode->value.c_str();
+ *valueSize = xmpNode->value.size();
+ }
+
+ }
+
+ #if TraceIterators
+ printf ( " Next node %s, stage = %s\n",
+ info.currPos->fullPath.c_str(), sStageNames[info.currPos->visitStage] );
+ #endif
+
+ return true;
+
+} // Next
+
+// -------------------------------------------------------------------------------------------------
+// Skip
+// ----
+//
+// Skip some portion of the traversal related to the last visited node. We skip either that node's
+// children, or those children and the previous node's siblings. The implementation might look a bit
+// awkward because info.currNode always points to the next node to be visited. We might already have
+// moved past the things to skip, e.g. if the previous node was simple and the last of its siblings.
+
+enum {
+ kXMP_ValidIterSkipOptions = kXMP_IterSkipSubtree | kXMP_IterSkipSiblings
+};
+
+void
+XMPIterator::Skip ( XMP_OptionBits iterOptions )
+{
+// if ( (info.currPos == kIter_NullPos) ) XMP_Throw ( "No prior postion to skip from", kXMPErr_BadIterPosition );
+ if ( iterOptions == 0 ) XMP_Throw ( "Must specify what to skip", kXMPErr_BadOptions );
+ if ( (iterOptions & ~kXMP_ValidIterSkipOptions) != 0 ) XMP_Throw ( "Undefined options", kXMPErr_BadOptions );
+
+ #if TraceIterators
+ printf ( "Skipping from %s, stage = %s, iterator @ %.8X",
+ info.currPos->fullPath.c_str(), sStageNames[info.currPos->visitStage], this );
+ #endif
+
+ if ( iterOptions & kXMP_IterSkipSubtree ) {
+ #if TraceIterators
+ printf ( ", mode = subtree\n" );
+ #endif
+ info.currPos->visitStage = kIter_VisitChildren;
+ } else if ( iterOptions & kXMP_IterSkipSiblings ) {
+ #if TraceIterators
+ printf ( ", mode = siblings\n" );
+ #endif
+ info.currPos = info.endPos;
+ AdvanceIterPos ( info );
+ }
+ #if TraceIterators
+ printf ( " Skipped to %s, stage = %s\n",
+ info.currPos->fullPath.c_str(), sStageNames[info.currPos->visitStage] );
+ #endif
+
+
+} // Skip
+
+// -------------------------------------------------------------------------------------------------
+// UnlockIter
+// ----------
+
+void
+XMPIterator::UnlockIter ( XMP_OptionBits options )
+{
+ options = options; // Avoid unused parameter warning.
+
+ XMPMeta::Unlock ( 0 );
+
+} // UnlockIter
+
+// =================================================================================================
diff --git a/source/XMPCore/XMPIterator.hpp b/source/XMPCore/XMPIterator.hpp
new file mode 100644
index 0000000..b72b975
--- /dev/null
+++ b/source/XMPCore/XMPIterator.hpp
@@ -0,0 +1,148 @@
+#ifndef __XMPIterator_hpp__
+#define __XMPIterator_hpp__
+
+// =================================================================================================
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "XMP_Environment.h"
+#include "XMP_Const.h"
+#include "XMPMeta.hpp"
+
+// =================================================================================================
+
+struct IterNode;
+typedef std::vector < IterNode > IterOffspring;
+typedef IterOffspring::iterator IterPos;
+
+typedef std::pair < IterPos, IterPos > IterPosPair;
+typedef std::vector < IterPosPair > IterPosStack;
+
+enum { // Values for the visitStage field, used to decide how to proceed past a node.
+ kIter_BeforeVisit = 0, // Have not visited this node at all.
+ kIter_VisitSelf = 1, // Have visited this node and returned its value/options portion.
+ kIter_VisitQualifiers = 2, // In the midst of visiting this node's qualifiers.
+ kIter_VisitChildren = 3 // In the midst of visiting this node's children.
+};
+
+struct IterNode {
+
+ XMP_OptionBits options;
+ XMP_VarString fullPath;
+ size_t leafOffset;
+ IterOffspring children, qualifiers;
+ XMP_Uns8 visitStage;
+ #if 0 // *** XMP_DebugBuild
+ XMP_StringPtr _pathPtr, _leafPtr; // *** Not working, need operator=?
+ #endif
+
+ IterNode() : options(0), leafOffset(0), visitStage(kIter_BeforeVisit)
+ {
+ #if 0 // *** XMP_DebugBuild
+ _pathPtr = _leafPtr = 0;
+ #endif
+ };
+
+ IterNode ( XMP_OptionBits _options, const XMP_VarString& _fullPath, size_t _leafOffset )
+ : options(_options), fullPath(_fullPath), leafOffset(_leafOffset), visitStage(kIter_BeforeVisit)
+ {
+ #if 0 // *** XMP_DebugBuild
+ _pathPtr = fullPath.c_str();
+ _leafPtr = _pathPtr + leafOffset;
+ #endif
+ };
+
+};
+
+struct IterInfo {
+
+ XMP_OptionBits options;
+ const XMPMeta * xmpObj;
+ XMP_VarString currSchema;
+ IterPos currPos, endPos;
+ IterPosStack ancestors;
+ IterNode tree;
+ #if 0 // *** XMP_DebugBuild
+ XMP_StringPtr _schemaPtr; // *** Not working, need operator=?
+ #endif
+
+ IterInfo() : options(0), xmpObj(0)
+ {
+ #if 0 // *** XMP_DebugBuild
+ _schemaPtr = 0;
+ #endif
+ };
+
+ IterInfo ( XMP_OptionBits _options, const XMPMeta * _xmpObj ) : options(_options), xmpObj(_xmpObj)
+ {
+ #if 0 // *** XMP_DebugBuild
+ _schemaPtr = 0;
+ #endif
+ };
+
+};
+
+// =================================================================================================
+
+class XMPIterator {
+public:
+
+ static bool
+ Initialize(); // ! For internal use only!
+
+ static void
+ Terminate() RELEASE_NO_THROW; // ! For internal use only!
+
+ static void
+ Unlock ( XMP_OptionBits options );
+
+ XMPIterator ( const XMPMeta & xmpObj, // Construct a property iterator.
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_OptionBits options );
+
+ XMPIterator ( XMP_StringPtr schemaNS, // Construct a table iterator.
+ XMP_StringPtr propName,
+ XMP_OptionBits options );
+
+ virtual ~XMPIterator() RELEASE_NO_THROW;
+
+ bool
+ Next ( XMP_StringPtr * schemaNS,
+ XMP_StringLen * nsSize,
+ XMP_StringPtr * propPath,
+ XMP_StringLen * pathSize,
+ XMP_StringPtr * propValue,
+ XMP_StringLen * valueSize,
+ XMP_OptionBits * propOptions );
+
+ void
+ Skip ( XMP_OptionBits options );
+
+ void
+ UnlockIter ( XMP_OptionBits options );
+
+ // ! Expose so that wrappers and file static functions can see the data.
+
+ XMP_Int32 clientRefs; // ! Must be signed to allow decrement from 0.
+ IterInfo info;
+
+private:
+
+ // ! These are hidden on purpose:
+ XMPIterator() : clientRefs(0)
+ { XMP_Throw ( "Call to hidden constructor", kXMPErr_InternalFailure ); };
+ XMPIterator ( const XMPIterator & /* original */ ) : clientRefs(0)
+ { XMP_Throw ( "Call to hidden constructor", kXMPErr_InternalFailure ); };
+ void operator= ( const XMPIterator & /* rhs */ )
+ { XMP_Throw ( "Call to hidden operator=", kXMPErr_InternalFailure ); };
+
+};
+
+// =================================================================================================
+
+#endif // __XMPIterator_hpp__
diff --git a/source/XMPCore/XMPMeta-GetSet.cpp b/source/XMPCore/XMPMeta-GetSet.cpp
new file mode 100644
index 0000000..b564b37
--- /dev/null
+++ b/source/XMPCore/XMPMeta-GetSet.cpp
@@ -0,0 +1,1209 @@
+// =================================================================================================
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+//
+// Adobe patent application tracking #P435, entitled 'Unique markers to simplify embedding data of
+// one format in a file with a different format', inventors: Sean Parent, Greg Gilley.
+// =================================================================================================
+
+#include "XMP_Environment.h" // ! This must be the first include!
+#include "XMPCore_Impl.hpp"
+
+#include "XMPMeta.hpp"
+#include "XMPIterator.hpp"
+#include "XMPUtils.hpp"
+
+#include "XMP_Version.h"
+#include "UnicodeInlines.incl_cpp"
+#include "UnicodeConversions.hpp"
+#include "ExpatAdapter.hpp"
+
+#if XMP_DebugBuild
+ #include <iostream>
+#endif
+
+using namespace std;
+
+#if XMP_WinBuild
+ #pragma warning ( disable : 4533 ) // initialization of '...' is skipped by 'goto ...'
+ #pragma warning ( disable : 4702 ) // unreachable code
+ #pragma warning ( disable : 4800 ) // forcing value to bool 'true' or 'false' (performance warning)
+#endif
+
+
+// *** Use the XMP_PropIsXyz (Schema, Simple, Struct, Array, ...) macros
+// *** Add debug codegen checks, e.g. that typical masking operations really work
+// *** Change all uses of strcmp and strncmp to XMP_LitMatch and XMP_LitNMatch
+
+
+// =================================================================================================
+// Local Types and Constants
+// =========================
+
+typedef unsigned char XMP_CLTMatch;
+
+enum { // Values for XMP_CLTMatch.
+ kXMP_CLT_NoValues,
+ kXMP_CLT_SpecificMatch,
+ kXMP_CLT_SingleGeneric,
+ kXMP_CLT_MultipleGeneric,
+ kXMP_CLT_XDefault,
+ kXMP_CLT_FirstItem
+};
+
+
+// =================================================================================================
+// Static Variables
+// ================
+
+
+// =================================================================================================
+// Local Utilities
+// ===============
+
+
+// -------------------------------------------------------------------------------------------------
+// SetNodeValue
+// ------------
+
+static inline void
+SetNodeValue ( XMP_Node * node, XMP_StringPtr value )
+{
+
+ #if XMP_DebugBuild // ! Hack to force an assert.
+ if ( (node->name == "xap:TestAssertNotify") && XMP_LitMatch ( value, "DoIt!" ) ) {
+ XMP_Assert ( node->name != "xap:TestAssertNotify" );
+ }
+ #endif
+
+ node->value = value;
+
+ XMP_Uns8* chPtr = (XMP_Uns8*) node->value.c_str(); // Check for valid UTF-8, replace ASCII controls with a space.
+ while ( *chPtr != 0 ) {
+ while ( (*chPtr != 0) && (*chPtr < 0x80) ) {
+ if ( *chPtr < 0x20 ) {
+ if ( (*chPtr != kTab) && (*chPtr != kLF) && (*chPtr != kCR) ) *chPtr = 0x20;
+ } else if (*chPtr == 0x7F ) {
+ *chPtr = 0x20;
+ }
+ ++chPtr;
+ }
+ XMP_Assert ( (*chPtr == 0) || (*chPtr >= 0x80) );
+ if ( *chPtr != 0 ) (void) GetCodePoint ( (const XMP_Uns8 **) &chPtr ); // Throws for bad UTF-8.
+ }
+
+ if ( XMP_PropIsQualifier(node->options) && (node->name == "xml:lang") ) NormalizeLangValue ( &node->value );
+
+ #if 0 // *** XMP_DebugBuild
+ node->_valuePtr = node->value.c_str();
+ #endif
+
+} // SetNodeValue
+
+
+// -------------------------------------------------------------------------------------------------
+// SetNode
+// -------
+//
+// The internals for SetProperty and related calls, used after the node is found or created.
+
+static void
+SetNode ( XMP_Node * node, XMP_StringPtr value, XMP_OptionBits options )
+{
+ if ( options & kXMP_DeleteExisting ) {
+ XMP_ClearOption ( options, kXMP_DeleteExisting );
+ node->options = options;
+ node->value.erase();
+ node->RemoveChildren();
+ node->RemoveQualifiers();
+ }
+
+ node->options |= options; // Keep options set by FindNode when creating a new node.
+
+ if ( value != 0 ) {
+
+ // This is setting the value of a leaf node.
+ if ( node->options & kXMP_PropCompositeMask ) XMP_Throw ( "Composite nodes can't have values", kXMPErr_BadXPath );
+ XMP_Assert ( node->children.empty() );
+ SetNodeValue ( node, value );
+
+ } else {
+
+ // This is setting up an array or struct.
+ if ( ! node->value.empty() ) XMP_Throw ( "Composite nodes can't have values", kXMPErr_BadXPath );
+ if ( node->options & kXMP_PropCompositeMask ) { // Can't change an array to a struct, or vice versa.
+ if ( (options & kXMP_PropCompositeMask) != (node->options & kXMP_PropCompositeMask) ) {
+ XMP_Throw ( "Requested and existing composite form mismatch", kXMPErr_BadXPath );
+ }
+ }
+ node->RemoveChildren();
+
+ }
+
+} // SetNode
+
+
+// -------------------------------------------------------------------------------------------------
+// DoSetArrayItem
+// --------------
+
+static void
+DoSetArrayItem ( XMP_Node * arrayNode,
+ XMP_Index itemIndex,
+ XMP_StringPtr itemValue,
+ XMP_OptionBits options )
+{
+ XMP_OptionBits itemLoc = options & kXMP_PropArrayLocationMask;
+ XMP_Index arraySize = arrayNode->children.size();
+
+ options &= ~kXMP_PropArrayLocationMask;
+ options = VerifySetOptions ( options, itemValue );
+
+ // Now locate or create the item node and set the value. Note the index parameter is one-based!
+ // The index can be in the range [0..size+1] or "last", normalize it and check the insert flags.
+ // The order of the normalization checks is important. If the array is empty we end up with an
+ // index and location to set item size+1.
+
+ XMP_Node * itemNode = 0;
+
+ if ( itemIndex == kXMP_ArrayLastItem ) itemIndex = arraySize;
+ if ( (itemIndex == 0) && (itemLoc == kXMP_InsertAfterItem) ) {
+ itemIndex = 1;
+ itemLoc = kXMP_InsertBeforeItem;
+ }
+ if ( (itemIndex == arraySize) && (itemLoc == kXMP_InsertAfterItem) ) {
+ itemIndex += 1;
+ itemLoc = 0;
+ }
+ if ( (itemIndex == arraySize+1) && (itemLoc == kXMP_InsertBeforeItem) ) itemLoc = 0;
+
+ if ( itemIndex == arraySize+1 ) {
+
+ if ( itemLoc != 0 ) XMP_Throw ( "Can't insert before or after implicit new item", kXMPErr_BadIndex );
+ itemNode = new XMP_Node ( arrayNode, kXMP_ArrayItemName, 0 );
+ arrayNode->children.push_back ( itemNode );
+
+ } else {
+
+ if ( (itemIndex < 1) || (itemIndex > arraySize) ) XMP_Throw ( "Array index out of bounds", kXMPErr_BadIndex );
+ --itemIndex; // ! Convert the index to a C zero-based value!
+ if ( itemLoc == 0 ) {
+ itemNode = arrayNode->children[itemIndex];
+ } else {
+ XMP_NodePtrPos itemPos = arrayNode->children.begin() + itemIndex;
+ if ( itemLoc == kXMP_InsertAfterItem ) ++itemPos;
+ itemNode = new XMP_Node ( arrayNode, kXMP_ArrayItemName, 0 );
+ itemPos = arrayNode->children.insert ( itemPos, itemNode );
+ }
+
+ }
+
+ SetNode ( itemNode, itemValue, options );
+
+} // DoSetArrayItem
+
+
+// -------------------------------------------------------------------------------------------------
+// ChooseLocalizedText
+// -------------------
+//
+// 1. Look for an exact match with the specific language.
+// 2. If a generic language is given, look for partial matches.
+// 3. Look for an "x-default" item.
+// 4. Choose the first item.
+
+static XMP_CLTMatch
+ChooseLocalizedText ( const XMP_Node * arrayNode,
+ XMP_StringPtr genericLang,
+ XMP_StringPtr specificLang,
+ const XMP_Node * * itemNode )
+{
+ const XMP_Node * currItem = 0;
+ const size_t itemLim = arrayNode->children.size();
+ size_t itemNum;
+
+ // See if the array has the right form. Allow empty alt arrays, that is what parsing returns.
+ // *** Should check alt-text bit when that is reliably maintained.
+
+ if ( ! ( XMP_ArrayIsAltText(arrayNode->options) ||
+ (arrayNode->children.empty() && XMP_ArrayIsAlternate(arrayNode->options)) ) ) {
+ XMP_Throw ( "Localized text array is not alt-text", kXMPErr_BadXPath );
+ }
+ if ( arrayNode->children.empty() ) {
+ *itemNode = 0;
+ return kXMP_CLT_NoValues;
+ }
+
+ for ( itemNum = 0; itemNum < itemLim; ++itemNum ) {
+ currItem = arrayNode->children[itemNum];
+ if ( currItem->options & kXMP_PropCompositeMask ) {
+ XMP_Throw ( "Alt-text array item is not simple", kXMPErr_BadXPath );
+ }
+ if ( currItem->qualifiers.empty() || (currItem->qualifiers[0]->name != "xml:lang") ) {
+ XMP_Throw ( "Alt-text array item has no language qualifier", kXMPErr_BadXPath );
+ }
+ }
+
+ // Look for an exact match with the specific language.
+ for ( itemNum = 0; itemNum < itemLim; ++itemNum ) {
+ currItem = arrayNode->children[itemNum];
+ if ( currItem->qualifiers[0]->value == specificLang ) {
+ *itemNode = currItem;
+ return kXMP_CLT_SpecificMatch;
+ }
+ }
+
+ if ( *genericLang != 0 ) {
+
+ // Look for the first partial match with the generic language.
+ const size_t genericLen = strlen ( genericLang );
+ for ( itemNum = 0; itemNum < itemLim; ++itemNum ) {
+ currItem = arrayNode->children[itemNum];
+ XMP_StringPtr currLang = currItem->qualifiers[0]->value.c_str();
+ const size_t currLangSize = currItem->qualifiers[0]->value.size();
+ if ( (currLangSize >= genericLen) &&
+ XMP_LitNMatch ( currLang, genericLang, genericLen ) &&
+ ((currLangSize == genericLen) || (currLang[genericLen] == '-')) ) {
+ *itemNode = currItem;
+ break; // ! Don't return, need to look for other matches.
+ }
+ }
+
+ if ( itemNum < itemLim ) {
+
+ // Look for a second partial match with the generic language.
+ for ( ++itemNum; itemNum < itemLim; ++itemNum ) {
+ currItem = arrayNode->children[itemNum];
+ XMP_StringPtr currLang = currItem->qualifiers[0]->value.c_str();
+ const size_t currLangSize = currItem->qualifiers[0]->value.size();
+ if ( (currLangSize >= genericLen) &&
+ XMP_LitNMatch ( currLang, genericLang, genericLen ) &&
+ ((currLangSize == genericLen) || (currLang[genericLen] == '-')) ) {
+ return kXMP_CLT_MultipleGeneric; // ! Leave itemNode with the first partial match.
+ }
+ }
+ return kXMP_CLT_SingleGeneric; // No second partial match was found.
+
+ }
+
+ }
+
+ // Look for an 'x-default' item.
+ for ( itemNum = 0; itemNum < itemLim; ++itemNum ) {
+ currItem = arrayNode->children[itemNum];
+ if ( currItem->qualifiers[0]->value == "x-default" ) {
+ *itemNode = currItem;
+ return kXMP_CLT_XDefault;
+ }
+ }
+
+ // Everything failed, choose the first item.
+ *itemNode = arrayNode->children[0];
+ return kXMP_CLT_FirstItem;
+
+} // ChooseLocalizedText
+
+
+// -------------------------------------------------------------------------------------------------
+// AppendLangItem
+// --------------
+
+static void
+AppendLangItem ( XMP_Node * arrayNode, XMP_StringPtr itemLang, XMP_StringPtr itemValue )
+{
+ XMP_Node * newItem = new XMP_Node ( arrayNode, kXMP_ArrayItemName, itemValue, (kXMP_PropHasQualifiers | kXMP_PropHasLang) );
+ XMP_Node * langQual = new XMP_Node ( newItem, "xml:lang", itemLang, kXMP_PropIsQualifier );
+ newItem->qualifiers.push_back ( langQual );
+
+ if ( (arrayNode->children.empty()) || (langQual->value != "x-default") ) {
+ arrayNode->children.push_back ( newItem );
+ } else {
+ arrayNode->children.insert ( arrayNode->children.begin(), newItem );
+ }
+
+} // AppendLangItem
+
+
+// =================================================================================================
+// Class Methods
+// =============
+//
+//
+// =================================================================================================
+
+
+// -------------------------------------------------------------------------------------------------
+// GetProperty
+// -----------
+
+bool
+XMPMeta::GetProperty ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr * propValue,
+ XMP_StringLen * valueSize,
+ XMP_OptionBits * options ) const
+{
+ XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper.
+ XMP_Assert ( (propValue != 0) && (valueSize != 0) && (options != 0) ); // Enforced by wrapper.
+
+ XMP_ExpandedXPath expPath;
+ ExpandXPath ( schemaNS, propName, &expPath );
+
+ XMP_Node * propNode = FindConstNode ( &tree, expPath );
+ if ( propNode == 0 ) return false;
+
+ *propValue = propNode->value.c_str();
+ *valueSize = propNode->value.size();
+ *options = propNode->options;
+
+ return true;
+
+} // GetProperty
+
+
+// -------------------------------------------------------------------------------------------------
+// GetArrayItem
+// ------------
+
+bool
+XMPMeta::GetArrayItem ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex,
+ XMP_StringPtr * itemValue,
+ XMP_StringLen * valueSize,
+ XMP_OptionBits * options ) const
+{
+ XMP_Assert ( (schemaNS != 0) && (arrayName != 0) ); // Enforced by wrapper.
+ XMP_Assert ( (itemValue != 0) && (valueSize != 0) && (options != 0) ); // Enforced by wrapper.
+
+ XMP_StringPtr itemPath;
+ XMP_StringLen pathLen;
+
+ XMPUtils::ComposeArrayItemPath ( schemaNS, arrayName, itemIndex, &itemPath, &pathLen );
+ return GetProperty ( schemaNS, itemPath, itemValue, valueSize, options );
+
+} // GetArrayItem
+
+
+// -------------------------------------------------------------------------------------------------
+// GetStructField
+// --------------
+
+bool
+XMPMeta::GetStructField ( XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ XMP_StringPtr * fieldValue,
+ XMP_StringLen * valueSize,
+ XMP_OptionBits * options ) const
+{
+ XMP_Assert ( (schemaNS != 0) && (structName != 0) && (fieldNS != 0) && (fieldName != 0) ); // Enforced by wrapper.
+ XMP_Assert ( (fieldValue != 0) && (valueSize != 0) && (options != 0) ); // Enforced by wrapper.
+
+ XMP_StringPtr fieldPath;
+ XMP_StringLen pathLen;
+
+ XMPUtils::ComposeStructFieldPath ( schemaNS, structName, fieldNS, fieldName, &fieldPath, &pathLen );
+ return GetProperty ( schemaNS, fieldPath, fieldValue, valueSize, options );
+
+} // GetStructField
+
+
+// -------------------------------------------------------------------------------------------------
+// GetQualifier
+// ------------
+
+bool
+XMPMeta::GetQualifier ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName,
+ XMP_StringPtr * qualValue,
+ XMP_StringLen * valueSize,
+ XMP_OptionBits * options ) const
+{
+ XMP_Assert ( (schemaNS != 0) && (propName != 0) && (qualNS != 0) && (qualName != 0) ); // Enforced by wrapper.
+ XMP_Assert ( (qualValue != 0) && (valueSize != 0) && (options != 0) ); // Enforced by wrapper.
+
+ XMP_StringPtr qualPath;
+ XMP_StringLen pathLen;
+
+ XMPUtils::ComposeQualifierPath ( schemaNS, propName, qualNS, qualName, &qualPath, &pathLen );
+ return GetProperty ( schemaNS, qualPath, qualValue, valueSize, options );
+
+} // GetQualifier
+
+
+// -------------------------------------------------------------------------------------------------
+// SetProperty
+// -----------
+
+// *** Should handle array items specially, calling SetArrayItem.
+
+void
+XMPMeta::SetProperty ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr propValue,
+ XMP_OptionBits options )
+{
+ XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper.
+
+ options = VerifySetOptions ( options, propValue );
+
+ XMP_ExpandedXPath expPath;
+ ExpandXPath ( schemaNS, propName, &expPath );
+
+ XMP_Node * propNode = FindNode ( &tree, expPath, kXMP_CreateNodes, options );
+ if ( propNode == 0 ) XMP_Throw ( "Specified property does not exist", kXMPErr_BadXPath );
+
+ SetNode ( propNode, propValue, options );
+
+} // SetProperty
+
+
+// -------------------------------------------------------------------------------------------------
+// SetArrayItem
+// ------------
+
+void
+XMPMeta::SetArrayItem ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex,
+ XMP_StringPtr itemValue,
+ XMP_OptionBits options )
+{
+ XMP_Assert ( (schemaNS != 0) && (arrayName != 0) ); // Enforced by wrapper.
+
+ XMP_ExpandedXPath arrayPath;
+ ExpandXPath ( schemaNS, arrayName, &arrayPath );
+ XMP_Node * arrayNode = FindNode ( &tree, arrayPath, kXMP_ExistingOnly ); // Just lookup, don't try to create.
+ if ( arrayNode == 0 ) XMP_Throw ( "Specified array does not exist", kXMPErr_BadXPath );
+
+ DoSetArrayItem ( arrayNode, itemIndex, itemValue, options );
+
+} // SetArrayItem
+
+
+// -------------------------------------------------------------------------------------------------
+// AppendArrayItem
+// ---------------
+
+void
+XMPMeta::AppendArrayItem ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_OptionBits arrayOptions,
+ XMP_StringPtr itemValue,
+ XMP_OptionBits options )
+{
+ XMP_Assert ( (schemaNS != 0) && (arrayName != 0) ); // Enforced by wrapper.
+
+ arrayOptions = VerifySetOptions ( arrayOptions, 0 );
+ if ( (arrayOptions & ~kXMP_PropArrayFormMask) != 0 ) {
+ XMP_Throw ( "Only array form flags allowed for arrayOptions", kXMPErr_BadOptions );
+ }
+
+ // Locate or create the array. If it already exists, make sure the array form from the options
+ // parameter is compatible with the current state.
+
+ XMP_ExpandedXPath arrayPath;
+ ExpandXPath ( schemaNS, arrayName, &arrayPath );
+ XMP_Node * arrayNode = FindNode ( &tree, arrayPath, kXMP_ExistingOnly ); // Just lookup, don't try to create.
+
+ if ( arrayNode != 0 ) {
+ // The array exists, make sure the form is compatible. Zero arrayForm means take what exists.
+ if ( ! (arrayNode->options & kXMP_PropValueIsArray) ) {
+ XMP_Throw ( "The named property is not an array", kXMPErr_BadXPath );
+ }
+ #if 0
+ // *** Disable for now. Need to do some general rethinking of semantic checks.
+ if ( (arrayOptions != 0) && (arrayOptions != (arrayNode->options & kXMP_PropArrayFormMask)) ) {
+ XMP_Throw ( "Mismatch of existing and specified array form", kXMPErr_BadOptions );
+ }
+ #endif
+ } else {
+ // The array does not exist, try to create it.
+ if ( arrayOptions == 0 ) XMP_Throw ( "Explicit arrayOptions required to create new array", kXMPErr_BadOptions );
+ arrayNode = FindNode ( &tree, arrayPath, kXMP_CreateNodes, arrayOptions );
+ if ( arrayNode == 0 ) XMP_Throw ( "Failure creating array node", kXMPErr_BadXPath );
+ }
+
+ DoSetArrayItem ( arrayNode, kXMP_ArrayLastItem, itemValue, (options | kXMP_InsertAfterItem) );
+
+} // AppendArrayItem
+
+
+// -------------------------------------------------------------------------------------------------
+// SetStructField
+// --------------
+
+void
+XMPMeta::SetStructField ( XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ XMP_StringPtr fieldValue,
+ XMP_OptionBits options )
+{
+ XMP_Assert ( (schemaNS != 0) && (structName != 0) && (fieldNS != 0) && (fieldName != 0) ); // Enforced by wrapper.
+
+ XMP_StringPtr fieldPath;
+ XMP_StringLen pathLen;
+
+ XMPUtils::ComposeStructFieldPath ( schemaNS, structName, fieldNS, fieldName, &fieldPath, &pathLen );
+ SetProperty ( schemaNS, fieldPath, fieldValue, options );
+
+} // SetStructField
+
+
+// -------------------------------------------------------------------------------------------------
+// SetQualifier
+// ------------
+
+void
+XMPMeta::SetQualifier ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName,
+ XMP_StringPtr qualValue,
+ XMP_OptionBits options )
+{
+ XMP_Assert ( (schemaNS != 0) && (propName != 0) && (qualNS != 0) && (qualName != 0) ); // Enforced by wrapper.
+
+ XMP_StringPtr qualPath;
+ XMP_StringLen pathLen;
+
+ XMP_ExpandedXPath expPath;
+ ExpandXPath ( schemaNS, propName, &expPath );
+ XMP_Node * propNode = FindNode ( &tree, expPath, kXMP_ExistingOnly );
+ if ( propNode == 0 ) XMP_Throw ( "Specified property does not exist", kXMPErr_BadXPath );
+
+ XMPUtils::ComposeQualifierPath ( schemaNS, propName, qualNS, qualName, &qualPath, &pathLen );
+ SetProperty ( schemaNS, qualPath, qualValue, options );
+
+} // SetQualifier
+
+
+// -------------------------------------------------------------------------------------------------
+// DeleteProperty
+// --------------
+
+void
+XMPMeta::DeleteProperty ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName )
+{
+ XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper.
+
+ XMP_ExpandedXPath expPath;
+ ExpandXPath ( schemaNS, propName, &expPath );
+
+ XMP_NodePtrPos ptrPos;
+ XMP_Node * propNode = FindNode ( &tree, expPath, kXMP_ExistingOnly, kXMP_NoOptions, &ptrPos );
+ if ( propNode == 0 ) return;
+ XMP_Node * parentNode = propNode->parent;
+
+ // Erase the pointer from the parent's vector, then delete the node and all below it.
+
+ if ( ! (propNode->options & kXMP_PropIsQualifier) ) {
+
+ parentNode->children.erase ( ptrPos );
+ DeleteEmptySchema ( parentNode );
+
+ } else {
+
+ if ( propNode->name == "xml:lang" ) {
+ XMP_Assert ( parentNode->options & kXMP_PropHasLang ); // *** &= ~flag would be safer
+ parentNode->options ^= kXMP_PropHasLang;
+ } else if ( propNode->name == "rdf:type" ) {
+ XMP_Assert ( parentNode->options & kXMP_PropHasType );
+ parentNode->options ^= kXMP_PropHasType;
+ }
+
+ parentNode->qualifiers.erase ( ptrPos );
+ XMP_Assert ( parentNode->options & kXMP_PropHasQualifiers );
+ if ( parentNode->qualifiers.empty() ) parentNode->options ^= kXMP_PropHasQualifiers;
+
+ }
+
+ delete propNode; // ! The destructor takes care of the whole subtree.
+
+} // DeleteProperty
+
+
+// -------------------------------------------------------------------------------------------------
+// DeleteArrayItem
+// ---------------
+
+void
+XMPMeta::DeleteArrayItem ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex )
+{
+ XMP_Assert ( (schemaNS != 0) && (arrayName != 0) ); // Enforced by wrapper.
+
+ XMP_StringPtr itemPath;
+ XMP_StringLen pathLen;
+
+ XMPUtils::ComposeArrayItemPath ( schemaNS, arrayName, itemIndex, &itemPath, &pathLen );
+ DeleteProperty ( schemaNS, itemPath );
+
+} // DeleteArrayItem
+
+
+// -------------------------------------------------------------------------------------------------
+// DeleteStructField
+// -----------------
+
+void
+XMPMeta::DeleteStructField ( XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName )
+{
+ XMP_Assert ( (schemaNS != 0) && (structName != 0) && (fieldNS != 0) && (fieldName != 0) ); // Enforced by wrapper.
+
+ XMP_StringPtr fieldPath;
+ XMP_StringLen pathLen;
+
+ XMPUtils::ComposeStructFieldPath ( schemaNS, structName, fieldNS, fieldName, &fieldPath, &pathLen );
+ DeleteProperty ( schemaNS, fieldPath );
+
+} // DeleteStructField
+
+
+// -------------------------------------------------------------------------------------------------
+// DeleteQualifier
+// ---------------
+
+void
+XMPMeta::DeleteQualifier ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName )
+{
+ XMP_Assert ( (schemaNS != 0) && (propName != 0) && (qualNS != 0) && (qualName != 0) ); // Enforced by wrapper.
+
+ XMP_StringPtr qualPath;
+ XMP_StringLen pathLen;
+
+ XMPUtils::ComposeQualifierPath ( schemaNS, propName, qualNS, qualName, &qualPath, &pathLen );
+ DeleteProperty ( schemaNS, qualPath );
+
+} // DeleteQualifier
+
+
+// -------------------------------------------------------------------------------------------------
+// DoesPropertyExist
+// -----------------
+
+bool
+XMPMeta::DoesPropertyExist ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName ) const
+{
+ XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper.
+
+ XMP_ExpandedXPath expPath;
+ ExpandXPath ( schemaNS, propName, &expPath );
+
+ XMP_Node * propNode = FindConstNode ( &tree, expPath );
+ return (propNode != 0);
+
+} // DoesPropertyExist
+
+
+// -------------------------------------------------------------------------------------------------
+// DoesArrayItemExist
+// ------------------
+
+bool
+XMPMeta::DoesArrayItemExist ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex ) const
+{
+ XMP_Assert ( (schemaNS != 0) && (arrayName != 0) ); // Enforced by wrapper.
+
+ XMP_StringPtr itemPath;
+ XMP_StringLen pathLen;
+
+ XMPUtils::ComposeArrayItemPath ( schemaNS, arrayName, itemIndex, &itemPath, &pathLen );
+ return DoesPropertyExist ( schemaNS, itemPath );
+
+} // DoesArrayItemExist
+
+
+// -------------------------------------------------------------------------------------------------
+// DoesStructFieldExist
+// --------------------
+
+bool
+XMPMeta::DoesStructFieldExist ( XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName ) const
+{
+ XMP_Assert ( (schemaNS != 0) && (structName != 0) && (fieldNS != 0) && (fieldName != 0) ); // Enforced by wrapper.
+
+ XMP_StringPtr fieldPath;
+ XMP_StringLen pathLen;
+
+ XMPUtils::ComposeStructFieldPath ( schemaNS, structName, fieldNS, fieldName, &fieldPath, &pathLen );
+ return DoesPropertyExist ( schemaNS, fieldPath );
+
+} // DoesStructFieldExist
+
+
+// -------------------------------------------------------------------------------------------------
+// DoesQualifierExist
+// ------------------
+
+bool
+XMPMeta::DoesQualifierExist ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName ) const
+{
+ XMP_Assert ( (schemaNS != 0) && (propName != 0) && (qualNS != 0) && (qualName != 0) ); // Enforced by wrapper.
+
+ XMP_StringPtr qualPath;
+ XMP_StringLen pathLen;
+
+ XMPUtils::ComposeQualifierPath ( schemaNS, propName, qualNS, qualName, &qualPath, &pathLen );
+ return DoesPropertyExist ( schemaNS, qualPath );
+
+} // DoesQualifierExist
+
+
+// -------------------------------------------------------------------------------------------------
+// GetLocalizedText
+// ----------------
+
+bool
+XMPMeta::GetLocalizedText ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_StringPtr _genericLang,
+ XMP_StringPtr _specificLang,
+ XMP_StringPtr * actualLang,
+ XMP_StringLen * langSize,
+ XMP_StringPtr * itemValue,
+ XMP_StringLen * valueSize,
+ XMP_OptionBits * options ) const
+{
+ XMP_Assert ( (schemaNS != 0) && (arrayName != 0) && (_genericLang != 0) && (_specificLang != 0) ); // Enforced by wrapper.
+ XMP_Assert ( (actualLang != 0) && (langSize != 0) ); // Enforced by wrapper.
+ XMP_Assert ( (itemValue != 0) && (valueSize != 0) && (options != 0) ); // Enforced by wrapper.
+
+ XMP_VarString zGenericLang ( _genericLang );
+ XMP_VarString zSpecificLang ( _specificLang );
+ NormalizeLangValue ( &zGenericLang );
+ NormalizeLangValue ( &zSpecificLang );
+
+ XMP_StringPtr genericLang = zGenericLang.c_str();
+ XMP_StringPtr specificLang = zSpecificLang.c_str();
+
+ XMP_ExpandedXPath arrayPath;
+ ExpandXPath ( schemaNS, arrayName, &arrayPath );
+
+ const XMP_Node * arrayNode = FindConstNode ( &tree, arrayPath ); // *** This expand/find idiom is used in 3 Getters.
+ if ( arrayNode == 0 ) return false; // *** Should extract it into a local utility.
+
+ XMP_CLTMatch match;
+ const XMP_Node * itemNode;
+
+ match = ChooseLocalizedText ( arrayNode, genericLang, specificLang, &itemNode );
+ if ( match == kXMP_CLT_NoValues ) return false;
+
+ *actualLang = itemNode->qualifiers[0]->value.c_str();
+ *langSize = itemNode->qualifiers[0]->value.size();
+ *itemValue = itemNode->value.c_str();
+ *valueSize = itemNode->value.size();
+ *options = itemNode->options;
+
+ return true;
+
+} // GetLocalizedText
+
+
+// -------------------------------------------------------------------------------------------------
+// SetLocalizedText
+// ----------------
+
+void
+XMPMeta::SetLocalizedText ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_StringPtr _genericLang,
+ XMP_StringPtr _specificLang,
+ XMP_StringPtr itemValue,
+ XMP_OptionBits options )
+{
+ options = options; // Avoid unused parameter warning.
+
+ XMP_Assert ( (schemaNS != 0) && (arrayName != 0) && (_genericLang != 0) && (_specificLang != 0) ); // Enforced by wrapper.
+
+ XMP_VarString zGenericLang ( _genericLang );
+ XMP_VarString zSpecificLang ( _specificLang );
+ NormalizeLangValue ( &zGenericLang );
+ NormalizeLangValue ( &zSpecificLang );
+
+ XMP_StringPtr genericLang = zGenericLang.c_str();
+ XMP_StringPtr specificLang = zSpecificLang.c_str();
+
+ XMP_ExpandedXPath arrayPath;
+ ExpandXPath ( schemaNS, arrayName, &arrayPath );
+
+ // Find the array node and set the options if it was just created.
+ XMP_Node * arrayNode = FindNode ( &tree, arrayPath, kXMP_CreateNodes,
+ (kXMP_PropValueIsArray | kXMP_PropArrayIsOrdered | kXMP_PropArrayIsAlternate) );
+ if ( arrayNode == 0 ) XMP_Throw ( "Failed to find or create array node", kXMPErr_BadXPath );
+ if ( ! XMP_ArrayIsAltText(arrayNode->options) ) {
+ if ( arrayNode->children.empty() && XMP_ArrayIsAlternate(arrayNode->options) ) {
+ arrayNode->options |= kXMP_PropArrayIsAltText;
+ } else {
+ XMP_Throw ( "Localized text array is not alt-text", kXMPErr_BadXPath );
+ }
+ }
+
+ // Make sure the x-default item, if any, is first.
+
+ size_t itemNum, itemLim;
+ XMP_Node * xdItem = 0;
+ bool haveXDefault = false;
+
+ for ( itemNum = 0, itemLim = arrayNode->children.size(); itemNum < itemLim; ++itemNum ) {
+ XMP_Node * currItem = arrayNode->children[itemNum];
+ XMP_Assert ( XMP_PropHasLang(currItem->options) );
+ if ( currItem->qualifiers.empty() || (currItem->qualifiers[0]->name != "xml:lang") ) {
+ XMP_Throw ( "Language qualifier must be first", kXMPErr_BadXPath );
+ }
+ if ( currItem->qualifiers[0]->value == "x-default" ) {
+ xdItem = currItem;
+ haveXDefault = true;
+ break;
+ }
+ }
+
+ if ( haveXDefault && (itemNum != 0) ) {
+ XMP_Assert ( arrayNode->children[itemNum]->qualifiers[0]->value == "x-default" );
+ XMP_Node * temp = arrayNode->children[0];
+ arrayNode->children[0] = arrayNode->children[itemNum];
+ arrayNode->children[itemNum] = temp;
+ }
+
+ // Find the appropriate item. ChooseLocalizedText will make sure the array is a language alternative.
+
+ const XMP_Node * cItemNode; // ! ChooseLocalizedText returns a pointer to a const node.
+ XMP_CLTMatch match = ChooseLocalizedText ( arrayNode, genericLang, specificLang, &cItemNode );
+ XMP_Node * itemNode = const_cast<XMP_Node*> ( cItemNode );
+
+ const bool specificXDefault = XMP_LitMatch ( specificLang, "x-default" );
+
+ switch ( match ) {
+
+ case kXMP_CLT_NoValues :
+
+ // Create the array items for the specificLang and x-default, with x-default first.
+ AppendLangItem ( arrayNode, "x-default", itemValue );
+ haveXDefault = true;
+ if ( ! specificXDefault ) AppendLangItem ( arrayNode, specificLang, itemValue );
+ break;
+
+ case kXMP_CLT_SpecificMatch :
+
+ if ( ! specificXDefault ) {
+ // Update the specific item, update x-default if it matches the old value.
+ if ( haveXDefault && (xdItem != itemNode) && (xdItem->value == itemNode->value) ) {
+ SetNodeValue ( xdItem, itemValue );
+ }
+ SetNodeValue ( itemNode, itemValue ); // ! Do this after the x-default check!
+ } else {
+ // Update all items whose values match the old x-default value.
+ XMP_Assert ( haveXDefault && (xdItem == itemNode) );
+ for ( itemNum = 0, itemLim = arrayNode->children.size(); itemNum < itemLim; ++itemNum ) {
+ XMP_Node * currItem = arrayNode->children[itemNum];
+ if ( (currItem == xdItem) || (currItem->value != xdItem->value) ) continue;
+ SetNodeValue ( currItem, itemValue );
+ }
+ SetNodeValue ( xdItem, itemValue ); // And finally do the x-default item.
+ }
+ break;
+
+ case kXMP_CLT_SingleGeneric :
+
+ // Update the generic item, update x-default if it matches the old value.
+ if ( haveXDefault && (xdItem != itemNode) && (xdItem->value == itemNode->value) ) {
+ SetNodeValue ( xdItem, itemValue );
+ }
+ SetNodeValue ( itemNode, itemValue ); // ! Do this after the x-default check!
+ break;
+
+ case kXMP_CLT_MultipleGeneric :
+
+ // Create the specific language, ignore x-default.
+ AppendLangItem ( arrayNode, specificLang, itemValue );
+ if ( specificXDefault ) haveXDefault = true;
+ break;
+
+ case kXMP_CLT_XDefault :
+
+ // Create the specific language, update x-default if it was the only item.
+ if ( arrayNode->children.size() == 1 ) SetNodeValue ( xdItem, itemValue );
+ AppendLangItem ( arrayNode, specificLang, itemValue );
+ break;
+
+ case kXMP_CLT_FirstItem :
+
+ // Create the specific language, don't add an x-default item.
+ AppendLangItem ( arrayNode, specificLang, itemValue );
+ if ( specificXDefault ) haveXDefault = true;
+ break;
+
+ default :
+ XMP_Throw ( "Unexpected result from ChooseLocalizedText", kXMPErr_InternalFailure );
+
+ }
+
+ // Add an x-default at the front if needed.
+ if ( (! haveXDefault) && (arrayNode->children.size() == 1) ) {
+ AppendLangItem ( arrayNode, "x-default", itemValue );
+ }
+
+} // SetLocalizedText
+
+
+// -------------------------------------------------------------------------------------------------
+// GetProperty_Bool
+// ----------------
+
+bool
+XMPMeta::GetProperty_Bool ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ bool * propValue,
+ XMP_OptionBits * options ) const
+{
+ XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper.
+ XMP_Assert ( (propValue != 0) && (options != 0) ); // Enforced by wrapper.
+
+ XMP_StringPtr valueStr;
+ XMP_StringLen valueLen;
+
+ bool found = GetProperty ( schemaNS, propName, &valueStr, &valueLen, options );
+ if ( found ) {
+ if ( ! XMP_PropIsSimple ( *options ) ) XMP_Throw ( "Property must be simple", kXMPErr_BadXPath );
+ *propValue = XMPUtils::ConvertToBool ( valueStr );
+ }
+ return found;
+
+} // GetProperty_Bool
+
+
+// -------------------------------------------------------------------------------------------------
+// GetProperty_Int
+// ---------------
+
+bool
+XMPMeta::GetProperty_Int ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_Int32 * propValue,
+ XMP_OptionBits * options ) const
+{
+ XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper.
+ XMP_Assert ( (propValue != 0) && (options != 0) ); // Enforced by wrapper.
+
+ XMP_StringPtr valueStr;
+ XMP_StringLen valueLen;
+
+ bool found = GetProperty ( schemaNS, propName, &valueStr, &valueLen, options );
+ if ( found ) {
+ if ( ! XMP_PropIsSimple ( *options ) ) XMP_Throw ( "Property must be simple", kXMPErr_BadXPath );
+ *propValue = XMPUtils::ConvertToInt ( valueStr );
+ }
+ return found;
+
+} // GetProperty_Int
+
+
+// -------------------------------------------------------------------------------------------------
+// GetProperty_Int64
+// -----------------
+
+bool
+XMPMeta::GetProperty_Int64 ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_Int64 * propValue,
+ XMP_OptionBits * options ) const
+{
+ XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper.
+ XMP_Assert ( (propValue != 0) && (options != 0) ); // Enforced by wrapper.
+
+ XMP_StringPtr valueStr;
+ XMP_StringLen valueLen;
+
+ bool found = GetProperty ( schemaNS, propName, &valueStr, &valueLen, options );
+ if ( found ) {
+ if ( ! XMP_PropIsSimple ( *options ) ) XMP_Throw ( "Property must be simple", kXMPErr_BadXPath );
+ *propValue = XMPUtils::ConvertToInt64 ( valueStr );
+ }
+ return found;
+
+} // GetProperty_Int64
+
+
+// -------------------------------------------------------------------------------------------------
+// GetProperty_Float
+// -----------------
+
+bool
+XMPMeta::GetProperty_Float ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ double * propValue,
+ XMP_OptionBits * options ) const
+{
+ XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper.
+ XMP_Assert ( (propValue != 0) && (options != 0) ); // Enforced by wrapper.
+
+ XMP_StringPtr valueStr;
+ XMP_StringLen valueLen;
+
+ bool found = GetProperty ( schemaNS, propName, &valueStr, &valueLen, options );
+ if ( found ) {
+ if ( ! XMP_PropIsSimple ( *options ) ) XMP_Throw ( "Property must be simple", kXMPErr_BadXPath );
+ *propValue = XMPUtils::ConvertToFloat ( valueStr );
+ }
+ return found;
+
+} // GetProperty_Float
+
+
+// -------------------------------------------------------------------------------------------------
+// GetProperty_Date
+// ----------------
+
+bool
+XMPMeta::GetProperty_Date ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_DateTime * propValue,
+ XMP_OptionBits * options ) const
+{
+ XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper.
+ XMP_Assert ( (propValue != 0) && (options != 0) ); // Enforced by wrapper.
+
+ XMP_StringPtr valueStr;
+ XMP_StringLen valueLen;
+
+ bool found = GetProperty ( schemaNS, propName, &valueStr, &valueLen, options );
+ if ( found ) {
+ if ( ! XMP_PropIsSimple ( *options ) ) XMP_Throw ( "Property must be simple", kXMPErr_BadXPath );
+ XMPUtils::ConvertToDate ( valueStr, propValue );
+ }
+ return found;
+
+} // GetProperty_Date
+
+
+// -------------------------------------------------------------------------------------------------
+// SetProperty_Bool
+// ----------------
+
+void
+XMPMeta::SetProperty_Bool ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ bool propValue,
+ XMP_OptionBits options )
+{
+ XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper.
+
+ XMP_StringPtr valueStr;
+ XMP_StringLen valueLen;
+
+ XMPUtils::ConvertFromBool ( propValue, &valueStr, &valueLen );
+ SetProperty ( schemaNS, propName, valueStr, options );
+
+} // SetProperty_Bool
+
+
+// -------------------------------------------------------------------------------------------------
+// SetProperty_Int
+// ---------------
+
+void
+XMPMeta::SetProperty_Int ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_Int32 propValue,
+ XMP_OptionBits options )
+{
+ XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper.
+
+ XMP_StringPtr valueStr;
+ XMP_StringLen valueLen;
+
+ XMPUtils::ConvertFromInt ( propValue, "", &valueStr, &valueLen );
+ SetProperty ( schemaNS, propName, valueStr, options );
+
+} // SetProperty_Int
+
+
+// -------------------------------------------------------------------------------------------------
+// SetProperty_Int64
+// -----------------
+
+void
+XMPMeta::SetProperty_Int64 ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_Int64 propValue,
+ XMP_OptionBits options )
+{
+ XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper.
+
+ XMP_StringPtr valueStr;
+ XMP_StringLen valueLen;
+
+ XMPUtils::ConvertFromInt64 ( propValue, "", &valueStr, &valueLen );
+ SetProperty ( schemaNS, propName, valueStr, options );
+
+} // SetProperty_Int64
+
+
+// -------------------------------------------------------------------------------------------------
+// SetProperty_Float
+// -----------------
+
+void
+XMPMeta::SetProperty_Float ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ double propValue,
+ XMP_OptionBits options )
+{
+ XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper.
+
+ XMP_StringPtr valueStr;
+ XMP_StringLen valueLen;
+
+ XMPUtils::ConvertFromFloat ( propValue, "", &valueStr, &valueLen );
+ SetProperty ( schemaNS, propName, valueStr, options );
+
+} // SetProperty_Float
+
+
+// -------------------------------------------------------------------------------------------------
+// SetProperty_Date
+// ----------------
+
+void
+XMPMeta::SetProperty_Date ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ const XMP_DateTime & propValue,
+ XMP_OptionBits options )
+{
+ XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper.
+
+ XMP_StringPtr valueStr;
+ XMP_StringLen valueLen;
+
+ XMPUtils::ConvertFromDate ( propValue, &valueStr, &valueLen );
+ SetProperty ( schemaNS, propName, valueStr, options );
+
+} // SetProperty_Date
+
+// =================================================================================================
diff --git a/source/XMPCore/XMPMeta-Parse.cpp b/source/XMPCore/XMPMeta-Parse.cpp
new file mode 100644
index 0000000..9861286
--- /dev/null
+++ b/source/XMPCore/XMPMeta-Parse.cpp
@@ -0,0 +1,1290 @@
+// =================================================================================================
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+//
+// Adobe patent application tracking #P435, entitled 'Unique markers to simplify embedding data of
+// one format in a file with a different format', inventors: Sean Parent, Greg Gilley.
+// =================================================================================================
+
+#include "XMP_Environment.h" // ! This must be the first include!
+#include "XMPCore_Impl.hpp"
+
+#include "XMPMeta.hpp"
+#include "XMPUtils.hpp"
+
+#include "UnicodeInlines.incl_cpp"
+#include "UnicodeConversions.hpp"
+#include "ExpatAdapter.hpp"
+
+#if XMP_DebugBuild
+ #include <iostream>
+#endif
+
+using namespace std;
+
+#if XMP_WinBuild
+ #pragma warning ( disable : 4533 ) // initialization of '...' is skipped by 'goto ...'
+ #pragma warning ( disable : 4702 ) // unreachable code
+ #pragma warning ( disable : 4800 ) // forcing value to bool 'true' or 'false' (performance warning)
+ #pragma warning ( disable : 4996 ) // '...' was declared deprecated
+#endif
+
+
+// *** Use the XMP_PropIsXyz (Schema, Simple, Struct, Array, ...) macros
+// *** Add debug codegen checks, e.g. that typical masking operations really work
+// *** Change all uses of strcmp and strncmp to XMP_LitMatch and XMP_LitNMatch
+
+
+// =================================================================================================
+// Local Types and Constants
+// =========================
+
+
+// =================================================================================================
+// Static Variables
+// ================
+
+#ifndef Trace_ParsingHackery
+ #define Trace_ParsingHackery 0
+#endif
+
+static const char * kReplaceLatin1[128] =
+ {
+
+ // The 0x80..0x9F range is undefined in Latin-1, but is defined in Windows code page 1252.
+ // The bytes 0x81, 0x8D, 0x8F, 0x90, and 0x9D are formally undefined by Windows 1252, but
+ // their conversion API maps them to U+0081, etc. These are in XML's RestrictedChar set, so
+ // we map them to a space.
+
+ "\xE2\x82\xAC", " ", "\xE2\x80\x9A", "\xC6\x92", // 0x80 .. 0x83
+ "\xE2\x80\x9E", "\xE2\x80\xA6", "\xE2\x80\xA0", "\xE2\x80\xA1", // 0x84 .. 0x87
+ "\xCB\x86", "\xE2\x80\xB0", "\xC5\xA0", "\xE2\x80\xB9", // 0x88 .. 0x8B
+ "\xC5\x92", " ", "\xC5\xBD", " ", // 0x8C .. 0x8F
+
+ " ", "\xE2\x80\x98", "\xE2\x80\x99", "\xE2\x80\x9C", // 0x90 .. 0x93
+ "\xE2\x80\x9D", "\xE2\x80\xA2", "\xE2\x80\x93", "\xE2\x80\x94", // 0x94 .. 0x97
+ "\xCB\x9C", "\xE2\x84\xA2", "\xC5\xA1", "\xE2\x80\xBA", // 0x98 .. 0x9B
+ "\xC5\x93", " ", "\xC5\xBE", "\xC5\xB8", // 0x9C .. 0x9F
+
+ // These are the UTF-8 forms of the official Latin-1 characters in the range 0xA0..0xFF. Not
+ // too surprisingly these map to U+00A0, etc. Which is the Unicode Latin Supplement range.
+
+ "\xC2\xA0", "\xC2\xA1", "\xC2\xA2", "\xC2\xA3", "\xC2\xA4", "\xC2\xA5", "\xC2\xA6", "\xC2\xA7", // 0xA0 .. 0xA7
+ "\xC2\xA8", "\xC2\xA9", "\xC2\xAA", "\xC2\xAB", "\xC2\xAC", "\xC2\xAD", "\xC2\xAE", "\xC2\xAF", // 0xA8 .. 0xAF
+
+ "\xC2\xB0", "\xC2\xB1", "\xC2\xB2", "\xC2\xB3", "\xC2\xB4", "\xC2\xB5", "\xC2\xB6", "\xC2\xB7", // 0xB0 .. 0xB7
+ "\xC2\xB8", "\xC2\xB9", "\xC2\xBA", "\xC2\xBB", "\xC2\xBC", "\xC2\xBD", "\xC2\xBE", "\xC2\xBF", // 0xB8 .. 0xBF
+
+ "\xC3\x80", "\xC3\x81", "\xC3\x82", "\xC3\x83", "\xC3\x84", "\xC3\x85", "\xC3\x86", "\xC3\x87", // 0xC0 .. 0xC7
+ "\xC3\x88", "\xC3\x89", "\xC3\x8A", "\xC3\x8B", "\xC3\x8C", "\xC3\x8D", "\xC3\x8E", "\xC3\x8F", // 0xC8 .. 0xCF
+
+ "\xC3\x90", "\xC3\x91", "\xC3\x92", "\xC3\x93", "\xC3\x94", "\xC3\x95", "\xC3\x96", "\xC3\x97", // 0xD0 .. 0xD7
+ "\xC3\x98", "\xC3\x99", "\xC3\x9A", "\xC3\x9B", "\xC3\x9C", "\xC3\x9D", "\xC3\x9E", "\xC3\x9F", // 0xD8 .. 0xDF
+
+ "\xC3\xA0", "\xC3\xA1", "\xC3\xA2", "\xC3\xA3", "\xC3\xA4", "\xC3\xA5", "\xC3\xA6", "\xC3\xA7", // 0xE0 .. 0xE7
+ "\xC3\xA8", "\xC3\xA9", "\xC3\xAA", "\xC3\xAB", "\xC3\xAC", "\xC3\xAD", "\xC3\xAE", "\xC3\xAF", // 0xE8 .. 0xEF
+
+ "\xC3\xB0", "\xC3\xB1", "\xC3\xB2", "\xC3\xB3", "\xC3\xB4", "\xC3\xB5", "\xC3\xB6", "\xC3\xB7", // 0xF0 .. 0xF7
+ "\xC3\xB8", "\xC3\xB9", "\xC3\xBA", "\xC3\xBB", "\xC3\xBC", "\xC3\xBD", "\xC3\xBE", "\xC3\xBF", // 0xF8 .. 0xFF
+
+ };
+
+
+// =================================================================================================
+// Local Utilities
+// ===============
+
+
+#define IsHexDigit(ch) ( (('0' <= (ch)) && ((ch) <= '9')) || (('A' <= (ch)) && ((ch) <= 'F')) )
+#define HexDigitValue(ch) ( (((ch) - '0') < 10) ? ((ch) - '0') : ((ch) - 'A' + 10) )
+
+
+// -------------------------------------------------------------------------------------------------
+// PickBestRoot
+// ------------
+//
+// Pick the first pxmp:XMP_Packet or x:xmpmeta among multiple root candidates. If there aren't any,
+// pick the first bare rdf:RDF if that is allowed. The returned root is the rdf:RDF child if an
+// x:xmpmeta element was chosen. The search is breadth first, so a higher level candiate is chosen
+// over a lower level one that was textually earlier in the serialized XML.
+
+static const XML_Node * PickBestRoot ( const XML_Node & xmlParent, XMP_OptionBits options )
+{
+ // Look among this parent's content for pxmp:XMP_Packet or x:xmpmeta. The recursion for
+ // x:xmpmeta is broader than the strictly defined choice, but gives us smaller code.
+ for ( size_t childNum = 0, childLim = xmlParent.content.size(); childNum < childLim; ++childNum ) {
+ const XML_Node * childNode = xmlParent.content[childNum];
+ if ( childNode->kind != kElemNode ) continue;
+ if ( childNode->name == "pxmp:XMP_Packet" ) return childNode;
+ if ( (childNode->name == "x:xmpmeta") || (childNode->name == "x:xapmeta") ) return PickBestRoot ( *childNode, 0 );
+ }
+
+ // Look among this parent's content for a bare rdf:RDF if that is allowed.
+ if ( ! (options & kXMP_RequireXMPMeta) ) {
+ for ( size_t childNum = 0, childLim = xmlParent.content.size(); childNum < childLim; ++childNum ) {
+ const XML_Node * childNode = xmlParent.content[childNum];
+ if ( childNode->kind != kElemNode ) continue;
+ if ( childNode->name == "rdf:RDF" ) return childNode;
+ }
+ }
+
+ // Recurse into the content.
+ for ( size_t childNum = 0, childLim = xmlParent.content.size(); childNum < childLim; ++childNum ) {
+ const XML_Node * foundRoot = PickBestRoot ( *xmlParent.content[childNum], options );
+ if ( foundRoot != 0 ) return foundRoot;
+ }
+
+ return 0;
+
+} // PickBestRoot
+
+// -------------------------------------------------------------------------------------------------
+// FindRootNode
+// ------------
+//
+// Find the XML node that is the root of the XMP data tree. Generally this will be an outer node,
+// but it could be anywhere if a general XML document is parsed (e.g. SVG). The XML parser counted
+// all rdf:RDF and pxmp:XMP_Packet nodes, and kept a pointer to the last one. If there is more than
+// one possible root use PickBestRoot to choose among them.
+//
+// If there is a root node, try to extract the version of the previous XMP toolkit.
+
+static const XML_Node * FindRootNode ( XMPMeta * thiz, const XMLParserAdapter & xmlParser, XMP_OptionBits options )
+{
+ const XML_Node * rootNode = xmlParser.rootNode;
+
+ if ( xmlParser.rootCount > 1 ) rootNode = PickBestRoot ( xmlParser.tree, options );
+ if ( rootNode == 0 ) return 0;
+
+ // We have a root node. Try to extract previous toolkit version number.
+
+ XMP_StringPtr verStr = "";
+
+ if ( rootNode->name == "pxmp:XMP_Packet" ) {
+
+ for ( size_t attrNum = 0, attrLim = rootNode->attrs.size(); attrNum < attrLim; ++attrNum ) {
+ const XML_Node * currAttr =rootNode->attrs[attrNum];
+ if ( currAttr->name == "pxmp:xmptk" ) {
+ verStr = currAttr->value.c_str();
+ break;
+ }
+ }
+
+ } else {
+
+ XMP_Assert ( rootNode->name == "rdf:RDF" );
+
+ if ( (options & kXMP_RequireXMPMeta) &&
+ ((rootNode->parent == 0) ||
+ ((rootNode->parent->name != "x:xmpmeta") && (rootNode->parent->name != "x:xapmeta"))) ) return 0;
+
+ for ( size_t attrNum = 0, attrLim = rootNode->parent->attrs.size(); attrNum < attrLim; ++attrNum ) {
+ const XML_Node * currAttr =rootNode->parent->attrs[attrNum];
+ if ( (currAttr->name == "x:xmptk") || (currAttr->name == "x:xaptk") ) {
+ verStr = currAttr->value.c_str();
+ break;
+ }
+ }
+
+ }
+
+ // Decode the version number into MMmmuubbb digits. If any part is too big, peg it at 99 or 999.
+
+ unsigned long part;
+ while ( (*verStr != 0) && ((*verStr < '0') || (*verStr > '9')) ) ++verStr;
+
+ part = 0;
+ while ( (*verStr != 0) && ('0' <= *verStr) && (*verStr <= '9') ) {
+ part = (part * 10) + (*verStr - '0');
+ ++verStr;
+ }
+ if ( part > 99 ) part = 99;
+ thiz->prevTkVer = part * 100*100*1000;
+
+ part = 0;
+ if ( *verStr == '.' ) ++verStr;
+ while ( (*verStr != 0) && ('0' <= *verStr) && (*verStr <= '9') ) {
+ part = (part * 10) + (*verStr - '0');
+ ++verStr;
+ }
+ if ( part > 99 ) part = 99;
+ thiz->prevTkVer += part * 100*1000;
+
+ part = 0;
+ if ( *verStr == '.' ) ++verStr;
+ while ( (*verStr != 0) && ('0' <= *verStr) && (*verStr <= '9') ) {
+ part = (part * 10) + (*verStr - '0');
+ ++verStr;
+ }
+ if ( part > 99 ) part = 99;
+ thiz->prevTkVer += part * 1000;
+
+ part = 0;
+ if ( *verStr == '-' ) ++verStr;
+ while ( (*verStr != 0) && ('0' <= *verStr) && (*verStr <= '9') ) {
+ part = (part * 10) + (*verStr - '0');
+ ++verStr;
+ }
+ if ( part > 999 ) part = 999;
+ thiz->prevTkVer += part;
+
+ return rootNode;
+
+} // FindRootNode
+
+// -------------------------------------------------------------------------------------------------
+// NormalizeDCArrays
+// -----------------
+//
+// Undo the denormalization performed by the XMP used in Acrobat 5. If a Dublin Core array had only
+// one item, it was serialized as a simple property. The xml:lang attribute was dropped from an
+// alt-text item if the language was x-default.
+
+// *** This depends on the dc: namespace prefix.
+
+static void
+NormalizeDCArrays ( XMP_Node * xmpTree )
+{
+ XMP_Node * dcSchema = FindSchemaNode ( xmpTree, kXMP_NS_DC, kXMP_ExistingOnly );
+ if ( dcSchema == 0 ) return;
+
+ for ( size_t propNum = 0, propLimit = dcSchema->children.size(); propNum < propLimit; ++propNum ) {
+ XMP_Node * currProp = dcSchema->children[propNum];
+ XMP_OptionBits arrayForm = 0;
+
+ if ( ! XMP_PropIsSimple ( currProp->options ) ) continue; // Nothing to do if not simple.
+
+ if ( (currProp->name == "dc:creator" ) || // See if it is supposed to be an array.
+ (currProp->name == "dc:date" ) ) { // *** Think about an array of char* and a loop.
+ arrayForm = kXMP_PropArrayIsOrdered;
+ } else if (
+ (currProp->name == "dc:description" ) ||
+ (currProp->name == "dc:rights" ) ||
+ (currProp->name == "dc:title" ) ) {
+ arrayForm = kXMP_PropArrayIsAltText;
+ } else if (
+ (currProp->name == "dc:contributor" ) ||
+ (currProp->name == "dc:language" ) ||
+ (currProp->name == "dc:publisher" ) ||
+ (currProp->name == "dc:relation" ) ||
+ (currProp->name == "dc:subject" ) ||
+ (currProp->name == "dc:type" ) ) {
+ arrayForm = kXMP_PropValueIsArray;
+ }
+ if ( arrayForm == 0 ) continue; // Nothing to do if it isn't supposed to be an array.
+
+ arrayForm = VerifySetOptions ( arrayForm, 0 ); // Set the implicit array bits.
+ XMP_Node * newArray = new XMP_Node ( dcSchema, currProp->name.c_str(), arrayForm );
+ dcSchema->children[propNum] = newArray;
+ newArray->children.push_back ( currProp );
+ currProp->parent = newArray;
+ currProp->name = kXMP_ArrayItemName;
+
+ if ( XMP_ArrayIsAltText ( arrayForm ) && (! (currProp->options & kXMP_PropHasLang)) ) {
+ XMP_Node * newLang = new XMP_Node ( currProp, "xml:lang", "x-default", kXMP_PropIsQualifier );
+ currProp->options |= (kXMP_PropHasQualifiers | kXMP_PropHasLang);
+ if ( currProp->qualifiers.empty() ) { // *** Need a util?
+ currProp->qualifiers.push_back ( newLang );
+ } else {
+ currProp->qualifiers.insert ( currProp->qualifiers.begin(), newLang );
+ }
+ }
+
+ }
+
+} // NormalizeDCArrays
+
+
+// -------------------------------------------------------------------------------------------------
+// CompareAliasedSubtrees
+// ----------------------
+
+// *** Change to do some alias-specific setup, then use CompareSubtrees. One special case for
+// *** aliases is a simple to x-default alias, the options and qualifiers obviously differ.
+
+static void
+CompareAliasedSubtrees ( XMP_Node * aliasNode, XMP_Node * baseNode, bool outerCall = true )
+{
+ // ! The outermost call is special. The names almost certainly differ. The qualifiers (and
+ // ! hence options) will differ for an alias to the x-default item of a langAlt array.
+ if ( (aliasNode->value != baseNode->value) ||
+ (aliasNode->children.size() != baseNode->children.size()) ) {
+ XMP_Throw ( "Mismatch between alias and base nodes", kXMPErr_BadXMP );
+ }
+ if ( ! outerCall ) {
+ if ( (aliasNode->name != baseNode->name) ||
+ (aliasNode->options != baseNode->options) ||
+ (aliasNode->qualifiers.size() != baseNode->qualifiers.size()) ) {
+ XMP_Throw ( "Mismatch between alias and base nodes", kXMPErr_BadXMP );
+ }
+ }
+
+ for ( size_t childNum = 0, childLim = aliasNode->children.size(); childNum < childLim; ++childNum ) {
+ XMP_Node * aliasChild = aliasNode->children[childNum];
+ XMP_Node * baseChild = baseNode->children[childNum];
+ CompareAliasedSubtrees ( aliasChild, baseChild, false );
+ }
+
+ for ( size_t qualNum = 0, qualLim = aliasNode->qualifiers.size(); qualNum < qualLim; ++qualNum ) {
+ XMP_Node * aliasQual = aliasNode->qualifiers[qualNum];
+ XMP_Node * baseQual = baseNode->qualifiers[qualNum];
+ CompareAliasedSubtrees ( aliasQual, baseQual, false );
+ }
+
+} // CompareAliasedSubtrees
+
+
+// -------------------------------------------------------------------------------------------------
+// TransplantArrayItemAlias
+// ------------------------
+
+static void
+TransplantArrayItemAlias ( XMP_Node * oldParent, size_t oldNum, XMP_Node * newParent )
+{
+ XMP_Node * childNode = oldParent->children[oldNum];
+
+ if ( newParent->options & kXMP_PropArrayIsAltText ) {
+ if ( childNode->options & kXMP_PropHasLang ) {
+ XMP_Throw ( "Alias to x-default already has a language qualifier", kXMPErr_BadXMP ); // *** Allow x-default.
+ }
+ childNode->options |= (kXMP_PropHasQualifiers | kXMP_PropHasLang);
+ XMP_Node * langQual = new XMP_Node ( childNode, "xml:lang", "x-default", kXMP_PropIsQualifier ); // *** AddLangQual util?
+ if ( childNode->qualifiers.empty() ) {
+ childNode->qualifiers.push_back ( langQual );
+ } else {
+ childNode->qualifiers.insert ( childNode->qualifiers.begin(), langQual );
+ }
+ }
+
+ oldParent->children.erase ( oldParent->children.begin() + oldNum );
+ childNode->name = kXMP_ArrayItemName;
+ childNode->parent = newParent;
+ if ( newParent->children.empty() ) {
+ newParent->children.push_back ( childNode );
+ } else {
+ newParent->children.insert ( newParent->children.begin(), childNode );
+ }
+
+} // TransplantArrayItemAlias
+
+
+// -------------------------------------------------------------------------------------------------
+// TransplantNamedAlias
+// --------------------
+
+static void
+TransplantNamedAlias ( XMP_Node * oldParent, size_t oldNum, XMP_Node * newParent, XMP_VarString & newName )
+{
+ XMP_Node * childNode = oldParent->children[oldNum];
+
+ oldParent->children.erase ( oldParent->children.begin() + oldNum );
+ childNode->name = newName;
+ childNode->parent = newParent;
+ newParent->children.push_back ( childNode );
+
+} // TransplantNamedAlias
+
+
+// -------------------------------------------------------------------------------------------------
+// MoveExplicitAliases
+// -------------------
+
+static void
+MoveExplicitAliases ( XMP_Node * tree, XMP_OptionBits parseOptions )
+{
+ tree->options ^= kXMP_PropHasAliases;
+ const bool strictAliasing = ((parseOptions & kXMP_StrictAliasing) != 0);
+
+ // 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.
+
+ // ! Use "while" loops not "for" loops since both the schema and property loops can remove the
+ // ! current item from the vector being traversed. And don't increment the counter for a delete.
+
+ size_t schemaNum = 0;
+ while ( schemaNum < tree->children.size() ) {
+ XMP_Node * currSchema = tree->children[schemaNum];
+
+ size_t propNum = 0;
+ while ( propNum < currSchema->children.size() ) {
+ XMP_Node * currProp = currSchema->children[propNum];
+ if ( ! (currProp->options & kXMP_PropIsAlias) ) {
+ ++propNum;
+ continue;
+ }
+ currProp->options ^= kXMP_PropIsAlias;
+
+ // Find the base path, look for the base schema and root node.
+
+ XMP_AliasMapPos aliasPos = sRegisteredAliasMap->find ( currProp->name );
+ XMP_Assert ( aliasPos != sRegisteredAliasMap->end() );
+ XMP_ExpandedXPath & basePath = aliasPos->second;
+ XMP_OptionBits arrayOptions = (basePath[kRootPropStep].options & kXMP_PropArrayFormMask);
+
+ XMP_Node * baseSchema = FindSchemaNode ( tree, basePath[kSchemaStep].step.c_str(), kXMP_CreateNodes );
+ if ( baseSchema->options & kXMP_NewImplicitNode ) baseSchema->options ^= kXMP_NewImplicitNode;
+ XMP_Node * baseNode = FindChildNode ( baseSchema, basePath[kRootPropStep].step.c_str(), kXMP_ExistingOnly );
+
+ if ( baseNode == 0 ) {
+
+ if ( basePath.size() == 2 ) {
+ // A top-to-top alias, transplant the property.
+ TransplantNamedAlias ( currSchema, propNum, baseSchema, basePath[kRootPropStep].step );
+ } else {
+ // An alias to an array item, create the array and transplant the property.
+ baseNode = new XMP_Node ( baseSchema, basePath[kRootPropStep].step.c_str(), arrayOptions );
+ baseSchema->children.push_back ( baseNode );
+ TransplantArrayItemAlias ( currSchema, propNum, baseNode );
+ }
+
+ } else if ( basePath.size() == 2 ) {
+
+ // 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 );
+ currSchema->children.erase ( currSchema->children.begin() + propNum );
+ delete 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.
+
+ XMP_Node * itemNode = 0;
+ if ( arrayOptions & kXMP_PropArrayIsAltText ) {
+ XMP_Index xdIndex = LookupLangItem ( baseNode, *xdefaultName );
+ if ( xdIndex != -1 ) itemNode = baseNode->children[xdIndex];
+ } else if ( ! baseNode->children.empty() ) {
+ itemNode = baseNode->children[0];
+ }
+
+ if ( itemNode == 0 ) {
+ TransplantArrayItemAlias ( currSchema, propNum, baseNode );
+ } else {
+ if ( strictAliasing ) CompareAliasedSubtrees ( currProp, itemNode );
+ currSchema->children.erase ( currSchema->children.begin() + propNum );
+ delete currProp;
+ }
+
+ }
+
+ } // Property loop
+
+ // Increment the counter or remove an empty schema node.
+ if ( currSchema->children.size() > 0 ) {
+ ++schemaNum;
+ } else {
+ delete tree->children[schemaNum]; // ! Delete the schema node itself.
+ tree->children.erase ( tree->children.begin() + schemaNum );
+ }
+
+ } // Schema loop
+
+} // MoveExplicitAliases
+
+
+// -------------------------------------------------------------------------------------------------
+// FixGPSTimeStamp
+// ---------------
+
+static void
+FixGPSTimeStamp ( XMP_Node * exifSchema, XMP_Node * gpsDateTime )
+{
+ XMP_DateTime binGPSStamp;
+ try {
+ XMPUtils::ConvertToDate ( gpsDateTime->value.c_str(), &binGPSStamp );
+ } catch ( ... ) {
+ return; // Don't let a bad date stop other things.
+ }
+ if ( (binGPSStamp.year != 0) || (binGPSStamp.month != 0) || (binGPSStamp.day != 0) ) return;
+
+ XMP_Node * otherDate = FindChildNode ( exifSchema, "exif:DateTimeOriginal", kXMP_ExistingOnly );
+ if ( otherDate == 0 ) otherDate = FindChildNode ( exifSchema, "exif:DateTimeDigitized", kXMP_ExistingOnly );
+ if ( otherDate == 0 ) return;
+
+ XMP_DateTime binOtherDate;
+ try {
+ XMPUtils::ConvertToDate ( otherDate->value.c_str(), &binOtherDate );
+ } catch ( ... ) {
+ return; // Don't let a bad date stop other things.
+ }
+
+ binGPSStamp.year = binOtherDate.year;
+ binGPSStamp.month = binOtherDate.month;
+ binGPSStamp.day = binOtherDate.day;
+
+ XMP_StringPtr goodStr;
+ XMP_StringLen goodLen;
+ XMPUtils::ConvertFromDate ( binGPSStamp, &goodStr, &goodLen );
+
+ gpsDateTime->value.assign ( goodStr, goodLen );
+
+} // FixGPSTimeStamp
+
+
+// -------------------------------------------------------------------------------------------------
+// MigrateAudioCopyright
+// ---------------------
+//
+// 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:
+//
+// 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.
+
+static void
+MigrateAudioCopyright ( XMPMeta * xmp, XMP_Node * dmCopyright )
+{
+
+ try {
+
+ std::string & dmValue = dmCopyright->value;
+ static const char * kDoubleLF = "\xA\xA";
+
+ XMP_Node * dcSchema = FindSchemaNode ( &xmp->tree, kXMP_NS_DC, kXMP_CreateNodes );
+ XMP_Node * dcRightsArray = FindChildNode ( dcSchema, "dc:rights", kXMP_ExistingOnly );
+
+ if ( (dcRightsArray == 0) || dcRightsArray->children.empty() ) {
+
+ // 1. No dc:rights array, create from double linefeed and xmpDM:copyright.
+ dmValue.insert ( 0, kDoubleLF );
+ xmp->SetLocalizedText ( kXMP_NS_DC, "rights", "", "x-default", dmValue.c_str(), 0 );
+
+ } else {
+
+ std::string xdefaultStr ( "x-default" );
+
+ XMP_Index xdIndex = LookupLangItem ( dcRightsArray, xdefaultStr );
+
+ if ( xdIndex < 0 ) {
+ // 2. No x-default item, create from the first item.
+ XMP_StringPtr firstValue = dcRightsArray->children[0]->value.c_str();
+ xmp->SetLocalizedText ( kXMP_NS_DC, "rights", "", "x-default", firstValue, 0 );
+ xdIndex = LookupLangItem ( dcRightsArray, xdefaultStr );
+ }
+
+ // 3. Look for a double linefeed in the x-default value.
+ XMP_Assert ( xdIndex == 0 );
+ std::string & defaultValue = dcRightsArray->children[xdIndex]->value;
+ XMP_Index lfPos = defaultValue.find ( kDoubleLF );
+
+ if ( lfPos < 0 ) {
+
+ // 3A. No double LF, compare whole values.
+ if ( dmValue != defaultValue ) {
+ // 3A2. Append the xmpDM:copyright to the x-default item.
+ defaultValue += kDoubleLF;
+ defaultValue += dmValue;
+ }
+
+ } else {
+
+ // 3B. Has double LF, compare the tail.
+ if ( defaultValue.compare ( lfPos+2, std::string::npos, dmValue ) != 0 ) {
+ // 3B2. Replace the x-default tail.
+ defaultValue.replace ( lfPos+2, std::string::npos, dmValue );
+ }
+
+ }
+
+ }
+
+ // 4. Get rid of the xmpDM:copyright.
+ xmp->DeleteProperty ( kXMP_NS_DM, "copyright" );
+
+ } catch ( ... ) {
+ // Don't let failures (like a bad dc:rights form) stop other cleanup.
+ }
+
+} // MigrateAudioCopyright
+
+
+// -------------------------------------------------------------------------------------------------
+// RepairAltText
+// -------------
+//
+// Make sure that the array is well-formed AltText. Each item must be simple and have an xml:lang
+// qualifier. If repairs are needed, keep simple non-empty items by adding the xml:lang.
+
+static void
+RepairAltText ( XMP_Node & tree, XMP_StringPtr schemaNS, XMP_StringPtr arrayName )
+{
+ XMP_Node * schemaNode = FindSchemaNode ( &tree, schemaNS, kXMP_ExistingOnly );
+ if ( schemaNode == 0 ) return;
+
+ XMP_Node * arrayNode = FindChildNode ( schemaNode, arrayName, kXMP_ExistingOnly );
+ if ( (arrayNode == 0) || XMP_ArrayIsAltText ( arrayNode->options ) ) return; // Already OK.
+
+ if ( ! XMP_PropIsArray ( arrayNode->options ) ) return; // ! Not even an array, leave it alone.
+
+ arrayNode->options |= (kXMP_PropArrayIsOrdered | kXMP_PropArrayIsAlternate | kXMP_PropArrayIsAltText);
+
+ for ( int i = arrayNode->children.size()-1; i >= 0; --i ) { // ! Need a signed index type.
+
+ XMP_Node * currChild = arrayNode->children[i];
+
+ if ( ! XMP_PropIsSimple ( currChild->options ) ) {
+
+ // Delete non-simple children.
+ delete ( currChild );
+ arrayNode->children.erase ( arrayNode->children.begin() + i );
+
+ } else if ( ! XMP_PropHasLang ( currChild->options ) ) {
+
+ if ( currChild->value.empty() ) {
+
+ // Delete empty valued children that have no xml:lang.
+ delete ( currChild );
+ arrayNode->children.erase ( arrayNode->children.begin() + i );
+
+ } else {
+
+ // Add an xml:lang qualifier with the value "x-repair".
+ XMP_Node * repairLang = new XMP_Node ( currChild, "xml:lang", "x-repair", kXMP_PropIsQualifier );
+ if ( currChild->qualifiers.empty() ) {
+ currChild->qualifiers.push_back ( repairLang );
+ } else {
+ currChild->qualifiers.insert ( currChild->qualifiers.begin(), repairLang );
+ }
+ currChild->options |= (kXMP_PropHasQualifiers | kXMP_PropHasLang);
+
+ }
+
+ }
+
+ }
+
+} // RepairAltText
+
+
+// -------------------------------------------------------------------------------------------------
+// TouchUpDataModel
+// ----------------
+
+static void
+TouchUpDataModel ( XMPMeta * xmp )
+{
+ XMP_Node & tree = xmp->tree;
+
+ // Do special case touch ups for certain schema.
+
+ XMP_Node * currSchema = 0;
+
+ currSchema = FindSchemaNode ( &tree, kXMP_NS_EXIF, kXMP_ExistingOnly );
+ if ( currSchema != 0 ) {
+ // Do a special case fix for exif:GPSTimeStamp.
+ XMP_Node * gpsDateTime = FindChildNode ( currSchema, "exif:GPSTimeStamp", kXMP_ExistingOnly );
+ if ( gpsDateTime != 0 ) FixGPSTimeStamp ( currSchema, gpsDateTime );
+ }
+
+ currSchema = FindSchemaNode ( &tree, kXMP_NS_DM, kXMP_ExistingOnly );
+ if ( currSchema != 0 ) {
+ // Do a special case migration of xmpDM:copyright to dc:rights['x-default']. Do this before
+ // the dc: touch up since it can affect the dc: schema.
+ XMP_Node * dmCopyright = FindChildNode ( currSchema, "xmpDM:copyright", kXMP_ExistingOnly );
+ if ( dmCopyright != 0 ) MigrateAudioCopyright ( xmp, dmCopyright );
+ }
+
+ currSchema = FindSchemaNode ( &tree, kXMP_NS_DC, kXMP_ExistingOnly );
+ if ( currSchema != 0 ) {
+ // Do a special case fix for dc:subject, make sure it is an unordered array.
+ XMP_Node * dcSubject = FindChildNode ( currSchema, "dc:subject", kXMP_ExistingOnly );
+ if ( dcSubject != 0 ) {
+ XMP_OptionBits keepMask = ~(kXMP_PropArrayIsOrdered | kXMP_PropArrayIsAlternate | kXMP_PropArrayIsAltText);
+ dcSubject->options &= keepMask; // Make sure any ordered array bits are clear.
+ }
+ }
+
+ // Fix any broken AltText arrays that we know about.
+
+ RepairAltText ( tree, kXMP_NS_DC, "dc:description" ); // ! Note inclusion of prefixes for direct node lookup!
+ RepairAltText ( tree, kXMP_NS_DC, "dc:rights" );
+ RepairAltText ( tree, kXMP_NS_DC, "dc:title" );
+ RepairAltText ( tree, kXMP_NS_XMP_Rights, "xapRights:UsageTerms" );
+ RepairAltText ( tree, kXMP_NS_EXIF, "exif:UserComment" );
+
+ // Tweak old XMP: Move an instance ID from rdf:about to the xmpMM:InstanceID property. An old
+ // instance ID usually looks like "uuid:bac965c4-9d87-11d9-9a30-000d936b79c4", plus InDesign
+ // 3.0 wrote them like "bac965c4-9d87-11d9-9a30-000d936b79c4". If the name looks like a UUID
+ // simply move it to xmpMM:InstanceID, don't worry about any existing xmpMM:InstanceID. Both
+ // will only be present when a newer file with the xmpMM:InstanceID property is updated by an
+ // old app that uses rdf:about.
+
+ if ( ! tree.name.empty() ) {
+
+ bool nameIsUUID = false;
+ XMP_StringPtr nameStr = tree.name.c_str();
+
+ if ( XMP_LitNMatch ( nameStr, "uuid:", 5 ) ) {
+
+ nameIsUUID = true;
+
+ } else if ( tree.name.size() == 36 ) {
+
+ nameIsUUID = true; // ! Assume true, we'll set it to false below if not.
+ for ( int i = 0; i < 36; ++i ) {
+ char ch = nameStr[i];
+ if ( ch == '-' ) {
+ if ( (i == 8) || (i == 13) || (i == 18) || (i == 23) ) continue;
+ nameIsUUID = false;
+ break;
+ } else {
+ if ( (('0' <= ch) && (ch <= '9')) || (('a' <= ch) && (ch <= 'z')) ) continue;
+ nameIsUUID = false;
+ break;
+ }
+ }
+
+ }
+
+ if ( nameIsUUID ) {
+
+ XMP_ExpandedXPath expPath;
+ ExpandXPath ( kXMP_NS_XMP_MM, "InstanceID", &expPath );
+ XMP_Node * idNode = FindNode ( &tree, expPath, kXMP_CreateNodes, 0 );
+ if ( idNode == 0 ) XMP_Throw ( "Failure creating xmpMM:InstanceID", kXMPErr_InternalFailure );
+
+ idNode->options = 0; // Clobber any existing xmpMM:InstanceID.
+ idNode->value = tree.name;
+ idNode->RemoveChildren();
+ idNode->RemoveQualifiers();
+
+ tree.name.erase();
+
+ }
+
+ }
+
+} // TouchUpDataModel
+
+
+// -------------------------------------------------------------------------------------------------
+// DetermineInputEncoding
+// ----------------------
+//
+// Try to determine the character encoding, making a guess if the input is too short. We make some
+// simplifying assumtions: the first character must be U+FEFF or ASCII, U+0000 is not allowed. The
+// XML 1.1 spec is even more strict, UTF-16 XML documents must begin with U+FEFF, and the first
+// "real" character must be '<'. Ignoring the XML declaration, the first XML character could be '<',
+// space, tab, CR, or LF.
+//
+// The possible input sequences are:
+//
+// Cases with U+FEFF
+// EF BB BF -- - UTF-8
+// FE FF -- -- - Big endian UTF-16
+// 00 00 FE FF - Big endian UTF 32
+// FF FE 00 00 - Little endian UTF-32
+// FF FE -- -- - Little endian UTF-16
+//
+// Cases with ASCII
+// nn mm -- -- - UTF-8 -
+// 00 00 00 nn - Big endian UTF-32
+// 00 nn -- -- - Big endian UTF-16
+// nn 00 00 00 - Little endian UTF-32
+// nn 00 -- -- - Little endian UTF-16
+//
+// ! We don't check for full patterns, or for errors. We just check enough to determine what the
+// ! only possible (or reasonable) case would be.
+
+static XMP_OptionBits
+DetermineInputEncoding ( const XMP_Uns8 * buffer, size_t length )
+{
+ if ( length < 2 ) return kXMP_EncodeUTF8;
+
+ XMP_Uns8 * uniChar = (XMP_Uns8*)buffer; // ! Make sure comparisons are unsigned.
+
+ if ( uniChar[0] == 0 ) {
+
+ // These cases are:
+ // 00 nn -- -- - Big endian UTF-16
+ // 00 00 00 nn - Big endian UTF-32
+ // 00 00 FE FF - Big endian UTF 32
+
+ if ( (length < 4) || (uniChar[1] != 0) ) return kXMP_EncodeUTF16Big;
+ return kXMP_EncodeUTF32Big;
+
+ } else if ( uniChar[0] < 0x80 ) {
+
+ // These cases are:
+ // nn mm -- -- - UTF-8, includes EF BB BF case
+ // nn 00 00 00 - Little endian UTF-32
+ // nn 00 -- -- - Little endian UTF-16
+
+ if ( uniChar[1] != 0 ) return kXMP_EncodeUTF8;
+ if ( (length < 4) || (uniChar[2] != 0) ) return kXMP_EncodeUTF16Little;
+ return kXMP_EncodeUTF32Little;
+
+ } else {
+
+ // These cases are:
+ // EF BB BF -- - UTF-8
+ // FE FF -- -- - Big endian UTF-16
+ // FF FE 00 00 - Little endian UTF-32
+ // FF FE -- -- - Little endian UTF-16
+
+ if ( uniChar[0] == 0xEF ) return kXMP_EncodeUTF8;
+ if ( uniChar[0] == 0xFE ) return kXMP_EncodeUTF16Big;
+ if ( (length < 4) || (uniChar[2] != 0) ) return kXMP_EncodeUTF16Little;
+ return kXMP_EncodeUTF32Little;
+
+ }
+
+} // DetermineInputEncoding
+
+
+// -------------------------------------------------------------------------------------------------
+// CountUTF8
+// ---------
+//
+// Look for a valid multi-byte UTF-8 sequence and return its length. Returns 0 for an invalid UTF-8
+// sequence. Returns a negative value for a partial valid sequence at the end of the buffer.
+//
+// The checking is not strict. We simply count the number of high order 1 bits in the first byte,
+// then look for n-1 following bytes whose high order 2 bits are 1 and 0. We do not check for a
+// minimal length representation of the codepoint, or that the codepoint is defined by Unicode.
+
+static int
+CountUTF8 ( const XMP_Uns8 * charStart, const XMP_Uns8 * bufEnd )
+{
+ XMP_Assert ( charStart < bufEnd ); // Catch this in debug builds.
+ if ( charStart >= bufEnd ) return 0; // Don't run-on in release builds.
+ if ( (*charStart & 0xC0) != 0xC0 ) return 0; // Must have at least 2 high bits set.
+
+ int byteCount = 2;
+ XMP_Uns8 firstByte = *charStart;
+ for ( firstByte = firstByte << 2; (firstByte & 0x80) != 0; firstByte = firstByte << 1 ) ++byteCount;
+
+ if ( (charStart + byteCount) > bufEnd ) return -byteCount;
+
+ for ( int i = 1; i < byteCount; ++i ) {
+ if ( (charStart[i] & 0xC0) != 0x80 ) return 0;
+ }
+
+ return byteCount;
+
+} // CountUTF8
+
+
+// -------------------------------------------------------------------------------------------------
+// CountControlEscape
+// ------------------
+//
+// Look for a numeric escape sequence for a "prohibited" ASCII control character. These are 0x7F,
+// and the range 0x00..0x1F except for tab/LF/CR. Return 0 if this is definitely not a numeric
+// escape, the length of the escape if found, or a negative value for a partial escape.
+
+static int
+CountControlEscape ( const XMP_Uns8 * escStart, const XMP_Uns8 * bufEnd )
+{
+ XMP_Assert ( escStart < bufEnd ); // Catch this in debug builds.
+ if ( escStart >= bufEnd ) return 0; // Don't run-on in release builds.
+ XMP_Assert ( *escStart == '&' );
+
+ size_t tailLen = bufEnd - escStart;
+ if ( tailLen < 5 ) return -1; // Don't need a more thorough check, we'll catch it on the next pass.
+
+ if ( strncmp ( (char*)escStart, "&#x", 3 ) != 0 ) return 0;
+
+ XMP_Uns8 escValue = 0;
+ const XMP_Uns8 * escPos = escStart + 3;
+
+ if ( ('0' <= *escPos) && (*escPos <= '9') ) {
+ escValue = *escPos - '0';
+ ++escPos;
+ } else if ( ('A' <= *escPos) && (*escPos <= 'F') ) {
+ escValue = *escPos - 'A' + 10;
+ ++escPos;
+ } else if ( ('a' <= *escPos) && (*escPos <= 'f') ) {
+ escValue = *escPos - 'a' + 10;
+ ++escPos;
+ }
+
+ if ( ('0' <= *escPos) && (*escPos <= '9') ) {
+ escValue = (escValue << 4) + (*escPos - '0');
+ ++escPos;
+ } else if ( ('A' <= *escPos) && (*escPos <= 'F') ) {
+ escValue = (escValue << 4) + (*escPos - 'A' + 10);
+ ++escPos;
+ } else if ( ('a' <= *escPos) && (*escPos <= 'f') ) {
+ escValue = (escValue << 4) + (*escPos - 'a' + 10);
+ ++escPos;
+ }
+
+ if ( escPos == bufEnd ) return -1; // Partial escape.
+ if ( *escPos != ';' ) return 0;
+
+ size_t escLen = escPos - escStart + 1;
+ if ( escLen < 5 ) return 0; // ! Catch "&#x;".
+
+ if ( (escValue == kTab) || (escValue == kLF) || (escValue == kCR) ) return 0; // An allowed escape.
+
+ return escLen; // Found a full "prohibited" numeric escape.
+
+} // CountControlEscape
+
+
+// -------------------------------------------------------------------------------------------------
+// ProcessUTF8Portion
+// ------------------
+//
+// Early versions of the XMP spec mentioned allowing ISO Latin-1 input. There are also problems with
+// some clients placing ASCII control characters within XMP values. This is an XML problem, the XML
+// spec only allows tab (0x09), LF (0x0A), and CR (0x0D) from the 0x00..0x1F range. As a concession
+// to this we scan 8-bit input for byte sequences that are not valid UTF-8 or in the 0x00..0x1F
+// range and replace each byte as follows:
+// 0x00..0x1F - Replace with a space, except for tab, CR, and LF.
+// 0x7F - Replace with a space. This is ASCII Delete, not allowed by ISO Latin-1.
+// 0x80..0x9F - Replace with the UTF-8 for a corresponding Unicode character.
+// 0xA0..0XFF - Replace with the UTF-8 for a corresponding Unicode character.
+//
+// The 0x80..0x9F range is not defined by Latin-1. But the Windows 1252 code page defines these and
+// is otherwise the same as Latin-1.
+//
+// For at least historical compatibility reasons we also find and replace singly escaped ASCII
+// control characters. The Expat parser we're using does not allow numeric escapes like "&#x10;".
+// The XML spec is clear that raw controls are not allowed (in the RestrictedChar set), but it isn't
+// as clear about numeric escapes for them. At any rate, Expat complains, so we treat the numeric
+// escapes like raw characters and replace them with a space.
+//
+// We check for 1 or 2 hex digits ("&#x9;" or "&#x09;") and upper or lower case ("&#xA;" or "&#xa;").
+// The full escape sequence is 5 or 6 bytes.
+
+static size_t
+ProcessUTF8Portion ( XMLParserAdapter * xmlParser,
+ const XMP_Uns8 * buffer,
+ size_t length,
+ bool last )
+{
+ const XMP_Uns8 * bufEnd = buffer + length;
+
+ const XMP_Uns8 * spanStart = buffer;
+ const XMP_Uns8 * spanEnd;
+
+ for ( spanEnd = spanStart; spanEnd < bufEnd; ++spanEnd ) {
+
+ if ( (0x20 <= *spanEnd) && (*spanEnd <= 0x7E) && (*spanEnd != '&') ) continue; // A regular ASCII character.
+
+ if ( *spanEnd >= 0x80 ) {
+
+ // See if this is a multi-byte UTF-8 sequence, or a Latin-1 character to replace.
+
+ int uniLen = CountUTF8 ( spanEnd, bufEnd );
+
+ if ( uniLen > 0 ) {
+
+ // A valid UTF-8 character, keep it as-is.
+ spanEnd += uniLen - 1; // ! The loop increment will put back the +1.
+
+ } else if ( (uniLen < 0) && (! last) ) {
+
+ // Have a partial UTF-8 character at the end of the buffer and more input coming.
+ xmlParser->ParseBuffer ( spanStart, (spanEnd - spanStart), false );
+ return (spanEnd - buffer);
+
+ } else {
+
+ // Not a valid UTF-8 sequence. Replace the first byte with the Latin-1 equivalent.
+ xmlParser->ParseBuffer ( spanStart, (spanEnd - spanStart), false );
+ const char * replacement = kReplaceLatin1 [ *spanEnd - 0x80 ];
+ xmlParser->ParseBuffer ( replacement, strlen ( replacement ), false );
+ spanStart = spanEnd + 1; // ! The loop increment will do "spanEnd = spanStart".
+
+ }
+
+ } else if ( (*spanEnd < 0x20) || (*spanEnd == 0x7F) ) {
+
+ // Replace ASCII controls other than tab, LF, and CR with a space.
+
+ if ( (*spanEnd == kTab) || (*spanEnd == kLF) || (*spanEnd == kCR) ) continue;
+
+ xmlParser->ParseBuffer ( spanStart, (spanEnd - spanStart), false );
+ xmlParser->ParseBuffer ( " ", 1, false );
+ spanStart = spanEnd + 1; // ! The loop increment will do "spanEnd = spanStart".
+
+ } else {
+
+ // See if this is a numeric escape sequence for a prohibited ASCII control.
+
+ XMP_Assert ( *spanEnd == '&' );
+ int escLen = CountControlEscape ( spanEnd, bufEnd );
+
+ if ( escLen < 0 ) {
+
+ // Have a partial numeric escape in this buffer, wait for more input.
+ if ( last ) continue; // No more buffers, not an escape, absorb as normal input.
+ xmlParser->ParseBuffer ( spanStart, (spanEnd - spanStart), false );
+ return (spanEnd - buffer);
+
+ } else if ( escLen > 0 ) {
+
+ // Have a complete numeric escape to replace.
+ xmlParser->ParseBuffer ( spanStart, (spanEnd - spanStart), false );
+ xmlParser->ParseBuffer ( " ", 1, false );
+ spanStart = spanEnd + escLen;
+ spanEnd = spanStart - 1; // ! The loop continuation will increment spanEnd!
+
+ }
+
+ }
+
+ }
+
+ XMP_Assert ( spanEnd == bufEnd );
+
+ if ( spanStart < bufEnd ) xmlParser->ParseBuffer ( spanStart, (spanEnd - spanStart), false );
+ if ( last ) xmlParser->ParseBuffer ( " ", 1, true );
+
+ return length;
+
+} // ProcessUTF8Portion
+
+
+// -------------------------------------------------------------------------------------------------
+// ParseFromBuffer
+// ---------------
+//
+// Although most clients will probably parse everything in one call, we have a buffered API model
+// and need to support even the extreme case of 1 byte at a time parsing. This is considerably
+// complicated by some special cases for 8-bit input. Because of this, the first thing we do is
+// determine whether the input is 8-bit, UTF-16, or UTF-32.
+//
+// Both the 8-bit special cases and the encoding determination are easier to do with 8 bytes or more
+// of input. The XMLParserAdapter class has a pending-input buffer for this. At the start of parsing
+// we (moght) try to fill this buffer before determining the input character encoding. After that,
+// we (might) use this buffer with the current input to simplify the logic in Process8BitInput. The
+// "(might)" part means that we don't actually use the pending-input buffer unless we have to. In
+// particular, the common case of single-buffer parsing won't use it.
+
+void
+XMPMeta::ParseFromBuffer ( XMP_StringPtr buffer,
+ XMP_StringLen xmpSize,
+ XMP_OptionBits options )
+{
+ if ( (buffer == 0) && (xmpSize != 0) ) XMP_Throw ( "Null parse buffer", kXMPErr_BadParam );
+ if ( xmpSize == kXMP_UseNullTermination ) xmpSize = strlen ( buffer );
+
+ const bool lastClientCall = ((options & kXMP_ParseMoreBuffers) == 0); // *** Could use FlagIsSet & FlagIsClear macros.
+
+ this->tree.ClearNode(); // Make sure the target XMP object is totally empty.
+
+ if ( this->xmlParser == 0 ) {
+ if ( (xmpSize == 0) && lastClientCall ) return; // Tolerate empty parse. Expat complains if there are no XML elements.
+ this->xmlParser = new ExpatAdapter;
+ }
+
+ XMLParserAdapter& parser = *this->xmlParser;
+
+ #if 0 // XMP_DebugBuild
+ if ( parser.parseLog != 0 ) {
+ char message [200]; // AUDIT: Using sizeof(message) below for snprintf length is safe.
+ snprintf ( message, sizeof(message), "<!-- ParseFromBuffer, length = %d, options = %X%s -->", // AUDIT: See above.
+ xmpSize, options, (lastClientCall ? " (last)" : "") );
+ fwrite ( message, 1, strlen(message), parser.parseLog );
+ fflush ( parser.parseLog );
+ }
+ #endif
+
+ try { // Cleanup the tree and xmlParser if anything fails.
+
+ // Determine the character encoding before doing any real parsing. This is needed to do the
+ // 8-bit special processing.
+
+ if ( parser.charEncoding == XMP_OptionBits(-1) ) {
+
+ if ( (parser.pendingCount == 0) && (xmpSize >= kXMLPendingInputMax) ) {
+
+ // This ought to be the common case, the first buffer is big enough.
+ parser.charEncoding = DetermineInputEncoding ( (XMP_Uns8*)buffer, xmpSize );
+
+ } else {
+
+ // Try to fill the pendingInput buffer before calling DetermineInputEncoding.
+
+ size_t pendingOverlap = kXMLPendingInputMax - parser.pendingCount;
+ if ( pendingOverlap > xmpSize ) pendingOverlap = xmpSize;
+
+ memcpy ( &parser.pendingInput[parser.pendingCount], buffer, pendingOverlap ); // AUDIT: Count is safe.
+ buffer += pendingOverlap;
+ xmpSize -= pendingOverlap;
+ parser.pendingCount += pendingOverlap;
+
+ if ( (! lastClientCall) && (parser.pendingCount < kXMLPendingInputMax) ) return;
+ parser.charEncoding = DetermineInputEncoding ( parser.pendingInput, parser.pendingCount );
+
+ #if Trace_ParsingHackery
+ fprintf ( stderr, "XMP Character encoding is %d\n", parser.charEncoding );
+ #endif
+
+ }
+
+ }
+
+ // We have the character encoding. Process UTF-16 and UTF-32 as is. UTF-8 needs special
+ // handling to take care of things like ISO Latin-1 or unescaped ASCII controls.
+
+ XMP_Assert ( parser.charEncoding != XMP_OptionBits(-1) );
+
+ if ( parser.charEncoding != kXMP_EncodeUTF8 ) {
+
+ if ( parser.pendingCount > 0 ) {
+ // Might have pendingInput from the above portion to determine the character encoding.
+ parser.ParseBuffer ( parser.pendingInput, parser.pendingCount, false );
+ }
+ parser.ParseBuffer ( buffer, xmpSize, lastClientCall );
+
+ } else {
+
+ #if Trace_ParsingHackery
+ fprintf ( stderr, "Parsing %d bytes @ %.8X, %s, %d pending, context: %.8s\n",
+ xmpSize, buffer, (lastClientCall ? "last" : "not last"), parser.pendingCount, buffer );
+ #endif
+
+ // The UTF-8 processing is a bit complex due to the need to tolerate ISO Latin-1 input.
+ // This is done by scanning the input for byte sequences that are not valid UTF-8,
+ // assuming they are Latin-1 characters in the range 0x80..0xFF. This requires saving a
+ // pending input buffer to handle partial UTF-8 sequences at the end of a buffer.
+
+ while ( parser.pendingCount > 0 ) {
+
+ // We've got some leftover input, process it first then continue with the current
+ // buffer. Try to fill the pendingInput buffer before parsing further. We use a loop
+ // for wierd edge cases like a 2 byte input buffer, using 1 byte for pendingInput,
+ // then having a partial UTF-8 end and need to absorb more.
+
+ size_t pendingOverlap = kXMLPendingInputMax - parser.pendingCount;
+ if ( pendingOverlap > xmpSize ) pendingOverlap = xmpSize;
+
+ memcpy ( &parser.pendingInput[parser.pendingCount], buffer, pendingOverlap ); // AUDIT: Count is safe.
+ parser.pendingCount += pendingOverlap;
+ buffer += pendingOverlap;
+ xmpSize -= pendingOverlap;
+
+ if ( (! lastClientCall) && (parser.pendingCount < kXMLPendingInputMax) ) return;
+ size_t bytesDone = ProcessUTF8Portion ( &parser, parser.pendingInput, parser.pendingCount, lastClientCall );
+ size_t bytesLeft = parser.pendingCount - bytesDone;
+
+ #if Trace_ParsingHackery
+ fprintf ( stderr, " ProcessUTF8Portion handled %d pending bytes\n", bytesDone );
+ #endif
+
+ if ( bytesDone == parser.pendingCount ) {
+
+ // Done with all of the pending input, move on to the current buffer.
+ parser.pendingCount = 0;
+
+ } else if ( bytesLeft <= pendingOverlap ) {
+
+ // The leftover pending input all came from the current buffer. Exit this loop.
+ buffer -= bytesLeft;
+ xmpSize += bytesLeft;
+ parser.pendingCount = 0;
+
+ } else if ( xmpSize > 0 ) {
+
+ // Pull more of the current buffer into the pending input and try again.
+ // Backup by this pass's overlap so the loop entry code runs OK.
+ parser.pendingCount -= pendingOverlap;
+ buffer -= pendingOverlap;
+ xmpSize += pendingOverlap;
+
+ } else {
+
+ // There is no more of the current buffer. Wait for more. Partial sequences at
+ // the end of the last buffer should be treated as Latin-1 by ProcessUTF8Portion.
+ XMP_Assert ( ! lastClientCall );
+ parser.pendingCount = bytesLeft;
+ memcpy ( &parser.pendingInput[0], &parser.pendingInput[bytesDone], bytesLeft ); // AUDIT: Count is safe.
+ return;
+
+ }
+
+ }
+
+ // Done with the pending input, process the current buffer.
+
+ size_t bytesDone = ProcessUTF8Portion ( &parser, (XMP_Uns8*)buffer, xmpSize, lastClientCall );
+
+ #if Trace_ParsingHackery
+ fprintf ( stderr, " ProcessUTF8Portion handled %d additional bytes\n", bytesDone );
+ #endif
+
+ if ( bytesDone < xmpSize ) {
+
+ XMP_Assert ( ! lastClientCall );
+ size_t bytesLeft = xmpSize - bytesDone;
+ if ( bytesLeft > kXMLPendingInputMax ) XMP_Throw ( "Parser bytesLeft too large", kXMPErr_InternalFailure );
+
+ memcpy ( parser.pendingInput, &buffer[bytesDone], bytesLeft ); // AUDIT: Count is safe.
+ parser.pendingCount = bytesLeft;
+ return; // Wait for the next buffer.
+
+ }
+
+ }
+
+ if ( lastClientCall ) {
+
+ #if XMP_DebugBuild && DumpXMLParseTree
+ if ( parser.parseLog == 0 ) parser.parseLog = stdout;
+ DumpXMLTree ( parser.parseLog, parser.tree, 0 );
+ #endif
+
+ const XML_Node * xmlRoot = FindRootNode ( this, *this->xmlParser, options );
+
+ if ( xmlRoot != 0 ) {
+
+ ProcessRDF ( &this->tree, *xmlRoot, options );
+ NormalizeDCArrays ( &this->tree );
+ if ( this->tree.options & kXMP_PropHasAliases ) MoveExplicitAliases ( &this->tree, options );
+ TouchUpDataModel ( this );
+
+ // Delete empty schema nodes. Do this last, other cleanup can make empty schema.
+ size_t schemaNum = 0;
+ while ( schemaNum < this->tree.children.size() ) {
+ XMP_Node * currSchema = this->tree.children[schemaNum];
+ if ( currSchema->children.size() > 0 ) {
+ ++schemaNum;
+ } else {
+ delete this->tree.children[schemaNum]; // ! Delete the schema node itself.
+ this->tree.children.erase ( this->tree.children.begin() + schemaNum );
+ }
+ }
+
+ }
+
+ delete this->xmlParser;
+ this->xmlParser = 0;
+
+ }
+
+ } catch ( ... ) {
+
+ delete this->xmlParser;
+ this->xmlParser = 0;
+ prevTkVer = 0;
+ this->tree.ClearNode();
+ throw;
+
+ }
+
+} // ParseFromBuffer
+
+// =================================================================================================
diff --git a/source/XMPCore/XMPMeta-Serialize.cpp b/source/XMPCore/XMPMeta-Serialize.cpp
new file mode 100644
index 0000000..73c0d2b
--- /dev/null
+++ b/source/XMPCore/XMPMeta-Serialize.cpp
@@ -0,0 +1,1352 @@
+// =================================================================================================
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+//
+// Adobe patent application tracking #P435, entitled 'Unique markers to simplify embedding data of
+// one format in a file with a different format', inventors: Sean Parent, Greg Gilley.
+// =================================================================================================
+
+#include "XMP_Environment.h" // ! This must be the first include!
+#include "XMPCore_Impl.hpp"
+
+#include "XMPMeta.hpp"
+
+#include "XMP_Version.h"
+#include "UnicodeInlines.incl_cpp"
+#include "UnicodeConversions.hpp"
+
+#if XMP_DebugBuild
+ #include <iostream>
+#endif
+
+using namespace std;
+
+#if XMP_WinBuild
+ #pragma warning ( disable : 4533 ) // initialization of '...' is skipped by 'goto ...'
+ #pragma warning ( disable : 4702 ) // unreachable code
+ #pragma warning ( disable : 4800 ) // forcing value to bool 'true' or 'false' (performance warning)
+#endif
+
+
+// *** Use the XMP_PropIsXyz (Schema, Simple, Struct, Array, ...) macros
+// *** Add debug codegen checks, e.g. that typical masking operations really work
+// *** Change all uses of strcmp and strncmp to XMP_LitMatch and XMP_LitNMatch
+
+
+// =================================================================================================
+// Local Types and Constants
+// =========================
+
+static const char * kPacketHeader = "<?xpacket begin=\"\xEF\xBB\xBF\" id=\"W5M0MpCehiHzreSzNTczkc9d\"?>";
+static const char * kPacketTrailer = "<?xpacket end=\"w\"?>"; // ! The w/r is at [size-4].
+
+static const char * kPXMP_PacketStart = "<pxmp:XMP_Packet";
+static const char * kPXMP_PacketEnd = "</pxmp:XMP_Packet>";
+
+static const char * kPXMP_SchemaGroup = "XMP_SchemaGroup";
+
+static const char * kRDF_XMPMetaStart = "<x:xmpmeta xmlns:x=\"adobe:ns:meta/\" x:xmptk=\"";
+static const char * kRDF_XMPMetaEnd = "</x:xmpmeta>";
+
+static const char * kRDF_RDFStart = "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">";
+static const char * kRDF_RDFEnd = "</rdf:RDF>";
+
+static const char * kRDF_SchemaStart = "<rdf:Description rdf:about=";
+static const char * kRDF_SchemaEnd = "</rdf:Description>";
+
+static const char * kRDF_StructStart = "<rdf:Description>";
+static const char * kRDF_StructEnd = "</rdf:Description>";
+
+static const char * kRDF_BagStart = "<rdf:Bag>";
+static const char * kRDF_BagEnd = "</rdf:Bag>";
+
+static const char * kRDF_SeqStart = "<rdf:Seq>";
+static const char * kRDF_SeqEnd = "</rdf:Seq>";
+
+static const char * kRDF_AltStart = "<rdf:Alt>";
+static const char * kRDF_AltEnd = "</rdf:Alt>";
+
+static const char * kRDF_ItemStart = "<rdf:li>";
+static const char * kRDF_ItemEnd = "</rdf:li>";
+
+static const char * kRDF_ValueStart = "<rdf:value>";
+static const char * kRDF_ValueEnd = "</rdf:value>";
+
+
+// =================================================================================================
+// Static Variables
+// ================
+
+
+// =================================================================================================
+// Local Utilities
+// ===============
+
+
+// -------------------------------------------------------------------------------------------------
+// EstimateRDFSize
+// ---------------
+
+// *** Pull the strlen(kXyz) calls into constants.
+
+static size_t
+EstimateRDFSize ( const XMP_Node * currNode, XMP_Index indent, size_t indentLen )
+{
+ size_t outputLen = 2 * (indent*indentLen + currNode->name.size() + 4); // The property element tags.
+
+ if ( ! currNode->qualifiers.empty() ) {
+ // This node has qualifiers, assume it is written using rdf:value and estimate the qualifiers.
+
+ indent += 2; // Everything else is indented inside the rdf:Description element.
+ outputLen += 2 * ((indent-1)*indentLen + strlen(kRDF_StructStart) + 2); // The rdf:Description tags.
+ outputLen += 2 * (indent*indentLen + strlen(kRDF_ValueStart) + 2); // The rdf:value tags.
+
+ for ( size_t qualNum = 0, qualLim = currNode->qualifiers.size(); qualNum < qualLim; ++qualNum ) {
+ const XMP_Node * currQual = currNode->qualifiers[qualNum];
+ outputLen += EstimateRDFSize ( currQual, indent, indentLen );
+ }
+
+ }
+
+ if ( currNode->options & kXMP_PropValueIsStruct ) {
+ indent += 1;
+ outputLen += 2 * (indent*indentLen + strlen(kRDF_StructStart) + 2); // The rdf:Description tags.
+ } else if ( currNode->options & kXMP_PropValueIsArray ) {
+ indent += 2;
+ outputLen += 2 * ((indent-1)*indentLen + strlen(kRDF_BagStart) + 2); // The rdf:Bag/Seq/Alt tags.
+ outputLen += 2 * currNode->children.size() * (strlen(kRDF_ItemStart) + 2); // The rdf:li tags, indent counted in children.
+ } else if ( ! (currNode->options & kXMP_SchemaNode) ) {
+ outputLen += currNode->value.size(); // This is a leaf value node.
+ }
+
+ for ( size_t childNum = 0, childLim = currNode->children.size(); childNum < childLim; ++childNum ) {
+ const XMP_Node * currChild = currNode->children[childNum];
+ outputLen += EstimateRDFSize ( currChild, indent+1, indentLen );
+ }
+
+ return outputLen;
+
+} // EstimateRDFSize
+
+
+// -------------------------------------------------------------------------------------------------
+// DeclareOneNamespace
+// -------------------
+
+static void
+DeclareOneNamespace ( const XMP_VarString & nsPrefix,
+ const XMP_VarString & nsURI,
+ XMP_VarString & usedNS, // ! A catenation of the prefixes with colons.
+ XMP_VarString & outputStr,
+ XMP_StringPtr newline,
+ XMP_StringPtr indentStr,
+ XMP_Index indent )
+{
+ size_t nsPos = usedNS.find ( nsPrefix );
+
+ if ( nsPos == XMP_VarString::npos ) {
+
+ outputStr += newline;
+ for ( ; indent > 0; --indent ) outputStr += indentStr;
+ outputStr += "xmlns:";
+ outputStr += nsPrefix;
+ outputStr[outputStr.size()-1] = '='; // Change the colon to =.
+ outputStr += '"';
+ outputStr += nsURI;
+ outputStr += '"';
+
+ usedNS += nsPrefix;
+
+ }
+
+} // DeclareOneNamespace
+
+
+// -------------------------------------------------------------------------------------------------
+// DeclareElemNamespace
+// --------------------
+
+static void
+DeclareElemNamespace ( const XMP_VarString & elemName,
+ XMP_VarString & usedNS,
+ XMP_VarString & outputStr,
+ XMP_StringPtr newline,
+ XMP_StringPtr indentStr,
+ XMP_Index indent )
+{
+ size_t colonPos = elemName.find ( ':' );
+
+ if ( colonPos != XMP_VarString::npos ) {
+ XMP_VarString nsPrefix ( elemName.substr ( 0, colonPos+1 ) );
+ XMP_StringMapPos prefixPos = sNamespacePrefixToURIMap->find ( nsPrefix );
+ XMP_Enforce ( prefixPos != sNamespacePrefixToURIMap->end() );
+ DeclareOneNamespace ( nsPrefix, prefixPos->second, usedNS, outputStr, newline, indentStr, indent );
+ }
+
+} // DeclareElemNamespace
+
+
+// -------------------------------------------------------------------------------------------------
+// DeclareUsedNamespaces
+// ---------------------
+
+// ??? Should iterators be passed by reference to avoid temp copies?
+
+static void
+DeclareUsedNamespaces ( const XMP_Node * currNode,
+ XMP_VarString & usedNS,
+ XMP_VarString & outputStr,
+ XMP_StringPtr newline,
+ XMP_StringPtr indentStr,
+ XMP_Index indent )
+{
+
+ if ( currNode->options & kXMP_SchemaNode ) {
+ // The schema node name is the URI, the value is the prefix.
+ DeclareOneNamespace ( currNode->value, currNode->name, usedNS, outputStr, newline, indentStr, indent );
+ } else if ( currNode->options & kXMP_PropValueIsStruct ) {
+ for ( size_t fieldNum = 0, fieldLim = currNode->children.size(); fieldNum < fieldLim; ++fieldNum ) {
+ const XMP_Node * currField = currNode->children[fieldNum];
+ DeclareElemNamespace ( currField->name, usedNS, outputStr, newline, indentStr, indent );
+ }
+ }
+
+ for ( size_t childNum = 0, childLim = currNode->children.size(); childNum < childLim; ++childNum ) {
+ const XMP_Node * currChild = currNode->children[childNum];
+ DeclareUsedNamespaces ( currChild, usedNS, outputStr, newline, indentStr, indent );
+ }
+
+ for ( size_t qualNum = 0, qualLim = currNode->qualifiers.size(); qualNum < qualLim; ++qualNum ) {
+ const XMP_Node * currQual = currNode->qualifiers[qualNum];
+ DeclareElemNamespace ( currQual->name, usedNS, outputStr, newline, indentStr, indent );
+ DeclareUsedNamespaces ( currQual, usedNS, outputStr, newline, indentStr, indent );
+ }
+
+} // DeclareUsedNamespaces
+
+// -------------------------------------------------------------------------------------------------
+// EmitRDFArrayTag
+// ---------------
+
+// ??? Should iterators be passed by reference to avoid temp copies?
+
+enum {
+ kIsStartTag = true,
+ kIsEndTag = false
+};
+
+static void
+EmitRDFArrayTag ( XMP_OptionBits arrayForm,
+ XMP_VarString & outputStr,
+ XMP_StringPtr newline,
+ XMP_StringPtr indentStr,
+ XMP_Index indent,
+ XMP_Index arraySize,
+ bool isStartTag )
+{
+ if ( (! isStartTag) && (arraySize == 0) ) return;
+
+ for ( XMP_Index level = indent; level > 0; --level ) outputStr += indentStr;
+ if ( isStartTag ) {
+ outputStr += "<rdf:";
+ } else {
+ outputStr += "</rdf:";
+ }
+
+ if ( arrayForm & kXMP_PropArrayIsAlternate ) {
+ outputStr += "Alt";
+ } else if ( arrayForm & kXMP_PropArrayIsOrdered ) {
+ outputStr += "Seq";
+ } else {
+ outputStr += "Bag";
+ }
+
+ if ( isStartTag && (arraySize == 0) ) outputStr += '/';
+ outputStr += '>';
+ outputStr += newline;
+
+} // EmitRDFArrayTag
+
+
+// -------------------------------------------------------------------------------------------------
+// AppendNodeValue
+// ---------------
+//
+// Append a property or qualifier value to the output with appropriate XML escaping. The escaped
+// characters for elements and attributes are '&', '<', '>', and ASCII controls (tab, LF, CR). In
+// addition, '"' is escaped for attributes. For efficiency, this is done in a double loop. The outer
+// loop makes sure the whole value is processed. The inner loop does a contiguous unescaped run
+// followed by one escaped character (if we're not at the end).
+//
+// We depend on parsing and SetProperty logic to make sure there are no invalid ASCII controls in
+// the XMP values. The XML spec only allows tab, LF, and CR. Others are not even allowed as
+// numeric escape sequences.
+
+enum {
+ kForAttribute = true,
+ kForElement = false
+};
+
+static void
+AppendNodeValue ( XMP_VarString & outputStr, const XMP_VarString & value, bool forAttribute )
+{
+
+ unsigned char * runStart = (unsigned char *) value.c_str();
+ unsigned char * runLimit = runStart + value.size();
+ unsigned char * runEnd;
+ unsigned char ch;
+
+ while ( runStart < runLimit ) {
+
+ for ( runEnd = runStart; runEnd < runLimit; ++runEnd ) {
+ ch = *runEnd;
+ if ( forAttribute && (ch == '"') ) break;
+ if ( (ch < 0x20) || (ch == '&') || (ch == '<') || (ch == '>') ) break;
+ }
+
+ outputStr.append ( (char *) runStart, (runEnd - runStart) );
+
+ if ( runEnd < runLimit ) {
+
+ if ( ch < 0x20 ) {
+
+ XMP_Assert ( (ch == kTab) || (ch == kLF) || (ch == kCR) );
+
+ char hexBuf[16];
+ memcpy ( hexBuf, "&#xn;", 10 ); // AUDIT: Length of "&#xn;" is 5, hexBuf size is 16.
+ hexBuf[3] = kHexDigits[ch&0xF];
+ outputStr.append ( hexBuf, 5 );
+
+ } else {
+
+ if ( ch == '"' ) {
+ outputStr += "&quot;";
+ } else if ( ch == '<' ) {
+ outputStr += "&lt;";
+ } else if ( ch == '>' ) {
+ outputStr += "&gt;";
+ } else {
+ XMP_Assert ( ch == '&' );
+ outputStr += "&amp;";
+ }
+
+ }
+
+ ++runEnd;
+
+ }
+
+ runStart = runEnd;
+
+ }
+
+} // AppendNodeValue
+
+
+// -------------------------------------------------------------------------------------------------
+// CanBeRDFAttrProp
+// ----------------
+
+static bool
+CanBeRDFAttrProp ( const XMP_Node * propNode )
+{
+
+ if ( propNode->name[0] == '[' ) return false;
+ if ( ! propNode->qualifiers.empty() ) return false;
+ if ( propNode->options & kXMP_PropValueIsURI ) return false;
+ if ( propNode->options & kXMP_PropCompositeMask ) return false;
+
+ return true;
+
+} // CanBeRDFAttrProp
+
+
+// -------------------------------------------------------------------------------------------------
+// IsRDFAttrQualifier
+// ------------------
+
+static XMP_StringPtr sAttrQualifiers[] = { "xml:lang", "rdf:resource", "rdf:ID", "rdf:bagID", "rdf:nodeID", "" };
+
+static bool
+IsRDFAttrQualifier ( XMP_VarString qualName )
+{
+
+ for ( size_t i = 0; *sAttrQualifiers[i] != 0; ++i ) {
+ if ( qualName == sAttrQualifiers[i] ) return true;
+ }
+
+ return false;
+
+} // IsRDFAttrQualifier
+
+
+// -------------------------------------------------------------------------------------------------
+// SerializePrettyRDFProperty
+// --------------------------
+//
+// Recursively handles the "value" for a node. It does not matter if it is a top level property, a
+// field of a struct, or an item of an array. The indent is that for the property element. An
+// xml:lang qualifier is written as an attribute of the property start tag, not by itself forcing
+// the qualified property form. The patterns below mostly ignore attribute qualifiers like xml:lang.
+// Except for the one struct case, attribute qualifiers don't affect the output form.
+//
+// <ns:UnqualifiedSimpleProperty>value</ns:UnqualifiedSimpleProperty>
+//
+// <ns:UnqualifiedStructProperty rdf:parseType="Resource"> (If no rdf:resource qualifier)
+// ... Fields, same forms as top level properties
+// </ns:UnqualifiedStructProperty>
+//
+// <ns:ResourceStructProperty rdf:resource="URI"
+// ... Fields as attributes
+// >
+//
+// <ns:UnqualifiedArrayProperty>
+// <rdf:Bag> or Seq or Alt
+// ... Array items as rdf:li elements, same forms as top level properties
+// </rdf:Bag>
+// </ns:UnqualifiedArrayProperty>
+//
+// <ns:QualifiedProperty rdf:parseType="Resource">
+// <rdf:value> ... Property "value" following the unqualified forms ... </rdf:value>
+// ... Qualifiers looking like named struct fields
+// </ns:QualifiedProperty>
+
+static void
+SerializePrettyRDFProperty ( const XMP_Node * propNode,
+ XMP_VarString & outputStr,
+ XMP_StringPtr newline,
+ XMP_StringPtr indentStr,
+ XMP_Index indent,
+ bool emitAsRDFValue = false )
+{
+ XMP_Index level;
+ bool emitEndTag = true;
+ bool indentEndTag = true;
+
+ XMP_OptionBits propForm = propNode->options & kXMP_PropCompositeMask;
+
+ // ------------------------------------------------------------------------------------------
+ // Determine the XML element name. Open the start tag with the name and attribute qualifiers.
+
+ XMP_StringPtr elemName = propNode->name.c_str();
+ if ( emitAsRDFValue ) {
+ elemName= "rdf:value";
+ } else if ( *elemName == '[' ) {
+ elemName = "rdf:li";
+ }
+
+ for ( level = indent; level > 0; --level ) outputStr += indentStr;
+ outputStr += '<';
+ outputStr += elemName;
+
+ #define isCompact false
+ bool hasGeneralQualifiers = isCompact; // Might also become true later.
+ bool hasRDFResourceQual = false;
+
+ for ( size_t qualNum = 0, qualLim = propNode->qualifiers.size(); qualNum < qualLim; ++qualNum ) {
+ const XMP_Node * currQual = propNode->qualifiers[qualNum];
+ if ( ! IsRDFAttrQualifier ( currQual->name ) ) {
+ hasGeneralQualifiers = true;
+ } else {
+ if ( currQual->name == "rdf:resource" ) hasRDFResourceQual = true;
+ if ( ! emitAsRDFValue ) {
+ outputStr += ' ';
+ outputStr += currQual->name;
+ outputStr += "=\"";
+ AppendNodeValue ( outputStr, currQual->value, kForAttribute );
+ outputStr += '"';
+ }
+ }
+ }
+
+ // --------------------------------------------------------
+ // Process the property according to the standard patterns.
+
+ if ( hasGeneralQualifiers && (! emitAsRDFValue) ) {
+
+ // -----------------------------------------------------------------------------------------
+ // This node has general, non-attribute, qualifiers. Emit using the qualified property form.
+ // ! The value is output by a recursive call ON THE SAME NODE with emitAsRDFValue set.
+
+ if ( hasRDFResourceQual ) {
+ XMP_Throw ( "Can't mix rdf:resource and general qualifiers", kXMPErr_BadRDF );
+ }
+
+ outputStr += " rdf:parseType=\"Resource\">";
+ outputStr += newline;
+
+ SerializePrettyRDFProperty ( propNode, outputStr, newline, indentStr, indent+1, true );
+
+ for ( size_t qualNum = 0, qualLim = propNode->qualifiers.size(); qualNum < qualLim; ++qualNum ) {
+ const XMP_Node * currQual = propNode->qualifiers[qualNum];
+ if ( IsRDFAttrQualifier ( currQual->name ) ) continue;
+ SerializePrettyRDFProperty ( currQual, outputStr, newline, indentStr, indent+1 );
+ }
+
+ } else {
+
+ // --------------------------------------------------------------------
+ // This node has no general qualifiers. Emit using an unqualified form.
+
+ if ( propForm == 0 ) {
+
+ // --------------------------
+ // This is a simple property.
+
+ if ( propNode->options & kXMP_PropValueIsURI ) {
+ outputStr += " rdf:resource=\"";
+ AppendNodeValue ( outputStr, propNode->value, kForAttribute );
+ outputStr += "\"/>";
+ outputStr += newline;
+ emitEndTag = false;
+ } else if ( propNode->value.empty() ) {
+ outputStr += "/>";
+ outputStr += newline;
+ emitEndTag = false;
+ } else {
+ outputStr += '>';
+ AppendNodeValue ( outputStr, propNode->value, kForElement );
+ indentEndTag = false;
+ }
+
+ } else if ( propForm & kXMP_PropValueIsArray ) {
+
+ // This is an array.
+ outputStr += '>';
+ outputStr += newline;
+ EmitRDFArrayTag ( propForm, outputStr, newline, indentStr, indent+1, propNode->children.size(), kIsStartTag );
+ if ( XMP_ArrayIsAltText(propNode->options) ) NormalizeLangArray ( (XMP_Node*)propNode );
+ for ( size_t childNum = 0, childLim = propNode->children.size(); childNum < childLim; ++childNum ) {
+ const XMP_Node * currChild = propNode->children[childNum];
+ SerializePrettyRDFProperty ( currChild, outputStr, newline, indentStr, indent+2 );
+ }
+ EmitRDFArrayTag ( propForm, outputStr, newline, indentStr, indent+1, propNode->children.size(), kIsEndTag );
+
+
+ } else if ( ! hasRDFResourceQual ) {
+
+ // This is a "normal" struct, use the rdf:parseType="Resource" form.
+ XMP_Assert ( propForm & kXMP_PropValueIsStruct );
+ if ( propNode->children.size() == 0 ) {
+ outputStr += " rdf:parseType=\"Resource\"/>";
+ outputStr += newline;
+ emitEndTag = false;
+ } else {
+ outputStr += " rdf:parseType=\"Resource\">";
+ outputStr += newline;
+ for ( size_t childNum = 0, childLim = propNode->children.size(); childNum < childLim; ++childNum ) {
+ const XMP_Node * currChild = propNode->children[childNum];
+ SerializePrettyRDFProperty ( currChild, outputStr, newline, indentStr, indent+1 );
+ }
+ }
+
+ } else {
+
+ // This is a struct with an rdf:resource attribute, use the "empty property element" form.
+ XMP_Assert ( propForm & kXMP_PropValueIsStruct );
+ for ( size_t childNum = 0, childLim = propNode->children.size(); childNum < childLim; ++childNum ) {
+ const XMP_Node * currChild = propNode->children[childNum];
+ if ( ! CanBeRDFAttrProp ( currChild ) ) {
+ XMP_Throw ( "Can't mix rdf:resource and complex fields", kXMPErr_BadRDF );
+ }
+ outputStr += newline;
+ for ( level = indent+1; level > 0; --level ) outputStr += indentStr;
+ outputStr += ' ';
+ outputStr += currChild->name;
+ outputStr += "=\"";
+ outputStr += currChild->value;
+ outputStr += '"';
+ }
+ outputStr += "/>";
+ outputStr += newline;
+ emitEndTag = false;
+
+ }
+
+ }
+
+ // ----------------------------------
+ // Emit the property element end tag.
+
+ if ( emitEndTag ) {
+ if ( indentEndTag ) for ( level = indent; level > 0; --level ) outputStr += indentStr;
+ outputStr += "</";
+ outputStr += elemName;
+ outputStr += '>';
+ outputStr += newline;
+ }
+
+} // SerializePrettyRDFProperty
+
+
+// -------------------------------------------------------------------------------------------------
+// SerializePrettyRDFSchema
+// ------------------------
+//
+// Each schema's properties are written in a separate rdf:Description element. All of the necessary
+// namespaces are declared in the rdf:Description element. The baseIndent is the base level for the
+// entire serialization, that of the x:xmpmeta element. An xml:lang qualifier is written as an
+// attribute of the property start tag, not by itself forcing the qualified property form.
+//
+// <rdf:Description rdf:about="TreeName"
+// xmlns:ns="URI" ... >
+//
+// ... The actual properties of the schema, see SerializePrettyRDFProperty
+//
+// <!-- ns1:Alias is aliased to ns2:Actual --> ... If alias comments are wanted
+//
+// </rdf:Description>
+
+static void
+SerializePrettyRDFSchema ( const XMP_VarString & treeName,
+ const XMP_Node * schemaNode,
+ XMP_VarString & outputStr,
+ XMP_OptionBits options,
+ XMP_StringPtr newline,
+ XMP_StringPtr indentStr,
+ XMP_Index baseIndent )
+{
+ XMP_Assert ( schemaNode->options & kXMP_SchemaNode );
+ XMP_Assert ( schemaNode->qualifiers.empty() );
+
+ // Write the rdf:Description start tag with the namespace declarations.
+
+ XMP_Index level;
+ for ( level = baseIndent+2; level > 0; --level ) outputStr += indentStr;
+ outputStr += kRDF_SchemaStart;
+ outputStr += '"';
+ outputStr += treeName;
+ outputStr += '"';
+
+ size_t totalLen = 8; // Start at 8 for "xml:rdf:".
+ XMP_cStringMapPos currPos = sNamespacePrefixToURIMap->begin();
+ XMP_cStringMapPos endPos = sNamespacePrefixToURIMap->end();
+ for ( ; currPos != endPos; ++currPos ) totalLen += currPos->first.size();
+
+ XMP_VarString usedNS;
+ usedNS.reserve ( totalLen );
+ usedNS = "xml:rdf:";
+ DeclareUsedNamespaces ( schemaNode, usedNS, outputStr, newline, indentStr, baseIndent+4 );
+
+ outputStr += ">";
+ outputStr += newline;
+
+ // Write alias comments, if wanted.
+
+ if ( options & kXMP_WriteAliasComments ) { // *** Hoist into a routine, used for Plain XMP also.
+
+ #if 0 // *** Buggy, disable for now.
+
+ XMP_cAliasMapPos aliasPos = sRegisteredAliasMap->begin();
+ XMP_cAliasMapPos aliasEnd = sRegisteredAliasMap->end();
+
+ for ( ; aliasPos != aliasEnd; ++aliasPos ) {
+
+ size_t nsPos = aliasPos->first.find ( schemaNode->value );
+ if ( nsPos == XMP_VarString::npos ) continue;
+ XMP_Assert ( nsPos == 0 );
+
+ for ( level = baseIndent+3; level > 0; --level ) outputStr += indentStr;
+
+ outputStr += "<!-- ";
+ outputStr += aliasPos->first;
+ outputStr += " is aliased to ";
+ for ( size_t step = 1, stepLim = aliasPos->second.size(); step != stepLim; ++step ) {
+ outputStr += aliasPos->second[step].step;
+ }
+ outputStr += " -->";
+ outputStr += newline;
+
+ }
+
+ #endif
+
+ }
+
+ // Write each of the schema's actual properties.
+ for ( size_t propNum = 0, propLim = schemaNode->children.size(); propNum < propLim; ++propNum ) {
+ const XMP_Node * currProp = schemaNode->children[propNum];
+ SerializePrettyRDFProperty ( currProp, outputStr, newline, indentStr, baseIndent+3 );
+ }
+
+ // Write the rdf:Description end tag.
+ for ( level = baseIndent+2; level > 0; --level ) outputStr += indentStr;
+ outputStr += kRDF_SchemaEnd;
+ outputStr += newline;
+
+} // SerializePrettyRDFSchema
+
+
+// -------------------------------------------------------------------------------------------------
+// SerializeCompactRDFAttrProps
+// ----------------------------
+//
+// Write each of the parent's simple unqualified properties as an attribute. Returns true if all
+// of the properties are written as attributes.
+
+static bool
+SerializeCompactRDFAttrProps ( const XMP_Node * parentNode,
+ XMP_VarString & outputStr,
+ XMP_StringPtr newline,
+ XMP_StringPtr indentStr,
+ XMP_Index indent )
+{
+ size_t prop, propLim;
+ bool allAreAttrs = true;
+
+ for ( prop = 0, propLim = parentNode->children.size(); prop != propLim; ++prop ) {
+
+ const XMP_Node * currProp = parentNode->children[prop];
+ if ( ! CanBeRDFAttrProp ( currProp ) ) {
+ allAreAttrs = false;
+ continue;
+ }
+
+ outputStr += newline;
+ for ( XMP_Index level = indent; level > 0; --level ) outputStr += indentStr;
+ outputStr += currProp->name;
+ outputStr += "=\"";
+ AppendNodeValue ( outputStr, currProp->value, kForAttribute );
+ outputStr += '"';
+
+ }
+
+ return allAreAttrs;
+
+} // SerializeCompactRDFAttrProps
+
+
+// -------------------------------------------------------------------------------------------------
+// SerializeCompactRDFElemProps
+// ----------------------------
+//
+// Recursively handles the "value" for a node that must be written as an RDF property element. It
+// does not matter if it is a top level property, a field of a struct, or an item of an array. The
+// indent is that for the property element. The patterns bwlow ignore attribute qualifiers such as
+// xml:lang, they don't affect the output form.
+//
+// <ns:UnqualifiedStructProperty-1
+// ... The fields as attributes, if all are simple and unqualified
+// />
+//
+// <ns:UnqualifiedStructProperty-2 rdf:parseType="Resource">
+// ... The fields as elements, if none are simple and unqualified
+// </ns:UnqualifiedStructProperty-2>
+//
+// <ns:UnqualifiedStructProperty-3>
+// <rdf:Description
+// ... The simple and unqualified fields as attributes
+// >
+// ... The compound or qualified fields as elements
+// </rdf:Description>
+// </ns:UnqualifiedStructProperty-3>
+//
+// <ns:UnqualifiedArrayProperty>
+// <rdf:Bag> or Seq or Alt
+// ... Array items as rdf:li elements, same forms as top level properties
+// </rdf:Bag>
+// </ns:UnqualifiedArrayProperty>
+//
+// <ns:QualifiedProperty rdf:parseType="Resource">
+// <rdf:value> ... Property "value" following the unqualified forms ... </rdf:value>
+// ... Qualifiers looking like named struct fields
+// </ns:QualifiedProperty>
+
+// *** Consider numbered array items, but has compatibility problems.
+// *** Consider qualified form with rdf:Description and attributes.
+
+static void
+SerializeCompactRDFElemProps ( const XMP_Node * parentNode,
+ XMP_VarString & outputStr,
+ XMP_StringPtr newline,
+ XMP_StringPtr indentStr,
+ XMP_Index indent )
+{
+ XMP_Index level;
+
+ for ( size_t prop = 0, propLim = parentNode->children.size(); prop != propLim; ++prop ) {
+
+ const XMP_Node * propNode = parentNode->children[prop];
+ if ( CanBeRDFAttrProp ( propNode ) ) continue;
+
+ bool emitEndTag = true;
+ bool indentEndTag = true;
+
+ XMP_OptionBits propForm = propNode->options & kXMP_PropCompositeMask;
+
+ // -----------------------------------------------------------------------------------
+ // Determine the XML element name, write the name part of the start tag. Look over the
+ // qualifiers to decide on "normal" versus "rdf:value" form. Emit the attribute
+ // qualifiers at the same time.
+
+ XMP_StringPtr elemName = propNode->name.c_str();
+ if ( *elemName == '[' ) elemName = "rdf:li";
+
+ for ( level = indent; level > 0; --level ) outputStr += indentStr;
+ outputStr += '<';
+ outputStr += elemName;
+
+ #define isCompact false
+ bool hasGeneralQualifiers = isCompact; // Might also become true later.
+ bool hasRDFResourceQual = false;
+
+ for ( size_t qualNum = 0, qualLim = propNode->qualifiers.size(); qualNum < qualLim; ++qualNum ) {
+ const XMP_Node * currQual = propNode->qualifiers[qualNum];
+ if ( ! IsRDFAttrQualifier ( currQual->name ) ) {
+ hasGeneralQualifiers = true;
+ } else {
+ if ( currQual->name == "rdf:resource" ) hasRDFResourceQual = true;
+ outputStr += ' ';
+ outputStr += currQual->name;
+ outputStr += "=\"";
+ AppendNodeValue ( outputStr, currQual->value, kForAttribute );
+ outputStr += '"';
+ }
+ }
+
+ // --------------------------------------------------------
+ // Process the property according to the standard patterns.
+
+ if ( hasGeneralQualifiers ) {
+
+ // -------------------------------------------------------------------------------------
+ // The node has general qualifiers, ones that can't be attributes on a property element.
+ // Emit using the qualified property pseudo-struct form. The value is output by a call
+ // to SerializePrettyRDFProperty with emitAsRDFValue set.
+
+ // *** We're losing compactness in the calls to SerializePrettyRDFProperty.
+ // *** Should refactor to have SerializeCompactRDFProperty that does one node.
+
+ outputStr += " rdf:parseType=\"Resource\">";
+ outputStr += newline;
+
+ SerializePrettyRDFProperty ( propNode, outputStr, newline, indentStr, indent+1, true );
+
+ size_t qualNum = 0;
+ size_t qualLim = propNode->qualifiers.size();
+ if ( propNode->options & kXMP_PropHasLang ) ++qualNum;
+
+ for ( ; qualNum < qualLim; ++qualNum ) {
+ const XMP_Node * currQual = propNode->qualifiers[qualNum];
+ SerializePrettyRDFProperty ( currQual, outputStr, newline, indentStr, indent+1 );
+ }
+
+ } else {
+
+ // --------------------------------------------------------------------
+ // This node has only attribute qualifiers. Emit as a property element.
+
+ if ( propForm == 0 ) {
+
+ // --------------------------
+ // This is a simple property.
+
+ if ( propNode->options & kXMP_PropValueIsURI ) {
+ outputStr += " rdf:resource=\"";
+ AppendNodeValue ( outputStr, propNode->value, kForAttribute );
+ outputStr += "\"/>";
+ outputStr += newline;
+ emitEndTag = false;
+ } else if ( propNode->value.empty() ) {
+ outputStr += "/>";
+ outputStr += newline;
+ emitEndTag = false;
+ } else {
+ outputStr += '>';
+ AppendNodeValue ( outputStr, propNode->value, kForElement );
+ indentEndTag = false;
+ }
+
+ } else if ( propForm & kXMP_PropValueIsArray ) {
+
+ // -----------------
+ // This is an array.
+
+ outputStr += '>';
+ outputStr += newline;
+ EmitRDFArrayTag ( propForm, outputStr, newline, indentStr, indent+1, propNode->children.size(), kIsStartTag );
+
+ if ( XMP_ArrayIsAltText(propNode->options) ) NormalizeLangArray ( (XMP_Node*)propNode );
+ SerializeCompactRDFElemProps ( propNode, outputStr, newline, indentStr, indent+2 );
+
+ EmitRDFArrayTag ( propForm, outputStr, newline, indentStr, indent+1, propNode->children.size(), kIsEndTag );
+
+ } else {
+
+ // ----------------------
+ // This must be a struct.
+
+ XMP_Assert ( propForm & kXMP_PropValueIsStruct );
+
+ bool hasAttrFields = false;
+ bool hasElemFields = false;
+
+ size_t field, fieldLim;
+ for ( field = 0, fieldLim = propNode->children.size(); field != fieldLim; ++field ) {
+ XMP_Node * currField = propNode->children[field];
+ if ( CanBeRDFAttrProp ( currField ) ) {
+ hasAttrFields = true;
+ if ( hasElemFields ) break; // No sense looking further.
+ } else {
+ hasElemFields = true;
+ if ( hasAttrFields ) break; // No sense looking further.
+ }
+ }
+
+ if ( hasRDFResourceQual && hasElemFields ) {
+ XMP_Throw ( "Can't mix rdf:resource qualifier and element fields", kXMPErr_BadRDF );
+ }
+
+ if ( propNode->children.size() == 0 ) {
+
+ // Catch an empty struct as a special case. The case below would emit an empty
+ // XML element, which gets reparsed as a simple property with an empty value.
+ outputStr += " rdf:parseType=\"Resource\"/>";
+ outputStr += newline;
+ emitEndTag = false;
+
+ } else if ( ! hasElemFields ) {
+
+ // All fields can be attributes, use the emptyPropertyElt form.
+ SerializeCompactRDFAttrProps ( propNode, outputStr, newline, indentStr, indent+1 );
+ outputStr += "/>";
+ outputStr += newline;
+ emitEndTag = false;
+
+ } else if ( ! hasAttrFields ) {
+
+ // All fields must be elements, use the parseTypeResourcePropertyElt form.
+ outputStr += " rdf:parseType=\"Resource\">";
+ outputStr += newline;
+ SerializeCompactRDFElemProps ( propNode, outputStr, newline, indentStr, indent+1 );
+
+ } else {
+
+ // Have a mix of attributes and elements, use an inner rdf:Description.
+ outputStr += '>';
+ outputStr += newline;
+ for ( level = indent+1; level > 0; --level ) outputStr += indentStr;
+ outputStr += "<rdf:Description";
+ SerializeCompactRDFAttrProps ( propNode, outputStr, newline, indentStr, indent+2 );
+ outputStr += ">";
+ outputStr += newline;
+ SerializeCompactRDFElemProps ( propNode, outputStr, newline, indentStr, indent+1 );
+ for ( level = indent+1; level > 0; --level ) outputStr += indentStr;
+ outputStr += kRDF_StructEnd;
+ outputStr += newline;
+
+ }
+
+ }
+
+ }
+
+ // ----------------------------------
+ // Emit the property element end tag.
+
+ if ( emitEndTag ) {
+ if ( indentEndTag ) for ( level = indent; level > 0; --level ) outputStr += indentStr;
+ outputStr += "</";
+ outputStr += elemName;
+ outputStr += '>';
+ outputStr += newline;
+ }
+
+ }
+
+} // SerializeCompactRDFElemProps
+
+
+// -------------------------------------------------------------------------------------------------
+// SerializeCompactRDFSchemas
+// --------------------------
+//
+// All properties from all schema are written in a single rdf:Description element, as are all of the
+// necessary namespace declarations. The baseIndent is the base level for the entire serialization,
+// that of the x:xmpmeta element. The x:xmpmeta and rdf:RDF elements have already been written.
+//
+// Top level simple unqualified properties are written as attributes of the (only) rdf:Description
+// element. Structs, arrays, and qualified properties are written by SerializeCompactRDFElemProp. An
+// xml:lang qualifier on a simple property prevents the attribute form.
+//
+// <rdf:Description rdf:about="TreeName"
+// xmlns:ns="URI" ...
+// ns:UnqualifiedSimpleProperty="value" ... >
+// ... The remaining properties of the schema, see SerializeCompactRDFElemProps
+// </rdf:Description>
+
+static void
+SerializeCompactRDFSchemas ( const XMP_Node & xmpTree,
+ XMP_VarString & outputStr,
+ XMP_StringPtr newline,
+ XMP_StringPtr indentStr,
+ XMP_Index baseIndent )
+{
+ XMP_Index level;
+ size_t schema, schemaLim;
+
+ // Begin the rdf:Description start tag.
+ for ( level = baseIndent+2; level > 0; --level ) outputStr += indentStr;
+ outputStr += kRDF_SchemaStart;
+ outputStr += '"';
+ outputStr += xmpTree.name;
+ outputStr += '"';
+
+ // Write all necessary xmlns attributes.
+
+ size_t totalLen = 8; // Start at 8 for "xml:rdf:".
+ XMP_cStringMapPos currPos = sNamespacePrefixToURIMap->begin();
+ XMP_cStringMapPos endPos = sNamespacePrefixToURIMap->end();
+ for ( ; currPos != endPos; ++currPos ) totalLen += currPos->first.size();
+
+ XMP_VarString usedNS;
+ usedNS.reserve ( totalLen );
+ usedNS = "xml:rdf:";
+
+ for ( schema = 0, schemaLim = xmpTree.children.size(); schema != schemaLim; ++schema ) {
+ const XMP_Node * currSchema = xmpTree.children[schema];
+ DeclareUsedNamespaces ( currSchema, usedNS, outputStr, newline, indentStr, baseIndent+4 );
+ }
+
+ // Write the top level "attrProps" and close the rdf:Description start tag.
+ bool allAreAttrs = true;
+ for ( schema = 0, schemaLim = xmpTree.children.size(); schema != schemaLim; ++schema ) {
+ const XMP_Node * currSchema = xmpTree.children[schema];
+ allAreAttrs &= SerializeCompactRDFAttrProps ( currSchema, outputStr, newline, indentStr, baseIndent+3 );
+ }
+ if ( ! allAreAttrs ) {
+ outputStr += ">";
+ outputStr += newline;
+ } else {
+ outputStr += "/>";
+ outputStr += newline;
+ return; // ! Done if all properties in all schema are written as attributes.
+ }
+
+ // Write the remaining properties for each schema.
+ for ( schema = 0, schemaLim = xmpTree.children.size(); schema != schemaLim; ++schema ) {
+ const XMP_Node * currSchema = xmpTree.children[schema];
+ SerializeCompactRDFElemProps ( currSchema, outputStr, newline, indentStr, baseIndent+3 );
+ }
+
+ // Write the rdf:Description end tag.
+ // *** Elide the end tag if everything (all props in all schema) is an attr.
+ for ( level = baseIndent+2; level > 0; --level ) outputStr += indentStr;
+ outputStr += kRDF_SchemaEnd;
+ outputStr += newline;
+
+} // SerializeCompactRDFSchemas
+
+
+// -------------------------------------------------------------------------------------------------
+// SerializeAsRDF
+// --------------
+//
+// <?xpacket begin... ?>
+// <x:xmpmeta xmlns:x=... >
+// <rdf:RDF xmlns:rdf=... >
+//
+// ... The properties, see SerializePrettyRDFSchema or SerializeCompactRDFSchemas
+//
+// </rdf:RDF>
+// </x:xmpmeta>
+// <?xpacket end... ?>
+
+// *** Need to strip empty arrays?
+// *** Option to strip/keep empty structs?
+// *** Need to verify handling of rdf:type qualifiers in pretty and compact.
+// *** Need to verify round tripping of rdf:ID and similar qualifiers, see RDF 7.2.21.
+// *** Check cases of rdf:resource plus explicit attr qualifiers (like xml:lang).
+
+static void
+SerializeAsRDF ( const XMPMeta & xmpObj,
+ XMP_VarString & headStr, // Everything up to the padding.
+ XMP_VarString & tailStr, // Everything after the padding.
+ XMP_OptionBits options,
+ XMP_StringPtr newline,
+ XMP_StringPtr indentStr,
+ XMP_Index baseIndent )
+{
+ const size_t treeNameLen = xmpObj.tree.name.size();
+ const size_t indentLen = strlen ( indentStr );
+
+ // First estimate the worst case space and reserve room in the output string. This optimization
+ // avoids reallocating and copying the output as it grows. The initial count does not look at
+ // the values of properties, so it does not account for character entities, e.g. &#xA; for newline.
+ // Since there can be a lot of these in things like the base 64 encoding of a large thumbnail,
+ // inflate the count by 1/4 (easy to do) to accommodate.
+
+ // *** Need to include estimate for alias comments.
+
+ size_t outputLen = 2 * (strlen(kPacketHeader) + strlen(kRDF_XMPMetaStart) + strlen(kRDF_RDFStart) + 3*baseIndent*indentLen);
+
+ for ( size_t schemaNum = 0, schemaLim = xmpObj.tree.children.size(); schemaNum < schemaLim; ++schemaNum ) {
+ const XMP_Node * currSchema = xmpObj.tree.children[schemaNum];
+ outputLen += 2*(baseIndent+2)*indentLen + strlen(kRDF_SchemaStart) + treeNameLen + strlen(kRDF_SchemaEnd) + 2;
+ outputLen += EstimateRDFSize ( currSchema, baseIndent+2, indentLen );
+ }
+
+ outputLen += (outputLen >> 2); // Inflate by 1/4, an empirical fudge factor.
+
+ // Now generate the RDF into the head string as UTF-8.
+
+ XMP_Index level;
+
+ headStr.erase();
+ headStr.reserve ( outputLen );
+
+ // Write the packet header PI.
+ if ( ! (options & kXMP_OmitPacketWrapper) ) {
+ for ( level = baseIndent; level > 0; --level ) headStr += indentStr;
+ headStr += kPacketHeader;
+ headStr += newline;
+ }
+
+ // Write the xmpmeta element's start tag.
+ for ( level = baseIndent; level > 0; --level ) headStr += indentStr;
+ headStr += kRDF_XMPMetaStart;
+ headStr += kXMPCore_VersionMessage "\">";
+ headStr += newline;
+
+ // Write the rdf:RDF start tag.
+ for ( level = baseIndent+1; level > 0; --level ) headStr += indentStr;
+ headStr += kRDF_RDFStart;
+ headStr += newline;
+
+ // Write all of the properties.
+ if ( options & kXMP_UseCompactFormat ) {
+ SerializeCompactRDFSchemas ( xmpObj.tree, headStr, newline, indentStr, baseIndent );
+ } else {
+ if ( xmpObj.tree.children.size() > 0 ) {
+ for ( size_t schemaNum = 0, schemaLim = xmpObj.tree.children.size(); schemaNum < schemaLim; ++schemaNum ) {
+ const XMP_Node * currSchema = xmpObj.tree.children[schemaNum];
+ SerializePrettyRDFSchema ( xmpObj.tree.name, currSchema, headStr, options, newline, indentStr, baseIndent );
+ }
+ } else {
+ for ( XMP_Index level = baseIndent+2; level > 0; --level ) headStr += indentStr;
+ headStr += kRDF_SchemaStart; // Special case an empty XMP object.
+ headStr += '"';
+ headStr += xmpObj.tree.name;
+ headStr += "\"/>";
+ headStr += newline;
+ }
+ }
+
+ // Write the rdf:RDF end tag.
+ for ( level = baseIndent+1; level > 0; --level ) headStr += indentStr;
+ headStr += kRDF_RDFEnd;
+ headStr += newline;
+
+ // Write the xmpmeta end tag.
+ for ( level = baseIndent; level > 0; --level ) headStr += indentStr;
+ headStr += kRDF_XMPMetaEnd;
+ headStr += newline;
+
+ // Write the packet trailer PI into the tail string as UTF-8.
+ tailStr.erase();
+ if ( ! (options & kXMP_OmitPacketWrapper) ) {
+ tailStr.reserve ( strlen(kPacketTrailer) + (strlen(indentStr) * baseIndent) );
+ for ( level = baseIndent; level > 0; --level ) tailStr += indentStr;
+ tailStr += kPacketTrailer;
+ if ( options & kXMP_ReadOnlyPacket ) tailStr[tailStr.size()-4] = 'r';
+ }
+
+ // ! This assert is just a performance check, to see if the reserve was enough.
+ // *** XMP_Assert ( headStr.size() <= outputLen );
+ // *** Don't use an assert. Think of some way to track this without risk of aborting the client.
+
+} // SerializeAsRDF
+
+// -------------------------------------------------------------------------------------------------
+// SerializeToBuffer
+// -----------------
+
+void
+XMPMeta::SerializeToBuffer ( XMP_StringPtr * rdfString,
+ XMP_StringLen * rdfSize,
+ XMP_OptionBits options,
+ XMP_StringLen padding,
+ XMP_StringPtr newline,
+ XMP_StringPtr indentStr,
+ XMP_Index baseIndent ) const
+{
+ XMP_Assert ( (rdfString != 0) && (rdfSize != 0) && (newline != 0) && (indentStr != 0) );
+
+ // Fix up some default parameters.
+
+ enum { kDefaultPad = 2048 };
+ size_t unicodeUnitSize = 1;
+ XMP_OptionBits charEncoding = options & kXMP_EncodingMask;
+
+ if ( charEncoding != kXMP_EncodeUTF8 ) {
+ if ( options & _XMP_UTF16_Bit ) {
+ if ( options & _XMP_UTF32_Bit ) XMP_Throw ( "Can't use both _XMP_UTF16_Bit and _XMP_UTF32_Bit", kXMPErr_BadOptions );
+ unicodeUnitSize = 2;
+ } else if ( options & _XMP_UTF32_Bit ) {
+ unicodeUnitSize = 4;
+ } else {
+ XMP_Throw ( "Can't use _XMP_LittleEndian_Bit by itself", kXMPErr_BadOptions );
+ }
+ }
+
+ if ( options & kXMP_OmitAllFormatting ) {
+ newline = " "; // ! Yes, a space for "newline". This ensures token separation.
+ indentStr = "";
+ } else {
+ if ( *newline == 0 ) newline = "\xA"; // Linefeed
+ if ( *indentStr == 0 ) {
+ indentStr = " ";
+ if ( ! (options & kXMP_UseCompactFormat) ) indentStr = " ";
+ }
+ }
+
+ if ( options & kXMP_ExactPacketLength ) {
+ if ( options & (kXMP_OmitPacketWrapper | kXMP_IncludeThumbnailPad) ) {
+ XMP_Throw ( "Inconsistent options for exact size serialize", kXMPErr_BadOptions );
+ }
+ if ( (padding & (unicodeUnitSize-1)) != 0 ) {
+ XMP_Throw ( "Exact size must be a multiple of the Unicode element", kXMPErr_BadOptions );
+ }
+ } else if ( options & kXMP_ReadOnlyPacket ) {
+ if ( options & (kXMP_OmitPacketWrapper | kXMP_IncludeThumbnailPad) ) {
+ XMP_Throw ( "Inconsistent options for read-only packet", kXMPErr_BadOptions );
+ }
+ padding = 0;
+ } else if ( options & kXMP_OmitPacketWrapper ) {
+ if ( options & kXMP_IncludeThumbnailPad ) {
+ XMP_Throw ( "Inconsistent options for non-packet serialize", kXMPErr_BadOptions );
+ }
+ padding = 0;
+ } else {
+ if ( padding == 0 ) padding = kDefaultPad * unicodeUnitSize;
+ if ( options & kXMP_IncludeThumbnailPad ) {
+ if ( ! this->DoesPropertyExist ( kXMP_NS_XMP, "Thumbnails" ) ) padding += (10000 * unicodeUnitSize); // *** Need a better estimate.
+ }
+ }
+
+ // Serialize as UTF-8, then convert to UTF-16 or UTF-32 if necessary, and assemble with the padding and tail.
+
+ std::string tailStr;
+
+ SerializeAsRDF ( *this, *sOutputStr, tailStr, options, newline, indentStr, baseIndent );
+ if ( charEncoding == kXMP_EncodeUTF8 ) {
+
+ if ( options & kXMP_ExactPacketLength ) {
+ size_t minSize = sOutputStr->size() + tailStr.size();
+ if ( minSize > padding ) XMP_Throw ( "Can't fit into specified packet size", kXMPErr_BadSerialize );
+ padding -= minSize; // Now the actual amount of padding to add.
+ }
+
+ size_t newlineLen = strlen ( newline );
+
+ if ( padding < newlineLen ) {
+ sOutputStr->append ( padding, ' ' );
+ } else {
+ padding -= newlineLen; // Write this newline last.
+ while ( padding >= (100 + newlineLen) ) {
+ sOutputStr->append ( 100, ' ' );
+ *sOutputStr += newline;
+ padding -= (100 + newlineLen);
+ }
+ sOutputStr->append ( padding, ' ' );
+ *sOutputStr += newline;
+ }
+
+ *sOutputStr += tailStr;
+
+ } else {
+
+ // Need to convert the encoding. Swap the UTF-8 into a local string and convert back. Assemble everything.
+
+ XMP_VarString utf8Str, newlineStr;
+ bool bigEndian = ((charEncoding & _XMP_LittleEndian_Bit) == 0);
+
+ if ( charEncoding & _XMP_UTF16_Bit ) {
+
+ std::string padStr ( " " ); padStr[0] = 0; // Assume big endian.
+
+ utf8Str.swap ( *sOutputStr );
+ ToUTF16 ( (UTF8Unit*)utf8Str.c_str(), utf8Str.size(), sOutputStr, bigEndian );
+ utf8Str.swap ( tailStr );
+ ToUTF16 ( (UTF8Unit*)utf8Str.c_str(), utf8Str.size(), &tailStr, bigEndian );
+
+ if ( options & kXMP_ExactPacketLength ) {
+ size_t minSize = sOutputStr->size() + tailStr.size();
+ if ( minSize > padding ) XMP_Throw ( "Can't fit into specified packet size", kXMPErr_BadSerialize );
+ padding -= minSize; // Now the actual amount of padding to add (in bytes).
+ }
+
+ utf8Str.assign ( newline );
+ ToUTF16 ( (UTF8Unit*)utf8Str.c_str(), utf8Str.size(), &newlineStr, bigEndian );
+ size_t newlineLen = newlineStr.size();
+
+ if ( padding < newlineLen ) {
+ for ( int i = padding/2; i > 0; --i ) *sOutputStr += padStr;
+ } else {
+ padding -= newlineLen; // Write this newline last.
+ while ( padding >= (200 + newlineLen) ) {
+ for ( int i = 100; i > 0; --i ) *sOutputStr += padStr;
+ *sOutputStr += newlineStr;
+ padding -= (200 + newlineLen);
+ }
+ for ( int i = padding/2; i > 0; --i ) *sOutputStr += padStr;
+ *sOutputStr += newlineStr;
+ }
+
+ *sOutputStr += tailStr;
+
+ } else {
+
+ std::string padStr ( " " ); padStr[0] = padStr[1] = padStr[2] = 0; // Assume big endian.
+ UTF8_to_UTF32_Proc Converter = UTF8_to_UTF32BE;
+
+ if ( charEncoding & _XMP_LittleEndian_Bit ) {
+ padStr[0] = ' '; padStr[1] = padStr[2] = padStr[3] = 0;
+ Converter = UTF8_to_UTF32LE;
+ }
+
+ utf8Str.swap ( *sOutputStr );
+ ToUTF32 ( (UTF8Unit*)utf8Str.c_str(), utf8Str.size(), sOutputStr, bigEndian );
+ utf8Str.swap ( tailStr );
+ ToUTF32 ( (UTF8Unit*)utf8Str.c_str(), utf8Str.size(), &tailStr, bigEndian );
+
+ if ( options & kXMP_ExactPacketLength ) {
+ size_t minSize = sOutputStr->size() + tailStr.size();
+ if ( minSize > padding ) XMP_Throw ( "Can't fit into specified packet size", kXMPErr_BadSerialize );
+ padding -= minSize; // Now the actual amount of padding to add (in bytes).
+ }
+
+ utf8Str.assign ( newline );
+ ToUTF32 ( (UTF8Unit*)utf8Str.c_str(), utf8Str.size(), &newlineStr, bigEndian );
+ size_t newlineLen = newlineStr.size();
+
+ if ( padding < newlineLen ) {
+ for ( int i = padding/4; i > 0; --i ) *sOutputStr += padStr;
+ } else {
+ padding -= newlineLen; // Write this newline last.
+ while ( padding >= (400 + newlineLen) ) {
+ for ( int i = 100; i > 0; --i ) *sOutputStr += padStr;
+ *sOutputStr += newlineStr;
+ padding -= (400 + newlineLen);
+ }
+ for ( int i = padding/4; i > 0; --i ) *sOutputStr += padStr;
+ *sOutputStr += newlineStr;
+ }
+
+ *sOutputStr += tailStr;
+
+ }
+
+ }
+
+ // Return the finished string.
+
+ *rdfString = sOutputStr->c_str();
+ *rdfSize = sOutputStr->size();
+
+} // SerializeToBuffer
+
+// =================================================================================================
diff --git a/source/XMPCore/XMPMeta.cpp b/source/XMPCore/XMPMeta.cpp
new file mode 100644
index 0000000..888d48e
--- /dev/null
+++ b/source/XMPCore/XMPMeta.cpp
@@ -0,0 +1,1471 @@
+// =================================================================================================
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+//
+// Adobe patent application tracking #P435, entitled 'Unique markers to simplify embedding data of
+// one format in a file with a different format', inventors: Sean Parent, Greg Gilley.
+// =================================================================================================
+
+#include "XMP_Environment.h" // ! This must be the first include!
+#include "XMPCore_Impl.hpp"
+
+#include "XMPMeta.hpp"
+#include "XMPIterator.hpp"
+#include "XMPUtils.hpp"
+
+#include "XMP_Version.h"
+#include "UnicodeInlines.incl_cpp"
+#include "UnicodeConversions.hpp"
+
+#if XMP_DebugBuild
+ #include <iostream>
+#endif
+
+using namespace std;
+
+#if XMP_WinBuild
+ #pragma warning ( disable : 4533 ) // initialization of '...' is skipped by 'goto ...'
+ #pragma warning ( disable : 4702 ) // unreachable code
+ #pragma warning ( disable : 4800 ) // forcing value to bool 'true' or 'false' (performance warning)
+ #pragma warning ( disable : 4996 ) // '...' was declared deprecated
+#endif
+
+
+// *** Use the XMP_PropIsXyz (Schema, Simple, Struct, Array, ...) macros
+// *** Add debug codegen checks, e.g. that typical masking operations really work
+// *** Change all uses of strcmp and strncmp to XMP_LitMatch and XMP_LitNMatch
+
+
+// =================================================================================================
+// Local Types and Constants
+// =========================
+
+
+// =================================================================================================
+// Static Variables
+// ================
+
+XMP_VarString * xdefaultName = 0;
+
+// These are embedded version strings.
+
+const char * kXMPCore_EmbeddedVersion = kXMPCore_VersionMessage;
+const char * kXMPCore_EmbeddedCopyright = kXMPCoreName " " kXMP_CopyrightStr;
+
+// =================================================================================================
+// Local Utilities
+// ===============
+
+#define IsHexDigit(ch) ( (('0' <= (ch)) && ((ch) <= '9')) || (('A' <= (ch)) && ((ch) <= 'F')) )
+#define HexDigitValue(ch) ( (((ch) - '0') < 10) ? ((ch) - '0') : ((ch) - 'A' + 10) )
+
+static const char * kTenSpaces = " ";
+#define OutProcPadding(pad) { size_t padLen = (pad); \
+ for ( ; padLen >= 10; padLen -= 10 ) OutProcNChars ( kTenSpaces, 10 ); \
+ for ( ; padLen > 0; padLen -= 1 ) OutProcNChars ( " ", 1 ); }
+
+
+#define OutProcNewline() { status = (*outProc) ( refCon, "\n", 1 ); if ( status != 0 ) goto EXIT; }
+
+#define OutProcNChars(p,n) { status = (*outProc) ( refCon, (p), (n) ); if ( status != 0 ) goto EXIT; }
+
+#define OutProcLiteral(lit) { status = (*outProc) ( refCon, (lit), strlen(lit) ); if ( status != 0 ) goto EXIT; }
+
+#define OutProcString(str) { status = (*outProc) ( refCon, (str).c_str(), (str).size() ); if ( status != 0 ) goto EXIT; }
+
+#define OutProcDecInt(num) { snprintf ( buffer, sizeof(buffer), "%d", (num) ); /* AUDIT: Using sizeof for snprintf length is safe */ \
+ status = (*outProc) ( refCon, buffer, strlen(buffer) ); if ( status != 0 ) goto EXIT; }
+
+#define OutProcHexInt(num) { snprintf ( buffer, sizeof(buffer), "%X", (num) ); /* AUDIT: Using sizeof for snprintf length is safe */ \
+ status = (*outProc) ( refCon, buffer, strlen(buffer) ); if ( status != 0 ) goto EXIT; }
+
+static const char * kIndent = " ";
+#define OutProcIndent(lev) { for ( size_t i = 0; i < (lev); ++i ) OutProcNChars ( kIndent, 3 ); }
+
+
+// -------------------------------------------------------------------------------------------------
+// DumpStringMap
+// -------------
+
+static XMP_Status
+DumpStringMap ( const XMP_StringMap & map, XMP_StringPtr label, XMP_TextOutputProc outProc, void * refCon )
+{
+ XMP_Status status;
+ XMP_cStringMapPos currPos;
+ XMP_cStringMapPos endPos = map.end();
+
+ size_t maxLen = 0;
+ for ( currPos = map.begin(); currPos != endPos; ++currPos ) {
+ size_t currLen = currPos->first.size();
+ if ( currLen > maxLen ) maxLen = currLen;
+ }
+
+ OutProcNewline();
+ OutProcLiteral ( label );
+ OutProcNewline();
+
+ for ( currPos = map.begin(); currPos != endPos; ++currPos ) {
+ OutProcNChars ( " ", 2 );
+ OutProcString ( currPos->first );
+ OutProcPadding ( maxLen - currPos->first.size() );
+ OutProcNChars ( " => ", 4 );
+ OutProcString ( currPos->second );
+ OutProcNewline();
+ }
+
+EXIT:
+ return status;
+
+} // DumpStringMap
+
+
+// -------------------------------------------------------------------------------------------------
+// DumpNodeOptions
+// ---------------
+
+static XMP_Status
+DumpNodeOptions ( XMP_OptionBits options,
+ XMP_TextOutputProc outProc,
+ void * refCon )
+{
+ XMP_Status status;
+ char buffer [32]; // Decimal of a 64 bit int is at most about 20 digits.
+
+ static const char * optNames[] = { " schema", // 0x8000_0000
+ " ?30",
+ " ?29",
+ " -COMMAS-",
+ " ?27", // 0x0800_0000
+ " ?26",
+ " ?25",
+ " ?24",
+ " ?23", // 0x0080_0000
+ " isStale",
+ " isDerived",
+ " isStable",
+ " ?19", // 0x0008_0000
+ " isInternal",
+ " hasAliases",
+ " isAlias",
+ " -AFTER-", // 0x0000_8000
+ " -BEFORE-",
+ " isCompact",
+ " isLangAlt",
+ " isAlt", // 0x0000_0800
+ " isOrdered",
+ " isArray",
+ " isStruct",
+ " hasType", // 0x0000_0080
+ " hasLang",
+ " isQual",
+ " hasQual",
+ " ?3", // 0x0000_0008
+ " ?2",
+ " URI",
+ " ?0" };
+
+ if ( options == 0 ) {
+
+ OutProcNChars ( "(0x0)", 5 );
+
+ } else {
+
+ OutProcNChars ( "(0x", 3 );
+ OutProcHexInt ( options );
+ OutProcNChars ( " :", 2 );
+
+ XMP_OptionBits mask = 0x80000000;
+ for ( int b = 0; b < 32; ++b ) {
+ if ( options & mask ) OutProcLiteral ( optNames[b] );
+ mask = mask >> 1;
+ }
+ OutProcNChars ( ")", 1 );
+
+ }
+
+EXIT:
+ return status;
+
+} // DumpNodeOptions
+
+
+// -------------------------------------------------------------------------------------------------
+// DumpPropertyTree
+// ----------------
+
+// *** Extract the validation code into a separate routine to call on exit in debug builds.
+
+static XMP_Status
+DumpPropertyTree ( const XMP_Node * currNode,
+ int indent,
+ size_t itemIndex,
+ XMP_TextOutputProc outProc,
+ void * refCon )
+{
+ XMP_Status status;
+ char buffer [32]; // Decimal of a 64 bit int is at most about 20 digits.
+
+ OutProcIndent ( (size_t)indent );
+ if ( itemIndex == 0 ) {
+ if ( currNode->options & kXMP_PropIsQualifier ) OutProcNChars ( "? ", 2 );
+ OutProcString ( currNode->name );
+ } else {
+ OutProcNChars ( "[", 1 );
+ OutProcDecInt ( itemIndex );
+ OutProcNChars ( "]", 1 );
+ }
+
+ if ( ! (currNode->options & kXMP_PropCompositeMask) ) {
+ OutProcNChars ( " = \"", 4 );
+ OutProcString ( currNode->value );
+ OutProcNChars ( "\"", 1 );
+ }
+
+ if ( currNode->options != 0 ) {
+ OutProcNChars ( " ", 2 );
+ status = DumpNodeOptions ( currNode->options, outProc, refCon );
+ if ( status != 0 ) goto EXIT;
+ }
+
+ if ( currNode->options & kXMP_PropHasLang ) {
+ if ( currNode->qualifiers.empty() || (currNode->qualifiers[0]->name != "xml:lang") ) {
+ OutProcLiteral ( " ** bad lang flag **" );
+ }
+ }
+ // *** Check rdf:type also.
+
+ if ( ! (currNode->options & kXMP_PropCompositeMask) ) {
+ if ( ! currNode->children.empty() ) OutProcLiteral ( " ** bad children **" );
+ } else if ( currNode->options & kXMP_PropValueIsArray ) {
+ if ( currNode->options & kXMP_PropValueIsStruct ) OutProcLiteral ( " ** bad comp flags **" );
+ } else if ( (currNode->options & kXMP_PropCompositeMask) != kXMP_PropValueIsStruct ) {
+ OutProcLiteral ( " ** bad comp flags **" );
+ }
+
+ #if 0 // *** XMP_DebugBuild
+ if ( (currNode->_namePtr != currNode->name.c_str()) ||
+ (currNode->_valuePtr != currNode->value.c_str()) ) OutProcLiteral ( " ** bad debug string **" );
+ #endif
+
+ OutProcNewline();
+
+ for ( size_t qualNum = 0, qualLim = currNode->qualifiers.size(); qualNum < qualLim; ++qualNum ) {
+
+ const XMP_Node * currQual = currNode->qualifiers[qualNum];
+
+ if ( currQual->parent != currNode ) OutProcLiteral ( "** bad parent link => " );
+ if ( currQual->name == kXMP_ArrayItemName ) OutProcLiteral ( "** bad qual name => " );
+ if ( ! (currQual->options & kXMP_PropIsQualifier) ) OutProcLiteral ( "** bad qual flag => " );
+ if ( currQual->name == "xml:lang" ) {
+ if ( (qualNum != 0) || (! (currNode->options & kXMP_PropHasLang)) ) OutProcLiteral ( "** bad lang qual => " );
+ }
+
+ status = DumpPropertyTree ( currQual, indent+2, 0, outProc, refCon );
+ if ( status != 0 ) goto EXIT;
+
+ }
+
+ for ( size_t childNum = 0, childLim = currNode->children.size(); childNum < childLim; ++childNum ) {
+
+ const XMP_Node * currChild = currNode->children[childNum];
+
+ if ( currChild->parent != currNode ) OutProcLiteral ( "** bad parent link => " );
+ if ( currChild->options & kXMP_PropIsQualifier ) OutProcLiteral ( "** bad qual flag => " );
+
+ if ( currNode->options & kXMP_PropValueIsArray ) {
+ itemIndex = childNum+1;
+ if ( currChild->name != kXMP_ArrayItemName ) OutProcLiteral ( "** bad item name => " );
+ } else {
+ itemIndex = 0;
+ if ( currChild->name == kXMP_ArrayItemName ) OutProcLiteral ( "** bad field name => " );
+ }
+
+ status = DumpPropertyTree ( currChild, indent+1, itemIndex, outProc, refCon );
+ if ( status != 0 ) goto EXIT;
+
+ }
+
+EXIT:
+ return status;
+
+} // DumpPropertyTree
+
+
+// -------------------------------------------------------------------------------------------------
+// DumpXMLTree
+// -----------
+
+#if DumpXMLParseTree
+
+static inline void PutHexByte ( FILE * log, unsigned char ch )
+{
+
+ fprintf ( log, "\\x" );
+ if ( ch < 0x10 ) {
+ fprintf ( log, "%c", kHexDigits[ch] );
+ } else {
+ fprintf ( log, "%c%c", kHexDigits[ch>>4], kHexDigits[ch&0xF] );
+ }
+
+} // PutHexByte
+
+// -------------------------------------------------------------------------------------------------
+
+static void PutClearString ( FILE * log, const std::string & str )
+{
+
+ for ( size_t i = 0; i != str.size(); ++i ) {
+ unsigned char ch = str[i];
+ if ( (0x20 <= ch) && (ch <= 0x7F) ) {
+ fprintf ( log, "%c", ch );
+ } else {
+ PutHexByte ( log, ch );
+ }
+ }
+
+} // PutClearString
+
+// -------------------------------------------------------------------------------------------------
+
+static void DumpXMLTree ( FILE * log, const XML_Node & node, int indent )
+{
+ size_t i;
+
+ #if 0 // *** XMP_DebugBuild
+ if ( (node._namePtr != node.name.c_str()) ||
+ (node._valuePtr != node.value.c_str()) ) fprintf ( log, "*** bad debug string ***\n" );
+ #endif
+
+ for ( i = 0; i != (size_t)indent; ++i ) fprintf ( log, " " );
+
+ switch ( node.kind ) {
+
+ case kRootNode :
+ fprintf ( log, "\nStart of XML tree dump\n\n" );
+ if ( (indent != 0) || (! node.attrs.empty()) ||
+ (! node.ns.empty()) || (! node.name.empty()) || (!node.value.empty()) ) fprintf ( log, " ** invalid root ** \n" );
+ for ( i = 0; i < node.children.size(); ++i ) {
+ XMP_Uns8 kind = node.children[i]->kind;
+ if ( (kind == kRootNode) || (kind == kAttrNode) ) fprintf ( log, " ** invalid child ** \n" );
+ DumpXMLTree ( log, *node.children[i], indent+1 );
+ }
+ fprintf ( log, "\nEnd of XML tree dump\n" );
+ break;
+
+ case kElemNode :
+ fprintf ( log, "Elem %s", node.name.c_str() );
+ if ( indent == 0 ) fprintf ( log, " ** invalid elem ** " );
+ if ( ! node.ns.empty() ) fprintf ( log, " @ %s", node.ns.c_str() );
+ fprintf ( log, "\n" );
+ for ( i = 0; i < node.attrs.size(); ++i ) {
+ XMP_Uns8 kind = node.attrs[i]->kind;
+ if ( kind != kAttrNode ) fprintf ( log, " ** invalid attr ** \n" );
+ DumpXMLTree ( log, *node.attrs[i], indent+2 );
+ }
+ for ( i = 0; i < node.children.size(); ++i ) {
+ XMP_Uns8 kind = node.children[i]->kind;
+ if ( (kind == kRootNode) || (kind == kAttrNode) ) fprintf ( log, " ** invalid child ** \n" );
+ DumpXMLTree ( log, *node.children[i], indent+1 );
+ }
+ break;
+
+ case kAttrNode :
+ fprintf ( log, "Attr %s", node.name.c_str() );
+ if ( (indent == 0) || node.name.empty() || (! node.attrs.empty()) || (! node.children.empty()) ) fprintf ( log, " ** invalid attr ** " );
+ fprintf ( log, " = \"" );
+ PutClearString ( log, node.value );
+ fprintf ( log, "\"" );
+ if ( ! node.ns.empty() ) fprintf ( log, " @ %s", node.ns.c_str() );
+ fprintf ( log, "\n" );
+ break;
+
+ case kCDataNode :
+ if ( (indent == 0) || (! node.ns.empty()) || (! node.name.empty()) ||
+ (! node.attrs.empty()) || (! node.children.empty()) ) fprintf ( log, " ** invalid cdata ** \n" );
+ fprintf ( log, "\"" );
+ PutClearString ( log, node.value );
+ fprintf ( log, "\"\n" );
+ break;
+
+ case kPINode :
+ fprintf ( log, "PI %s", node.name.c_str() );
+ if ( (indent == 0) || node.name.empty() || (! node.children.empty()) ) fprintf ( log, " ** invalid pi ** \n" );
+ if ( ! node.value.empty() ) {
+ fprintf ( log, " <? " );
+ PutClearString ( log, node.value );
+ fprintf ( log, " ?>" );
+ }
+ fprintf ( log, "\n" );
+ break;
+
+ }
+
+} // DumpXMLTree
+
+#endif // DumpXMLParseTree
+
+
+// =================================================================================================
+// Constructors
+// ============
+
+
+XMPMeta::XMPMeta() : tree(XMP_Node(0,"",0)), clientRefs(0), prevTkVer(0), xmlParser(0)
+{
+ // Nothing more to do, clientRefs is incremented in wrapper.
+ #if XMP_TraceCTorDTor
+ printf ( "Default construct XMPMeta @ %.8X\n", this );
+ #endif
+} // XMPMeta
+
+// -------------------------------------------------------------------------------------------------
+
+XMPMeta::~XMPMeta() RELEASE_NO_THROW
+{
+ #if XMP_TraceCTorDTor
+ printf ( "Destruct XMPMeta @ %.8X\n", this );
+ #endif
+
+ XMP_Assert ( this->clientRefs <= 0 );
+ if ( xmlParser != 0 ) delete ( xmlParser );
+ xmlParser = 0;
+
+} // ~XMPMeta
+
+
+// =================================================================================================
+// Class Static Functions
+// ======================
+//
+//
+// =================================================================================================
+
+// -------------------------------------------------------------------------------------------------
+// GetVersionInfo
+// --------------
+
+/* class-static */ void
+XMPMeta::GetVersionInfo ( XMP_VersionInfo * info )
+{
+
+ memset ( info, 0, sizeof(XMP_VersionInfo) );
+
+ info->major = XMP_API_VERSION_MAJOR;
+ info->minor = XMP_API_VERSION_MINOR;
+ info->micro = XMP_API_VERSION_MICRO;
+ info->isDebug = kXMPCore_DebugFlag;
+ info->flags = 0; // ! None defined yet.
+ info->message = kXMPCore_VersionMessage;
+
+} // GetVersionInfo
+
+// -------------------------------------------------------------------------------------------------
+// Initialize
+// ----------
+
+/* class-static */ bool
+XMPMeta::Initialize()
+{
+ // Allocate and initialize static objects.
+
+ ++sXMP_InitCount;
+ if ( sXMP_InitCount > 1 ) return true;
+
+ #if TraceXMPCalls
+ // xmpOut = fopen ( "xmp.out", "w" ); // Coordinate with client glue in WXMP_Common.hpp
+ fprintf ( xmpOut, "XMP initializing\n" ); fflush ( xmpOut );
+ #endif
+
+ sExceptionMessage = new XMP_VarString();
+ XMP_InitMutex ( &sXMPCoreLock );
+ sOutputNS = new XMP_VarString;
+ sOutputStr = new XMP_VarString;
+
+ xdefaultName = new XMP_VarString ( "x-default" );
+
+ sNamespaceURIToPrefixMap = new XMP_StringMap;
+ sNamespacePrefixToURIMap = new XMP_StringMap;
+ sRegisteredAliasMap = new XMP_AliasMap;
+
+ InitializeUnicodeConversions();
+
+ // Register standard namespaces and aliases.
+
+ XMP_StringPtr voidPtr;
+ XMP_StringLen voidLen;
+
+ (void) RegisterNamespace ( kXMP_NS_XML, "xml", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_RDF, "rdf", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_DC, "dc", &voidPtr, &voidLen );
+
+ (void) RegisterNamespace ( kXMP_NS_XMP, "xap", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_PDF, "pdf", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_Photoshop, "photoshop", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_PSAlbum, "album", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_EXIF, "exif", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_EXIF_Aux, "aux", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_TIFF, "tiff", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_PNG, "png", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_JPEG, "jpeg", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_JP2K, "jp2k", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_CameraRaw, "crs", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_ASF, "asf", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_WAV, "wav", &voidPtr, &voidLen );
+
+ (void) RegisterNamespace ( kXMP_NS_AdobeStockPhoto, "bmsp", &voidPtr, &voidLen );
+
+ (void) RegisterNamespace ( kXMP_NS_XMP_Rights, "xapRights", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_XMP_MM, "xapMM", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_XMP_BJ, "xapBJ", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_XMP_Note, "xmpNote", &voidPtr, &voidLen );
+
+ (void) RegisterNamespace ( kXMP_NS_DM, "xmpDM", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_XMP_Text, "xapT", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_XMP_PagedFile, "xapTPg", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_XMP_Graphics, "xapG", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_XMP_Image, "xapGImg", &voidPtr, &voidLen );
+
+ (void) RegisterNamespace ( kXMP_NS_XMP_Font, "stFnt", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_XMP_Dimensions, "stDim", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_XMP_ResourceEvent, "stEvt", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_XMP_ResourceRef, "stRef", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_XMP_ST_Version, "stVer", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_XMP_ST_Job, "stJob", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_XMP_ManifestItem, "stMfs", &voidPtr, &voidLen );
+
+ (void) RegisterNamespace ( kXMP_NS_XMP_IdentifierQual, "xmpidq", &voidPtr, &voidLen );
+
+ (void) RegisterNamespace ( kXMP_NS_IPTCCore, "Iptc4xmpCore", &voidPtr, &voidLen );
+
+ (void) RegisterNamespace ( kXMP_NS_PDFA_Schema, "pdfaSchema", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_PDFA_Property, "pdfaProperty", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_PDFA_Type, "pdfaType", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_PDFA_Field, "pdfaField", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_PDFA_ID, "pdfaid", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_PDFA_Extension, "pdfaExtension", &voidPtr, &voidLen );
+
+ (void) RegisterNamespace ( kXMP_NS_PDFX, "pdfx", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_PDFX_ID, "pdfxid", &voidPtr, &voidLen );
+
+ (void) RegisterNamespace ( "adobe:ns:meta/", "x", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( "http://ns.adobe.com/iX/1.0/", "iX", &voidPtr, &voidLen );
+
+ XMPMeta::RegisterStandardAliases ( "" );
+
+ // Initialize the other core classes.
+
+ if ( ! XMPIterator::Initialize() ) XMP_Throw ( "Failure from XMPIterator::Initialize", kXMPErr_InternalFailure );
+ if ( ! XMPUtils::Initialize() ) XMP_Throw ( "Failure from XMPUtils::Initialize", kXMPErr_InternalFailure );
+
+ // Do miscelaneous semantic checks of types and arithmetic.
+
+ XMP_Assert ( sizeof(XMP_Int8) == 1 );
+ XMP_Assert ( sizeof(XMP_Int16) == 2 );
+ XMP_Assert ( sizeof(XMP_Int32) == 4 );
+ XMP_Assert ( sizeof(XMP_Int64) == 8 );
+ XMP_Assert ( sizeof(XMP_Uns8) == 1 );
+ XMP_Assert ( sizeof(XMP_Uns16) == 2 );
+ XMP_Assert ( sizeof(XMP_Uns32) == 4 );
+ XMP_Assert ( sizeof(XMP_Uns64) == 8 );
+
+ XMP_Assert ( sizeof(XMP_OptionBits) == 4 ); // Check that option masking work on all 32 bits.
+ XMP_OptionBits flag = ~0UL;
+ XMP_Assert ( flag == (XMP_OptionBits)(-1L) );
+ XMP_Assert ( (flag ^ kXMP_PropHasLang) == 0xFFFFFFBFUL );
+ XMP_Assert ( (flag & ~kXMP_PropHasLang) == 0xFFFFFFBFUL );
+
+ XMP_OptionBits opt1 = 0; // Check the general option bit macros.
+ XMP_OptionBits opt2 = ~0UL;
+ XMP_SetOption ( opt1, kXMP_PropValueIsArray );
+ XMP_ClearOption ( opt2, kXMP_PropValueIsArray );
+ XMP_Assert ( opt1 == ~opt2 );
+ XMP_Assert ( XMP_TestOption ( opt1, kXMP_PropValueIsArray ) );
+ XMP_Assert ( ! XMP_TestOption ( opt2, kXMP_PropValueIsArray ) );
+
+ XMP_Assert ( XMP_PropIsSimple ( ~kXMP_PropCompositeMask ) ); // Check the special option bit macros.
+ XMP_Assert ( ! XMP_PropIsSimple ( kXMP_PropValueIsStruct ) );
+ XMP_Assert ( ! XMP_PropIsSimple ( kXMP_PropValueIsArray ) );
+
+ XMP_Assert ( XMP_PropIsStruct ( kXMP_PropValueIsStruct ) );
+ XMP_Assert ( XMP_PropIsArray ( kXMP_PropValueIsArray ) );
+ XMP_Assert ( ! XMP_PropIsStruct ( ~kXMP_PropValueIsStruct ) );
+ XMP_Assert ( ! XMP_PropIsArray ( ~kXMP_PropValueIsArray ) );
+
+ XMP_Assert ( XMP_ArrayIsUnordered ( ~kXMP_PropArrayIsOrdered ) );
+ XMP_Assert ( XMP_ArrayIsOrdered ( kXMP_PropArrayIsOrdered ) );
+ XMP_Assert ( XMP_ArrayIsAlternate ( kXMP_PropArrayIsAlternate ) );
+ XMP_Assert ( XMP_ArrayIsAltText ( kXMP_PropArrayIsAltText ) );
+ XMP_Assert ( ! XMP_ArrayIsUnordered ( kXMP_PropArrayIsOrdered ) );
+ XMP_Assert ( ! XMP_ArrayIsOrdered ( ~kXMP_PropArrayIsOrdered ) );
+ XMP_Assert ( ! XMP_ArrayIsAlternate ( ~kXMP_PropArrayIsAlternate ) );
+ XMP_Assert ( ! XMP_ArrayIsAltText ( ~kXMP_PropArrayIsAltText ) );
+
+ XMP_Assert ( XMP_PropHasQualifiers ( kXMP_PropHasQualifiers ) );
+ XMP_Assert ( XMP_PropIsQualifier ( kXMP_PropIsQualifier ) );
+ XMP_Assert ( XMP_PropHasLang ( kXMP_PropHasLang ) );
+ XMP_Assert ( ! XMP_PropHasQualifiers ( ~kXMP_PropHasQualifiers ) );
+ XMP_Assert ( ! XMP_PropIsQualifier ( ~kXMP_PropIsQualifier ) );
+ XMP_Assert ( ! XMP_PropHasLang ( ~kXMP_PropHasLang ) );
+
+ XMP_Assert ( XMP_NodeIsSchema ( kXMP_SchemaNode ) );
+ XMP_Assert ( XMP_PropIsAlias ( kXMP_PropIsAlias ) );
+ XMP_Assert ( ! XMP_NodeIsSchema ( ~kXMP_SchemaNode ) );
+ XMP_Assert ( ! XMP_PropIsAlias ( ~kXMP_PropIsAlias ) );
+
+ #if 0 // Generally off, enable to hand check generated code.
+ extern XMP_OptionBits opt3, opt4;
+ if ( XMP_TestOption ( opt3, kXMP_PropValueIsArray ) ) opt4 = opt3;
+ if ( ! XMP_TestOption ( opt3, kXMP_PropValueIsStruct ) ) opt4 = opt3;
+ static bool ok1 = XMP_TestOption ( opt4, kXMP_PropValueIsArray );
+ static bool ok2 = ! XMP_TestOption ( opt4, kXMP_PropValueIsStruct );
+ #endif
+
+ // Make sure the embedded info strings are referenced and kept.
+ if ( (kXMPCore_EmbeddedVersion[0] == 0) || (kXMPCore_EmbeddedCopyright[0] == 0) ) return false;
+ return true;
+
+} // Initialize
+
+
+// -------------------------------------------------------------------------------------------------
+// Terminate
+// ---------
+
+#define EliminateGlobal(g) delete ( g ); g = 0
+
+/* class-static */ void
+XMPMeta::Terminate() RELEASE_NO_THROW
+{
+ --sXMP_InitCount;
+ if ( sXMP_InitCount > 0 ) return;
+
+ #if TraceXMPCalls
+ fprintf ( xmpOut, "XMP terminating\n" ); fflush ( xmpOut );
+ // fclose ( xmpOut ); // Coordinate with fopen in XMPMeta::Initialize.
+ #endif
+
+ XMPIterator::Terminate();
+ XMPUtils::Terminate();
+
+ EliminateGlobal ( sNamespaceURIToPrefixMap );
+ EliminateGlobal ( sNamespacePrefixToURIMap );
+ EliminateGlobal ( sRegisteredAliasMap );
+
+ EliminateGlobal ( xdefaultName );
+ EliminateGlobal ( sOutputNS );
+ EliminateGlobal ( sOutputStr );
+ EliminateGlobal ( sExceptionMessage );
+
+ XMP_TermMutex ( sXMPCoreLock );
+
+} // Terminate
+
+
+// -------------------------------------------------------------------------------------------------
+// Unlock
+// ------
+
+/* class-static */ void
+XMPMeta::Unlock ( XMP_OptionBits options )
+{
+ options = options; // Avoid unused parameter warning. // *** Need IgnoreParam macro.
+
+ #if TraceXMPLocking
+ fprintf ( xmpOut, " Unlocking XMP toolkit, count = %d\n", sLockCount ); fflush ( xmpOut );
+ #endif
+ --sLockCount;
+ XMP_Assert ( sLockCount == 0 );
+ XMP_ExitCriticalRegion ( sXMPCoreLock );
+
+} // Unlock
+
+
+// -------------------------------------------------------------------------------------------------
+// UnlockObject
+// ------------
+
+void
+XMPMeta::UnlockObject ( XMP_OptionBits options ) const
+{
+ options = options; // Avoid unused parameter warning.
+
+ XMPMeta::Unlock ( 0 );
+
+} // UnlockObject
+
+
+// -------------------------------------------------------------------------------------------------
+// DumpNamespaces
+// --------------
+//
+// Dump the prefix to URI map (easier to read) and verify that both are consistent and legit.
+
+// *** Should put checks in a separate routine for regular calling in debug builds.
+
+/* class-static */ XMP_Status
+XMPMeta::DumpNamespaces ( XMP_TextOutputProc outProc,
+ void * refCon )
+{
+ XMP_Assert ( outProc != 0 ); // ! Enforced by wrapper.
+ XMP_Status status;
+
+ XMP_StringMapPos p2uEnd = sNamespacePrefixToURIMap->end(); // ! Move up to avoid gcc complaints.
+ XMP_StringMapPos u2pEnd = sNamespaceURIToPrefixMap->end();
+
+ status = DumpStringMap ( *sNamespacePrefixToURIMap, "Dumping namespace prefix to URI map", outProc, refCon );
+ if ( status != 0 ) goto EXIT;
+
+ if ( sNamespacePrefixToURIMap->size() != sNamespaceURIToPrefixMap->size() ) {
+ OutProcLiteral ( "** bad namespace map sizes **" );
+ XMP_Throw ( "Fatal namespace map problem", kXMPErr_InternalFailure );
+ }
+
+ for ( XMP_StringMapPos nsLeft = sNamespacePrefixToURIMap->begin(); nsLeft != p2uEnd; ++nsLeft ) {
+
+ XMP_StringMapPos nsOther = sNamespaceURIToPrefixMap->find ( nsLeft->second );
+ if ( (nsOther == u2pEnd) || (nsLeft != sNamespacePrefixToURIMap->find ( nsOther->second )) ) {
+ OutProcLiteral ( " ** bad namespace URI ** " );
+ OutProcString ( nsLeft->second );
+ goto FAILURE;
+ }
+
+ for ( XMP_StringMapPos nsRight = nsLeft; nsRight != p2uEnd; ++nsRight ) {
+ if ( nsRight == nsLeft ) continue; // ! Can't start at nsLeft+1, no operator+!
+ if ( nsLeft->second == nsRight->second ) {
+ OutProcLiteral ( " ** duplicate namespace URI ** " );
+ OutProcString ( nsLeft->second );
+ goto FAILURE;
+ }
+ }
+
+ }
+
+ for ( XMP_StringMapPos nsLeft = sNamespaceURIToPrefixMap->begin(); nsLeft != u2pEnd; ++nsLeft ) {
+
+ XMP_StringMapPos nsOther = sNamespacePrefixToURIMap->find ( nsLeft->second );
+ if ( (nsOther == p2uEnd) || (nsLeft != sNamespaceURIToPrefixMap->find ( nsOther->second )) ) {
+ OutProcLiteral ( " ** bad namespace prefix ** " );
+ OutProcString ( nsLeft->second );
+ goto FAILURE;
+ }
+
+ for ( XMP_StringMapPos nsRight = nsLeft; nsRight != u2pEnd; ++nsRight ) {
+ if ( nsRight == nsLeft ) continue; // ! Can't start at nsLeft+1, no operator+!
+ if ( nsLeft->second == nsRight->second ) {
+ OutProcLiteral ( " ** duplicate namespace prefix ** " );
+ OutProcString ( nsLeft->second );
+ goto FAILURE;
+ }
+ }
+
+ }
+
+EXIT:
+ return status;
+
+FAILURE:
+ OutProcNewline();
+ (void) DumpStringMap ( *sNamespaceURIToPrefixMap, "Dumping namespace URI to prefix map", outProc, refCon );
+ XMP_Throw ( "Fatal namespace map problem", kXMPErr_InternalFailure );
+ return 0;
+
+} // DumpNamespaces
+
+
+// -------------------------------------------------------------------------------------------------
+// DumpAliases
+// -----------
+
+/* class-static */ XMP_Status
+XMPMeta::DumpAliases ( XMP_TextOutputProc outProc,
+ void * refCon )
+{
+ XMP_Assert ( outProc != 0 ); // ! Enforced by wrapper.
+ XMP_Status status;
+
+ XMP_Assert ( sRegisteredAliasMap != 0 );
+
+ XMP_cAliasMapPos aliasPos;
+ XMP_cAliasMapPos aliasEnd = sRegisteredAliasMap->end();
+
+ size_t maxLen = 0;
+ for ( aliasPos = sRegisteredAliasMap->begin(); aliasPos != aliasEnd; ++aliasPos ) {
+ size_t currLen = aliasPos->first.size();
+ if ( currLen > maxLen ) maxLen = currLen;
+ }
+
+ OutProcLiteral ( "Dumping alias name to actual path map" );
+ OutProcNewline();
+
+ for ( aliasPos = sRegisteredAliasMap->begin(); aliasPos != aliasEnd; ++aliasPos ) {
+
+ OutProcNChars ( " ", 3 );
+ OutProcString ( aliasPos->first );
+ OutProcPadding ( maxLen - aliasPos->first.size() );
+ OutProcNChars ( " => ", 4 );
+
+ size_t actualPathSize = aliasPos->second.size();
+ for ( size_t stepNum = 1; stepNum < actualPathSize; ++stepNum ) OutProcString ( aliasPos->second[stepNum].step );
+
+ XMP_OptionBits arrayForm = aliasPos->second[1].options & kXMP_PropArrayFormMask;
+
+ if ( arrayForm == 0 ) {
+ if ( actualPathSize != 2 ) OutProcLiteral ( " ** bad actual path **" );
+ } else {
+ OutProcNChars ( " ", 2 );
+ DumpNodeOptions ( arrayForm, outProc, refCon );
+ if ( ! (arrayForm & kXMP_PropValueIsArray) ) OutProcLiteral ( " ** bad array form **" );
+ if ( actualPathSize != 3 ) OutProcLiteral ( " ** bad actual path **" );
+ }
+
+ if ( aliasPos->second[0].options != kXMP_SchemaNode ) OutProcLiteral ( " ** bad schema form **" );
+
+ OutProcNewline();
+
+ }
+
+EXIT:
+ return status;
+
+} // DumpAliases
+
+
+// -------------------------------------------------------------------------------------------------
+// GetGlobalOptions
+// ----------------
+
+/* class-static */ XMP_OptionBits
+XMPMeta::GetGlobalOptions()
+{
+ XMP_OptionBits options = 0;
+
+ return options;
+
+} // GetGlobalOptions
+
+
+// -------------------------------------------------------------------------------------------------
+// SetGlobalOptions
+// ----------------
+
+/* class-static */ void
+XMPMeta::SetGlobalOptions ( XMP_OptionBits options )
+{
+
+ XMP_Throw ( "Unimplemented method XMPMeta::SetGlobalOptions", kXMPErr_Unimplemented );
+ void * p; p = &options; // Avoid unused param warnings.
+
+} // SetGlobalOptions
+
+
+// -------------------------------------------------------------------------------------------------
+// RegisterNamespace
+// -----------------
+
+/* class-static */ bool
+XMPMeta::RegisterNamespace ( XMP_StringPtr namespaceURI,
+ XMP_StringPtr suggestedPrefix,
+ XMP_StringPtr * registeredPrefix,
+ XMP_StringLen * prefixSize )
+{
+ bool prefixMatches = false;
+
+ XMP_Assert ( (registeredPrefix != 0) && (prefixSize != 0) ); // ! Enforced by wrapper.
+ if ( (*namespaceURI == 0) || (*suggestedPrefix == 0) ) {
+ XMP_Throw ( "Empty namespace URI or prefix", kXMPErr_BadParam );
+ }
+
+ XMP_VarString nsURI ( namespaceURI );
+ XMP_VarString suggPrefix ( suggestedPrefix );
+ if ( suggPrefix[suggPrefix.size()-1] != ':' ) suggPrefix += ':';
+ VerifySimpleXMLName ( suggestedPrefix, suggestedPrefix+suggPrefix.size()-1 ); // Exclude the colon.
+
+ XMP_StringMapPos uriPos = sNamespaceURIToPrefixMap->find ( nsURI );
+
+ if ( uriPos == sNamespaceURIToPrefixMap->end() ) {
+
+ // The URI is not yet registered, make sure we use a unique prefix.
+
+ XMP_VarString uniqPrefix ( suggPrefix );
+ int suffix = 0;
+ char buffer [32];
+
+ while ( true ) {
+ if ( sNamespacePrefixToURIMap->find ( uniqPrefix ) == sNamespacePrefixToURIMap->end() ) break;
+ ++suffix;
+ snprintf ( buffer, sizeof(buffer), "_%d_:", suffix ); // AUDIT: Using sizeof for snprintf length is safe.
+ uniqPrefix = suggPrefix;
+ uniqPrefix.erase ( uniqPrefix.size()-1 ); // ! Remove the trailing ':'.
+ uniqPrefix += buffer;
+ }
+
+ // Add the new namespace to both maps.
+
+ XMP_StringPair newNS ( nsURI, uniqPrefix );
+ uriPos = sNamespaceURIToPrefixMap->insert ( sNamespaceURIToPrefixMap->end(), newNS );
+
+ newNS.first.swap ( newNS.second );
+ (void) sNamespacePrefixToURIMap->insert ( sNamespacePrefixToURIMap->end(), newNS );
+
+ }
+
+ // Return the actual prefix and see if it matches the suggested prefix.
+
+ *registeredPrefix = uriPos->second.c_str();
+ *prefixSize = uriPos->second.size();
+
+ prefixMatches = ( uriPos->second == suggPrefix );
+ return prefixMatches;
+
+} // RegisterNamespace
+
+
+// -------------------------------------------------------------------------------------------------
+// GetNamespacePrefix
+// ------------------
+
+/* class-static */ bool
+XMPMeta::GetNamespacePrefix ( XMP_StringPtr namespaceURI,
+ XMP_StringPtr * namespacePrefix,
+ XMP_StringLen * prefixSize )
+{
+ bool found = false;
+
+ XMP_Assert ( *namespaceURI != 0 ); // ! Enforced by wrapper.
+ XMP_Assert ( (namespacePrefix != 0) && (prefixSize != 0) ); // ! Enforced by wrapper.
+
+ XMP_VarString nsURI ( namespaceURI );
+ XMP_StringMapPos uriPos = sNamespaceURIToPrefixMap->find ( nsURI );
+
+ if ( uriPos != sNamespaceURIToPrefixMap->end() ) {
+ *namespacePrefix = uriPos->second.c_str();
+ *prefixSize = uriPos->second.size();
+ found = true;
+ }
+
+ return found;
+
+} // GetNamespacePrefix
+
+
+// -------------------------------------------------------------------------------------------------
+// GetNamespaceURI
+// ---------------
+
+/* class-static */ bool
+XMPMeta::GetNamespaceURI ( XMP_StringPtr namespacePrefix,
+ XMP_StringPtr * namespaceURI,
+ XMP_StringLen * uriSize )
+{
+ bool found = false;
+
+ XMP_Assert ( *namespacePrefix != 0 ); // ! Enforced by wrapper.
+ XMP_Assert ( (namespacePrefix != 0) && (namespaceURI != 0) ); // ! Enforced by wrapper.
+
+ XMP_VarString nsPrefix ( namespacePrefix );
+ if ( nsPrefix[nsPrefix.size()-1] != ':' ) nsPrefix += ':';
+
+ XMP_StringMapPos prefixPos = sNamespacePrefixToURIMap->find ( nsPrefix );
+
+ if ( prefixPos != sNamespacePrefixToURIMap->end() ) {
+ *namespaceURI = prefixPos->second.c_str();
+ *uriSize = prefixPos->second.size();
+ found = true;
+ }
+
+ return found;
+
+} // GetNamespaceURI
+
+
+// -------------------------------------------------------------------------------------------------
+// DeleteNamespace
+// ---------------
+
+// *** Don't allow standard namespaces to be deleted.
+
+/* class-static */ void
+XMPMeta::DeleteNamespace ( XMP_StringPtr namespaceURI )
+{
+ namespaceURI = namespaceURI; // Avoid unused parameter warning.
+ XMP_Assert ( *namespaceURI != 0 ); // ! Enforced by wrapper.
+ XMP_Throw ( "Unimplemented method XMPMeta::DeleteNamespace", kXMPErr_Unimplemented ); // *** #error "write me"
+
+} // DeleteNamespace
+
+
+// -------------------------------------------------------------------------------------------------
+// RegisterAlias
+// -------------
+//
+// Allow 3 kinds of alias:
+// TopProp => TopProp
+// TopProp => TopArray[1]
+// TopProp => TopArray[@xml:lang='x-default']
+//
+// A new alias can be made to something that is already aliased, as long as the net result is one of
+// the legitimate forms. The new alias can already have aliases to it, also as long as result of
+// adjusting all of the exiting aliases leaves them legal.
+//
+// ! The caller assumes all risk that new aliases do not invalidate existing XMPMeta objects. Any
+// ! conflicts will result in later references throwing bad XPath exceptions.
+
+/* class-static */ void
+XMPMeta::RegisterAlias ( XMP_StringPtr aliasNS,
+ XMP_StringPtr aliasProp,
+ XMP_StringPtr actualNS,
+ XMP_StringPtr actualProp,
+ XMP_OptionBits arrayForm )
+{
+ XMP_ExpandedXPath expAlias, expActual;
+ XMP_AliasMapPos mapPos;
+ XMP_ExpandedXPath * regActual = 0;
+
+ XMP_Assert ( (aliasNS != 0) && (aliasProp != 0) && (actualNS != 0) && (actualProp != 0) ); // Enforced by wrapper.
+
+ // Expand the alias and actual names, make sure they are one of the basic 3 forms. When counting
+ // the expanded XPath size remember that the schema URI is the first component. We don't have to
+ // compare the schema URIs though, the (unique) prefix is part of the top property name.
+
+ ExpandXPath ( aliasNS, aliasProp, &expAlias );
+ ExpandXPath ( actualNS, actualProp, &expActual );
+ if ( (expAlias.size() != 2) || (expActual.size() != 2) ) {
+ XMP_Throw ( "Alias and actual property names must be simple", kXMPErr_BadXPath );
+ }
+
+ arrayForm = VerifySetOptions ( arrayForm, 0 );
+ if ( arrayForm != 0 ) {
+ if ( (arrayForm & ~kXMP_PropArrayFormMask) != 0 ) XMP_Throw ( "Only array form flags are allowed", kXMPErr_BadOptions );
+ expActual[1].options |= arrayForm; // Set the array form for the top level step.
+ if ( ! (arrayForm & kXMP_PropArrayIsAltText) ) {
+ expActual.push_back ( XPathStepInfo ( "[1]", kXMP_ArrayIndexStep ) );
+ } else {
+ expActual.push_back ( XPathStepInfo ( "[?xml:lang=\"x-default\"]", kXMP_QualSelectorStep ) );
+ }
+ }
+
+ // See if there are any conflicts with existing aliases. A couple of the checks are easy. If the
+ // alias is already aliased it is only OK to reregister an identical alias. If the actual is
+ // already aliased to something else and the new chain is legal, just swap in the old base.
+
+ mapPos = sRegisteredAliasMap->find ( expAlias[kRootPropStep].step );
+ if ( mapPos != sRegisteredAliasMap->end() ) {
+
+ // This alias is already registered to something, make sure it is the same something.
+
+ regActual = &mapPos->second;
+ if ( arrayForm != (mapPos->second[1].options & kXMP_PropArrayFormMask) ) {
+ XMP_Throw ( "Mismatch with existing alias array form", kXMPErr_BadParam );
+ }
+ if ( expActual.size() != regActual->size() ) {
+ XMP_Throw ( "Mismatch with existing actual path", kXMPErr_BadParam );
+ }
+ if ( expActual[kRootPropStep].step != (*regActual)[kRootPropStep].step ) {
+ XMP_Throw ( "Mismatch with existing actual name", kXMPErr_BadParam );
+ }
+ if ( (expActual.size() == 3) && (expActual[kAliasIndexStep].step != (*regActual)[kAliasIndexStep].step) ) {
+ XMP_Throw ( "Mismatch with existing actual array item", kXMPErr_BadParam );
+ }
+ return;
+
+ }
+
+ mapPos = sRegisteredAliasMap->find ( expActual[kRootPropStep].step );
+ if ( mapPos != sRegisteredAliasMap->end() ) {
+
+ // The actual is already aliased to something else.
+
+ regActual = &mapPos->second;
+ if ( expActual.size() == 2 ) {
+ expActual = *regActual; // TopProp => TopProp => anything : substitute the entire old base.
+ } else if ( regActual->size() != 2 ) {
+ XMP_Throw ( "Can't alias an array item to an array item", kXMPErr_BadParam ); // TopProp => TopArray[] => TopArray[] : nope.
+ } else {
+ expActual[kSchemaStep].step = (*regActual)[kSchemaStep].step; // TopProp => TopArray[] => TopProp :
+ expActual[kRootPropStep].step = (*regActual)[kRootPropStep].step; // substitute the old base name.
+ }
+
+ }
+
+ // Checking for existing aliases to this one is touchier. This involves updating the alias map,
+ // which must not be done unless all of the changes are legal. So we need 2 loops, one to verify
+ // that everything is OK, and one to make the changes. The bad case is:
+ // TopProp => TopArray[] => TopArray[]
+ // In the valid cases we back substitute the new base.
+
+ for ( mapPos = sRegisteredAliasMap->begin(); mapPos != sRegisteredAliasMap->end(); ++mapPos ) {
+ regActual = &mapPos->second;
+ if ( expAlias[kRootPropStep].step == (*regActual)[kRootPropStep].step ) {
+ if ( (regActual->size() == 2) && (expAlias.size() == 2) ) {
+ XMP_Throw ( "Can't alias an array item to an array item", kXMPErr_BadParam );
+ }
+ }
+ }
+
+ for ( mapPos = sRegisteredAliasMap->begin(); mapPos != sRegisteredAliasMap->end(); ++mapPos ) {
+ regActual = &mapPos->second;
+ if ( expAlias[kRootPropStep].step == (*regActual)[kRootPropStep].step ) {
+
+ if ( regActual->size() == 1 ) {
+ *regActual = expActual; // TopProp => TopProp => anything : substitute the entire new base.
+ } else {
+ (*regActual)[kSchemaStep].step = expActual[kSchemaStep].step; // TopProp => TopArray[] => TopProp :
+ (*regActual)[kRootPropStep].step = expActual[kRootPropStep].step; // substitute the new base name.
+ }
+
+ }
+ }
+
+ // Finally, all is OK to register the new alias.
+
+ (void) sRegisteredAliasMap->insert ( XMP_AliasMap::value_type ( expAlias[kRootPropStep].step, expActual ) );
+
+} // RegisterAlias
+
+
+// -------------------------------------------------------------------------------------------------
+// ResolveAlias
+// ------------
+
+/* class-static */ bool
+XMPMeta::ResolveAlias ( XMP_StringPtr aliasNS,
+ XMP_StringPtr aliasProp,
+ XMP_StringPtr * actualNS,
+ XMP_StringLen * nsSize,
+ XMP_StringPtr * actualProp,
+ XMP_StringLen * propSize,
+ XMP_OptionBits * arrayForm )
+{
+ XMP_Assert ( (aliasNS != 0) && (aliasProp != 0) ); // Enforced by wrapper.
+ XMP_Assert ( (actualNS != 0) && (nsSize != 0) && (actualProp != 0) && (propSize != 0) && (arrayForm != 0) ); // Enforced by wrapper.
+
+ // Expand the input path and look up the first component in the alias table. Return if not an alias.
+
+ XMP_ExpandedXPath fullPath, minPath;
+ ExpandXPath ( aliasNS, aliasProp, &fullPath );
+ XMP_Assert ( fullPath.size() >= 2 );
+
+ minPath.push_back ( fullPath[kSchemaStep] );
+ minPath.push_back ( fullPath[kRootPropStep] );
+ XMP_AliasMapPos mapPos = sRegisteredAliasMap->find ( minPath[kRootPropStep].step );
+ if ( mapPos == sRegisteredAliasMap->end() ) return false;
+
+ // Replace the alias portion of the full expanded path. Compose the output path string.
+
+ const XMP_ExpandedXPath & actualPath = mapPos->second;
+
+ fullPath[kSchemaStep] = actualPath[kSchemaStep];
+ fullPath[kRootPropStep] = actualPath[kRootPropStep];
+ if ( actualPath.size() > 2 ) { // This is an alias to an array item.
+ XMP_ExpandedXPathPos insertPos = fullPath.begin() + kAliasIndexStep;
+ fullPath.insert ( insertPos, actualPath[kAliasIndexStep] );
+ }
+
+ *sOutputNS = fullPath[kSchemaStep].step;
+ *actualNS = sOutputNS->c_str();
+ *nsSize = sOutputNS->size();
+
+ ComposeXPath ( fullPath, sOutputStr );
+ *actualProp = sOutputStr->c_str();
+ *propSize = sOutputStr->size();
+
+ *arrayForm = actualPath[kRootPropStep].options & kXMP_PropArrayFormMask;
+
+ #if XMP_DebugBuild // Test that the output string is valid and unchanged by round trip expand/compose.
+ XMP_ExpandedXPath rtPath;
+ ExpandXPath ( *actualNS, *actualProp, &rtPath );
+ std::string rtString;
+ ComposeXPath ( rtPath, &rtString );
+ XMP_Assert ( rtString == *sOutputStr );
+ #endif
+
+ return true;
+
+} // ResolveAlias
+
+
+// -------------------------------------------------------------------------------------------------
+// DeleteAlias
+// -----------
+
+/* class-static */ void
+XMPMeta::DeleteAlias ( XMP_StringPtr aliasNS,
+ XMP_StringPtr aliasProp )
+{
+
+ XMP_Assert ( (aliasNS != 0) && (aliasProp != 0) ); // Enforced by wrapper.
+ XMP_Throw ( "Unimplemented method XMPMeta::DeleteAlias", kXMPErr_Unimplemented ); // *** #error "write me"
+ void * p; p = &aliasNS; p = &aliasProp; // Avoid unused param warnings.
+
+} // DeleteAlias
+
+
+// -------------------------------------------------------------------------------------------------
+// RegisterStandardAliases
+// -----------------------
+
+/* class-static */ void
+XMPMeta::RegisterStandardAliases ( XMP_StringPtr schemaNS )
+{
+ XMP_Assert ( schemaNS != 0 ); // Enforced by wrapper.
+
+ const bool doAll = (*schemaNS == 0);
+
+ if ( doAll || XMP_LitMatch ( schemaNS, kXMP_NS_XMP ) ) {
+ // Aliases from XMP to DC.
+ XMPMeta::RegisterAlias ( kXMP_NS_XMP, "Author", kXMP_NS_DC, "creator", kXMP_PropArrayIsOrdered );
+ XMPMeta::RegisterAlias ( kXMP_NS_XMP, "Authors", kXMP_NS_DC, "creator", 0 );
+ XMPMeta::RegisterAlias ( kXMP_NS_XMP, "Description", kXMP_NS_DC, "description", 0 );
+ XMPMeta::RegisterAlias ( kXMP_NS_XMP, "Format", kXMP_NS_DC, "format", 0 );
+ XMPMeta::RegisterAlias ( kXMP_NS_XMP, "Keywords", kXMP_NS_DC, "subject", 0 );
+ XMPMeta::RegisterAlias ( kXMP_NS_XMP, "Locale", kXMP_NS_DC, "language", 0 );
+ XMPMeta::RegisterAlias ( kXMP_NS_XMP, "Title", kXMP_NS_DC, "title", 0 );
+ XMPMeta::RegisterAlias ( kXMP_NS_XMP_Rights, "Copyright", kXMP_NS_DC, "rights", 0 );
+ }
+
+ if ( doAll || XMP_LitMatch ( schemaNS, kXMP_NS_PDF ) ) {
+ // Aliases from PDF to DC and XMP.
+ XMPMeta::RegisterAlias ( kXMP_NS_PDF, "Author", kXMP_NS_DC, "creator", kXMP_PropArrayIsOrdered );
+ XMPMeta::RegisterAlias ( kXMP_NS_PDF, "BaseURL", kXMP_NS_XMP, "BaseURL", 0 );
+ XMPMeta::RegisterAlias ( kXMP_NS_PDF, "CreationDate", kXMP_NS_XMP, "CreateDate", 0 );
+ XMPMeta::RegisterAlias ( kXMP_NS_PDF, "Creator", kXMP_NS_XMP, "CreatorTool", 0 );
+ XMPMeta::RegisterAlias ( kXMP_NS_PDF, "ModDate", kXMP_NS_XMP, "ModifyDate", 0 );
+ XMPMeta::RegisterAlias ( kXMP_NS_PDF, "Subject", kXMP_NS_DC, "description", kXMP_PropArrayIsAltText );
+ XMPMeta::RegisterAlias ( kXMP_NS_PDF, "Title", kXMP_NS_DC, "title", kXMP_PropArrayIsAltText );
+ }
+
+ if ( doAll || XMP_LitMatch ( schemaNS, kXMP_NS_Photoshop ) ) {
+ // Aliases from PHOTOSHOP to DC and XMP.
+ XMPMeta::RegisterAlias ( kXMP_NS_Photoshop, "Author", kXMP_NS_DC, "creator", kXMP_PropArrayIsOrdered );
+ XMPMeta::RegisterAlias ( kXMP_NS_Photoshop, "Caption", kXMP_NS_DC, "description", kXMP_PropArrayIsAltText );
+ XMPMeta::RegisterAlias ( kXMP_NS_Photoshop, "Copyright", kXMP_NS_DC, "rights", kXMP_PropArrayIsAltText );
+ XMPMeta::RegisterAlias ( kXMP_NS_Photoshop, "Keywords", kXMP_NS_DC, "subject", 0 );
+ XMPMeta::RegisterAlias ( kXMP_NS_Photoshop, "Marked", kXMP_NS_XMP_Rights, "Marked", 0 );
+ XMPMeta::RegisterAlias ( kXMP_NS_Photoshop, "Title", kXMP_NS_DC, "title", kXMP_PropArrayIsAltText );
+ XMPMeta::RegisterAlias ( kXMP_NS_Photoshop, "WebStatement", kXMP_NS_XMP_Rights, "WebStatement", 0 );
+ }
+
+ if ( doAll || XMP_LitMatch ( schemaNS, kXMP_NS_TIFF ) || XMP_LitMatch ( schemaNS, kXMP_NS_EXIF ) ) {
+ // Aliases from TIFF and EXIF to DC and XMP.
+ XMPMeta::RegisterAlias ( kXMP_NS_TIFF, "Artist", kXMP_NS_DC, "creator", kXMP_PropArrayIsOrdered);
+ XMPMeta::RegisterAlias ( kXMP_NS_TIFF, "Copyright", kXMP_NS_DC, "rights", 0 );
+ XMPMeta::RegisterAlias ( kXMP_NS_TIFF, "DateTime", kXMP_NS_XMP, "ModifyDate", 0 );
+ XMPMeta::RegisterAlias ( kXMP_NS_TIFF, "ImageDescription", kXMP_NS_DC, "description", 0 );
+ XMPMeta::RegisterAlias ( kXMP_NS_TIFF, "Software", kXMP_NS_XMP, "CreatorTool", 0 );
+ }
+
+ if ( doAll || XMP_LitMatch ( schemaNS, kXMP_NS_PNG ) ) { // ! From Acrobat ImageCapture:
+ XMPMeta::RegisterAlias ( kXMP_NS_PNG, "Author", kXMP_NS_DC, "creator", kXMP_PropArrayIsOrdered);
+ XMPMeta::RegisterAlias ( kXMP_NS_PNG, "Copyright", kXMP_NS_DC, "rights", kXMP_PropArrayIsAltText);
+ XMPMeta::RegisterAlias ( kXMP_NS_PNG, "CreationTime", kXMP_NS_XMP, "CreateDate", 0 );
+ XMPMeta::RegisterAlias ( kXMP_NS_PNG, "Description", kXMP_NS_DC, "description", kXMP_PropArrayIsAltText);
+ XMPMeta::RegisterAlias ( kXMP_NS_PNG, "ModificationTime", kXMP_NS_XMP, "ModifyDate", 0 );
+ XMPMeta::RegisterAlias ( kXMP_NS_PNG, "Software", kXMP_NS_XMP, "CreatorTool", 0 );
+ XMPMeta::RegisterAlias ( kXMP_NS_PNG, "Title", kXMP_NS_DC, "title", kXMP_PropArrayIsAltText);
+ }
+
+} // RegisterStandardAliases
+
+
+// =================================================================================================
+// Class Methods
+// =============
+//
+//
+// =================================================================================================
+
+
+// -------------------------------------------------------------------------------------------------
+// DumpObject
+// ----------
+
+XMP_Status
+XMPMeta::DumpObject ( XMP_TextOutputProc outProc,
+ void * refCon ) const
+{
+ XMP_Assert ( outProc != 0 ); // ! Enforced by wrapper.
+ XMP_Status status;
+
+ OutProcLiteral ( "Dumping XMPMeta object \"" );
+ OutProcString ( tree.name );
+ OutProcNChars ( "\" ", 3 );
+ status = DumpNodeOptions ( tree.options, outProc, refCon );
+ if ( status != 0 ) goto EXIT;
+ #if 0 // *** XMP_DebugBuild
+ if ( (tree._namePtr != tree.name.c_str()) ||
+ (tree._valuePtr != tree.value.c_str()) ) OutProcLiteral ( " ** bad debug string **" );
+ #endif
+ OutProcNewline();
+
+ if ( ! tree.value.empty() ) {
+ OutProcLiteral ( "** bad root value ** \"" );
+ OutProcString ( tree.value );
+ OutProcNChars ( "\"", 1 );
+ OutProcNewline();
+ }
+
+ if ( ! tree.qualifiers.empty() ) {
+ OutProcLiteral ( "** bad root qualifiers **" );
+ OutProcNewline();
+ for ( size_t qualNum = 0, qualLim = tree.qualifiers.size(); qualNum < qualLim; ++qualNum ) {
+ status = DumpPropertyTree ( tree.qualifiers[qualNum], 3, 0, outProc, refCon );
+ }
+ }
+
+ if ( ! tree.children.empty() ) {
+
+ for ( size_t childNum = 0, childLim = tree.children.size(); childNum < childLim; ++childNum ) {
+
+ const XMP_Node * currSchema = tree.children[childNum];
+
+ OutProcNewline();
+ OutProcIndent ( 1 );
+ OutProcString ( currSchema->name );
+ OutProcNChars ( " ", 2 );
+ OutProcString ( currSchema->value );
+ OutProcNChars ( " ", 2 );
+ status = DumpNodeOptions ( currSchema->options, outProc, refCon );
+ if ( status != 0 ) goto EXIT;
+ #if 0 // *** XMP_DebugBuild
+ if ( (currSchema->_namePtr != currSchema->name.c_str()) ||
+ (currSchema->_valuePtr != currSchema->value.c_str()) ) OutProcLiteral ( " ** bad debug string **" );
+ #endif
+ OutProcNewline();
+
+ if ( ! (currSchema->options & kXMP_SchemaNode) ) {
+ OutProcLiteral ( "** bad schema options **" );
+ OutProcNewline();
+ }
+
+ if ( ! currSchema->qualifiers.empty() ) {
+ OutProcLiteral ( "** bad schema qualifiers **" );
+ OutProcNewline();
+ for ( size_t qualNum = 0, qualLim = currSchema->qualifiers.size(); qualNum < qualLim; ++qualNum ) {
+ DumpPropertyTree ( currSchema->qualifiers[qualNum], 3, 0, outProc, refCon );
+ }
+ }
+
+ for ( size_t childNum = 0, childLim = currSchema->children.size(); childNum < childLim; ++childNum ) {
+ DumpPropertyTree ( currSchema->children[childNum], 2, 0, outProc, refCon );
+ }
+
+ }
+
+ }
+
+EXIT:
+ return status;
+
+} // DumpObject
+
+
+// -------------------------------------------------------------------------------------------------
+// CountArrayItems
+// ---------------
+
+XMP_Index
+XMPMeta::CountArrayItems ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName ) const
+{
+ XMP_Assert ( (schemaNS != 0) && (arrayName != 0) ); // Enforced by wrapper.
+
+ XMP_ExpandedXPath expPath;
+ ExpandXPath ( schemaNS, arrayName, &expPath );
+
+ const XMP_Node * arrayNode = FindConstNode ( &tree, expPath );
+
+ if ( arrayNode == 0 ) return 0;
+ if ( ! (arrayNode->options & kXMP_PropValueIsArray) ) XMP_Throw ( "The named property is not an array", kXMPErr_BadXPath );
+ return arrayNode->children.size();
+
+} // CountArrayItems
+
+
+// -------------------------------------------------------------------------------------------------
+// GetObjectName
+// -------------
+
+void
+XMPMeta::GetObjectName ( XMP_StringPtr * namePtr,
+ XMP_StringLen * nameLen ) const
+{
+
+ *namePtr = tree.name.c_str();
+ *nameLen = tree.name.size();
+
+} // GetObjectName
+
+
+// -------------------------------------------------------------------------------------------------
+// SetObjectName
+// -------------
+
+void
+XMPMeta::SetObjectName ( XMP_StringPtr name )
+{
+ VerifyUTF8 ( name ); // Throws if the string is not legit UTF-8.
+ tree.name = name;
+
+} // SetObjectName
+
+
+// -------------------------------------------------------------------------------------------------
+// GetObjectOptions
+// ----------------
+
+XMP_OptionBits
+XMPMeta::GetObjectOptions() const
+{
+ XMP_OptionBits options = 0;
+
+ return options;
+
+} // GetObjectOptions
+
+
+// -------------------------------------------------------------------------------------------------
+// SetObjectOptions
+// ----------------
+
+void
+XMPMeta::SetObjectOptions ( XMP_OptionBits options )
+{
+
+ XMP_Throw ( "Unimplemented method XMPMeta::SetObjectOptions", kXMPErr_Unimplemented );
+ void * p; p = &options; // Avoid unused param warnings.
+
+} // SetObjectOptions
+
+
+// -------------------------------------------------------------------------------------------------
+// Clone
+// -----
+
+XMPMeta *
+XMPMeta::Clone ( XMP_OptionBits options ) const
+{
+ if ( options != 0 ) XMP_Throw ( "No options are defined yet", kXMPErr_BadOptions );
+
+ XMPMeta * clone = new XMPMeta;
+
+ clone->tree.options = this->tree.options;
+ clone->tree.name = this->tree.name;
+ clone->tree.value = this->tree.value;
+ XMP_Assert ( this->tree.parent == 0 );
+
+ #if 0 // *** XMP_DebugBuild
+ clone->tree._namePtr = clone->tree.name.c_str();
+ clone->tree._valuePtr = clone->tree.value.c_str();
+ #endif
+
+ CloneOffspring ( &this->tree, &clone->tree );
+
+ XMP_Assert ( clone->clientRefs == 0 ); // Gets incremneted later.
+ return clone;
+
+} // Clone
+
+// =================================================================================================
diff --git a/source/XMPCore/XMPMeta.hpp b/source/XMPCore/XMPMeta.hpp
new file mode 100644
index 0000000..a73eb6a
--- /dev/null
+++ b/source/XMPCore/XMPMeta.hpp
@@ -0,0 +1,414 @@
+#ifndef __XMPMeta_hpp__
+#define __XMPMeta_hpp__
+
+// =================================================================================================
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "XMP_Environment.h"
+#include "XMP_Const.h"
+#include "XMPCore_Impl.hpp"
+#include "XMLParserAdapter.hpp"
+
+// -------------------------------------------------------------------------------------------------
+
+#ifndef DumpXMLParseTree
+ #define DumpXMLParseTree 0
+#endif
+
+extern XMP_VarString * xdefaultName;
+
+class XMPIterator;
+class XMPUtils;
+
+// -------------------------------------------------------------------------------------------------
+
+class XMPMeta {
+public:
+
+ static void
+ GetVersionInfo ( XMP_VersionInfo * info );
+
+ static bool
+ Initialize();
+ static void
+ Terminate() RELEASE_NO_THROW;
+
+ static void
+ Unlock ( XMP_OptionBits options );
+
+ // ---------------------------------------------------------------------------------------------
+
+ XMPMeta();
+
+ virtual ~XMPMeta() RELEASE_NO_THROW;
+
+ // ---------------------------------------------------------------------------------------------
+
+ static XMP_OptionBits
+ GetGlobalOptions();
+
+ static void
+ SetGlobalOptions ( XMP_OptionBits options );
+
+ // ---------------------------------------------------------------------------------------------
+
+ static XMP_Status
+ DumpNamespaces ( XMP_TextOutputProc outProc,
+ void * refCon );
+
+ static XMP_Status
+ DumpAliases ( XMP_TextOutputProc outProc,
+ void * refCon );
+
+ // ---------------------------------------------------------------------------------------------
+
+ static bool
+ RegisterNamespace ( XMP_StringPtr namespaceURI,
+ XMP_StringPtr suggestedPrefix,
+ XMP_StringPtr * registeredPrefix,
+ XMP_StringLen * prefixSize );
+
+ static bool
+ GetNamespacePrefix ( XMP_StringPtr namespaceURI,
+ XMP_StringPtr * namespacePrefix,
+ XMP_StringLen * prefixSize );
+
+ static bool
+ GetNamespaceURI ( XMP_StringPtr namespacePrefix,
+ XMP_StringPtr * namespaceURI,
+ XMP_StringLen * uriSize );
+
+ static void
+ DeleteNamespace ( XMP_StringPtr namespaceURI );
+
+ // ---------------------------------------------------------------------------------------------
+
+ static void
+ RegisterAlias ( XMP_StringPtr aliasNS,
+ XMP_StringPtr aliasProp,
+ XMP_StringPtr actualNS,
+ XMP_StringPtr actualProp,
+ XMP_OptionBits arrayForm );
+
+ static bool
+ ResolveAlias ( XMP_StringPtr aliasNS,
+ XMP_StringPtr aliasProp,
+ XMP_StringPtr * actualNS,
+ XMP_StringLen * nsSize,
+ XMP_StringPtr * actualProp,
+ XMP_StringLen * propSize,
+ XMP_OptionBits * arrayForm );
+
+ static void
+ DeleteAlias ( XMP_StringPtr aliasNS,
+ XMP_StringPtr aliasProp );
+
+ static void
+ RegisterStandardAliases ( XMP_StringPtr schemaNS );
+
+ // ---------------------------------------------------------------------------------------------
+
+ void
+ UnlockObject ( XMP_OptionBits options ) const;
+
+ // ---------------------------------------------------------------------------------------------
+
+ bool
+ GetProperty ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr * propValue,
+ XMP_StringLen * valueSize,
+ XMP_OptionBits * options ) const;
+
+ bool
+ GetArrayItem ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex,
+ XMP_StringPtr * itemValue,
+ XMP_StringLen * valueSize,
+ XMP_OptionBits * options ) const;
+
+ bool
+ GetStructField ( XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ XMP_StringPtr * fieldValue,
+ XMP_StringLen * valueSize,
+ XMP_OptionBits * options ) const;
+
+ bool
+ GetQualifier ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName,
+ XMP_StringPtr * qualValue,
+ XMP_StringLen * valueSize,
+ XMP_OptionBits * options ) const;
+
+ // ---------------------------------------------------------------------------------------------
+
+ void
+ SetProperty ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr propValue,
+ XMP_OptionBits options );
+
+ void
+ SetArrayItem ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex,
+ XMP_StringPtr itemValue,
+ XMP_OptionBits options );
+
+ void
+ AppendArrayItem ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_OptionBits arrayOptions,
+ XMP_StringPtr itemValue,
+ XMP_OptionBits options );
+
+ void
+ SetStructField ( XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ XMP_StringPtr fieldValue,
+ XMP_OptionBits options );
+
+ void
+ SetQualifier ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName,
+ XMP_StringPtr qualValue,
+ XMP_OptionBits options );
+
+ // ---------------------------------------------------------------------------------------------
+
+ void
+ DeleteProperty ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName );
+
+ void
+ DeleteArrayItem ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex );
+
+ void
+ DeleteStructField ( XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName );
+
+ void
+ DeleteQualifier ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName );
+
+ // ---------------------------------------------------------------------------------------------
+
+ bool
+ DoesPropertyExist ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName ) const;
+
+ bool
+ DoesArrayItemExist ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex ) const;
+
+ bool
+ DoesStructFieldExist ( XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName ) const;
+
+ bool
+ DoesQualifierExist ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName ) const;
+
+ // ---------------------------------------------------------------------------------------------
+
+ bool
+ GetLocalizedText ( XMP_StringPtr schemaNS,
+ XMP_StringPtr altTextName,
+ XMP_StringPtr genericLang,
+ XMP_StringPtr specificLang,
+ XMP_StringPtr * actualLang,
+ XMP_StringLen * langSize,
+ XMP_StringPtr * itemValue,
+ XMP_StringLen * valueSize,
+ XMP_OptionBits * options ) const;
+
+ void
+ SetLocalizedText ( XMP_StringPtr schemaNS,
+ XMP_StringPtr altTextName,
+ XMP_StringPtr genericLang,
+ XMP_StringPtr specificLang,
+ XMP_StringPtr itemValue,
+ XMP_OptionBits options );
+
+ // ---------------------------------------------------------------------------------------------
+
+ bool
+ GetProperty_Bool ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ bool * propValue,
+ XMP_OptionBits * options ) const;
+
+ bool
+ GetProperty_Int ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_Int32 * propValue,
+ XMP_OptionBits * options ) const;
+
+ bool
+ GetProperty_Int64 ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_Int64 * propValue,
+ XMP_OptionBits * options ) const;
+
+ bool
+ GetProperty_Float ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ double * propValue,
+ XMP_OptionBits * options ) const;
+
+ bool
+ GetProperty_Date ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_DateTime * propValue,
+ XMP_OptionBits * options ) const;
+
+ // ---------------------------------------------------------------------------------------------
+
+ void
+ SetProperty_Bool ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ bool propValue,
+ XMP_OptionBits options );
+
+ void
+ SetProperty_Int ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_Int32 propValue,
+ XMP_OptionBits options );
+
+ void
+ SetProperty_Int64 ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_Int64 propValue,
+ XMP_OptionBits options );
+
+ void
+ SetProperty_Float ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ double propValue,
+ XMP_OptionBits options );
+
+ void
+ SetProperty_Date ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ const XMP_DateTime & propValue,
+ XMP_OptionBits options );
+
+ // ---------------------------------------------------------------------------------------------
+
+ void
+ GetObjectName ( XMP_StringPtr * namePtr,
+ XMP_StringLen * nameLen ) const;
+
+ void
+ SetObjectName ( XMP_StringPtr name );
+
+ XMP_OptionBits
+ GetObjectOptions() const;
+
+ void
+ SetObjectOptions ( XMP_OptionBits options );
+
+ XMPMeta *
+ Clone ( XMP_OptionBits options ) const;
+
+ XMP_Index
+ CountArrayItems ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName ) const;
+
+ XMP_Status
+ DumpObject ( XMP_TextOutputProc outProc,
+ void * refCon ) const;
+
+ // ---------------------------------------------------------------------------------------------
+
+ void
+ ParseFromBuffer ( XMP_StringPtr buffer,
+ XMP_StringLen bufferSize,
+ XMP_OptionBits options );
+
+ void
+ SerializeToBuffer ( XMP_StringPtr * rdfString,
+ XMP_StringLen * rdfSize,
+ XMP_OptionBits options,
+ XMP_StringLen padding,
+ XMP_StringPtr newline,
+ XMP_StringPtr indent,
+ XMP_Index baseIndent ) const;
+
+ // =============================================================================================
+
+ // ---------------------------------------------------------------------------------------------
+ // - Everything is built out of standard nodes. Each node has a name, value, option flags, a
+ // vector of child nodes, and a vector of qualifier nodes.
+ //
+ // - The option flags are those passed to SetProperty and returned from GetProperty. They tell
+ // if the node is simple, a struct or an array; whether it has qualifiers, etc.
+ //
+ // - The name of the node is an XML qualified name, of the form "prefix:simple-name". Since we
+ // force all namespaces to be known and to have unique prefixes, this is semantically equivalent
+ // to using a URI and simple name pair.
+ //
+ // - Although the value part is only for leaf properties and the children part is only for
+ // structs and arrays, it is easier to simply have them in every node. This keeps things visible
+ // so that debugging is easier
+ //
+ // - The top level node children are the namespaces that contain properties, the next level are
+ // the top level properties, lower levels are the fields of structs or items of arrays. The name
+ // of the top level nodes is just the namespace prefix, with the colon terminator. The name of
+ // top level properties includes the namespace prefix.
+ //
+ // - Any property node, at any level, can have qualifiers. These are themselves general property
+ // nodes. And could in fact themselves have qualifiers!
+
+ // ! Expose the implementation so that file static functions can see the data.
+
+ XMP_Int32 clientRefs; // ! Must be signed to allow decrement from 0.
+ XMP_Int32 prevTkVer; // Previous toolkit version as MMmmuubbb (major, minor, micro, build).
+ XMP_Node tree;
+
+ XMLParserAdapter * xmlParser;
+
+ friend class XMPIterator;
+ friend class XMPUtils;
+
+private:
+
+ // ! These are hidden on purpose:
+ XMPMeta ( const XMPMeta & /* original */ ) : tree(XMP_Node(0,"",0)), clientRefs(0), prevTkVer(0), xmlParser(0)
+ { XMP_Throw ( "Call to hidden constructor", kXMPErr_InternalFailure ); };
+ void operator= ( const XMPMeta & /* rhs */ )
+ { XMP_Throw ( "Call to hidden operator=", kXMPErr_InternalFailure ); };
+
+}; // class XMPMeta
+
+
+// =================================================================================================
+
+#endif // __XMPMeta_hpp__
diff --git a/source/XMPCore/XMPUtils-FileInfo.cpp b/source/XMPCore/XMPUtils-FileInfo.cpp
new file mode 100644
index 0000000..7bf3836
--- /dev/null
+++ b/source/XMPCore/XMPUtils-FileInfo.cpp
@@ -0,0 +1,1257 @@
+// =================================================================================================
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "XMP_Environment.h" // ! This must be the first include!
+#include "XMPCore_Impl.hpp"
+
+#include "XMPUtils.hpp"
+
+#include <time.h>
+#include <string.h>
+#include <stdlib.h>
+#include <locale.h>
+#include <errno.h>
+
+#include <stdio.h> // For snprintf.
+
+#if XMP_WinBuild
+ #pragma warning ( disable : 4800 ) // forcing value to bool 'true' or 'false' (performance warning)
+#endif
+
+
+// =================================================================================================
+// Local Types and Constants
+// =========================
+
+typedef unsigned long UniCodePoint;
+
+enum UniCharKind {
+ UCK_normal,
+ UCK_space,
+ UCK_comma,
+ UCK_semicolon,
+ UCK_quote,
+ UCK_control
+};
+typedef enum UniCharKind UniCharKind;
+
+#define UnsByte(c) ((unsigned char)(c))
+#define UCP(u) ((UniCodePoint)(u))
+ // ! Needed on Windows (& PC Linux?) for inequalities with literals ito avoid sign extension.
+
+#ifndef TraceMultiFile
+ #define TraceMultiFile 0
+#endif
+
+// =================================================================================================
+// Static Variables
+// ================
+
+
+// =================================================================================================
+// Local Utilities
+// ===============
+
+// -------------------------------------------------------------------------------------------------
+// ClassifyCharacter
+// -----------------
+
+static void
+ClassifyCharacter ( XMP_StringPtr fullString, size_t offset,
+ UniCharKind * charKind, size_t * charSize, UniCodePoint * uniChar )
+{
+ *charKind = UCK_normal; // Assume typical case.
+
+ unsigned char currByte = UnsByte ( fullString[offset] );
+
+ if ( currByte < UnsByte(0x80) ) {
+
+ // ----------------------------------------
+ // We've got a single byte ASCII character.
+
+ *charSize = 1;
+ *uniChar = currByte;
+
+ if ( currByte > UnsByte(0x22) ) {
+
+ if ( currByte == UnsByte(0x2C) ) {
+ *charKind = UCK_comma;
+ } else if ( currByte == UnsByte(0x3B) ) {
+ *charKind = UCK_semicolon;
+ } else if ( (currByte == UnsByte(0x5B)) || (currByte == UnsByte(0x5D)) ) {
+ *charKind = UCK_quote; // ! ASCII '[' and ']' are used as quotes in Chinese and Korean.
+ }
+
+ } else { // currByte <= 0x22
+
+ if ( currByte == UnsByte(0x22) ) {
+ *charKind = UCK_quote;
+ } else if ( currByte == UnsByte(0x21) ) {
+ *charKind = UCK_normal;
+ } else if ( currByte == UnsByte(0x20) ) {
+ *charKind = UCK_space;
+ } else {
+ *charKind = UCK_control;
+ }
+
+ }
+
+ } else { // currByte >= 0x80
+
+ // ---------------------------------------------------------------------------------------
+ // We've got a multibyte Unicode character. The first byte has the number of bytes and the
+ // highest order bits. The other bytes each add 6 more bits. Compose the UTF-32 form so we
+ // can classify directly with the Unicode code points. Order the upperBits tests to be
+ // fastest for Japan, probably the most common non-ASCII usage.
+
+ *charSize = 0;
+ *uniChar = currByte;
+ while ( (*uniChar & 0x80) != 0 ) { // Count the leading 1 bits in the byte.
+ ++(*charSize);
+ *uniChar = *uniChar << 1;
+ }
+ XMP_Assert ( (offset + *charSize) <= strlen(fullString) );
+
+ *uniChar = *uniChar & 0x7F; // Put the character bits in the bottom of uniChar.
+ *uniChar = *uniChar >> *charSize;
+
+ for ( size_t i = (offset + 1); i < (offset + *charSize); ++i ) {
+ *uniChar = (*uniChar << 6) | (UnsByte(fullString[i]) & 0x3F);
+ }
+
+ XMP_Uns32 upperBits = *uniChar >> 8; // First filter on just the high order 24 bits.
+
+ if ( upperBits == 0xFF ) { // U+FFxx
+
+ if ( *uniChar == UCP(0xFF0C) ) {
+ *charKind = UCK_comma; // U+FF0C, full width comma.
+ } else if ( *uniChar == UCP(0xFF1B) ) {
+ *charKind = UCK_semicolon; // U+FF1B, full width semicolon.
+ } else if ( *uniChar == UCP(0xFF64) ) {
+ *charKind = UCK_comma; // U+FF64, half width ideographic comma.
+ }
+
+ } else if ( upperBits == 0xFE ) { // U+FE--
+
+ if ( *uniChar == UCP(0xFE50) ) {
+ *charKind = UCK_comma; // U+FE50, small comma.
+ } else if ( *uniChar == UCP(0xFE51) ) {
+ *charKind = UCK_comma; // U+FE51, small ideographic comma.
+ } else if ( *uniChar == UCP(0xFE54) ) {
+ *charKind = UCK_semicolon; // U+FE54, small semicolon.
+ }
+
+ } else if ( upperBits == 0x30 ) { // U+30--
+
+ if ( *uniChar == UCP(0x3000) ) {
+ *charKind = UCK_space; // U+3000, ideographic space.
+ } else if ( *uniChar == UCP(0x3001) ) {
+ *charKind = UCK_comma; // U+3001, ideographic comma.
+ } else if ( (UCP(0x3008) <= *uniChar) && (*uniChar <= UCP(0x300F)) ) {
+ *charKind = UCK_quote; // U+3008..U+300F, various quotes.
+ } else if ( *uniChar == UCP(0x303F) ) {
+ *charKind = UCK_space; // U+303F, ideographic half fill space.
+ } else if ( (UCP(0x301D) <= *uniChar) && (*uniChar <= UCP(0x301F)) ) {
+ *charKind = UCK_quote; // U+301D..U+301F, double prime quotes.
+ }
+
+ } else if ( upperBits == 0x20 ) { // U+20--
+
+ if ( (UCP(0x2000) <= *uniChar) && (*uniChar <= UCP(0x200B)) ) {
+ *charKind = UCK_space; // U+2000..U+200B, en quad through zero width space.
+ } else if ( *uniChar == UCP(0x2015) ) {
+ *charKind = UCK_quote; // U+2015, dash quote.
+ } else if ( (UCP(0x2018) <= *uniChar) && (*uniChar <= UCP(0x201F)) ) {
+ *charKind = UCK_quote; // U+2018..U+201F, various quotes.
+ } else if ( *uniChar == UCP(0x2028) ) {
+ *charKind = UCK_control; // U+2028, line separator.
+ } else if ( *uniChar == UCP(0x2029) ) {
+ *charKind = UCK_control; // U+2029, paragraph separator.
+ } else if ( (*uniChar == UCP(0x2039)) || (*uniChar == UCP(0x203A)) ) {
+ *charKind = UCK_quote; // U+2039 and U+203A, guillemet quotes.
+ }
+
+ } else if ( upperBits == 0x06 ) { // U+06--
+
+ if ( *uniChar == UCP(0x060C) ) {
+ *charKind = UCK_comma; // U+060C, Arabic comma.
+ } else if ( *uniChar == UCP(0x061B) ) {
+ *charKind = UCK_semicolon; // U+061B, Arabic semicolon.
+ }
+
+ } else if ( upperBits == 0x05 ) { // U+05--
+
+ if ( *uniChar == UCP(0x055D) ) {
+ *charKind = UCK_comma; // U+055D, Armenian comma.
+ }
+
+ } else if ( upperBits == 0x03 ) { // U+03--
+
+ if ( *uniChar == UCP(0x037E) ) {
+ *charKind = UCK_semicolon; // U+037E, Greek "semicolon" (really a question mark).
+ }
+
+ } else if ( upperBits == 0x00 ) { // U+00--
+
+ if ( (*uniChar == UCP(0x00AB)) || (*uniChar == UCP(0x00BB)) ) {
+ *charKind = UCK_quote; // U+00AB and U+00BB, guillemet quotes.
+ }
+
+ }
+
+ }
+
+} // ClassifyCharacter
+
+
+// -------------------------------------------------------------------------------------------------
+// IsClosingingQuote
+// -----------------
+
+static inline bool
+IsClosingingQuote ( UniCodePoint uniChar, UniCodePoint openQuote, UniCodePoint closeQuote )
+{
+
+ if ( (uniChar == closeQuote) ||
+ ( (openQuote == UCP(0x301D)) && ((uniChar == UCP(0x301E)) || (uniChar == UCP(0x301F))) ) ) {
+ return true;
+ } else {
+ return false;
+ }
+
+} // IsClosingingQuote
+
+
+// -------------------------------------------------------------------------------------------------
+// IsSurroundingQuote
+// ------------------
+
+static inline bool
+IsSurroundingQuote ( UniCodePoint uniChar, UniCodePoint openQuote, UniCodePoint closeQuote )
+{
+
+ if ( (uniChar == openQuote) || IsClosingingQuote ( uniChar, openQuote, closeQuote ) ) {
+ return true;
+ } else {
+ return false;
+ }
+
+} // IsSurroundingQuote
+
+
+// -------------------------------------------------------------------------------------------------
+// GetClosingQuote
+// ---------------
+
+static UniCodePoint
+GetClosingQuote ( UniCodePoint openQuote )
+{
+ UniCodePoint closeQuote;
+
+ switch ( openQuote ) {
+
+ case UCP(0x0022) : closeQuote = UCP(0x0022); // ! U+0022 is both opening and closing.
+ break;
+ case UCP(0x005B) : closeQuote = UCP(0x005D);
+ break;
+ case UCP(0x00AB) : closeQuote = UCP(0x00BB); // ! U+00AB and U+00BB are reversible.
+ break;
+ case UCP(0x00BB) : closeQuote = UCP(0x00AB);
+ break;
+ case UCP(0x2015) : closeQuote = UCP(0x2015); // ! U+2015 is both opening and closing.
+ break;
+ case UCP(0x2018) : closeQuote = UCP(0x2019);
+ break;
+ case UCP(0x201A) : closeQuote = UCP(0x201B);
+ break;
+ case UCP(0x201C) : closeQuote = UCP(0x201D);
+ break;
+ case UCP(0x201E) : closeQuote = UCP(0x201F);
+ break;
+ case UCP(0x2039) : closeQuote = UCP(0x203A); // ! U+2039 and U+203A are reversible.
+ break;
+ case UCP(0x203A) : closeQuote = UCP(0x2039);
+ break;
+ case UCP(0x3008) : closeQuote = UCP(0x3009);
+ break;
+ case UCP(0x300A) : closeQuote = UCP(0x300B);
+ break;
+ case UCP(0x300C) : closeQuote = UCP(0x300D);
+ break;
+ case UCP(0x300E) : closeQuote = UCP(0x300F);
+ break;
+ case UCP(0x301D) : closeQuote = UCP(0x301F); // ! U+301E also closes U+301D.
+ break;
+ default : closeQuote = 0;
+ break;
+
+ }
+
+ return closeQuote;
+
+} // GetClosingQuote
+
+
+// -------------------------------------------------------------------------------------------------
+// CodePointToUTF8
+// ---------------
+
+static void
+CodePointToUTF8 ( UniCodePoint uniChar, XMP_VarString & utf8Str )
+{
+ size_t i, byteCount;
+ XMP_Uns8 buffer [8];
+ UniCodePoint cpTemp;
+
+ if ( uniChar <= 0x7F ) {
+
+ i = 7;
+ byteCount = 1;
+ buffer[7] = char(uniChar);
+
+ } else {
+
+ // ---------------------------------------------------------------------------------------
+ // Copy the data bits from the low order end to the high order end, include the 0x80 mask.
+
+ i = 8;
+ cpTemp = uniChar;
+ while ( cpTemp != 0 ) {
+ -- i; // Exit with i pointing to the last byte stored.
+ buffer[i] = UnsByte(0x80) | (UnsByte(cpTemp) & 0x3F);
+ cpTemp = cpTemp >> 6;
+ }
+ byteCount = 8 - i; // The total number of bytes needed.
+
+ // -------------------------------------------------------------------------------------
+ // Make sure the high order byte can hold the byte count mask, compute and set the mask.
+
+ size_t bitCount = 0; // The number of data bits in the first byte.
+ for ( cpTemp = (buffer[i] & UnsByte(0x3F)); cpTemp != 0; cpTemp = cpTemp >> 1 ) bitCount += 1;
+ if ( bitCount > (8 - (byteCount + 1)) ) byteCount += 1;
+
+ i = 8 - byteCount; // First byte index and mask shift count.
+ buffer[i] |= (UnsByte(0xFF) << i) & UnsByte(0xFF);
+
+ }
+
+ utf8Str.assign ( (char*)(&buffer[i]), byteCount );
+
+} // CodePointToUTF8
+
+
+// -------------------------------------------------------------------------------------------------
+// ApplyQuotes
+// -----------
+
+static void
+ApplyQuotes ( XMP_VarString * item, UniCodePoint openQuote, UniCodePoint closeQuote, bool allowCommas )
+{
+ bool prevSpace = false;
+ size_t charOffset, charLen;
+ UniCharKind charKind;
+ UniCodePoint uniChar;
+
+ // -----------------------------------------------------------------------------------------
+ // See if there are any separators in the value. Stop at the first occurrance. This is a bit
+ // tricky in order to make typical typing work conveniently. The purpose of applying quotes
+ // is to preserve the values when splitting them back apart. That is CatenateContainerItems
+ // and SeparateContainerItems must round trip properly. For the most part we only look for
+ // separators here. Internal quotes, as in -- Irving "Bud" Jones -- won't cause problems in
+ // the separation. An initial quote will though, it will make the value look quoted.
+
+ charOffset = 0;
+ ClassifyCharacter ( item->c_str(), charOffset, &charKind, &charLen, &uniChar );
+
+ if ( charKind != UCK_quote ) {
+
+ for ( charOffset = 0; size_t(charOffset) < item->size(); charOffset += charLen ) {
+
+ ClassifyCharacter ( item->c_str(), charOffset, &charKind, &charLen, &uniChar );
+
+ if ( charKind == UCK_space ) {
+ if ( prevSpace ) break; // Multiple spaces are a separator.
+ prevSpace = true;
+ } else {
+ prevSpace = false;
+ if ( (charKind == UCK_semicolon) || (charKind == UCK_control) ) break;
+ if ( (charKind == UCK_comma) && (! allowCommas) ) break;
+ }
+
+ }
+
+ }
+
+ if ( size_t(charOffset) < item->size() ) {
+
+ // --------------------------------------------------------------------------------------
+ // Create a quoted copy, doubling any internal quotes that match the outer ones. Internal
+ // quotes did not stop the "needs quoting" search, but they do need doubling. So we have
+ // to rescan the front of the string for quotes. Handle the special case of U+301D being
+ // closed by either U+301E or U+301F.
+
+ XMP_VarString newItem;
+ size_t splitPoint;
+
+ for ( splitPoint = 0; splitPoint <= charOffset; ++splitPoint ) {
+ ClassifyCharacter ( item->c_str(), splitPoint, &charKind, &charLen, &uniChar );
+ if ( charKind == UCK_quote ) break;
+ }
+
+ CodePointToUTF8 ( openQuote, newItem );
+ newItem.append ( *item, 0, splitPoint ); // Copy the leading "normal" portion.
+
+ for ( charOffset = splitPoint; size_t(charOffset) < item->size(); charOffset += charLen ) {
+ ClassifyCharacter ( item->c_str(), charOffset, &charKind, &charLen, &uniChar );
+ newItem.append ( *item, charOffset, charLen );
+ if ( (charKind == UCK_quote) && IsSurroundingQuote ( uniChar, openQuote, closeQuote ) ) {
+ newItem.append ( *item, charOffset, charLen );
+ }
+ }
+
+ XMP_VarString closeStr;
+ CodePointToUTF8 ( closeQuote, closeStr );
+ newItem.append ( closeStr );
+
+ *item = newItem;
+
+ }
+
+} // ApplyQuotes
+
+
+// -------------------------------------------------------------------------------------------------
+// IsInternalProperty
+// ------------------
+
+// *** Need static checks of the schema prefixes!
+
+#define IsExternalProperty(s,p) (! IsInternalProperty ( s, p ))
+
+static bool
+IsInternalProperty ( const XMP_VarString & schema, const XMP_VarString & prop )
+{
+ bool isInternal = false;
+
+ if ( schema == kXMP_NS_DC ) {
+
+ if ( (prop == "dc:format") ||
+ (prop == "dc:language") ) {
+ isInternal = true;
+ }
+
+ } else if ( schema == kXMP_NS_XMP ) {
+
+ if ( (prop == "xap:BaseURL") ||
+ (prop == "xap:CreatorTool") ||
+ (prop == "xap:Format") ||
+ (prop == "xap:Locale") ||
+ (prop == "xap:MetadataDate") ||
+ (prop == "xap:ModifyDate") ) {
+ isInternal = true;
+ }
+
+ } else if ( schema == kXMP_NS_PDF ) {
+
+ if ( (prop == "pdf:BaseURL") ||
+ (prop == "pdf:Creator") ||
+ (prop == "pdf:ModDate") ||
+ (prop == "pdf:PDFVersion") ||
+ (prop == "pdf:Producer") ) {
+ isInternal = true;
+ }
+
+ } else if ( schema == kXMP_NS_TIFF ) {
+
+ isInternal = true; // ! The TIFF properties are internal by default.
+ if ( (prop == "tiff:ImageDescription") || // ! ImageDescription, Artist, and Copyright are aliased.
+ (prop == "tiff:Artist") ||
+ (prop == "tiff:Copyright") ) {
+ isInternal = false;
+ }
+
+ } else if ( schema == kXMP_NS_EXIF ) {
+
+ isInternal = true; // ! The EXIF properties are internal by default.
+ if ( prop == "exif:UserComment" ) isInternal = false;
+
+ } else if ( schema == kXMP_NS_EXIF_Aux ) {
+
+ isInternal = true; // ! The EXIF Aux properties are internal by default.
+
+ } else if ( schema == kXMP_NS_Photoshop ) {
+
+ if ( prop == "photoshop:ICCProfile" ) isInternal = true;
+
+ } else if ( schema == kXMP_NS_CameraRaw ) {
+
+ if ( (prop == "crs:Version") ||
+ (prop == "crs:RawFileName") ||
+ (prop == "crs:ToneCurveName") ) {
+ isInternal = true;
+ }
+
+ } else if ( schema == kXMP_NS_AdobeStockPhoto ) {
+
+ isInternal = true; // ! The bmsp schema has only internal properties.
+
+ } else if ( schema == kXMP_NS_XMP_MM ) {
+
+ isInternal = true; // ! The xmpMM schema has only internal properties.
+
+ } else if ( schema == kXMP_NS_XMP_Text ) {
+
+ isInternal = true; // ! The xmpT schema has only internal properties.
+
+ } else if ( schema == kXMP_NS_XMP_PagedFile ) {
+
+ isInternal = true; // ! The xmpTPg schema has only internal properties.
+
+ } else if ( schema == kXMP_NS_XMP_Graphics ) {
+
+ isInternal = true; // ! The xmpG schema has only internal properties.
+
+ } else if ( schema == kXMP_NS_XMP_Image ) {
+
+ isInternal = true; // ! The xmpGImg schema has only internal properties.
+
+ } else if ( schema == kXMP_NS_XMP_Font ) {
+
+ isInternal = true; // ! The stFNT schema has only internal properties.
+
+ }
+
+ return isInternal;
+
+} // IsInternalProperty
+
+
+// -------------------------------------------------------------------------------------------------
+// RemoveSchemaChildren
+// --------------------
+
+static void
+RemoveSchemaChildren ( XMP_NodePtrPos schemaPos, bool doAll )
+{
+ XMP_Node * schemaNode = *schemaPos;
+ XMP_Assert ( XMP_NodeIsSchema ( schemaNode->options ) );
+
+ // ! Iterate backwards to reduce shuffling as children are erased and to simplify the logic for
+ // ! denoting the current child. (Erasing child n makes the old n+1 now be n.)
+
+ size_t propCount = schemaNode->children.size();
+ XMP_NodePtrPos beginPos = schemaNode->children.begin();
+
+ for ( size_t propNum = propCount-1, propLim = (size_t)(-1); propNum != propLim; --propNum ) {
+ XMP_NodePtrPos currProp = beginPos + propNum;
+ if ( doAll || IsExternalProperty ( schemaNode->name, (*currProp)->name ) ) {
+ delete *currProp; // ! Both delete the node and erase the pointer from the parent.
+ schemaNode->children.erase ( currProp );
+ }
+ }
+
+ if ( schemaNode->children.empty() ) {
+ XMP_Node * tree = schemaNode->parent;
+ tree->children.erase ( schemaPos );
+ delete schemaNode;
+ }
+
+} // RemoveSchemaChildren
+
+
+// -------------------------------------------------------------------------------------------------
+// ItemValuesMatch
+// ---------------
+//
+// Does the value comparisons for array merging as part of XMPUtils::AppendProperties.
+
+static bool
+ItemValuesMatch ( const XMP_Node * leftNode, const XMP_Node * rightNode )
+{
+ const XMP_OptionBits leftForm = leftNode->options & kXMP_PropCompositeMask;
+ const XMP_OptionBits rightForm = leftNode->options & kXMP_PropCompositeMask;
+
+ if ( leftForm != rightForm ) return false;
+
+ if ( leftForm == 0 ) {
+
+ // Simple nodes, check the values and xml:lang qualifiers.
+
+ if ( leftNode->value != rightNode->value ) return false;
+ if ( (leftNode->options & kXMP_PropHasLang) != (rightNode->options & kXMP_PropHasLang) ) return false;
+ if ( leftNode->options & kXMP_PropHasLang ) {
+ if ( leftNode->qualifiers[0]->value != rightNode->qualifiers[0]->value ) return false;
+ }
+
+ } else if ( leftForm == kXMP_PropValueIsStruct ) {
+
+ // Struct nodes, see if all fields match, ignoring order.
+
+ if ( leftNode->children.size() != rightNode->children.size() ) return false;
+
+ for ( size_t leftNum = 0, leftLim = leftNode->children.size(); leftNum != leftLim; ++leftNum ) {
+ const XMP_Node * leftField = leftNode->children[leftNum];
+ const XMP_Node * rightField = FindConstChild ( rightNode, leftField->name.c_str() );
+ if ( (rightField == 0) || (! ItemValuesMatch ( leftField, rightField )) ) return false;
+ }
+
+ } else {
+
+ // Array nodes, see if the "leftNode" values are present in the "rightNode", ignoring order, duplicates,
+ // and extra values in the rightNode-> The rightNode is the destination for AppendProperties.
+
+ XMP_Assert ( leftForm & kXMP_PropValueIsArray );
+
+ for ( size_t leftNum = 0, leftLim = leftNode->children.size(); leftNum != leftLim; ++leftNum ) {
+
+ const XMP_Node * leftItem = leftNode->children[leftNum];
+
+ size_t rightNum, rightLim;
+ for ( rightNum = 0, rightLim = rightNode->children.size(); rightNum != rightLim; ++rightNum ) {
+ const XMP_Node * rightItem = rightNode->children[rightNum];
+ if ( ItemValuesMatch ( leftItem, rightItem ) ) break;
+ }
+ if ( rightNum == rightLim ) return false;
+
+ }
+
+ }
+
+ return true; // All of the checks passed.
+
+} // ItemValuesMatch
+
+
+// -------------------------------------------------------------------------------------------------
+// AppendSubtree
+// -------------
+//
+// The main implementation of XMPUtils::AppendProperties. See the description in TXMPMeta.hpp.
+
+static void
+AppendSubtree ( const XMP_Node * sourceNode, XMP_Node * destParent, const bool replaceOld, const bool deleteEmpty )
+{
+ XMP_NodePtrPos destPos;
+ XMP_Node * destNode = FindChildNode ( destParent, sourceNode->name.c_str(), kXMP_ExistingOnly, &destPos );
+
+ bool valueIsEmpty = false;
+ if ( deleteEmpty ) {
+ if ( XMP_PropIsSimple ( sourceNode->options ) ) {
+ valueIsEmpty = sourceNode->value.empty();
+ } else {
+ valueIsEmpty = sourceNode->children.empty();
+ }
+ }
+
+ if ( deleteEmpty & valueIsEmpty ) {
+
+ if ( destNode != 0 ) {
+ delete ( destNode );
+ destParent->children.erase ( destPos );
+ }
+
+ } else if ( destNode == 0 ) {
+
+ // The one easy case, the destination does not exist.
+ CloneSubtree ( sourceNode, destParent );
+
+ } else if ( replaceOld ) {
+
+ // The destination exists and should be replaced.
+
+ destNode->value = sourceNode->value; // *** Should use SetNode.
+ destNode->options = sourceNode->options;
+ destNode->RemoveChildren();
+ destNode->RemoveQualifiers();
+ CloneOffspring ( sourceNode, destNode );
+
+ #if 0 // *** XMP_DebugBuild
+ destNode->_valuePtr = destNode->value.c_str();
+ #endif
+
+ } else {
+
+ // The destination exists and is not totally replaced. Structs and arrays are merged.
+
+ XMP_OptionBits sourceForm = sourceNode->options & kXMP_PropCompositeMask;
+ XMP_OptionBits destForm = destNode->options & kXMP_PropCompositeMask;
+ if ( sourceForm != destForm ) return;
+
+ if ( sourceForm == kXMP_PropValueIsStruct ) {
+
+ // To merge a struct process the fields recursively. E.g. add simple missing fields. The
+ // recursive call to AppendSubtree will handle deletion for fields with empty values.
+
+ for ( size_t sourceNum = 0, sourceLim = sourceNode->children.size(); sourceNum != sourceLim; ++sourceNum ) {
+ const XMP_Node * sourceField = sourceNode->children[sourceNum];
+ AppendSubtree ( sourceField, destNode, replaceOld, deleteEmpty );
+ if ( deleteEmpty && destNode->children.empty() ) {
+ delete ( destNode );
+ destParent->children.erase ( destPos );
+ }
+ }
+
+ } else if ( sourceForm & kXMP_PropArrayIsAltText ) {
+
+ // Merge AltText arrays by the xml:lang qualifiers. Make sure x-default is first. Make a
+ // special check for deletion of empty values. Meaningful in AltText arrays because the
+ // xml:lang qualifier provides unambiguous source/dest correspondence.
+
+ for ( size_t sourceNum = 0, sourceLim = sourceNode->children.size(); sourceNum != sourceLim; ++sourceNum ) {
+
+ const XMP_Node * sourceItem = sourceNode->children[sourceNum];
+ if ( sourceItem->qualifiers.empty() || (sourceItem->qualifiers[0]->name != "xml:lang") ) continue;
+
+ XMP_Index destIndex = LookupLangItem ( destNode, sourceItem->qualifiers[0]->value );
+
+ if ( deleteEmpty && sourceItem->value.empty() ) {
+
+ if ( destIndex != -1 ) {
+ delete ( destNode->children[destIndex] );
+ destNode->children.erase ( destNode->children.begin() + destIndex );
+ if ( destNode->children.empty() ) {
+ delete ( destNode );
+ destParent->children.erase ( destPos );
+ }
+ }
+
+ } else {
+
+ if ( destIndex != -1 ) continue; // Not replacing, keep the existing item.
+
+ if ( (sourceItem->qualifiers[0]->value != "x-default") || destNode->children.empty() ) {
+ CloneSubtree ( sourceItem, destNode );
+ } else {
+ XMP_Node * destItem = new XMP_Node ( destNode, sourceItem->name, sourceItem->value, sourceItem->options );
+ CloneOffspring ( sourceItem, destItem );
+ destNode->children.insert ( destNode->children.begin(), destItem );
+ }
+
+ }
+
+ }
+
+ } else if ( sourceForm & kXMP_PropValueIsArray ) {
+
+ // Merge other arrays by item values. Don't worry about order or duplicates. Source
+ // items with empty values do not cause deletion, that conflicts horribly with merging.
+
+ for ( size_t sourceNum = 0, sourceLim = sourceNode->children.size(); sourceNum != sourceLim; ++sourceNum ) {
+ const XMP_Node * sourceItem = sourceNode->children[sourceNum];
+
+ size_t destNum, destLim;
+ for ( destNum = 0, destLim = destNode->children.size(); destNum != destLim; ++destNum ) {
+ const XMP_Node * destItem = destNode->children[destNum];
+ if ( ItemValuesMatch ( sourceItem, destItem ) ) break;
+ }
+ if ( destNum == destLim ) CloneSubtree ( sourceItem, destNode );
+
+ }
+
+ }
+
+ }
+
+} // AppendSubtree
+
+
+// =================================================================================================
+// Class Static Functions
+// ======================
+
+// -------------------------------------------------------------------------------------------------
+// CatenateArrayItems
+// ------------------
+
+/* class static */ void
+XMPUtils::CatenateArrayItems ( const XMPMeta & xmpObj,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_StringPtr separator,
+ XMP_StringPtr quotes,
+ XMP_OptionBits options,
+ XMP_StringPtr * catedStr,
+ XMP_StringLen * catedLen )
+{
+ XMP_Assert ( (schemaNS != 0) && (arrayName != 0) ); // ! Enforced by wrapper.
+ XMP_Assert ( (separator != 0) && (quotes != 0) && (catedStr != 0) && (catedLen != 0) ); // ! Enforced by wrapper.
+
+ size_t strLen, strPos, charLen;
+ UniCharKind charKind;
+ UniCodePoint currUCP, openQuote, closeQuote;
+
+ const bool allowCommas = ((options & kXMPUtil_AllowCommas) != 0);
+
+ const XMP_Node * arrayNode = 0; // ! Move up to avoid gcc complaints.
+ XMP_OptionBits arrayForm = 0;
+ const XMP_Node * currItem = 0;
+
+ // Make sure the separator is OK. It must be one semicolon surrounded by zero or more spaces.
+ // Any of the recognized semicolons or spaces are allowed.
+
+ strPos = 0;
+ strLen = strlen ( separator );
+ bool haveSemicolon = false;
+
+ while ( strPos < strLen ) {
+ ClassifyCharacter ( separator, strPos, &charKind, &charLen, &currUCP );
+ strPos += charLen;
+ if ( charKind == UCK_semicolon ) {
+ if ( haveSemicolon ) XMP_Throw ( "Separator can have only one semicolon", kXMPErr_BadParam );
+ haveSemicolon = true;
+ } else if ( charKind != UCK_space ) {
+ XMP_Throw ( "Separator can have only spaces and one semicolon", kXMPErr_BadParam );
+ }
+ };
+ if ( ! haveSemicolon ) XMP_Throw ( "Separator must have one semicolon", kXMPErr_BadParam );
+
+ // Make sure the open and close quotes are a legitimate pair.
+
+ strLen = strlen ( quotes );
+ ClassifyCharacter ( quotes, 0, &charKind, &charLen, &openQuote );
+ if ( charKind != UCK_quote ) XMP_Throw ( "Invalid quoting character", kXMPErr_BadParam );
+
+ if ( charLen == strLen ) {
+ closeQuote = openQuote;
+ } else {
+ strPos = charLen;
+ ClassifyCharacter ( quotes, strPos, &charKind, &charLen, &closeQuote );
+ if ( charKind != UCK_quote ) XMP_Throw ( "Invalid quoting character", kXMPErr_BadParam );
+ if ( (strPos + charLen) != strLen ) XMP_Throw ( "Quoting string too long", kXMPErr_BadParam );
+ }
+ if ( closeQuote != GetClosingQuote ( openQuote ) ) XMP_Throw ( "Mismatched quote pair", kXMPErr_BadParam );
+
+ // Return an empty result if the array does not exist, hurl if it isn't the right form.
+
+ sCatenatedItems->erase();
+
+ XMP_ExpandedXPath arrayPath;
+ ExpandXPath ( schemaNS, arrayName, &arrayPath );
+
+ arrayNode = FindConstNode ( &xmpObj.tree, arrayPath );
+ if ( arrayNode == 0 ) goto EXIT; // ! Need to set the output pointer and length.
+
+ arrayForm = arrayNode->options & kXMP_PropCompositeMask;
+ if ( (! (arrayForm & kXMP_PropValueIsArray)) || (arrayForm & kXMP_PropArrayIsAlternate) ) {
+ XMP_Throw ( "Named property must be non-alternate array", kXMPErr_BadParam );
+ }
+ if ( arrayNode->children.empty() ) goto EXIT; // ! Need to set the output pointer and length.
+
+ // Build the result, quoting the array items, adding separators. Hurl if any item isn't simple.
+ // Start the result with the first value, then add the rest with a preceeding separator.
+
+ currItem = arrayNode->children[0];
+
+ if ( (currItem->options & kXMP_PropCompositeMask) != 0 ) XMP_Throw ( "Array items must be simple", kXMPErr_BadParam );
+ *sCatenatedItems = currItem->value;
+ ApplyQuotes ( sCatenatedItems, openQuote, closeQuote, allowCommas );
+
+ for ( size_t itemNum = 1, itemLim = arrayNode->children.size(); itemNum != itemLim; ++itemNum ) {
+ const XMP_Node * currItem = arrayNode->children[itemNum];
+ if ( (currItem->options & kXMP_PropCompositeMask) != 0 ) XMP_Throw ( "Array items must be simple", kXMPErr_BadParam );
+ XMP_VarString tempStr ( currItem->value );
+ ApplyQuotes ( &tempStr, openQuote, closeQuote, allowCommas );
+ *sCatenatedItems += separator;
+ *sCatenatedItems += tempStr;
+ }
+
+EXIT:
+ *catedStr = sCatenatedItems->c_str();
+ *catedLen = sCatenatedItems->size();
+
+} // CatenateArrayItems
+
+
+// -------------------------------------------------------------------------------------------------
+// SeparateArrayItems
+// ------------------
+
+/* class static */ void
+XMPUtils::SeparateArrayItems ( XMPMeta * xmpObj,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_OptionBits options,
+ XMP_StringPtr catedStr )
+{
+ XMP_Assert ( (schemaNS != 0) && (arrayName != 0) && (catedStr != 0) ); // ! Enforced by wrapper.
+
+ XMP_VarString itemValue;
+ size_t itemStart, itemEnd;
+ size_t nextSize, charSize = 0; // Avoid VS uninit var warnings.
+ UniCharKind nextKind, charKind = UCK_normal;
+ UniCodePoint nextChar, uniChar = 0;
+
+ // Extract "special" option bits, verify and normalize the others.
+
+ bool preserveCommas = false;
+ if ( options & kXMPUtil_AllowCommas ) {
+ preserveCommas = true;
+ options ^= kXMPUtil_AllowCommas;
+ }
+
+ options = VerifySetOptions ( options, 0 ); // Keep a zero value, has special meaning below.
+ if ( options & ~kXMP_PropArrayFormMask ) XMP_Throw ( "Options can only provide array form", kXMPErr_BadOptions );
+
+ // Find the array node, make sure it is OK. Move the current children aside, to be readded later if kept.
+
+ XMP_ExpandedXPath arrayPath;
+ ExpandXPath ( schemaNS, arrayName, &arrayPath );
+ XMP_Node * arrayNode = FindNode ( &xmpObj->tree, arrayPath, kXMP_ExistingOnly );
+
+ if ( arrayNode != 0 ) {
+ // The array exists, make sure the form is compatible. Zero arrayForm means take what exists.
+ XMP_OptionBits arrayForm = arrayNode->options & kXMP_PropArrayFormMask;
+ if ( (arrayForm == 0) || (arrayForm & kXMP_PropArrayIsAlternate) ) {
+ XMP_Throw ( "Named property must be non-alternate array", kXMPErr_BadXPath );
+ }
+ if ( (options != 0) && (options != arrayForm) ) XMP_Throw ( "Mismatch of specified and existing array form", kXMPErr_BadXPath ); // *** Right error?
+ } else {
+ // The array does not exist, try to create it.
+ arrayNode = FindNode ( &xmpObj->tree, arrayPath, kXMP_CreateNodes, (options | kXMP_PropValueIsArray) );
+ if ( arrayNode == 0 ) XMP_Throw ( "Failed to create named array", kXMPErr_BadXPath );
+ }
+
+ XMP_NodeOffspring oldChildren ( arrayNode->children );
+ size_t oldChildCount = oldChildren.size();
+ arrayNode->children.clear();
+
+ // Extract the item values one at a time, until the whole input string is done. Be very careful
+ // in the extraction about the string positions. They are essentially byte pointers, while the
+ // contents are UTF-8. Adding or subtracting 1 does not necessarily move 1 Unicode character!
+
+ size_t endPos = strlen ( catedStr );
+
+ itemEnd = 0;
+ while ( itemEnd < endPos ) {
+
+ // Skip any leading spaces and separation characters. Always skip commas here. They can be
+ // kept when within a value, but not when alone between values.
+
+ for ( itemStart = itemEnd; itemStart < endPos; itemStart += charSize ) {
+ ClassifyCharacter ( catedStr, itemStart, &charKind, &charSize, &uniChar );
+ if ( (charKind == UCK_normal) || (charKind == UCK_quote) ) break;
+ }
+ if ( itemStart >= endPos ) break;
+
+ if ( charKind != UCK_quote ) {
+
+ // This is not a quoted value. Scan for the end, create an array item from the substring.
+
+ for ( itemEnd = itemStart; itemEnd < endPos; itemEnd += charSize ) {
+
+ ClassifyCharacter ( catedStr, itemEnd, &charKind, &charSize, &uniChar );
+
+ if ( (charKind == UCK_normal) || (charKind == UCK_quote) ) continue;
+ if ( (charKind == UCK_comma) && preserveCommas ) continue;
+ if ( charKind != UCK_space ) break;
+
+ if ( (itemEnd + charSize) >= endPos ) break; // Anything left?
+ ClassifyCharacter ( catedStr, (itemEnd+charSize), &nextKind, &nextSize, &nextChar );
+ if ( (nextKind == UCK_normal) || (nextKind == UCK_quote) ) continue;
+ if ( (nextKind == UCK_comma) && preserveCommas ) continue;
+ break; // Have multiple spaces, or a space followed by a separator.
+
+ }
+
+ itemValue.assign ( catedStr, itemStart, (itemEnd - itemStart) );
+
+ } else {
+
+ // Accumulate quoted values into a local string, undoubling internal quotes that
+ // match the surrounding quotes. Do not undouble "unmatching" quotes.
+
+ UniCodePoint openQuote = uniChar;
+ UniCodePoint closeQuote = GetClosingQuote ( openQuote );
+
+ itemStart += charSize; // Skip the opening quote;
+ itemValue.erase();
+
+ for ( itemEnd = itemStart; itemEnd < endPos; itemEnd += charSize ) {
+
+ ClassifyCharacter ( catedStr, itemEnd, &charKind, &charSize, &uniChar );
+
+ if ( (charKind != UCK_quote) || (! IsSurroundingQuote ( uniChar, openQuote, closeQuote)) ) {
+
+ // This is not a matching quote, just append it to the item value.
+ itemValue.append ( catedStr, itemEnd, charSize );
+
+ } else {
+
+ // This is a "matching" quote. Is it doubled, or the final closing quote? Tolerate
+ // various edge cases like undoubled opening (non-closing) quotes, or end of input.
+
+ if ( (itemEnd + charSize) < endPos ) {
+ ClassifyCharacter ( catedStr, itemEnd+charSize, &nextKind, &nextSize, &nextChar );
+ } else {
+ nextKind = UCK_semicolon; nextSize = 0; nextChar = 0x3B;
+ }
+
+ if ( uniChar == nextChar ) {
+ // This is doubled, copy it and skip the double.
+ itemValue.append ( catedStr, itemEnd, charSize );
+ itemEnd += nextSize; // Loop will add in charSize.
+ } else if ( ! IsClosingingQuote ( uniChar, openQuote, closeQuote ) ) {
+ // This is an undoubled, non-closing quote, copy it.
+ itemValue.append ( catedStr, itemEnd, charSize );
+ } else {
+ // This is an undoubled closing quote, skip it and exit the loop.
+ itemEnd += charSize;
+ break;
+ }
+
+ }
+
+ } // Loop to accumulate the quoted value.
+
+ }
+
+ // Add the separated item to the array. Keep a matching old value in case it had separators.
+
+ size_t oldChild;
+ for ( oldChild = 0; oldChild < oldChildCount; ++oldChild ) {
+ if ( (oldChildren[oldChild] != 0) && (itemValue == oldChildren[oldChild]->value) ) break;
+ }
+
+ XMP_Node * newItem = 0;
+ if ( oldChild == oldChildCount ) {
+ newItem = new XMP_Node ( arrayNode, kXMP_ArrayItemName, itemValue.c_str(), 0 );
+ } else {
+ newItem = oldChildren[oldChild];
+ oldChildren[oldChild] = 0; // ! Don't match again, let duplicates be seen.
+ }
+ arrayNode->children.push_back ( newItem );
+
+ } // Loop through all of the returned items.
+
+ // Delete any of the old children that were not kept.
+ for ( size_t i = 0; i < oldChildCount; ++i ) {
+ if ( oldChildren[i] != 0 ) delete oldChildren[i];
+ }
+
+} // SeparateArrayItems
+
+
+// -------------------------------------------------------------------------------------------------
+// RemoveProperties
+// ----------------
+
+/* class static */ void
+XMPUtils::RemoveProperties ( XMPMeta * xmpObj,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_OptionBits options )
+{
+ XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // ! Enforced by wrapper.
+
+ const bool doAll = XMP_TestOption (options, kXMPUtil_DoAllProperties );
+ const bool includeAliases = XMP_TestOption ( options, kXMPUtil_IncludeAliases );
+
+ if ( *propName != 0 ) {
+
+ // Remove just the one indicated property. This might be an alias, the named schema might
+ // not actually exist. So don't lookup the schema node.
+
+ if ( *schemaNS == 0 ) XMP_Throw ( "Property name requires schema namespace", kXMPErr_BadParam );
+
+ XMP_ExpandedXPath expPath;
+ ExpandXPath ( schemaNS, propName, &expPath );
+
+ XMP_NodePtrPos propPos;
+ XMP_Node * propNode = FindNode ( &(xmpObj->tree), expPath, kXMP_ExistingOnly, kXMP_NoOptions, &propPos );
+ if ( propNode != 0 ) {
+ if ( doAll || IsExternalProperty ( expPath[kSchemaStep].step, expPath[kRootPropStep].step ) ) {
+ XMP_Node * parent = propNode->parent; // *** Should have XMP_Node::RemoveChild(pos).
+ delete propNode; // ! Both delete the node and erase the pointer from the parent.
+ parent->children.erase ( propPos );
+ DeleteEmptySchema ( parent );
+ }
+ }
+
+ } else if ( *schemaNS != 0 ) {
+
+ // Remove all properties from the named schema. Optionally include aliases, in which case
+ // there might not be an actual schema node.
+
+ XMP_NodePtrPos schemaPos;
+ XMP_Node * schemaNode = FindSchemaNode ( &xmpObj->tree, schemaNS, kXMP_ExistingOnly, &schemaPos );
+ if ( schemaNode != 0 ) RemoveSchemaChildren ( schemaPos, doAll );
+
+ if ( includeAliases ) {
+
+ // We're removing the aliases also. Look them up by their namespace prefix. Yes, the
+ // alias map is sorted so we could process just that portion. But that takes more code
+ // and the extra speed isn't worth it. (Plus this way we avoid a dependence on the map
+ // implementation.) Lookup the XMP node from the alias, to make sure the actual exists.
+
+ XMP_StringPtr nsPrefix;
+ XMP_StringLen nsLen;
+ (void) XMPMeta::GetNamespacePrefix ( schemaNS, &nsPrefix, &nsLen );
+
+ XMP_AliasMapPos currAlias = sRegisteredAliasMap->begin();
+ XMP_AliasMapPos endAlias = sRegisteredAliasMap->end();
+
+ for ( ; currAlias != endAlias; ++currAlias ) {
+ if ( strncmp ( currAlias->first.c_str(), nsPrefix, nsLen ) == 0 ) {
+ XMP_NodePtrPos actualPos;
+ XMP_Node * actualProp = FindNode ( &xmpObj->tree, currAlias->second, kXMP_ExistingOnly, kXMP_NoOptions, &actualPos );
+ if ( actualProp != 0 ) {
+ XMP_Node * rootProp = actualProp;
+ while ( ! XMP_NodeIsSchema ( rootProp->parent->options ) ) rootProp = rootProp->parent;
+ if ( doAll || IsExternalProperty ( rootProp->parent->name, rootProp->name ) ) {
+ XMP_Node * parent = actualProp->parent;
+ delete actualProp; // ! Both delete the node and erase the pointer from the parent.
+ parent->children.erase ( actualPos );
+ DeleteEmptySchema ( parent );
+ }
+ }
+ }
+ }
+
+ }
+
+ } else {
+
+ // Remove all appropriate properties from all schema. In this case we don't have to be
+ // concerned with aliases, they are handled implicitly from the actual properties.
+
+ // ! Iterate backwards to reduce shuffling if schema are erased and to simplify the logic
+ // ! for denoting the current schema. (Erasing schema n makes the old n+1 now be n.)
+
+ size_t schemaCount = xmpObj->tree.children.size();
+ XMP_NodePtrPos beginPos = xmpObj->tree.children.begin();
+
+ for ( size_t schemaNum = schemaCount-1, schemaLim = (size_t)(-1); schemaNum != schemaLim; --schemaNum ) {
+ XMP_NodePtrPos currSchema = beginPos + schemaNum;
+ RemoveSchemaChildren ( currSchema, doAll );
+ }
+
+ }
+
+} // RemoveProperties
+
+
+// -------------------------------------------------------------------------------------------------
+// AppendProperties
+// ----------------
+
+/* class static */ void
+XMPUtils::AppendProperties ( const XMPMeta & source,
+ XMPMeta * dest,
+ XMP_OptionBits options )
+{
+ XMP_Assert ( dest != 0 ); // ! Enforced by wrapper.
+
+ const bool doAll = ((options & kXMPUtil_DoAllProperties) != 0);
+ const bool replaceOld = ((options & kXMPUtil_ReplaceOldValues) != 0);
+ const bool deleteEmpty = ((options & kXMPUtil_DeleteEmptyValues) != 0);
+
+ for ( size_t schemaNum = 0, schemaLim = source.tree.children.size(); schemaNum != schemaLim; ++schemaNum ) {
+
+ const XMP_Node * sourceSchema = source.tree.children[schemaNum];
+
+ // Make sure we have a destination schema node. Remember if it is newly created.
+
+ XMP_Node * destSchema = FindSchemaNode ( &dest->tree, sourceSchema->name.c_str(), kXMP_ExistingOnly );
+ const bool newDestSchema = (destSchema == 0);
+ if ( newDestSchema ) {
+ destSchema = new XMP_Node ( &dest->tree, sourceSchema->name, sourceSchema->value, kXMP_SchemaNode );
+ dest->tree.children.push_back ( destSchema );
+ }
+
+ // Process the source schema's children. Do this backwards in case deleteEmpty is set.
+
+ for ( long propNum = ((long)sourceSchema->children.size() - 1); propNum >= 0; --propNum ) {
+ const XMP_Node * sourceProp = sourceSchema->children[propNum];
+ if ( doAll || IsExternalProperty ( sourceSchema->name, sourceProp->name ) ) {
+ AppendSubtree ( sourceProp, destSchema, replaceOld, deleteEmpty );
+// *** RemoveMultiValueInfo ( dest, sourceSchema->name.c_str(), sourceProp->name.c_str() );
+ }
+ }
+
+ if ( destSchema->children.empty() ) {
+ if ( newDestSchema ) {
+ delete ( destSchema );
+ dest->tree.children.pop_back();
+ } else if ( deleteEmpty ) {
+ DeleteEmptySchema ( destSchema );
+ }
+ }
+
+ }
+
+} // AppendProperties
+
+
+// -------------------------------------------------------------------------------------------------
+// DuplicateSubtree
+// ----------------
+
+/* class static */ void
+XMPUtils::DuplicateSubtree ( const XMPMeta & source,
+ XMPMeta * dest,
+ XMP_StringPtr sourceNS,
+ XMP_StringPtr sourceRoot,
+ XMP_StringPtr destNS,
+ XMP_StringPtr destRoot,
+ XMP_OptionBits options )
+{
+ options = options; // Avoid unused parameter warning.
+
+ XMP_Assert ( (sourceNS != 0) && (*sourceNS != 0) );
+ XMP_Assert ( (sourceRoot != 0) && (*sourceRoot != 0) );
+ XMP_Assert ( (dest != 0) && (destNS != 0) && (destRoot != 0) );
+
+ if ( *destNS == 0 ) destNS = sourceNS;
+ if ( *destRoot == 0 ) destRoot = sourceRoot;
+
+ if ( (&source == dest) &&
+ XMP_LitMatch ( sourceNS, destNS ) &&
+ XMP_LitMatch ( sourceRoot, destRoot ) ) XMP_Throw ( "Can't duplicate subtree onto itself", kXMPErr_BadParam );
+
+ // Find the root nodes for the source and destination subtrees.
+
+ XMP_ExpandedXPath sourcePath, destPath;
+ ExpandXPath ( sourceNS, sourceRoot, &sourcePath );
+ ExpandXPath ( destNS, destRoot, &destPath );
+
+ XMP_Node * sourceNode = FindConstNode ( &source.tree, sourcePath );
+ if ( sourceNode == 0 ) XMP_Throw ( "Can't find source subtree", kXMPErr_BadXPath );
+
+ XMP_Node * destNode = FindNode ( &dest->tree, destPath, kXMP_ExistingOnly ); // Dest must not yet exist.
+ if ( destNode != 0 ) XMP_Throw ( "Destination subtree must not exist", kXMPErr_BadXPath );
+
+ destNode = FindNode ( &dest->tree, destPath, kXMP_CreateNodes ); // Now create the dest.
+ if ( destNode == 0 ) XMP_Throw ( "Can't create destination root node", kXMPErr_BadXPath );
+
+ // Make sure the destination is not within the source! The source can't be inside the destination
+ // because the source already existed and the destination was just created.
+
+ if ( &source == dest ) {
+ for ( XMP_Node * testNode = destNode; testNode != 0; testNode = testNode->parent ) {
+ if ( testNode == sourceNode ) {
+ // *** delete the just-created dest root node
+ XMP_Throw ( "Destination subtree is within the source subtree", kXMPErr_BadXPath );
+ }
+ }
+ }
+
+ // All OK, copy the subtree.
+ // *** Could use a CloneTree util here and maybe elsewhere.
+
+ destNode->value = sourceNode->value; // *** Should use SetNode.
+ destNode->options = sourceNode->options;
+ CloneOffspring ( sourceNode, destNode );
+
+ #if 0 // *** XMP_DebugBuild
+ destNode->_valuePtr = destNode->value.c_str();
+ #endif
+
+} // DuplicateSubtree
+
+
+// =================================================================================================
diff --git a/source/XMPCore/XMPUtils.cpp b/source/XMPCore/XMPUtils.cpp
new file mode 100644
index 0000000..0dacc0c
--- /dev/null
+++ b/source/XMPCore/XMPUtils.cpp
@@ -0,0 +1,2123 @@
+// =================================================================================================
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "XMP_Environment.h" // ! This must be the first include!
+#include "XMPCore_Impl.hpp"
+
+#include "XMPUtils.hpp"
+
+#include "MD5.h"
+
+#include <map>
+
+#include <time.h>
+#include <string.h>
+#include <stdlib.h>
+#include <locale.h>
+#include <errno.h>
+
+#include <stdio.h> // For snprintf.
+
+#if XMP_WinBuild
+ #pragma warning ( disable : 4800 ) // forcing value to bool 'true' or 'false' (performance warning)
+ #pragma warning ( disable : 4996 ) // '...' was declared deprecated
+#endif
+
+
+// =================================================================================================
+// Local Types and Constants
+// =========================
+
+static const char * sBase64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+// =================================================================================================
+// Static Variables
+// ================
+
+XMP_VarString * sComposedPath = 0; // *** Only really need 1 string. Shrink periodically?
+XMP_VarString * sConvertedValue = 0;
+XMP_VarString * sBase64Str = 0;
+XMP_VarString * sCatenatedItems = 0;
+XMP_VarString * sStandardXMP = 0;
+XMP_VarString * sExtendedXMP = 0;
+XMP_VarString * sExtendedDigest = 0;
+
+// =================================================================================================
+// Local Utilities
+// ===============
+
+
+// -------------------------------------------------------------------------------------------------
+// ANSI Time Functions
+// -------------------
+//
+// A bit of hackery to use the best available time functions. Mac and UNIX have thread safe versions
+// of gmtime and localtime. On Mac the CodeWarrior functions are buggy, use Apple's.
+
+#if XMP_UNIXBuild
+
+ typedef time_t ansi_tt;
+ typedef struct tm ansi_tm;
+
+ #define ansi_time time
+ #define ansi_mktime mktime
+ #define ansi_difftime difftime
+
+ #define ansi_gmtime gmtime_r
+ #define ansi_localtime localtime_r
+
+#elif XMP_WinBuild
+
+ // ! VS.Net 2003 (VC7) does not provide thread safe versions of gmtime and localtime.
+ // ! VS.Net 2005 (VC8) inverts the parameters for the safe versions of gmtime and localtime.
+
+ typedef time_t ansi_tt;
+ typedef struct tm ansi_tm;
+
+ #define ansi_time time
+ #define ansi_mktime mktime
+ #define ansi_difftime difftime
+
+ #if defined(_MSC_VER) && (_MSC_VER >= 1400)
+ #define ansi_gmtime(tt,tm) gmtime_s ( tm, tt )
+ #define ansi_localtime(tt,tm) localtime_s ( tm, tt )
+ #else
+ static inline void ansi_gmtime ( const ansi_tt * ttTime, ansi_tm * tmTime )
+ {
+ ansi_tm * tmx = gmtime ( ttTime ); // ! Hope that there is no race!
+ if ( tmx == 0 ) XMP_Throw ( "Failure from ANSI C gmtime function", kXMPErr_ExternalFailure );
+ *tmTime = *tmx;
+ }
+ static inline void ansi_localtime ( const ansi_tt * ttTime, ansi_tm * tmTime )
+ {
+ ansi_tm * tmx = localtime ( ttTime ); // ! Hope that there is no race!
+ if ( tmx == 0 ) XMP_Throw ( "Failure from ANSI C localtime function", kXMPErr_ExternalFailure );
+ *tmTime = *tmx;
+ }
+ #endif
+
+#elif XMP_MacBuild
+
+ #if ! __MWERKS__
+
+ typedef time_t ansi_tt;
+ typedef struct tm ansi_tm;
+
+ #define ansi_time time
+ #define ansi_mktime mktime
+ #define ansi_difftime difftime
+
+ #define ansi_gmtime gmtime_r
+ #define ansi_localtime localtime_r
+
+ #else
+
+ // ! The CW versions are buggy. Use Apple's code, time_t, and "struct tm".
+
+ #include <mach-o/dyld.h>
+
+ typedef _BSD_TIME_T_ ansi_tt;
+
+ typedef struct apple_tm {
+ int tm_sec; /* seconds after the minute [0-60] */
+ int tm_min; /* minutes after the hour [0-59] */
+ int tm_hour; /* hours since midnight [0-23] */
+ int tm_mday; /* day of the month [1-31] */
+ int tm_mon; /* months since January [0-11] */
+ int tm_year; /* years since 1900 */
+ int tm_wday; /* days since Sunday [0-6] */
+ int tm_yday; /* days since January 1 [0-365] */
+ int tm_isdst; /* Daylight Savings Time flag */
+ long tm_gmtoff; /* offset from CUT in seconds */
+ char *tm_zone; /* timezone abbreviation */
+ } ansi_tm;
+
+
+ typedef ansi_tt (* GetTimeProc) ( ansi_tt * ttTime );
+ typedef ansi_tt (* MakeTimeProc) ( ansi_tm * tmTime );
+ typedef double (* DiffTimeProc) ( ansi_tt t1, ansi_tt t0 );
+
+ typedef void (* ConvertTimeProc) ( const ansi_tt * ttTime, ansi_tm * tmTime );
+
+ static GetTimeProc ansi_time = 0;
+ static MakeTimeProc ansi_mktime = 0;
+ static DiffTimeProc ansi_difftime = 0;
+
+ static ConvertTimeProc ansi_gmtime = 0;
+ static ConvertTimeProc ansi_localtime = 0;
+
+ static void LookupTimeProcs()
+ {
+ _dyld_lookup_and_bind_with_hint ( "_time", "libSystem", (XMP_Uns32*)&ansi_time, 0 );
+ _dyld_lookup_and_bind_with_hint ( "_mktime", "libSystem", (XMP_Uns32*)&ansi_mktime, 0 );
+ _dyld_lookup_and_bind_with_hint ( "_difftime", "libSystem", (XMP_Uns32*)&ansi_difftime, 0 );
+ _dyld_lookup_and_bind_with_hint ( "_gmtime_r", "libSystem", (XMP_Uns32*)&ansi_gmtime, 0 );
+ _dyld_lookup_and_bind_with_hint ( "_localtime_r", "libSystem", (XMP_Uns32*)&ansi_localtime, 0 );
+ }
+
+ #endif
+
+#endif
+
+
+// -------------------------------------------------------------------------------------------------
+// IsLeapYear
+// ----------
+
+static bool
+IsLeapYear ( long year )
+{
+
+ if ( year < 0 ) year = -year + 1; // Fold the negative years, assuming there is a year 0.
+
+ if ( (year % 4) != 0 ) return false; // Not a multiple of 4.
+ if ( (year % 100) != 0 ) return true; // A multiple of 4 but not a multiple of 100.
+ if ( (year % 400) == 0 ) return true; // A multiple of 400.
+
+ return false; // A multiple of 100 but not a multiple of 400.
+
+} // IsLeapYear
+
+
+// -------------------------------------------------------------------------------------------------
+// DaysInMonth
+// -----------
+
+static int
+DaysInMonth ( XMP_Int32 year, XMP_Int32 month )
+{
+
+ static short daysInMonth[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+ // Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
+
+ int days = daysInMonth [ month ];
+ if ( (month == 2) && IsLeapYear ( year ) ) days += 1;
+
+ return days;
+
+} // DaysInMonth
+
+
+// -------------------------------------------------------------------------------------------------
+// AdjustTimeOverflow
+// ------------------
+
+static void
+AdjustTimeOverflow ( XMP_DateTime * time )
+{
+ enum { kBillion = 1000*1000*1000L };
+
+ // ----------------------------------------------------------------------------------------------
+ // To be safe against pathalogical overflow we first adjust from month to second, then from
+ // nanosecond back up to month. This leaves each value closer to zero before propagating into it.
+ // For example if the hour and minute are both near max, adjusting minutes first can cause the
+ // hour to overflow.
+
+ // ! Photoshop 8 creates "time only" values with zeros for year, month, and day.
+
+ if ( (time->year != 0) || (time->month != 0) || (time->day != 0) ) {
+
+ while ( time->month < 1 ) {
+ time->year -= 1;
+ time->month += 12;
+ }
+
+ while ( time->month > 12 ) {
+ time->year += 1;
+ time->month -= 12;
+ }
+
+ while ( time->day < 1 ) {
+ time->month -= 1;
+ if ( time->month < 1 ) { // ! Keep the months in range for indexing daysInMonth!
+ time->year -= 1;
+ time->month += 12;
+ }
+ time->day += DaysInMonth ( time->year, time->month ); // ! Decrement month before so index here is right!
+ }
+
+ while ( time->day > DaysInMonth ( time->year, time->month ) ) {
+ time->day -= DaysInMonth ( time->year, time->month ); // ! Increment month after so index here is right!
+ time->month += 1;
+ if ( time->month > 12 ) {
+ time->year += 1;
+ time->month -= 12;
+ }
+ }
+
+ }
+
+ while ( time->hour < 0 ) {
+ time->day -= 1;
+ time->hour += 24;
+ }
+
+ while ( time->hour >= 24 ) {
+ time->day += 1;
+ time->hour -= 24;
+ }
+
+ while ( time->minute < 0 ) {
+ time->hour -= 1;
+ time->minute += 60;
+ }
+
+ while ( time->minute >= 60 ) {
+ time->hour += 1;
+ time->minute -= 60;
+ }
+
+ while ( time->second < 0 ) {
+ time->minute -= 1;
+ time->second += 60;
+ }
+
+ while ( time->second >= 60 ) {
+ time->minute += 1;
+ time->second -= 60;
+ }
+
+ while ( time->nanoSecond < 0 ) {
+ time->second -= 1;
+ time->nanoSecond += kBillion;
+ }
+
+ while ( time->nanoSecond >= kBillion ) {
+ time->second += 1;
+ time->nanoSecond -= kBillion;
+ }
+
+ while ( time->second < 0 ) {
+ time->minute -= 1;
+ time->second += 60;
+ }
+
+ while ( time->second >= 60 ) {
+ time->minute += 1;
+ time->second -= 60;
+ }
+
+ while ( time->minute < 0 ) {
+ time->hour -= 1;
+ time->minute += 60;
+ }
+
+ while ( time->minute >= 60 ) {
+ time->hour += 1;
+ time->minute -= 60;
+ }
+
+ while ( time->hour < 0 ) {
+ time->day -= 1;
+ time->hour += 24;
+ }
+
+ while ( time->hour >= 24 ) {
+ time->day += 1;
+ time->hour -= 24;
+ }
+
+ if ( (time->year != 0) || (time->month != 0) || (time->day != 0) ) {
+
+ while ( time->month < 1 ) { // Make sure the months are OK first, for DaysInMonth.
+ time->year -= 1;
+ time->month += 12;
+ }
+
+ while ( time->month > 12 ) {
+ time->year += 1;
+ time->month -= 12;
+ }
+
+ while ( time->day < 1 ) {
+ time->month -= 1;
+ if ( time->month < 1 ) {
+ time->year -= 1;
+ time->month += 12;
+ }
+ time->day += DaysInMonth ( time->year, time->month );
+ }
+
+ while ( time->day > DaysInMonth ( time->year, time->month ) ) {
+ time->day -= DaysInMonth ( time->year, time->month );
+ time->month += 1;
+ if ( time->month > 12 ) {
+ time->year += 1;
+ time->month -= 12;
+ }
+ }
+
+ }
+
+} // AdjustTimeOverflow
+
+
+// -------------------------------------------------------------------------------------------------
+// GatherInt
+// ---------
+
+static XMP_Int32
+GatherInt ( XMP_StringPtr strValue, size_t * _pos, const char * errMsg )
+{
+ size_t pos = *_pos;
+ XMP_Int32 value = 0;
+
+ for ( char ch = strValue[pos]; ('0' <= ch) && (ch <= '9'); ++pos, ch = strValue[pos] ) {
+ value = (value * 10) + (ch - '0');
+ }
+
+ if ( pos == *_pos ) XMP_Throw ( errMsg, kXMPErr_BadParam );
+ *_pos = pos;
+ return value;
+
+} // GatherInt
+
+
+// -------------------------------------------------------------------------------------------------
+
+static void FormatFullDateTime ( XMP_DateTime & tempDate, char * buffer, size_t bufferLen )
+{
+
+ AdjustTimeOverflow ( &tempDate ); // Make sure all time parts are in range.
+
+ if ( (tempDate.second == 0) && (tempDate.nanoSecond == 0) ) {
+
+ // Output YYYY-MM-DDThh:mmTZD.
+ snprintf ( buffer, bufferLen, "%.4d-%02d-%02dT%02d:%02d", // AUDIT: Callers pass sizeof(buffer).
+ tempDate.year, tempDate.month, tempDate.day, tempDate.hour, tempDate.minute );
+
+ } else if ( tempDate.nanoSecond == 0 ) {
+
+ // Output YYYY-MM-DDThh:mm:ssTZD.
+ snprintf ( buffer, bufferLen, "%.4d-%02d-%02dT%02d:%02d:%02d", // AUDIT: Callers pass sizeof(buffer).
+ tempDate.year, tempDate.month, tempDate.day,
+ tempDate.hour, tempDate.minute, tempDate.second );
+
+ } else {
+
+ // Output YYYY-MM-DDThh:mm:ss.sTZD.
+ snprintf ( buffer, bufferLen, "%.4d-%02d-%02dT%02d:%02d:%02d.%09d", // AUDIT: Callers pass sizeof(buffer).
+ tempDate.year, tempDate.month, tempDate.day,
+ tempDate.hour, tempDate.minute, tempDate.second, tempDate.nanoSecond );
+ for ( size_t i = strlen(buffer)-1; buffer[i] == '0'; --i ) buffer[i] = 0; // Trim excess digits.
+
+ }
+
+} // FormatFullDateTime
+
+
+// -------------------------------------------------------------------------------------------------
+// DecodeBase64Char
+// ----------------
+
+// The decode mapping:
+//
+// encoded encoded raw
+// char value value
+// ------- ------- -----
+// A .. Z 0x41 .. 0x5A 0 .. 25
+// a .. z 0x61 .. 0x7A 26 .. 51
+// 0 .. 9 0x30 .. 0x39 52 .. 61
+// + 0x2B 62
+// / 0x2F 63
+
+static unsigned char
+DecodeBase64Char ( XMP_Uns8 ch )
+{
+
+ if ( ('A' <= ch) && (ch <= 'Z') ) {
+ ch = ch - 'A';
+ } else if ( ('a' <= ch) && (ch <= 'z') ) {
+ ch = ch - 'a' + 26;
+ } else if ( ('0' <= ch) && (ch <= '9') ) {
+ ch = ch - '0' + 52;
+ } else if ( ch == '+' ) {
+ ch = 62;
+ } else if ( ch == '/' ) {
+ ch = 63;
+ } else if ( (ch == ' ') || (ch == kTab) || (ch == kLF) || (ch == kCR) ) {
+ ch = 0xFF; // Will be ignored by the caller.
+ } else {
+ XMP_Throw ( "Invalid base-64 encoded character", kXMPErr_BadParam );
+ }
+
+ return ch;
+
+} // DecodeBase64Char ();
+
+
+// -------------------------------------------------------------------------------------------------
+// EstimateSizeForJPEG
+// -------------------
+//
+// Estimate the serialized size for the subtree of an XMP_Node. Support for PackageForJPEG.
+
+static size_t
+EstimateSizeForJPEG ( const XMP_Node * xmpNode )
+{
+
+ size_t estSize = 0;
+ size_t nameSize = xmpNode->name.size();
+ bool includeName = (! XMP_PropIsArray ( xmpNode->parent->options ));
+
+ if ( XMP_PropIsSimple ( xmpNode->options ) ) {
+
+ if ( includeName ) estSize += (nameSize + 3); // Assume attribute form.
+ estSize += xmpNode->value.size();
+
+ } else if ( XMP_PropIsArray ( xmpNode->options ) ) {
+
+ // The form of the value portion is: <rdf:Xyz><rdf:li>...</rdf:li>...</rdf:Xyx>
+ if ( includeName ) estSize += (2*nameSize + 5);
+ size_t arraySize = xmpNode->children.size();
+ estSize += 9 + 10; // The rdf:Xyz tags.
+ estSize += arraySize * (8 + 9); // The rdf:li tags.
+ for ( size_t i = 0; i < arraySize; ++i ) {
+ estSize += EstimateSizeForJPEG ( xmpNode->children[i] );
+ }
+
+ } else {
+
+ // The form is: <headTag rdf:parseType="Resource">...fields...</tailTag>
+ if ( includeName ) estSize += (2*nameSize + 5);
+ estSize += 25; // The rdf:parseType="Resource" attribute.
+ size_t fieldCount = xmpNode->children.size();
+ for ( size_t i = 0; i < fieldCount; ++i ) {
+ estSize += EstimateSizeForJPEG ( xmpNode->children[i] );
+ }
+
+ }
+
+ return estSize;
+
+} // EstimateSizeForJPEG
+
+
+// -------------------------------------------------------------------------------------------------
+// MoveOneProperty
+// ---------------
+
+static bool MoveOneProperty ( XMPMeta & stdXMP, XMPMeta * extXMP,
+ XMP_StringPtr schemaURI, XMP_StringPtr propName )
+{
+
+ XMP_Node * propNode = 0;
+ XMP_NodePtrPos stdPropPos;
+
+ XMP_Node * stdSchema = FindSchemaNode ( &stdXMP.tree, schemaURI, kXMP_ExistingOnly, 0 );
+ if ( stdSchema != 0 ) {
+ propNode = FindChildNode ( stdSchema, propName, kXMP_ExistingOnly, &stdPropPos );
+ }
+ if ( propNode == 0 ) return false;
+
+ XMP_Node * extSchema = FindSchemaNode ( &extXMP->tree, schemaURI, kXMP_CreateNodes );
+
+ propNode->parent = extSchema;
+
+ extSchema->options &= ~kXMP_NewImplicitNode;
+ extSchema->children.push_back ( propNode );
+
+ stdSchema->children.erase ( stdPropPos );
+ DeleteEmptySchema ( stdSchema );
+
+ return true;
+
+} // MoveOneProperty
+
+
+// -------------------------------------------------------------------------------------------------
+// CreateEstimatedSizeMap
+// ----------------------
+
+#ifndef Trace_PackageForJPEG
+ #define Trace_PackageForJPEG 0
+#endif
+
+typedef std::pair < XMP_VarString*, XMP_VarString* > StringPtrPair;
+typedef std::multimap < size_t, StringPtrPair > PropSizeMap;
+
+static void CreateEstimatedSizeMap ( XMPMeta & stdXMP, PropSizeMap * propSizes )
+{
+ #if Trace_PackageForJPEG
+ printf ( " Creating top level property map:\n" );
+ #endif
+
+ for ( size_t s = stdXMP.tree.children.size(); s > 0; --s ) {
+
+ XMP_Node * stdSchema = stdXMP.tree.children[s-1];
+
+ for ( size_t p = stdSchema->children.size(); p > 0; --p ) {
+
+ XMP_Node * stdProp = stdSchema->children[p-1];
+ if ( (stdSchema->name == kXMP_NS_XMP_Note) &&
+ (stdProp->name == "xmpNote:HasExtendedXMP") ) continue; // ! Don't move xmpNote:HasExtendedXMP.
+
+ size_t propSize = EstimateSizeForJPEG ( stdProp );
+ StringPtrPair namePair ( &stdSchema->name, &stdProp->name );
+ PropSizeMap::value_type mapValue ( propSize, namePair );
+
+ (void) propSizes->insert ( propSizes->upper_bound ( propSize ), mapValue );
+ #if Trace_PackageForJPEG
+ printf ( " %d bytes, %s in %s\n", propSize, stdProp->name.c_str(), stdSchema->name.c_str() );
+ #endif
+
+ }
+
+ }
+
+} // CreateEstimatedSizeMap
+
+
+// -------------------------------------------------------------------------------------------------
+// MoveLargestProperty
+// -------------------
+
+static size_t MoveLargestProperty ( XMPMeta & stdXMP, XMPMeta * extXMP, PropSizeMap & propSizes )
+{
+ XMP_Assert ( ! propSizes.empty() );
+
+ #if 0
+ // *** Xocde 2.3 on Mac OS X 10.4.7 seems to have a bug where this does not pick the last
+ // *** item in the map. We'll just avoid it on all platforms until thoroughly tested.
+ PropSizeMap::iterator lastPos = propSizes.end();
+ --lastPos; // Move to the actual last item.
+ #else
+ PropSizeMap::iterator lastPos = propSizes.begin();
+ PropSizeMap::iterator nextPos = lastPos;
+ for ( ++nextPos; nextPos != propSizes.end(); ++nextPos ) lastPos = nextPos;
+ #endif
+
+ size_t propSize = lastPos->first;
+ const char * schemaURI = lastPos->second.first->c_str();
+ const char * propName = lastPos->second.second->c_str();
+
+ #if Trace_PackageForJPEG
+ printf ( " Move %s, %d bytes\n", propName, propSize );
+ #endif
+
+ bool moved = MoveOneProperty ( stdXMP, extXMP, schemaURI, propName );
+ XMP_Assert ( moved );
+
+ propSizes.erase ( lastPos );
+ return propSize;
+
+} // MoveLargestProperty
+
+
+// =================================================================================================
+// Class Static Functions
+// ======================
+
+
+// -------------------------------------------------------------------------------------------------
+// Initialize
+// ----------
+
+/* class static */ bool
+XMPUtils::Initialize()
+{
+ sComposedPath = new XMP_VarString();
+ sConvertedValue = new XMP_VarString();
+ sBase64Str = new XMP_VarString();
+ sCatenatedItems = new XMP_VarString();
+ sStandardXMP = new XMP_VarString();
+ sExtendedXMP = new XMP_VarString();
+ sExtendedDigest = new XMP_VarString();
+
+ #if XMP_MacBuild && __MWERKS__
+ LookupTimeProcs();
+ #endif
+
+ return true;
+
+} // Initialize
+
+
+// -------------------------------------------------------------------------------------------------
+// Terminate
+// ---------
+
+#define EliminateGlobal(g) delete ( g ); g = 0
+
+/* class static */ void
+XMPUtils::Terminate() RELEASE_NO_THROW
+{
+ EliminateGlobal ( sComposedPath );
+ EliminateGlobal ( sConvertedValue );
+ EliminateGlobal ( sBase64Str );
+ EliminateGlobal ( sCatenatedItems );
+ EliminateGlobal ( sStandardXMP );
+ EliminateGlobal ( sExtendedXMP );
+ EliminateGlobal ( sExtendedDigest );
+
+ return;
+
+} // Terminate
+
+
+// -------------------------------------------------------------------------------------------------
+// Unlock
+// ------
+
+/* class static */ void
+XMPUtils::Unlock ( XMP_OptionBits options )
+{
+ options = options; // Avoid unused parameter warning.
+
+ XMPMeta::Unlock ( 0 );
+
+} // Unlock
+
+// -------------------------------------------------------------------------------------------------
+// ComposeArrayItemPath
+// --------------------
+//
+// Return "arrayName[index]".
+
+/* class static */ void
+XMPUtils::ComposeArrayItemPath ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex,
+ XMP_StringPtr * fullPath,
+ XMP_StringLen * pathSize )
+{
+ XMP_Assert ( schemaNS != 0 ); // Enforced by wrapper.
+ XMP_Assert ( *arrayName != 0 ); // Enforced by wrapper.
+ XMP_Assert ( (fullPath != 0) && (pathSize != 0) ); // Enforced by wrapper.
+
+ XMP_ExpandedXPath expPath; // Just for side effects to check namespace and basic path.
+ ExpandXPath ( schemaNS, arrayName, &expPath );
+
+ if ( (itemIndex < 0) && (itemIndex != kXMP_ArrayLastItem) ) XMP_Throw ( "Array index out of bounds", kXMPErr_BadParam );
+
+ XMP_StringLen reserveLen = strlen(arrayName) + 2 + 32; // Room plus padding.
+
+ sComposedPath->erase();
+ sComposedPath->reserve ( reserveLen );
+ sComposedPath->append ( reserveLen, ' ' );
+
+ if ( itemIndex != kXMP_ArrayLastItem ) {
+ // AUDIT: Using string->capacity() for the snprintf length is safe.
+ snprintf ( const_cast<char*>(sComposedPath->c_str()), sComposedPath->capacity(), "%s[%d]", arrayName, itemIndex );
+ } else {
+ *sComposedPath = arrayName;
+ *sComposedPath += "[last()] ";
+ (*sComposedPath)[sComposedPath->size()-1] = 0; // ! Final null is for the strlen at exit.
+ }
+
+ *fullPath = sComposedPath->c_str();
+ *pathSize = strlen ( *fullPath ); // ! Don't use sComposedPath->size()!
+
+ XMP_Enforce ( *pathSize < sComposedPath->size() ); // Rather late, but complain about buffer overflow.
+
+} // ComposeArrayItemPath
+
+
+// -------------------------------------------------------------------------------------------------
+// ComposeStructFieldPath
+// ----------------------
+//
+// Return "structName/ns:fieldName".
+
+/* class static */ void
+XMPUtils::ComposeStructFieldPath ( XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ XMP_StringPtr * fullPath,
+ XMP_StringLen * pathSize )
+{
+ XMP_Assert ( (schemaNS != 0) && (fieldNS != 0) ); // Enforced by wrapper.
+ XMP_Assert ( (*structName != 0) && (*fieldName != 0) ); // Enforced by wrapper.
+ XMP_Assert ( (fullPath != 0) && (pathSize != 0) ); // Enforced by wrapper.
+
+ XMP_ExpandedXPath expPath; // Just for side effects to check namespace and basic path.
+ ExpandXPath ( schemaNS, structName, &expPath );
+
+ XMP_ExpandedXPath fieldPath;
+ ExpandXPath ( fieldNS, fieldName, &fieldPath );
+ if ( fieldPath.size() != 2 ) XMP_Throw ( "The fieldName must be simple", kXMPErr_BadXPath );
+
+ XMP_StringLen reserveLen = strlen(structName) + fieldPath[kRootPropStep].step.size() + 1;
+
+ sComposedPath->erase();
+ sComposedPath->reserve ( reserveLen );
+ *sComposedPath = structName;
+ *sComposedPath += '/';
+ *sComposedPath += fieldPath[kRootPropStep].step;
+
+ *fullPath = sComposedPath->c_str();
+ *pathSize = sComposedPath->size();
+
+} // ComposeStructFieldPath
+
+
+// -------------------------------------------------------------------------------------------------
+// ComposeQualifierPath
+// --------------------
+//
+// Return "propName/?ns:qualName".
+
+/* class static */ void
+XMPUtils::ComposeQualifierPath ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName,
+ XMP_StringPtr * fullPath,
+ XMP_StringLen * pathSize )
+{
+ XMP_Assert ( (schemaNS != 0) && (qualNS != 0) ); // Enforced by wrapper.
+ XMP_Assert ( (*propName != 0) && (*qualName != 0) ); // Enforced by wrapper.
+ XMP_Assert ( (fullPath != 0) && (pathSize != 0) ); // Enforced by wrapper.
+
+ XMP_ExpandedXPath expPath; // Just for side effects to check namespace and basic path.
+ ExpandXPath ( schemaNS, propName, &expPath );
+
+ XMP_ExpandedXPath qualPath;
+ ExpandXPath ( qualNS, qualName, &qualPath );
+ if ( qualPath.size() != 2 ) XMP_Throw ( "The qualifier name must be simple", kXMPErr_BadXPath );
+
+ XMP_StringLen reserveLen = strlen(propName) + qualPath[kRootPropStep].step.size() + 2;
+
+ sComposedPath->erase();
+ sComposedPath->reserve ( reserveLen );
+ *sComposedPath = propName;
+ *sComposedPath += "/?";
+ *sComposedPath += qualPath[kRootPropStep].step;
+
+ *fullPath = sComposedPath->c_str();
+ *pathSize = sComposedPath->size();
+
+} // ComposeQualifierPath
+
+
+// -------------------------------------------------------------------------------------------------
+// ComposeLangSelector
+// -------------------
+//
+// Return "arrayName[?xml:lang="lang"]".
+
+// *** #error "handle quotes in the lang - or verify format"
+
+/* class static */ void
+XMPUtils::ComposeLangSelector ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_StringPtr _langName,
+ XMP_StringPtr * fullPath,
+ XMP_StringLen * pathSize )
+{
+ XMP_Assert ( schemaNS != 0 ); // Enforced by wrapper.
+ XMP_Assert ( (*arrayName != 0) && (*_langName != 0) ); // Enforced by wrapper.
+ XMP_Assert ( (fullPath != 0) && (pathSize != 0) ); // Enforced by wrapper.
+
+ XMP_ExpandedXPath expPath; // Just for side effects to check namespace and basic path.
+ ExpandXPath ( schemaNS, arrayName, &expPath );
+
+ XMP_VarString langName ( _langName );
+ NormalizeLangValue ( &langName );
+
+ XMP_StringLen reserveLen = strlen(arrayName) + langName.size() + 14;
+
+ sComposedPath->erase();
+ sComposedPath->reserve ( reserveLen );
+ *sComposedPath = arrayName;
+ *sComposedPath += "[?xml:lang=\"";
+ *sComposedPath += langName;
+ *sComposedPath += "\"]";
+
+ *fullPath = sComposedPath->c_str();
+ *pathSize = sComposedPath->size();
+
+} // ComposeLangSelector
+
+
+// -------------------------------------------------------------------------------------------------
+// ComposeFieldSelector
+// --------------------
+//
+// Return "arrayName[ns:fieldName="fieldValue"]".
+
+// *** #error "handle quotes in the value"
+
+/* class static */ void
+XMPUtils::ComposeFieldSelector ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ XMP_StringPtr fieldValue,
+ XMP_StringPtr * fullPath,
+ XMP_StringLen * pathSize )
+{
+ XMP_Assert ( (schemaNS != 0) && (fieldNS != 0) && (fieldValue != 0) ); // Enforced by wrapper.
+ XMP_Assert ( (*arrayName != 0) && (*fieldName != 0) ); // Enforced by wrapper.
+ XMP_Assert ( (fullPath != 0) && (pathSize != 0) ); // Enforced by wrapper.
+
+ XMP_ExpandedXPath expPath; // Just for side effects to check namespace and basic path.
+ ExpandXPath ( schemaNS, arrayName, &expPath );
+
+ XMP_ExpandedXPath fieldPath;
+ ExpandXPath ( fieldNS, fieldName, &fieldPath );
+ if ( fieldPath.size() != 2 ) XMP_Throw ( "The fieldName must be simple", kXMPErr_BadXPath );
+
+ XMP_StringLen reserveLen = strlen(arrayName) + fieldPath[kRootPropStep].step.size() + strlen(fieldValue) + 5;
+
+ sComposedPath->erase();
+ sComposedPath->reserve ( reserveLen );
+ *sComposedPath = arrayName;
+ *sComposedPath += '[';
+ *sComposedPath += fieldPath[kRootPropStep].step;
+ *sComposedPath += "=\"";
+ *sComposedPath += fieldValue;
+ *sComposedPath += "\"]";
+
+ *fullPath = sComposedPath->c_str();
+ *pathSize = sComposedPath->size();
+
+} // ComposeFieldSelector
+
+
+// -------------------------------------------------------------------------------------------------
+// ConvertFromBool
+// ---------------
+
+/* class static */ void
+XMPUtils::ConvertFromBool ( bool binValue,
+ XMP_StringPtr * strValue,
+ XMP_StringLen * strSize )
+{
+ XMP_Assert ( (strValue != 0) && (strSize != 0) ); // Enforced by wrapper.
+
+ if ( binValue ) {
+ *strValue = kXMP_TrueStr;
+ *strSize = strlen ( kXMP_TrueStr );
+ } else {
+ *strValue = kXMP_FalseStr;
+ *strSize = strlen ( kXMP_FalseStr );
+ }
+
+} // ConvertFromBool
+
+
+// -------------------------------------------------------------------------------------------------
+// ConvertFromInt
+// --------------
+
+/* class static */ void
+XMPUtils::ConvertFromInt ( XMP_Int32 binValue,
+ XMP_StringPtr format,
+ XMP_StringPtr * strValue,
+ XMP_StringLen * strSize )
+{
+ XMP_Assert ( (format != 0) && (strValue != 0) && (strSize != 0) ); // Enforced by wrapper.
+
+ if ( *format == 0 ) format = "%d";
+
+ sConvertedValue->erase();
+ sConvertedValue->reserve ( 100 ); // More than enough for any reasonable format and value.
+ sConvertedValue->append ( 100, ' ' );
+
+ // AUDIT: Using string->capacity() for the snprintf length is safe.
+ snprintf ( const_cast<char*>(sConvertedValue->c_str()), sConvertedValue->capacity(), format, binValue );
+
+ *strValue = sConvertedValue->c_str();
+ *strSize = strlen ( *strValue ); // ! Don't use sConvertedValue->size()!
+
+ XMP_Enforce ( *strSize < sConvertedValue->size() ); // Rather late, but complain about buffer overflow.
+
+} // ConvertFromInt
+
+
+// -------------------------------------------------------------------------------------------------
+// ConvertFromInt64
+// ----------------
+
+/* class static */ void
+XMPUtils::ConvertFromInt64 ( XMP_Int64 binValue,
+ XMP_StringPtr format,
+ XMP_StringPtr * strValue,
+ XMP_StringLen * strSize )
+{
+ XMP_Assert ( (format != 0) && (strValue != 0) && (strSize != 0) ); // Enforced by wrapper.
+
+ if ( *format == 0 ) format = "%d";
+
+ sConvertedValue->erase();
+ sConvertedValue->reserve ( 100 ); // More than enough for any reasonable format and value.
+ sConvertedValue->append ( 100, ' ' );
+
+ // AUDIT: Using string->capacity() for the snprintf length is safe.
+ snprintf ( const_cast<char*>(sConvertedValue->c_str()), sConvertedValue->capacity(), format, binValue );
+
+ *strValue = sConvertedValue->c_str();
+ *strSize = strlen ( *strValue ); // ! Don't use sConvertedValue->size()!
+
+ XMP_Enforce ( *strSize < sConvertedValue->size() ); // Rather late, but complain about buffer overflow.
+
+} // ConvertFromInt64
+
+
+// -------------------------------------------------------------------------------------------------
+// ConvertFromFloat
+// ----------------
+
+/* class static */ void
+XMPUtils::ConvertFromFloat ( double binValue,
+ XMP_StringPtr format,
+ XMP_StringPtr * strValue,
+ XMP_StringLen * strSize )
+{
+ XMP_Assert ( (format != 0) && (strValue != 0) && (strSize != 0) ); // Enforced by wrapper.
+
+ if ( *format == 0 ) format = "%f";
+
+ sConvertedValue->erase();
+ sConvertedValue->reserve ( 1000 ); // More than enough for any reasonable format and value.
+ sConvertedValue->append ( 1000, ' ' );
+
+ // AUDIT: Using string->capacity() for the snprintf length is safe.
+ snprintf ( const_cast<char*>(sConvertedValue->c_str()), sConvertedValue->capacity(), format, binValue );
+
+ *strValue = sConvertedValue->c_str();
+ *strSize = strlen ( *strValue ); // ! Don't use sConvertedValue->size()!
+
+ XMP_Enforce ( *strSize < sConvertedValue->size() ); // Rather late, but complain about buffer overflow.
+
+} // ConvertFromFloat
+
+
+// -------------------------------------------------------------------------------------------------
+// ConvertFromDate
+// ---------------
+//
+// Format a date according to ISO 8601 and http://www.w3.org/TR/NOTE-datetime:
+// YYYY
+// YYYY-MM
+// YYYY-MM-DD
+// YYYY-MM-DDThh:mmTZD
+// YYYY-MM-DDThh:mm:ssTZD
+// YYYY-MM-DDThh:mm:ss.sTZD
+//
+// YYYY = four-digit year
+// MM = two-digit month (01=January, etc.)
+// DD = two-digit day of month (01 through 31)
+// hh = two digits of hour (00 through 23)
+// mm = two digits of minute (00 through 59)
+// ss = two digits of second (00 through 59)
+// s = one or more digits representing a decimal fraction of a second
+// TZD = time zone designator (Z or +hh:mm or -hh:mm)
+//
+// Note that ISO 8601 does not seem to allow years less than 1000 or greater than 9999. We allow
+// any year, even negative ones. The year is formatted as "%.4d".
+
+// *** Need to check backward compatibility for partial forms!
+
+/* class static */ void
+XMPUtils::ConvertFromDate ( const XMP_DateTime & binValue,
+ XMP_StringPtr * strValue,
+ XMP_StringLen * strSize )
+{
+ XMP_Assert ( (strValue != 0) && (strSize != 0) ); // Enforced by wrapper.
+
+ bool addTimeZone = false;
+ char buffer [100]; // Plenty long enough.
+
+ // Pick the format, use snprintf to format into a local buffer, assign to static output string.
+ // Don't use AdjustTimeOverflow at the start, that will wipe out zero month or day values.
+
+ // ! Photoshop 8 creates "time only" values with zeros for year, month, and day.
+
+ XMP_DateTime tempDate = binValue;
+
+ // Temporary fix for bug 1269463, silently fix out of range month or day.
+
+ bool haveDay = (tempDate.day != 0);
+ bool haveTime = ( (tempDate.hour != 0) || (tempDate.minute != 0) ||
+ (tempDate.second != 0) || (tempDate.nanoSecond != 0) ||
+ (tempDate.tzSign != 0) || (tempDate.tzHour != 0) || (tempDate.tzMinute != 0) );
+
+ if ( tempDate.month == 0 ) {
+ if ( haveDay || haveTime ) tempDate.month = 1;
+ } else {
+ if ( tempDate.month < 1 ) tempDate.month = 1;
+ if ( tempDate.month > 12 ) tempDate.month = 12;
+ }
+
+ if ( tempDate.day == 0 ) {
+ if ( haveTime ) tempDate.day = 1;
+ } else {
+ if ( tempDate.day < 1 ) tempDate.day = 1;
+ if ( tempDate.day > 31 ) tempDate.day = 31;
+ }
+
+ // Now carry on with the original logic.
+
+ if ( tempDate.month == 0 ) {
+
+ // Output YYYY if all else is zero, otherwise output a full string for the quasi-bogus
+ // "time only" values from Photoshop CS.
+ if ( (tempDate.day == 0) && (tempDate.hour == 0) && (tempDate.minute == 0) &&
+ (tempDate.second == 0) && (tempDate.nanoSecond == 0) &&
+ (tempDate.tzSign == 0) && (tempDate.tzHour == 0) && (tempDate.tzMinute == 0) ) {
+ snprintf ( buffer, sizeof(buffer), "%.4d", tempDate.year ); // AUDIT: Using sizeof for snprintf length is safe.
+ } else if ( (tempDate.year == 0) && (tempDate.day == 0) ) {
+ FormatFullDateTime ( tempDate, buffer, sizeof(buffer) );
+ addTimeZone = true;
+ } else {
+ XMP_Throw ( "Invalid partial date", kXMPErr_BadParam);
+ }
+
+ } else if ( tempDate.day == 0 ) {
+
+ // Output YYYY-MM.
+ if ( (tempDate.month < 1) || (tempDate.month > 12) ) XMP_Throw ( "Month is out of range", kXMPErr_BadParam);
+ if ( (tempDate.hour != 0) || (tempDate.minute != 0) ||
+ (tempDate.second != 0) || (tempDate.nanoSecond != 0) ||
+ (tempDate.tzSign != 0) || (tempDate.tzHour != 0) || (tempDate.tzMinute != 0) ) {
+ XMP_Throw ( "Invalid partial date, non-zeros after zero month and day", kXMPErr_BadParam);
+ }
+ snprintf ( buffer, sizeof(buffer), "%.4d-%02d", tempDate.year, tempDate.month ); // AUDIT: Using sizeof for snprintf length is safe.
+
+ } else if ( (tempDate.hour == 0) && (tempDate.minute == 0) &&
+ (tempDate.second == 0) && (tempDate.nanoSecond == 0) &&
+ (tempDate.tzSign == 0) && (tempDate.tzHour == 0) && (tempDate.tzMinute == 0) ) {
+
+ // Output YYYY-MM-DD.
+ if ( (tempDate.month < 1) || (tempDate.month > 12) ) XMP_Throw ( "Month is out of range", kXMPErr_BadParam);
+ if ( (tempDate.day < 1) || (tempDate.day > 31) ) XMP_Throw ( "Day is out of range", kXMPErr_BadParam);
+ snprintf ( buffer, sizeof(buffer), "%.4d-%02d-%02d", tempDate.year, tempDate.month, tempDate.day ); // AUDIT: Using sizeof for snprintf length is safe.
+
+ } else {
+
+ FormatFullDateTime ( tempDate, buffer, sizeof(buffer) );
+ addTimeZone = true;
+
+ }
+
+ sConvertedValue->assign ( buffer );
+
+ if ( addTimeZone ) {
+
+ if ( (tempDate.tzHour < 0) || (tempDate.tzHour > 23) ||
+ (tempDate.tzMinute < 0 ) || (tempDate.tzMinute > 59) ||
+ (tempDate.tzSign < -1) || (tempDate.tzSign > +1) ||
+ ((tempDate.tzSign != 0) && (tempDate.tzHour == 0) && (tempDate.tzMinute == 0)) ||
+ ((tempDate.tzSign == 0) && ((tempDate.tzHour != 0) || (tempDate.tzMinute != 0))) ) {
+ XMP_Throw ( "Invalid time zone values", kXMPErr_BadParam );
+ }
+
+ if ( tempDate.tzSign == 0 ) {
+ *sConvertedValue += 'Z';
+ } else {
+ snprintf ( buffer, sizeof(buffer), "+%02d:%02d", tempDate.tzHour, tempDate.tzMinute ); // AUDIT: Using sizeof for snprintf length is safe.
+ if ( tempDate.tzSign < 0 ) buffer[0] = '-';
+ *sConvertedValue += buffer;
+ }
+
+ }
+
+ *strValue = sConvertedValue->c_str();
+ *strSize = sConvertedValue->size();
+
+} // ConvertFromDate
+
+
+// -------------------------------------------------------------------------------------------------
+// ConvertToBool
+// -------------
+//
+// Formally the string value should be "True" or "False", but we should be more flexible here. Map
+// the string to lower case. Allow any of "true", "false", "t", "f", "1", or "0".
+
+/* class static */ bool
+XMPUtils::ConvertToBool ( XMP_StringPtr strValue )
+{
+ if ( (strValue == 0) || (*strValue == 0) ) XMP_Throw ( "Empty convert-from string", kXMPErr_BadValue );
+
+ bool result = false;
+ XMP_VarString strObj ( strValue );
+
+ for ( XMP_VarStringPos ch = strObj.begin(); ch != strObj.end(); ++ch ) {
+ if ( ('A' <= *ch) && (*ch <= 'Z') ) *ch += 0x20;
+ }
+
+ if ( (strObj == "true") || (strObj == "t") || (strObj == "1") ) {
+ result = true;
+ } else if ( (strObj == "false") || (strObj == "f") || (strObj == "0") ) {
+ result = false;
+ } else {
+ XMP_Throw ( "Invalid Boolean string", kXMPErr_BadParam );
+ }
+
+ return result;
+
+} // ConvertToBool
+
+
+// -------------------------------------------------------------------------------------------------
+// ConvertToInt
+// ------------
+
+/* class static */ XMP_Int32
+XMPUtils::ConvertToInt ( XMP_StringPtr strValue )
+{
+ if ( (strValue == 0) || (*strValue == 0) ) XMP_Throw ( "Empty convert-from string", kXMPErr_BadValue );
+
+ errno = 0;
+ char * numEnd;
+ XMP_Int32 result;
+
+ if ( strncmp ( strValue, "0x", 2 ) != 0 ) {
+ result = strtol ( strValue, &numEnd, 0 );
+ } else {
+ result = (XMP_Int32) strtoul ( strValue, &numEnd, 0 ); // Treat hex form as raw bits.
+ }
+
+ if ( (errno != 0) || (*numEnd != 0) ) XMP_Throw ( "Invalid integer string", kXMPErr_BadParam );
+
+ return result;
+
+} // ConvertToInt
+
+
+// -------------------------------------------------------------------------------------------------
+// ConvertToInt64
+// --------------
+
+/* class static */ XMP_Int64
+XMPUtils::ConvertToInt64 ( XMP_StringPtr strValue )
+{
+ if ( (strValue == 0) || (*strValue == 0) ) XMP_Throw ( "Empty convert-from string", kXMPErr_BadValue );
+
+ errno = 0;
+ char * numEnd;
+ XMP_Int64 result;
+
+ if ( strncmp ( strValue, "0x", 2 ) != 0 ) {
+ result = strtol ( strValue, &numEnd, 0 );
+ } else {
+ result = (XMP_Int64) strtoul ( strValue, &numEnd, 0 ); // Treat hex form as raw bits.
+ }
+
+ if ( (errno != 0) || (*numEnd != 0) ) XMP_Throw ( "Invalid integer string", kXMPErr_BadParam );
+
+ return result;
+
+} // ConvertToInt64
+
+
+// -------------------------------------------------------------------------------------------------
+// ConvertToFloat
+// --------------
+
+/* class static */ double
+XMPUtils::ConvertToFloat ( XMP_StringPtr strValue )
+{
+ if ( (strValue == 0) || (*strValue == 0) ) XMP_Throw ( "Empty convert-from string", kXMPErr_BadValue );
+
+ XMP_VarString oldLocale; // Try to make sure number conversion uses '.' as the decimal point.
+ XMP_StringPtr oldLocalePtr = setlocale ( LC_ALL, 0 );
+ if ( oldLocalePtr != 0 ) {
+ oldLocale.assign ( oldLocalePtr );
+ setlocale ( LC_ALL, "C" );
+ }
+
+ errno = 0;
+ char * numEnd;
+ double result = strtod ( strValue, &numEnd );
+
+ if ( oldLocalePtr != 0 ) setlocale ( LC_ALL, oldLocalePtr ); // ! Reset locale before possible throw!
+ if ( (errno != 0) || (*numEnd != 0) ) XMP_Throw ( "Invalid float string", kXMPErr_BadParam );
+
+ return result;
+
+} // ConvertToFloat
+
+
+// -------------------------------------------------------------------------------------------------
+// ConvertToDate
+// -------------
+//
+// Parse a date according to ISO 8601 and http://www.w3.org/TR/NOTE-datetime:
+// YYYY
+// YYYY-MM
+// YYYY-MM-DD
+// YYYY-MM-DDThh:mmTZD
+// YYYY-MM-DDThh:mm:ssTZD
+// YYYY-MM-DDThh:mm:ss.sTZD
+//
+// YYYY = four-digit year
+// MM = two-digit month (01=January, etc.)
+// DD = two-digit day of month (01 through 31)
+// hh = two digits of hour (00 through 23)
+// mm = two digits of minute (00 through 59)
+// ss = two digits of second (00 through 59)
+// s = one or more digits representing a decimal fraction of a second
+// TZD = time zone designator (Z or +hh:mm or -hh:mm)
+//
+// Note that ISO 8601 does not seem to allow years less than 1000 or greater than 9999. We allow
+// any year, even negative ones. The year is formatted as "%.4d".
+
+// ! Tolerate missing TZD, assume is UTC. Photoshop 8 writes dates like this for exif:GPSTimeStamp.
+// ! Tolerate missing date portion, in case someone foolishly writes a time-only value that way.
+
+// *** Put the ISO format comments in the header documentation.
+
+/* class static */ void
+XMPUtils::ConvertToDate ( XMP_StringPtr strValue,
+ XMP_DateTime * binValue )
+{
+ if ( (strValue == 0) || (*strValue == 0) ) XMP_Throw ( "Empty convert-from string", kXMPErr_BadValue);
+
+ size_t pos = 0;
+ XMP_Int32 temp;
+
+ (void) memset ( binValue, 0, sizeof ( XMP_DateTime ) );
+
+ bool timeOnly = ( (strValue[0] == 'T') ||
+ ((strlen(strValue) >= 2) && (strValue[1] == ':')) ||
+ ((strlen(strValue) >= 3) && (strValue[2] == ':')) );
+
+ if ( ! timeOnly ) {
+
+ if ( strValue[0] == '-' ) pos = 1;
+
+ temp = GatherInt ( strValue, &pos, "Invalid year in date string" ); // Extract the year.
+ if ( (strValue[pos] != 0) && (strValue[pos] != '-') ) XMP_Throw ( "Invalid date string, after year", kXMPErr_BadParam );
+ if ( strValue[0] == '-' ) temp = -temp;
+ binValue->year = temp;
+ if ( strValue[pos] == 0 ) return;
+
+ ++pos;
+ temp = GatherInt ( strValue, &pos, "Invalid month in date string" ); // Extract the month.
+ if ( (strValue[pos] != 0) && (strValue[pos] != '-') ) XMP_Throw ( "Invalid date string, after month", kXMPErr_BadParam );
+ binValue->month = temp;
+ if ( strValue[pos] == 0 ) return;
+
+ ++pos;
+ temp = GatherInt ( strValue, &pos, "Invalid day in date string" ); // Extract the day.
+ if ( (strValue[pos] != 0) && (strValue[pos] != 'T') ) XMP_Throw ( "Invalid date string, after day", kXMPErr_BadParam );
+ binValue->day = temp;
+ if ( strValue[pos] == 0 ) return;
+
+ // Allow year, month, and day to all be zero; implies the date portion is missing.
+ if ( (binValue->year != 0) || (binValue->month != 0) || (binValue->day != 0) ) {
+ // Temporary fix for bug 1269463, silently fix out of range month or day.
+ // if ( (binValue->month < 1) || (binValue->month > 12) ) XMP_Throw ( "Month is out of range", kXMPErr_BadParam );
+ // if ( (binValue->day < 1) || (binValue->day > 31) ) XMP_Throw ( "Day is out of range", kXMPErr_BadParam );
+ if ( binValue->month < 1 ) binValue->month = 1;
+ if ( binValue->month > 12 ) binValue->month = 12;
+ if ( binValue->day < 1 ) binValue->day = 1;
+ if ( binValue->day > 31 ) binValue->day = 31;
+ }
+
+ }
+
+ if ( strValue[pos] == 'T' ) {
+ ++pos;
+ } else if ( ! timeOnly ) {
+ XMP_Throw ( "Invalid date string, missing 'T' after date", kXMPErr_BadParam );
+ }
+
+ temp = GatherInt ( strValue, &pos, "Invalid hour in date string" ); // Extract the hour.
+ if ( strValue[pos] != ':' ) XMP_Throw ( "Invalid date string, after hour", kXMPErr_BadParam );
+ if ( temp > 23 ) temp = 23; // *** 1269463: XMP_Throw ( "Hour is out of range", kXMPErr_BadParam );
+ binValue->hour = temp;
+ // Don't check for done, we have to work up to the time zone.
+
+ ++pos;
+ temp = GatherInt ( strValue, &pos, "Invalid minute in date string" ); // And the minute.
+ if ( (strValue[pos] != ':') && (strValue[pos] != 'Z') &&
+ (strValue[pos] != '+') && (strValue[pos] != '-') && (strValue[pos] != 0) ) XMP_Throw ( "Invalid date string, after minute", kXMPErr_BadParam );
+ if ( temp > 59 ) temp = 59; // *** 1269463: XMP_Throw ( "Minute is out of range", kXMPErr_BadParam );
+ binValue->minute = temp;
+ // Don't check for done, we have to work up to the time zone.
+
+ if ( strValue[pos] == ':' ) {
+
+ ++pos;
+ temp = GatherInt ( strValue, &pos, "Invalid whole seconds in date string" ); // Extract the whole seconds.
+ if ( (strValue[pos] != '.') && (strValue[pos] != 'Z') &&
+ (strValue[pos] != '+') && (strValue[pos] != '-') && (strValue[pos] != 0) ) {
+ XMP_Throw ( "Invalid date string, after whole seconds", kXMPErr_BadParam );
+ }
+ if ( temp > 59 ) temp = 59; // *** 1269463: XMP_Throw ( "Whole second is out of range", kXMPErr_BadParam );
+ binValue->second = temp;
+ // Don't check for done, we have to work up to the time zone.
+
+ if ( strValue[pos] == '.' ) {
+
+ ++pos;
+ size_t digits = pos; // Will be the number of digits later.
+
+ temp = GatherInt ( strValue, &pos, "Invalid fractional seconds in date string" ); // Extract the fractional seconds.
+ if ( (strValue[pos] != 'Z') && (strValue[pos] != '+') && (strValue[pos] != '-') && (strValue[pos] != 0) ) {
+ XMP_Throw ( "Invalid date string, after fractional second", kXMPErr_BadParam );
+ }
+
+ digits = pos - digits;
+ for ( ; digits > 9; --digits ) temp = temp / 10;
+ for ( ; digits < 9; ++digits ) temp = temp * 10;
+
+ if ( temp >= 1000*1000*1000 ) XMP_Throw ( "Fractional second is out of range", kXMPErr_BadParam );
+ binValue->nanoSecond = temp;
+ // Don't check for done, we have to work up to the time zone.
+
+ }
+
+ }
+
+ if ( strValue[pos] == 'Z' ) {
+
+ ++pos;
+
+ } else if ( strValue[pos] != 0 ) {
+
+ if ( strValue[pos] == '+' ) {
+ binValue->tzSign = kXMP_TimeEastOfUTC;
+ } else if ( strValue[pos] == '-' ) {
+ binValue->tzSign = kXMP_TimeWestOfUTC;
+ } else {
+ XMP_Throw ( "Time zone must begin with 'Z', '+', or '-'", kXMPErr_BadParam );
+ }
+
+ ++pos;
+ temp = GatherInt ( strValue, &pos, "Invalid time zone hour in date string" ); // Extract the time zone hour.
+ if ( strValue[pos] != ':' ) XMP_Throw ( "Invalid date string, after time zone hour", kXMPErr_BadParam );
+ if ( temp > 23 ) XMP_Throw ( "Time zone hour is out of range", kXMPErr_BadParam );
+ binValue->tzHour = temp;
+
+ ++pos;
+ temp = GatherInt ( strValue, &pos, "Invalid time zone minute in date string" ); // Extract the time zone minute.
+ if ( temp > 59 ) XMP_Throw ( "Time zone minute is out of range", kXMPErr_BadParam );
+ binValue->tzMinute = temp;
+
+ }
+
+ if ( strValue[pos] != 0 ) XMP_Throw ( "Invalid date string, extra chars at end", kXMPErr_BadParam );
+
+} // ConvertToDate
+
+
+// -------------------------------------------------------------------------------------------------
+// EncodeToBase64
+// --------------
+//
+// Encode a string of raw data bytes in base 64 according to RFC 2045. For the encoding definition
+// see section 6.8 in <http://www.ietf.org/rfc/rfc2045.txt>. Although it isn't needed for RDF, we
+// do insert a linefeed character as a newline for every 76 characters of encoded output.
+
+/* class static */ void
+XMPUtils::EncodeToBase64 ( XMP_StringPtr rawStr,
+ XMP_StringLen rawLen,
+ XMP_StringPtr * encodedStr,
+ XMP_StringLen * encodedLen )
+{
+ if ( (rawStr == 0) && (rawLen != 0) ) XMP_Throw ( "Null raw data buffer", kXMPErr_BadParam );
+ if ( rawLen == 0 ) {
+ *encodedStr = 0;
+ *encodedLen = 0;
+ return;
+ }
+
+ char encChunk[4];
+
+ unsigned long in, out;
+ unsigned char c1, c2, c3;
+ unsigned long merge;
+
+ const size_t outputSize = (rawLen / 3) * 4; // Approximate, might be small.
+
+ sBase64Str->erase();
+ sBase64Str->reserve ( outputSize );
+
+ // ----------------------------------------------------------------------------------------
+ // Each 6 bits of input produces 8 bits of output, so 3 input bytes become 4 output bytes.
+ // Process the whole chunks of 3 bytes first, then deal with any remainder. Be careful with
+ // the loop comparison, size-2 could be negative!
+
+ for ( in = 0, out = 0; (in+2) < rawLen; in += 3, out += 4 ) {
+
+ c1 = rawStr[in];
+ c2 = rawStr[in+1];
+ c3 = rawStr[in+2];
+
+ merge = (c1 << 16) + (c2 << 8) + c3;
+
+ encChunk[0] = sBase64Chars [ merge >> 18 ];
+ encChunk[1] = sBase64Chars [ (merge >> 12) & 0x3F ];
+ encChunk[2] = sBase64Chars [ (merge >> 6) & 0x3F ];
+ encChunk[3] = sBase64Chars [ merge & 0x3F ];
+
+ if ( out >= 76 ) {
+ sBase64Str->append ( 1, kLF );
+ out = 0;
+ }
+ sBase64Str->append ( encChunk, 4 );
+
+ }
+
+ // ------------------------------------------------------------------------------------------
+ // The output must always be a multiple of 4 bytes. If there is a 1 or 2 byte input remainder
+ // we need to create another chunk. Zero pad with bits to a 6 bit multiple, then add one or
+ // two '=' characters to pad out to 4 bytes.
+
+ switch ( rawLen - in ) {
+
+ case 0: // Done, no remainder.
+ break;
+
+ case 1: // One input byte remains.
+
+ c1 = rawStr[in];
+ merge = c1 << 16;
+
+ encChunk[0] = sBase64Chars [ merge >> 18 ];
+ encChunk[1] = sBase64Chars [ (merge >> 12) & 0x3F ];
+ encChunk[2] = encChunk[3] = '=';
+
+ if ( out >= 76 ) sBase64Str->append ( 1, kLF );
+ sBase64Str->append ( encChunk, 4 );
+ break;
+
+ case 2: // Two input bytes remain.
+
+ c1 = rawStr[in];
+ c2 = rawStr[in+1];
+ merge = (c1 << 16) + (c2 << 8);
+
+ encChunk[0] = sBase64Chars [ merge >> 18 ];
+ encChunk[1] = sBase64Chars [ (merge >> 12) & 0x3F ];
+ encChunk[2] = sBase64Chars [ (merge >> 6) & 0x3F ];
+ encChunk[3] = '=';
+
+ if ( out >= 76 ) sBase64Str->append ( 1, kLF );
+ sBase64Str->append ( encChunk, 4 );
+ break;
+
+ }
+
+ // -------------------------
+ // Assign the output values.
+
+ *encodedStr = sBase64Str->c_str();
+ *encodedLen = sBase64Str->size();
+
+} // EncodeToBase64
+
+
+// -------------------------------------------------------------------------------------------------
+// DecodeFromBase64
+// ----------------
+//
+// Decode a string of raw data bytes from base 64 according to RFC 2045. For the encoding definition
+// see section 6.8 in <http://www.ietf.org/rfc/rfc2045.txt>. RFC 2045 talks about ignoring all "bad"
+// input but warning about non-whitespace. For XMP use we ignore space, tab, LF, and CR. Any other
+// bad input is rejected.
+
+/* class static */ void
+XMPUtils::DecodeFromBase64 ( XMP_StringPtr encodedStr,
+ XMP_StringLen encodedLen,
+ XMP_StringPtr * rawStr,
+ XMP_StringLen * rawLen )
+{
+ if ( (encodedStr == 0) && (encodedLen != 0) ) XMP_Throw ( "Null encoded data buffer", kXMPErr_BadParam );
+ if ( encodedLen == 0 ) {
+ *rawStr = 0;
+ *rawLen = 0;
+ return;
+ }
+
+ unsigned char ch, rawChunk[3];
+ unsigned long inStr, inChunk, inLimit, merge, padding;
+
+ XMP_StringLen outputSize = (encodedLen / 4) * 3; // Only a close approximation.
+
+ sBase64Str->erase();
+ sBase64Str->reserve ( outputSize );
+
+
+ // ----------------------------------------------------------------------------------------
+ // Each 8 bits of input produces 6 bits of output, so 4 input bytes become 3 output bytes.
+ // Process all but the last 4 data bytes first, then deal with the final chunk. Whitespace
+ // in the input must be ignored. The first loop finds where the last 4 data bytes start and
+ // counts the number of padding equal signs.
+
+ padding = 0;
+ for ( inStr = 0, inLimit = encodedLen; (inStr < 4) && (inLimit > 0); ) {
+ inLimit -= 1; // ! Don't do in the loop control, the decr/test order is wrong.
+ ch = encodedStr[inLimit];
+ if ( ch == '=' ) {
+ padding += 1; // The equal sign padding is a data byte.
+ } else if ( DecodeBase64Char(ch) == 0xFF ) {
+ continue; // Ignore whitespace, don't increment inStr.
+ } else {
+ inStr += 1;
+ }
+ }
+
+ // ! Be careful to count whitespace that is immediately before the final data. Otherwise
+ // ! middle portion will absorb the final data and mess up the final chunk processing.
+
+ while ( (inLimit > 0) && (DecodeBase64Char(encodedStr[inLimit-1]) == 0xFF) ) --inLimit;
+
+ if ( inStr == 0 ) return; // Nothing but whitespace.
+ if ( padding > 2 ) XMP_Throw ( "Invalid encoded string", kXMPErr_BadParam );
+
+ // -------------------------------------------------------------------------------------------
+ // Now process all but the last chunk. The limit ensures that we have at least 4 data bytes
+ // left when entering the output loop, so the inner loop will succeed without overrunning the
+ // end of the data. At the end of the outer loop we might be past inLimit though.
+
+ inStr = 0;
+ while ( inStr < inLimit ) {
+
+ merge = 0;
+ for ( inChunk = 0; inChunk < 4; ++inStr ) { // ! Yes, increment inStr on each pass.
+ ch = DecodeBase64Char ( encodedStr [inStr] );
+ if ( ch == 0xFF ) continue; // Ignore whitespace.
+ merge = (merge << 6) + ch;
+ inChunk += 1;
+ }
+
+ rawChunk[0] = (unsigned char) (merge >> 16);
+ rawChunk[1] = (unsigned char) ((merge >> 8) & 0xFF);
+ rawChunk[2] = (unsigned char) (merge & 0xFF);
+
+ sBase64Str->append ( (char*)rawChunk, 3 );
+
+ }
+
+ // -------------------------------------------------------------------------------------------
+ // Process the final, possibly partial, chunk of data. The input is always a multiple 4 bytes,
+ // but the raw data can be any length. The number of padding '=' characters determines if the
+ // final chunk has 1, 2, or 3 raw data bytes.
+
+ XMP_Assert ( inStr < encodedLen );
+
+ merge = 0;
+ for ( inChunk = 0; inChunk < 4-padding; ++inStr ) { // ! Yes, increment inStr on each pass.
+ ch = DecodeBase64Char ( encodedStr[inStr] );
+ if ( ch == 0xFF ) continue; // Ignore whitespace.
+ merge = (merge << 6) + ch;
+ inChunk += 1;
+ }
+
+ if ( padding == 2 ) {
+
+ rawChunk[0] = (unsigned char) (merge >> 4);
+ sBase64Str->append ( (char*)rawChunk, 1 );
+
+ } else if ( padding == 1 ) {
+
+ rawChunk[0] = (unsigned char) (merge >> 10);
+ rawChunk[1] = (unsigned char) ((merge >> 2) & 0xFF);
+ sBase64Str->append ( (char*)rawChunk, 2 );
+
+ } else {
+
+ rawChunk[0] = (unsigned char) (merge >> 16);
+ rawChunk[1] = (unsigned char) ((merge >> 8) & 0xFF);
+ rawChunk[2] = (unsigned char) (merge & 0xFF);
+ sBase64Str->append ( (char*)rawChunk, 3 );
+
+ }
+
+ // -------------------------
+ // Assign the output values.
+
+ *rawStr = sBase64Str->c_str();
+ *rawLen = sBase64Str->size();
+
+} // DecodeFromBase64
+
+
+// -------------------------------------------------------------------------------------------------
+// PackageForJPEG
+// --------------
+
+/* class static */ void
+XMPUtils::PackageForJPEG ( const XMPMeta & origXMP,
+ XMP_StringPtr * stdStr,
+ XMP_StringLen * stdLen,
+ XMP_StringPtr * extStr,
+ XMP_StringLen * extLen,
+ XMP_StringPtr * digestStr,
+ XMP_StringLen * digestLen )
+{
+ enum { kStdXMPLimit = 65000 };
+ static const char * kPacketTrailer = "<?xpacket end=\"w\"?>";
+ static size_t kTrailerLen = strlen ( kPacketTrailer );
+
+ XMP_StringPtr tempStr;
+ XMP_StringLen tempLen;
+
+ XMPMeta stdXMP, extXMP;
+
+ sStandardXMP->clear(); // Clear the static strings that get returned to the client.
+ sExtendedXMP->clear();
+ sExtendedDigest->clear();
+
+ XMP_OptionBits keepItSmall = kXMP_UseCompactFormat | kXMP_OmitAllFormatting;
+
+ // Try to serialize everything. Note that we're making internal calls to SerializeToBuffer, so
+ // we'll be getting back the pointer and length for its internal string.
+
+ origXMP.SerializeToBuffer ( &tempStr, &tempLen, keepItSmall, 1, "", "", 0 );
+ #if Trace_PackageForJPEG
+ printf ( "\nXMPUtils::PackageForJPEG - Full serialize %d bytes\n", tempLen );
+ #endif
+
+ if ( tempLen > kStdXMPLimit ) {
+
+ // Couldn't fit everything, make a copy of the input XMP and make sure there is no xmp:Thumbnails property.
+
+ stdXMP.tree.options = origXMP.tree.options;
+ stdXMP.tree.name = origXMP.tree.name;
+ stdXMP.tree.value = origXMP.tree.value;
+ CloneOffspring ( &origXMP.tree, &stdXMP.tree );
+
+ if ( stdXMP.DoesPropertyExist ( kXMP_NS_XMP, "Thumbnails" ) ) {
+ stdXMP.DeleteProperty ( kXMP_NS_XMP, "Thumbnails" );
+ stdXMP.SerializeToBuffer ( &tempStr, &tempLen, keepItSmall, 1, "", "", 0 );
+ #if Trace_PackageForJPEG
+ printf ( " Delete xmp:Thumbnails, %d bytes left\n", tempLen );
+ #endif
+ }
+
+ }
+
+ if ( tempLen > kStdXMPLimit ) {
+
+ // Still doesn't fit, move all of the Camera Raw namespace. Add a dummy value for xmpNote:HasExtendedXMP.
+
+ stdXMP.SetProperty ( kXMP_NS_XMP_Note, "HasExtendedXMP", "123456789-123456789-123456789-12", 0 );
+
+ XMP_NodePtrPos crSchemaPos;
+ XMP_Node * crSchema = FindSchemaNode ( &stdXMP.tree, kXMP_NS_CameraRaw, kXMP_ExistingOnly, &crSchemaPos );
+
+ if ( crSchema != 0 ) {
+ crSchema->parent = &extXMP.tree;
+ extXMP.tree.children.push_back ( crSchema );
+ stdXMP.tree.children.erase ( crSchemaPos );
+ stdXMP.SerializeToBuffer ( &tempStr, &tempLen, keepItSmall, 1, "", "", 0 );
+ #if Trace_PackageForJPEG
+ printf ( " Move Camera Raw schema, %d bytes left\n", tempLen );
+ #endif
+ }
+
+ }
+
+ if ( tempLen > kStdXMPLimit ) {
+
+ // Still doesn't fit, move photoshop:History.
+
+ bool moved = MoveOneProperty ( stdXMP, &extXMP, kXMP_NS_Photoshop, "photoshop:History" );
+
+ if ( moved ) {
+ stdXMP.SerializeToBuffer ( &tempStr, &tempLen, keepItSmall, 1, "", "", 0 );
+ #if Trace_PackageForJPEG
+ printf ( " Move photoshop:History, %d bytes left\n", tempLen );
+ #endif
+ }
+
+ }
+
+ if ( tempLen > kStdXMPLimit ) {
+
+ // Still doesn't fit, move top level properties in order of estimated size. This is done by
+ // creating a multi-map that maps the serialized size to the string pair for the schema URI
+ // and top level property name. Since maps are inherently ordered, a reverse iteration of
+ // the map can be done to move the largest things first. We use a double loop to keep going
+ // until the serialization actually fits, in case the estimates are off.
+
+ PropSizeMap propSizes;
+ CreateEstimatedSizeMap ( stdXMP, &propSizes );
+
+ #if Trace_PackageForJPEG
+ if ( ! propSizes.empty() ) {
+ printf ( " Top level property map, smallest to largest:\n" );
+ PropSizeMap::iterator mapPos = propSizes.begin();
+ PropSizeMap::iterator mapEnd = propSizes.end();
+ for ( ; mapPos != mapEnd; ++mapPos ) {
+ size_t propSize = mapPos->first;
+ const char * schemaName = mapPos->second.first->c_str();
+ const char * propName = mapPos->second.second->c_str();
+ printf ( " %d bytes, %s in %s\n", propSize, propName, schemaName );
+ }
+ }
+ #endif
+
+ #if 0 // Trace_PackageForJPEG *** Xcode 2.3 on 10.4.7 has bugs in backwards iteration
+ if ( ! propSizes.empty() ) {
+ printf ( " Top level property map, largest to smallest:\n" );
+ PropSizeMap::iterator mapPos = propSizes.end();
+ PropSizeMap::iterator mapBegin = propSizes.begin();
+ for ( --mapPos; true; --mapPos ) {
+ size_t propSize = mapPos->first;
+ const char * schemaName = mapPos->second.first->c_str();
+ const char * propName = mapPos->second.second->c_str();
+ printf ( " %d bytes, %s in %s\n", propSize, propName, schemaName );
+ if ( mapPos == mapBegin ) break;
+ }
+ }
+ #endif
+
+ // Outer loop to make sure enough is actually moved.
+
+ while ( (tempLen > kStdXMPLimit) && (! propSizes.empty()) ) {
+
+ // Inner loop, move what seems to be enough according to the estimates.
+
+ while ( (tempLen > kStdXMPLimit) && (! propSizes.empty()) ) {
+
+ size_t propSize = MoveLargestProperty ( stdXMP, &extXMP, propSizes );
+ XMP_Assert ( propSize > 0 );
+
+ if ( propSize > tempLen ) propSize = tempLen; // ! Don't go negative.
+ tempLen -= propSize;
+
+ }
+
+ // Reserialize the remaining standard XMP.
+
+ stdXMP.SerializeToBuffer ( &tempStr, &tempLen, keepItSmall, 1, "", "", 0 );
+
+ }
+
+ }
+
+ if ( tempLen > kStdXMPLimit ) {
+ // Still doesn't fit, throw an exception and let the client decide what to do.
+ // ! This should never happen with the policy of moving any and all top level properties.
+ XMP_Throw ( "Can't reduce XMP enough for JPEG file", kXMPErr_TooLargeForJPEG );
+ }
+
+ // Set the static output strings.
+
+ if ( extXMP.tree.children.empty() ) {
+
+ // Just have the standard XMP.
+ sStandardXMP->assign ( tempStr, tempLen );
+
+ } else {
+
+ // Have extended XMP. Serialize it, compute the digest, reset xmpNote:HasExtendedXMP, and
+ // reserialize the standard XMP.
+
+ extXMP.SerializeToBuffer ( &tempStr, &tempLen, (keepItSmall | kXMP_OmitPacketWrapper), 0, "", "", 0 );
+ sExtendedXMP->assign ( tempStr, tempLen );
+
+ MD5_CTX context;
+ XMP_Uns8 digest [16];
+ MD5Init ( &context );
+ MD5Update ( &context, (XMP_Uns8*)tempStr, tempLen );
+ MD5Final ( digest, &context );
+
+ sExtendedDigest->reserve ( 32 );
+ for ( size_t i = 0; i < 16; ++i ) {
+ XMP_Uns8 byte = digest[i];
+ sExtendedDigest->push_back ( kHexDigits [ byte>>4 ] );
+ sExtendedDigest->push_back ( kHexDigits [ byte&0xF ] );
+ }
+
+ stdXMP.SetProperty ( kXMP_NS_XMP_Note, "HasExtendedXMP", sExtendedDigest->c_str(), 0 );
+ stdXMP.SerializeToBuffer ( &tempStr, &tempLen, keepItSmall, 1, "", "", 0 );
+ sStandardXMP->assign ( tempStr, tempLen );
+
+ }
+
+ // Adjust the standard XMP padding to be up to 2KB.
+
+ XMP_Assert ( (sStandardXMP->size() > kTrailerLen) && (sStandardXMP->size() <= kStdXMPLimit) );
+ const char * packetEnd = sStandardXMP->c_str() + sStandardXMP->size() - kTrailerLen;
+ XMP_Assert ( XMP_LitMatch ( packetEnd, kPacketTrailer ) );
+
+ size_t extraPadding = kStdXMPLimit - sStandardXMP->size(); // ! Do this before erasing the trailer.
+ if ( extraPadding > 2047 ) extraPadding = 2047;
+ sStandardXMP->erase ( sStandardXMP->size() - kTrailerLen );
+ sStandardXMP->append ( extraPadding, ' ' );
+ sStandardXMP->append ( kPacketTrailer );
+
+ // Assign the output pointer and sizes.
+
+ *stdStr = sStandardXMP->c_str();
+ *stdLen = sStandardXMP->size();
+ *extStr = sExtendedXMP->c_str();
+ *extLen = sExtendedXMP->size();
+ *digestStr = sExtendedDigest->c_str();
+ *digestLen = sExtendedDigest->size();
+
+} // PackageForJPEG
+
+
+// -------------------------------------------------------------------------------------------------
+// MergeFromJPEG
+// -------------
+//
+// Copy all of the top level properties from extendedXMP to fullXMP, replacing any duplicates.
+// Delete the xmpNote:HasExtendedXMP property from fullXMP.
+
+/* class static */ void
+XMPUtils::MergeFromJPEG ( XMPMeta * fullXMP,
+ const XMPMeta & extendedXMP )
+{
+
+ XMPUtils::AppendProperties ( extendedXMP, fullXMP, kXMPUtil_DoAllProperties );
+ fullXMP->DeleteProperty ( kXMP_NS_XMP_Note, "HasExtendedXMP" );
+
+} // MergeFromJPEG
+
+
+// -------------------------------------------------------------------------------------------------
+// CurrentDateTime
+// ---------------
+
+/* class static */ void
+XMPUtils::CurrentDateTime ( XMP_DateTime * xmpTime )
+{
+ XMP_Assert ( xmpTime != 0 ); // ! Enforced by wrapper.
+
+ ansi_tt binTime = ansi_time(0);
+ if ( binTime == -1 ) XMP_Throw ( "Failure from ANSI C time function", kXMPErr_ExternalFailure );
+ ansi_tm currTime;
+ ansi_localtime ( &binTime, &currTime );
+
+ xmpTime->year = currTime.tm_year + 1900;
+ xmpTime->month = currTime.tm_mon + 1;
+ xmpTime->day = currTime.tm_mday;
+ xmpTime->hour = currTime.tm_hour;
+ xmpTime->minute = currTime.tm_min;
+ xmpTime->second = currTime.tm_sec;
+
+ xmpTime->nanoSecond = 0;
+ xmpTime->tzSign = 0;
+ xmpTime->tzHour = 0;
+ xmpTime->tzMinute = 0;
+
+ XMPUtils::SetTimeZone ( xmpTime );
+
+} // CurrentDateTime
+
+
+// -------------------------------------------------------------------------------------------------
+// SetTimeZone
+// -----------
+//
+// Sets just the time zone part of the time. Useful for determining the local time zone or for
+// converting a "zone-less" time to a proper local time. The ANSI C time functions are smart enough
+// to do all the right stuff, as long as we call them properly!
+
+/* class static */ void
+XMPUtils::SetTimeZone ( XMP_DateTime * xmpTime )
+{
+ XMP_Assert ( xmpTime != 0 ); // ! Enforced by wrapper.
+
+ if ( (xmpTime->tzSign != 0) || (xmpTime->tzHour != 0) || (xmpTime->tzMinute != 0) ) {
+ XMP_Throw ( "SetTimeZone can only be used on \"zoneless\" times", kXMPErr_BadParam );
+ }
+
+ // Create ansi_tt form of the input time. Need the ansi_tm form to make the ansi_tt form.
+
+ ansi_tt ttTime;
+ ansi_tm tmLocal, tmUTC;
+
+ if ( (xmpTime->year == 0) && (xmpTime->month == 0) && (xmpTime->day == 0) ) {
+ ansi_tt now = ansi_time(0);
+ if ( now == -1 ) XMP_Throw ( "Failure from ANSI C time function", kXMPErr_ExternalFailure );
+ ansi_localtime ( &now, &tmLocal );
+ } else {
+ tmLocal.tm_year = xmpTime->year - 1900;
+ while ( tmLocal.tm_year < 70 ) tmLocal.tm_year += 4; // ! Some versions of mktime barf on years before 1970.
+ tmLocal.tm_mon = xmpTime->month - 1;
+ tmLocal.tm_mday = xmpTime->day;
+ }
+
+ tmLocal.tm_hour = xmpTime->hour;
+ tmLocal.tm_min = xmpTime->minute;
+ tmLocal.tm_sec = xmpTime->second;
+ tmLocal.tm_isdst = -1; // Don't know if daylight time is in effect.
+
+ ttTime = ansi_mktime ( &tmLocal );
+ if ( ttTime == -1 ) XMP_Throw ( "Failure from ANSI C mktime function", kXMPErr_ExternalFailure );
+
+ // Convert back to a localized ansi_tm time and get the corresponding UTC ansi_tm time.
+
+ ansi_localtime ( &ttTime, &tmLocal );
+ ansi_gmtime ( &ttTime, &tmUTC );
+
+ // Get the offset direction and amount.
+
+ ansi_tm tmx = tmLocal; // ! Note that mktime updates the ansi_tm parameter, messing up difftime!
+ ansi_tm tmy = tmUTC;
+ tmx.tm_isdst = tmy.tm_isdst = 0;
+ ansi_tt ttx = ansi_mktime ( &tmx );
+ ansi_tt tty = ansi_mktime ( &tmy );
+ double diffSecs;
+
+ if ( (ttx != -1) && (tty != -1) ) {
+ diffSecs = ansi_difftime ( ttx, tty );
+ } else {
+ #if XMP_MacBuild
+ // Looks like Apple's mktime is buggy - see W1140533. But the offset is visible.
+ diffSecs = tmLocal.tm_gmtoff;
+ #else
+ // Win and UNIX don't have a visible offset. Make sure we know about the failure,
+ // then try using the current date/time as a close fallback.
+ ttTime = ansi_time(0);
+ if ( ttTime == -1 ) XMP_Throw ( "Failure from ANSI C time function", kXMPErr_ExternalFailure );
+ ansi_localtime ( &ttTime, &tmx );
+ ansi_gmtime ( &ttTime, &tmy );
+ tmx.tm_isdst = tmy.tm_isdst = 0;
+ ttx = ansi_mktime ( &tmx );
+ tty = ansi_mktime ( &tmy );
+ if ( (ttx == -1) || (tty == -1) ) XMP_Throw ( "Failure from ANSI C mktime function", kXMPErr_ExternalFailure );
+ diffSecs = ansi_difftime ( ttx, tty );
+ #endif
+ }
+
+ if ( diffSecs > 0.0 ) {
+ xmpTime->tzSign = kXMP_TimeEastOfUTC;
+ } else if ( diffSecs == 0.0 ) {
+ xmpTime->tzSign = kXMP_TimeIsUTC;
+ } else {
+ xmpTime->tzSign = kXMP_TimeWestOfUTC;
+ diffSecs = -diffSecs;
+ }
+ xmpTime->tzHour = XMP_Int32 ( diffSecs / 3600.0 );
+ xmpTime->tzMinute = XMP_Int32 ( (diffSecs / 60.0) - (xmpTime->tzHour * 60.0) );
+
+ // *** Save the tm_isdst flag in a qualifier?
+
+ XMP_Assert ( (0 <= xmpTime->tzHour) && (xmpTime->tzHour <= 23) );
+ XMP_Assert ( (0 <= xmpTime->tzMinute) && (xmpTime->tzMinute <= 59) );
+ XMP_Assert ( (-1 <= xmpTime->tzSign) && (xmpTime->tzSign <= +1) );
+ XMP_Assert ( (xmpTime->tzSign == 0) ? ((xmpTime->tzHour == 0) && (xmpTime->tzMinute == 0)) :
+ ((xmpTime->tzHour != 0) || (xmpTime->tzMinute != 0)) );
+
+} // SetTimeZone
+
+
+// -------------------------------------------------------------------------------------------------
+// ConvertToUTCTime
+// ----------------
+
+/* class static */ void
+XMPUtils::ConvertToUTCTime ( XMP_DateTime * time )
+{
+ XMP_Assert ( time != 0 ); // ! Enforced by wrapper.
+
+ XMP_Assert ( (0 <= time->tzHour) && (time->tzHour <= 23) );
+ XMP_Assert ( (0 <= time->tzMinute) && (time->tzMinute <= 59) );
+ XMP_Assert ( (-1 <= time->tzSign) && (time->tzSign <= +1) );
+ XMP_Assert ( (time->tzSign == 0) ? ((time->tzHour == 0) && (time->tzMinute == 0)) :
+ ((time->tzHour != 0) || (time->tzMinute != 0)) );
+
+ if ( time->tzSign == kXMP_TimeEastOfUTC ) {
+ // We are before (east of) GMT, subtract the offset from the time.
+ time->hour -= time->tzHour;
+ time->minute -= time->tzMinute;
+ } else if ( time->tzSign == kXMP_TimeWestOfUTC ) {
+ // We are behind (west of) GMT, add the offset to the time.
+ time->hour += time->tzHour;
+ time->minute += time->tzMinute;
+ }
+
+ AdjustTimeOverflow ( time );
+ time->tzSign = time->tzHour = time->tzMinute = 0;
+
+} // ConvertToUTCTime
+
+
+// -------------------------------------------------------------------------------------------------
+// ConvertToLocalTime
+// ------------------
+
+/* class static */ void
+XMPUtils::ConvertToLocalTime ( XMP_DateTime * time )
+{
+ XMP_Assert ( time != 0 ); // ! Enforced by wrapper.
+
+ XMP_Assert ( (0 <= time->tzHour) && (time->tzHour <= 23) );
+ XMP_Assert ( (0 <= time->tzMinute) && (time->tzMinute <= 59) );
+ XMP_Assert ( (-1 <= time->tzSign) && (time->tzSign <= +1) );
+ XMP_Assert ( (time->tzSign == 0) ? ((time->tzHour == 0) && (time->tzMinute == 0)) :
+ ((time->tzHour != 0) || (time->tzMinute != 0)) );
+
+ ConvertToUTCTime ( time ); // The existing time zone might not be the local one.
+ SetTimeZone ( time ); // Fill in the local timezone offset, then adjust the time.
+
+ if ( time->tzSign > 0 ) {
+ // We are before (east of) GMT, add the offset to the time.
+ time->hour += time->tzHour;
+ time->minute += time->tzMinute;
+ } else if ( time->tzSign < 0 ) {
+ // We are behind (west of) GMT, subtract the offset from the time.
+ time->hour -= time->tzHour;
+ time->minute -= time->tzMinute;
+ }
+
+ AdjustTimeOverflow ( time );
+
+} // ConvertToLocalTime
+
+
+// -------------------------------------------------------------------------------------------------
+// CompareDateTime
+// ---------------
+
+/* class static */ int
+XMPUtils::CompareDateTime ( const XMP_DateTime & _in_left,
+ const XMP_DateTime & _in_right )
+{
+ int result;
+
+ XMP_DateTime left = _in_left;
+ XMP_DateTime right = _in_right;
+
+ ConvertToUTCTime ( &left );
+ ConvertToUTCTime ( &right );
+
+ // *** We could use memcmp if the XMP_DateTime stuct has no holes.
+
+ if ( left.year < right.year ) {
+ result = -1;
+ } else if ( left.year > right.year ) {
+ result = +1;
+ } else if ( left.month < right.month ) {
+ result = -1;
+ } else if ( left.month > right.month ) {
+ result = +1;
+ } else if ( left.day < right.day ) {
+ result = -1;
+ } else if ( left.day > right.day ) {
+ result = +1;
+ } else if ( left.hour < right.hour ) {
+ result = -1;
+ } else if ( left.hour > right.hour ) {
+ result = +1;
+ } else if ( left.minute < right.minute ) {
+ result = -1;
+ } else if ( left.minute > right.minute ) {
+ result = +1;
+ } else if ( left.second < right.second ) {
+ result = -1;
+ } else if ( left.second > right.second ) {
+ result = +1;
+ } else if ( left.nanoSecond < right.nanoSecond ) {
+ result = -1;
+ } else if ( left.nanoSecond > right.nanoSecond ) {
+ result = +1;
+ } else {
+ result = 0;
+ }
+
+ return result;
+
+} // CompareDateTime
+
+// =================================================================================================
diff --git a/source/XMPCore/XMPUtils.hpp b/source/XMPCore/XMPUtils.hpp
new file mode 100644
index 0000000..adba673
--- /dev/null
+++ b/source/XMPCore/XMPUtils.hpp
@@ -0,0 +1,220 @@
+#ifndef __XMPUtils_hpp__
+#define __XMPUtils_hpp__
+
+// =================================================================================================
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "XMP_Environment.h"
+#include "XMP_Const.h"
+
+#include "XMPMeta.hpp"
+#include "XMPCore_Impl.hpp"
+
+// -------------------------------------------------------------------------------------------------
+
+extern XMP_VarString * sComposedPath; // *** Only really need 1 string. Shrink periodically?
+extern XMP_VarString * sConvertedValue;
+extern XMP_VarString * sBase64Str;
+extern XMP_VarString * sCatenatedItems;
+extern XMP_VarString * sStandardXMP;
+extern XMP_VarString * sExtendedXMP;
+extern XMP_VarString * sExtendedDigest;
+
+// -------------------------------------------------------------------------------------------------
+
+class XMPUtils {
+public:
+
+ static bool
+ Initialize(); // ! For internal use only!
+
+ static void
+ Terminate() RELEASE_NO_THROW; // ! For internal use only!
+
+ static void
+ Unlock ( XMP_OptionBits options );
+
+ // ---------------------------------------------------------------------------------------------
+
+ static void
+ ComposeArrayItemPath ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex,
+ XMP_StringPtr * fullPath,
+ XMP_StringLen * pathSize );
+
+ static void
+ ComposeStructFieldPath ( XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ XMP_StringPtr * fullPath,
+ XMP_StringLen * pathSize );
+
+ static void
+ ComposeQualifierPath ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName,
+ XMP_StringPtr * fullPath,
+ XMP_StringLen * pathSize );
+
+ static void
+ ComposeLangSelector ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_StringPtr langName,
+ XMP_StringPtr * fullPath,
+ XMP_StringLen * pathSize );
+
+ static void
+ ComposeFieldSelector ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ XMP_StringPtr fieldValue,
+ XMP_StringPtr * fullPath,
+ XMP_StringLen * pathSize );
+
+ // ---------------------------------------------------------------------------------------------
+
+ static void
+ ConvertFromBool ( bool binValue,
+ XMP_StringPtr * strValue,
+ XMP_StringLen * strSize );
+
+ static void
+ ConvertFromInt ( XMP_Int32 binValue,
+ XMP_StringPtr format,
+ XMP_StringPtr * strValue,
+ XMP_StringLen * strSize );
+
+ static void
+ ConvertFromInt64 ( XMP_Int64 binValue,
+ XMP_StringPtr format,
+ XMP_StringPtr * strValue,
+ XMP_StringLen * strSize );
+
+ static void
+ ConvertFromFloat ( double binValue,
+ XMP_StringPtr format,
+ XMP_StringPtr * strValue,
+ XMP_StringLen * strSize );
+
+ static void
+ ConvertFromDate ( const XMP_DateTime & binValue,
+ XMP_StringPtr * strValue,
+ XMP_StringLen * strSize );
+
+ // ---------------------------------------------------------------------------------------------
+
+ static bool
+ ConvertToBool ( XMP_StringPtr strValue );
+
+ static XMP_Int32
+ ConvertToInt ( XMP_StringPtr strValue );
+
+ static XMP_Int64
+ ConvertToInt64 ( XMP_StringPtr strValue );
+
+ static double
+ ConvertToFloat ( XMP_StringPtr strValue );
+
+ static void
+ ConvertToDate ( XMP_StringPtr strValue,
+ XMP_DateTime * binValue );
+
+ // ---------------------------------------------------------------------------------------------
+
+ static void
+ CurrentDateTime ( XMP_DateTime * time );
+
+ static void
+ SetTimeZone ( XMP_DateTime * time );
+
+ static void
+ ConvertToUTCTime ( XMP_DateTime * time );
+
+ static void
+ ConvertToLocalTime ( XMP_DateTime * time );
+
+ static int
+ CompareDateTime ( const XMP_DateTime & left,
+ const XMP_DateTime & right );
+ // ---------------------------------------------------------------------------------------------
+
+ static void
+ EncodeToBase64 ( XMP_StringPtr rawStr,
+ XMP_StringLen rawLen,
+ XMP_StringPtr * encodedStr,
+ XMP_StringLen * encodedLen );
+
+ static void
+ DecodeFromBase64 ( XMP_StringPtr encodedStr,
+ XMP_StringLen encodedLen,
+ XMP_StringPtr * rawStr,
+ XMP_StringLen * rawLen );
+
+ // ---------------------------------------------------------------------------------------------
+
+ static void
+ PackageForJPEG ( const XMPMeta & xmpObj,
+ XMP_StringPtr * stdStr,
+ XMP_StringLen * stdLen,
+ XMP_StringPtr * extStr,
+ XMP_StringLen * extLen,
+ XMP_StringPtr * digestStr,
+ XMP_StringLen * digestLen );
+
+ static void
+ MergeFromJPEG ( XMPMeta * fullXMP,
+ const XMPMeta & extendedXMP );
+
+ // ---------------------------------------------------------------------------------------------
+
+ static void
+ CatenateArrayItems ( const XMPMeta & xmpObj,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_StringPtr separator,
+ XMP_StringPtr quotes,
+ XMP_OptionBits options,
+ XMP_StringPtr * catedStr,
+ XMP_StringLen * catedLen );
+
+ static void
+ SeparateArrayItems ( XMPMeta * xmpObj,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_OptionBits options,
+ XMP_StringPtr catedStr );
+
+ static void
+ RemoveProperties ( XMPMeta * xmpObj,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_OptionBits options );
+
+ static void
+ AppendProperties ( const XMPMeta & source,
+ XMPMeta * dest,
+ XMP_OptionBits options );
+
+ static void
+ DuplicateSubtree ( const XMPMeta & source,
+ XMPMeta * dest,
+ XMP_StringPtr sourceNS,
+ XMP_StringPtr sourceRoot,
+ XMP_StringPtr destNS,
+ XMP_StringPtr destRoot,
+ XMP_OptionBits options );
+
+}; // XMPUtils
+
+// =================================================================================================
+
+#endif // __XMPUtils_hpp__
diff --git a/source/XMPFiles/FileHandlers/AVI_Handler.cpp b/source/XMPFiles/FileHandlers/AVI_Handler.cpp
new file mode 100644
index 0000000..6511246
--- /dev/null
+++ b/source/XMPFiles/FileHandlers/AVI_Handler.cpp
@@ -0,0 +1,432 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "AVI_Handler.hpp"
+#include "RIFF_Support.hpp"
+
+#if XMP_WinBuild
+ #include <vfw.h>
+#else
+ #ifndef formtypeAVI
+ #define formtypeAVI MakeFourCC('A', 'V', 'I', ' ')
+ #else
+ #error "formtypeAVI already defined"
+ #endif
+#endif
+
+
+using namespace std;
+
+#define kXMPUserDataType MakeFourCC ( '_', 'P', 'M', 'X' ) /* Yes, backwards! */
+
+
+/*******************************************************
+** Premiere Pro specific info for reconciliation
+*******************************************************/
+// FourCC codes for the RIFF chunks
+#define aviTimeChunk MakeFourCC('I','S','M','T')
+#define avihdrlChunk MakeFourCC('h','d','r','l')
+#define myOrgTimeChunk MakeFourCC('t','c','_','O') /* 0x4f5f6374 */
+#define myAltTimeChunk MakeFourCC('t','c','_','A')
+#define myOrgReelChunk MakeFourCC('r','n','_','O') /* 0x4f5f6e72 */
+#define myAltReelChunk MakeFourCC('r','n','_','A')
+#define myCommentChunk MakeFourCC('c','m','n','t')
+#define myTimeList MakeFourCC('T','d','a','t') /* 0x74616454 */
+#define myCommentList MakeFourCC('C','d','a','t')
+
+#define TIMELEN 18
+#define REELLEN 40
+#define REALTIMELEN 11
+#define COMMENTLEN 256
+
+/* list id (4 bytes) + four tags hdrs (8 each) + 2 TIMEs + 2 REELs */
+#define PR_AVI_TIMELEN (12 + 2 * (8 + TIMELEN) + 2 * (8 + REELLEN))
+
+#define PR_AVI_COMMENTLEN (12 + 8 + COMMENTLEN)
+
+#define kStartTimecode "startTimecode"
+#define kTimeValue "timeValue"
+#define kAltTimecode "altTimecode"
+#define kTapeName "tapeName"
+#define kAltTapeName "altTapeName"
+#define kLogComment "logComment"
+
+/*******************************************************
+*******************************************************/
+
+
+// =================================================================================================
+/// \file AVI_Handler.cpp
+/// \brief File format handler for AVI.
+///
+/// This header ...
+///
+// =================================================================================================
+
+// =================================================================================================
+// AVI_MetaHandlerCTor
+// ====================
+
+XMPFileHandler * AVI_MetaHandlerCTor ( XMPFiles * parent )
+{
+ return new AVI_MetaHandler ( parent );
+
+} // AVI_MetaHandlerCTor
+
+// =================================================================================================
+// AVI_CheckFormat
+// ===============
+//
+// An AVI file must begin with "RIFF", a 4 byte little endian length, then "AVI ". The length should
+// be fileSize-8, but we don't bother checking this here.
+
+bool AVI_CheckFormat ( XMP_FileFormat format,
+ XMP_StringPtr filePath,
+ LFA_FileRef fileRef,
+ XMPFiles * parent )
+{
+ IgnoreParam(format); IgnoreParam(parent);
+ XMP_Assert ( format == kXMP_AVIFile );
+
+ if ( fileRef == 0 ) return false;
+
+ enum { kBufferSize = 12 };
+ XMP_Uns8 buffer [kBufferSize];
+
+ LFA_Seek ( fileRef, 0, SEEK_SET );
+ LFA_Read ( fileRef, buffer, kBufferSize );
+
+ // "RIFF" is 52 49 46 46, "AVI " is 41 56 49 20
+ if ( (! CheckBytes ( &buffer[0], "\x52\x49\x46\x46", 4 )) ||
+ (! CheckBytes ( &buffer[8], "\x41\x56\x49\x20", 4 )) ) return false;
+
+ return true;
+
+} // AVI_CheckFormat
+
+// =================================================================================================
+// AVI_MetaHandler::AVI_MetaHandler
+// ================================
+
+AVI_MetaHandler::AVI_MetaHandler ( XMPFiles * _parent )
+{
+ this->parent = _parent;
+ this->handlerFlags = kAVI_HandlerFlags;
+ this->stdCharForm = kXMP_Char8Bit;
+
+} // AVI_MetaHandler::AVI_MetaHandler
+
+// =================================================================================================
+// AVI_MetaHandler::~AVI_MetaHandler
+// =================================
+
+AVI_MetaHandler::~AVI_MetaHandler()
+{
+ // Nothing to do.
+
+} // AVI_MetaHandler::~AVI_MetaHandler
+
+// =================================================================================================
+// AVI_MetaHandler::UpdateFile
+// ===========================
+
+void AVI_MetaHandler::UpdateFile ( bool doSafeUpdate )
+{
+ bool ok;
+
+ if ( ! this->needsUpdate ) return;
+ if ( doSafeUpdate ) XMP_Throw ( "AVI_MetaHandler::UpdateFile: Safe update not supported", kXMPErr_Unavailable );
+
+ XMP_StringPtr packetStr = xmpPacket.c_str();
+ XMP_StringLen packetLen = xmpPacket.size();
+ if ( packetLen == 0 ) return;
+
+ // Make sure we're writing an even number of bytes as required by the RIFF specification.
+ if ( (xmpPacket.size() & 1) == 1 ) xmpPacket.push_back ( ' ' );
+ XMP_Assert ( (xmpPacket.size() & 1) == 0 );
+ packetStr = xmpPacket.c_str(); // ! Make sure they are current.
+ packetLen = xmpPacket.size();
+
+ LFA_FileRef fileRef(this->parent->fileRef);
+ if ( fileRef == 0 ) return;
+
+ RIFF_Support::RiffState riffState;
+ long numTags = RIFF_Support::OpenRIFF ( fileRef, riffState );
+ if ( numTags == 0 ) return;
+
+ ok = RIFF_Support::PutChunk ( fileRef, riffState, formtypeAVI, kXMPUserDataType, (char*)packetStr, packetLen );
+ if ( ! ok )return; // If there's an error writing the chunk, bail.
+
+ // Update legacy metadata
+
+ std::string startTimecodeString, altTimecodeString, orgReelString, altReelString, logCommentString;
+
+ this->xmpObj.GetStructField ( kXMP_NS_DM, kStartTimecode, kXMP_NS_DM, kTimeValue, &startTimecodeString, 0 );
+ this->xmpObj.GetStructField ( kXMP_NS_DM, kAltTimecode, kXMP_NS_DM, kTimeValue, &altTimecodeString, 0 );
+ this->xmpObj.GetProperty ( kXMP_NS_DM, kTapeName, &orgReelString, 0 );
+ this->xmpObj.GetProperty ( kXMP_NS_DM, kAltTapeName, &altReelString, 0 );
+ this->xmpObj.GetProperty ( kXMP_NS_DM, kLogComment, &logCommentString, 0 );
+
+ if ( startTimecodeString.size() != 0 ) {
+ // I'm not sure why we copy into this 12 char buffer, but this is what Premiere code does.
+ char aviTime [12];
+ memset ( aviTime, 0, 12 );
+ memcpy ( aviTime, startTimecodeString.data(), 11 ); // AUDIT: 11 is less than 12
+ RewriteChunk ( fileRef, riffState, aviTimeChunk, avihdrlChunk, aviTime );
+ }
+
+ if ( logCommentString.size() != 0 ) {
+
+ ok = FindChunk ( riffState, myCommentChunk, myCommentList, 0, 0, 0, 0 );
+
+ if ( ! ok ) {
+
+ // Always rewrite the comment string, even if empty, so the user can erase it.
+ RIFF_Support::RewriteChunk ( fileRef, riffState, myCommentChunk, myCommentList, logCommentString.c_str() );
+
+ } else {
+
+ ok = MakeChunk ( fileRef, riffState, formtypeAVI, PR_AVI_COMMENTLEN );
+ if ( ! ok ) return; // If there's an error making a chunk, bail
+
+ RIFF_Support::ltag listtag;
+ listtag.id = MakeUns32LE ( FOURCC_LIST );
+ listtag.len = MakeUns32LE ( PR_AVI_COMMENTLEN - 8 );
+ listtag.subid = MakeUns32LE ( myCommentList );
+ LFA_Write ( fileRef, &listtag, 12 );
+
+ RIFF_Support::WriteChunk ( fileRef, myCommentChunk, logCommentString.c_str(), COMMENTLEN );
+
+ }
+
+ }
+
+ ok = RIFF_Support::FindChunk ( riffState, myOrgTimeChunk, myTimeList, 0, 0, 0, 0 );
+
+ if ( ok ) {
+
+ if ( startTimecodeString.size() != 0 ) {
+ RewriteChunk ( fileRef, riffState, myOrgTimeChunk, myTimeList, startTimecodeString.c_str() );
+ }
+
+ if ( altTimecodeString.size() != 0 ) {
+ RewriteChunk ( fileRef, riffState, myAltTimeChunk, myTimeList, altTimecodeString.c_str() );
+ }
+
+ // Always rewrite the reel strings, even if empty, so the user can erase them.
+ RewriteChunk ( fileRef, riffState, myOrgReelChunk, myTimeList, orgReelString.c_str() );
+ RewriteChunk ( fileRef, riffState, myAltReelChunk, myTimeList, altReelString.c_str() );
+
+ } else {
+
+ ok = MakeChunk ( fileRef, riffState, formtypeAVI, PR_AVI_TIMELEN );
+ if ( ! ok ) return; // If there's an error making a chunk, bail
+
+ RIFF_Support::ltag listtag;
+ listtag.id = MakeUns32LE ( FOURCC_LIST );
+ listtag.len = MakeUns32LE ( PR_AVI_TIMELEN - 8 );
+ listtag.subid = MakeUns32LE ( myTimeList );
+ LFA_Write(fileRef, &listtag, 12);
+
+ RIFF_Support::WriteChunk ( fileRef, myOrgTimeChunk, startTimecodeString.c_str(), TIMELEN );
+ RIFF_Support::WriteChunk ( fileRef, myAltTimeChunk, altTimecodeString.c_str(), TIMELEN );
+ RIFF_Support::WriteChunk ( fileRef, myOrgReelChunk, orgReelString.c_str(), REELLEN );
+ RIFF_Support::WriteChunk ( fileRef, myAltReelChunk, altReelString.c_str(), REELLEN );
+
+ }
+
+ this->needsUpdate = false;
+
+} // AVI_MetaHandler::UpdateFile
+
+// =================================================================================================
+// AVI_MetaHandler::WriteFile
+// ==========================
+
+void AVI_MetaHandler::WriteFile ( LFA_FileRef sourceRef,
+ const std::string & sourcePath )
+{
+ IgnoreParam(sourceRef); IgnoreParam(sourcePath);
+
+ XMP_Throw ( "AVI_MetaHandler::WriteFile: Not supported", kXMPErr_Unavailable );
+
+} // AVI_MetaHandler::WriteFile
+
+// =================================================================================================
+// AVI_MetaHandler::CacheFileData
+// ==============================
+
+void AVI_MetaHandler::CacheFileData()
+{
+ bool ok;
+
+ this->containsXMP = false;
+
+ LFA_FileRef fileRef ( this->parent->fileRef );
+ if ( fileRef == 0 ) return;
+
+ RIFF_Support::RiffState riffState;
+ long numTags = RIFF_Support::OpenRIFF ( fileRef, riffState );
+ if ( numTags == 0 ) return;
+
+ // Determine the size of the metadata
+ unsigned long bufferSize(0);
+ ok = RIFF_Support::GetRIFFChunk ( fileRef, riffState, kXMPUserDataType, 0, 0, 0, &bufferSize );
+
+ if ( ! ok ) {
+
+ packetInfo.writeable = true; // If no packet found, created packets will be writeable.
+
+ } else if ( bufferSize > 0 ) {
+
+ // Size and clear the buffer
+ this->xmpPacket.reserve ( bufferSize );
+ this->xmpPacket.assign ( bufferSize, ' ' );
+
+ // Get the metadata
+ ok = RIFF_Support::GetRIFFChunk ( fileRef, riffState, kXMPUserDataType, 0, 0, (char*)this->xmpPacket.c_str(), &bufferSize );
+ if ( ok ) {
+ this->packetInfo.offset = kXMPFiles_UnknownOffset;
+ this->packetInfo.length = bufferSize;
+ this->xmpObj.ParseFromBuffer ( this->xmpPacket.c_str(), this->xmpPacket.size() );
+ this->containsXMP = true;
+ }
+
+ }
+
+
+ // Reconcile legacy metadata.
+
+ std::string aviTimeString, orgTimeString, altTimeString;
+ unsigned long aviTimeSize, orgTimeSize, altTimeSize;
+
+ ok = RIFF_Support::GetRIFFChunk ( fileRef, riffState, aviTimeChunk, avihdrlChunk, 0, 0, &aviTimeSize );
+ if ( ok ) {
+ aviTimeString.reserve ( aviTimeSize );
+ aviTimeString.assign ( aviTimeSize, ' ' );
+ RIFF_Support::GetRIFFChunk ( fileRef, riffState, aviTimeChunk, avihdrlChunk, 0, (char*)aviTimeString.c_str(), &aviTimeSize );
+ }
+
+ ok = RIFF_Support::GetRIFFChunk ( fileRef, riffState, myOrgTimeChunk, myTimeList, 0, 0, &orgTimeSize );
+ if ( ok ) {
+ orgTimeString.reserve ( orgTimeSize );
+ orgTimeString.assign ( orgTimeSize, ' ' );
+ RIFF_Support::GetRIFFChunk ( fileRef, riffState, myOrgTimeChunk, myTimeList, 0, (char*)orgTimeString.c_str(), &orgTimeSize );
+ }
+
+ ok = RIFF_Support::GetRIFFChunk ( fileRef, riffState, myAltTimeChunk, myTimeList, 0, 0, &altTimeSize );
+ if ( ok ) {
+ altTimeString.reserve ( altTimeSize );
+ altTimeString.assign ( altTimeSize, ' ' );
+ RIFF_Support::GetRIFFChunk ( fileRef, riffState, myAltTimeChunk, myTimeList, 0, (char*)altTimeString.c_str(), &altTimeSize );
+ }
+
+ if ( (! aviTimeString.empty()) && orgTimeString.empty() && (altTimeString.empty()) ) {
+
+ // If we have an avi time, and not the org or alt, use the avi. I suspect this is for some earlier backwards compatibility.
+
+ std::string xmpString;
+ this->xmpObj.GetStructField ( kXMP_NS_DM, kStartTimecode, kXMP_NS_DM, kTimeValue, &xmpString, 0 );
+ if ( xmpString.compare ( 0, REALTIMELEN, aviTimeString, 0, REALTIMELEN ) ) {
+ this->xmpObj.SetStructField ( kXMP_NS_DM, kStartTimecode, kXMP_NS_DM, kTimeValue, aviTimeString, 0 );
+ this->containsXMP = true;
+ }
+
+ } else {
+
+ // Otherwise, check the original and alt timecodes.
+
+ if ( ! orgTimeString.empty() ) {
+ std::string xmpString;
+ this->xmpObj.GetStructField ( kXMP_NS_DM, kStartTimecode, kXMP_NS_DM, kTimeValue, &xmpString, 0 );
+ if (xmpString.compare ( 0, REALTIMELEN, orgTimeString, 0, REALTIMELEN ) ) {
+ this->xmpObj.SetStructField ( kXMP_NS_DM, kStartTimecode, kXMP_NS_DM, kTimeValue, orgTimeString, 0 );
+ this->containsXMP = true;
+ }
+ }
+
+ if ( ! altTimeString.empty() ) {
+ std::string xmpString;
+ this->xmpObj.GetStructField ( kXMP_NS_DM, kAltTimecode, kXMP_NS_DM, kTimeValue, &xmpString, 0 );
+ if ( xmpString.compare ( 0, REALTIMELEN, altTimeString, 0, REALTIMELEN ) ) {
+ this->xmpObj.SetStructField ( kXMP_NS_DM, kAltTimecode, kXMP_NS_DM, kTimeValue, altTimeString, 0 );
+ this->containsXMP = true;
+ }
+ }
+
+ }
+
+ unsigned long orgReelSize;
+ ok = RIFF_Support::GetRIFFChunk ( fileRef, riffState, myOrgReelChunk, myTimeList, 0, 0, &orgReelSize );
+ if ( ok ) {
+
+ std::string orgReelString;
+ orgReelString.reserve ( orgReelSize );
+ orgReelString.assign ( orgReelSize, ' ' );
+ RIFF_Support::GetRIFFChunk ( fileRef, riffState, myOrgReelChunk, myTimeList, 0, (char*)orgReelString.c_str(), &orgReelSize );
+
+ if ( ! orgReelString.empty() ) {
+ std::string xmpString;
+ this->xmpObj.GetProperty ( kXMP_NS_DM, kTapeName, &xmpString, 0 );
+ if ( xmpString.compare ( 0, REELLEN, orgReelString, 0, REELLEN ) ) {
+ this->xmpObj.SetProperty ( kXMP_NS_DM, kTapeName, orgReelString, 0 );
+ this->containsXMP = true;
+ }
+ }
+
+ }
+
+ unsigned long altReelSize;
+ ok = RIFF_Support::GetRIFFChunk ( fileRef, riffState, myAltReelChunk, myTimeList, 0, 0, &altReelSize );
+ if ( ok ) {
+
+ std::string altReelString;
+ altReelString.reserve ( altReelSize );
+ altReelString.assign ( altReelSize, ' ' );
+ RIFF_Support::GetRIFFChunk ( fileRef, riffState, myAltReelChunk, myTimeList, 0, (char*)altReelString.c_str(), &altReelSize );
+
+ if ( ! altReelString.empty() ) {
+ std::string xmpString;
+ this->xmpObj.GetProperty ( kXMP_NS_DM, kAltTapeName, &xmpString, 0 );
+ if ( xmpString.compare ( 0, REELLEN, altReelString, 0, REELLEN ) ) {
+ this->xmpObj.SetProperty ( kXMP_NS_DM, kAltTapeName, altReelString, 0 );
+ this->containsXMP = true;
+ }
+ }
+
+ }
+
+ unsigned long logCommentSize;
+ ok = RIFF_Support::GetRIFFChunk ( fileRef, riffState, myCommentChunk, myCommentList, 0, 0, &logCommentSize );
+ if ( ok ) {
+
+ std::string logCommentString;
+ logCommentString.reserve ( logCommentSize );
+ logCommentString.assign ( logCommentSize, ' ' );
+ RIFF_Support::GetRIFFChunk ( fileRef, riffState, myCommentChunk, myCommentList, 0, (char*)logCommentString.c_str(), &logCommentSize );
+
+ if ( ! logCommentString.empty() ) {
+ std::string xmpString;
+ this->xmpObj.GetProperty ( kXMP_NS_DM, kLogComment, &xmpString, 0 );
+ if ( xmpString.compare ( logCommentString ) ) {
+ this->xmpObj.SetProperty ( kXMP_NS_DM, kLogComment, logCommentString, 0 );
+ this->containsXMP = true;
+ }
+ }
+
+ }
+
+ // Update the xmpPacket, as the xmpObj might have been updated with legacy info.
+ this->xmpObj.SerializeToBuffer ( &this->xmpPacket, kXMP_UseCompactFormat );
+ this->packetInfo.offset = kXMPFiles_UnknownOffset;
+ this->packetInfo.length = this->xmpPacket.size();
+
+ this->processedXMP = this->containsXMP;
+
+} // AVI_MetaHandler::CacheFileData
diff --git a/source/XMPFiles/FileHandlers/AVI_Handler.hpp b/source/XMPFiles/FileHandlers/AVI_Handler.hpp
new file mode 100644
index 0000000..9db656c
--- /dev/null
+++ b/source/XMPFiles/FileHandlers/AVI_Handler.hpp
@@ -0,0 +1,53 @@
+#ifndef __AVI_Handler_hpp__
+#define __AVI_Handler_hpp__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "XMPFiles_Impl.hpp"
+
+// =================================================================================================
+/// \file AVI_Handler.hpp
+/// \brief File format handler for AVI.
+///
+/// This header ...
+///
+// =================================================================================================
+
+extern XMPFileHandler * AVI_MetaHandlerCTor ( XMPFiles * parent );
+
+extern bool AVI_CheckFormat ( XMP_FileFormat format,
+ XMP_StringPtr filePath,
+ LFA_FileRef fileRef,
+ XMPFiles * parent );
+
+static const XMP_OptionBits kAVI_HandlerFlags = (kXMPFiles_CanInjectXMP |
+ kXMPFiles_CanExpand |
+ kXMPFiles_PrefersInPlace |
+ kXMPFiles_AllowsOnlyXMP |
+ kXMPFiles_ReturnsRawPacket);
+ // In the future, we'll add kXMPFiles_CanReconcile
+
+class AVI_MetaHandler : public XMPFileHandler
+{
+public:
+
+ AVI_MetaHandler ( XMPFiles * parent );
+ ~AVI_MetaHandler();
+
+ void CacheFileData();
+
+ void UpdateFile ( bool doSafeUpdate );
+ void WriteFile ( LFA_FileRef sourceRef, const std::string & sourcePath );
+
+}; // AVI_MetaHandler
+
+// =================================================================================================
+
+#endif /* __AVI_Handler_hpp__ */
diff --git a/source/XMPFiles/FileHandlers/Basic_Handler.cpp b/source/XMPFiles/FileHandlers/Basic_Handler.cpp
new file mode 100644
index 0000000..845fe16
--- /dev/null
+++ b/source/XMPFiles/FileHandlers/Basic_Handler.cpp
@@ -0,0 +1,247 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "Basic_Handler.hpp"
+
+using namespace std;
+
+// =================================================================================================
+/// \file Basic_Handler.cpp
+/// \brief Base class for basic handlers that only process in-place XMP.
+///
+/// This header ...
+///
+// =================================================================================================
+
+// =================================================================================================
+// Basic_MetaHandler::~Basic_MetaHandler
+// =====================================
+
+Basic_MetaHandler::~Basic_MetaHandler()
+{
+ // ! Inherit the base cleanup.
+
+} // Basic_MetaHandler::~Basic_MetaHandler
+
+// =================================================================================================
+// Basic_MetaHandler::UpdateFile
+// =============================
+
+// ! This must be called from the destructor for all derived classes. It can't be called from the
+// ! Basic_MetaHandler destructor, by then calls to the virtual functions would not go to the
+// ! actual implementations for the derived class.
+
+void Basic_MetaHandler::UpdateFile ( bool doSafeUpdate )
+{
+ IgnoreParam ( doSafeUpdate );
+ XMP_Assert ( ! doSafeUpdate ); // Not supported at this level.
+ if ( ! this->needsUpdate ) return;
+
+ LFA_FileRef fileRef = this->parent->fileRef;
+ XMP_PacketInfo & packetInfo = this->packetInfo;
+ std::string & xmpPacket = this->xmpPacket;
+
+ XMP_AbortProc abortProc = this->parent->abortProc;
+ void * abortArg = this->parent->abortArg;
+ const bool checkAbort = (abortProc != 0);
+
+ this->CaptureFileEnding(); // ! Do this first, before any location info changes.
+ if ( checkAbort && abortProc(abortArg) ) {
+ XMP_Throw ( "Basic_MetaHandler::UpdateFile - User abort", kXMPErr_UserAbort );
+ }
+
+ this->NoteXMPRemoval();
+ this->ShuffleTrailingContent();
+ if ( checkAbort && abortProc(abortArg) ) {
+ XMP_Throw ( "Basic_MetaHandler::UpdateFile - User abort", kXMPErr_UserAbort );
+ }
+
+ XMP_Int64 tempLength = this->xmpFileOffset - this->xmpPrefixSize + this->trailingContentSize;
+ LFA_Truncate ( fileRef, tempLength );
+ LFA_Flush ( fileRef );
+
+ packetInfo.offset = tempLength + this->xmpPrefixSize;
+ this->NoteXMPInsertion();
+
+ LFA_Seek ( fileRef, 0, SEEK_END );
+ this->WriteXMPPrefix();
+ LFA_Write ( fileRef, xmpPacket.c_str(), xmpPacket.size() );
+ this->WriteXMPSuffix();
+ if ( checkAbort && abortProc(abortArg) ) {
+ XMP_Throw ( "Basic_MetaHandler::UpdateFile - User abort", kXMPErr_UserAbort );
+ }
+
+ this->RestoreFileEnding();
+ LFA_Flush ( fileRef );
+
+ this->xmpFileOffset = packetInfo.offset;
+ this->xmpFileSize = packetInfo.length;
+ this->needsUpdate = false;
+
+} // Basic_MetaHandler::UpdateFile
+
+// =================================================================================================
+// Basic_MetaHandler::WriteFile
+// ============================
+
+// *** What about computing the new file length and pre-allocating the file?
+
+void Basic_MetaHandler::WriteFile ( LFA_FileRef sourceRef, const std::string & sourcePath )
+{
+ IgnoreParam ( sourcePath );
+
+ XMP_AbortProc abortProc = this->parent->abortProc;
+ void * abortArg = this->parent->abortArg;
+ const bool checkAbort = (abortProc != 0);
+
+ LFA_FileRef destRef = this->parent->fileRef;
+
+ // Capture the "back" of the source file.
+
+ this->parent->fileRef = sourceRef;
+ this->CaptureFileEnding();
+ this->parent->fileRef = destRef;
+ if ( checkAbort && abortProc(abortArg) ) {
+ XMP_Throw ( "Basic_MetaHandler::UpdateFile - User abort", kXMPErr_UserAbort );
+ }
+
+ // Seek to the beginning of the source and destination files, truncate the destination.
+
+ LFA_Seek ( sourceRef, 0, SEEK_SET );
+ LFA_Seek ( destRef, 0, SEEK_SET );
+ LFA_Truncate ( destRef, 0 );
+
+ // Copy the front of the source file to the destination. Note the XMP (pseudo) removal and
+ // insertion. This mainly updates info about the new XMP length.
+
+ XMP_Int64 xmpSectionOffset = this->xmpFileOffset - this->xmpPrefixSize;
+ XMP_Int32 oldSectionLength = this->xmpPrefixSize + this->xmpFileSize + this->xmpSuffixSize;
+
+ LFA_Copy ( sourceRef, destRef, xmpSectionOffset, abortProc, abortArg );
+ this->NoteXMPRemoval();
+ packetInfo.offset = this->xmpFileOffset; // ! The packet offset does not change.
+ this->NoteXMPInsertion();
+ LFA_Seek ( destRef, 0, SEEK_END );
+ if ( checkAbort && abortProc(abortArg) ) {
+ XMP_Throw ( "Basic_MetaHandler::WriteFile - User abort", kXMPErr_UserAbort );
+ }
+
+ // Write the new XMP section to the destination.
+
+ this->WriteXMPPrefix();
+ LFA_Write ( destRef, this->xmpPacket.c_str(), this->xmpPacket.size() );
+ this->WriteXMPSuffix();
+ if ( checkAbort && abortProc(abortArg) ) {
+ XMP_Throw ( "Basic_MetaHandler::WriteFile - User abort", kXMPErr_UserAbort );
+ }
+
+ // Copy the trailing file content from the source and write the "back" of the file.
+
+ XMP_Int64 remainderOffset = xmpSectionOffset + oldSectionLength;
+
+ LFA_Seek ( sourceRef, remainderOffset, SEEK_SET );
+ LFA_Copy ( sourceRef, destRef, this->trailingContentSize, abortProc, abortArg );
+ this->RestoreFileEnding();
+
+ // Done.
+
+ LFA_Flush ( destRef );
+
+ this->xmpFileOffset = packetInfo.offset;
+ this->xmpFileSize = packetInfo.length;
+ this->needsUpdate = false;
+
+} // Basic_MetaHandler::WriteFile
+
+// =================================================================================================
+// ShuffleTrailingContent
+// ======================
+//
+// Shuffle the trailing content portion of a file forward. This does not include the final "back"
+// portion of the file, just the arbitrary length content between the XMP section and the back.
+// Don't use LFA_Copy, that assumes separate files and hence separate I/O positions.
+
+// ! The XMP packet location and prefix/suffix sizes must still reflect the XMP section that is in
+// ! the process of being removed.
+
+void Basic_MetaHandler::ShuffleTrailingContent()
+{
+ LFA_FileRef fileRef = this->parent->fileRef;
+
+ XMP_Int64 readOffset = this->packetInfo.offset + xmpSuffixSize;
+ XMP_Int64 writeOffset = this->packetInfo.offset - xmpPrefixSize;
+
+ XMP_Int64 remainingLength = this->trailingContentSize;
+
+ enum { kBufferSize = 64*1024 };
+ char buffer [kBufferSize];
+
+ XMP_AbortProc abortProc = this->parent->abortProc;
+ void * abortArg = this->parent->abortArg;
+ const bool checkAbort = (abortProc != 0);
+
+ while ( remainingLength > 0 ) {
+
+ XMP_Int32 ioCount = kBufferSize;
+ if ( remainingLength < kBufferSize ) ioCount = (XMP_Int32)remainingLength;
+
+ LFA_Seek ( fileRef, readOffset, SEEK_SET );
+ LFA_Read ( fileRef, buffer, ioCount, kLFA_RequireAll );
+ LFA_Seek ( fileRef, writeOffset, SEEK_SET );
+ LFA_Write ( fileRef, buffer, ioCount );
+
+ readOffset += ioCount;
+ writeOffset += ioCount;
+ remainingLength -= ioCount;
+
+ if ( checkAbort && abortProc(abortArg) ) {
+ XMP_Throw ( "Basic_MetaHandler::ShuffleTrailingContent - User abort", kXMPErr_UserAbort );
+ }
+
+ }
+
+ LFA_Flush ( fileRef );
+
+} // ShuffleTrailingContent
+
+// =================================================================================================
+// Dummies needed for VS.Net
+// =========================
+
+void Basic_MetaHandler::WriteXMPPrefix()
+{
+ XMP_Throw ( "Basic_MetaHandler::WriteXMPPrefix - Needs specific override", kXMPErr_InternalFailure );
+}
+
+void Basic_MetaHandler::WriteXMPSuffix()
+{
+ XMP_Throw ( "Basic_MetaHandler::WriteXMPSuffix - Needs specific override", kXMPErr_InternalFailure );
+}
+
+void Basic_MetaHandler::NoteXMPRemoval()
+{
+ XMP_Throw ( "Basic_MetaHandler::NoteXMPRemoval - Needs specific override", kXMPErr_InternalFailure );
+}
+
+void Basic_MetaHandler::NoteXMPInsertion()
+{
+ XMP_Throw ( "Basic_MetaHandler::NoteXMPInsertion - Needs specific override", kXMPErr_InternalFailure );
+}
+
+void Basic_MetaHandler::CaptureFileEnding()
+{
+ XMP_Throw ( "Basic_MetaHandler::CaptureFileEnding - Needs specific override", kXMPErr_InternalFailure );
+}
+
+void Basic_MetaHandler::RestoreFileEnding()
+{
+ XMP_Throw ( "Basic_MetaHandler::RestoreFileEnding - Needs specific override", kXMPErr_InternalFailure );
+}
+
+// =================================================================================================
diff --git a/source/XMPFiles/FileHandlers/Basic_Handler.hpp b/source/XMPFiles/FileHandlers/Basic_Handler.hpp
new file mode 100644
index 0000000..4f8dc77
--- /dev/null
+++ b/source/XMPFiles/FileHandlers/Basic_Handler.hpp
@@ -0,0 +1,103 @@
+#ifndef __Basic_Handler_hpp__
+#define __Basic_Handler_hpp__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "XMPFiles_Impl.hpp"
+
+// =================================================================================================
+/// \file Basic_Handler.hpp
+///
+/// \brief Base class for handlers that support a simple file model allowing insertion and expansion
+/// of XMP, but probably not reconciliation with other forms of metadata. Reconciliation would have
+/// to be done within the I/O model presented here.
+///
+/// \note Any specific derived handler might not be able to do insertion, but all must support
+/// expansion. If a handler can't do either it should be derived from Trivial_Handler. Common code
+/// must check the actual canInject flag where appropriate.
+///
+/// The model for a basic handler divides the file into 6 portions:
+///
+/// \li The front of the file. This portion can be arbitrarily large. Files over 4GB are supported.
+/// Adding or expanding the XMP must not require expanding this portion of the file. The XMP offset
+/// or length might be written into reserved space in this section though.
+///
+/// \li A prefix for the XMP section. The prefix and suffix for the XMP "section" are the format
+/// specific portions that surround the raw XMP packet. They must be generated on the fly, even when
+/// updating existing XMP with or without expansion. Their length must not depend on the XMP packet.
+///
+/// \li The XMP packet, as created by SXMPMeta::SerializeToBuffer. The size must be less than 2GB.
+///
+/// \li A suffix for the XMP section.
+///
+/// \li Trailing file content. This portion can be arbitarily large. It must be possible to remove
+/// the XMP, move this portion of the file forward, then reinsert the XMP after this portion. This
+/// is actually how the XMP is expanded. There must not be any embedded file offsets in this part,
+/// this content must not change if the XMP changes size.
+///
+/// \li The back of the file. This portion must have modest size, and/or be generated on the fly.
+/// When inserting XMP, part of this may be buffered in RAM (hence the modest size requirement), the
+/// XMP section is written, then this portion is rewritten. There must not be any embedded file
+/// offsets in this part, this content must not change if the XMP changes size.
+///
+/// \note There is no general promise here about crash-safe I/O. An update to an existing file might
+/// have invalid partial state, for example while moving the trailing content portion forward if the
+/// XMP increases in size or even rewriting existing XMP in-place. Crash-safe updates are managed at
+/// a higher level of XMPFiles, using a temporary file and final swap of file content.
+///
+// =================================================================================================
+
+static const XMP_OptionBits kBasic_HandlerFlags = (kXMPFiles_CanInjectXMP |
+ kXMPFiles_CanExpand |
+ kXMPFiles_CanRewrite |
+ kXMPFiles_AllowsOnlyXMP |
+ kXMPFiles_ReturnsRawPacket |
+ kXMPFiles_AllowsSafeUpdate);
+
+class Basic_MetaHandler : public XMPFileHandler
+{
+public:
+
+ Basic_MetaHandler() :
+ xmpFileOffset(0), xmpFileSize(0), xmpPrefixSize(0), xmpSuffixSize(0), trailingContentSize(0) {};
+ ~Basic_MetaHandler();
+
+ virtual void CacheFileData() = 0; // Sets offset for insertion if no XMP yet.
+
+ void UpdateFile ( bool doSafeUpdate );
+ void WriteFile ( LFA_FileRef sourceRef, const std::string & sourcePath );
+
+protected:
+
+ virtual void WriteXMPPrefix() = 0; // ! Must have override in actual handlers!
+ virtual void WriteXMPSuffix() = 0; // ! Must have override in actual handlers!
+
+ virtual void NoteXMPRemoval() = 0; // ! Must have override in actual handlers!
+ virtual void NoteXMPInsertion() = 0; // ! Must have override in actual handlers!
+
+ virtual void CaptureFileEnding() = 0; // ! Must have override in actual handlers!
+ virtual void RestoreFileEnding() = 0; // ! Must have override in actual handlers!
+
+ void ShuffleTrailingContent(); // Move the trailing content portion forward. Excludes "back" of the file.
+
+ XMP_Uns64 xmpFileOffset; // The offset of the XMP in the file.
+ XMP_Uns32 xmpFileSize; // The size of the XMP in the file.
+ // ! The packetInfo offset and length are updated by PutXMP, before the file is updated!
+
+ XMP_Uns32 xmpPrefixSize; // The size of the existing header for the XMP section.
+ XMP_Uns32 xmpSuffixSize; // The size of the existing trailer for the XMP section.
+
+ XMP_Uns64 trailingContentSize; // The size of the existing trailing content. Excludes "back" of the file.
+
+}; // Basic_MetaHandler
+
+// =================================================================================================
+
+#endif /* __Basic_Handler_hpp__ */
diff --git a/source/XMPFiles/FileHandlers/InDesign_Handler.cpp b/source/XMPFiles/FileHandlers/InDesign_Handler.cpp
new file mode 100644
index 0000000..55332c0
--- /dev/null
+++ b/source/XMPFiles/FileHandlers/InDesign_Handler.cpp
@@ -0,0 +1,423 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "InDesign_Handler.hpp"
+
+using namespace std;
+
+// =================================================================================================
+/// \file InDesign_Handler.cpp
+/// \brief File format handler for InDesign files.
+///
+/// This header ...
+///
+/// The layout of an InDesign file in terms of the Basic_MetaHandler model is:
+///
+/// \li The front of the file. This is everything up to the XMP contiguous object section. The file
+/// starts with a pair of master pages, followed by the data pages, followed by contiguous object
+/// sections, finished with padding to a page boundary.
+///
+/// \li A prefix for the XMP section. This is the contiguous object header. The offset is
+/// (this->packetInfo.offset - this->xmpPrefixSize).
+///
+/// \li The XMP packet. The offset is this->packetInfo.offset.
+///
+/// \li A suffix for the XMP section. This is the contiguous object header. The offset is
+/// (this->packetInfo.offset + this->packetInfo.length).
+///
+/// \li Trailing file content. This is the contiguous objects that follow the XMP. The offset is
+/// (this->packetInfo.offset + this->packetInfo.length + this->xmpSuffixSize).
+///
+/// \li The back of the file. This is the final padding to a page boundary. The offset is
+/// (this->packetInfo.offset + this->packetInfo.length + this->xmpSuffixSize + this->trailingContentSize).
+///
+// =================================================================================================
+
+// *** Add PutXMP overrides that throw if the file does not contain XMP.
+
+#ifndef TraceInDesignHandler
+ #define TraceInDesignHandler 0
+#endif
+
+enum { kInDesignGUIDSize = 16 };
+
+struct InDesignMasterPage {
+ XMP_Uns8 fGUID [kInDesignGUIDSize];
+ XMP_Uns8 fMagicBytes [8];
+ XMP_Uns8 fObjectStreamEndian;
+ XMP_Uns8 fIrrelevant1 [239];
+ XMP_Uns64 fSequenceNumber;
+ XMP_Uns8 fIrrelevant2 [8];
+ XMP_Uns32 fFilePages;
+ XMP_Uns8 fIrrelevant3 [3812];
+};
+
+enum {
+ kINDD_PageSize = 4096,
+ kINDD_PageMask = (kINDD_PageSize - 1),
+ kINDD_LittleEndian = 1,
+ kINDD_BigEndian = 2 };
+
+struct InDesignContigObjMarker {
+ XMP_Uns8 fGUID [kInDesignGUIDSize];
+ XMP_Uns32 fObjectUID;
+ XMP_Uns32 fObjectClassID;
+ XMP_Uns32 fStreamLength;
+ XMP_Uns32 fChecksum;
+};
+
+static const XMP_Uns8 * kINDD_MasterPageGUID =
+ (const XMP_Uns8 *) "\x06\x06\xED\xF5\xD8\x1D\x46\xE5\xBD\x31\xEF\xE7\xFE\x74\xB7\x1D";
+
+static const XMP_Uns8 * kINDDContigObjHeaderGUID =
+ (const XMP_Uns8 *) "\xDE\x39\x39\x79\x51\x88\x4B\x6C\x8E\x63\xEE\xF8\xAE\xE0\xDD\x38";
+
+static const XMP_Uns8 * kINDDContigObjTrailerGUID =
+ (const XMP_Uns8 *) "\xFD\xCE\xDB\x70\xF7\x86\x4B\x4F\xA4\xD3\xC7\x28\xB3\x41\x71\x06";
+
+// =================================================================================================
+// InDesign_MetaHandlerCTor
+// ========================
+
+XMPFileHandler * InDesign_MetaHandlerCTor ( XMPFiles * parent )
+{
+ return new InDesign_MetaHandler ( parent );
+
+} // InDesign_MetaHandlerCTor
+
+// =================================================================================================
+// InDesign_CheckFormat
+// ====================
+//
+// For InDesign we check that the pair of master pages begin with the 16 byte GUID.
+
+bool InDesign_CheckFormat ( XMP_FileFormat format,
+ XMP_StringPtr filePath,
+ LFA_FileRef fileRef,
+ XMPFiles * parent )
+{
+ IgnoreParam(format); IgnoreParam(filePath); IgnoreParam(parent);
+ XMP_Assert ( format == kXMP_InDesignFile );
+ XMP_Assert ( strlen ( (const char *) kINDD_MasterPageGUID ) == kInDesignGUIDSize );
+
+ enum { kBufferSize = 2*kINDD_PageSize };
+ XMP_Uns8 buffer [kBufferSize];
+
+ XMP_Int64 filePos = 0;
+ XMP_Uns8 * bufPtr = buffer;
+ XMP_Uns8 * bufLimit = bufPtr + kBufferSize;
+
+ LFA_Seek ( fileRef, 0, SEEK_SET );
+ size_t bufLen = LFA_Read ( fileRef, buffer, kBufferSize );
+ if ( bufLen != kBufferSize ) return false;
+
+ if ( ! CheckBytes ( bufPtr, kINDD_MasterPageGUID, kInDesignGUIDSize ) ) return false;
+ if ( ! CheckBytes ( bufPtr+kINDD_PageSize, kINDD_MasterPageGUID, kInDesignGUIDSize ) ) return false;
+
+ return true;
+
+} // InDesign_CheckFormat
+
+// =================================================================================================
+// InDesign_MetaHandler::InDesign_MetaHandler
+// ==========================================
+
+InDesign_MetaHandler::InDesign_MetaHandler ( XMPFiles * _parent ) : streamBigEndian(0), xmpObjID(0), xmpClassID(0)
+{
+ this->parent = _parent;
+ this->handlerFlags = kInDesign_HandlerFlags;
+ this->stdCharForm = kXMP_Char8Bit;
+
+} // InDesign_MetaHandler::InDesign_MetaHandler
+
+// =================================================================================================
+// InDesign_MetaHandler::~InDesign_MetaHandler
+// ===========================================
+
+InDesign_MetaHandler::~InDesign_MetaHandler()
+{
+ // Nothing to do here.
+
+} // InDesign_MetaHandler::~InDesign_MetaHandler
+
+// =================================================================================================
+// InDesign_MetaHandler::CacheFileData
+// ===================================
+//
+// Look for the XMP in an InDesign database file. This is a paged database using 4K byte pages,
+// followed by redundant "contiguous object streams". Each contiguous object stream is a copy of a
+// database object stored as a contiguous byte stream. The XMP that we want is one of these.
+//
+// The first 2 pages of the database are alternating master pages. A generation number is used to
+// select the active master page. The master page contains an offset to the start of the contiguous
+// object streams. Each of the contiguous object streams contains a header and trailer, allowing
+// fast motion from one stream to the next.
+//
+// There is no unique "what am I" tagging to the contiguous object streams, so we simply pick the
+// first one that looks right. At present this is a 4 byte little endian packet size followed by the
+// packet.
+
+// ! Note that insertion of XMP is not allowed for InDesign, the XMP must be a contiguous copy of an
+// ! internal database object. So we don't set the packet offset to an insertion point if not found.
+
+void InDesign_MetaHandler::CacheFileData()
+{
+ LFA_FileRef fileRef = this->parent->fileRef;
+ XMP_PacketInfo & packetInfo = this->packetInfo;
+
+ IOBuffer ioBuf;
+ size_t dbPages;
+ XMP_Uns8 cobjEndian;
+
+ XMP_AbortProc abortProc = this->parent->abortProc;
+ void * abortArg = this->parent->abortArg;
+ const bool checkAbort = (abortProc != 0);
+
+ XMP_Assert ( kINDD_PageSize == sizeof(InDesignMasterPage) );
+ XMP_Assert ( kIOBufferSize >= (2 * kINDD_PageSize) );
+
+ this->containsXMP = false;
+
+ // ---------------------------------------------------------------------------------
+ // Figure out which master page is active and seek to the contiguous object portion.
+
+ {
+ ioBuf.filePos = 0;
+ ioBuf.ptr = ioBuf.limit; // Make sure RefillBuffer does a simple read.
+ LFA_Seek ( fileRef, ioBuf.filePos, SEEK_SET );
+ RefillBuffer ( fileRef, &ioBuf );
+ if ( ioBuf.len < (2 * kINDD_PageSize) ) XMP_Throw ( "GetMainPacket/ScanInDesignFile: Read failure", kXMPErr_ExternalFailure );
+
+ InDesignMasterPage * masters = (InDesignMasterPage *) ioBuf.ptr;
+ XMP_Uns64 seq0 = GetUns64LE ( (XMP_Uns8 *) &masters[0].fSequenceNumber );
+ XMP_Uns64 seq1 = GetUns64LE ( (XMP_Uns8 *) &masters[1].fSequenceNumber );
+
+ dbPages = GetUns32LE ( (XMP_Uns8 *) &masters[0].fFilePages );
+ cobjEndian = masters[0].fObjectStreamEndian;
+ if ( seq1 > seq0 ) {
+ dbPages = GetUns32LE ( (XMP_Uns8 *) &masters[1].fFilePages );
+ cobjEndian = masters[1].fObjectStreamEndian;
+ }
+ }
+
+ XMP_Assert ( ! this->streamBigEndian );
+ if ( cobjEndian == kINDD_BigEndian ) this->streamBigEndian = true;
+
+ // ---------------------------------------------------------------------------------------------
+ // Look for the XMP contiguous object stream. Most of the time there will be just one stream and
+ // it will be the XMP. So we might as well fill the whole buffer and not worry about reading too
+ // much and seeking back to the start of the following stream.
+
+ XMP_Int64 cobjPos = (XMP_Int64)dbPages * kINDD_PageSize; // ! Use a 64 bit multiply!
+ XMP_Uns32 streamLength = (XMP_Uns32)(-(long)(2*sizeof(InDesignContigObjMarker))); // ! For the first pass in the loop.
+
+ while ( true ) {
+
+ if ( checkAbort && abortProc(abortArg) ) {
+ XMP_Throw ( "InDesign_MetaHandler::LocateXMP - User abort", kXMPErr_UserAbort );
+ }
+
+ // Fetch the start of the next stream and check the contiguous object header.
+ // ! The writeable bit of fObjectClassID is ignored, we use the packet trailer flag.
+
+ cobjPos += streamLength + (2 * sizeof(InDesignContigObjMarker));
+ ioBuf.filePos = cobjPos;
+ ioBuf.ptr = ioBuf.limit; // Make sure RefillBuffer does a simple read.
+ LFA_Seek ( fileRef, ioBuf.filePos, SEEK_SET );
+ RefillBuffer ( fileRef, &ioBuf );
+ if ( ioBuf.len < (2 * sizeof(InDesignContigObjMarker)) ) break; // Too small, must be end of file.
+
+ const InDesignContigObjMarker * cobjHeader = (const InDesignContigObjMarker *) ioBuf.ptr;
+ if ( ! CheckBytes ( Uns8Ptr(&cobjHeader->fGUID), kINDDContigObjHeaderGUID, kInDesignGUIDSize ) ) break; // Not a contiguous object header.
+ this->xmpObjID = cobjHeader->fObjectUID; // Save these now while the buffer is good.
+ this->xmpClassID = cobjHeader->fObjectClassID;
+ streamLength = GetUns32LE ( (XMP_Uns8 *) &cobjHeader->fStreamLength );
+ ioBuf.ptr += sizeof ( InDesignContigObjMarker );
+
+ // See if this is the XMP stream. Only check for UTF-8, others get caught in fallback scanning.
+
+ if ( ! CheckFileSpace ( fileRef, &ioBuf, 4 ) ) continue; // Too small, can't possibly be XMP.
+
+ XMP_Uns32 innerLength = GetUns32LE ( ioBuf.ptr );
+ if ( this->streamBigEndian ) innerLength = GetUns32BE ( ioBuf.ptr );
+ if ( innerLength != (streamLength - 4) ) continue; // Not legit XMP.
+ ioBuf.ptr += 4;
+
+ if ( ! CheckFileSpace ( fileRef, &ioBuf, kUTF8_PacketHeaderLen ) ) continue; // Too small, can't possibly be XMP.
+
+ if ( ! CheckBytes ( ioBuf.ptr, kUTF8_PacketStart, strlen((char*)kUTF8_PacketStart) ) ) continue;
+ ioBuf.ptr += strlen((char*)kUTF8_PacketStart);
+
+ XMP_Uns8 quote = *ioBuf.ptr;
+ if ( (quote != '\'') && (quote != '"') ) continue;
+ ioBuf.ptr += 1;
+ if ( *ioBuf.ptr != quote ) {
+ if ( ! CheckBytes ( ioBuf.ptr, Uns8Ptr("\xEF\xBB\xBF"), 3 ) ) continue;
+ ioBuf.ptr += 3;
+ }
+ if ( *ioBuf.ptr != quote ) continue;
+ ioBuf.ptr += 1;
+
+ if ( ! CheckBytes ( ioBuf.ptr, Uns8Ptr(" id="), 4 ) ) continue;
+ ioBuf.ptr += 4;
+ quote = *ioBuf.ptr;
+ if ( (quote != '\'') && (quote != '"') ) continue;
+ ioBuf.ptr += 1;
+ if ( ! CheckBytes ( ioBuf.ptr, kUTF8_PacketID, strlen((char*)kUTF8_PacketID) ) ) continue;
+ ioBuf.ptr += strlen((char*)kUTF8_PacketID);
+ if ( *ioBuf.ptr != quote ) continue;
+ ioBuf.ptr += 1;
+
+ // We've seen enough, it is the XMP. To fit the Basic_Handler model we need to compute the
+ // total size of remaining contiguous objects, the trailingContentSize.
+
+ this->xmpPrefixSize = sizeof(InDesignContigObjMarker) + 4;
+ this->xmpSuffixSize = sizeof(InDesignContigObjMarker);
+ packetInfo.offset = cobjPos + this->xmpPrefixSize;
+ packetInfo.length = innerLength;
+
+
+ XMP_Int64 tcStart = cobjPos + streamLength + (2 * sizeof(InDesignContigObjMarker));
+ while ( true ) {
+ if ( checkAbort && abortProc(abortArg) ) {
+ XMP_Throw ( "InDesign_MetaHandler::LocateXMP - User abort", kXMPErr_UserAbort );
+ }
+ cobjPos += streamLength + (2 * sizeof(InDesignContigObjMarker));
+ ioBuf.filePos = cobjPos;
+ ioBuf.ptr = ioBuf.limit; // Make sure RefillBuffer does a simple read.
+ LFA_Seek ( fileRef, ioBuf.filePos, SEEK_SET );
+ RefillBuffer ( fileRef, &ioBuf );
+ if ( ioBuf.len < sizeof(InDesignContigObjMarker) ) break; // Too small, must be end of file.
+ cobjHeader = (const InDesignContigObjMarker *) ioBuf.ptr;
+ if ( ! CheckBytes ( Uns8Ptr(&cobjHeader->fGUID), kINDDContigObjHeaderGUID, kInDesignGUIDSize ) ) break; // Not a contiguous object header.
+ streamLength = GetUns32LE ( (XMP_Uns8 *) &cobjHeader->fStreamLength );
+ }
+ this->trailingContentSize = cobjPos - tcStart;
+
+ #if TraceInDesignHandler
+ XMP_Uns32 pktOffset = (XMP_Uns32)this->packetInfo.offset;
+ printf ( "Found XMP in InDesign file, offsets:\n" );
+ printf ( " CObj head %X, XMP %X, CObj tail %X, file tail %X, padding %X\n",
+ (pktOffset - this->xmpPrefixSize), pktOffset, (pktOffset + this->packetInfo.length),
+ (pktOffset + this->packetInfo.length + this->xmpSuffixSize),
+ (pktOffset + this->packetInfo.length + this->xmpSuffixSize + (XMP_Uns32)this->trailingContentSize) );
+ #endif
+
+ this->containsXMP = true;
+ break;
+
+ }
+
+ if ( this->containsXMP ) {
+ this->xmpFileOffset = packetInfo.offset;
+ this->xmpFileSize = packetInfo.length;
+ ReadXMPPacket ( this );
+ }
+
+} // InDesign_MetaHandler::CacheFileData
+
+// =================================================================================================
+// InDesign_MetaHandler::WriteXMPPrefix
+// ====================================
+
+void InDesign_MetaHandler::WriteXMPPrefix()
+{
+ // Write the contiguous object header and the 4 byte length of the XMP packet.
+
+ LFA_FileRef fileRef = this->parent->fileRef;
+ XMP_PacketInfo & packetInfo = this->packetInfo;
+
+ InDesignContigObjMarker header;
+ memcpy ( header.fGUID, kINDDContigObjHeaderGUID, sizeof(header.fGUID) ); // AUDIT: Use of dest sizeof for length is safe.
+ header.fObjectUID = this->xmpObjID;
+ header.fObjectClassID = this->xmpClassID;
+ header.fStreamLength = MakeUns32LE ( 4 + packetInfo.length );
+ header.fChecksum = (XMP_Uns32)(-1);
+ LFA_Write ( fileRef, &header, sizeof(header) );
+
+ XMP_Uns32 pktLength = MakeUns32LE ( packetInfo.length );
+ if ( this->streamBigEndian ) pktLength = MakeUns32BE ( packetInfo.length );
+ LFA_Write ( fileRef, &pktLength, sizeof(pktLength) );
+
+} // InDesign_MetaHandler::WriteXMPPrefix
+
+// =================================================================================================
+// InDesign_MetaHandler::WriteXMPSuffix
+// ====================================
+
+void InDesign_MetaHandler::WriteXMPSuffix()
+{
+ // Write the contiguous object trailer.
+
+ LFA_FileRef fileRef = this->parent->fileRef;
+ XMP_PacketInfo & packetInfo = this->packetInfo;
+
+ InDesignContigObjMarker trailer;
+
+ memcpy ( trailer.fGUID, kINDDContigObjTrailerGUID, sizeof(trailer.fGUID) ); // AUDIT: Use of dest sizeof for length is safe.
+ trailer.fObjectUID = this->xmpObjID;
+ trailer.fObjectClassID = this->xmpClassID;
+ trailer.fStreamLength = MakeUns32LE ( 4 + packetInfo.length );
+ trailer.fChecksum = (XMP_Uns32)(-1);
+
+ LFA_Write ( fileRef, &trailer, sizeof(trailer) );
+
+} // InDesign_MetaHandler::WriteXMPSuffix
+
+// =================================================================================================
+// InDesign_MetaHandler::NoteXMPRemoval
+// ====================================
+
+void InDesign_MetaHandler::NoteXMPRemoval()
+{
+ // Nothing to do.
+
+} // InDesign_MetaHandler::NoteXMPRemoval
+
+// =================================================================================================
+// InDesign_MetaHandler::NoteXMPInsertion
+// ======================================
+
+void InDesign_MetaHandler::NoteXMPInsertion()
+{
+ // Nothing to do.
+
+} // InDesign_MetaHandler::NoteXMPInsertion
+
+// =================================================================================================
+// InDesign_MetaHandler::CaptureFileEnding
+// =======================================
+
+void InDesign_MetaHandler::CaptureFileEnding()
+{
+ // Nothing to do. The back of an InDesign file is the final zero padding.
+
+} // InDesign_MetaHandler::CaptureFileEnding
+
+// =================================================================================================
+// InDesign_MetaHandler::RestoreFileEnding
+// =======================================
+
+void InDesign_MetaHandler::RestoreFileEnding()
+{
+ // Pad the file with zeros to a page boundary.
+
+ LFA_FileRef fileRef = this->parent->fileRef;
+ XMP_PacketInfo & packetInfo = this->packetInfo;
+
+ XMP_Int64 dataLength = LFA_Measure ( fileRef );
+ XMP_Int32 padLength = (kINDD_PageSize - ((XMP_Int32)dataLength & kINDD_PageMask)) & kINDD_PageMask;
+
+ XMP_Uns8 buffer [kINDD_PageSize];
+ memset ( buffer, 0, kINDD_PageSize );
+ LFA_Write ( fileRef, buffer, padLength );
+
+} // InDesign_MetaHandler::RestoreFileEnding
+
+// =================================================================================================
diff --git a/source/XMPFiles/FileHandlers/InDesign_Handler.hpp b/source/XMPFiles/FileHandlers/InDesign_Handler.hpp
new file mode 100644
index 0000000..bed1851
--- /dev/null
+++ b/source/XMPFiles/FileHandlers/InDesign_Handler.hpp
@@ -0,0 +1,60 @@
+#ifndef __InDesign_Handler_hpp__
+#define __InDesign_Handler_hpp__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "Basic_Handler.hpp"
+
+// =================================================================================================
+/// \file InDesign_Handler.hpp
+/// \brief File format handler for InDesign files.
+///
+/// This header ...
+///
+// =================================================================================================
+
+extern XMPFileHandler * InDesign_MetaHandlerCTor ( XMPFiles * parent );
+
+extern bool InDesign_CheckFormat ( XMP_FileFormat format,
+ XMP_StringPtr filePath,
+ LFA_FileRef fileRef,
+ XMPFiles * parent );
+
+static const XMP_OptionBits kInDesign_HandlerFlags = kBasic_HandlerFlags & (~kXMPFiles_CanInjectXMP); // ! InDesign can't inject.
+
+class InDesign_MetaHandler : public Basic_MetaHandler
+{
+public:
+
+ InDesign_MetaHandler ( XMPFiles * parent );
+ ~InDesign_MetaHandler();
+
+ void CacheFileData();
+
+protected:
+
+ void WriteXMPPrefix();
+ void WriteXMPSuffix();
+
+ void NoteXMPRemoval();
+ void NoteXMPInsertion();
+
+ void CaptureFileEnding();
+ void RestoreFileEnding();
+
+ bool streamBigEndian; // Set from master page's fObjectStreamEndian.
+ XMP_Uns32 xmpObjID; // Set from contiguous object's fObjectID, still as little endian.
+ XMP_Uns32 xmpClassID; // Set from contiguous object's fObjectClassID, still as little endian.
+
+}; // InDesign_MetaHandler
+
+// =================================================================================================
+
+#endif /* __InDesign_Handler_hpp__ */
diff --git a/source/XMPFiles/FileHandlers/JPEG_Handler.cpp b/source/XMPFiles/FileHandlers/JPEG_Handler.cpp
new file mode 100644
index 0000000..e57c83f
--- /dev/null
+++ b/source/XMPFiles/FileHandlers/JPEG_Handler.cpp
@@ -0,0 +1,997 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "JPEG_Handler.hpp"
+
+#include "TIFF_Support.hpp"
+#include "PSIR_Support.hpp"
+#include "IPTC_Support.hpp"
+#include "ReconcileLegacy.hpp"
+
+#include "MD5.h"
+
+using namespace std;
+
+// =================================================================================================
+/// \file JPEG_Handler.cpp
+/// \brief File format handler for JPEG.
+///
+/// This handler ...
+///
+// =================================================================================================
+
+static const char * kExifSignatureString = "Exif\0\x00";
+static const char * kExifSignatureAltStr = "Exif\0\xFF";
+static const size_t kExifSignatureLength = 6;
+static const size_t kExifMaxDataLength = 0xFFFF - 2 - kExifSignatureLength;
+
+static const char * kPSIRSignatureString = "Photoshop 3.0\0";
+static const size_t kPSIRSignatureLength = 14;
+static const size_t kPSIRMaxDataLength = 0xFFFF - 2 - kPSIRSignatureLength;
+
+static const char * kMainXMPSignatureString = "http://ns.adobe.com/xap/1.0/\0";
+static const size_t kMainXMPSignatureLength = 29;
+
+static const char * kExtXMPSignatureString = "http://ns.adobe.com/xmp/extension/\0";
+static const size_t kExtXMPSignatureLength = 35;
+static const size_t kExtXMPPrefixLength = kExtXMPSignatureLength + 32 + 4 + 4;
+
+typedef std::map < XMP_Uns32 /* offset */, std::string /* portion */ > ExtXMPPortions;
+
+struct ExtXMPContent {
+ XMP_Uns32 length;
+ ExtXMPPortions portions;
+ ExtXMPContent() : length(0) {};
+ ExtXMPContent ( XMP_Uns32 _length ) : length(_length) {};
+};
+
+typedef std::map < JPEG_MetaHandler::GUID_32 /* guid */, ExtXMPContent /* content */ > ExtendedXMPInfo;
+
+#ifndef Trace_UnlimitedJPEG
+ #define Trace_UnlimitedJPEG 0
+#endif
+
+// =================================================================================================
+// JPEG_MetaHandlerCTor
+// ====================
+
+XMPFileHandler * JPEG_MetaHandlerCTor ( XMPFiles * parent )
+{
+ return new JPEG_MetaHandler ( parent );
+
+} // JPEG_MetaHandlerCTor
+
+// =================================================================================================
+// JPEG_CheckFormat
+// ================
+
+// For JPEG we just check for the initial SOI standalone marker followed by any of the other markers
+// that might, well, follow it. A more aggressive check might be to read 4KB then check for legit
+// marker segments within that portion. Probably won't buy much, and thrashes the dCache more. We
+// tolerate only a small amount of 0xFF padding between the SOI and following marker. This formally
+// violates the rules of JPEG, but in practice there won't be any padding anyway.
+//
+// ! The CheckXyzFormat routines don't track the filePos, that is left to ScanXyzFile.
+
+bool JPEG_CheckFormat ( XMP_FileFormat format,
+ XMP_StringPtr filePath,
+ LFA_FileRef fileRef,
+ XMPFiles * parent )
+{
+ IgnoreParam(format); IgnoreParam(filePath); IgnoreParam(parent);
+ XMP_Assert ( format == kXMP_JPEGFile );
+
+ IOBuffer ioBuf;
+
+ LFA_Seek ( fileRef, 0, SEEK_SET );
+ if ( ! CheckFileSpace ( fileRef, &ioBuf, 4 ) ) return false; // We need at least 4, the buffer is filled anyway.
+
+ // First look for the SOI standalone marker. Then skip all 0xFF bytes, padding plus the high
+ // order byte of the next marker. Finally see if the next marker is legit.
+
+ if ( ! CheckBytes ( ioBuf.ptr, "\xFF\xD8", 2 ) ) return false;
+ ioBuf.ptr += 2; // Move past the SOI.
+ while ( (ioBuf.ptr < ioBuf.limit) && (*ioBuf.ptr == 0xFF) ) ++ioBuf.ptr;
+ if ( ioBuf.ptr == ioBuf.limit ) return false;
+
+ XMP_Uns8 id = *ioBuf.ptr;
+ if ( id >= 0xDD ) return true; // The most probable cases.
+ if ( (id < 0xC0) || ((id & 0xF8) == 0xD0) || (id == 0xD8) || (id == 0xDA) || (id == 0xDC) ) return false;
+ return true;
+
+} // JPEG_CheckFormat
+
+// =================================================================================================
+// JPEG_MetaHandler::JPEG_MetaHandler
+// ==================================
+
+JPEG_MetaHandler::JPEG_MetaHandler ( XMPFiles * _parent )
+ : exifMgr(0), psirMgr(0), iptcMgr(0), skipReconcile(false)
+{
+ this->parent = _parent;
+ this->handlerFlags = kJPEG_HandlerFlags;
+ this->stdCharForm = kXMP_Char8Bit;
+
+} // JPEG_MetaHandler::JPEG_MetaHandler
+
+// =================================================================================================
+// JPEG_MetaHandler::~JPEG_MetaHandler
+// ===================================
+
+JPEG_MetaHandler::~JPEG_MetaHandler()
+{
+
+ if ( exifMgr != 0 ) delete ( exifMgr );
+ if ( psirMgr != 0 ) delete ( psirMgr );
+ if ( iptcMgr != 0 ) delete ( iptcMgr );
+
+} // JPEG_MetaHandler::~JPEG_MetaHandler
+
+// =================================================================================================
+// TableOrDataMarker
+// =================
+//
+// Returns true if the marker is for a table or data marker segment:
+// FFC4 - DHT
+// FFCC - DAC
+// FFDB - DQT
+// FFDC - DNL
+// FFDD - DRI
+// FFDE - DHP
+// FFDF - EXP
+// FFEn - APPn
+// FFFE - COM
+
+static inline bool TableOrDataMarker ( XMP_Uns16 marker )
+{
+
+ if ( (marker & 0xFFF0) == 0xFFE0 ) return true; // APPn is probably the most common case.
+
+ if ( marker < 0xFFC4 ) return false;
+ if ( marker == 0xFFC4 ) return true;
+
+ if ( marker < 0xFFCC ) return false;
+ if ( marker == 0xFFCC ) return true;
+
+ if ( marker < 0xFFDB ) return false;
+ if ( marker <= 0xFFDF ) return true;
+
+ if ( marker < 0xFFFE ) return false;
+ if ( marker == 0xFFFE ) return true;
+
+ return false;
+
+} // TableOrDataMarker
+
+// =================================================================================================
+// JPEG_MetaHandler::CacheFileData
+// ===============================
+//
+// Look for the Exif metadata, Photoshop image resources, and XMP in a JPEG (JFIF) file. The native
+// thumbnail is inside the Exif. The general layout of a JPEG file is:
+// SOI marker, 2 bytes, 0xFFD8
+// Marker segments for tables and metadata
+// SOFn marker segment
+// Image data
+// EOI marker, 2 bytes, 0xFFD9
+//
+// Each marker segment begins with a 2 byte big endian marker and a 2 byte big endian length. The
+// length includes the 2 bytes of the length field but not the marker. The high order byte of a
+// marker is 0xFF, the low order byte tells what kind of marker. A marker can be preceeded by any
+// number of 0xFF fill bytes, however there are no alignment constraints.
+//
+// There are virtually no constraints on the order of the marker segments before the SOFn. A reader
+// must be prepared to handle any order.
+//
+// The Exif metadata is in an APP1 marker segment with a 6 byte signature string of "Exif\0\0" at
+// the start of the data. The rest of the data is a TIFF stream.
+//
+// The Photoshop image resources are in an APP13 marker segment with a 14 byte signature string of
+// "Photoshop 3.0\0". The rest of the data is a sequence of image resources.
+//
+// The main XMP is in an APP1 marker segment with a 29 byte signature string of
+// "http://ns.adobe.com/xap/1.0/\0". The rest of the data is the serialized XMP packet. This is the
+// only XMP if everything fits within the 64KB limit for marker segment data. If not, there will be
+// a series of XMP extension segments.
+//
+// Each XMP extension segment is an APP1 marker segment whose data contains:
+// - A 35 byte signature string of "http://ns.adobe.com/xmp/extension/\0".
+// - A 128 bit GUID stored as 32 ASCII hex digits, capital A-F, no nul termination.
+// - A 32 bit unsigned integer length for the full extended XMP serialization.
+// - A 32 bit unsigned integer offset for this portion of the extended XMP serialization.
+// - A portion of the extended XMP serialization, up to about 65400 bytes (at most 65458).
+//
+// A reader must be prepared to encounter the extended XMP portions out of order. Also to encounter
+// defective files that have differing extended XMP according to the GUID. The main XMP contains the
+// GUID for the associated extended XMP.
+
+// *** This implementation simply returns when invalid JPEG is encountered. Should we throw instead?
+
+void JPEG_MetaHandler::CacheFileData()
+{
+ LFA_FileRef fileRef = this->parent->fileRef;
+ XMP_PacketInfo & packetInfo = this->packetInfo;
+
+ size_t segLen;
+ bool ok;
+ IOBuffer ioBuf;
+
+ XMP_AbortProc abortProc = this->parent->abortProc;
+ void * abortArg = this->parent->abortArg;
+ const bool checkAbort = (abortProc != 0);
+
+ ExtendedXMPInfo extXMP;
+
+ XMP_Assert ( (! this->containsXMP) && (! this->containsTNail) );
+ // Set containsXMP to true here only if the standard XMP packet is found.
+
+ XMP_Assert ( kPSIRSignatureLength == (strlen(kPSIRSignatureString) + 1) );
+ XMP_Assert ( kMainXMPSignatureLength == (strlen(kMainXMPSignatureString) + 1) );
+ XMP_Assert ( kExtXMPSignatureLength == (strlen(kExtXMPSignatureString) + 1) );
+
+ // -------------------------------------------------------------------------------------------
+ // Look for any of the Exif, PSIR, main XMP, or extended XMP marker segments. Quit when we hit
+ // an SOFn, EOI, or invalid/unexpected marker.
+
+ LFA_Seek ( fileRef, 2, SEEK_SET ); // Skip the SOI. The JPEG header has already been verified.
+ ioBuf.filePos = 2;
+ RefillBuffer ( fileRef, &ioBuf );
+
+ while ( true ) {
+
+ if ( checkAbort && abortProc(abortArg) ) {
+ XMP_Throw ( "JPEG_MetaHandler::CacheFileData - User abort", kXMPErr_UserAbort );
+ }
+
+ if ( ! CheckFileSpace ( fileRef, &ioBuf, 2 ) ) return;
+
+ if ( *ioBuf.ptr != 0xFF ) return; // All valid markers have a high byte of 0xFF.
+ while ( *ioBuf.ptr == 0xFF ) { // Skip padding 0xFF bytes and the marker's high byte.
+ ++ioBuf.ptr;
+ if ( ! CheckFileSpace ( fileRef, &ioBuf, 1 ) ) return;
+ }
+
+ XMP_Uns16 marker = 0xFF00 + *ioBuf.ptr;
+
+ if ( marker == 0xFFED ) {
+
+ // This is an APP13 marker, is it the Photoshop image resources?
+
+ ++ioBuf.ptr; // Move ioBuf.ptr to the marker segment length field.
+ if ( ! CheckFileSpace ( fileRef, &ioBuf, 2 ) ) return;
+
+ segLen = GetUns16BE ( ioBuf.ptr );
+ if ( segLen < 2 ) return; // Invalid JPEG.
+
+ ioBuf.ptr += 2; // Move ioBuf.ptr to the marker segment content.
+ segLen -= 2; // Adjust segLen to count just the content portion.
+
+ ok = CheckFileSpace ( fileRef, &ioBuf, kPSIRSignatureLength );
+ if ( ok && (segLen >= kPSIRSignatureLength) &&
+ CheckBytes ( ioBuf.ptr, kPSIRSignatureString, kPSIRSignatureLength ) ) {
+
+ // This is the Photoshop image resources, cache the contents.
+
+ ioBuf.ptr += kPSIRSignatureLength; // Move ioBuf.ptr to the image resources.
+ segLen -= kPSIRSignatureLength; // Adjust segLen to count just the image resources.
+ ok = CheckFileSpace ( fileRef, &ioBuf, segLen ); // Buffer the full content portion.
+ if ( ! ok ) return; // Must be a truncated file.
+
+ this->psirContents.assign ( (XMP_StringPtr)ioBuf.ptr, segLen );
+ ioBuf.ptr += segLen;
+
+ } else {
+
+ // This is the not Photoshop image resources, skip the marker segment's content.
+
+ if ( segLen <= size_t(ioBuf.limit - ioBuf.ptr) ) {
+ ioBuf.ptr += segLen; // The next marker is in this buffer.
+ } else {
+ // The next marker is beyond this buffer, RefillBuffer assumes we're doing sequential reads.
+ size_t skipCount = segLen - (ioBuf.limit - ioBuf.ptr); // The amount to move beyond this buffer.
+ ioBuf.filePos = LFA_Seek ( fileRef, skipCount, SEEK_CUR );
+ ioBuf.ptr = ioBuf.limit; // No data left in the buffer.
+ }
+
+ }
+
+ continue; // Move on to the next marker.
+
+ } else if ( marker == 0xFFE1 ) {
+
+ // This is an APP1 marker, is it the Exif, main XMP, or extended XMP?
+ // ! Check in that order, which happens to be increasing signature string length.
+
+ ++ioBuf.ptr; // Move ioBuf.ptr to the marker segment length field.
+ if ( ! CheckFileSpace ( fileRef, &ioBuf, 2 ) ) return;
+
+ segLen = GetUns16BE ( ioBuf.ptr );
+ if ( segLen < 2 ) return; // Invalid JPEG.
+
+ ioBuf.ptr += 2; // Move ioBuf.ptr to the marker segment content.
+ segLen -= 2; // Adjust segLen to count just the content portion.
+
+ // Check for the Exif APP1 marker segment.
+
+ ok = CheckFileSpace ( fileRef, &ioBuf, kExifSignatureLength );
+ if ( ok && (segLen >= kExifSignatureLength) &&
+ (CheckBytes ( ioBuf.ptr, kExifSignatureString, kExifSignatureLength ) ||
+ CheckBytes ( ioBuf.ptr, kExifSignatureAltStr, kExifSignatureLength )) ) {
+
+ // This is the Exif metadata, cache the contents.
+
+ ioBuf.ptr += kExifSignatureLength; // Move ioBuf.ptr to the TIFF stream.
+ segLen -= kExifSignatureLength; // Adjust segLen to count just the TIFF stream.
+ ok = CheckFileSpace ( fileRef, &ioBuf, segLen ); // Buffer the full content portion.
+ if ( ! ok ) return; // Must be a truncated file.
+
+ this->exifContents.assign ( (XMP_StringPtr)ioBuf.ptr, segLen );
+ ioBuf.ptr += segLen;
+
+ continue; // Move on to the next marker.
+
+ }
+
+ // Check for the main XMP APP1 marker segment.
+
+ ok = CheckFileSpace ( fileRef, &ioBuf, kMainXMPSignatureLength );
+ if ( ok && (segLen >= kMainXMPSignatureLength) &&
+ CheckBytes ( ioBuf.ptr, kMainXMPSignatureString, kMainXMPSignatureLength ) ) {
+
+ // This is the main XMP, cache the contents.
+
+ ioBuf.ptr += kMainXMPSignatureLength; // Move ioBuf.ptr to the XMP Packet.
+ segLen -= kMainXMPSignatureLength; // Adjust segLen to count just the XMP Packet.
+ ok = CheckFileSpace ( fileRef, &ioBuf, segLen ); // Buffer the full content portion.
+ if ( ! ok ) return; // Must be a truncated file.
+
+ this->packetInfo.offset = ioBuf.filePos + (ioBuf.ptr - &ioBuf.data[0]);
+ this->packetInfo.length = segLen;
+ this->packetInfo.padSize = 0; // Assume for now, set these properly in ProcessXMP.
+ this->packetInfo.charForm = kXMP_CharUnknown;
+ this->packetInfo.writeable = true;
+
+ this->xmpPacket.assign ( (XMP_StringPtr)ioBuf.ptr, segLen );
+ ioBuf.ptr += segLen; // ! Set this->packetInfo.offset first!
+
+ this->containsXMP = true; // Found the standard XMP packet.
+ continue; // Move on to the next marker.
+
+ }
+
+ // Check for an extension XMP APP1 marker segment.
+
+ ok = CheckFileSpace ( fileRef, &ioBuf, kExtXMPPrefixLength ); // ! The signature, GUID, length, and offset.
+ if ( ok && (segLen >= kExtXMPPrefixLength) &&
+ CheckBytes ( ioBuf.ptr, kExtXMPSignatureString, kExtXMPSignatureLength ) ) {
+
+ // This is a portion of the extended XMP, cache the contents. This is complicated by
+ // the need to tolerate files where the extension portions are not in order. The
+ // local ExtendedXMPInfo map uses the GUID as the key and maps that to a struct that
+ // has the full length and a map of the known portions. This known portion map uses
+ // the offset of the portion as the key and maps that to a string. Only fully seen
+ // extended XMP streams are kept, the right one gets picked in ProcessXMP.
+
+ segLen -= kExtXMPPrefixLength; // Adjust segLen to count just the XMP stream portion.
+
+ ioBuf.ptr += kExtXMPSignatureLength; // Move ioBuf.ptr to the GUID.
+ GUID_32 guid;
+ XMP_Assert ( sizeof(guid.data) == 32 );
+ memcpy ( &guid.data[0], ioBuf.ptr, sizeof(guid.data) ); // AUDIT: Use of sizeof(guid.data) is safe.
+
+ ioBuf.ptr += 32; // Move ioBuf.ptr to the length and offset.
+ XMP_Uns32 fullLen = GetUns32BE ( ioBuf.ptr );
+ XMP_Uns32 offset = GetUns32BE ( ioBuf.ptr+4 );
+
+ ioBuf.ptr += 8; // Move ioBuf.ptr to the XMP stream portion.
+
+ #if Trace_UnlimitedJPEG
+ printf ( "New extended XMP portion: fullLen %d, offset %d, GUID %.32s\n", fullLen, offset, guid.data );
+ #endif
+
+ // Find the ExtXMPContent for this GUID, and the string for this portion's offset.
+
+ ExtendedXMPInfo::iterator guidPos = extXMP.find ( guid );
+ if ( guidPos == extXMP.end() ) {
+ ExtXMPContent newExtContent ( fullLen );
+ guidPos = extXMP.insert ( extXMP.begin(), ExtendedXMPInfo::value_type ( guid, newExtContent ) );
+ }
+
+ ExtXMPPortions::iterator offsetPos;
+ ExtXMPContent & extContent = guidPos->second;
+
+ if ( extContent.portions.empty() ) {
+ // When new create a full size offset 0 string, to which all in-order portions will get appended.
+ offsetPos = extContent.portions.insert ( extContent.portions.begin(),
+ ExtXMPPortions::value_type ( 0, std::string() ) );
+ offsetPos->second.reserve ( extContent.length );
+ }
+
+ // Try to append this portion to a logically contiguous preceeding one.
+
+ if ( offset == 0 ) {
+ offsetPos = extContent.portions.begin();
+ XMP_Assert ( (offsetPos->first == 0) && (offsetPos->second.size() == 0) );
+ } else {
+ offsetPos = extContent.portions.lower_bound ( offset );
+ --offsetPos; // Back up to the portion whose offset is less than the new offset.
+ if ( (offsetPos->first + offsetPos->second.size()) != offset ) {
+ // Can't append, create a new portion.
+ offsetPos = extContent.portions.insert ( extContent.portions.begin(),
+ ExtXMPPortions::value_type ( offset, std::string() ) );
+ }
+ }
+
+ // Cache this portion of the extended XMP.
+
+ std::string & extPortion = offsetPos->second;
+ ok = CheckFileSpace ( fileRef, &ioBuf, segLen ); // Buffer the full content portion.
+ if ( ! ok ) return; // Must be a truncated file.
+ extPortion.append ( (XMP_StringPtr)ioBuf.ptr, segLen );
+ ioBuf.ptr += segLen;
+
+ continue; // Move on to the next marker.
+
+ }
+
+ // If we get here this is some other uninteresting APP1 marker segment, skip it.
+
+ if ( segLen <= size_t(ioBuf.limit - ioBuf.ptr) ) {
+ ioBuf.ptr += segLen; // The next marker is in this buffer.
+ } else {
+ // The next marker is beyond this buffer, RefillBuffer assumes we're doing sequential reads.
+ size_t skipCount = segLen - (ioBuf.limit - ioBuf.ptr); // The amount to move beyond this buffer.
+ ioBuf.filePos = LFA_Seek ( fileRef, skipCount, SEEK_CUR );
+ ioBuf.ptr = ioBuf.limit; // No data left in the buffer.
+ }
+
+ } else if ( TableOrDataMarker ( marker ) ) {
+
+ // This is a non-terminating but uninteresting marker segment. Skip it.
+
+ ++ioBuf.ptr; // Move ioBuf.ptr to the marker segment length field.
+ if ( ! CheckFileSpace ( fileRef, &ioBuf, 2 ) ) return;
+
+ segLen = GetUns16BE ( ioBuf.ptr ); // Remember that the length includes itself.
+ if ( segLen < 2 ) return; // Invalid JPEG.
+
+ if ( segLen <= size_t(ioBuf.limit - ioBuf.ptr) ) {
+ ioBuf.ptr += segLen; // The next marker is in this buffer.
+ } else {
+ // The next marker is beyond this buffer, RefillBuffer assumes we're doing sequential reads.
+ size_t skipCount = segLen - (ioBuf.limit - ioBuf.ptr); // The amount to move beyond this buffer.
+ ioBuf.filePos = LFA_Seek ( fileRef, skipCount, SEEK_CUR );
+ ioBuf.ptr = ioBuf.limit; // No data left in the buffer.
+ }
+
+ continue; // Move on to the next marker.
+
+ } else {
+
+ break; // This is a terminating marker of some sort.
+
+ }
+
+ }
+
+ if ( ! extXMP.empty() ) {
+
+ // We have extended XMP. Find out which ones are complete, collapse them into a single
+ // string, and save them for ProcessXMP.
+
+ ExtendedXMPInfo::iterator guidPos = extXMP.begin();
+ ExtendedXMPInfo::iterator guidEnd = extXMP.end();
+
+ for ( ; guidPos != guidEnd; ++guidPos ) {
+
+ ExtXMPContent & thisContent = guidPos->second;
+ ExtXMPPortions::iterator partZero = thisContent.portions.begin();
+ ExtXMPPortions::iterator partEnd = thisContent.portions.end();
+ ExtXMPPortions::iterator partPos = partZero;
+
+ #if Trace_UnlimitedJPEG
+ printf ( "Extended XMP portions for GUID %.32s, full length %d\n",
+ guidPos->first.data, guidPos->second.length );
+ printf ( " Offset %d, length %d, next offset %d\n",
+ partZero->first, partZero->second.size(), (partZero->first + partZero->second.size()) );
+ #endif
+
+ for ( ++partPos; partPos != partEnd; ++partPos ) {
+ #if Trace_UnlimitedJPEG
+ printf ( " Offset %d, length %d, next offset %d\n",
+ partPos->first, partPos->second.size(), (partPos->first + partPos->second.size()) );
+ #endif
+ if ( partPos->first != partZero->second.size() ) break; // Quit if not contiguous.
+ partZero->second.append ( partPos->second );
+ }
+
+ if ( (partPos == partEnd) && (partZero->first == 0) && (partZero->second.size() == thisContent.length) ) {
+ // This is a complete extended XMP stream.
+ this->extendedXMP.insert ( ExtendedXMPMap::value_type ( guidPos->first, partZero->second ) );
+ #if Trace_UnlimitedJPEG
+ printf ( "Full extended XMP for GUID %.32s, full length %d\n",
+ guidPos->first.data, partZero->second.size() );
+ #endif
+ }
+
+ }
+
+ }
+
+} // JPEG_MetaHandler::CacheFileData
+
+// =================================================================================================
+// JPEG_MetaHandler::ProcessTNail
+// ==============================
+
+void JPEG_MetaHandler::ProcessTNail()
+{
+
+ XMP_Assert ( ! this->processedTNail );
+ this->processedTNail = true; // Make sure we only come through here once.
+ this->containsTNail = false; // Set it to true after all of the info is gathered.
+
+ if ( this->exifMgr == 0 ) { // Thumbnails only need the Exif, not the PSIR or IPTC.
+ bool readOnly = ((this->parent->openFlags & kXMPFiles_OpenForUpdate) == 0);
+ if ( readOnly ) { // *** Could reduce heap usage by not copying in TIFF_MemoryReader.
+ this->exifMgr = new TIFF_MemoryReader();
+ } else {
+ this->exifMgr = new TIFF_FileWriter();
+ }
+ this->exifMgr->ParseMemoryStream ( this->exifContents.c_str(), this->exifContents.size() );
+ }
+
+ this->containsTNail = this->exifMgr->GetTNailInfo ( &this->tnailInfo );
+ if ( this->containsTNail ) this->tnailInfo.fileFormat = this->parent->format;
+
+} // JPEG_MetaHandler::ProcessTNail
+
+// =================================================================================================
+// JPEG_MetaHandler::ProcessXMP
+// ============================
+//
+// Process the raw XMP and legacy metadata that was previously cached.
+
+void JPEG_MetaHandler::ProcessXMP()
+{
+
+ XMP_Assert ( ! this->processedXMP );
+ this->processedXMP = true; // Make sure we only come through here once.
+
+ // Create the PSIR and IPTC handlers, even if there is no legacy. They might be needed for updates.
+
+ XMP_Assert ( (this->psirMgr == 0) && (this->iptcMgr == 0) ); // ProcessTNail might create the exifMgr.
+
+ bool readOnly = ((this->parent->openFlags & kXMPFiles_OpenForUpdate) == 0);
+
+ if ( readOnly ) {
+ if ( this->exifMgr == 0 ) this->exifMgr = new TIFF_MemoryReader();
+ this->psirMgr = new PSIR_MemoryReader();
+ this->iptcMgr = new IPTC_Reader(); // ! Parse it later.
+ } else {
+ if ( this->exifMgr == 0 ) this->exifMgr = new TIFF_FileWriter();
+ this->psirMgr = new PSIR_FileWriter();
+ this->iptcMgr = new IPTC_Writer(); // ! Parse it later.
+ }
+
+ // Set up everything for the legacy import, but don't do it yet. This lets us do a forced legacy
+ // import if the XMP packet gets parsing errors.
+
+ bool found;
+ bool haveExif = (! this->exifContents.empty());
+ bool haveIPTC = false;
+
+ RecJTP_LegacyPriority lastLegacy = kLegacyJTP_None;
+
+ TIFF_Manager & exif = *this->exifMgr; // Give the compiler help in recognizing non-aliases.
+ PSIR_Manager & psir = *this->psirMgr;
+ IPTC_Manager & iptc = *this->iptcMgr;
+
+ if ( haveExif ) {
+ exif.ParseMemoryStream ( this->exifContents.c_str(), this->exifContents.size() );
+ }
+
+ if ( ! this->psirContents.empty() ) {
+ psir.ParseMemoryResources ( this->psirContents.c_str(), this->psirContents.size() );
+ }
+
+ // Determine the last-legacy priority and do the reconciliation. For JPEG files, the relevant
+ // legacy priorities (ignoring Mac pnot and ANPA resources) are:
+ // kLegacyJTP_PSIR_OldCaption - highest
+ // kLegacyJTP_PSIR_IPTC
+ // kLegacyJTP_JPEG_TIFF_Tags
+ // kLegacyJTP_None - lowest
+
+ found = psir.GetImgRsrc ( kPSIR_OldCaption, 0 );
+ if ( ! found ) found = psir.GetImgRsrc ( kPSIR_OldCaptionPStr, 0 );
+ if ( found ) {
+ haveIPTC = true;
+ lastLegacy = kLegacyJTP_PSIR_OldCaption;
+ }
+
+ PSIR_Manager::ImgRsrcInfo iptcInfo;
+ found = psir.GetImgRsrc ( kPSIR_IPTC, &iptcInfo );
+ if ( found ) {
+ haveIPTC = true;
+ iptc.ParseMemoryDataSets ( iptcInfo.dataPtr, iptcInfo.dataLen );
+ if ( lastLegacy < kLegacyJTP_PSIR_IPTC ) lastLegacy = kLegacyJTP_PSIR_IPTC;
+ }
+
+ if ( lastLegacy < kLegacyJTP_JPEG_TIFF_Tags ) {
+ found = exif.GetTag ( kTIFF_PrimaryIFD, kTIFF_ImageDescription, 0 );
+ if ( ! found ) found = exif.GetTag ( kTIFF_PrimaryIFD, kTIFF_Artist, 0 );
+ if ( ! found ) found = exif.GetTag ( kTIFF_PrimaryIFD, kTIFF_Copyright, 0 );
+ if ( found ) lastLegacy = kLegacyJTP_JPEG_TIFF_Tags;
+ }
+
+ XMP_OptionBits options = 0;
+ if ( this->containsXMP ) options |= k2XMP_FileHadXMP;
+ if ( haveExif ) options |= k2XMP_FileHadExif;
+ if ( haveIPTC ) options |= k2XMP_FileHadIPTC;
+
+ // Process the main XMP packet. If it fails to parse, do a forced legacy import but still throw
+ // an exception. This tells the caller that an error happened, but gives them recovered legacy
+ // should they want to proceed with that.
+
+ if ( ! this->xmpPacket.empty() ) {
+ XMP_Assert ( this->containsXMP );
+ // Common code takes care of packetInfo.charForm, .padSize, and .writeable.
+ XMP_StringPtr packetStr = this->xmpPacket.c_str();
+ XMP_StringLen packetLen = this->xmpPacket.size();
+ try {
+ this->xmpObj.ParseFromBuffer ( packetStr, packetLen );
+ } catch ( ... ) {
+ XMP_ClearOption ( options, k2XMP_FileHadXMP );
+ ImportJTPtoXMP ( kXMP_JPEGFile, lastLegacy, &exif, psir, &iptc, &this->xmpObj, options );
+ throw; // ! Rethrow the exception, don't absorb it.
+ }
+ }
+
+ // Process the extended XMP if it has a matching GUID.
+
+ if ( ! this->extendedXMP.empty() ) {
+
+ bool found;
+ GUID_32 g32;
+ std::string extGUID, extPacket;
+ ExtendedXMPMap::iterator guidPos = this->extendedXMP.end();
+
+ found = this->xmpObj.GetProperty ( kXMP_NS_XMP_Note, "HasExtendedXMP", &extGUID, 0 );
+ if ( found && (extGUID.size() == sizeof(g32.data)) ) {
+ XMP_Assert ( sizeof(g32.data) == 32 );
+ memcpy ( g32.data, extGUID.c_str(), sizeof(g32.data) ); // AUDIT: Use of sizeof(g32.data) is safe.
+ guidPos = this->extendedXMP.find ( g32 );
+ this->xmpObj.DeleteProperty ( kXMP_NS_XMP_Note, "HasExtendedXMP" ); // ! Must only be in the file.
+ #if Trace_UnlimitedJPEG
+ printf ( "%s extended XMP for GUID %s\n",
+ ((guidPos != this->extendedXMP.end()) ? "Found" : "Missing"), extGUID.c_str() );
+ #endif
+ }
+
+ if ( guidPos != this->extendedXMP.end() ) {
+ try {
+ XMP_StringPtr extStr = guidPos->second.c_str();
+ XMP_StringLen extLen = guidPos->second.size();
+ SXMPMeta extXMP ( extStr, extLen );
+ SXMPUtils::MergeFromJPEG ( &this->xmpObj, extXMP );
+ } catch ( ... ) {
+ // Ignore failures, let the rest of the XMP and legacy be kept.
+ }
+ }
+
+ }
+
+ // Process the legacy metadata.
+
+ ImportJTPtoXMP ( kXMP_JPEGFile, lastLegacy, &exif, psir, &iptc, &this->xmpObj, options );
+ if ( haveExif | haveIPTC ) this->containsXMP = true; // Assume we had something for the XMP.
+
+} // JPEG_MetaHandler::ProcessXMP
+
+// =================================================================================================
+// JPEG_MetaHandler::UpdateFile
+// ============================
+
+void JPEG_MetaHandler::UpdateFile ( bool doSafeUpdate )
+{
+ XMP_Assert ( ! doSafeUpdate ); // This should only be called for "unsafe" updates.
+
+ // Decide whether to do an in-place update. This can only happen if all of the following are true:
+ // - There is a standard packet in the file.
+ // - There is no extended XMP in the file.
+ // - The are no changes to the legacy Exif or PSIR portions. (The IPTC is in the PSIR.)
+ // - The new XMP can fit in the old space, without extensions.
+
+ ExportXMPtoJTP ( kXMP_JPEGFile, &this->xmpObj, this->exifMgr, this->psirMgr, this->iptcMgr );
+
+ XMP_Int64 oldPacketOffset = this->packetInfo.offset;
+ XMP_Int32 oldPacketLength = this->packetInfo.length;
+
+ if ( oldPacketOffset == kXMPFiles_UnknownOffset ) oldPacketOffset = 0; // ! Simplify checks.
+ if ( oldPacketLength == kXMPFiles_UnknownLength ) oldPacketLength = 0;
+
+ bool doInPlace = (oldPacketOffset != 0) && (oldPacketLength != 0); // ! Has old packet and new packet fits.
+
+ if ( doInPlace && (! this->extendedXMP.empty()) ) doInPlace = false;
+
+ if ( doInPlace && (this->exifMgr != 0) && (this->exifMgr->IsLegacyChanged()) ) doInPlace = false;
+ if ( doInPlace && (this->psirMgr != 0) && (this->psirMgr->IsLegacyChanged()) ) doInPlace = false;
+
+ if ( doInPlace ) {
+
+ #if GatherPerformanceData
+ sAPIPerf->back().extraInfo += ", JPEG in-place update";
+ #endif
+
+ LFA_FileRef liveFile = this->parent->fileRef;
+ std::string & newPacket = this->xmpPacket;
+
+ XMP_Assert ( newPacket.size() == (size_t)oldPacketLength ); // ! Done by common PutXMP logic.
+
+ LFA_Seek ( liveFile, oldPacketOffset, SEEK_SET );
+ LFA_Write ( liveFile, newPacket.c_str(), newPacket.size() );
+
+ } else {
+
+ #if GatherPerformanceData
+ sAPIPerf->back().extraInfo += ", JPEG copy update";
+ #endif
+
+ std::string origPath = this->parent->filePath;
+ LFA_FileRef origRef = this->parent->fileRef;
+
+ std::string updatePath;
+ LFA_FileRef updateRef = 0;
+
+ CreateTempFile ( origPath, &updatePath, kCopyMacRsrc );
+ updateRef = LFA_Open ( updatePath.c_str(), 'w' );
+
+ this->parent->filePath = updatePath;
+ this->parent->fileRef = updateRef;
+
+ try {
+ XMP_Assert ( ! this->skipReconcile );
+ this->skipReconcile = true;
+ this->WriteFile ( origRef, origPath );
+ this->skipReconcile = false;
+ } catch ( ... ) {
+ this->skipReconcile = false;
+ LFA_Close ( updateRef );
+ this->parent->filePath = origPath;
+ this->parent->fileRef = origRef;
+ throw;
+ }
+
+ LFA_Close ( origRef );
+ LFA_Delete ( origPath.c_str() );
+
+ LFA_Close ( updateRef );
+ LFA_Rename ( updatePath.c_str(), origPath.c_str() );
+ this->parent->filePath = origPath;
+ this->parent->fileRef = 0;
+
+ }
+
+ this->needsUpdate = false;
+
+} // JPEG_MetaHandler::UpdateFile
+
+// =================================================================================================
+// JPEG_MetaHandler::WriteFile
+// ===========================
+//
+// The metadata parts of a JPEG file are APP1 marker segments for Exif and XMP, and an APP13 marker
+// segment for Photoshop image resources which contain the IPTC. Corresponding marker segments in
+// the source file are ignored, other parts of the source file are copied. Any initial APP0 marker
+// segments are copied first. Then the new Exif, XMP, and PSIR marker segments are written. Then the
+// rest of the file is copied, skipping the old Exif, XMP, and PSIR. The checking for old metadata
+// stops at the first SOFn marker.
+
+// *** What about Mac resources?
+
+void JPEG_MetaHandler::WriteFile ( LFA_FileRef sourceRef, const std::string & sourcePath )
+{
+ LFA_FileRef destRef = this->parent->fileRef;
+
+ XMP_AbortProc abortProc = this->parent->abortProc;
+ void * abortArg = this->parent->abortArg;
+ const bool checkAbort = (abortProc != 0);
+
+ XMP_Uns16 marker;
+ size_t segLen; // ! Must be a size to hold at least 64k+2.
+ IOBuffer ioBuf;
+ XMP_Uns32 first4;
+
+ XMP_Assert ( kIOBufferSize >= (2 + 64*1024) ); // Enough for a marker plus maximum contents.
+
+ if ( LFA_Measure ( sourceRef ) == 0 ) return; // Tolerate empty files.
+ LFA_Seek ( sourceRef, 0, SEEK_SET );
+ LFA_Truncate (destRef, 0 );
+
+ if ( ! skipReconcile ) {
+ ExportXMPtoJTP ( kXMP_JPEGFile, &this->xmpObj, this->exifMgr, this->psirMgr, this->iptcMgr );
+ }
+
+ RefillBuffer ( sourceRef, &ioBuf );
+ if ( ! CheckFileSpace ( sourceRef, &ioBuf, 4 ) ) {
+ XMP_Throw ( "JPEG must have at least SOI and EOI markers", kXMPErr_BadJPEG );
+ }
+
+ marker = GetUns16BE ( ioBuf.ptr );
+ if ( marker != 0xFFD8 ) XMP_Throw ( "Missing SOI marker", kXMPErr_BadJPEG );
+ LFA_Write ( destRef, ioBuf.ptr, 2 );
+ ioBuf.ptr += 2;
+
+ // Copy the leading APP0 marker segments.
+
+ while ( true ) {
+
+ if ( checkAbort && abortProc(abortArg) ) {
+ XMP_Throw ( "JPEG_MetaHandler::WriteFile - User abort", kXMPErr_UserAbort );
+ }
+
+ if ( ! CheckFileSpace ( sourceRef, &ioBuf, 2 ) ) XMP_Throw ( "Unexpected end to JPEG", kXMPErr_BadJPEG );
+ marker = GetUns16BE ( ioBuf.ptr );
+ if ( marker == 0xFFFF ) {
+ LFA_Write ( destRef, ioBuf.ptr, 1 ); // Copy the 0xFF pad byte.
+ ++ioBuf.ptr;
+ continue;
+ }
+
+ if ( marker != 0xFFE0 ) break;
+
+ if ( ! CheckFileSpace ( sourceRef, &ioBuf, 4 ) ) XMP_Throw ( "Unexpected end to JPEG", kXMPErr_BadJPEG );
+ segLen = GetUns16BE ( ioBuf.ptr+2 );
+ segLen += 2; // ! Don't do above in case machine does 16 bit "+".
+
+ if ( ! CheckFileSpace ( sourceRef, &ioBuf, segLen ) ) XMP_Throw ( "Unexpected end to JPEG", kXMPErr_BadJPEG );
+ LFA_Write ( destRef, ioBuf.ptr, segLen );
+ ioBuf.ptr += segLen;
+
+ }
+
+ // Write the new Exif APP1 marker segment.
+
+ if ( this->exifMgr != 0 ) {
+
+ void* exifPtr;
+ XMP_Uns32 exifLen = this->exifMgr->UpdateMemoryStream ( &exifPtr );
+ if ( exifLen > kExifMaxDataLength ) exifLen = this->exifMgr->UpdateMemoryStream ( &exifPtr, true );
+ if ( exifLen > kExifMaxDataLength ) XMP_Throw ( "Overflow of Exif APP1 data", kXMPErr_BadJPEG );
+
+ if ( exifLen > 0 ) {
+ first4 = MakeUns32BE ( 0xFFE10000 + 2 + kExifSignatureLength + exifLen );
+ LFA_Write ( destRef, &first4, 4 );
+ LFA_Write ( destRef, kExifSignatureString, kExifSignatureLength );
+ LFA_Write ( destRef, exifPtr, exifLen );
+ }
+
+ }
+
+ // Write the new XMP APP1 marker segment, with possible extension marker segments.
+
+ std::string mainXMP, extXMP, extDigest;
+ SXMPUtils::PackageForJPEG ( this->xmpObj, &mainXMP, &extXMP, &extDigest );
+ XMP_Assert ( (extXMP.size() == 0) || (extDigest.size() == 32) );
+
+ first4 = MakeUns32BE ( 0xFFE10000 + 2 + kMainXMPSignatureLength + mainXMP.size() );
+ LFA_Write ( destRef, &first4, 4 );
+ LFA_Write ( destRef, kMainXMPSignatureString, kMainXMPSignatureLength );
+ LFA_Write ( destRef, mainXMP.c_str(), mainXMP.size() );
+
+ size_t extPos = 0;
+ size_t extLen = extXMP.size();
+
+ while ( extLen > 0 ) {
+
+ size_t partLen = extLen;
+ if ( partLen > 65000 ) partLen = 65000;
+
+ first4 = MakeUns32BE ( 0xFFE10000 + 2 + kExtXMPPrefixLength + partLen );
+ LFA_Write ( destRef, &first4, 4 );
+
+ LFA_Write ( destRef, kExtXMPSignatureString, kExtXMPSignatureLength );
+ LFA_Write ( destRef, extDigest.c_str(), extDigest.size() );
+
+ first4 = MakeUns32BE ( extXMP.size() );
+ LFA_Write ( destRef, &first4, 4 );
+ first4 = MakeUns32BE ( extPos );
+ LFA_Write ( destRef, &first4, 4 );
+
+ LFA_Write ( destRef, &extXMP[extPos], partLen );
+
+ extPos += partLen;
+ extLen -= partLen;
+
+ }
+
+ // Write the new PSIR APP13 marker segment.
+
+ if ( this->psirMgr != 0 ) {
+
+ void* psirPtr;
+ XMP_Uns32 psirLen = this->psirMgr->UpdateMemoryResources ( &psirPtr );
+ if ( psirLen > kPSIRMaxDataLength ) XMP_Throw ( "Overflow of PSIR APP13 data", kXMPErr_BadJPEG );
+
+ if ( psirLen > 0 ) {
+ first4 = MakeUns32BE ( 0xFFED0000 + 2 + kPSIRSignatureLength + psirLen );
+ LFA_Write ( destRef, &first4, 4 );
+ LFA_Write ( destRef, kPSIRSignatureString, kPSIRSignatureLength );
+ LFA_Write ( destRef, psirPtr, psirLen );
+ }
+
+ }
+
+ // Copy remaining marker segments, skipping old metadata, to the first SOFn marker.
+
+ while ( true ) {
+
+ if ( checkAbort && abortProc(abortArg) ) {
+ XMP_Throw ( "JPEG_MetaHandler::WriteFile - User abort", kXMPErr_UserAbort );
+ }
+
+ if ( ! CheckFileSpace ( sourceRef, &ioBuf, 2 ) ) XMP_Throw ( "Unexpected end to JPEG", kXMPErr_BadJPEG );
+ marker = GetUns16BE ( ioBuf.ptr );
+ if ( marker == 0xFFFF ) {
+ LFA_Write ( destRef, ioBuf.ptr, 1 ); // Copy the 0xFF pad byte.
+ ++ioBuf.ptr;
+ continue;
+ }
+
+ if ( ! TableOrDataMarker ( marker ) ) break;
+
+ if ( ! CheckFileSpace ( sourceRef, &ioBuf, 4 ) ) XMP_Throw ( "Unexpected end to JPEG", kXMPErr_BadJPEG );
+ segLen = GetUns16BE ( ioBuf.ptr+2 );
+
+ if ( ! CheckFileSpace ( sourceRef, &ioBuf, 2+segLen ) ) XMP_Throw ( "Unexpected end to JPEG", kXMPErr_BadJPEG );
+
+ bool copySegment = true;
+ XMP_Uns8* signaturePtr = ioBuf.ptr + 4;
+
+ if ( marker == 0xFFED ) {
+ if ( (segLen >= kPSIRSignatureLength) &&
+ CheckBytes ( signaturePtr, kPSIRSignatureString, kPSIRSignatureLength ) ) {
+ copySegment = false;
+ }
+ } else if ( marker == 0xFFE1 ) {
+ if ( (segLen >= kExifSignatureLength) &&
+ (CheckBytes ( signaturePtr, kExifSignatureString, kExifSignatureLength ) ||
+ CheckBytes ( signaturePtr, kExifSignatureAltStr, kExifSignatureLength )) ) {
+ copySegment = false;
+ } else if ( (segLen >= kMainXMPSignatureLength) &&
+ CheckBytes ( signaturePtr, kMainXMPSignatureString, kMainXMPSignatureLength ) ) {
+ copySegment = false;
+ } else if ( (segLen >= kExtXMPPrefixLength) &&
+ CheckBytes ( signaturePtr, kExtXMPSignatureString, kExtXMPSignatureLength ) ) {
+ copySegment = false;
+ }
+ }
+
+ if ( copySegment ) LFA_Write ( destRef, ioBuf.ptr, 2+segLen );
+
+ ioBuf.ptr += 2+segLen;
+
+ }
+
+ // Copy the remainder of the source file.
+
+ size_t bufTail = ioBuf.len - (ioBuf.ptr - &ioBuf.data[0]);
+ LFA_Write ( destRef, ioBuf.ptr, bufTail );
+ ioBuf.ptr += bufTail;
+
+ while ( true ) {
+ RefillBuffer ( sourceRef, &ioBuf );
+ if ( ioBuf.len == 0 ) break;
+ LFA_Write ( destRef, ioBuf.ptr, ioBuf.len );
+ ioBuf.ptr += ioBuf.len;
+ }
+
+ this->needsUpdate = false;
+
+} // JPEG_MetaHandler::WriteFile
diff --git a/source/XMPFiles/FileHandlers/JPEG_Handler.hpp b/source/XMPFiles/FileHandlers/JPEG_Handler.hpp
new file mode 100644
index 0000000..8a5c0f1
--- /dev/null
+++ b/source/XMPFiles/FileHandlers/JPEG_Handler.hpp
@@ -0,0 +1,95 @@
+#ifndef __JPEG_Handler_hpp__
+#define __JPEG_Handler_hpp__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "TIFF_Support.hpp"
+#include "PSIR_Support.hpp"
+#include "IPTC_Support.hpp"
+
+// =================================================================================================
+/// \file JPEG_Handler.hpp
+/// \brief File format handler for JPEG.
+///
+/// This header ...
+///
+// =================================================================================================
+
+// *** Could derive from Basic_Handler - buffer file tail in a temp file.
+
+extern XMPFileHandler * JPEG_MetaHandlerCTor ( XMPFiles * parent );
+
+extern bool JPEG_CheckFormat ( XMP_FileFormat format,
+ XMP_StringPtr filePath,
+ LFA_FileRef fileRef,
+ XMPFiles * parent );
+
+static const XMP_OptionBits kJPEG_HandlerFlags = (kXMPFiles_CanInjectXMP |
+ kXMPFiles_CanExpand |
+ kXMPFiles_CanRewrite |
+ kXMPFiles_PrefersInPlace |
+ kXMPFiles_CanReconcile |
+ kXMPFiles_AllowsOnlyXMP |
+ kXMPFiles_ReturnsRawPacket |
+ kXMPFiles_ReturnsTNail |
+ kXMPFiles_AllowsSafeUpdate);
+
+class JPEG_MetaHandler : public XMPFileHandler
+{
+public:
+
+ void CacheFileData();
+ void ProcessTNail();
+ void ProcessXMP();
+
+ void UpdateFile ( bool doSafeUpdate );
+ void WriteFile ( LFA_FileRef sourceRef, const std::string & sourcePath );
+
+ struct GUID_32 { // A hack to get an assignment operator for an array.
+ char data [32];
+ void operator= ( const GUID_32 & in )
+ {
+ memcpy ( this->data, in.data, sizeof(this->data) ); // AUDIT: Use of sizeof(this->data) is safe.
+ };
+ bool operator< ( const GUID_32 & right ) const
+ {
+ return (memcmp ( this->data, right.data, sizeof(this->data) ) < 0);
+ };
+ bool operator== ( const GUID_32 & right ) const
+ {
+ return (memcmp ( this->data, right.data, sizeof(this->data) ) == 0);
+ };
+ };
+
+ JPEG_MetaHandler ( XMPFiles * parent );
+ virtual ~JPEG_MetaHandler();
+
+private:
+
+ JPEG_MetaHandler() : exifMgr(0), psirMgr(0), iptcMgr(0), skipReconcile(false) {}; // Hidden on purpose.
+
+ std::string exifContents;
+ std::string psirContents;
+
+ TIFF_Manager * exifMgr; // The Exif manager will be created by ProcessTNail or ProcessXMP.
+ PSIR_Manager * psirMgr; // Need to use pointers so we can properly select between read-only and
+ IPTC_Manager * iptcMgr; // read-write modes of usage.
+
+ bool skipReconcile; // ! Used between UpdateFile and WriteFile.
+
+ typedef std::map < GUID_32, std::string > ExtendedXMPMap;
+
+ ExtendedXMPMap extendedXMP; // ! Only contains those with complete data.
+
+}; // JPEG_MetaHandler
+
+// =================================================================================================
+
+#endif /* __JPEG_Handler_hpp__ */
diff --git a/source/XMPFiles/FileHandlers/MOV_Handler.cpp b/source/XMPFiles/FileHandlers/MOV_Handler.cpp
new file mode 100644
index 0000000..d7b6dcd
--- /dev/null
+++ b/source/XMPFiles/FileHandlers/MOV_Handler.cpp
@@ -0,0 +1,312 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#if WIN_ENV
+ #pragma warning ( disable : 4996 ) // '...' was declared deprecated
+#endif
+
+#include "MOV_Handler.hpp"
+#include "QuickTime_Support.hpp"
+
+#include "QuickTimeComponents.h"
+
+#if XMP_WinBuild
+ #include "QTML.h"
+ #include "Movies.h"
+#endif
+
+#if XMP_MacBuild
+ #include <Movies.h>
+#endif
+
+using namespace std;
+
+static OSType kXMPUserDataType = 'XMP_';
+static long kXMPUserDataTypeIndex = 1;
+
+// =================================================================================================
+/// \file MOV_Handler.cpp
+/// \brief File format handler for MOV.
+///
+/// This header ...
+///
+// =================================================================================================
+
+// =================================================================================================
+// MOV_MetaHandlerCTor
+// ===================
+
+XMPFileHandler * MOV_MetaHandlerCTor ( XMPFiles * parent )
+{
+ return new MOV_MetaHandler ( parent );
+
+} // MOV_MetaHandlerCTor
+
+
+// =================================================================================================
+// MOV_CheckFormat
+// ===============
+
+bool MOV_CheckFormat ( XMP_FileFormat format,
+ XMP_StringPtr filePath,
+ LFA_FileRef fileRef,
+ XMPFiles * parent )
+{
+ IgnoreParam(format); IgnoreParam(fileRef);
+
+ XMP_Assert ( format == kXMP_MOVFile );
+ XMP_Assert ( fileRef == 0 );
+
+ bool inBackground = XMP_OptionIsSet ( parent->openFlags, kXMPFiles_OpenInBackground );
+
+ if ( parent->format != kXMP_MOVFile ) return false; // Check the first call hint, QT is promiscuous.
+ if ( ! QuickTime_Support::sMainInitOK ) return false;
+
+ if ( inBackground ) {
+ if ( ! QuickTime_Support::ThreadInitialize() ) return false;
+ }
+
+ bool isMov = false;
+ OSErr err = noErr;
+
+ Handle qtDataRef = 0;
+ OSType qtRefType;
+ Movie tempMovie = 0;
+ short flags;
+
+ CFStringRef cfsPath = CFStringCreateWithCString ( 0, filePath, kCFStringEncodingUTF8 );
+ if ( cfsPath == 0 ) return false; // ? Throw?
+
+ err = QTNewDataReferenceFromFullPathCFString ( cfsPath, kQTNativeDefaultPathStyle, 0, &qtDataRef, &qtRefType );
+ if ( err != noErr ) goto EXIT;
+
+ flags = newMovieDontResolveDataRefs | newMovieDontAskUnresolvedDataRefs;
+ err = NewMovieFromDataRef ( &tempMovie, flags, 0, qtDataRef, qtRefType );
+ if ( err != noErr ) goto EXIT;
+
+ isMov = true;
+
+EXIT:
+
+ if ( tempMovie != 0 ) DisposeMovie ( tempMovie );
+ if ( qtDataRef != 0 ) DisposeHandle ( qtDataRef );
+ if ( cfsPath != 0 ) CFRelease ( cfsPath );
+
+ if ( inBackground && (! isMov) ) QuickTime_Support::ThreadTerminate();
+ return isMov;
+
+} // MOV_CheckFormat
+
+// =================================================================================================
+// MOV_MetaHandler::MOV_MetaHandler
+// ================================
+
+MOV_MetaHandler::MOV_MetaHandler ( XMPFiles * _parent )
+ : mQTInit(false), mMovieDataRef(0), mMovieDataHandler(0), mMovie(NULL), mMovieResourceID(0), mFilePermission(0)
+{
+
+ this->parent = _parent;
+ this->handlerFlags = kMOV_HandlerFlags;
+ this->stdCharForm = kXMP_Char8Bit;
+
+} // MOV_MetaHandler::MOV_MetaHandler
+
+// =================================================================================================
+// MOV_MetaHandler::~MOV_MetaHandler
+// =================================
+
+MOV_MetaHandler::~MOV_MetaHandler()
+{
+ bool inBackground = XMP_OptionIsSet ( this->parent->openFlags, kXMPFiles_OpenInBackground );
+
+ this->CloseMovie();
+ if ( inBackground ) QuickTime_Support::ThreadTerminate();
+
+} // MOV_MetaHandler::~MOV_MetaHandler
+
+// =================================================================================================
+// MOV_MetaHandler::UpdateFile
+// ===========================
+
+void MOV_MetaHandler::UpdateFile ( bool doSafeUpdate )
+{
+ if ( ! this->needsUpdate ) return;
+ if ( doSafeUpdate ) XMP_Throw ( "MOV_MetaHandler::UpdateFile: Safe update not supported", kXMPErr_Unavailable );
+
+ XMP_StringPtr packetStr = this->xmpPacket.c_str();
+ XMP_StringLen packetLen = this->xmpPacket.size();
+
+ if ( packetLen == 0 ) return; // Bail if no XMP packet
+
+ if ( this->OpenMovie ( (kDataHCanRead | kDataHCanWrite) ) ) {
+
+ UserData movieUserData ( GetMovieUserData ( this->mMovie ) );
+ if ( movieUserData != 0 ) {
+
+ OSErr err;
+
+ // Remove previous versions
+ err = GetUserData ( movieUserData, NULL, kXMPUserDataType, kXMPUserDataTypeIndex );
+ if ( err == noErr ) {
+ RemoveUserData(movieUserData, kXMPUserDataType, kXMPUserDataTypeIndex);
+ }
+
+ // Add the new one
+ Handle XMPdata ( NewHandle(packetLen) );
+ if ( XMPdata != 0 ) {
+ HLock ( XMPdata );
+ strncpy ( *XMPdata, packetStr, packetLen ); // AUDIT: Handle created above using packetLen.
+ HUnlock ( XMPdata );
+ err = AddUserData ( movieUserData, XMPdata, kXMPUserDataType );
+ DisposeHandle ( XMPdata );
+ }
+
+ }
+
+ }
+
+ this->needsUpdate = false;
+
+} // MOV_MetaHandler::UpdateFile
+
+// =================================================================================================
+// MOV_MetaHandler::WriteFile
+// ==========================
+
+void MOV_MetaHandler::WriteFile ( LFA_FileRef sourceRef,
+ const std::string & sourcePath )
+{
+ IgnoreParam(sourceRef); IgnoreParam(sourcePath);
+
+ XMP_Throw ( "MOV_MetaHandler::WriteFile: Not supported", kXMPErr_Unavailable );
+
+} // MOV_MetaHandler::WriteFile
+
+// =================================================================================================
+// MOV_MetaHandler::OpenMovie
+// ==========================
+
+bool MOV_MetaHandler::OpenMovie ( long inPermission )
+{
+ // If the file is already opened with the correct permission, bail
+ if ( (inPermission == this->mFilePermission) && (this->mMovie != 0) ) return true;
+
+ // If already open, close to open with new permissions
+ if ( (this->mMovieDataRef != 0) || (this->mMovieDataHandler != 0) || (this->mMovie != 0) ) this->CloseMovie();
+ XMP_Assert ( (this->mMovieDataRef == 0) && (this->mMovieDataHandler == 0) && (this->mMovie == 0) );
+
+ OSErr err = noErr;
+ OSType qtRefType;
+ short flags;
+
+ CFStringRef cfsPath = CFStringCreateWithCString ( 0, this->parent->filePath.c_str(), kCFStringEncodingUTF8 );
+ if ( cfsPath == 0 ) return false; // ? Throw?
+
+ err = QTNewDataReferenceFromFullPathCFString ( cfsPath, kQTNativeDefaultPathStyle, 0,
+ &this->mMovieDataRef, &qtRefType );
+ if ( err != noErr ) goto FAILURE;
+
+ this->mFilePermission = inPermission;
+ err = OpenMovieStorage ( this->mMovieDataRef, qtRefType, this->mFilePermission, &this->mMovieDataHandler );
+ if ( err != noErr ) goto FAILURE;
+
+ flags = newMovieDontAskUnresolvedDataRefs;
+ this->mMovieResourceID = 0; // *** Is this the right input value?
+ err = NewMovieFromDataRef ( &this->mMovie, flags, &this->mMovieResourceID, this->mMovieDataRef, qtRefType );
+ if ( err != noErr ) goto FAILURE;
+
+ if ( cfsPath != 0 ) CFRelease ( cfsPath );
+ return true;
+
+FAILURE:
+
+ if ( this->mMovie != 0 ) DisposeMovie ( this->mMovie );
+ if ( this->mMovieDataHandler != 0 ) CloseMovieStorage ( this->mMovieDataHandler );
+ if ( this->mMovieDataRef != 0 ) DisposeHandle ( this->mMovieDataRef );
+
+ this->mMovie = 0;
+ this->mMovieDataHandler = 0;
+ this->mMovieDataRef = 0;
+
+ if ( cfsPath != 0 ) CFRelease ( cfsPath );
+ return false;
+
+} // MOV_MetaHandler::OpenMovie
+
+// =================================================================================================
+// MOV_MetaHandler::CloseMovie
+// ===========================
+
+void MOV_MetaHandler::CloseMovie()
+{
+
+ if ( this->mMovie != 0 ) {
+ if ( HasMovieChanged ( this->mMovie ) ) { // If the movie has been modified, write it to disk.
+ (void) UpdateMovieInStorage ( this->mMovie, this->mMovieDataHandler );
+ }
+ DisposeMovie ( this->mMovie );
+ }
+
+ if ( this->mMovieDataHandler != 0 ) CloseMovieStorage ( this->mMovieDataHandler );
+ if ( this->mMovieDataRef != 0 ) DisposeHandle ( this->mMovieDataRef );
+
+ this->mMovie = 0;
+ this->mMovieDataHandler = 0;
+ this->mMovieDataRef = 0;
+
+} // MOV_MetaHandler::CloseMovie
+
+// =================================================================================================
+// MOV_MetaHandler::CacheFileData
+// ==============================
+
+void MOV_MetaHandler::CacheFileData()
+{
+
+ this->containsXMP = false;
+
+ if ( this->OpenMovie ( kDataHCanRead ) ) {
+
+ UserData movieUserData ( GetMovieUserData ( this->mMovie ) );
+ if ( movieUserData != 0 ) {
+
+ Handle XMPdataHandle ( NewHandle(0) );
+ if ( XMPdataHandle != 0 ) {
+
+ OSErr err = GetUserData ( movieUserData, XMPdataHandle, kXMPUserDataType, kXMPUserDataTypeIndex );
+ if (err != noErr) { // userDataItemNotFound = -2026
+
+ packetInfo.writeable = true; // If no packet found, created packets will be writeable
+
+ } else {
+
+ // Convert handles data, to std::string raw
+ this->xmpPacket.clear();
+ size_t dataSize = GetHandleSize ( XMPdataHandle );
+ HLock(XMPdataHandle);
+ this->xmpPacket.assign ( (const char*)(*XMPdataHandle), dataSize );
+ HUnlock ( XMPdataHandle );
+
+ this->packetInfo.offset = kXMPFiles_UnknownOffset;
+ this->packetInfo.length = (XMP_Int32)dataSize;
+ this->containsXMP = true;
+
+ }
+
+ DisposeHandle ( XMPdataHandle );
+
+ }
+
+ }
+
+ }
+
+} // MOV_MetaHandler::CacheFileData
+
+// =================================================================================================
diff --git a/source/XMPFiles/FileHandlers/MOV_Handler.hpp b/source/XMPFiles/FileHandlers/MOV_Handler.hpp
new file mode 100644
index 0000000..9c7f8c3
--- /dev/null
+++ b/source/XMPFiles/FileHandlers/MOV_Handler.hpp
@@ -0,0 +1,76 @@
+#ifndef __MOV_Handler_hpp__
+#define __MOV_Handler_hpp__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "XMPFiles_Impl.hpp"
+
+// Include these first to prevent collision with CIcon
+#if XMP_WinBuild
+#include "QTML.h"
+#include "Movies.h"
+#endif
+
+#if XMP_MacBuild
+#include <Movies.h>
+#endif
+
+// =================================================================================================
+/// \file MOV_Handler.hpp
+/// \brief File format handler for MOV.
+///
+/// This header ...
+///
+// =================================================================================================
+
+extern XMPFileHandler * MOV_MetaHandlerCTor ( XMPFiles * parent );
+
+extern bool MOV_CheckFormat ( XMP_FileFormat format,
+ XMP_StringPtr filePath,
+ LFA_FileRef fileRef,
+ XMPFiles * parent );
+
+static const XMP_OptionBits kMOV_HandlerFlags = (kXMPFiles_CanInjectXMP |
+ kXMPFiles_CanExpand |
+ kXMPFiles_PrefersInPlace |
+ kXMPFiles_AllowsOnlyXMP |
+ kXMPFiles_ReturnsRawPacket |
+ kXMPFiles_HandlerOwnsFile);
+ // In the future, we'll add kXMPFiles_CanReconcile
+
+class MOV_MetaHandler : public XMPFileHandler
+{
+public:
+
+ MOV_MetaHandler ( XMPFiles * parent );
+ ~MOV_MetaHandler();
+
+ void CacheFileData();
+
+ void UpdateFile ( bool doSafeUpdate );
+ void WriteFile ( LFA_FileRef sourceRef, const std::string & sourcePath );
+
+protected:
+
+ bool mQTInit;
+ Handle mMovieDataRef;
+ DataHandler mMovieDataHandler;
+ Movie mMovie;
+ short mMovieResourceID;
+ long mFilePermission;
+
+ bool OpenMovie ( long inPermission );
+ void CloseMovie();
+
+}; // MOV_MetaHandler
+
+// =================================================================================================
+
+#endif /* __MOV_Handler_hpp__ */
diff --git a/source/XMPFiles/FileHandlers/MP3_Handler.cpp b/source/XMPFiles/FileHandlers/MP3_Handler.cpp
new file mode 100644
index 0000000..56dcf09
--- /dev/null
+++ b/source/XMPFiles/FileHandlers/MP3_Handler.cpp
@@ -0,0 +1,339 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "MP3_Handler.hpp"
+#include "ID3_Support.hpp"
+
+using namespace std;
+
+#define mp3TitleChunk "TIT2"
+#define mp3CreateDateChunk3 "TYER"
+#define mp3CreateDateChunk4 "TDRV"
+#define mp3ArtistChunk "TPE1"
+#define mp3AlbumChunk "TALB"
+#define mp3GenreChunk "TCON"
+#define mp3CommentChunk "COMM"
+#define mp3TrackChunk "TRCK"
+
+// DC
+#define kTitle "title"
+
+// XMP
+#define kCreateDate "CreateDate"
+
+// DM
+#define kArtist "artist"
+#define kAlbum "album"
+#define kGenre "genre"
+#define kLogComment "logComment"
+#define kTrack "trackNumber"
+
+// =================================================================================================
+/// \file MP3_Handler.cpp
+/// \brief File format handler for MP3.
+///
+/// This header ...
+///
+// =================================================================================================
+
+// =================================================================================================
+// MP3_MetaHandlerCTor
+// ====================
+
+XMPFileHandler * MP3_MetaHandlerCTor ( XMPFiles * parent )
+{
+ return new MP3_MetaHandler ( parent );
+
+} // MP3_MetaHandlerCTor
+
+// =================================================================================================
+// MP3_CheckFormat
+// ===============
+
+// For MP3 we check parts .... See the MP3 spec for offset info.
+//
+//
+
+bool MP3_CheckFormat ( XMP_FileFormat format,
+ XMP_StringPtr filePath,
+ LFA_FileRef inFileRef,
+ XMPFiles * parent )
+{
+ IgnoreParam(format); IgnoreParam(filePath);
+ XMP_Assert ( format == kXMP_MP3File );
+
+ if ( inFileRef == 0 ) return false;
+
+ // BUG FIX 1219125: If we find that the "unsynchronistation" flag is turned on, we should fail on that file.
+ // TODO: Support "unsynchronized" files.
+
+ LFA_Seek ( inFileRef, 0ULL, SEEK_SET );
+
+ char szID [4] = { "xxx" };
+ long bytesRead = LFA_Read ( inFileRef, szID, 3 );
+ if ( bytesRead != 3 ) return false;
+
+ if ( strncmp ( szID, "ID3", 3 ) != 0 ) {
+
+ return (parent->format == kXMP_MP3File); // No ID3 signature, depend on first call hint.
+
+ } else {
+
+ // Read the version, flag and size.
+ XMP_Uns8 v2 = 0, flags = 0, bMajorVer = 0;
+ unsigned long dwLen = 0;
+ bool ok = ID3_Support::GetTagInfo ( inFileRef, bMajorVer, v2, flags, dwLen );
+
+ if ( ok ) {
+ if ( (bMajorVer < 3) || (bMajorVer > 4) ) return false;
+ if ( flags & 0x80 ) return false; // 0x80 == "unsynchronized"
+ }
+
+ }
+
+ return true;
+
+} // MP3_CheckFormat
+
+
+// =================================================================================================
+// MP3_MetaHandler::MP3_MetaHandler
+// ================================
+
+MP3_MetaHandler::MP3_MetaHandler ( XMPFiles * _parent )
+{
+ this->parent = _parent;
+ this->handlerFlags = kMP3_HandlerFlags;
+ this->stdCharForm = kXMP_Char8Bit;
+
+} // MP3_MetaHandler::MP3_MetaHandler
+
+// =================================================================================================
+// MP3_MetaHandler::~MP3_MetaHandler
+// =================================
+
+MP3_MetaHandler::~MP3_MetaHandler()
+{
+ // Nothing to do.
+
+} // MP3_MetaHandler::~MP3_MetaHandler
+
+// =================================================================================================
+// MP3_MetaHandler::UpdateFile
+// ===========================
+
+void MP3_MetaHandler::UpdateFile ( bool doSafeUpdate )
+{
+ if ( ! this->needsUpdate ) return;
+ if ( doSafeUpdate ) XMP_Throw ( "MP3_MetaHandler::UpdateFile: Safe update not supported", kXMPErr_Unavailable );
+
+ bool fReconciliate = !(this->parent->openFlags & kXMPFiles_OpenOnlyXMP);
+
+ XMP_StringPtr packetStr = xmpPacket.c_str();
+ XMP_StringLen packetLen = xmpPacket.size();
+ if ( packetLen == 0 ) return;
+
+ LFA_FileRef fileRef ( this->parent->fileRef );
+ if ( fileRef == 0 ) return;
+
+ // Get the id3v2 version
+ XMP_Uns8 bVersion = 3;
+ unsigned long dwTagSize;
+ bool ok = ID3_Support::FindID3Tag ( fileRef, dwTagSize, bVersion );
+ if ( ! ok ) bVersion = 3;
+
+ // Allocate the temp buffer for the native frames we have to overwrite
+ unsigned long bufferSize = 7*TAG_MAX_SIZE; // Just enough buffer for all 7 tags
+ char buffer[7*TAG_MAX_SIZE];
+ memset ( buffer, 0, bufferSize );
+ unsigned long dwCurOffset = 0;
+
+ if ( fReconciliate ) {
+
+ std::string strTitle;
+ this->xmpObj.GetLocalizedText ( kXMP_NS_DC, kTitle, "", "x-default", 0, &strTitle, 0 );
+ ID3_Support::AddXMPTagToID3Buffer ( buffer, &dwCurOffset, bufferSize, bVersion,
+ mp3TitleChunk, strTitle.c_str(), strTitle.size() );
+
+ std::string strDate;
+ this->xmpObj.GetProperty ( kXMP_NS_XMP, kCreateDate, &strDate, 0 );
+ if ( bVersion == 4 ) {
+ ID3_Support::AddXMPTagToID3Buffer ( buffer, &dwCurOffset, bufferSize, bVersion,
+ mp3CreateDateChunk4, strDate.c_str(), strDate.size() );
+ } else {
+ ID3_Support::AddXMPTagToID3Buffer ( buffer, &dwCurOffset, bufferSize, bVersion,
+ mp3CreateDateChunk3, strDate.c_str(), strDate.size() );
+ }
+
+ std::string strArtist;
+ this->xmpObj.GetProperty ( kXMP_NS_DM, kArtist, &strArtist, 0 );
+ ID3_Support::AddXMPTagToID3Buffer ( buffer, &dwCurOffset, bufferSize, bVersion, mp3ArtistChunk,
+ strArtist.c_str(), strArtist.size() );
+
+ std::string strAlbum;
+ this->xmpObj.GetProperty ( kXMP_NS_DM, kAlbum, &strAlbum, 0 );
+ ID3_Support::AddXMPTagToID3Buffer ( buffer, &dwCurOffset, bufferSize, bVersion,
+ mp3AlbumChunk, strAlbum.c_str(), strAlbum.size() );
+
+ std::string strGenre;
+ this->xmpObj.GetProperty ( kXMP_NS_DM, kGenre, &strGenre, 0 );
+ ID3_Support::AddXMPTagToID3Buffer ( buffer, &dwCurOffset, bufferSize, bVersion,
+ mp3GenreChunk, strGenre.c_str(), strGenre.size() );
+
+ std::string strComment;
+ this->xmpObj.GetProperty ( kXMP_NS_DM, kLogComment, &strComment, 0 );
+ ID3_Support::AddXMPTagToID3Buffer ( buffer, &dwCurOffset, bufferSize, bVersion,
+ mp3CommentChunk, strComment.c_str(), strComment.size() );
+
+ std::string strTrack;
+ this->xmpObj.GetProperty ( kXMP_NS_DM, kTrack, &strTrack, 0 );
+ ID3_Support::AddXMPTagToID3Buffer ( buffer, &dwCurOffset, bufferSize, bVersion,
+ mp3TrackChunk, strTrack.c_str(), strTrack.size() );
+
+ }
+
+ // TODO id3v1 tags
+
+ // Saving it all
+ ID3_Support::SetMetaData ( fileRef, (char*)packetStr, packetLen, buffer, dwCurOffset, fReconciliate );
+
+ this->needsUpdate = false;
+
+} // MP3_MetaHandler::UpdateFile
+
+// =================================================================================================
+// MP3_MetaHandler::WriteFile
+// ==========================
+
+void MP3_MetaHandler::WriteFile ( LFA_FileRef sourceRef,
+ const std::string & sourcePath )
+{
+ IgnoreParam(sourceRef); IgnoreParam(sourcePath);
+
+ XMP_Throw ( "MP3_MetaHandler::WriteFile: Not supported", kXMPErr_Unavailable );
+
+} // MP3_MetaHandler::WriteFile
+
+// =================================================================================================
+// MP3_MetaHandler::CacheFileData
+// ==============================
+
+void MP3_MetaHandler::CacheFileData()
+{
+ bool fReconciliate = ! ( this->parent->openFlags & kXMPFiles_OpenOnlyXMP );
+ bool ok;
+
+ this->containsXMP = false;
+
+ // We asked the host to allow us to manage the opening of the file
+ LFA_FileRef fileRef ( this->parent->fileRef );
+ if ( fileRef == 0 ) return;
+
+ // Determine the size of the metadata
+ unsigned long bufferSize(0);
+ ok = ID3_Support::GetMetaData ( fileRef, 0, &bufferSize, 0 );
+
+ if ( ! ok ) {
+
+ packetInfo.writeable = true; // If no packet found, created packets will be writeable
+
+ } else if ( bufferSize > 0 ) {
+
+ // Allocate the buffer
+ std::string buffer;
+ buffer.reserve ( bufferSize );
+ buffer.assign ( bufferSize, ' ' );
+
+ // Get the metadata
+ XMP_Int64 xmpOffset;
+ ok = ID3_Support::GetMetaData ( fileRef, (char*)buffer.c_str(), &bufferSize, &xmpOffset );
+ if ( ok ) {
+ this->packetInfo.offset = xmpOffset;
+ this->packetInfo.length = bufferSize;
+ this->xmpPacket.assign(buffer.data(), bufferSize);
+ this->xmpObj.ParseFromBuffer ( this->xmpPacket.c_str(), this->xmpPacket.size() );
+ this->containsXMP = true;
+ }
+
+ }
+
+ if ( fReconciliate ) {
+
+ // ! Note that LoadPropertyFromID3 sets this->containsXMP, update this->processedXMP after!
+ LoadPropertyFromID3 ( fileRef, mp3TitleChunk, kXMP_NS_DC, kTitle, true );
+ LoadPropertyFromID3 ( fileRef, mp3CreateDateChunk3, kXMP_NS_XMP, kCreateDate );
+ LoadPropertyFromID3 ( fileRef, mp3ArtistChunk, kXMP_NS_DM, kArtist );
+ LoadPropertyFromID3 ( fileRef, mp3AlbumChunk, kXMP_NS_DM, kAlbum );
+ LoadPropertyFromID3 ( fileRef, mp3GenreChunk, kXMP_NS_DM, kGenre );
+ LoadPropertyFromID3 ( fileRef, mp3CommentChunk, kXMP_NS_DM, kLogComment );
+ LoadPropertyFromID3 ( fileRef, mp3TrackChunk, kXMP_NS_DM, kTrack );
+
+ }
+
+ this->processedXMP = this->containsXMP;
+
+} // MP3_MetaHandler::CacheFileData
+
+// =================================================================================================
+
+bool MP3_MetaHandler::LoadPropertyFromID3 ( LFA_FileRef inFileRef, char * strFrame, char * strNameSpace, char * strXMPTag, bool fLocalText )
+{
+
+ // Allocate the temp buffer for the native frames we have to overwrite
+ unsigned long bufferSize = TAG_MAX_SIZE;
+ std::string buffer;
+ buffer.reserve ( bufferSize );
+ buffer.assign ( bufferSize, '\0' );
+
+ // Get the old XMP tag
+ std::string xmpString("");
+ if ( fLocalText ) {
+ this->xmpObj.GetLocalizedText ( strNameSpace, strXMPTag, "", "x-default", 0, &xmpString, 0 );
+ } else {
+ this->xmpObj.GetProperty ( strNameSpace, strXMPTag, &xmpString, 0 );
+ }
+
+ // Get the frame
+ bool ok = ID3_Support::GetFrameData ( inFileRef, strFrame, (char*)buffer.c_str(), bufferSize );
+ if ( ok ) {
+ if ( ! buffer.empty() ) {
+
+ if ( xmpString.compare ( buffer ) ) {
+ if ( fLocalText ) {
+ this->xmpObj.SetLocalizedText ( strNameSpace, strXMPTag, 0, "x-default", buffer );
+ } else {
+ this->xmpObj.SetProperty ( strNameSpace, strXMPTag, buffer, 0 );
+ }
+ }
+
+ this->containsXMP = true;
+ return true;
+
+ }
+ }
+
+ // Couldn't find the frame, let's clean it on the XMP side if that tag exists.
+ if ( xmpString.size() != 0 ) {
+
+ buffer = "";
+
+ if ( fLocalText ) {
+ this->xmpObj.SetLocalizedText ( strNameSpace, strXMPTag, 0, "x-default", buffer );
+ } else {
+ this->xmpObj.SetProperty ( strNameSpace, strXMPTag, buffer, 0 );
+ }
+
+ this->containsXMP = true;
+ return true;
+
+ }
+
+ return false;
+
+} // WAV_MetaHandler::LoadPropertyFromID3
diff --git a/source/XMPFiles/FileHandlers/MP3_Handler.hpp b/source/XMPFiles/FileHandlers/MP3_Handler.hpp
new file mode 100644
index 0000000..f9aa46d
--- /dev/null
+++ b/source/XMPFiles/FileHandlers/MP3_Handler.hpp
@@ -0,0 +1,56 @@
+#ifndef __MP3_Handler_hpp__
+#define __MP3_Handler_hpp__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "XMPFiles_Impl.hpp"
+
+// =================================================================================================
+/// \file MP3_Handler.hpp
+/// \brief File format handler for MP3.
+///
+/// This header ...
+///
+// =================================================================================================
+
+extern XMPFileHandler * MP3_MetaHandlerCTor ( XMPFiles * parent );
+
+extern bool MP3_CheckFormat ( XMP_FileFormat format,
+ XMP_StringPtr filePath,
+ LFA_FileRef fileRef,
+ XMPFiles * parent );
+
+static const XMP_OptionBits kMP3_HandlerFlags = (kXMPFiles_CanInjectXMP |
+ kXMPFiles_CanExpand |
+ kXMPFiles_PrefersInPlace |
+ kXMPFiles_AllowsOnlyXMP |
+ kXMPFiles_ReturnsRawPacket);
+ // In the future, we'll add kXMPFiles_CanReconcile
+
+class MP3_MetaHandler : public XMPFileHandler
+{
+public:
+
+ MP3_MetaHandler ( XMPFiles * parent );
+ ~MP3_MetaHandler();
+
+ void CacheFileData();
+
+ void UpdateFile ( bool doSafeUpdate );
+ void WriteFile ( LFA_FileRef sourceRef, const std::string & sourcePath );
+
+private:
+ bool LoadPropertyFromID3(LFA_FileRef inFileRef, char *strFrame, char *strNameSpace, char *strXMPTag, bool fLocalText = false);
+
+}; // MP3_MetaHandler
+
+// =================================================================================================
+
+#endif /* __MP3_Handler_hpp__ */
diff --git a/source/XMPFiles/FileHandlers/MPEG_Handler.cpp b/source/XMPFiles/FileHandlers/MPEG_Handler.cpp
new file mode 100644
index 0000000..674c5e3
--- /dev/null
+++ b/source/XMPFiles/FileHandlers/MPEG_Handler.cpp
@@ -0,0 +1,234 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#if WIN_ENV
+ #pragma warning ( disable : 4996 ) // '...' was declared deprecated
+#endif
+
+#include "MPEG_Handler.hpp"
+
+using namespace std;
+
+// =================================================================================================
+/// \file MPEG_Handler.cpp
+/// \brief File format handler for MPEG.
+///
+/// BLECH! YUCK! GAG! MPEG is done using a sidecar and recognition only by file extension! BARF!!!!!
+///
+// =================================================================================================
+
+// =================================================================================================
+// FindFileExtension
+// =================
+
+static inline XMP_StringPtr FindFileExtension ( XMP_StringPtr filePath )
+{
+
+ XMP_StringPtr pathEnd = filePath + strlen(filePath);
+ XMP_StringPtr extPtr;
+
+ for ( extPtr = pathEnd-1; extPtr > filePath; --extPtr ) {
+ if ( (*extPtr == '.') || (*extPtr == '/') ) break;
+ #if XMP_WinBuild
+ if ( (*extPtr == '\\') || (*extPtr == ':') ) break;
+ #endif
+ }
+
+ if ( (extPtr < filePath) || (*extPtr != '.') ) return pathEnd;
+ return extPtr;
+
+} // FindFileExtension
+
+// =================================================================================================
+// MPEG_MetaHandlerCTor
+// ====================
+
+XMPFileHandler * MPEG_MetaHandlerCTor ( XMPFiles * parent )
+{
+ return new MPEG_MetaHandler ( parent );
+
+} // MPEG_MetaHandlerCTor
+
+// =================================================================================================
+// MPEG_CheckFormat
+// ================
+
+// The MPEG handler uses just the file extension, not the file content. Worse yet, it also uses a
+// sidecar file for the XMP. This works better if the handler owns the file, we open the sidecar
+// instead of the actual MPEG file.
+
+bool MPEG_CheckFormat ( XMP_FileFormat format,
+ XMP_StringPtr filePath,
+ LFA_FileRef fileRef,
+ XMPFiles * parent )
+{
+ IgnoreParam(format); IgnoreParam(filePath); IgnoreParam(fileRef);
+
+ XMP_Assert ( format == kXMP_MPEGFile );
+ XMP_Assert ( fileRef == 0 );
+
+ return ( parent->format == kXMP_MPEGFile ); // ! Just use the first call's format hint.
+
+} // MPEG_CheckFormat
+
+// =================================================================================================
+// MPEG_MetaHandler::MPEG_MetaHandler
+// ==================================
+
+MPEG_MetaHandler::MPEG_MetaHandler ( XMPFiles * _parent )
+{
+ this->parent = _parent;
+ this->handlerFlags = kMPEG_HandlerFlags;
+ this->stdCharForm = kXMP_Char8Bit;
+
+} // MPEG_MetaHandler::MPEG_MetaHandler
+
+// =================================================================================================
+// MPEG_MetaHandler::~MPEG_MetaHandler
+// ===================================
+
+MPEG_MetaHandler::~MPEG_MetaHandler()
+{
+ // Nothing to do.
+
+} // MPEG_MetaHandler::~MPEG_MetaHandler
+
+// =================================================================================================
+// MPEG_MetaHandler::CacheFileData
+// ===============================
+
+void MPEG_MetaHandler::CacheFileData()
+{
+ bool readOnly = (! (this->parent->openFlags & kXMPFiles_OpenForUpdate));
+
+ this->containsXMP = false;
+ this->processedXMP = true; // Whatever we do here is all that we do for XMPFiles::OpenFile.
+
+ // Try to open the sidecar XMP file. Tolerate an open failure, there might not be any XMP.
+ // Note that MPEG_CheckFormat can't save the sidecar path because the handler doesn't exist then.
+
+ XMP_StringPtr filePath = this->parent->filePath.c_str();
+ XMP_StringPtr extPtr = FindFileExtension ( filePath );
+ this->sidecarPath.assign ( filePath, (extPtr - filePath) );
+ this->sidecarPath += ".xmp";
+
+ if ( readOnly ) {
+
+ try { // *** At this time LFA_Open throws for a failure.
+ this->parent->fileRef = LFA_Open ( this->sidecarPath.c_str(), 'r' );
+ if ( this->parent->fileRef == 0 ) return; // *** Could someday check for a permission failure.
+ } catch ( ... ) {
+ return; // *** Could someday check for a permission failure.
+ }
+
+ } else {
+
+ try { // *** At this time LFA_Open throws for a failure.
+ this->parent->fileRef = LFA_Open ( this->sidecarPath.c_str(), 'w' );
+ } catch ( ... ) {
+ this->parent->fileRef = 0; // *** Could someday check for a permission failure.
+ }
+
+ if ( this->parent->fileRef == 0 ) {
+ // Try to create a file if it does not yet exist.
+ // *** Could someday check for a permission failure versus no .xmp file.
+ this->parent->fileRef = LFA_Create ( this->sidecarPath.c_str() );
+ if ( this->parent->fileRef == 0 ) XMP_Throw ( "Can't create MPEG sidecar", kXMPErr_ExternalFailure );
+ }
+
+ }
+
+ // Extract the sidecar's contents and parse.
+
+ this->packetInfo.offset = 0; // We take the whole sidecar file.
+ this->packetInfo.length = (XMP_Int32) LFA_Measure ( this->parent->fileRef );
+
+ if ( this->packetInfo.length > 0 ) {
+
+ this->xmpPacket.assign ( this->packetInfo.length, ' ' );
+ LFA_Read ( this->parent->fileRef, (void*)this->xmpPacket.c_str(), this->packetInfo.length, kLFA_RequireAll );
+ if ( readOnly ) {
+ LFA_Close ( this->parent->fileRef );
+ this->parent->fileRef = 0;
+ }
+
+ this->xmpObj.ParseFromBuffer ( this->xmpPacket.c_str(), this->xmpPacket.size() );
+ this->containsXMP = true;
+
+ }
+
+} // MPEG_MetaHandler::CacheFileData
+
+// =================================================================================================
+// MPEG_MetaHandler::UpdateFile
+// ============================
+
+void MPEG_MetaHandler::UpdateFile ( bool doSafeUpdate )
+{
+ if ( ! this->needsUpdate ) return;
+
+ LFA_FileRef fileRef = this->parent->fileRef;
+ XMP_Assert ( fileRef != 0 );
+
+ XMP_StringPtr packetStr = this->xmpPacket.c_str();
+ XMP_StringLen packetLen = this->xmpPacket.size();
+
+ if ( ! doSafeUpdate ) {
+
+ // Not doing a crash-safe update, simply rewrite the existing sidecar file.
+ LFA_Seek ( fileRef, 0, SEEK_SET );
+ LFA_Truncate ( fileRef, 0 );
+ LFA_Write ( fileRef, packetStr, packetLen );
+
+ } else {
+
+ // Do the usual crash-safe update dance.
+
+ LFA_FileRef tempFileRef = 0;
+ std::string tempFilePath;
+
+ try {
+
+ CreateTempFile ( this->sidecarPath, &tempFilePath, kCopyMacRsrc );
+ tempFileRef = LFA_Open ( tempFilePath.c_str(), 'w' );
+ LFA_Write ( tempFileRef, packetStr, packetLen );
+
+ LFA_Close ( fileRef );
+ this->parent->fileRef = 0;
+ LFA_Close ( tempFileRef );
+ tempFileRef = 0;
+
+ LFA_Delete ( this->sidecarPath.c_str() );
+ LFA_Rename ( tempFilePath.c_str(), this->sidecarPath.c_str() );
+
+ } catch ( ... ) {
+
+ if ( tempFileRef != 0 ) LFA_Close ( tempFileRef );
+ if ( ! tempFilePath.empty() ) LFA_Delete ( tempFilePath.c_str() );
+
+ }
+
+ }
+
+ this->needsUpdate = false;
+
+} // MPEG_MetaHandler::UpdateFile
+
+// =================================================================================================
+// MPEG_MetaHandler::WriteFile
+// ===========================
+
+void MPEG_MetaHandler::WriteFile ( LFA_FileRef sourceRef,
+ const std::string & sourcePath )
+{
+ IgnoreParam(sourceRef); IgnoreParam(sourcePath);
+
+ XMP_Throw ( "MPEG_MetaHandler::WriteFile: Should never be called", kXMPErr_Unavailable );
+
+} // MPEG_MetaHandler::WriteFile
diff --git a/source/XMPFiles/FileHandlers/MPEG_Handler.hpp b/source/XMPFiles/FileHandlers/MPEG_Handler.hpp
new file mode 100644
index 0000000..21484ce
--- /dev/null
+++ b/source/XMPFiles/FileHandlers/MPEG_Handler.hpp
@@ -0,0 +1,57 @@
+#ifndef __MPEG_Handler_hpp__
+#define __MPEG_Handler_hpp__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "XMPFiles_Impl.hpp"
+
+// =================================================================================================
+/// \file MPEG_Handler.hpp
+/// \brief File format handler for MPEG.
+///
+/// This header ...
+///
+// =================================================================================================
+
+extern XMPFileHandler * MPEG_MetaHandlerCTor ( XMPFiles * parent );
+
+extern bool MPEG_CheckFormat ( XMP_FileFormat format,
+ XMP_StringPtr filePath,
+ LFA_FileRef fileRef,
+ XMPFiles * parent);
+
+static const XMP_OptionBits kMPEG_HandlerFlags = ( kXMPFiles_CanInjectXMP |
+ kXMPFiles_CanExpand |
+ kXMPFiles_CanRewrite |
+ kXMPFiles_AllowsOnlyXMP |
+ kXMPFiles_ReturnsRawPacket |
+ kXMPFiles_HandlerOwnsFile |
+ kXMPFiles_AllowsSafeUpdate |
+ kXMPFiles_UsesSidecarXMP );
+
+class MPEG_MetaHandler : public XMPFileHandler
+{
+public:
+
+ std::string sidecarPath;
+
+ MPEG_MetaHandler ( XMPFiles * parent );
+ ~MPEG_MetaHandler();
+
+ void CacheFileData();
+
+ void UpdateFile ( bool doSafeUpdate );
+ void WriteFile ( LFA_FileRef sourceRef, const std::string & sourcePath );
+
+}; // MPEG_MetaHandler
+
+// =================================================================================================
+
+#endif /* __MPEG_Handler_hpp__ */
diff --git a/source/XMPFiles/FileHandlers/PNG_Handler.cpp b/source/XMPFiles/FileHandlers/PNG_Handler.cpp
new file mode 100644
index 0000000..44a08dd
--- /dev/null
+++ b/source/XMPFiles/FileHandlers/PNG_Handler.cpp
@@ -0,0 +1,281 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "PNG_Handler.hpp"
+
+#include "PNG_Support.hpp"
+
+using namespace std;
+
+// =================================================================================================
+/// \file PNG_Handler.hpp
+/// \brief File format handler for PNG.
+///
+/// This handler ...
+///
+// =================================================================================================
+
+// =================================================================================================
+// PNG_MetaHandlerCTor
+// ====================
+
+XMPFileHandler * PNG_MetaHandlerCTor ( XMPFiles * parent )
+{
+ return new PNG_MetaHandler ( parent );
+
+} // PNG_MetaHandlerCTor
+
+// =================================================================================================
+// PNG_CheckFormat
+// ===============
+
+bool PNG_CheckFormat ( XMP_FileFormat format,
+ XMP_StringPtr filePath,
+ LFA_FileRef fileRef,
+ XMPFiles * parent )
+{
+ IgnoreParam(format); IgnoreParam(fileRef); IgnoreParam(parent);
+ XMP_Assert ( format == kXMP_PNGFile );
+
+ IOBuffer ioBuf;
+
+ LFA_Seek ( fileRef, 0, SEEK_SET );
+ if ( ! CheckFileSpace ( fileRef, &ioBuf, PNG_SIGNATURE_LEN ) ) return false; // We need at least 8, the buffer is filled anyway.
+
+ if ( ! CheckBytes ( ioBuf.ptr, PNG_SIGNATURE_DATA, PNG_SIGNATURE_LEN ) ) return false;
+
+ return true;
+
+} // PNG_CheckFormat
+
+// =================================================================================================
+// PNG_MetaHandler::PNG_MetaHandler
+// ==================================
+
+PNG_MetaHandler::PNG_MetaHandler ( XMPFiles * _parent )
+{
+ this->parent = _parent;
+ this->handlerFlags = kPNG_HandlerFlags;
+ this->stdCharForm = kXMP_Char8Bit;
+
+}
+
+// =================================================================================================
+// PNG_MetaHandler::~PNG_MetaHandler
+// ===================================
+
+PNG_MetaHandler::~PNG_MetaHandler()
+{
+}
+
+// =================================================================================================
+// PNG_MetaHandler::CacheFileData
+// ===============================
+
+void PNG_MetaHandler::CacheFileData()
+{
+
+ this->containsXMP = false;
+
+ LFA_FileRef fileRef ( this->parent->fileRef );
+ if ( fileRef == 0) return;
+
+ PNG_Support::ChunkState chunkState;
+ long numChunks = PNG_Support::OpenPNG ( fileRef, chunkState );
+ if ( numChunks == 0 ) return;
+
+ if (chunkState.xmpLen != 0)
+ {
+ // XMP present
+
+ this->xmpPacket.reserve(chunkState.xmpLen);
+ this->xmpPacket.assign(chunkState.xmpLen, ' ');
+
+ if (PNG_Support::ReadBuffer ( fileRef, chunkState.xmpPos, chunkState.xmpLen, const_cast<char *>(this->xmpPacket.data()) ))
+ {
+ this->packetInfo.offset = chunkState.xmpPos;
+ this->packetInfo.length = chunkState.xmpLen;
+ this->containsXMP = true;
+ }
+ }
+ else
+ {
+ // no XMP
+ }
+
+} // PNG_MetaHandler::CacheFileData
+
+// =================================================================================================
+// PNG_MetaHandler::ProcessTNail
+// ==============================
+
+void PNG_MetaHandler::ProcessTNail()
+{
+
+ XMP_Throw ( "PNG_MetaHandler::ProcessTNail isn't implemented yet", kXMPErr_Unimplemented );
+
+} // PNG_MetaHandler::ProcessTNail
+
+// =================================================================================================
+// PNG_MetaHandler::ProcessXMP
+// ============================
+//
+// Process the raw XMP and legacy metadata that was previously cached.
+
+void PNG_MetaHandler::ProcessXMP()
+{
+ this->processedXMP = true; // Make sure we only come through here once.
+
+ // Process the XMP packet.
+
+ if ( ! this->xmpPacket.empty() ) {
+
+ XMP_Assert ( this->containsXMP );
+ XMP_StringPtr packetStr = this->xmpPacket.c_str();
+ XMP_StringLen packetLen = this->xmpPacket.size();
+
+ this->xmpObj.ParseFromBuffer ( packetStr, packetLen );
+
+ this->containsXMP = true;
+
+ }
+
+} // PNG_MetaHandler::ProcessXMP
+
+// =================================================================================================
+// PNG_MetaHandler::UpdateFile
+// ============================
+
+void PNG_MetaHandler::UpdateFile ( bool doSafeUpdate )
+{
+ bool updated = false;
+
+ if ( ! this->needsUpdate ) return;
+ if ( doSafeUpdate ) XMP_Throw ( "PNG_MetaHandler::UpdateFile: Safe update not supported", kXMPErr_Unavailable );
+
+ XMP_StringPtr packetStr = xmpPacket.c_str();
+ XMP_StringLen packetLen = xmpPacket.size();
+ if ( packetLen == 0 ) return;
+
+ LFA_FileRef fileRef(this->parent->fileRef);
+ if ( fileRef == 0 ) return;
+
+ PNG_Support::ChunkState chunkState;
+ long numChunks = PNG_Support::OpenPNG ( fileRef, chunkState );
+ if ( numChunks == 0 ) return;
+
+ // write/update chunk
+ if (chunkState.xmpLen == 0)
+ {
+ // no current chunk -> inject
+ updated = SafeWriteFile();
+ }
+ else if (chunkState.xmpLen >= packetLen )
+ {
+ // current chunk size is sufficient -> write and update CRC (in place update)
+ updated = PNG_Support::WriteBuffer(fileRef, chunkState.xmpPos, packetLen, packetStr );
+ PNG_Support::UpdateChunkCRC(fileRef, chunkState.xmpChunk );
+ }
+ else if (chunkState.xmpLen < packetLen)
+ {
+ // XMP is too large for current chunk -> expand
+ updated = SafeWriteFile();
+ }
+
+ if ( ! updated )return; // If there's an error writing the chunk, bail.
+
+ this->needsUpdate = false;
+
+} // PNG_MetaHandler::UpdateFile
+
+// =================================================================================================
+// PNG_MetaHandler::WriteFile
+// ===========================
+
+void PNG_MetaHandler::WriteFile ( LFA_FileRef sourceRef, const std::string & sourcePath )
+{
+ LFA_FileRef destRef = this->parent->fileRef;
+
+ PNG_Support::ChunkState chunkState;
+ long numChunks = PNG_Support::OpenPNG ( sourceRef, chunkState );
+ if ( numChunks == 0 ) return;
+
+ LFA_Truncate(destRef, 0);
+ LFA_Write(destRef, PNG_SIGNATURE_DATA, PNG_SIGNATURE_LEN);
+
+ PNG_Support::ChunkIterator curPos = chunkState.chunks.begin();
+ PNG_Support::ChunkIterator endPos = chunkState.chunks.end();
+
+ for (; (curPos != endPos); ++curPos)
+ {
+ PNG_Support::ChunkData chunk = *curPos;
+
+ // discard existing XMP chunk
+ if (chunk.xmp)
+ continue;
+
+ // copy any other chunk
+ PNG_Support::CopyChunk(sourceRef, destRef, chunk);
+
+ // place XMP chunk immediately after IHDR-chunk
+ if (PNG_Support::CheckIHDRChunkHeader(chunk))
+ {
+ XMP_StringPtr packetStr = xmpPacket.c_str();
+ XMP_StringLen packetLen = xmpPacket.size();
+
+ PNG_Support::WriteXMPChunk(destRef, packetLen, packetStr );
+ }
+ }
+
+} // PNG_MetaHandler::WriteFile
+
+// =================================================================================================
+// PNG_MetaHandler::SafeWriteFile
+// ===========================
+
+bool PNG_MetaHandler::SafeWriteFile ()
+{
+ bool ret = false;
+
+ std::string origPath = this->parent->filePath;
+ LFA_FileRef origRef = this->parent->fileRef;
+
+ std::string updatePath;
+ LFA_FileRef updateRef = 0;
+
+ CreateTempFile ( origPath, &updatePath, kCopyMacRsrc );
+ updateRef = LFA_Open ( updatePath.c_str(), 'w' );
+
+ this->parent->filePath = updatePath;
+ this->parent->fileRef = updateRef;
+
+ try {
+ this->WriteFile ( origRef, origPath );
+ ret = true;
+ } catch ( ... ) {
+ LFA_Close ( updateRef );
+ this->parent->filePath = origPath;
+ this->parent->fileRef = origRef;
+ throw;
+ }
+
+ LFA_Close ( origRef );
+ LFA_Delete ( origPath.c_str() );
+
+ LFA_Close ( updateRef );
+ LFA_Rename ( updatePath.c_str(), origPath.c_str() );
+ this->parent->filePath = origPath;
+
+ this->parent->fileRef = 0;
+
+ return ret;
+
+} // PNG_MetaHandler::SafeWriteFile
+
+// =================================================================================================
diff --git a/source/XMPFiles/FileHandlers/PNG_Handler.hpp b/source/XMPFiles/FileHandlers/PNG_Handler.hpp
new file mode 100644
index 0000000..92ee15c
--- /dev/null
+++ b/source/XMPFiles/FileHandlers/PNG_Handler.hpp
@@ -0,0 +1,60 @@
+#ifndef __PNG_Handler_hpp__
+#define __PNG_Handler_hpp__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "PNG_Support.hpp"
+
+// =================================================================================================
+/// \file PNG_Handler.hpp
+/// \brief File format handler for PNG.
+///
+/// This header ...
+///
+// =================================================================================================
+
+// *** Could derive from Basic_Handler - buffer file tail in a temp file.
+
+extern XMPFileHandler* PNG_MetaHandlerCTor ( XMPFiles* parent );
+
+extern bool PNG_CheckFormat ( XMP_FileFormat format,
+ XMP_StringPtr filePath,
+ LFA_FileRef fileRef,
+ XMPFiles* parent );
+
+static const XMP_OptionBits kPNG_HandlerFlags = ( kXMPFiles_CanInjectXMP |
+ kXMPFiles_CanExpand |
+ kXMPFiles_PrefersInPlace |
+ kXMPFiles_AllowsOnlyXMP |
+ kXMPFiles_ReturnsRawPacket |
+ kXMPFiles_NeedsReadOnlyPacket
+ );
+
+class PNG_MetaHandler : public XMPFileHandler
+{
+public:
+
+ void CacheFileData();
+ void ProcessTNail();
+ void ProcessXMP();
+
+ void UpdateFile ( bool doSafeUpdate );
+ void WriteFile ( LFA_FileRef sourceRef, const std::string& sourcePath );
+
+ bool SafeWriteFile ();
+
+ PNG_MetaHandler ( XMPFiles* parent );
+ virtual ~PNG_MetaHandler();
+
+}; // PNG_MetaHandler
+
+// =================================================================================================
+
+#endif /* __PNG_Handler_hpp__ */
diff --git a/source/XMPFiles/FileHandlers/PSD_Handler.cpp b/source/XMPFiles/FileHandlers/PSD_Handler.cpp
new file mode 100644
index 0000000..6d9523e
--- /dev/null
+++ b/source/XMPFiles/FileHandlers/PSD_Handler.cpp
@@ -0,0 +1,457 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "PSD_Handler.hpp"
+
+#include "TIFF_Support.hpp"
+#include "PSIR_Support.hpp"
+#include "IPTC_Support.hpp"
+#include "ReconcileLegacy.hpp"
+
+#include "MD5.h"
+
+using namespace std;
+
+// =================================================================================================
+/// \file PSD_Handler.cpp
+/// \brief File format handler for PSD (Photoshop).
+///
+/// This handler ...
+///
+// =================================================================================================
+
+// =================================================================================================
+// PSD_CheckFormat
+// ===============
+
+// For PSD we just check the "8BPS" signature, the following version, and that the file is at least
+// 34 bytes long. This covers the 26 byte header, the 4 byte color mode section length (which might
+// be 0), and the 4 byte image resource section length (which might be 0). The parsing logic in
+// CacheFileData will do further checks that the image resources actually exist. Those checks are
+// not needed to decide if this is a PSD file though, instead they decide if this is valid PSD.
+
+// ! The CheckXyzFormat routines don't track the filePos, that is left to ScanXyzFile.
+
+bool PSD_CheckFormat ( XMP_FileFormat format,
+ XMP_StringPtr filePath,
+ LFA_FileRef fileRef,
+ XMPFiles * parent )
+{
+ IgnoreParam(format); IgnoreParam(filePath); IgnoreParam(parent);
+ XMP_Assert ( format == kXMP_PhotoshopFile );
+
+ IOBuffer ioBuf;
+
+ LFA_Seek ( fileRef, 0, SEEK_SET );
+ if ( ! CheckFileSpace ( fileRef, &ioBuf, 34 ) ) return false; // 34 = header plus 2 lengths
+
+ if ( ! CheckBytes ( ioBuf.ptr, "8BPS", 4 ) ) return false;
+ ioBuf.ptr += 4; // Move to the version.
+ XMP_Uns16 version = GetUns16BE ( ioBuf.ptr );
+ if ( (version != 1) && (version != 2) ) return false;
+
+ return true;
+
+} // PSD_CheckFormat
+
+// =================================================================================================
+// PSD_MetaHandlerCTor
+// ===================
+
+XMPFileHandler * PSD_MetaHandlerCTor ( XMPFiles * parent )
+{
+ return new PSD_MetaHandler ( parent );
+
+} // PSD_MetaHandlerCTor
+
+// =================================================================================================
+// PSD_MetaHandler::PSD_MetaHandler
+// ================================
+
+PSD_MetaHandler::PSD_MetaHandler ( XMPFiles * _parent ) : iptcMgr(0), exifMgr(0), skipReconcile(false)
+{
+ this->parent = _parent;
+ this->handlerFlags = kPSD_HandlerFlags;
+ this->stdCharForm = kXMP_Char8Bit;
+
+} // PSD_MetaHandler::PSD_MetaHandler
+
+// =================================================================================================
+// PSD_MetaHandler::~PSD_MetaHandler
+// =================================
+
+PSD_MetaHandler::~PSD_MetaHandler()
+{
+
+ if ( this->iptcMgr != 0 ) delete ( this->iptcMgr );
+ if ( this->exifMgr != 0 ) delete ( this->exifMgr );
+
+} // PSD_MetaHandler::~PSD_MetaHandler
+
+// =================================================================================================
+// PSD_MetaHandler::CacheFileData
+// ==============================
+//
+// Find and parse the image resource section, everything we want is in there. Don't simply capture
+// the whole section, there could be lots of stuff we don't care about.
+
+// *** This implementation simply returns when an invalid file is encountered. Should we throw instead?
+
+void PSD_MetaHandler::CacheFileData()
+{
+ LFA_FileRef fileRef = this->parent->fileRef;
+ XMP_PacketInfo & packetInfo = this->packetInfo;
+
+ XMP_AbortProc abortProc = this->parent->abortProc;
+ void * abortArg = this->parent->abortArg;
+ const bool checkAbort = (abortProc != 0);
+
+ XMP_Assert ( (! this->containsXMP) && (! this->containsTNail) );
+ // Set containsXMP to true here only if the XMP image resource is found.
+
+ if ( checkAbort && abortProc(abortArg) ) {
+ XMP_Throw ( "PSD_MetaHandler::CacheFileData - User abort", kXMPErr_UserAbort );
+ }
+
+ XMP_Uns8 psdHeader[30];
+ XMP_Int64 filePos;
+ XMP_Uns32 ioLen, cmLen, psirLen;
+
+ filePos = LFA_Seek ( fileRef, 0, SEEK_SET );
+
+ ioLen = LFA_Read ( fileRef, psdHeader, 30 );
+ if ( ioLen != 30 ) return; // Throw?
+
+ this->imageHeight = GetUns32BE ( &psdHeader[14] );
+ this->imageWidth = GetUns32BE ( &psdHeader[18] );
+
+ cmLen = GetUns32BE ( &psdHeader[26] );
+
+ XMP_Int64 psirOrigin = 26 + 4 + cmLen;
+
+ filePos = LFA_Seek ( fileRef, psirOrigin, SEEK_SET );
+ if ( filePos != psirOrigin ) return; // Throw?
+
+ ioLen = LFA_Read ( fileRef, psdHeader, 4 );
+ if ( ioLen != 4 ) return; // Throw?
+
+ psirLen = GetUns32BE ( &psdHeader[0] );
+
+ this->psirMgr.ParseFileResources ( fileRef, psirLen );
+
+ PSIR_Manager::ImgRsrcInfo xmpInfo;
+ bool found = this->psirMgr.GetImgRsrc ( kPSIR_XMP, &xmpInfo );
+
+ if ( found ) {
+
+ // printf ( "PSD_MetaHandler::CacheFileData - XMP packet offset %d (0x%X), size %d\n",
+ // xmpInfo.origOffset, xmpInfo.origOffset, xmpInfo.dataLen );
+ this->packetInfo.offset = xmpInfo.origOffset;
+ this->packetInfo.length = xmpInfo.dataLen;
+ this->packetInfo.padSize = 0; // Assume for now, set these properly in ProcessXMP.
+ this->packetInfo.charForm = kXMP_CharUnknown;
+ this->packetInfo.writeable = true;
+
+ this->xmpPacket.assign ( (XMP_StringPtr)xmpInfo.dataPtr, xmpInfo.dataLen );
+
+ this->containsXMP = true;
+
+ }
+
+} // PSD_MetaHandler::CacheFileData
+
+// =================================================================================================
+// PSD_MetaHandler::ProcessTNail
+// =============================
+//
+// A Photoshop file has a thumbnail in image resource 1036. This has the following layout:
+//
+// offset length description
+// 0 4 Format: 0 = kRawRGB, 1 = kJpegRGB
+// 4 4 Thumbnail image width in pixels
+// 8 4 Thumbnail image height in pixels
+// 12 4 Width bytes: Padded row bytes = (width * bits per pixel + 31) / 32 * 4
+// 16 4 Total size = widthbytes * height * planes
+// 20 4 Size after compression, used for consistency check
+// 24 2 Bits per pixel, must be 24
+// 26 2 Number of planes, must be 1
+// 28 - Thumbnail image stream
+//
+// We return the full image resource as the tnailImage part of the XMP_ThumbnailInfo. The client is
+// responsible for all further parsing, including conversions on little endian machines. (Since
+// Photoshop image resources are always stored big endian.)
+//
+// Actually image resource 1036 is for Photoshop 5 and later. Photoshop 4 used image resource 1033,
+// which was similar but used BGR pixels. We are ignoring the earlier format.
+
+void PSD_MetaHandler::ProcessTNail()
+{
+ this->processedTNail = true; // Make sure we only come through here once.
+ this->containsTNail = false; // Set it to true after all of the info is gathered.
+
+ PSIR_Manager::ImgRsrcInfo tnailRsrc;
+ bool found = this->psirMgr.GetImgRsrc ( kPSIR_Thumbnail, &tnailRsrc );
+ if ( ! found ) return;
+
+ this->tnailInfo.fileFormat = this->parent->format;
+ this->tnailInfo.tnailFormat = kXMP_PShopTNail;
+
+ this->tnailInfo.fullWidth = this->imageWidth;
+ this->tnailInfo.fullHeight = this->imageHeight;
+
+ this->tnailInfo.tnailImage = (XMP_Uns8*)tnailRsrc.dataPtr;
+ this->tnailInfo.tnailSize = tnailRsrc.dataLen;
+ this->tnailInfo.tnailWidth = GetUns32BE ( this->tnailInfo.tnailImage + 4 );
+ this->tnailInfo.tnailHeight = GetUns32BE ( this->tnailInfo.tnailImage + 8 );
+
+ this->tnailInfo.fullOrientation = this->tnailInfo.tnailOrientation = 0; // ! Not present in PSD files.
+
+ this->containsTNail = true;
+
+} // PSD_MetaHandler::ProcessTNail
+
+// =================================================================================================
+// PSD_MetaHandler::ProcessXMP
+// ===========================
+//
+// Process the raw XMP and legacy metadata that was previously cached.
+
+void PSD_MetaHandler::ProcessXMP()
+{
+
+ this->processedXMP = true; // Make sure we only come through here once.
+
+ // Set up everything for the legacy import, but don't do it yet. This lets us do a forced legacy
+ // import if the XMP packet gets parsing errors.
+
+ // Parse the IPTC and Exif, determine the last-legacy priority. For PSD files the relevant
+ // legacy priorities (ignoring Mac pnot and ANPA resources) are:
+ // kLegacyJTP_PSIR_OldCaption - highest
+ // kLegacyJTP_PSIR_IPTC
+ // kLegacyJTP_None - lowest
+
+ // ! Yes, TIFF tags 270 (Image Description, dc:description), 315 (Artist, dc:creator), and
+ // ! 33432 (Copyright, dc:rights) are ignored in Photoshop files. The only imported legacy forms
+ // ! of these are IPTC DataSets 2:120 (Caption), 2:80 (By-line), and 2:116 ( Copyright Notice).
+
+ bool found;
+ RecJTP_LegacyPriority lastLegacy = kLegacyJTP_None;
+
+ bool readOnly = ((this->parent->openFlags & kXMPFiles_OpenForUpdate) == 0);
+
+ if ( readOnly ) {
+ this->iptcMgr = new IPTC_Reader();
+ this->exifMgr = new TIFF_MemoryReader();
+ } else {
+ this->iptcMgr = new IPTC_Writer();
+ this->exifMgr = new TIFF_FileWriter();
+ }
+
+ PSIR_Manager & psir = this->psirMgr; // Give the compiler help in recognizing non-aliases.
+ IPTC_Manager & iptc = *this->iptcMgr;
+ TIFF_Manager & exif = *this->exifMgr;
+
+ PSIR_Manager::ImgRsrcInfo iptcInfo, exifInfo;
+ bool haveIPTC = psir.GetImgRsrc ( kPSIR_IPTC, &iptcInfo );
+ bool haveExif = psir.GetImgRsrc ( kPSIR_Exif, &exifInfo );
+
+ found = psir.GetImgRsrc ( kPSIR_OldCaption, 0 );
+ if ( ! found ) found = psir.GetImgRsrc ( kPSIR_OldCaptionPStr, 0 );
+ if ( found ) lastLegacy = kLegacyJTP_PSIR_OldCaption;
+
+ if ( haveIPTC ) {
+ iptc.ParseMemoryDataSets ( iptcInfo.dataPtr, iptcInfo.dataLen );
+ if ( lastLegacy < kLegacyJTP_PSIR_IPTC ) lastLegacy = kLegacyJTP_PSIR_IPTC;
+ }
+
+ if ( haveExif ) {
+ exif.ParseMemoryStream ( exifInfo.dataPtr, exifInfo.dataLen );
+ }
+
+ XMP_OptionBits options = 0;
+ if ( this->containsXMP ) options |= k2XMP_FileHadXMP;
+ if ( haveIPTC ) options |= k2XMP_FileHadIPTC;
+ if ( haveExif ) options |= k2XMP_FileHadExif;
+
+ // Process the XMP packet. If it fails to parse, do a forced legacy import but still throw an
+ // exception. This tells the caller that an error happened, but gives them recovered legacy
+ // should they want to proceed with that.
+
+ if ( ! this->xmpPacket.empty() ) {
+ XMP_Assert ( this->containsXMP );
+ // Common code takes care of packetInfo.charForm, .padSize, and .writeable.
+ XMP_StringPtr packetStr = this->xmpPacket.c_str();
+ XMP_StringLen packetLen = this->xmpPacket.size();
+ try {
+ this->xmpObj.ParseFromBuffer ( packetStr, packetLen );
+ } catch ( ... ) {
+ XMP_ClearOption ( options, k2XMP_FileHadXMP );
+ ImportJTPtoXMP ( kXMP_JPEGFile, lastLegacy, &exif, psir, &iptc, &this->xmpObj, options );
+ throw; // ! Rethrow the exception, don't absorb it.
+ }
+ }
+
+ // Process the legacy metadata.
+
+ ImportJTPtoXMP ( kXMP_PhotoshopFile, lastLegacy, &exif, psir, &iptc, &this->xmpObj, options );
+ this->containsXMP = true; // Assume we now have something in the XMP.
+
+} // PSD_MetaHandler::ProcessXMP
+
+// =================================================================================================
+// PSD_MetaHandler::UpdateFile
+// ===========================
+
+void PSD_MetaHandler::UpdateFile ( bool doSafeUpdate )
+{
+ XMP_Assert ( ! doSafeUpdate ); // This should only be called for "unsafe" updates.
+
+ // Decide whether to do an in-place update. This can only happen if all of the following are true:
+ // - There is an XMP packet in the file.
+ // - The are no changes to the legacy image resources. (The IPTC and EXIF are in the PSIR.)
+ // - The new XMP can fit in the old space.
+
+ ExportXMPtoJTP ( kXMP_PhotoshopFile, &this->xmpObj, this->exifMgr, &this->psirMgr, this->iptcMgr );
+
+ XMP_Int64 oldPacketOffset = this->packetInfo.offset;
+ XMP_Int32 oldPacketLength = this->packetInfo.length;
+ // printf ( "PSD_MetaHandler::UpdateFile - XMP old packet offset %lld (0x%llX), size %d\n",
+ // oldPacketOffset, oldPacketOffset, oldPacketLength );
+
+ if ( oldPacketOffset == kXMPFiles_UnknownOffset ) oldPacketOffset = 0; // ! Simplify checks.
+ if ( oldPacketLength == kXMPFiles_UnknownLength ) oldPacketLength = 0;
+
+ bool doInPlace = (oldPacketOffset != 0) && (oldPacketLength != 0); // ! Has old packet and new packet fits.
+ if ( doInPlace && (this->psirMgr.IsLegacyChanged()) ) doInPlace = false;
+
+ if ( doInPlace ) {
+
+ #if GatherPerformanceData
+ sAPIPerf->back().extraInfo += ", PSD in-place update";
+ #endif
+
+ LFA_FileRef liveFile = this->parent->fileRef;
+
+ XMP_Assert ( this->xmpPacket.size() == (size_t)oldPacketLength ); // ! Done by common PutXMP logic.
+
+ // printf ( "PSD_MetaHandler::UpdateFile - XMP in-place packet offset %lld (0x%llX), size %d\n",
+ // oldPacketOffset, oldPacketOffset, this->xmpPacket.size() );
+ LFA_Seek ( liveFile, oldPacketOffset, SEEK_SET );
+ LFA_Write ( liveFile, this->xmpPacket.c_str(), this->xmpPacket.size() );
+
+ } else {
+
+ #if GatherPerformanceData
+ sAPIPerf->back().extraInfo += ", PSD copy update";
+ #endif
+
+ std::string origPath = this->parent->filePath;
+ LFA_FileRef origRef = this->parent->fileRef;
+
+ std::string updatePath;
+ LFA_FileRef updateRef = 0;
+
+ CreateTempFile ( origPath, &updatePath, kCopyMacRsrc );
+ updateRef = LFA_Open ( updatePath.c_str(), 'w' );
+
+ this->parent->filePath = updatePath;
+ this->parent->fileRef = updateRef;
+
+ try {
+ XMP_Assert ( ! this->skipReconcile );
+ this->skipReconcile = true;
+ this->WriteFile ( origRef, origPath );
+ this->skipReconcile = false;
+ } catch ( ... ) {
+ this->skipReconcile = false;
+ LFA_Close ( updateRef );
+ this->parent->filePath = origPath;
+ this->parent->fileRef = origRef;
+ throw;
+ }
+
+ LFA_Close ( origRef );
+ LFA_Delete ( origPath.c_str() );
+
+ LFA_Close ( updateRef );
+ LFA_Rename ( updatePath.c_str(), origPath.c_str() );
+ this->parent->filePath = origPath;
+ this->parent->fileRef = 0;
+
+ }
+
+ this->needsUpdate = false;
+
+} // PSD_MetaHandler::UpdateFile
+
+// =================================================================================================
+// PSD_MetaHandler::WriteFile
+// ==========================
+
+// The metadata parts of a Photoshop file are all in the image resources. The PSIR_Manager's
+// UpdateFileResources method will take care of the image resource portion of the file, updating
+// those resources that have changed and preserving those that have not.
+
+void PSD_MetaHandler::WriteFile ( LFA_FileRef sourceRef, const std::string & sourcePath )
+{
+ LFA_FileRef destRef = this->parent->fileRef;
+
+ XMP_AbortProc abortProc = this->parent->abortProc;
+ void * abortArg = this->parent->abortArg;
+ const bool checkAbort = (abortProc != 0);
+
+ XMP_Uns32 sourceLen = (XMP_Uns32) LFA_Measure ( sourceRef );
+ if ( sourceLen == 0 ) return; // Tolerate empty files.
+
+ // Reconcile the legacy metadata, unless this is called from UpdateFile. Reserialize the XMP to
+ // get standard padding, PutXMP has probably done an in-place serialize. Set the XMP image resource.
+
+ if ( ! skipReconcile ) {
+ ExportXMPtoJTP ( kXMP_PhotoshopFile, &this->xmpObj, this->exifMgr, &this->psirMgr, this->iptcMgr );
+ }
+
+ this->xmpObj.SerializeToBuffer ( &this->xmpPacket, kXMP_UseCompactFormat );
+ this->packetInfo.offset = kXMPFiles_UnknownOffset;
+ this->packetInfo.length = this->xmpPacket.size();
+ this->packetInfo.padSize = GetPacketPadSize ( this->xmpPacket.c_str(), this->xmpPacket.size() );
+
+ this->psirMgr.SetImgRsrc ( kPSIR_XMP, this->xmpPacket.c_str(), this->xmpPacket.size() );
+
+ // Copy the file header and color mode section, then write the updated image resource section,
+ // and copy the tail of the source file (layer and mask section to EOF).
+
+ LFA_Seek ( sourceRef, 0, SEEK_SET );
+ LFA_Truncate (destRef, 0 );
+
+ LFA_Copy ( sourceRef, destRef, 26 ); // Copy the file header.
+
+ XMP_Uns32 cmLen;
+ LFA_Read ( sourceRef, &cmLen, 4 );
+ LFA_Write ( destRef, &cmLen, 4 ); // Copy the color mode section length.
+ cmLen = GetUns32BE ( &cmLen );
+ LFA_Copy ( sourceRef, destRef, cmLen ); // Copy the color mode section contents.
+
+ XMP_Uns32 irLen;
+ LFA_Read ( sourceRef, &irLen, 4 ); // Get the source image resource section length.
+ irLen = GetUns32BE ( &irLen );
+
+ this->psirMgr.UpdateFileResources ( sourceRef, destRef, 0, abortProc, abortArg );
+
+ XMP_Uns32 tailOffset = 26 + 4 + cmLen + 4 + irLen;
+ XMP_Uns32 tailLength = sourceLen - tailOffset;
+
+ LFA_Seek ( sourceRef, tailOffset, SEEK_SET );
+ LFA_Seek ( destRef, 0, SEEK_END );
+ LFA_Copy ( sourceRef, destRef, tailLength ); // Copy the tail of the file.
+
+ this->needsUpdate = false;
+
+} // PSD_MetaHandler::WriteFile
+
+// =================================================================================================
diff --git a/source/XMPFiles/FileHandlers/PSD_Handler.hpp b/source/XMPFiles/FileHandlers/PSD_Handler.hpp
new file mode 100644
index 0000000..385d9bf
--- /dev/null
+++ b/source/XMPFiles/FileHandlers/PSD_Handler.hpp
@@ -0,0 +1,74 @@
+#ifndef __PSD_Handler_hpp__
+#define __PSD_Handler_hpp__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "TIFF_Support.hpp"
+#include "PSIR_Support.hpp"
+#include "IPTC_Support.hpp"
+
+// =================================================================================================
+/// \file PSD_Handler.hpp
+/// \brief File format handler for PSD (Photoshop).
+///
+/// This header ...
+///
+// =================================================================================================
+
+// *** Could derive from Basic_Handler - buffer file tail in a temp file.
+
+extern XMPFileHandler * PSD_MetaHandlerCTor ( XMPFiles * parent );
+
+extern bool PSD_CheckFormat ( XMP_FileFormat format,
+ XMP_StringPtr filePath,
+ LFA_FileRef fileRef,
+ XMPFiles * parent );
+
+static const XMP_OptionBits kPSD_HandlerFlags = (kXMPFiles_CanInjectXMP |
+ kXMPFiles_CanExpand |
+ kXMPFiles_CanRewrite |
+ kXMPFiles_PrefersInPlace |
+ kXMPFiles_CanReconcile |
+ kXMPFiles_AllowsOnlyXMP |
+ kXMPFiles_ReturnsRawPacket |
+ kXMPFiles_ReturnsTNail |
+ kXMPFiles_AllowsSafeUpdate);
+
+class PSD_MetaHandler : public XMPFileHandler
+{
+public:
+
+ void CacheFileData();
+ void ProcessTNail();
+ void ProcessXMP();
+
+ void UpdateFile ( bool doSafeUpdate );
+ void WriteFile ( LFA_FileRef sourceRef, const std::string & sourcePath );
+
+ bool skipReconcile; // ! Used between UpdateFile and WriteFile.
+
+ PSD_MetaHandler ( XMPFiles * parent );
+ virtual ~PSD_MetaHandler();
+
+private:
+
+ PSD_MetaHandler() : iptcMgr(0), exifMgr(0), skipReconcile(false) {}; // Hidden on purpose.
+
+ PSIR_FileWriter psirMgr; // Don't need a pointer, the PSIR part is always file-based.
+ IPTC_Manager * iptcMgr; // Need to use pointers so we can properly select between read-only
+ TIFF_Manager * exifMgr; // and read-write modes of usage.
+
+ XMP_Uns32 imageWidth, imageHeight; // Pixel dimensions, used with thumbnail info.
+
+}; // PSD_MetaHandler
+
+// =================================================================================================
+
+#endif /* __PSD_Handler_hpp__ */
diff --git a/source/XMPFiles/FileHandlers/PostScript_Handler.cpp b/source/XMPFiles/FileHandlers/PostScript_Handler.cpp
new file mode 100644
index 0000000..316b37c
--- /dev/null
+++ b/source/XMPFiles/FileHandlers/PostScript_Handler.cpp
@@ -0,0 +1,578 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "XMPScanner.hpp"
+
+#include "Scanner_Handler.hpp"
+#include "PostScript_Handler.hpp"
+
+using namespace std;
+
+// =================================================================================================
+/// \file PostScript_Handler.cpp
+/// \brief File format handler for PostScript and EPS files.
+///
+/// This header ...
+///
+// =================================================================================================
+
+static const char * kPSFileTag = "%!PS-Adobe-";
+static const int kPSFileTagLen = strlen ( kPSFileTag );
+
+// =================================================================================================
+// PostScript_MetaHandlerCTor
+// ==========================
+
+XMPFileHandler * PostScript_MetaHandlerCTor ( XMPFiles * parent )
+{
+ XMPFileHandler * newHandler = new PostScript_MetaHandler ( parent );
+
+ return newHandler;
+
+} // PostScript_MetaHandlerCTor
+
+// =================================================================================================
+// PostScript_CheckFormat
+// ======================
+
+bool PostScript_CheckFormat ( XMP_FileFormat format,
+ XMP_StringPtr filePath,
+ LFA_FileRef fileRef,
+ XMPFiles * parent )
+{
+ IgnoreParam(filePath); IgnoreParam(parent);
+ XMP_Assert ( (format == kXMP_EPSFile) || (format == kXMP_PostScriptFile) );
+
+ IOBuffer ioBuf;
+
+ XMP_Int64 psOffset;
+ size_t psLength;
+ long temp1, temp2;
+
+ // Check for the binary EPSF preview header.
+
+ LFA_Seek ( fileRef, 0, SEEK_SET );
+ if ( ! CheckFileSpace ( fileRef, &ioBuf, 4 ) ) return false;
+ temp1 = GetUns32BE ( ioBuf.ptr );
+
+ if ( temp1 == (long)0xC5D0D3C6 ) {
+
+ if ( ! CheckFileSpace ( fileRef, &ioBuf, 30 ) ) return false;
+
+ psOffset = GetUns32LE ( ioBuf.ptr+4 ); // PostScript offset.
+ psLength = GetUns32LE ( ioBuf.ptr+8 ); // PostScript length.
+
+ bool ok;
+ LFA_Seek ( fileRef, psOffset, SEEK_SET, &ok );
+ if ( ! ok ) return false; // Don't throw for a failure.
+
+ ioBuf.ptr = ioBuf.limit; // Make sure RefillBuffer does a simple read.
+ RefillBuffer ( fileRef, &ioBuf );
+ if ( (ioBuf.len < kIOBufferSize) && (ioBuf.len < psLength) ) return false; // Not enough PostScript.
+
+ }
+
+ // Check the start of the PostScript DSC header comment.
+
+ if ( ! CheckFileSpace ( fileRef, &ioBuf, (kPSFileTagLen + 3 + 1) ) ) return false;
+ if ( ! CheckBytes ( ioBuf.ptr, Uns8Ptr(kPSFileTag), kPSFileTagLen ) ) return false;
+ ioBuf.ptr += kPSFileTagLen;
+
+ // Check the PostScript DSC major version number.
+
+ temp1 = LONG_MIN; // Will safely overflow if there are digits, remain negative if there aren't.
+ while ( (ioBuf.ptr < ioBuf.limit) && ('0' <= *ioBuf.ptr) && (*ioBuf.ptr <= '9') ) {
+ temp1 = (temp1 * 10) + (*ioBuf.ptr - '0');
+ if ( temp1 < 0 ) return false; // Overflow.
+ ioBuf.ptr += 1;
+ }
+ // if ( temp1 < 0 ) break; *** Covered by 3.0 check.
+ if ( temp1 < 3 ) return false; // The version must be at least 3.0.
+
+ if ( ! CheckFileSpace ( fileRef, &ioBuf, 3 ) ) return false;
+ if ( *ioBuf.ptr != '.' ) return false; // No minor number.
+ ioBuf.ptr += 1;
+
+ // Check the PostScript DSC minor version number.
+
+ temp2 = LONG_MIN; // Will safely overflow if there are digits, remain negative if there aren't.
+ while ( (ioBuf.ptr < ioBuf.limit) && ('0' <= *ioBuf.ptr) && (*ioBuf.ptr <= '9') ) {
+ temp2 = (temp2 * 10) + (*ioBuf.ptr - '0');
+ if ( temp2 < 0 ) return false; // Overflow.
+ ioBuf.ptr += 1;
+ }
+ if ( temp2 < 0 ) return false; // No digits or overflow.
+ // Note that we don't care about the actual minor version number.
+
+ if ( format == kXMP_PostScriptFile ) {
+
+ // Almost done for plain PostScript, check for whitespace.
+
+ if ( ! CheckFileSpace ( fileRef, &ioBuf, 1 ) ) return false;
+ if ( (*ioBuf.ptr != ' ') && (*ioBuf.ptr != kLF) && (*ioBuf.ptr != kCR) ) return false;
+ ioBuf.ptr += 1;
+
+ } else {
+
+ // Check for the EPSF keyword on the header comment.
+
+ if ( ! CheckFileSpace ( fileRef, &ioBuf, 6+3+1 ) ) return false;
+ if ( ! CheckBytes ( ioBuf.ptr, Uns8Ptr(" EPSF-"), 6 ) ) return false;
+ ioBuf.ptr += 6;
+
+ // Check the EPS major version number.
+
+ temp1 = LONG_MIN; // Will safely overflow if there are digits, remain negative if there aren't.
+ while ( (ioBuf.ptr < ioBuf.limit) && ('0' <= *ioBuf.ptr) && (*ioBuf.ptr <= '9') ) {
+ temp1 = (temp1 * 10) + (*ioBuf.ptr - '0');
+ if ( temp1 < 0 ) return false; // Overflow.
+ ioBuf.ptr += 1;
+ }
+ // if ( temp1 < 0 ) break; *** Covered by 3.0 check.
+ if ( temp1 < 3 ) return false; // The version must be at least 3.0.
+
+ if ( ! CheckFileSpace ( fileRef, &ioBuf, 3 ) ) return false;
+ if ( *ioBuf.ptr != '.' ) return false; // No minor number.
+ ioBuf.ptr += 1;
+
+ // Check the EPS minor version number.
+
+ temp2 = LONG_MIN; // Will safely overflow if there are digits, remain negative if there aren't.
+ while ( (ioBuf.ptr < ioBuf.limit) && ('0' <= *ioBuf.ptr) && (*ioBuf.ptr <= '9') ) {
+ temp2 = (temp2 * 10) + (*ioBuf.ptr - '0');
+ if ( temp2 < 0 ) return false; // Overflow.
+ ioBuf.ptr += 1;
+ }
+ if ( temp2 < 0 ) return false; // No digits or overflow.
+ // Note that we don't care about the actual minor version number.
+
+ if ( ! CheckFileSpace ( fileRef, &ioBuf, 1 ) ) return false;
+ if ( (*ioBuf.ptr != kLF) && (*ioBuf.ptr != kCR) ) return false;
+ ioBuf.ptr += 1;
+
+ }
+
+ return true;
+
+} // PostScript_CheckFormat
+
+// =================================================================================================
+// PostScript_MetaHandler::PostScript_MetaHandler
+// ==============================================
+
+PostScript_MetaHandler::PostScript_MetaHandler ( XMPFiles * _parent )
+{
+ this->parent = _parent;
+ this->handlerFlags = kPostScript_HandlerFlags;
+ this->stdCharForm = kXMP_Char8Bit;
+ this->psHint = kPSHint_NoMarker;
+
+} // PostScript_MetaHandler::PostScript_MetaHandler
+
+// =================================================================================================
+// PostScript_MetaHandler::~PostScript_MetaHandler
+// ===============================================
+
+PostScript_MetaHandler::~PostScript_MetaHandler()
+{
+ // ! Inherit the base cleanup.
+
+} // PostScript_MetaHandler::~PostScript_MetaHandler
+
+// =================================================================================================
+// PostScript_MetaHandler::FindPostScriptHint
+// ==========================================
+//
+// Search for "%ADO_ContainsXMP:" at the beginning of a line, it must be before "%%EndComments". If
+// the XMP marker is found, look for the MainFirst/MainLast/NoMain options.
+
+static const char * kPSContainsXMPString = "%ADO_ContainsXMP:";
+static const int kPSContainsXMPLength = strlen ( kPSContainsXMPString );
+
+static const char * kPSEndCommentString = "%%EndComments"; // ! Assumed shorter than kPSContainsXMPString.
+static const int kPSEndCommentLength = strlen ( kPSEndCommentString );
+
+int PostScript_MetaHandler::FindPostScriptHint()
+{
+ bool found = false;
+ IOBuffer ioBuf;
+ XMP_Uns8 ch;
+
+ LFA_FileRef fileRef = this->parent->fileRef;
+
+ XMP_AbortProc abortProc = this->parent->abortProc;
+ void * abortArg = this->parent->abortArg;
+ const bool checkAbort = (abortProc != 0);
+
+ // Check for the binary EPSF preview header.
+
+ LFA_Seek ( fileRef, 0, SEEK_SET );
+ if ( ! CheckFileSpace ( fileRef, &ioBuf, 4 ) ) return false;
+ long temp1 = GetUns32BE ( ioBuf.ptr );
+
+ if ( temp1 == (long)0xC5D0D3C6 ) {
+
+ if ( ! CheckFileSpace ( fileRef, &ioBuf, 30 ) ) return false;
+
+ size_t psOffset = GetUns32LE ( ioBuf.ptr+4 ); // PostScript offset.
+ size_t psLength = GetUns32LE ( ioBuf.ptr+8 ); // PostScript length.
+
+ bool ok;
+ LFA_Seek ( fileRef, psOffset, SEEK_SET, &ok );
+ if ( ! ok ) return false; // Don't throw for a failure.
+
+ ioBuf.ptr = ioBuf.limit; // Force the next check to refill the buffer.
+
+ }
+
+ // Look for the ContainsXMP comment.
+
+ while ( true ) {
+
+ if ( checkAbort && abortProc(abortArg) ) {
+ XMP_Throw ( "PostScript_MetaHandler::FindPostScriptHint - User abort", kXMPErr_UserAbort );
+ }
+
+ if ( ! CheckFileSpace ( fileRef, &ioBuf, kPSContainsXMPLength ) ) return kPSHint_NoMarker;
+
+ if ( CheckBytes ( ioBuf.ptr, Uns8Ptr(kPSEndCommentString), kPSEndCommentLength ) ) {
+
+ // Found "%%EndComments", don't look any further.
+ return kPSHint_NoMarker;
+
+ } else if ( ! CheckBytes ( ioBuf.ptr, Uns8Ptr(kPSContainsXMPString), kPSContainsXMPLength ) ) {
+
+ // Not "%%EndComments" or "%ADO_ContainsXMP:", skip past the end of this line.
+ do {
+ if ( ! CheckFileSpace ( fileRef, &ioBuf, 1 ) ) return kPSHint_NoMarker;
+ ch = *ioBuf.ptr;
+ ++ioBuf.ptr;
+ } while ( ! IsNewline ( ch ) );
+
+ } else {
+
+ // Found "%ADO_ContainsXMP:", look for the main packet location option.
+
+ ioBuf.ptr += kPSContainsXMPLength;
+ int xmpHint = kPSHint_NoMain; // ! From here on, a failure means "no main", not "no marker".
+ if ( ! CheckFileSpace ( fileRef, &ioBuf, 1 ) ) return kPSHint_NoMain;
+ if ( ! IsSpaceOrTab ( *ioBuf.ptr ) ) return kPSHint_NoMain;
+
+ while ( true ) {
+
+ while ( true ) { // Skip leading spaces and tabs.
+ if ( ! CheckFileSpace ( fileRef, &ioBuf, 1 ) ) return kPSHint_NoMain;
+ if ( ! IsSpaceOrTab ( *ioBuf.ptr ) ) break;
+ ++ioBuf.ptr;
+ }
+ if ( IsNewline ( *ioBuf.ptr ) ) return kPSHint_NoMain; // Reached the end of the ContainsXMP comment.
+
+ if ( ! CheckFileSpace ( fileRef, &ioBuf, 6 ) ) return kPSHint_NoMain;
+
+ if ( CheckBytes ( ioBuf.ptr, Uns8Ptr("NoMain"), 6 ) ) {
+
+ ioBuf.ptr += 6;
+ xmpHint = kPSHint_NoMain;
+ break;
+
+ } else if ( CheckBytes ( ioBuf.ptr, Uns8Ptr("MainFi"), 6 ) ) {
+
+ ioBuf.ptr += 6;
+ if ( ! CheckFileSpace ( fileRef, &ioBuf, 3 ) ) return kPSHint_NoMain;
+ if ( CheckBytes ( ioBuf.ptr, Uns8Ptr("rst"), 3 ) ) {
+ ioBuf.ptr += 3;
+ xmpHint = kPSHint_MainFirst;
+ }
+ break;
+
+ } else if ( CheckBytes ( ioBuf.ptr, Uns8Ptr("MainLa"), 6 ) ) {
+
+ ioBuf.ptr += 6;
+ if ( ! CheckFileSpace ( fileRef, &ioBuf, 2 ) ) return kPSHint_NoMain;
+ if ( CheckBytes ( ioBuf.ptr, Uns8Ptr("st"), 2 ) ) {
+ ioBuf.ptr += 2;
+ xmpHint = kPSHint_MainLast;
+ }
+ break;
+
+ } else {
+
+ while ( true ) { // Skip until whitespace.
+ if ( ! CheckFileSpace ( fileRef, &ioBuf, 1 ) ) return kPSHint_NoMain;
+ if ( IsWhitespace ( *ioBuf.ptr ) ) break;
+ ++ioBuf.ptr;
+ }
+
+ }
+
+ } // Look for the main packet location option.
+
+ // Make sure we found exactly a known option.
+ if ( ! CheckFileSpace ( fileRef, &ioBuf, 1 ) ) return kPSHint_NoMain;
+ if ( ! IsWhitespace ( *ioBuf.ptr ) ) return kPSHint_NoMain;
+ return xmpHint;
+
+ } // Found "%ADO_ContainsXMP:".
+
+ } // Outer marker loop.
+
+ return kPSHint_NoMarker; // Should never reach here.
+
+} // PostScript_MetaHandler::FindPostScriptHint
+
+
+// =================================================================================================
+// PostScript_MetaHandler::FindFirstPacket
+// =======================================
+//
+// Run the packet scanner until we find a valid packet. The first one is the main. For simplicity,
+// the state of all snips is checked after each buffer is read. In theory only the last of the
+// previous snips might change from partial to valid, but then we would have to special case the
+// first pass when there is no previous set of snips. Since we have to get a full report to look at
+// the last snip anyway, it costs virtually nothing extra to recheck all of the snips.
+
+bool PostScript_MetaHandler::FindFirstPacket()
+{
+ int snipCount;
+ bool found = false;
+ size_t bufPos, bufLen;
+
+ LFA_FileRef fileRef = this->parent->fileRef;
+ XMP_Int64 fileLen = LFA_Measure ( fileRef );
+ XMP_PacketInfo & packetInfo = this->packetInfo;
+
+ XMPScanner scanner ( fileLen );
+ XMPScanner::SnipInfoVector snips;
+
+ enum { kBufferSize = 64*1024 };
+ XMP_Uns8 buffer [kBufferSize];
+
+ XMP_AbortProc abortProc = this->parent->abortProc;
+ void * abortArg = this->parent->abortArg;
+ const bool checkAbort = (abortProc != 0);
+
+ bufPos = 0;
+ bufLen = 0;
+
+ LFA_Seek ( fileRef, 0, SEEK_SET ); // Seek back to the beginning of the file.
+
+ while ( true ) {
+
+ if ( checkAbort && abortProc(abortArg) ) {
+ XMP_Throw ( "PostScript_MetaHandler::FindFirstPacket - User abort", kXMPErr_UserAbort );
+ }
+
+ bufPos += bufLen;
+ bufLen = LFA_Read ( fileRef, buffer, kBufferSize );
+ if ( bufLen == 0 ) return false; // Must be at EoF, no packets found.
+
+ scanner.Scan ( buffer, bufPos, bufLen );
+ snipCount = scanner.GetSnipCount();
+ scanner.Report ( snips );
+
+ for ( int i = 0; i < snipCount; ++i ) {
+ if ( snips[i].fState == XMPScanner::eValidPacketSnip ) {
+ if ( snips[i].fLength > 0x7FFFFFFF ) XMP_Throw ( "PostScript_MetaHandler::FindFirstPacket: Oversize packet", kXMPErr_BadXMP );
+ packetInfo.offset = snips[i].fOffset;
+ packetInfo.length = (XMP_Int32)snips[i].fLength;
+ packetInfo.charForm = snips[i].fCharForm;
+ packetInfo.writeable = (snips[i].fAccess == 'w');
+ return true;
+ }
+ }
+
+ }
+
+ return false;
+
+} // FindFirstPacket
+
+
+// =================================================================================================
+// PostScript_MetaHandler::FindLastPacket
+// ======================================
+//
+// Run the packet scanner backwards until we find the start of a packet, or a valid packet. If we
+// found a packet start, resume forward scanning to see if it is a valid packet. For simplicity, all
+// of the snips are checked on each pass, for much the same reasons as in FindFirstPacket.
+
+#if 1
+
+// *** Doing this right (as described above) requires out of order scanning support which isn't
+// *** implemented yet. For now we scan the whole file and pick the last valid packet.
+
+bool PostScript_MetaHandler::FindLastPacket()
+{
+ int pkt;
+ size_t bufPos, bufLen;
+
+ LFA_FileRef fileRef = this->parent->fileRef;
+ XMP_Int64 fileLen = LFA_Measure ( fileRef );
+ XMP_PacketInfo & packetInfo = this->packetInfo;
+
+ // ------------------------------------------------------
+ // Scan the entire file to find all of the valid packets.
+
+ XMPScanner scanner ( fileLen );
+
+ enum { kBufferSize = 64*1024 };
+ XMP_Uns8 buffer [kBufferSize];
+
+ XMP_AbortProc abortProc = this->parent->abortProc;
+ void * abortArg = this->parent->abortArg;
+ const bool checkAbort = (abortProc != 0);
+
+ LFA_Seek ( fileRef, 0, SEEK_SET ); // Seek back to the beginning of the file.
+
+ for ( bufPos = 0; bufPos < fileLen; bufPos += bufLen ) {
+ if ( checkAbort && abortProc(abortArg) ) {
+ XMP_Throw ( "PostScript_MetaHandler::FindLastPacket - User abort", kXMPErr_UserAbort );
+ }
+ bufLen = LFA_Read ( fileRef, buffer, kBufferSize );
+ if ( bufLen == 0 ) XMP_Throw ( "PostScript_MetaHandler::FindLastPacket: Read failure", kXMPErr_ExternalFailure );
+ scanner.Scan ( buffer, bufPos, bufLen );
+ }
+
+ // -------------------------------
+ // Pick the last the valid packet.
+
+ long snipCount = scanner.GetSnipCount();
+
+ XMPScanner::SnipInfoVector snips ( snipCount );
+ scanner.Report ( snips );
+
+ for ( pkt = snipCount-1; pkt >= 0; --pkt ) {
+ if ( snips[pkt].fState == XMPScanner::eValidPacketSnip ) break;
+ }
+
+ if ( pkt >= 0 ) {
+ if ( snips[pkt].fLength > 0x7FFFFFFF ) XMP_Throw ( "PostScript_MetaHandler::FindLastPacket: Oversize packet", kXMPErr_BadXMP );
+ packetInfo.offset = snips[pkt].fOffset;
+ packetInfo.length = (XMP_Int32)snips[pkt].fLength;
+ packetInfo.charForm = snips[pkt].fCharForm;
+ packetInfo.writeable = (snips[pkt].fAccess == 'w');
+ return true;
+ }
+
+ return false;
+
+} // PostScript_MetaHandler::FindLastPacket
+
+#else
+
+bool PostScript_MetaHandler::FindLastPacket()
+{
+ int err, snipCount;
+ bool found = false;
+ XMP_Int64 backPos, backLen;
+ size_t ioCount;
+
+ LFA_FileRef fileRef = this->parent->fileRef;
+ XMP_Int64 fileLen = LFA_Measure ( fileRef );
+ XMP_PacketInfo & packetInfo = this->packetInfo;
+
+ XMPScanner scanner ( fileLen );
+ XMPScanner::SnipInfoVector snips;
+
+ enum { kBufferSize = 64*1024 };
+ XMP_Uns8 buffer [kBufferSize];
+
+ XMP_AbortProc abortProc = this->parent->abortProc;
+ void * abortArg = this->parent->abortArg;
+ const bool checkAbort = (abortProc != 0);
+
+ backPos = fileLen;
+ backLen = 0;
+
+ while ( true ) {
+
+ if ( checkAbort && abortProc(abortArg) ) {
+ XMP_Throw ( "PostScript_MetaHandler::FindLastPacket - User abort", kXMPErr_UserAbort );
+ }
+
+ backLen = kBufferSize;
+ if ( backPos < kBufferSize ) backLen = backPos;
+ if ( backLen == 0 ) return false; // Must be at BoF, no packets found.
+
+ backPos -= backLen;
+ LFA_Seek ( fileRef, backPos, SEEK_SET ); // Seek back to the start of the next buffer.
+
+ #error "ioCount is 32 bits, backLen is 64"
+ ioCount = LFA_Read ( fileRef, buffer, backLen );
+ if ( ioCount != backLen ) XMP_Throw ( "PostScript_MetaHandler::FindLastPacket: Read failure", kXMPErr_ExternalFailure );
+
+ scanner.Scan ( buffer, backPos, backLen );
+ snipCount = scanner.GetSnipCount();
+ scanner.Report ( snips );
+
+ for ( int i = snipCount-1; i >= 0; --i ) {
+
+ if ( snips[i].fState == XMPScanner::eValidPacketSnip ) {
+
+ return VerifyMainPacket ( fileRef, snips[i].fOffset, snips[i].fLength, format, beLenient, mainInfo );
+
+ } else if ( snips[i].fState == XMPScanner::ePartialPacketSnip ) {
+
+ // This part is a tad tricky. We have a partial packet, so we need to scan
+ // forward from its ending to see if it is a valid packet. Snips won't recombine,
+ // the partial snip will change state. Be careful with the I/O to not clobber the
+ // backward scan positions, so that it can be resumed if necessary.
+
+ size_t fwdPos = snips[i].fOffset + snips[i].fLength;
+ LFA_Seek ( fileRef, fwdPos, SEEK_SET ); // Seek to the end of the partial snip.
+
+ while ( (fwdPos < fileLen) && (snips[i].fState == XMPScanner::ePartialPacketSnip) ) {
+ ioCount = LFA_Read ( fileRef, buffer, kBufferSize );
+ if ( ioCount == 0 ) XMP_Throw ( "PostScript_MetaHandler::FindLastPacket: Read failure", kXMPErr_ExternalFailure );
+ scanner.Scan ( buffer, fwdPos, ioCount );
+ scanner.Report ( snips );
+ fwdPos += ioCount;
+ }
+
+ if ( snips[i].fState == XMPScanner::eValidPacketSnip ) {
+ if ( snips[i].fLength > 0x7FFFFFFF ) XMP_Throw ( "PostScript_MetaHandler::FindLastPacket: Oversize packet", kXMPErr_BadXMP );
+ packetInfo.offset = snips[i].fOffset;
+ packetInfo.length = (XMP_Int32)snips[i].fLength;
+ packetInfo.charForm = snips[i].fCharForm;
+ packetInfo.writeable = (snips[i].fAccess == 'w');
+ return true;
+ }
+
+ }
+
+ } // Backwards snip loop.
+
+ } // Backwards read loop.
+
+ return false; // Should never get here.
+
+} // PostScript_MetaHandler::FindLastPacket
+
+#endif
+
+// =================================================================================================
+// PostScript_MetaHandler::CacheFileData
+// =====================================
+
+void PostScript_MetaHandler::CacheFileData()
+{
+ this->containsXMP = false;
+ this->psHint = FindPostScriptHint();
+
+ if ( this->psHint == kPSHint_MainFirst ) {
+ this->containsXMP = FindFirstPacket();
+ } else if ( this->psHint == kPSHint_MainLast ) {
+ this->containsXMP = FindLastPacket();
+ }
+
+ if ( this->containsXMP ) ReadXMPPacket ( this );
+
+} // PostScript_MetaHandler::CacheFileData
+
+// =================================================================================================
diff --git a/source/XMPFiles/FileHandlers/PostScript_Handler.hpp b/source/XMPFiles/FileHandlers/PostScript_Handler.hpp
new file mode 100644
index 0000000..4170451
--- /dev/null
+++ b/source/XMPFiles/FileHandlers/PostScript_Handler.hpp
@@ -0,0 +1,63 @@
+#ifndef __PostScript_Handler_hpp__
+#define __PostScript_Handler_hpp__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "Trivial_Handler.hpp"
+
+// =================================================================================================
+/// \file PostScript_Handler.hpp
+/// \brief File format handler for PostScript and EPS files.
+///
+/// This header ...
+///
+// =================================================================================================
+
+// *** This probably could be derived from Basic_Handler, buffer the file tail in a temp file.
+
+extern XMPFileHandler * PostScript_MetaHandlerCTor ( XMPFiles * parent );
+
+extern bool PostScript_CheckFormat ( XMP_FileFormat format,
+ XMP_StringPtr filePath,
+ LFA_FileRef fileRef,
+ XMPFiles * parent );
+
+static const XMP_OptionBits kPostScript_HandlerFlags = kTrivial_HandlerFlags;
+
+enum {
+ kPSHint_NoMarker = 0,
+ kPSHint_NoMain = 1,
+ kPSHint_MainFirst = 2,
+ kPSHint_MainLast = 3
+};
+
+class PostScript_MetaHandler : public Trivial_MetaHandler
+{
+public:
+
+ PostScript_MetaHandler ( XMPFiles * parent );
+ ~PostScript_MetaHandler();
+
+ void CacheFileData();
+
+ int psHint;
+
+protected:
+
+ int FindPostScriptHint();
+
+ bool FindFirstPacket();
+ bool FindLastPacket();
+
+}; // PostScript_MetaHandler
+
+// =================================================================================================
+
+#endif /* __PostScript_Handler_hpp__ */
diff --git a/source/XMPFiles/FileHandlers/Scanner_Handler.cpp b/source/XMPFiles/FileHandlers/Scanner_Handler.cpp
new file mode 100644
index 0000000..8d704a6
--- /dev/null
+++ b/source/XMPFiles/FileHandlers/Scanner_Handler.cpp
@@ -0,0 +1,338 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include <vector>
+
+#include "XMPScanner.hpp"
+
+#include "Scanner_Handler.hpp"
+
+using namespace std;
+
+// =================================================================================================
+/// \file Scanner_Handler.cpp
+/// \brief File format handler for packet scanning.
+///
+/// This header ...
+///
+// =================================================================================================
+
+struct CandidateInfo {
+ XMP_PacketInfo packetInfo;
+ std::string xmpPacket;
+ SXMPMeta * xmpObj;
+};
+
+// =================================================================================================
+// Scanner_MetaHandlerCTor
+// =======================
+
+XMPFileHandler * Scanner_MetaHandlerCTor ( XMPFiles * parent )
+{
+ return new Scanner_MetaHandler ( parent );
+
+} // Scanner_MetaHandlerCTor
+
+// =================================================================================================
+// Scanner_MetaHandler::Scanner_MetaHandler
+// ========================================
+
+Scanner_MetaHandler::Scanner_MetaHandler ( XMPFiles * _parent )
+{
+ this->parent = _parent;
+ this->handlerFlags = kScanner_HandlerFlags;
+
+} // Scanner_MetaHandler::Scanner_MetaHandler
+
+// =================================================================================================
+// Scanner_MetaHandler::~Scanner_MetaHandler
+// =========================================
+
+Scanner_MetaHandler::~Scanner_MetaHandler()
+{
+ // ! Inherit the base cleanup.
+
+} // Scanner_MetaHandler::~Scanner_MetaHandler
+
+// =================================================================================================
+// PickMainPacket
+// ==============
+//
+// Pick the main packet from the vector of candidates. The rules:
+// 1. Use the manifest find containment. Prune contained packets.
+// 2. Use the metadata date to pick the most recent.
+// 3. if lenient, pick the last writeable packet, or the last if all are read only.
+
+static int
+PickMainPacket ( std::vector<CandidateInfo>& candidates, bool beLenient )
+{
+ int pkt; // ! Must be signed.
+ int main = -1; // Assume the worst.
+ XMP_OptionBits options;
+
+ int metaCount = candidates.size();
+ if ( metaCount == 0 ) return -1;
+ if ( metaCount == 1 ) return 0;
+
+ // ---------------------------------------------------------------------------------------------
+ // 1. Look at each packet to see if it has a manifest. If it does, prune all of the others that
+ // this one says it contains. Hopefully we'll end up with just one packet. Note that we have to
+ // mark all the children first, then prune. Pruning on the fly means that we won't do a proper
+ // tree discovery if we prune a parent before a child. This would happen if we happened to visit
+ // a grandparent first.
+
+ int child;
+
+ std::vector<bool> pruned ( metaCount, false );
+
+ for ( pkt = 0; pkt < (int)candidates.size(); ++pkt ) {
+
+ // First see if this candidate has a manifest.
+
+ try {
+ std::string voidValue;
+ bool found = candidates[pkt].xmpObj->GetProperty ( kXMP_NS_XMP_MM, "Manifest", &voidValue, &options );
+ if ( (! found) || (! XMP_PropIsArray ( options )) ) continue; // No manifest, or not an array.
+ } catch ( ... ) {
+ continue; // No manifest.
+ };
+
+ // Mark all other candidates that are referred to in this manifest.
+
+ for ( child = 0; child < (int)candidates.size(); ++child ) {
+ if ( pruned[child] || (child == pkt) ) continue; // Skip already pruned ones and self.
+#if 0 // *** Disable for now, SXMPUtils::HasContainedDoc is Adobe private.
+ pruned[child] = SXMPUtils::HasContainedDoc ( *candidates[pkt].xmpObj, *candidates[child].xmpObj );
+#endif
+ }
+
+ }
+
+ // Go ahead and actually remove the marked packets.
+
+ for ( pkt = 0; pkt < (int)candidates.size(); ++pkt ) {
+ if ( pruned[pkt] ) {
+ delete candidates[pkt].xmpObj;
+ candidates[pkt].xmpObj = 0;
+ metaCount -= 1;
+ }
+ }
+
+ // We're done if the containment pruning left us with 0 or 1 candidate.
+
+ if ( metaCount == 0 ) {
+ XMP_Throw ( "GetMainPacket/PickMainPacket: Recursive containment", kXMPErr_BadXMP );
+ } else if ( metaCount == 1 ) {
+ for ( pkt = 0; pkt < (int)candidates.size(); ++pkt ) {
+ if ( candidates[pkt].xmpObj != 0 ) {
+ main = pkt;
+ break;
+ }
+ }
+ }
+
+ if ( main != -1 ) return main; // We found the main.
+
+ // -------------------------------------------------------------------------------------------
+ // 2. Pick the packet with the most recent metadata date. If we are being lenient then missing
+ // dates are older than any real date, and equal dates pick the last packet. If we are being
+ // strict then any missing or equal dates mean we can't pick.
+
+ XMP_DateTime latestTime, currTime;
+
+ for ( pkt = 0; pkt < (int)candidates.size(); ++pkt ) {
+
+ if ( candidates[pkt].xmpObj == 0 ) continue; // This was pruned in the manifest stage.
+
+ bool haveDate = candidates[pkt].xmpObj->GetProperty_Date ( kXMP_NS_XMP, "MetadataDate", &currTime, &options );
+
+ if ( ! haveDate ) {
+
+ if ( ! beLenient ) return -1;
+ if ( main == -1 ) {
+ main = pkt;
+ memset ( &latestTime, 0, sizeof(latestTime) );
+ }
+
+ } else if ( main == -1 ) {
+
+ main = pkt;
+ latestTime = currTime;
+
+ } else {
+
+ int timeOp = SXMPUtils::CompareDateTime ( currTime, latestTime );
+
+ if ( timeOp > 0 ) {
+ main = pkt;
+ latestTime = currTime;
+ } else if ( timeOp == 0 ) {
+ if ( ! beLenient ) return -1;
+ main = pkt;
+ latestTime = currTime;
+ }
+
+ }
+
+ }
+
+ if ( main != -1 ) return main; // We found the main.
+
+ // --------------------------------------------------------------------------------------------
+ // 3. If we're being lenient, pick the last writeable packet, or the last if all are read only.
+
+ if ( beLenient ) {
+
+ for ( pkt = (int)candidates.size()-1; pkt >= 0; --pkt ) {
+ if ( candidates[pkt].xmpObj == 0 ) continue; // This was pruned in the manifest stage.
+ if ( candidates[pkt].packetInfo.writeable ) {
+ main = pkt;
+ break;
+ }
+ }
+
+ if ( main == -1 ) {
+ for ( pkt = (int)candidates.size()-1; pkt >= 0; --pkt ) {
+ if ( candidates[pkt].xmpObj != 0 ) {
+ main = pkt;
+ break;
+ }
+ }
+ }
+
+ }
+
+ return main;
+
+} // PickMainPacket
+
+// =================================================================================================
+// Scanner_MetaHandler::CacheFileData
+// ==================================
+
+void Scanner_MetaHandler::CacheFileData()
+{
+ LFA_FileRef fileRef = this->parent->fileRef;
+ bool beLenient = XMP_OptionIsClear ( this->parent->openFlags, kXMPFiles_OpenStrictly );
+
+ int pkt;
+ XMP_Int64 bufPos;
+ size_t bufLen;
+ SXMPMeta * newMeta;
+
+ XMP_AbortProc abortProc = this->parent->abortProc;
+ void * abortArg = this->parent->abortArg;
+ const bool checkAbort = (abortProc != 0);
+
+ std::vector<CandidateInfo> candidates; // ! These have SXMPMeta* fields, don't leak on exceptions.
+
+ this->containsXMP = false;
+
+ try {
+
+ // ------------------------------------------------------
+ // Scan the entire file to find all of the valid packets.
+
+ XMP_Int64 fileLen = LFA_Measure ( fileRef );
+ XMPScanner scanner ( fileLen );
+
+ enum { kBufferSize = 64*1024 };
+ XMP_Uns8 buffer [kBufferSize];
+
+ LFA_Seek ( fileRef, 0, SEEK_SET );
+
+ for ( bufPos = 0; bufPos < fileLen; bufPos += bufLen ) {
+ if ( checkAbort && abortProc(abortArg) ) {
+ XMP_Throw ( "Scanner_MetaHandler::LocateXMP - User abort", kXMPErr_UserAbort );
+ }
+ bufLen = LFA_Read ( fileRef, buffer, kBufferSize );
+ if ( bufLen == 0 ) XMP_Throw ( "Scanner_MetaHandler::LocateXMP: Read failure", kXMPErr_ExternalFailure );
+ scanner.Scan ( buffer, bufPos, bufLen );
+ }
+
+ // --------------------------------------------------------------
+ // Parse the valid packet snips, building a vector of candidates.
+
+ long snipCount = scanner.GetSnipCount();
+
+ XMPScanner::SnipInfoVector snips ( snipCount );
+ scanner.Report ( snips );
+
+ for ( pkt = 0; pkt < snipCount; ++pkt ) {
+
+ if ( checkAbort && abortProc(abortArg) ) {
+ XMP_Throw ( "Scanner_MetaHandler::LocateXMP - User abort", kXMPErr_UserAbort );
+ }
+
+ // Seek to the packet then try to parse it.
+
+ if ( snips[pkt].fState != XMPScanner::eValidPacketSnip ) continue;
+ LFA_Seek ( fileRef, snips[pkt].fOffset, SEEK_SET );
+ newMeta = new SXMPMeta();
+ std::string xmpPacket;
+ xmpPacket.reserve ( (size_t)snips[pkt].fLength );
+
+ try {
+ for ( bufPos = 0; bufPos < snips[pkt].fLength; bufPos += bufLen ) {
+ bufLen = kBufferSize;
+ if ( (bufPos + bufLen) > snips[pkt].fLength ) bufLen = size_t ( snips[pkt].fLength - bufPos );
+ (void) LFA_Read ( fileRef, buffer, bufLen, kLFA_RequireAll );
+ xmpPacket.append ( (const char *)buffer, bufLen );
+ newMeta->ParseFromBuffer ( (char *)buffer, bufLen, kXMP_ParseMoreBuffers );
+ }
+ newMeta->ParseFromBuffer ( 0, 0, kXMP_NoOptions );
+ } catch ( ... ) {
+ delete newMeta;
+ if ( beLenient ) continue; // Skip if we're being lenient, else rethrow.
+ throw;
+ }
+
+ // It parsed OK, add it to the array of candidates.
+
+ candidates.push_back ( CandidateInfo() );
+ CandidateInfo & newInfo = candidates.back();
+ newInfo.xmpObj = newMeta;
+ newInfo.xmpPacket.swap ( xmpPacket );
+ newInfo.packetInfo.offset = snips[pkt].fOffset;
+ newInfo.packetInfo.length = (XMP_Int32)snips[pkt].fLength;
+ newInfo.packetInfo.charForm = snips[pkt].fCharForm;
+ newInfo.packetInfo.writeable = (snips[pkt].fAccess == 'w');
+
+ }
+
+ // ----------------------------------------
+ // Figure out which packet is the main one.
+
+ int main = PickMainPacket ( candidates, beLenient );
+
+ if ( main != -1 ) {
+ this->packetInfo = candidates[main].packetInfo;
+ this->xmpPacket.swap ( candidates[main].xmpPacket );
+ this->xmpObj = *candidates[main].xmpObj;
+ this->containsXMP = true;
+ this->processedXMP = true;
+ }
+
+ for ( pkt = 0; pkt < (int)candidates.size(); ++pkt ) {
+ if ( candidates[pkt].xmpObj != 0 ) delete candidates[pkt].xmpObj;
+ }
+
+ } catch ( ... ) {
+
+ // Clean up the SXMPMeta* fields from the vector of candidates.
+ for ( pkt = 0; pkt < (int)candidates.size(); ++pkt ) {
+ if ( candidates[pkt].xmpObj != 0 ) delete candidates[pkt].xmpObj;
+ }
+ throw;
+
+ }
+
+} // Scanner_MetaHandler::CacheFileData
+
+// =================================================================================================
diff --git a/source/XMPFiles/FileHandlers/Scanner_Handler.hpp b/source/XMPFiles/FileHandlers/Scanner_Handler.hpp
new file mode 100644
index 0000000..625b565
--- /dev/null
+++ b/source/XMPFiles/FileHandlers/Scanner_Handler.hpp
@@ -0,0 +1,42 @@
+#ifndef __Scanner_Handler_hpp__
+#define __Scanner_Handler_hpp__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "Trivial_Handler.hpp"
+
+// =================================================================================================
+/// \file Scanner_Handler.hpp
+/// \brief File format handler for packet scanning.
+///
+/// This header ...
+///
+// =================================================================================================
+
+extern XMPFileHandler * Scanner_MetaHandlerCTor ( XMPFiles * parent );
+
+static const XMP_OptionBits kScanner_HandlerFlags = kTrivial_HandlerFlags;
+
+class Scanner_MetaHandler : public Trivial_MetaHandler
+{
+public:
+
+ Scanner_MetaHandler () {};
+ Scanner_MetaHandler ( XMPFiles * parent );
+
+ ~Scanner_MetaHandler();
+
+ void CacheFileData();
+
+}; // Scanner_MetaHandler
+
+// =================================================================================================
+
+#endif /* __Scanner_Handler_hpp__ */
diff --git a/source/XMPFiles/FileHandlers/TIFF_Handler.cpp b/source/XMPFiles/FileHandlers/TIFF_Handler.cpp
new file mode 100644
index 0000000..e63b28c
--- /dev/null
+++ b/source/XMPFiles/FileHandlers/TIFF_Handler.cpp
@@ -0,0 +1,379 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "TIFF_Handler.hpp"
+
+#include "TIFF_Support.hpp"
+#include "PSIR_Support.hpp"
+#include "IPTC_Support.hpp"
+#include "ReconcileLegacy.hpp"
+
+#include "MD5.h"
+
+using namespace std;
+
+// =================================================================================================
+/// \file TIFF_Handler.cpp
+/// \brief File format handler for TIFF.
+///
+/// This handler ...
+///
+// =================================================================================================
+
+// =================================================================================================
+// TIFF_CheckFormat
+// ================
+
+// For TIFF we just check for the II/42 or MM/42 in the first 4 bytes and that there are at least
+// 26 bytes of data (4+4+2+12+4).
+//
+// ! The CheckXyzFormat routines don't track the filePos, that is left to ScanXyzFile.
+
+bool TIFF_CheckFormat ( XMP_FileFormat format,
+ XMP_StringPtr filePath,
+ LFA_FileRef fileRef,
+ XMPFiles * parent )
+{
+ IgnoreParam(format); IgnoreParam(filePath); IgnoreParam(parent);
+ XMP_Assert ( format == kXMP_TIFFFile );
+
+ enum { kMinimalTIFFSize = 4+4+2+12+4 }; // Header plus IFD with 1 entry.
+
+ IOBuffer ioBuf;
+
+ LFA_Seek ( fileRef, 0, SEEK_SET );
+ if ( ! CheckFileSpace ( fileRef, &ioBuf, kMinimalTIFFSize ) ) return false;
+
+ bool leTIFF = CheckBytes ( ioBuf.ptr, "\x49\x49\x2A\x00", 4 );
+ bool beTIFF = CheckBytes ( ioBuf.ptr, "\x4D\x4D\x00\x2A", 4 );
+
+ return (leTIFF | beTIFF);
+
+} // TIFF_CheckFormat
+
+// =================================================================================================
+// TIFF_MetaHandlerCTor
+// ====================
+
+XMPFileHandler * TIFF_MetaHandlerCTor ( XMPFiles * parent )
+{
+ return new TIFF_MetaHandler ( parent );
+
+} // TIFF_MetaHandlerCTor
+
+// =================================================================================================
+// TIFF_MetaHandler::TIFF_MetaHandler
+// ==================================
+
+TIFF_MetaHandler::TIFF_MetaHandler ( XMPFiles * _parent ) : psirMgr(0), iptcMgr(0)
+{
+ this->parent = _parent;
+ this->handlerFlags = kTIFF_HandlerFlags;
+ this->stdCharForm = kXMP_Char8Bit;
+
+} // TIFF_MetaHandler::TIFF_MetaHandler
+
+// =================================================================================================
+// TIFF_MetaHandler::~TIFF_MetaHandler
+// ===================================
+
+TIFF_MetaHandler::~TIFF_MetaHandler()
+{
+
+ if ( this->psirMgr != 0 ) delete ( this->psirMgr );
+ if ( this->iptcMgr != 0 ) delete ( this->iptcMgr );
+
+} // TIFF_MetaHandler::~TIFF_MetaHandler
+
+// =================================================================================================
+// TIFF_MetaHandler::CacheFileData
+// ===============================
+//
+// The data caching for TIFF is easy to explain and implement, but does more processing than one
+// might at first expect. This seems unavoidable given the need to close the disk file after calling
+// CacheFileData. We parse the TIFF stream and cache the values for all tags of interest, and note
+// whether XMP is present. We do not parse the XMP, Photoshop image resources, or IPTC datasets.
+
+// *** This implementation simply returns when invalid TIFF is encountered. Should we throw instead?
+
+void TIFF_MetaHandler::CacheFileData()
+{
+ LFA_FileRef fileRef = this->parent->fileRef;
+ XMP_PacketInfo & packetInfo = this->packetInfo;
+
+ XMP_AbortProc abortProc = this->parent->abortProc;
+ void * abortArg = this->parent->abortArg;
+ const bool checkAbort = (abortProc != 0);
+
+ XMP_Assert ( (! this->containsXMP) && (! this->containsTNail) );
+ // Set containsXMP to true here only if the XMP tag is found.
+
+ if ( checkAbort && abortProc(abortArg) ) {
+ XMP_Throw ( "TIFF_MetaHandler::CacheFileData - User abort", kXMPErr_UserAbort );
+ }
+
+ this->tiffMgr.ParseFileStream ( fileRef );
+
+ TIFF_Manager::TagInfo xmpInfo;
+ bool found = this->tiffMgr.GetTag ( kTIFF_PrimaryIFD, kTIFF_XMP, &xmpInfo );
+
+ if ( found ) {
+
+ this->packetInfo.offset = this->tiffMgr.GetValueOffset ( kTIFF_PrimaryIFD, kTIFF_XMP );
+ this->packetInfo.length = xmpInfo.dataLen;
+ this->packetInfo.padSize = 0; // Assume for now, set these properly in ProcessXMP.
+ this->packetInfo.charForm = kXMP_CharUnknown;
+ this->packetInfo.writeable = true;
+
+ this->xmpPacket.assign ( (XMP_StringPtr)xmpInfo.dataPtr, xmpInfo.dataLen );
+
+ this->containsXMP = true;
+
+ }
+
+} // TIFF_MetaHandler::CacheFileData
+
+// =================================================================================================
+// TIFF_MetaHandler::ProcessTNail
+// ==============================
+//
+// Do the same processing as JPEG, even though Exif says that uncompressed images can only have
+// uncompressed thumbnails. Who know what someone might write?
+
+// *** Should extract this code into a utility shared with the JPEG handler.
+
+void TIFF_MetaHandler::ProcessTNail()
+{
+ this->processedTNail = true; // Make sure we only come through here once.
+ this->containsTNail = false; // Set it to true after all of the info is gathered.
+
+ this->containsTNail = this->tiffMgr.GetTNailInfo ( &this->tnailInfo );
+ if ( this->containsTNail ) this->tnailInfo.fileFormat = this->parent->format;
+
+} // TIFF_MetaHandler::ProcessTNail
+
+// =================================================================================================
+// TIFF_MetaHandler::ProcessXMP
+// ============================
+//
+// Process the raw XMP and legacy metadata that was previously cached. The legacy metadata in TIFF
+// is messy because there are 2 copies of the IPTC and because of a Photoshop 6 bug/quirk in the way
+// Exif metadata is saved.
+
+void TIFF_MetaHandler::ProcessXMP()
+{
+
+ this->processedXMP = true; // Make sure we only come through here once.
+
+ // Set up everything for the legacy import, but don't do it yet. This lets us do a forced legacy
+ // import if the XMP packet gets parsing errors.
+
+ // Parse the IPTC and PSIR, determine the last-legacy priority. For TIFF files the relevant
+ // legacy priorities (ignoring Mac pnot and ANPA resources) are:
+ // kLegacyJTP_TIFF_IPTC - highest
+ // kLegacyJTP_TIFF_TIFF_Tags
+ // kLegacyJTP_PSIR_OldCaption
+ // kLegacyJTP_PSIR_IPTC - yes, a TIFF file can have the IPTC in 2 places
+ // kLegacyJTP_None - lowest
+
+ // ! Photoshop 6 wrote annoyingly wacky TIFF files. It buried a lot of the Exif metadata inside
+ // ! image resource 1058, itself inside of tag 34377 in the 0th IFD. Take care of this before
+ // ! doing any of the legacy metadata presence or priority analysis. Delete image resource 1058
+ // ! to get rid of the buried Exif, but don't mark the XMPFiles object as changed. This change
+ // ! should not trigger an update, but should be included as part of a normal update.
+
+ bool found;
+ RecJTP_LegacyPriority lastLegacy = kLegacyJTP_None;
+
+ bool readOnly = ((this->parent->openFlags & kXMPFiles_OpenForUpdate) == 0);
+
+ if ( readOnly ) {
+ this->psirMgr = new PSIR_MemoryReader();
+ this->iptcMgr = new IPTC_Reader();
+ } else {
+ this->psirMgr = new PSIR_FileWriter();
+ this->iptcMgr = new IPTC_Writer();
+ }
+
+ TIFF_Manager & tiff = this->tiffMgr; // Give the compiler help in recognizing non-aliases.
+ PSIR_Manager & psir = *this->psirMgr;
+ IPTC_Manager & iptc = *this->iptcMgr;
+
+ TIFF_Manager::TagInfo psirInfo;
+ bool havePSIR = tiff.GetTag ( kTIFF_PrimaryIFD, kTIFF_PSIR, &psirInfo );
+
+ TIFF_Manager::TagInfo iptcInfo;
+ bool haveIPTC = tiff.GetTag ( kTIFF_PrimaryIFD, kTIFF_IPTC, &iptcInfo ); // The TIFF IPTC tag.
+
+ if ( havePSIR ) { // ! Do the Photoshop 6 integration before other legacy analysis.
+ psir.ParseMemoryResources ( psirInfo.dataPtr, psirInfo.dataLen );
+ PSIR_Manager::ImgRsrcInfo buriedExif;
+ found = psir.GetImgRsrc ( kPSIR_Exif, &buriedExif );
+ if ( found ) {
+ tiff.IntegrateFromPShop6 ( buriedExif.dataPtr, buriedExif.dataLen );
+ if ( ! readOnly ) psir.DeleteImgRsrc ( kPSIR_Exif );
+ }
+ }
+
+ if ( haveIPTC ) { // At this point "haveIPTC" means from TIFF tag 33723.
+ iptc.ParseMemoryDataSets ( iptcInfo.dataPtr, iptcInfo.dataLen );
+ lastLegacy = kLegacyJTP_TIFF_IPTC;
+ }
+
+ if ( lastLegacy < kLegacyJTP_TIFF_TIFF_Tags ) {
+ found = tiff.GetTag ( kTIFF_PrimaryIFD, kTIFF_ImageDescription, 0 );
+ if ( ! found ) found = tiff.GetTag ( kTIFF_PrimaryIFD, kTIFF_Artist, 0 );
+ if ( ! found ) found = tiff.GetTag ( kTIFF_PrimaryIFD, kTIFF_Copyright, 0 );
+ if ( found ) lastLegacy = kLegacyJTP_TIFF_TIFF_Tags;
+ }
+
+ if ( havePSIR ) {
+
+ if ( lastLegacy < kLegacyJTP_PSIR_OldCaption ) {
+ found = psir.GetImgRsrc ( kPSIR_OldCaption, 0 );
+ if ( ! found ) found = psir.GetImgRsrc ( kPSIR_OldCaptionPStr, 0 );
+ if ( found ) lastLegacy = kLegacyJTP_PSIR_OldCaption;
+ }
+
+ if ( ! haveIPTC ) {
+ PSIR_Manager::ImgRsrcInfo iptcInfo;
+ haveIPTC = psir.GetImgRsrc ( kPSIR_IPTC, &iptcInfo );
+ if ( haveIPTC ) {
+ iptc.ParseMemoryDataSets ( iptcInfo.dataPtr, iptcInfo.dataLen );
+ if ( lastLegacy < kLegacyJTP_PSIR_IPTC ) lastLegacy = kLegacyJTP_PSIR_IPTC;
+ }
+ }
+
+ }
+
+ XMP_OptionBits options = k2XMP_FileHadExif; // TIFF files are presumed to have Exif legacy.
+ if ( this->containsXMP ) options |= k2XMP_FileHadXMP;
+ if ( haveIPTC || (lastLegacy == kLegacyJTP_PSIR_OldCaption) ) options |= k2XMP_FileHadIPTC;
+
+ // Process the XMP packet. If it fails to parse, do a forced legacy import but still throw an
+ // exception. This tells the caller that an error happened, but gives them recovered legacy
+ // should they want to proceed with that.
+
+ if ( ! this->xmpPacket.empty() ) {
+ XMP_Assert ( this->containsXMP );
+ // Common code takes care of packetInfo.charForm, .padSize, and .writeable.
+ XMP_StringPtr packetStr = this->xmpPacket.c_str();
+ XMP_StringLen packetLen = this->xmpPacket.size();
+ try {
+ this->xmpObj.ParseFromBuffer ( packetStr, packetLen );
+ } catch ( ... ) {
+ XMP_ClearOption ( options, k2XMP_FileHadXMP );
+ ImportJTPtoXMP ( kXMP_TIFFFile, lastLegacy, &tiff, psir, &iptc, &this->xmpObj, options );
+ throw; // ! Rethrow the exception, don't absorb it.
+ }
+ }
+
+ // Process the legacy metadata.
+
+ ImportJTPtoXMP ( kXMP_TIFFFile, lastLegacy, &tiff, psir, &iptc, &this->xmpObj, options );
+ this->containsXMP = true; // Assume we now have something in the XMP.
+
+} // TIFF_MetaHandler::ProcessXMP
+
+// =================================================================================================
+// TIFF_MetaHandler::UpdateFile
+// ============================
+//
+// There is very little to do directly in UpdateFile. ExportXMPtoJTP takes care of setting all of
+// the necessary TIFF tags, including things like the 2nd copy of the IPTC in the Photoshop image
+// resources in tag 34377. TIFF_FileWriter::UpdateFileStream does all of the update-by-append I/O.
+
+// *** Need to pass the abort proc and arg to TIFF_FileWriter::UpdateFileStream.
+
+void TIFF_MetaHandler::UpdateFile ( bool doSafeUpdate )
+{
+ XMP_Assert ( ! doSafeUpdate ); // This should only be called for "unsafe" updates.
+
+ LFA_FileRef destRef = this->parent->fileRef;
+ XMP_AbortProc abortProc = this->parent->abortProc;
+ void * abortArg = this->parent->abortArg;
+
+ // Decide whether to do an in-place update. This can only happen if all of the following are true:
+ // - There is an XMP packet in the file.
+ // - The are no changes to the legacy tags. (The IPTC and PSIR are in the TIFF tags.)
+ // - The new XMP can fit in the old space.
+
+ ExportXMPtoJTP ( kXMP_TIFFFile, &this->xmpObj, &this->tiffMgr, this->psirMgr, this->iptcMgr );
+
+ XMP_Int64 oldPacketOffset = this->packetInfo.offset;
+ XMP_Int32 oldPacketLength = this->packetInfo.length;
+
+ if ( oldPacketOffset == kXMPFiles_UnknownOffset ) oldPacketOffset = 0; // ! Simplify checks.
+ if ( oldPacketLength == kXMPFiles_UnknownLength ) oldPacketLength = 0;
+
+ bool doInPlace = (oldPacketOffset != 0) && (oldPacketLength != 0); // ! Has old packet and new packet fits.
+ if ( doInPlace && (this->tiffMgr.IsLegacyChanged()) ) doInPlace = false;
+
+ if ( doInPlace ) {
+
+ #if GatherPerformanceData
+ sAPIPerf->back().extraInfo += ", TIFF in-place update";
+ #endif
+
+ LFA_FileRef liveFile = this->parent->fileRef;
+
+ XMP_Assert ( this->xmpPacket.size() == (size_t)oldPacketLength ); // ! Done by common PutXMP logic.
+
+ LFA_Seek ( liveFile, oldPacketOffset, SEEK_SET );
+ LFA_Write ( liveFile, this->xmpPacket.c_str(), this->xmpPacket.size() );
+
+ } else {
+
+ #if GatherPerformanceData
+ sAPIPerf->back().extraInfo += ", TIFF append update";
+ #endif
+
+ // Reserialize the XMP to get standard padding, PutXMP has probably done an in-place serialize.
+ this->xmpObj.SerializeToBuffer ( &this->xmpPacket, kXMP_UseCompactFormat );
+ this->packetInfo.offset = kXMPFiles_UnknownOffset;
+ this->packetInfo.length = this->xmpPacket.size();
+ this->packetInfo.padSize = GetPacketPadSize ( this->xmpPacket.c_str(), this->xmpPacket.size() );
+
+ this->tiffMgr.SetTag ( kTIFF_PrimaryIFD, kTIFF_XMP, kTIFF_UndefinedType, this->xmpPacket.size(), this->xmpPacket.c_str() );
+
+ this->tiffMgr.UpdateFileStream ( destRef );
+
+ }
+
+ this->needsUpdate = false;
+
+} // TIFF_MetaHandler::UpdateFile
+
+// =================================================================================================
+// TIFF_MetaHandler::WriteFile
+// ===========================
+//
+// The structure of TIFF makes it hard to do a sequential source-to-dest copy with interleaved
+// updates. So, copy the existing source to the destination and call UpdateFile.
+
+void TIFF_MetaHandler::WriteFile ( LFA_FileRef sourceRef, const std::string & sourcePath )
+{
+ LFA_FileRef destRef = this->parent->fileRef;
+ XMP_AbortProc abortProc = this->parent->abortProc;
+ void * abortArg = this->parent->abortArg;
+
+ XMP_Int64 fileLen = LFA_Measure ( sourceRef );
+ if ( fileLen > 0xFFFFFFFFLL ) { // Check before making a copy of the file.
+ XMP_Throw ( "TIFF fles can't exceed 4GB", kXMPErr_BadTIFF );
+ }
+
+ LFA_Seek ( sourceRef, 0, SEEK_SET );
+ LFA_Truncate ( destRef, 0 );
+ LFA_Copy ( sourceRef, destRef, fileLen, abortProc, abortArg );
+
+ this->UpdateFile ( false );
+
+} // TIFF_MetaHandler::WriteFile
+
+// =================================================================================================
diff --git a/source/XMPFiles/FileHandlers/TIFF_Handler.hpp b/source/XMPFiles/FileHandlers/TIFF_Handler.hpp
new file mode 100644
index 0000000..01c1e06
--- /dev/null
+++ b/source/XMPFiles/FileHandlers/TIFF_Handler.hpp
@@ -0,0 +1,70 @@
+#ifndef __TIFF_Handler_hpp__
+#define __TIFF_Handler_hpp__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "TIFF_Support.hpp"
+#include "PSIR_Support.hpp"
+#include "IPTC_Support.hpp"
+
+// =================================================================================================
+/// \file TIFF_Handler.hpp
+/// \brief File format handler for TIFF.
+///
+/// This header ...
+///
+// =================================================================================================
+
+// *** Could derive from Basic_Handler - buffer file tail in a temp file.
+
+extern XMPFileHandler * TIFF_MetaHandlerCTor ( XMPFiles * parent );
+
+extern bool TIFF_CheckFormat ( XMP_FileFormat format,
+ XMP_StringPtr filePath,
+ LFA_FileRef fileRef,
+ XMPFiles * parent );
+
+static const XMP_OptionBits kTIFF_HandlerFlags = (kXMPFiles_CanInjectXMP |
+ kXMPFiles_CanExpand |
+ kXMPFiles_CanRewrite |
+ kXMPFiles_PrefersInPlace |
+ kXMPFiles_CanReconcile |
+ kXMPFiles_AllowsOnlyXMP |
+ kXMPFiles_ReturnsRawPacket |
+ kXMPFiles_ReturnsTNail |
+ kXMPFiles_AllowsSafeUpdate);
+
+class TIFF_MetaHandler : public XMPFileHandler
+{
+public:
+
+ void CacheFileData();
+ void ProcessTNail();
+ void ProcessXMP();
+
+ void UpdateFile ( bool doSafeUpdate );
+ void WriteFile ( LFA_FileRef sourceRef, const std::string & sourcePath );
+
+ TIFF_MetaHandler ( XMPFiles * parent );
+ virtual ~TIFF_MetaHandler();
+
+private:
+
+ TIFF_MetaHandler() : psirMgr(0), iptcMgr(0) {}; // Hidden on purpose.
+
+ TIFF_FileWriter tiffMgr; // The TIFF part is always file-based.
+ PSIR_Manager * psirMgr; // Need to use pointers so we can properly select between read-only and
+ IPTC_Manager * iptcMgr; // read-write modes of usage.
+
+}; // TIFF_MetaHandler
+
+// =================================================================================================
+
+#endif /* __TIFF_Handler_hpp__ */
diff --git a/source/XMPFiles/FileHandlers/Trivial_Handler.cpp b/source/XMPFiles/FileHandlers/Trivial_Handler.cpp
new file mode 100644
index 0000000..c96c944
--- /dev/null
+++ b/source/XMPFiles/FileHandlers/Trivial_Handler.cpp
@@ -0,0 +1,66 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "Trivial_Handler.hpp"
+
+using namespace std;
+
+// =================================================================================================
+/// \file Trivial_Handler.cpp
+/// \brief Base class for trivial handlers that only process in-place XMP.
+///
+/// This header ...
+///
+// =================================================================================================
+
+// =================================================================================================
+// Trivial_MetaHandler::~Trivial_MetaHandler
+// =========================================
+
+Trivial_MetaHandler::~Trivial_MetaHandler()
+{
+ // Nothing to do.
+
+} // Trivial_MetaHandler::~Trivial_MetaHandler
+
+// =================================================================================================
+// Trivial_MetaHandler::UpdateFile
+// ===============================
+
+void Trivial_MetaHandler::UpdateFile ( bool doSafeUpdate )
+{
+ IgnoreParam ( doSafeUpdate );
+ XMP_Assert ( ! doSafeUpdate ); // Not supported at this level.
+ if ( ! this->needsUpdate ) return;
+
+ LFA_FileRef fileRef = this->parent->fileRef;
+ XMP_PacketInfo & packetInfo = this->packetInfo;
+ std::string & xmpPacket = this->xmpPacket;
+
+ LFA_Seek ( fileRef, packetInfo.offset, SEEK_SET );
+ LFA_Write ( fileRef, xmpPacket.c_str(), packetInfo.length );
+ XMP_Assert ( xmpPacket.size() == (size_t)packetInfo.length );
+
+ this->needsUpdate = false;
+
+} // Trivial_MetaHandler::UpdateFile
+
+// =================================================================================================
+// Trivial_MetaHandler::WriteFile
+// ==============================
+
+void Trivial_MetaHandler::WriteFile ( LFA_FileRef sourceRef, const std::string & sourcePath )
+{
+ IgnoreParam ( sourceRef ); IgnoreParam ( sourcePath );
+
+ XMP_Throw ( "Trivial_MetaHandler::WriteFile: Not supported", kXMPErr_Unavailable );
+
+} // Trivial_MetaHandler::WriteFile
+
+// =================================================================================================
diff --git a/source/XMPFiles/FileHandlers/Trivial_Handler.hpp b/source/XMPFiles/FileHandlers/Trivial_Handler.hpp
new file mode 100644
index 0000000..9729ba0
--- /dev/null
+++ b/source/XMPFiles/FileHandlers/Trivial_Handler.hpp
@@ -0,0 +1,47 @@
+#ifndef __Trivial_Handler_hpp__
+#define __Trivial_Handler_hpp__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "XMPFiles_Impl.hpp"
+
+// =================================================================================================
+/// \file Trivial_Handler.hpp
+/// \brief Base class for trivial handlers that only process in-place XMP.
+///
+/// This header ...
+///
+/// \note There is no general promise here about crash-safe I/O. An update to an existing file might
+/// have invalid partial state while rewriting existing XMP in-place. Crash-safe updates are managed
+/// at a higher level of XMPFiles, using a temporary file and final swap of file content.
+///
+// =================================================================================================
+
+static const XMP_OptionBits kTrivial_HandlerFlags = ( kXMPFiles_AllowsOnlyXMP |
+ kXMPFiles_ReturnsRawPacket |
+ kXMPFiles_AllowsSafeUpdate );
+
+class Trivial_MetaHandler : public XMPFileHandler
+{
+public:
+
+ Trivial_MetaHandler() {};
+ ~Trivial_MetaHandler();
+
+ virtual void CacheFileData() = 0;
+
+ void UpdateFile ( bool doSafeUpdate );
+ void WriteFile ( LFA_FileRef sourceRef, const std::string & sourcePath );
+
+}; // Trivial_MetaHandler
+
+// =================================================================================================
+
+#endif /* __Trivial_Handler_hpp__ */
diff --git a/source/XMPFiles/FileHandlers/WAV_Handler.cpp b/source/XMPFiles/FileHandlers/WAV_Handler.cpp
new file mode 100644
index 0000000..1cd5eb7
--- /dev/null
+++ b/source/XMPFiles/FileHandlers/WAV_Handler.cpp
@@ -0,0 +1,648 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#if WIN_ENV
+ #pragma warning ( disable : 4996 ) // '...' was declared deprecated
+#endif
+
+#include "WAV_Handler.hpp"
+#include "RIFF_Support.hpp"
+#include "Reconcile_Impl.hpp"
+#include "XMP_Const.h"
+
+using namespace std;
+
+#define kXMPUserDataType MakeFourCC ( '_', 'P', 'M', 'X' ) /* Yes, backwards! */
+
+#define formtypeWAVE MakeFourCC('W', 'A', 'V', 'E')
+
+
+// -------------------------------------------------------------------------------------------------
+// Premiere Pro specific info for reconciliation
+
+// ! MakeFourCC warning: The MakeFourCC macro creates a 32 bit int with the letters "reversed". This
+// ! is a leftover of the original Win-only code. It happens to work OK on little endian machines,
+// ! when stored in memory the letters are in the expected order. To be safe, always use the XMP
+// ! endian control macros when storing to memory or loading from memory.
+
+// FourCC codes for the RIFF chunks
+#define wavWaveTitleChunk MakeFourCC('D','I','S','P')
+#define wavInfoCreateDateChunk MakeFourCC('I','C','R','D')
+#define wavInfoArtistChunk MakeFourCC('I','A','R','T')
+#define wavInfoAlbumChunk MakeFourCC('I','N','A','M')
+#define wavInfoGenreChunk MakeFourCC('I','G','N','R')
+#define wavInfoCommentChunk MakeFourCC('I','C','M','T')
+#define wavInfoEngineerChunk MakeFourCC('I','E','N','G')
+#define wavInfoCopyrightChunk MakeFourCC('I','C','O','P')
+#define wavInfoSoftwareChunk MakeFourCC('I','S','F','T')
+
+#define wavInfoTag MakeFourCC('I','N','F','O')
+#define wavWaveTag MakeFourCC('W','A','V','E')
+
+// DC
+#define kTitle "title"
+#define kCopyright "rights"
+
+// XMP
+#define kCreateDate "CreateDate"
+
+// DM
+#define kArtist "artist"
+#define kAlbum "album"
+#define kGenre "genre"
+#define kLogComment "logComment"
+#define kEngineer "engineer"
+#define kSoftware "CreatorTool"
+
+// -------------------------------------------------------------------------------------------------
+// Legacy digest info
+// ------------------
+//
+// The original WAV handler code didn't keep a legacy digest, it imported the legacy on every open.
+// Because local encoding is used for the legacy, this can cause loss in the XMP. (The use of local
+// encoding itself is an issue, the AVI handler is using UTF-8.)
+//
+// The legacy digest for WAV is a list of chunk IDs and a 128-bit MD5 digest, formatted like:
+// DISP,IART,ICMT,ICOP,ICRD,IENG,IGNR,INAM,ISFT;012345678ABCDEF012345678ABCDEF
+//
+// The list of IDs are the recognized legacy chunks, in alphabetical order. This the full list that
+// could be recognized, not restricted to those actually present in the specific file. When opening
+// a file the new software's list is used to create the comparison digest, not the list from the
+// file. So that changes to the recognized list will trigger an import.
+//
+// The MD5 digest is computed from the full legacy chunk, including the ID and length portions, not
+// including any pad byte for odd data length. The length must be in file (little endian) order,
+// not native machine order. The legacy chunks are added to the digest in list (alphabetical by ID)
+// order.
+//
+// Legacy can be imported in 3 circumstances:
+//
+// 1. If the file does not yet have XMP, all of the legacy is imported.
+//
+// 2. If the file has XMP and a digest, and the recomputed digest differs from the saved digest, the
+// legacy is imported. The digest comparison is the full string, including the list of IDs. A
+// check is made for each legacy item:
+// 2a. If the legacy item is missing or has an empty value, the corresponding XMP is deleted.
+// 2b. If the corresponding XMP is missing, the legacy value is imported.
+// 2c. If the new legacy value differs from a local encoding of the XMP value, the legacy value
+// is imported.
+//
+// 3. If the file has XMP but no digest, legacy is imported for items that have no corresponding XMP.
+// Any existing XMP is left alone. This is protection for tools that might be XMP aware but do
+// not provide a digest or any legacy reconciliation.
+
+#define TAG_MAX_SIZE 5024
+
+// =================================================================================================
+
+static inline int GetStringRiffSize ( const std::string & str )
+{
+ int l = strlen ( const_cast<char *> (str.data()) );
+ if ( l & 1 ) ++l;
+ return l;
+}
+
+// =================================================================================================
+/// \file WAV_Handler.cpp
+/// \brief File format handler for WAV.
+///
+/// This header ...
+///
+// =================================================================================================
+
+// =================================================================================================
+// WAV_MetaHandlerCTor
+// ===================
+
+XMPFileHandler * WAV_MetaHandlerCTor ( XMPFiles * parent )
+{
+ return new WAV_MetaHandler ( parent );
+
+} // WAV_MetaHandlerCTor
+
+// =================================================================================================
+// WAV_CheckFormat
+// ===============
+//
+// A WAVE file must begin with "RIFF", a 4 byte little endian length, then "WAVE". The length should
+// be fileSize-8, but we don't bother checking this here.
+
+bool WAV_CheckFormat ( XMP_FileFormat format,
+ XMP_StringPtr filePath,
+ LFA_FileRef fileRef,
+ XMPFiles * parent )
+{
+ IgnoreParam(format); IgnoreParam(parent);
+ XMP_Assert ( format == kXMP_WAVFile );
+
+ if ( fileRef == 0 ) return false;
+
+ enum { kBufferSize = 12 };
+ XMP_Uns8 buffer [kBufferSize];
+
+ LFA_Seek ( fileRef, 0, SEEK_SET );
+ LFA_Read ( fileRef, buffer, kBufferSize );
+
+ // "RIFF" is 52 49 46 46, "WAVE" is 57 41 56 45
+ if ( (! CheckBytes ( &buffer[0], "\x52\x49\x46\x46", 4 )) ||
+ (! CheckBytes ( &buffer[8], "\x57\x41\x56\x45", 4 )) ) return false;
+
+ return true;
+
+} // WAV_CheckFormat
+
+// =================================================================================================
+// WAV_MetaHandler::WAV_MetaHandler
+// ================================
+
+WAV_MetaHandler::WAV_MetaHandler ( XMPFiles * _parent )
+{
+ this->parent = _parent;
+ this->handlerFlags = kWAV_HandlerFlags;
+ this->stdCharForm = kXMP_Char8Bit;
+
+} // WAV_MetaHandler::WAV_MetaHandler
+
+// =================================================================================================
+// WAV_MetaHandler::~WAV_MetaHandler
+// =================================
+
+WAV_MetaHandler::~WAV_MetaHandler()
+{
+ // Nothing to do.
+} // WAV_MetaHandler::~WAV_MetaHandler
+
+
+
+// =================================================================================================
+// WAV_MetaHandler::UpdateFile
+// ===========================
+
+void WAV_MetaHandler::UpdateFile ( bool doSafeUpdate )
+{
+ if ( ! this->needsUpdate ) return;
+ if ( doSafeUpdate ) XMP_Throw ( "WAV_MetaHandler::UpdateFile: Safe update not supported", kXMPErr_Unavailable );
+
+ bool fReconciliate = ! (this->parent->openFlags & kXMPFiles_OpenOnlyXMP);
+ bool ok;
+
+ std::string strTitle, strArtist, strComment, strCopyright, strCreateDate,
+ strEngineer, strGenre, strAlbum, strSoftware;
+
+ if ( fReconciliate ) {
+
+ // Get the legacy item values, create the new digest, and add the digest to the XMP. The
+ // legacy chunks in alphabetical ID order are:
+ // DISP - title
+ // IART - artist
+ // ICMT - log comment
+ // ICOP - copyright
+ // ICRD - create date
+ // IENG - engineer
+ // IGNR - genre
+ // INAM - album
+ // ISFT - software
+
+ MD5_CTX md5Ctx;
+ std::string digestStr;
+ XMP_Uns8 md5Val[16];
+ static char* hexDigits = "0123456789ABCDEF";
+
+ MD5Init ( &md5Ctx );
+
+ // Prepare the legacy values and compute the new digest.
+
+ PrepareLegacyExport ( kXMP_NS_DC, kTitle, wavWaveTitleChunk, &strTitle, &digestStr, &md5Ctx, true /* LangAlt */ );
+ PrepareLegacyExport ( kXMP_NS_DM, kArtist, wavInfoArtistChunk, &strArtist, &digestStr, &md5Ctx );
+ PrepareLegacyExport ( kXMP_NS_DM, kLogComment, wavInfoCommentChunk, &strComment, &digestStr, &md5Ctx );
+ PrepareLegacyExport ( kXMP_NS_DC, kCopyright, wavInfoCopyrightChunk, &strCopyright, &digestStr, &md5Ctx, true /* LangAlt */ );
+ PrepareLegacyExport ( kXMP_NS_XMP, kCreateDate, wavInfoCreateDateChunk, &strCreateDate, &digestStr, &md5Ctx );
+ PrepareLegacyExport ( kXMP_NS_DM, kEngineer, wavInfoEngineerChunk, &strEngineer, &digestStr, &md5Ctx );
+ PrepareLegacyExport ( kXMP_NS_DM, kGenre, wavInfoGenreChunk, &strGenre, &digestStr, &md5Ctx );
+ PrepareLegacyExport ( kXMP_NS_DM, kAlbum, wavInfoAlbumChunk, &strAlbum, &digestStr, &md5Ctx );
+ PrepareLegacyExport ( kXMP_NS_XMP, kSoftware, wavInfoSoftwareChunk, &strSoftware, &digestStr, &md5Ctx );
+
+ // Finish the digest and add it to the XMP.
+
+ MD5Final ( md5Val, &md5Ctx );
+
+ digestStr[digestStr.size()-1] = ';';
+ for ( size_t i = 0; i < 16; ++i ) {
+ XMP_Uns8 byte = md5Val[i];
+ digestStr += hexDigits [byte >> 4];
+ digestStr += hexDigits [byte & 0xF];
+ }
+
+ XMP_StringLen oldLen = this->xmpPacket.size();
+ this->xmpObj.SetProperty ( kXMP_NS_WAV, "NativeDigest", digestStr.c_str() );
+ try {
+ this->xmpObj.SerializeToBuffer ( &this->xmpPacket, kXMP_ExactPacketLength, oldLen );
+ } catch ( ... ) {
+ this->xmpObj.SerializeToBuffer ( &this->xmpPacket, kXMP_UseCompactFormat );
+ }
+
+ }
+
+ XMP_StringPtr packetStr = this->xmpPacket.c_str();
+ XMP_StringLen packetLen = this->xmpPacket.size();
+ if ( packetLen == 0 ) return;
+
+ // Make sure we're writing an even number of bytes as required by the RIFF specification
+ if ( (this->xmpPacket.size() & 1) == 1 ) this->xmpPacket.push_back (' ');
+ XMP_Assert ( (this->xmpPacket.size() & 1) == 0 );
+ packetStr = this->xmpPacket.c_str(); // ! Make sure they are current.
+ packetLen = this->xmpPacket.size();
+
+ LFA_FileRef fileRef ( this->parent->fileRef );
+ if ( fileRef == 0 ) return;
+
+ RIFF_Support::RiffState riffState;
+ long numTags = RIFF_Support::OpenRIFF(fileRef, riffState);
+ if ( numTags == 0 ) return;
+
+ ok = RIFF_Support::PutChunk ( fileRef, riffState, formtypeWAVE, kXMPUserDataType, (char*)packetStr, packetLen );
+ if ( ! ok ) return;
+
+ // If needed, reconciliate the XMP data back into the native metadata.
+ if ( fReconciliate ) {
+
+ PutChunk ( fileRef, riffState, wavWaveTag, wavWaveTitleChunk, strTitle.c_str(), strTitle.size() );
+
+ // Pad the old tags
+ RIFF_Support::MarkChunkAsPadding ( fileRef, riffState, 0, wavInfoCreateDateChunk, 0 );
+ RIFF_Support::MarkChunkAsPadding ( fileRef, riffState, 0, wavInfoArtistChunk, 0 );
+ RIFF_Support::MarkChunkAsPadding ( fileRef, riffState, 0, wavInfoAlbumChunk, 0 );
+ RIFF_Support::MarkChunkAsPadding ( fileRef, riffState, 0, wavInfoGenreChunk, 0 );
+ RIFF_Support::MarkChunkAsPadding ( fileRef, riffState, 0, wavInfoCommentChunk, 0 );
+ RIFF_Support::MarkChunkAsPadding ( fileRef, riffState, 0, wavInfoEngineerChunk, 0 );
+ RIFF_Support::MarkChunkAsPadding ( fileRef, riffState, 0, wavInfoCopyrightChunk, 0 );
+ RIFF_Support::MarkChunkAsPadding ( fileRef, riffState, 0, wavInfoSoftwareChunk, 0 );
+
+ // Get the old INFO list
+ std::string strOldInfo;
+ unsigned long lOldSize = 0;
+ bool ok = RIFF_Support::GetRIFFChunk ( fileRef, riffState, FOURCC_LIST, wavWaveTag, wavInfoTag, 0, &lOldSize );
+ if ( ok ) {
+ // We have to get rid of the "INFO" first.
+ strOldInfo.reserve ( lOldSize );
+ strOldInfo.assign ( lOldSize, ' ' );
+ RIFF_Support::GetRIFFChunk ( fileRef, riffState, FOURCC_LIST, wavWaveTag, wavInfoTag, (char*)strOldInfo.c_str(), &lOldSize );
+ // lOldSize -= 4;
+ }
+
+ // TODO: Cleaning up the OldInfo from the padding
+
+ // Pad the old INFO list
+ RIFF_Support::MarkChunkAsPadding ( fileRef, riffState, wavWaveTag, FOURCC_LIST, wavInfoTag );
+
+ // Calculating the new INFO list size
+ XMP_Int32 dwListSize = 4 + 8 * 8 +
+ GetStringRiffSize ( strCreateDate ) +
+ GetStringRiffSize ( strArtist ) +
+ GetStringRiffSize ( strAlbum ) +
+ GetStringRiffSize ( strGenre ) +
+ GetStringRiffSize ( strComment ) +
+ GetStringRiffSize ( strEngineer ) +
+ GetStringRiffSize ( strCopyright ) +
+ GetStringRiffSize ( strSoftware ) +
+ lOldSize; // list id (4 bytes) + 8 tags hdrs (8 each)
+
+ ok = MakeChunk ( fileRef, riffState, formtypeWAVE, dwListSize + 8 );
+ if ( ! ok ) return; // If there's an error making a chunk, bail
+
+ // Building the INFO list header
+ RIFF_Support::ltag listtag;
+ listtag.id = MakeUns32LE ( FOURCC_LIST );
+ listtag.len = MakeUns32LE ( dwListSize );
+ listtag.subid = MakeUns32LE ( wavInfoTag );
+ LFA_Write ( fileRef, &listtag, 12 );
+
+ // Writing all the chunks
+ RIFF_Support::WriteChunk ( fileRef, wavInfoCreateDateChunk, strCreateDate.c_str(), GetStringRiffSize ( strCreateDate ) );
+ RIFF_Support::WriteChunk ( fileRef, wavInfoArtistChunk, strArtist.c_str(), GetStringRiffSize ( strArtist ) );
+ RIFF_Support::WriteChunk ( fileRef, wavInfoAlbumChunk, strAlbum.c_str(), GetStringRiffSize ( strAlbum ) );
+ RIFF_Support::WriteChunk ( fileRef, wavInfoGenreChunk, strGenre.c_str(), GetStringRiffSize ( strGenre ) );
+ RIFF_Support::WriteChunk ( fileRef, wavInfoCommentChunk, strComment.c_str(), GetStringRiffSize ( strComment ) );
+ RIFF_Support::WriteChunk ( fileRef, wavInfoEngineerChunk, strEngineer.c_str(), GetStringRiffSize ( strEngineer ) );
+ RIFF_Support::WriteChunk ( fileRef, wavInfoCopyrightChunk, strCopyright.c_str(), GetStringRiffSize ( strCopyright ) );
+ RIFF_Support::WriteChunk ( fileRef, wavInfoSoftwareChunk, strSoftware.c_str(), GetStringRiffSize ( strSoftware ) );
+
+ LFA_Write ( fileRef, strOldInfo.c_str(), lOldSize );
+
+ }
+
+ this->needsUpdate = false;
+
+} // WAV_MetaHandler::UpdateFile
+
+// =================================================================================================
+// WAV_MetaHandler::WriteFile
+// ==========================
+
+void WAV_MetaHandler::WriteFile ( LFA_FileRef sourceRef,
+ const std::string & sourcePath )
+{
+ IgnoreParam(sourceRef); IgnoreParam(sourcePath);
+
+ XMP_Throw ( "WAV_MetaHandler::WriteFile: Not supported", kXMPErr_Unavailable );
+
+} // WAV_MetaHandler::WriteFile
+
+// =================================================================================================
+
+static void AddDigestItem ( XMP_Uns32 legacyID, std::string & legacyStr, std::string * digestStr, MD5_CTX * md5 )
+{
+
+ XMP_Uns32 leID = MakeUns32LE ( legacyID );
+ XMP_Uns32 leLen = MakeUns32LE (legacyStr.size());
+
+ digestStr->append ( (char*)(&leID), 4 );
+ digestStr->append ( "," );
+
+ MD5Update ( md5, (XMP_Uns8*)&leID, 4 );
+ MD5Update ( md5, (XMP_Uns8*)&leLen, 4 );
+ MD5Update ( md5, (XMP_Uns8*)legacyStr.c_str(), legacyStr.size() );
+
+} // AddDigestItem
+
+// =================================================================================================
+
+static void AddCurrentDigestItem ( LFA_FileRef fileRef, RIFF_Support::RiffState riffState,
+ XMP_Uns32 tagID, XMP_Uns32 parentID, std::string * digestStr, MD5_CTX * md5 )
+{
+ unsigned long legacySize;
+ std::string legacyStr;
+
+ bool found = RIFF_Support::GetRIFFChunk ( fileRef, riffState, tagID, parentID, 0, 0, &legacySize );
+ if ( found ) {
+ legacyStr.reserve ( legacySize );
+ legacyStr.assign ( legacySize, ' ' );
+ (void) RIFF_Support::GetRIFFChunk ( fileRef, riffState, tagID, parentID, 0, (char*)legacyStr.c_str(), &legacySize );
+ }
+
+ AddDigestItem ( tagID, legacyStr, digestStr, md5 );
+
+} // AddCurrentDigestItem
+
+// =================================================================================================
+
+static void CreateCurrentDigest ( LFA_FileRef fileRef, RIFF_Support::RiffState riffState, std::string * digestStr )
+{
+ MD5_CTX md5Ctx;
+ XMP_Uns8 md5Val[16];
+ static char* hexDigits = "0123456789ABCDEF";
+
+ MD5Init ( &md5Ctx );
+
+ AddCurrentDigestItem ( fileRef, riffState, wavWaveTitleChunk, wavWaveTag, digestStr, &md5Ctx );
+ AddCurrentDigestItem ( fileRef, riffState, wavInfoArtistChunk, wavInfoTag, digestStr, &md5Ctx );
+ AddCurrentDigestItem ( fileRef, riffState, wavInfoCommentChunk, wavInfoTag, digestStr, &md5Ctx );
+ AddCurrentDigestItem ( fileRef, riffState, wavInfoCopyrightChunk, wavInfoTag, digestStr, &md5Ctx);
+ AddCurrentDigestItem ( fileRef, riffState, wavInfoCreateDateChunk, wavInfoTag, digestStr, &md5Ctx );
+ AddCurrentDigestItem ( fileRef, riffState, wavInfoEngineerChunk, wavInfoTag, digestStr, &md5Ctx );
+ AddCurrentDigestItem ( fileRef, riffState, wavInfoGenreChunk, wavInfoTag, digestStr, &md5Ctx );
+ AddCurrentDigestItem ( fileRef, riffState, wavInfoAlbumChunk, wavInfoTag, digestStr, &md5Ctx );
+ AddCurrentDigestItem ( fileRef, riffState, wavInfoSoftwareChunk, wavInfoTag, digestStr, &md5Ctx );
+
+ MD5Final ( md5Val, &md5Ctx );
+
+ (*digestStr)[digestStr->size()-1] = ';';
+ for ( size_t i = 0; i < 16; ++i ) {
+ XMP_Uns8 byte = md5Val[i];
+ (*digestStr) += hexDigits [byte >> 4];
+ (*digestStr) += hexDigits [byte & 0xF];
+ }
+
+} // CreateCurrentDigest
+
+
+// =================================================================================================
+// WAV_MetaHandler::CacheFileData
+// ==============================
+
+void WAV_MetaHandler::CacheFileData()
+{
+
+ this->containsXMP = false;
+ bool fReconciliate = ! (this->parent->openFlags & kXMPFiles_OpenOnlyXMP);
+ bool keepExistingXMP = false; // By default an import will replace existing XMP.
+ bool haveLegacyItem, haveXMPItem;
+
+ LFA_FileRef fileRef ( this->parent->fileRef );
+
+ RIFF_Support::RiffState riffState;
+ long numTags = RIFF_Support::OpenRIFF ( fileRef, riffState );
+ if ( numTags == 0 ) return;
+
+ // Determine the size of the metadata
+ unsigned long bufferSize(0);
+ haveLegacyItem = RIFF_Support::GetRIFFChunk ( fileRef, riffState, kXMPUserDataType, 0, 0, 0, &bufferSize );
+
+ if ( ! haveLegacyItem ) {
+
+ packetInfo.writeable = true; // If no packet found, created packets will be writeable
+
+ } else if ( bufferSize > 0 ) {
+
+ // Size and clear the buffer
+ this->xmpPacket.reserve(bufferSize);
+ this->xmpPacket.assign(bufferSize, ' ');
+
+ // Get the metadata
+ haveLegacyItem = RIFF_Support::GetRIFFChunk ( fileRef, riffState, kXMPUserDataType, 0, 0,
+ const_cast<char *>(this->xmpPacket.data()), &bufferSize );
+ if ( haveLegacyItem ) {
+ this->packetInfo.offset = kXMPFiles_UnknownOffset;
+ this->packetInfo.length = bufferSize;
+ this->xmpObj.ParseFromBuffer ( this->xmpPacket.c_str(), this->xmpPacket.size() );
+ this->containsXMP = true;
+ }
+
+ }
+
+ // Figure out what to do overall. If there is no XMP, everything gets imported. If there is XMP
+ // but no digest, only import if there is no corresponding XMP. If there is XMP and a digest
+ // that matches, nothing is imported. If there is XMP and a digest that does not match, import
+ // everything that provides "new info".
+
+ if ( fReconciliate && this->containsXMP ) {
+
+ std::string savedDigest;
+ haveXMPItem = this->xmpObj.GetProperty ( kXMP_NS_WAV, "NativeDigest", &savedDigest, 0 );
+
+ if ( ! haveXMPItem ) {
+ keepExistingXMP = true;
+ } else {
+ std::string currDigest;
+ CreateCurrentDigest ( fileRef, riffState, &currDigest );
+ if ( currDigest == savedDigest ) fReconciliate = false;
+ }
+
+ }
+
+ // Now import the individual legacy items.
+
+ if ( fReconciliate ) {
+
+ ImportLegacyItem ( riffState, wavWaveTitleChunk, wavWaveTag, kXMP_NS_DC, kTitle, keepExistingXMP, true /* LangAlt */ );
+ ImportLegacyItem ( riffState, wavInfoCreateDateChunk, wavInfoTag, kXMP_NS_XMP, kCreateDate, keepExistingXMP );
+ ImportLegacyItem ( riffState, wavInfoArtistChunk, wavInfoTag, kXMP_NS_DM, kArtist, keepExistingXMP );
+ ImportLegacyItem ( riffState, wavInfoAlbumChunk, wavInfoTag, kXMP_NS_DM, kAlbum, keepExistingXMP );
+ ImportLegacyItem ( riffState, wavInfoGenreChunk, wavInfoTag, kXMP_NS_DM, kGenre, keepExistingXMP );
+ ImportLegacyItem ( riffState, wavInfoCommentChunk, wavInfoTag, kXMP_NS_DM, kLogComment, keepExistingXMP );
+ ImportLegacyItem ( riffState, wavInfoEngineerChunk, wavInfoTag, kXMP_NS_DM, kEngineer, keepExistingXMP );
+ ImportLegacyItem ( riffState, wavInfoCopyrightChunk, wavInfoTag, kXMP_NS_DC, kCopyright, keepExistingXMP, true /* LangAlt */ );
+ ImportLegacyItem ( riffState, wavInfoSoftwareChunk, wavInfoTag, kXMP_NS_XMP, kSoftware, keepExistingXMP );
+
+ }
+
+ // Update the xmpPacket, as the xmpObj might have been updated with legacy info
+ this->xmpObj.SerializeToBuffer ( &this->xmpPacket, kXMP_UseCompactFormat );
+ this->packetInfo.offset = kXMPFiles_UnknownOffset;
+ this->packetInfo.length = this->xmpPacket.size();
+
+ this->processedXMP = this->containsXMP;
+
+} // WAV_MetaHandler::CacheFileData
+
+// =================================================================================================
+
+void WAV_MetaHandler::UTF8ToMBCS ( std::string * inoutStr )
+{
+ std::string localStr;
+
+ try {
+ ReconcileUtils::UTF8ToLocal ( inoutStr->c_str(), inoutStr->size(), &localStr );
+ inoutStr->swap ( localStr );
+ } catch ( ... ) {
+ inoutStr->erase();
+ }
+
+}
+
+// =================================================================================================
+
+void WAV_MetaHandler::MBCSToUTF8 ( std::string * inoutStr )
+{
+ std::string utf8Str;
+
+ try {
+ ReconcileUtils::LocalToUTF8 ( inoutStr->c_str(), inoutStr->size(), &utf8Str );
+ inoutStr->swap ( utf8Str );
+ } catch ( ... ) {
+ inoutStr->erase();
+ }
+
+}
+
+// =================================================================================================
+
+void WAV_MetaHandler::PrepareLegacyExport ( XMP_StringPtr xmpNS, XMP_StringPtr xmpProp, XMP_Uns32 legacyID, std::string * legacyStr,
+ std::string * digestStr, MD5_CTX * md5, bool langAlt /* = false */ )
+{
+ if ( ! langAlt ) {
+ this->xmpObj.GetProperty ( xmpNS, xmpProp, legacyStr, 0 );
+ } else {
+ this->xmpObj.GetLocalizedText ( xmpNS, xmpProp, "", "x-default", 0, legacyStr, 0 );
+ }
+ UTF8ToMBCS ( legacyStr ); // Convert the XMP value to local encoding.
+
+ // ! Add a 0 pad byte if the value has an odd length. This would be better done inside RIFF_Support,
+ // ! but that means changing too much at this moment.
+
+ if ( (legacyStr->size() & 1) == 1 ) {
+ (*legacyStr) += " ";
+ (*legacyStr)[legacyStr->size()-1] = 0;
+ }
+
+ if ( legacyID == wavWaveTitleChunk ) { // ! The title gets 32 bit LE type code of 1 inserted.
+ legacyStr->insert ( 0, "1234" );
+ PutUns32LE ( 1, (void*)legacyStr->c_str() );
+ }
+
+ AddDigestItem ( legacyID, *legacyStr, digestStr, md5 );
+
+} // WAV_MetaHandler::PrepareLegacyExport
+
+// =================================================================================================
+
+void WAV_MetaHandler::ImportLegacyItem ( RIFF_Support::RiffState & inOutRiffState,
+ XMP_Uns32 tagID,
+ XMP_Uns32 parentID,
+ XMP_StringPtr xmpNS,
+ XMP_StringPtr xmpProp,
+ bool keepExistingXMP,
+ bool langAlt /* = false */ )
+{
+ LFA_FileRef fileRef ( this->parent->fileRef );
+
+ bool haveLegacyItem, haveXMPItem;
+ std::string legacyStr, xmpStr;
+ unsigned long legacySize;
+
+ if ( ! langAlt ) {
+ haveXMPItem = this->xmpObj.GetProperty ( xmpNS, xmpProp, &xmpStr, 0 );
+ } else {
+ haveXMPItem = this->xmpObj.GetLocalizedText ( xmpNS, xmpProp, "", "x-default", 0, &xmpStr, 0 );
+ }
+
+ haveLegacyItem = RIFF_Support::GetRIFFChunk ( fileRef, inOutRiffState, tagID, parentID, 0, 0, &legacySize );
+ if ( (legacySize == 0) || ((tagID == wavWaveTitleChunk) && (legacySize <= 4)) ) haveLegacyItem = false;
+ if ( haveXMPItem && keepExistingXMP ) haveLegacyItem = false; // Simplify following checks.
+
+ if ( ! haveLegacyItem ) {
+
+ // No legacy item, delete the corresponding XMP if we're not keeping existing XMP.
+
+ if ( haveXMPItem && (! keepExistingXMP) ) {
+ if ( ! langAlt ) {
+ this->xmpObj.DeleteProperty ( xmpNS, xmpProp );
+ } else {
+ std::string xdPath;
+ SXMPUtils::ComposeLangSelector ( xmpNS, xmpProp, "x-default", &xdPath );
+ this->xmpObj.DeleteProperty ( xmpNS, xdPath.c_str() );
+ if ( this->xmpObj.CountArrayItems ( xmpNS, xmpProp ) == 0 ) this->xmpObj.DeleteProperty ( xmpNS, xmpProp );
+ }
+ }
+
+ } else {
+
+ // Have a legacy Item, update the XMP as appropriate.
+
+ XMP_Assert ( (! haveXMPItem) || (! keepExistingXMP) );
+
+ legacyStr.reserve ( legacySize );
+ legacyStr.assign ( legacySize, ' ' );
+ haveLegacyItem = RIFF_Support::GetRIFFChunk ( fileRef, inOutRiffState, tagID, parentID, 0, (char*)legacyStr.c_str(), &legacySize );
+ XMP_Assert ( haveLegacyItem );
+
+ if ( tagID == wavWaveTitleChunk ) { // Check and strip the type code from the title.
+ XMP_Assert ( legacySize > 4 );
+ XMP_Uns32 typeCode = GetUns32LE ( legacyStr.data() );
+ if( typeCode != 1 ) return; // Bail if the type code isn't 1.
+ legacyStr.erase ( 0, 4 ); // Reduce the value to just the text part.
+ }
+
+ if ( haveXMPItem ) {
+ // Don't update the XMP if the legacy value matches the localized XMP value.
+ UTF8ToMBCS ( &xmpStr );
+ if ( xmpStr == legacyStr ) return;
+ }
+
+ MBCSToUTF8 ( &legacyStr );
+ if ( ! langAlt ) {
+ this->xmpObj.SetProperty ( xmpNS, xmpProp, legacyStr.c_str(), 0 );
+ } else {
+ this->xmpObj.SetLocalizedText ( xmpNS, xmpProp, "", "x-default", legacyStr.c_str(), 0 );
+ }
+ this->containsXMP = true;
+
+ }
+
+} // WAV_MetaHandler::LoadPropertyFromRIFF
diff --git a/source/XMPFiles/FileHandlers/WAV_Handler.hpp b/source/XMPFiles/FileHandlers/WAV_Handler.hpp
new file mode 100644
index 0000000..a84f46b
--- /dev/null
+++ b/source/XMPFiles/FileHandlers/WAV_Handler.hpp
@@ -0,0 +1,71 @@
+#ifndef __WAV_Handler_hpp__
+#define __WAV_Handler_hpp__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "XMPFiles_Impl.hpp"
+
+#include "MD5.h"
+
+// =================================================================================================
+/// \file WAV_Handler.hpp
+/// \brief File format handler for WAV.
+///
+/// This header ...
+///
+// =================================================================================================
+
+namespace RIFF_Support
+{
+ class RiffState;
+}
+
+extern XMPFileHandler * WAV_MetaHandlerCTor ( XMPFiles * parent );
+
+extern bool WAV_CheckFormat ( XMP_FileFormat format,
+ XMP_StringPtr filePath,
+ LFA_FileRef fileRef,
+ XMPFiles * parent );
+
+static const XMP_OptionBits kWAV_HandlerFlags = ( kXMPFiles_CanInjectXMP |
+ kXMPFiles_CanExpand |
+ kXMPFiles_PrefersInPlace |
+ kXMPFiles_AllowsOnlyXMP |
+ kXMPFiles_ReturnsRawPacket );
+ // In the future, we'll add kXMPFiles_CanReconcile
+
+class WAV_MetaHandler : public XMPFileHandler
+{
+public:
+
+ WAV_MetaHandler ( XMPFiles * parent );
+ ~WAV_MetaHandler();
+
+ void CacheFileData();
+
+ void UpdateFile ( bool doSafeUpdate );
+ void WriteFile ( LFA_FileRef sourceRef, const std::string & sourcePath );
+
+private:
+
+ void ImportLegacyItem ( RIFF_Support::RiffState& inOutRiffState, XMP_Uns32 tagID, XMP_Uns32 parentID,
+ XMP_StringPtr xmpNS, XMP_StringPtr xmpProp, bool keepExistingXMP, bool langAlt = false );
+
+ void PrepareLegacyExport ( XMP_StringPtr xmpNS, XMP_StringPtr xmpProp, XMP_Uns32 legacyID, std::string * legacyStr,
+ std::string * digestStr, MD5_CTX * md5, bool langAlt = false );
+
+ void UTF8ToMBCS ( std::string * str );
+ void MBCSToUTF8 ( std::string * str );
+
+}; // WAV_MetaHandler
+
+// =================================================================================================
+
+#endif /* __WAV_Handler_hpp__ */
diff --git a/source/XMPFiles/FormatSupport/EndianUtils.hpp b/source/XMPFiles/FormatSupport/EndianUtils.hpp
new file mode 100644
index 0000000..684c539
--- /dev/null
+++ b/source/XMPFiles/FormatSupport/EndianUtils.hpp
@@ -0,0 +1,422 @@
+#ifndef __EndianUtils_hpp__
+#define __EndianUtils_hpp__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "XMP_Environment.h" // ! This must be the first include.
+#include "XMP_Const.h"
+
+// *** These should be in a more common location. The Unicode conversions of XMPCore have similar utils.
+// *** May want to improve with PowerPC swapping load/store, or SSE instructions.
+
+// =================================================================================================
+
+#define kLittleEndianHost (! kBigEndianHost)
+#if XMP_WinBuild
+ #define kBigEndianHost 0
+#elif XMP_MacBuild
+ #if __MWERKS__
+ #if __POWERPC__
+ #define kBigEndianHost 1
+ #else
+ #error "CodeWarrior must only be for PowerPC"
+ #endif
+ #else // Must be an Xcode build.
+ #if __BIG_ENDIAN__
+ #define kBigEndianHost 1
+ #elif __LITTLE_ENDIAN__
+ #define kBigEndianHost 0
+ #else
+ #error "Neither __BIG_ENDIAN__ nor __LITTLE_ENDIAN__ is set"
+ #endif
+ #endif
+#elif XMP_UNIXBuild
+ #error "Endian macros not set up for generic UNIX yet"
+#else
+ #error "Unknown build environment"
+#endif
+
+// =================================================================================================
+
+typedef XMP_Uns16 (*GetUns16_Proc) ( const void* addr );
+typedef XMP_Uns32 (*GetUns32_Proc) ( const void* addr );
+typedef XMP_Uns64 (*GetUns64_Proc) ( const void* addr );
+typedef float (*GetFloat_Proc) ( const void* addr );
+typedef double (*GetDouble_Proc) ( const void* addr );
+
+typedef XMP_Uns16 (*MakeUns16_Proc) ( XMP_Uns16 value );
+typedef XMP_Uns32 (*MakeUns32_Proc) ( XMP_Uns32 value );
+typedef XMP_Uns64 (*MakeUns64_Proc) ( XMP_Uns64 value );
+typedef float (*MakeFloat_Proc) ( float value );
+typedef double (*MakeDouble_Proc) ( double value );
+
+typedef void (*PutUns16_Proc) ( XMP_Uns16 value, void* addr );
+typedef void (*PutUns32_Proc) ( XMP_Uns32 value, void* addr );
+typedef void (*PutUns64_Proc) ( XMP_Uns64 value, void* addr );
+typedef void (*PutFloat_Proc) ( float value, void* addr );
+typedef void (*PutDouble_Proc) ( double value, void* addr );
+
+// =================================================================================================
+
+static inline XMP_Uns16 Flip2 ( XMP_Uns16 value )
+{
+ value = ((value & 0x00FF) << 8) | ((value & 0xFF00) >> 8);
+ return value;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+static inline void Flip2 ( void * addr )
+{
+ XMP_Uns16 * u16Ptr = (XMP_Uns16*) addr;
+ *u16Ptr = Flip2 ( *u16Ptr );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+static inline XMP_Uns32 Flip4 ( XMP_Uns32 value )
+{
+ value = ((value & 0x000000FF) << 24) | ((value & 0x0000FF00) << 8) |
+ ((value >> 8) & 0x0000FF00) | ((value >> 24) & 0x000000FF);
+ return value;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+static inline void Flip4 ( void * addr )
+{
+ XMP_Uns32 * u32Ptr = (XMP_Uns32*) addr;
+ *u32Ptr = Flip4 ( *u32Ptr );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+static inline XMP_Uns64 Flip8 ( XMP_Uns64 value )
+{
+ XMP_Uns32 oldLow = (XMP_Uns32)(value);
+ XMP_Uns32 oldHigh = (XMP_Uns32)(value >> 32);
+ return (((XMP_Uns64)Flip4(oldLow)) << 32) | ((XMP_Uns64)Flip4(oldHigh));
+}
+
+// -------------------------------------------------------------------------------------------------
+
+static inline void Flip8 ( void * addr )
+{
+ XMP_Uns64 * u64Ptr = (XMP_Uns64*) addr;
+ *u64Ptr = Flip8 ( *u64Ptr );
+}
+
+// =================================================================================================
+
+static inline XMP_Uns16
+GetUns16BE ( const void * addr )
+{
+ XMP_Uns16 value = *((XMP_Uns16*)addr);
+ if ( kLittleEndianHost ) value = Flip2 ( value );
+ return value;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+static inline XMP_Uns16
+GetUns16LE ( const void * addr )
+{
+ XMP_Uns16 value = *((XMP_Uns16*)addr);
+ if ( kBigEndianHost ) value = Flip2 ( value );
+ return value;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+static inline XMP_Uns32
+GetUns32BE ( const void * addr )
+{
+ XMP_Uns32 value = *((XMP_Uns32*)addr);
+ if ( kLittleEndianHost ) value = Flip4 ( value );
+ return value;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+static inline XMP_Uns32
+GetUns32LE ( const void * addr )
+{
+ XMP_Uns32 value = *((XMP_Uns32*)addr);
+ if ( kBigEndianHost ) value = Flip4 ( value );
+ return value;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+static inline XMP_Uns64
+GetUns64BE ( const void * addr )
+{
+ XMP_Uns64 value = *((XMP_Uns64*)addr);
+ if ( kLittleEndianHost ) value = Flip8 ( value );
+ return value;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+static inline XMP_Uns64
+GetUns64LE ( const void * addr )
+{
+ XMP_Uns64 value = *((XMP_Uns64*)addr);
+ if ( kBigEndianHost ) value = Flip8 ( value );
+ return value;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+static inline float
+GetFloatBE ( const void * addr )
+{
+ XMP_Uns32 value = *((XMP_Uns32*)addr);
+ if ( kLittleEndianHost ) value = Flip4 ( value );
+ return *((float*)&value);
+}
+
+// -------------------------------------------------------------------------------------------------
+
+static inline float
+GetFloatLE ( const void * addr )
+{
+ XMP_Uns32 value = *((XMP_Uns32*)addr);
+ if ( kBigEndianHost ) value = Flip4 ( value );
+ return *((float*)&value);
+}
+
+// -------------------------------------------------------------------------------------------------
+
+static inline double
+GetDoubleBE ( const void * addr )
+{
+ XMP_Uns64 value = *((XMP_Uns64*)addr);
+ if ( kLittleEndianHost ) value = Flip8 ( value );
+ return *((double*)&value);
+}
+
+// -------------------------------------------------------------------------------------------------
+
+static inline double
+GetDoubleLE ( const void * addr )
+{
+ XMP_Uns64 value = *((XMP_Uns64*)addr);
+ if ( kBigEndianHost ) value = Flip8 ( value );
+ return *((double*)&value);
+}
+
+// =================================================================================================
+
+static inline XMP_Uns16
+MakeUns16BE ( XMP_Uns16 value )
+{
+ if ( kLittleEndianHost ) value = Flip2 ( value );
+ return value;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+static inline XMP_Uns16
+MakeUns16LE ( XMP_Uns16 value )
+{
+ if ( kBigEndianHost ) value = Flip2 ( value );
+ return value;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+static inline XMP_Uns32
+MakeUns32BE ( XMP_Uns32 value )
+{
+ if ( kLittleEndianHost ) value = Flip4 ( value );
+ return value;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+static inline XMP_Uns32
+MakeUns32LE ( XMP_Uns32 value )
+{
+ if ( kBigEndianHost ) value = Flip4 ( value );
+ return value;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+static inline XMP_Uns64
+MakeUns64BE ( XMP_Uns64 value )
+{
+ if ( kLittleEndianHost ) value = Flip8 ( value );
+ return value;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+static inline XMP_Uns64
+MakeUns64LE ( XMP_Uns64 value )
+{
+ if ( kBigEndianHost ) value = Flip8 ( value );
+ return value;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+static inline float
+MakeFloatBE ( float value )
+{
+ if ( kLittleEndianHost ) {
+ XMP_Uns32* intPtr = (XMP_Uns32*) &value;
+ *intPtr = Flip4 ( *intPtr );
+ }
+ return value;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+static inline float
+MakeFloatLE ( float value )
+{
+ if ( kBigEndianHost ) {
+ XMP_Uns32* intPtr = (XMP_Uns32*) &value;
+ *intPtr = Flip4 ( *intPtr );
+ }
+ return value;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+static inline double
+MakeDoubleBE ( double value )
+{
+ if ( kLittleEndianHost ) {
+ XMP_Uns64* intPtr = (XMP_Uns64*) &value;
+ *intPtr = Flip8 ( *intPtr );
+ }
+ return value;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+static inline double
+MakeDoubleLE ( double value )
+{
+ if ( kBigEndianHost ) {
+ XMP_Uns64* intPtr = (XMP_Uns64*) &value;
+ *intPtr = Flip8 ( *intPtr );
+ }
+ return value;
+}
+
+// =================================================================================================
+
+static inline void
+PutUns16BE ( XMP_Uns16 value, void * addr )
+{
+ if ( kLittleEndianHost ) value = Flip2 ( value );
+ *((XMP_Uns16*)addr) = value;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+static inline void
+PutUns16LE ( XMP_Uns16 value, void * addr )
+{
+ if ( kBigEndianHost ) value = Flip2 ( value );
+ *((XMP_Uns16*)addr) = value;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+static inline void
+PutUns32BE ( XMP_Uns32 value, void * addr )
+{
+ if ( kLittleEndianHost ) value = Flip4 ( value );
+ *((XMP_Uns32*)addr) = value;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+static inline void
+PutUns32LE ( XMP_Uns32 value, void * addr )
+{
+ if ( kBigEndianHost ) value = Flip4 ( value );
+ *((XMP_Uns32*)addr) = value;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+static inline void
+PutUns64BE ( XMP_Uns64 value, void * addr )
+{
+ if ( kLittleEndianHost ) value = Flip8 ( value );
+ *((XMP_Uns64*)addr) = value;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+static inline void
+PutUns64LE ( XMP_Uns64 value, void * addr )
+{
+ if ( kBigEndianHost ) value = Flip8 ( value );
+ *((XMP_Uns64*)addr) = value;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+static inline void
+PutFloatBE ( float value, void * addr )
+{
+ if ( kLittleEndianHost ) {
+ XMP_Uns32* intPtr = (XMP_Uns32*) &value;
+ *intPtr = Flip4 ( *intPtr );
+ }
+ *((float*)addr) = value;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+static inline void
+PutFloatLE ( float value, void * addr )
+{
+ if ( kBigEndianHost ) {
+ XMP_Uns32* intPtr = (XMP_Uns32*) &value;
+ *intPtr = Flip4 ( *intPtr );
+ }
+ *((float*)addr) = value;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+static inline void
+PutDoubleBE ( double value, void * addr )
+{
+ if ( kLittleEndianHost ) {
+ XMP_Uns64* intPtr = (XMP_Uns64*) &value;
+ *intPtr = Flip8 ( *intPtr );
+ }
+ *((double*)addr) = value;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+static inline void
+PutDoubleLE ( double value, void * addr )
+{
+ if ( kBigEndianHost ) {
+ XMP_Uns64* intPtr = (XMP_Uns64*) &value;
+ *intPtr = Flip8 ( *intPtr );
+ }
+ *((double*)addr) = value;
+}
+
+// =================================================================================================
+
+#endif // __EndianUtils_hpp__
diff --git a/source/XMPFiles/FormatSupport/ID3_Support.cpp b/source/XMPFiles/FormatSupport/ID3_Support.cpp
new file mode 100644
index 0000000..793f925
--- /dev/null
+++ b/source/XMPFiles/FormatSupport/ID3_Support.cpp
@@ -0,0 +1,1137 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "XMP_Environment.h" // ! This must be the first include.
+#include "XMP_Const.h"
+
+#include "ID3_Support.hpp"
+
+#include "UnicodeConversions.hpp"
+#include "Reconcile_Impl.hpp"
+
+#if XMP_WinBuild
+ #pragma warning ( disable : 4996 ) // '...' was declared deprecated
+#endif
+
+// For more information about the id3v2 specification
+// Please refer to http://www.id3.org/develop.html
+
+namespace ID3_Support {
+
+ char Genres[128][32]={
+ "Blues", // 0
+ "Classic Rock", // 1
+ "Country", // 2
+ "Dance",
+ "Disco",
+ "Funk",
+ "Grunge",
+ "Hip-Hop",
+ "Jazz", // 8
+ "Metal",
+ "New Age", // 10
+ "Oldies",
+ "Other", // 12
+ "Pop",
+ "R&B",
+ "Rap",
+ "Reggae", // 16
+ "Rock", // 17
+ "Techno",
+ "Industrial",
+ "Alternative",
+ "Ska",
+ "Death Metal",
+ "Pranks",
+ "Soundtrack", // 24
+ "Euro-Techno",
+ "Ambient",
+ "Trip-Hop",
+ "Vocal",
+ "Jazz+Funk",
+ "Fusion",
+ "Trance",
+ "Classical", // 32
+ "Instrumental",
+ "Acid",
+ "House",
+ "Game",
+ "Sound Clip",
+ "Gospel",
+ "Noise",
+ "AlternRock",
+ "Bass",
+ "Soul", //42
+ "Punk",
+ "Space",
+ "Meditative",
+ "Instrumental Pop",
+ "Instrumental Rock",
+ "Ethnic",
+ "Gothic",
+ "Darkwave",
+ "Techno-Industrial",
+ "Electronic",
+ "Pop-Folk",
+ "Eurodance",
+ "Dream",
+ "Southern Rock",
+ "Comedy",
+ "Cult",
+ "Gangsta",
+ "Top 40",
+ "Christian Rap",
+ "Pop/Funk",
+ "Jungle",
+ "Native American",
+ "Cabaret",
+ "New Wave", // 66
+ "Psychadelic",
+ "Rave",
+ "Showtunes",
+ "Trailer",
+ "Lo-Fi",
+ "Tribal",
+ "Acid Punk",
+ "Acid Jazz",
+ "Polka",
+ "Retro",
+ "Musical",
+ "Rock & Roll",
+ "Hard Rock",
+ "Folk", // 80
+ "Folk-Rock",
+ "National Folk",
+ "Swing",
+ "Fast Fusion",
+ "Bebob",
+ "Latin",
+ "Revival",
+ "Celtic",
+ "Bluegrass", // 89
+ "Avantgarde",
+ "Gothic Rock",
+ "Progressive Rock",
+ "Psychedelic Rock",
+ "Symphonic Rock",
+ "Slow Rock",
+ "Big Band",
+ "Chorus",
+ "Easy Listening",
+ "Acoustic",
+ "Humour", // 100
+ "Speech",
+ "Chanson",
+ "Opera",
+ "Chamber Music",
+ "Sonata",
+ "Symphony",
+ "Booty Bass",
+ "Primus",
+ "Porn Groove",
+ "Satire",
+ "Slow Jam",
+ "Club",
+ "Tango",
+ "Samba",
+ "Folklore",
+ "Ballad",
+ "Power Ballad",
+ "Rhythmic Soul",
+ "Freestyle",
+ "Duet",
+ "Punk Rock",
+ "Drum Solo",
+ "A capella",
+ "Euro-House",
+ "Dance Hall",
+ "Unknown" // 126
+ };
+
+ // Some types
+ #ifndef XMP_Int64
+ typedef unsigned long long XMP_Int64;
+ #endif
+
+ static bool FindXMPFrame(LFA_FileRef inFileRef, XMP_Int64 &posXMP, XMP_Int64 &posPAD, unsigned long &dwExtendedTag, unsigned long &dwLen);
+ static unsigned long SkipExtendedHeader(LFA_FileRef inFileRef, XMP_Uns8 bVersion, XMP_Uns8 flag);
+ static bool GetFrameInfo(LFA_FileRef inFileRef, XMP_Uns8 bVersion, char *strFrameID, XMP_Uns8 &cflag1, XMP_Uns8 &cflag2, unsigned long &dwSize);
+ static bool ReadSize(LFA_FileRef inFileRef, XMP_Uns8 bVersion, unsigned long &dwSize);
+ static unsigned long CalculateSize(XMP_Uns8 bVersion, unsigned long dwSizeIn);
+ static bool LoadTagHeaderAndUnknownFrames(LFA_FileRef inFileRef, char *strBuffer, bool fRecon, unsigned long &posPad);
+
+ #define GetFilePosition(file) LFA_Seek ( file, 0, SEEK_CUR )
+
+ const unsigned long k_dwTagHeaderSize = 10;
+ const unsigned long k_dwFrameHeaderSize = 10;
+ const unsigned long k_dwXMPLabelSize = 4; // 4 (size of "XMP\0")
+
+// ID3v2 flags %abcd0000
+// Where:
+// a - Unsynchronisation
+// b - Extended header
+// c - Experimental indicator
+// d - Footer present
+ const unsigned char flagUnsync = 0x80; // (MSb)
+ const unsigned char flagExt = 0x40;
+ const unsigned char flagExp = 0x20;
+ const unsigned char flagFooter = 0x10;
+
+
+#ifndef Trace_ID3_Support
+ #define Trace_ID3_Support 0
+#endif
+
+// =================================================================================================
+
+#if XMP_WinBuild
+
+ #define stricmp _stricmp
+
+#else
+
+ static int stricmp ( const char * left, const char * right ) // Case insensitive ASCII compare.
+ {
+ char chL = *left; // ! Allow for 0 passes in the loop (one string is empty).
+ char chR = *right; // ! Return -1 for stricmp ( "a", "Z" ).
+
+ for ( ; (*left != 0) && (*right != 0); ++left, ++right ) {
+ chL = *left;
+ chR = *right;
+ if ( chL == chR ) continue;
+ if ( ('A' <= chL) && (chL <= 'Z') ) chL |= 0x20;
+ if ( ('A' <= chR) && (chR <= 'Z') ) chR |= 0x20;
+ if ( chL != chR ) break;
+ }
+
+ if ( chL == chR ) return 0;
+ if ( chL < chR ) return -1;
+ return 1;
+
+ }
+
+#endif
+
+// =================================================================================================
+
+// *** Load Scenario:
+// - Check for id3v2 tag
+//
+// - Parse through the frame for "PRIV" + UTF8 Encoding + "XMP"
+//
+// - If found, load it.
+bool GetMetaData ( LFA_FileRef inFileRef, char* buffer, unsigned long* pBufferSize, ::XMP_Int64* fileOffset )
+{
+
+ if ( pBufferSize == 0 ) return false;
+
+ unsigned long dwSizeIn = *pBufferSize;
+ *pBufferSize = 0;
+ XMP_Int64 posXMP = 0ULL, posPAD = 0ULL;
+ unsigned long dwLen = 0, dwExtendedTag = 0;
+ if ( ! FindXMPFrame ( inFileRef, posXMP, posPAD, dwExtendedTag, dwLen ) ) return false;
+
+ // Found the XMP frame! Get the rest of frame into the buffer
+ unsigned long dwXMPBufferLen = dwLen - k_dwXMPLabelSize;
+ *pBufferSize = dwXMPBufferLen;
+
+ if ( fileOffset != 0 ) *fileOffset = posXMP + k_dwXMPLabelSize;
+
+ if ( buffer != 0 ) {
+ // Seek 4 bytes ahead to get the XMP data.
+ LFA_Seek ( inFileRef, posXMP+k_dwXMPLabelSize, SEEK_SET );
+ if ( dwXMPBufferLen > dwSizeIn ) dwXMPBufferLen = dwSizeIn;
+ LFA_Read ( inFileRef, buffer, dwXMPBufferLen ); // Get the XMP frame
+ }
+
+ return true;
+
+}
+
+// =================================================================================================
+
+bool FindFrame ( LFA_FileRef inFileRef, char* strFrame, XMP_Int64 & posFrame, unsigned long & dwLen )
+{
+ // Taking into account that the first Tag is the ID3 tag
+ bool fReturn = false;
+ LFA_Seek ( inFileRef, 0ULL, SEEK_SET );
+
+ #if Trace_ID3_Support
+ fprintf ( stderr, "ID3_Support::FindFrame : Looking for %s\n", strFrame );
+ #endif
+
+ // Read the tag name
+ char szID[4] = {"xxx"};
+ long bytesRead = LFA_Read ( inFileRef, szID, 3 );
+ if ( bytesRead == 0 ) return fReturn;
+
+ // Check for "ID3"
+ if ( strcmp ( szID, "ID3" ) != 0 ) return fReturn;
+
+ // Read the version, flag and size
+ XMP_Uns8 v1 = 0, v2 = 0, flags = 0;
+ unsigned long dwTagSize = 0;
+
+ if ( ! GetTagInfo ( inFileRef, v1, v2, flags, dwTagSize ) ) return fReturn;
+ if ( dwTagSize == 0 ) return fReturn;
+ if ( v1 > 4 ) return fReturn; // We don't support anything newer than id3v2 4.0
+
+ // If there's an extended header, ignore it
+ XMP_Int32 dwExtendedTag = SkipExtendedHeader(inFileRef, v1, flags);
+ dwTagSize -= dwExtendedTag;
+
+ // Enumerate through the frames
+ XMP_Int64 posCur = 0ULL;
+ posCur = GetFilePosition ( inFileRef );
+ XMP_Int64 posEnd = posCur + dwTagSize;
+
+ while ( posCur < posEnd ) {
+
+ char szFrameID[5] = {"xxxx"};
+ unsigned long dwFrameSize = 0;
+ XMP_Uns8 cflag1 = 0, cflag2 = 0;
+
+ // Get the next frame
+ if ( ! GetFrameInfo ( inFileRef, v1, szFrameID, cflag1, cflag2, dwFrameSize ) ) break;
+
+ // Are we in a padding frame?
+ if ( dwFrameSize == 0 ) break;
+
+ // Is it the Frame we're looking for?
+ if ( strcmp ( szFrameID, strFrame ) == 0 ) {
+ posFrame = GetFilePosition ( inFileRef );
+ dwLen = dwFrameSize;
+ fReturn = true;
+ break;
+ } else {
+ // Jump to the next frame
+ LFA_Seek ( inFileRef, dwFrameSize, SEEK_CUR );
+ }
+
+ posCur = GetFilePosition ( inFileRef );
+ }
+
+ #if Trace_ID3_Support
+ if ( fReturn ) {
+ fprintf ( stderr, " Found %s, offset %d, length %d\n", strFrame, (long)posFrame, dwLen );
+ }
+ #endif
+
+ return fReturn;
+}
+
+// =================================================================================================
+
+bool GetFrameData ( LFA_FileRef inFileRef, char* strFrame, char* buffer, unsigned long &dwBufferSize )
+{
+ char strData[TAG_MAX_SIZE+4]; // Plus 4 for two worst case UTF-16 nul terminators.
+ size_t sdPos = 0; // Offset within strData to the value.
+ memset ( &strData[0], 0, sizeof(strData) );
+
+ if ( (buffer == 0) || (dwBufferSize > TAG_MAX_SIZE) ) return false;
+
+ const unsigned long dwSizeIn = dwBufferSize;
+ XMP_Int64 posFrame = 0ULL;
+ unsigned long dwLen = 0;
+ XMP_Uns8 bEncoding = 0;
+
+ // Find the frame
+ if ( ! FindFrame ( inFileRef, strFrame, posFrame, dwLen ) ) return false;
+ #if Trace_ID3_Support
+ fprintf ( stderr, " Getting frame data\n" );
+ #endif
+
+ if ( dwLen <= 0 ) {
+
+ dwBufferSize = 1;
+ buffer[0] = 0;
+
+ } else {
+
+ // Get the value for a typical text frame, having an encoding byte followed by the value.
+ // COMM frames are special, see below. First get encoding, and the frame data into strData.
+
+ dwBufferSize = dwLen - 1; // Don't count the encoding byte.
+
+ // Seek to the frame
+ LFA_Seek ( inFileRef, posFrame, SEEK_SET );
+
+ // Read the Encoding
+ LFA_Read ( inFileRef, &bEncoding, 1 );
+ if ( bEncoding > 3 ) return false;
+
+ // Get the frame
+ if ( dwBufferSize > dwSizeIn ) dwBufferSize = dwSizeIn;
+
+ if ( dwBufferSize >= TAG_MAX_SIZE ) return false; // No room for data.
+ LFA_Read ( inFileRef, &strData[0], dwBufferSize );
+
+ if ( strcmp ( strFrame, "COMM" ) == 0 ) {
+
+ // A COMM frame has a 3 byte language tag, then an encoded and nul terminated description
+ // string, then the encoded value string. Set dwOffset to the offset to the value.
+
+ unsigned long dwOffset = 3; // Skip the 3 byte language code.
+
+ if ( (bEncoding == 0) || (bEncoding == 3) ) {
+ dwOffset += (strlen ( &strData[3] ) + 1); // Skip the descriptor and nul.
+ } else {
+ UTF16Unit* u16Ptr = (UTF16Unit*) (&strData[3]);
+ for ( ; *u16Ptr != 0; ++u16Ptr ) dwOffset += 2; // Skip the descriptor.
+ dwOffset += 2; // Skip the nul also.
+ }
+
+ if ( dwOffset >= dwBufferSize ) return false;
+ dwBufferSize -= dwOffset;
+
+ sdPos = dwOffset;
+
+ #if Trace_ID3_Support
+ fprintf ( stderr, " COMM frame, dwOffset %d\n", dwOffset );
+ #endif
+
+ }
+
+ // Encoding translation
+ switch ( bEncoding ) {
+
+ case 1: // UTF-16 with a BOM. (Might be missing for empty string.)
+ case 2: // Big endian UTF-16 with no BOM.
+ {
+ bool bigEndian = true; // Assume big endian if no BOM.
+ UTF16Unit* u16Ptr = (UTF16Unit*) &strData[sdPos];
+
+ if ( GetUns16BE ( u16Ptr ) == 0xFEFF ) {
+ ++u16Ptr; // Don't translate the BOM.
+ } else if ( GetUns16BE ( u16Ptr ) == 0xFFFE ) {
+ bigEndian = false;
+ ++u16Ptr; // Don't translate the BOM.
+ }
+
+ size_t u16Len = 0; // Count the UTF-16 units, not bytes.
+ for ( UTF16Unit* temp = u16Ptr; *temp != 0; ++temp ) ++u16Len;
+
+ std::string utf8Str;
+ FromUTF16 ( u16Ptr, u16Len, &utf8Str, bigEndian );
+ if ( utf8Str.size() >= (sizeof(strData) - sdPos) ) return false;
+ strcpy ( &strData[sdPos], utf8Str.c_str() ); // AUDIT: Protected by the above check.
+ }
+ break;
+
+ case 0: // ISO Latin-1 (8859-1).
+ {
+ std::string utf8Str;
+ char* localPtr = &strData[sdPos];
+ size_t localLen = dwBufferSize;
+
+ ReconcileUtils::Latin1ToUTF8 ( localPtr, localLen, &utf8Str );
+ if ( utf8Str.size() >= (sizeof(strData) - sdPos) ) return false;
+ strcpy ( &strData[sdPos], utf8Str.c_str() ); // AUDIT: Protected by the above check.
+ }
+ break;
+
+ case 3: // UTF-8
+ default:
+ // Handled appropriately
+ break;
+
+ }
+
+ char * strTemp = &strData[sdPos];
+
+ if ( strcmp ( strFrame, "TCON" ) == 0 ) {
+
+ char str[TAG_MAX_SIZE];
+ str[0] = 0;
+ if ( strlen ( &strData[sdPos] ) >= sizeof(str) ) return false;
+ strcpy ( str, &strData[sdPos] ); // AUDIT: Protected by the above check.
+
+ #if Trace_ID3_Support
+ fprintf ( stderr, " TCON frame, first char '%c'\n", str[0] );
+ #endif
+
+ // Genre: let's get the "string" value
+ if ( str[0] == '(' ) {
+ int iGenre = atoi(str+1);
+ if ( (iGenre > 0) && (iGenre < 127) ) {
+ strTemp = Genres[iGenre];
+ } else {
+ strTemp = Genres[12];
+ }
+ } else {
+ // Text, let's "try" to find it anyway
+ int i = 0;
+ for ( i=0; i < 127; ++i ) {
+ if ( stricmp ( str, Genres[i] ) == 0 ) {
+ strTemp = Genres[i]; // Found, let's use the one in the list
+ break;
+ }
+ }
+ if ( i == 127 ) strTemp = Genres[12]; // Not found
+ }
+
+ }
+
+ #if Trace_ID3_Support
+ fprintf ( stderr, " Have data, length %d, \"%s\"\n", strlen(strTemp), strTemp );
+ #endif
+
+ if ( strlen(strTemp) >= dwSizeIn ) return false;
+ strcpy ( buffer, strTemp ); // AUDIT: Protected by the above check.
+
+ }
+
+ return true;
+
+}
+
+// =================================================================================================
+
+bool AddXMPTagToID3Buffer ( char * strCur, unsigned long * pdwCurOffset, unsigned long dwMaxSize, XMP_Uns8 bVersion,
+ char *strFrameName, const char * strXMPTagTemp, unsigned long dwXMPLengthTemp )
+{
+ char strGenre[64];
+ const char * strXMPTag = strXMPTagTemp;
+ XMP_Int32 dwCurOffset = *pdwCurOffset;
+ XMP_Uns8 bEncoding = 0;
+ long dwXMPLength = dwXMPLengthTemp;
+
+ if ( dwXMPLength == 0 ) return false;
+
+ if ( strcmp ( strFrameName, "TCON" ) == 0 ) {
+
+ // Genre: we need to get the number back...
+ int iFound = 12;
+
+ for ( int i=0; i < 127; ++i ) {
+ if ( stricmp ( strXMPTag, Genres[i] ) == 0 ) {
+ iFound = i; // Found
+ break;
+ }
+ }
+
+ snprintf ( strGenre, sizeof(strGenre), "(%d)", iFound ); // AUDIT: Using sizeof(strGenre) is safe.
+ strXMPTag = strGenre;
+ dwXMPLength = strlen(strXMPTag);
+
+ }
+
+ // Stick with the ID3v2.3 encoding choices, they are a proper subset of ID3v2.4.
+ // 0 - ISO Latin-1
+ // 1 - UTF-16 with BOM
+ // For 3rd party reliability we always write UTF-16 as little endian. For example, Windows
+ // Media Player fails to honor the BOM, it assumes little endian.
+
+ std::string tempLatin1, tempUTF8;
+ ReconcileUtils::UTF8ToLatin1 ( strXMPTag, dwXMPLength, &tempLatin1 );
+ ReconcileUtils::Latin1ToUTF8 ( tempLatin1.data(), tempLatin1.size(), &tempUTF8 );
+ if ( ((size_t)dwXMPLength != tempUTF8.size()) || (memcmp ( strXMPTag, tempUTF8.data(), dwXMPLength ) != 0) ) {
+ bEncoding = 1; // Will convert to UTF-16 later.
+ } else {
+ strXMPTag = tempLatin1.c_str(); // Use the Latin-1 encoding for output.
+ dwXMPLength = tempLatin1.size();
+ }
+
+ std::string strUTF16;
+ if ( bEncoding == 1 ) {
+ ToUTF16 ( (UTF8Unit*)strXMPTag, dwXMPLength, &strUTF16, false /* little endian */ );
+ dwXMPLength = strUTF16.size() + 2; // ! Include the (to be inserted) BOM in the count.
+ }
+
+ // Frame Structure
+ // Frame ID $xx xx xx xx (four characters)
+ // Size 4 * %0xxxxxxx <<--- IMPORTANT NOTE: This is true only in v4.0 (v3.0 uses a UInt32)
+ // Flags $xx xx
+ // Encoding $xx (Not included in the frame header)
+ // Special case: "COMM" which we have to include "XXX\0" in front of it (also not included in the frame header)
+
+ unsigned long dwFrameSize = dwXMPLength + 1; // 1 == Encoding;
+
+ bool fCOMM = (strcmp ( strFrameName, "COMM" ) == 0);
+ if ( fCOMM ) {
+ dwFrameSize += 3; // The "XXX" language part.
+ dwFrameSize += ((bEncoding == 0) ? 1 : 4 ); // The empty descriptor string.
+ }
+
+ if ( (dwCurOffset + k_dwFrameHeaderSize + dwFrameSize) > dwMaxSize ) return false;
+
+ unsigned long dwCalculated = CalculateSize ( bVersion, dwFrameSize );
+
+ // FrameID
+ if ( (dwMaxSize - dwCurOffset) < 4 ) return false;
+ memcpy ( strCur+dwCurOffset, strFrameName, 4 ); // AUDIT: Protected by the above check.
+ dwCurOffset += 4;
+
+ // Frame Size - written as big endian
+ strCur[dwCurOffset] = (char)(dwCalculated >> 24);
+ ++dwCurOffset;
+ strCur[dwCurOffset] = (char)((dwCalculated >> 16) & 0xFF);
+ ++dwCurOffset;
+ strCur[dwCurOffset] = (char)((dwCalculated >> 8) & 0xFF);
+ ++dwCurOffset;
+ strCur[dwCurOffset] = (char)(dwCalculated & 0xFF);
+ ++dwCurOffset;
+
+ // Flags
+ strCur[dwCurOffset] = 0;
+ ++dwCurOffset;
+ strCur[dwCurOffset] = 0;
+ ++dwCurOffset;
+
+ // Encoding
+ strCur[dwCurOffset] = bEncoding;
+ ++dwCurOffset;
+
+ // COMM extras: XXX language and empty encoded descriptor string.
+ if ( fCOMM ) {
+ if ( (dwMaxSize - dwCurOffset) < 3 ) return false;
+ memcpy ( strCur+dwCurOffset, "XXX", 3 ); // AUDIT: Protected by the above check.
+ dwCurOffset += 3;
+ if ( bEncoding == 0 ) {
+ strCur[dwCurOffset] = 0;
+ ++dwCurOffset;
+ } else {
+ strCur[dwCurOffset] = 0xFF;
+ ++dwCurOffset;
+ strCur[dwCurOffset] = 0xFE;
+ ++dwCurOffset;
+ strCur[dwCurOffset] = 0;
+ ++dwCurOffset;
+ strCur[dwCurOffset] = 0;
+ ++dwCurOffset;
+ }
+ }
+
+ if ( bEncoding == 1 ) {
+ // Add the BOM "FFFE"
+ strCur[dwCurOffset] = 0xFF;
+ ++dwCurOffset;
+ strCur[dwCurOffset] = 0xFE;
+ ++dwCurOffset;
+ dwXMPLength -= 2; // The BOM was included above.
+ // Copy the Unicode data
+ if ( (long)(dwMaxSize - dwCurOffset) < dwXMPLength ) return false;
+ memcpy ( strCur+dwCurOffset, strUTF16.data(), dwXMPLength ); // AUDIT: Protected by the above check.
+ dwCurOffset += dwXMPLength;
+ } else {
+ // Copy the data
+ if ( (long)(dwMaxSize - dwCurOffset) < dwXMPLength ) return false;
+ memcpy ( strCur+dwCurOffset, strXMPTag, dwXMPLength ); // AUDIT: Protected by the above check.
+ dwCurOffset += dwXMPLength;
+ }
+
+ *pdwCurOffset = dwCurOffset;
+
+ return true;
+
+}
+
+// =================================================================================================
+
+static void OffsetAudioData ( LFA_FileRef inFileRef, XMP_Int64 audioOffset, XMP_Int64 oldAudioBase )
+{
+ enum { kBuffSize = 64*1024 };
+ XMP_Uns8 buffer [kBuffSize];
+
+ const XMP_Int64 posEOF = LFA_Measure ( inFileRef );
+ XMP_Int64 posCurrentCopy; // ! Must be a signed type!
+
+ posCurrentCopy = posEOF;
+ while ( posCurrentCopy >= (oldAudioBase + kBuffSize) ) {
+ posCurrentCopy -= kBuffSize; // *** Xcode 2.3 seemed to generate bad code using a for loop.
+ LFA_Seek ( inFileRef, posCurrentCopy, SEEK_SET );
+ LFA_Read ( inFileRef, buffer, kBuffSize );
+ LFA_Seek ( inFileRef, (posCurrentCopy + audioOffset), SEEK_SET );
+ LFA_Write ( inFileRef, buffer, kBuffSize );
+ }
+
+ if ( posCurrentCopy != oldAudioBase ) {
+ XMP_Uns32 remainder = (XMP_Uns32) (posCurrentCopy - oldAudioBase);
+ XMP_Assert ( remainder < kBuffSize );
+ LFA_Seek ( inFileRef, oldAudioBase, SEEK_SET );
+ LFA_Read ( inFileRef, buffer, remainder );
+ LFA_Seek ( inFileRef, (oldAudioBase + audioOffset), SEEK_SET );
+ LFA_Write ( inFileRef, buffer, remainder );
+ }
+
+}
+
+// =================================================================================================
+
+bool SetMetaData ( LFA_FileRef inFileRef, char* strXMPPacket, unsigned long dwXMPPacketSize,
+ char* strLegacyFrames, unsigned long dwFullLegacySize, bool fRecon )
+{
+ // The ID3 section layout:
+ // ID3 header, 10 bytes
+ // Unrecognized ID3 frames
+ // Legacy ID3 metadata frames (artist, album, genre, etc.)
+ // XMP frame, content is "XMP\0" plus the packet
+ // padding
+
+ // ID3 Buffer vars
+ const unsigned long kiMaxBuffer = 100*1000;
+ char szID3Buffer [kiMaxBuffer]; // Must be enough for the ID3 header, unknown ID3 frames, and legacy ID3 metadata.
+ unsigned long id3BufferLen = 0; // The amount of stuff currently in the buffer.
+
+ unsigned long dwOldID3ContentSize = 0; // The size of the existing ID3 content (not counting the header).
+ unsigned long dwNewID3ContentSize = 0; // The size of the updated ID3 content (not counting the header).
+
+ unsigned long newPadSize = 0;
+
+ XMP_Uns8 bMajorVersion = 3;
+
+ bool fFoundID3 = FindID3Tag ( inFileRef, dwOldID3ContentSize, bMajorVersion );
+ if ( (bMajorVersion > 4) || (bMajorVersion < 3) ) return false; // Not supported
+
+ // Now that we know the version of the ID3 tag, let's format the size of the XMP frame.
+
+ #define k_XMPPrefixSize (k_dwFrameHeaderSize + k_dwXMPLabelSize)
+ char szXMPPrefix [k_XMPPrefixSize] = { 'P', 'R', 'I', 'V', 0, 0, 0, 0, 0, 0, 'X', 'M', 'P', 0 };
+ unsigned long dwXMPContentSize = k_dwXMPLabelSize + dwXMPPacketSize;
+ unsigned long dwFullXMPFrameSize = k_dwFrameHeaderSize + dwXMPContentSize;
+
+ unsigned long dwFormattedTemp = CalculateSize ( bMajorVersion, dwXMPContentSize );
+
+ szXMPPrefix[4] = (char)(dwFormattedTemp >> 24);
+ szXMPPrefix[5] = (char)((dwFormattedTemp >> 16) & 0xFF);
+ szXMPPrefix[6] = (char)((dwFormattedTemp >> 8) & 0xFF);
+ szXMPPrefix[7] = (char)(dwFormattedTemp & 0xFF);
+
+ // Set up the ID3 buffer with the ID3 header and any existing unrecognized ID3 frames.
+
+ if ( ! fFoundID3 ) {
+
+ // Case 1 - No id3v2 tag: Create the tag with the XMP frame.
+ // Create the tag
+ // ID3v2/file identifier "ID3"
+ // ID3v2 version $03 00
+ // ID3v2 flags %abcd0000
+ // ID3v2 size 4 * %0xxxxxxx
+
+ XMP_Assert ( dwOldID3ContentSize == 0 );
+
+ char szID3Header [k_dwTagHeaderSize] = { 'I', 'D', '3', 3, 0, 0, 0, 0, 0, 0 };
+
+ // Copy the ID3 header
+ if ( sizeof(szID3Buffer) < k_dwTagHeaderSize ) return false;
+ memcpy ( szID3Buffer, szID3Header, k_dwTagHeaderSize ); // AUDIT: Protected by the above check.
+ id3BufferLen = k_dwTagHeaderSize;
+
+ newPadSize = 100;
+ dwNewID3ContentSize = dwFullLegacySize + dwFullXMPFrameSize + newPadSize;
+
+ } else {
+
+ // Case 2 - id3v2 tag is present
+ // 1. Copy all the unknown tags
+ // 2. Make the rest padding (to be used right there).
+
+ if ( (k_dwFrameHeaderSize + dwOldID3ContentSize) > kiMaxBuffer ) {
+ // The ID3Buffer is not big enough to fit the id3v2 tag... let's bail...
+ return false;
+ }
+
+ LoadTagHeaderAndUnknownFrames ( inFileRef, szID3Buffer, fRecon, id3BufferLen );
+
+ unsigned long spareLen = (k_dwFrameHeaderSize + dwOldID3ContentSize) - id3BufferLen;
+
+ if ( spareLen >= (dwFullLegacySize + dwFullXMPFrameSize) ) {
+
+ // The exising ID3 header can hold the update.
+ dwNewID3ContentSize = dwOldID3ContentSize;
+ newPadSize = spareLen - (dwFullLegacySize + dwFullXMPFrameSize);
+
+ } else {
+
+ // The existing ID3 header is too small, it will have to grow.
+ newPadSize = 100;
+ dwNewID3ContentSize = (id3BufferLen - k_dwTagHeaderSize) +
+ dwFullLegacySize + dwFullXMPFrameSize + newPadSize;
+
+ }
+
+ }
+
+ // Move the audio data if the ID3 frame is new or has to grow.
+
+ XMP_Assert ( dwNewID3ContentSize >= dwOldID3ContentSize );
+
+ if ( dwNewID3ContentSize > dwOldID3ContentSize ) {
+ unsigned long audioOffset = dwNewID3ContentSize - dwOldID3ContentSize;
+ unsigned long oldAudioBase = k_dwTagHeaderSize + dwOldID3ContentSize;
+ if ( ! fFoundID3 ) {
+ // We're injecting an entire ID3 section.
+ audioOffset = k_dwTagHeaderSize + dwNewID3ContentSize;
+ oldAudioBase = 0;
+ }
+ OffsetAudioData ( inFileRef, audioOffset, oldAudioBase );
+ }
+
+ // Set the new size for the ID3 content. This always uses the 4x7 format.
+
+ dwFormattedTemp = CalculateSize ( 4, dwNewID3ContentSize );
+ szID3Buffer[6] = (char)(dwFormattedTemp >> 24);
+ szID3Buffer[7] = (char)((dwFormattedTemp >> 16) & 0xFF);
+ szID3Buffer[8] = (char)((dwFormattedTemp >> 8) & 0xFF);
+ szID3Buffer[9] = (char)(dwFormattedTemp & 0xFF);
+
+ // Write the partial ID3 buffer (ID3 header plus unknown tags)
+ LFA_Seek ( inFileRef, 0, SEEK_SET );
+ LFA_Write ( inFileRef, szID3Buffer, id3BufferLen );
+
+ // Append the new legacy metadata frames
+ if ( dwFullLegacySize > 0 ) {
+ LFA_Write ( inFileRef, strLegacyFrames, dwFullLegacySize );
+ }
+
+ // Append the XMP frame prefix
+ LFA_Write ( inFileRef, szXMPPrefix, k_XMPPrefixSize );
+
+ // Append the XMP packet
+ LFA_Write ( inFileRef, strXMPPacket, dwXMPPacketSize );
+
+ // Append the padding.
+ if ( newPadSize > 0 ) {
+ std::string szPad;
+ szPad.reserve ( newPadSize );
+ szPad.assign ( newPadSize, '\0' );
+ LFA_Write ( inFileRef, const_cast<char *>(szPad.data()), newPadSize );
+ }
+
+ LFA_Flush ( inFileRef );
+
+ return true;
+
+}
+
+// =================================================================================================
+
+bool LoadTagHeaderAndUnknownFrames ( LFA_FileRef inFileRef, char * strBuffer, bool fRecon, unsigned long & posPad )
+{
+
+ LFA_Seek ( inFileRef, 3ULL, SEEK_SET ); // Point after the "ID3"
+
+ // Get the tag info
+ unsigned long dwOffset = 0;
+ XMP_Uns8 v1 = 0, v2 = 0, flags = 0;
+ unsigned long dwTagSize = 0;
+ GetTagInfo ( inFileRef, v1, v2, flags, dwTagSize );
+
+ unsigned long dwExtendedTag = SkipExtendedHeader ( inFileRef, v1, flags );
+
+ LFA_Seek ( inFileRef, 0ULL, SEEK_SET );
+ LFA_Read ( inFileRef, strBuffer, k_dwTagHeaderSize );
+ dwOffset += k_dwTagHeaderSize;
+
+ // Completely ignore the Extended Header
+ if ( ((flags & flagExt) == flagExt) && (dwExtendedTag > 0) ) {
+ strBuffer[5] = strBuffer[5] & 0xBF; // If the flag has been set, let's reset it
+ LFA_Seek ( inFileRef, dwExtendedTag, SEEK_CUR ); // And let's seek up to after the extended header
+ }
+
+ // Enumerate through the frames
+ XMP_Int64 posCur = 0ULL;
+ posCur = GetFilePosition ( inFileRef );
+ XMP_Int64 posEnd = posCur + dwTagSize;
+
+ while ( posCur < posEnd ) {
+
+ char szFrameID[5] = {"xxxx"};
+ unsigned long dwFrameSize = 0;
+ XMP_Uns8 cflag1 = 0, cflag2 = 0;
+
+ // Get the next frame
+ if ( ! GetFrameInfo ( inFileRef, v1, szFrameID, cflag1, cflag2, dwFrameSize ) ) break;
+
+ // Are we in a padding frame?
+ if ( dwFrameSize == 0 ) break; // We just hit a padding frame
+
+ bool fIgnore = false;
+ bool knownID = (strcmp ( szFrameID, "TIT2" ) == 0) ||
+ (strcmp ( szFrameID, "TYER" ) == 0) ||
+ (strcmp ( szFrameID, "TDRV" ) == 0) ||
+ (strcmp ( szFrameID, "TPE1" ) == 0) ||
+ (strcmp ( szFrameID, "TALB" ) == 0) ||
+ (strcmp ( szFrameID, "TCON" ) == 0) ||
+ (strcmp ( szFrameID, "COMM" ) == 0) ||
+ (strcmp ( szFrameID, "TRCK" ) == 0);
+
+ // If a known frame, just ignore
+ // Note: If recon is turned off, let's consider all known frames as unknown
+ if ( knownID && fRecon ) {
+
+ fIgnore = true;
+
+ } else if ( strcmp ( szFrameID, "PRIV" ) == 0 ) {
+
+ // Read the "PRIV" frame
+ // <Header for "PRIV">
+ // Short content descrip. <text string according to encoding> $00 (00)
+ // The actual data <full text string according to encoding>
+
+ // Get the PRIV descriptor
+ char szXMPTag[4] = {"xxx"};
+ if ( LFA_Read ( inFileRef, &szXMPTag, k_dwXMPLabelSize ) != 0 ) {
+ // Is it a XMP "PRIV"
+ if ( (szXMPTag[3] == 0) && (strcmp ( szXMPTag, "XMP" ) == 0) ) fIgnore = true;
+ LFA_Seek ( inFileRef, -(long)k_dwXMPLabelSize, SEEK_CUR );
+ }
+
+ }
+
+ if ( fIgnore ) {
+ LFA_Seek ( inFileRef, dwFrameSize, SEEK_CUR );
+ } else {
+ // Unknown frame, let's copy it
+ LFA_Seek ( inFileRef, -(long)k_dwFrameHeaderSize, SEEK_CUR );
+ LFA_Read ( inFileRef, strBuffer+dwOffset, dwFrameSize+k_dwFrameHeaderSize );
+ dwOffset += dwFrameSize+k_dwFrameHeaderSize;
+ }
+
+ posCur = GetFilePosition ( inFileRef );
+
+ }
+
+ posPad = dwOffset;
+
+ return true;
+
+}
+
+// =================================================================================================
+
+bool FindID3Tag ( LFA_FileRef inFileRef, unsigned long & dwLen, XMP_Uns8 & bMajorVer )
+{
+ // id3v2 tag:
+ // ID3v2/file identifier "ID3"
+ // ID3v2 version $04 00
+ // ID3v2 flags %abcd0000
+ // ID3v2 size 4 * %0xxxxxxx
+
+ // Taking into account that the first Tag is the ID3 tag
+ LFA_Seek ( inFileRef, 0ULL, SEEK_SET );
+
+ // Read the tag name
+ char szID[4] = {"xxx"};
+ long bytesRead = LFA_Read ( inFileRef, szID, 3 );
+ if ( bytesRead == 0 ) return false;
+
+ // Check for "ID3"
+ if ( strcmp ( szID, "ID3" ) != 0 ) return false;
+
+ // Read the version, flag and size
+ XMP_Uns8 v2 = 0, flags = 0;
+ if ( ! GetTagInfo ( inFileRef, bMajorVer, v2, flags, dwLen ) ) return false;
+
+ return true;
+
+}
+
+// =================================================================================================
+
+bool GetTagInfo ( LFA_FileRef inFileRef, XMP_Uns8 & v1, XMP_Uns8 & v2, XMP_Uns8 & flags, unsigned long & dwTagSize )
+{
+
+ if ((LFA_Read(inFileRef, &v1, 1)) == 0) return false;
+ if ((LFA_Read(inFileRef, &v2, 1)) == 0) return false;
+ if ((LFA_Read(inFileRef, &flags, 1)) == 0) return false;
+ if (!ReadSize(inFileRef, 4, dwTagSize)) return false; // Tag size is always using the size reading method.
+
+ return true;
+
+}
+
+// =================================================================================================
+
+static bool FindXMPFrame ( LFA_FileRef inFileRef, XMP_Int64 & posXMP, XMP_Int64 & posPAD, unsigned long & dwExtendedTag, unsigned long & dwLen )
+{
+ // Taking into account that the first Tag is the ID3 tag
+ bool fReturn = false;
+ dwExtendedTag = 0;
+ posPAD = 0;
+
+ LFA_Seek ( inFileRef, 0ULL, SEEK_SET );
+
+ // Read the tag name
+ char szID[4] = {"xxx"};
+ long bytesRead = LFA_Read ( inFileRef, szID, 3 );
+ if ( bytesRead == 0 ) return fReturn;
+
+ // Check for "ID3"
+ if ( strcmp ( szID, "ID3") != 0 ) return fReturn;
+
+ // Read the version, flag and size
+ XMP_Uns8 v1 = 0, v2 = 0, flags = 0;
+ unsigned long dwTagSize = 0;
+ if ( ! GetTagInfo ( inFileRef, v1, v2, flags, dwTagSize ) ) return fReturn;
+ if ( dwTagSize == 0 ) return fReturn;
+ if ( v1 > 4 ) return fReturn; // We don't support anything newer than id3v2 4.0
+
+ // If there's an extended header, ignore it
+ dwExtendedTag = SkipExtendedHeader(inFileRef, v1, flags);
+ dwTagSize -= dwExtendedTag;
+
+ // Enumerate through the frames
+ XMP_Int64 posCur = 0ULL;
+ posCur = GetFilePosition ( inFileRef );
+ XMP_Int64 posEnd = posCur + dwTagSize;
+
+ while ( posCur < posEnd ) {
+
+ char szFrameID[5] = {"xxxx"};
+ unsigned long dwFrameSize = 0;
+ XMP_Uns8 cflag1 = 0, cflag2 = 0;
+
+ // Get the next frame
+ if ( ! GetFrameInfo ( inFileRef, v1, szFrameID, cflag1, cflag2, dwFrameSize ) ) {
+ // Set the file pointer to the XMP or the start
+ LFA_Seek ( inFileRef, fReturn ? posXMP : 0ULL, SEEK_SET );
+ break;
+ }
+
+ // Are we in a padding frame?
+ if ( dwFrameSize == 0 ) {
+
+ // We just hit a padding frame
+ LFA_Seek ( inFileRef, -(long)k_dwFrameHeaderSize, SEEK_CUR );
+ posPAD = GetFilePosition ( inFileRef );
+
+ // Set the file pointer to the XMP or the start
+ LFA_Seek ( inFileRef, fReturn ? posXMP : 0ULL, SEEK_SET );
+ break;
+
+ }
+
+ // Is it a "PRIV"?
+ if ( strcmp(szFrameID, "PRIV") != 0 ) {
+
+ // Jump to the next frame
+ LFA_Seek ( inFileRef, dwFrameSize, SEEK_CUR );
+
+ } else {
+
+ // Read the "PRIV" frame
+ // <Header for "PRIV">
+ // Short content descrip. <text string according to encoding> $00 (00)
+ // The actual data <full text string according to encoding>
+
+ unsigned long dwBytesRead = 0;
+
+ // Get the PRIV descriptor
+ char szXMPTag[4] = {"xxx"};
+ if (LFA_Read(inFileRef, &szXMPTag, k_dwXMPLabelSize) == 0) return fReturn;
+ dwBytesRead += k_dwXMPLabelSize;
+
+ // Is it a XMP "PRIV"
+ if ( (szXMPTag[3] == 0) && (strcmp ( szXMPTag, "XMP" ) == 0) ) {
+ dwLen = dwFrameSize;
+ LFA_Seek ( inFileRef, -(long)k_dwXMPLabelSize, SEEK_CUR );
+ posXMP = GetFilePosition ( inFileRef );
+ fReturn = true;
+ dwBytesRead -= k_dwXMPLabelSize;
+ }
+
+ // Didn't find it, let skip the rest of the frame and continue
+ LFA_Seek ( inFileRef, dwFrameSize - dwBytesRead, SEEK_CUR );
+
+ }
+
+ posCur = GetFilePosition ( inFileRef );
+
+ }
+
+ return fReturn;
+
+}
+
+// =================================================================================================
+
+// Returns the size of the extended header
+static unsigned long SkipExtendedHeader ( LFA_FileRef inFileRef, XMP_Uns8 bVersion, XMP_Uns8 flags )
+{
+ if ( flags & flagExt ) {
+
+ unsigned long dwExtSize = 0; // <-- This will include the size (full extended header size)
+
+ if ( ReadSize ( inFileRef, bVersion, dwExtSize ) ) {
+ if ( bVersion < 4 ) dwExtSize += 4; // v3 doesn't include the size, while v4 does.
+ LFA_Seek ( inFileRef, (size_t)(dwExtSize - 4), SEEK_CUR );
+ }
+
+ return dwExtSize;
+
+ }
+
+ return 0;
+
+}
+
+// =================================================================================================
+
+static bool GetFrameInfo ( LFA_FileRef inFileRef, XMP_Uns8 bVersion, char * strFrameID, XMP_Uns8 & cflag1, XMP_Uns8 & cflag2, unsigned long & dwSize)
+{
+ // Frame ID $xx xx xx xx (four characters)
+ // Size 4 * %0xxxxxxx <<--- IMPORTANT NOTE: This is true only in v4.0 (v3.0 uses a XMP_Int32)
+ // Flags $xx xx
+
+ if ( strFrameID == 0 ) return false;
+
+ if ( LFA_Read ( inFileRef, strFrameID, 4 ) == 0 ) return false;
+ if ( ! ReadSize ( inFileRef, bVersion, dwSize ) ) return false;
+ if ( LFA_Read ( inFileRef, &cflag1, 1 ) == 0 ) return false;
+ if ( LFA_Read ( inFileRef, &cflag2, 1 ) == 0 ) return false;
+
+ return true;
+
+}
+
+// =================================================================================================
+
+static bool ReadSize ( LFA_FileRef inFileRef, XMP_Uns8 bVersion, unsigned long & dwSize )
+{
+ char s4 = 0, s3 = 0, s2 = 0, s1 = 0;
+
+ if ( LFA_Read ( inFileRef, &s4, 1 ) == 0 ) return false;
+ if ( LFA_Read ( inFileRef, &s3, 1 ) == 0 ) return false;
+ if ( LFA_Read ( inFileRef, &s2, 1 ) == 0 ) return false;
+ if ( LFA_Read ( inFileRef, &s1, 1 ) == 0 ) return false;
+
+ if ( bVersion > 3 ) {
+ dwSize = ((s4 & 0x7f) << 21) | ((s3 & 0x7f) << 14) | ((s2 & 0x7f) << 7) | (s1 & 0x7f);
+ } else {
+ dwSize = ((s4 << 24) | (s3 << 16) | (s2 << 8) | s1);
+ }
+
+ return true;
+
+}
+
+// =================================================================================================
+
+static unsigned long CalculateSize ( XMP_Uns8 bVersion, unsigned long dwSizeIn )
+{
+ unsigned long dwReturn;
+
+ if ( bVersion <= 3 ) {
+ dwReturn = dwSizeIn;
+ } else {
+ dwReturn = dwSizeIn & 0x7f; // Expand to 7 bits per byte.
+ dwSizeIn = dwSizeIn >> 7;
+ dwReturn |= ((dwSizeIn & 0x7f) << 8);
+ dwSizeIn = dwSizeIn >> 7;
+ dwReturn |= ((dwSizeIn & 0x7f) << 16);
+ dwSizeIn = dwSizeIn >> 7;
+ dwReturn |= ((dwSizeIn & 0x7f) << 24);
+ }
+
+ return dwReturn;
+
+}
+
+} // namespace ID3_Support
diff --git a/source/XMPFiles/FormatSupport/ID3_Support.hpp b/source/XMPFiles/FormatSupport/ID3_Support.hpp
new file mode 100644
index 0000000..17970cc
--- /dev/null
+++ b/source/XMPFiles/FormatSupport/ID3_Support.hpp
@@ -0,0 +1,39 @@
+#ifndef __ID3_Support_hpp__
+#define __ID3_Support_hpp__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "XMP_Environment.h" // ! This must be the first include.
+
+#include <vector>
+
+#include "XMP_Const.h"
+#include "XMPFiles_Impl.hpp"
+
+#define TAG_MAX_SIZE 5024
+
+namespace ID3_Support
+{
+
+ bool GetMetaData ( LFA_FileRef inFileRef, char* buffer, unsigned long* pBufferSize, XMP_Int64* fileOffset );
+ bool SetMetaData ( LFA_FileRef inFileRef, char * buffer, unsigned long bufferSize,
+ char * strReconciliatedFrames, unsigned long dwReconciliatedFramesSize, bool fRecon );
+
+ bool GetTagInfo ( LFA_FileRef inFileRef, XMP_Uns8 & v1, XMP_Uns8 & v2, XMP_Uns8 & flags, unsigned long & dwTagSize );
+ bool FindID3Tag ( LFA_FileRef inFileRef, unsigned long & dwLen, XMP_Uns8 & bMajorVer );
+
+ bool AddXMPTagToID3Buffer ( char * strCur, unsigned long * pdwCurOffset, unsigned long dwMaxSize,
+ XMP_Uns8 bVersion, char * strFrameName, const char * strXMPTag, unsigned long dwXMPLength );
+
+ bool GetFrameData ( LFA_FileRef inFileRef, char * strFrame, char * buffer, unsigned long & dwBufferSize );
+
+} // namespace ID3_Support
+
+#endif // __ID3_Support_hpp__
diff --git a/source/XMPFiles/FormatSupport/IPTC_Support.cpp b/source/XMPFiles/FormatSupport/IPTC_Support.cpp
new file mode 100644
index 0000000..e6e80ef
--- /dev/null
+++ b/source/XMPFiles/FormatSupport/IPTC_Support.cpp
@@ -0,0 +1,703 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "IPTC_Support.hpp"
+#include "EndianUtils.hpp"
+#include "Reconcile_Impl.hpp"
+
+// =================================================================================================
+/// \file IPTC_Support.cpp
+/// \brief XMPFiles support for IPTC (IIM) DataSets.
+///
+// =================================================================================================
+
+const DataSetCharacteristics kKnownDataSets[] =
+ { { kIPTC_ObjectType, kIPTC_UnmappedText, 67, "", "" }, // Not mapped to XMP.
+ { kIPTC_IntellectualGenre, kIPTC_MapSpecial, 68, kXMP_NS_IPTCCore, "IntellectualGenre" }, // Only the name part is in the XMP.
+ { kIPTC_Title, kIPTC_MapLangAlt, 64, kXMP_NS_DC, "title" },
+ { kIPTC_EditStatus, kIPTC_UnmappedText, 64, "", "" }, // Not mapped to XMP.
+ { kIPTC_EditorialUpdate, kIPTC_UnmappedText, 2, "", "" }, // Not mapped to XMP.
+ { kIPTC_Urgency, kIPTC_MapSimple, 1, kXMP_NS_Photoshop, "Urgency" },
+ { kIPTC_SubjectCode, kIPTC_MapSpecial, 236, kXMP_NS_IPTCCore, "SubjectCode" }, // Only the reference number is in the XMP.
+ { kIPTC_Category, kIPTC_MapSimple, 3, kXMP_NS_Photoshop, "Category" },
+ { kIPTC_SuppCategory, kIPTC_MapArray, 32, kXMP_NS_Photoshop, "SupplementalCategories" },
+ { kIPTC_FixtureIdentifier, kIPTC_UnmappedText, 32, "", "" }, // Not mapped to XMP.
+ { kIPTC_Keyword, kIPTC_MapArray, 64, kXMP_NS_DC, "subject" },
+ { kIPTC_ContentLocCode, kIPTC_UnmappedText, 3, "", "" }, // Not mapped to XMP.
+ { kIPTC_ContentLocName, kIPTC_UnmappedText, 64, "", "" }, // Not mapped to XMP.
+ { kIPTC_ReleaseDate, kIPTC_UnmappedText, 8, "", "" }, // Not mapped to XMP.
+ { kIPTC_ReleaseTime, kIPTC_UnmappedText, 11, "", "" }, // Not mapped to XMP.
+ { kIPTC_ExpDate, kIPTC_UnmappedText, 8, "", "" }, // Not mapped to XMP.
+ { kIPTC_ExpTime, kIPTC_UnmappedText, 11, "", "" }, // Not mapped to XMP.
+ { kIPTC_Instructions, kIPTC_MapSimple, 256, kXMP_NS_Photoshop, "Instructions" },
+ { kIPTC_ActionAdvised, kIPTC_UnmappedText, 2, "", "" }, // Not mapped to XMP.
+ { kIPTC_RefService, kIPTC_UnmappedText, 10, "", "" }, // Not mapped to XMP. ! Interleave 2:45, 2:47, 2:50!
+ { kIPTC_RefDate, kIPTC_UnmappedText, 8, "", "" }, // Not mapped to XMP. ! Interleave 2:45, 2:47, 2:50!
+ { kIPTC_RefNumber, kIPTC_UnmappedText, 8, "", "" }, // Not mapped to XMP. ! Interleave 2:45, 2:47, 2:50!
+ { kIPTC_DateCreated, kIPTC_MapSpecial, 8, kXMP_NS_Photoshop, "DateCreated" }, // Combined with 2:60, TimeCreated.
+ { kIPTC_TimeCreated, kIPTC_MapSpecial, 11, "", "" }, // Combined with 2:55, DateCreated.
+ { kIPTC_DigitalCreateDate, kIPTC_UnmappedText, 8, "", "" }, // Not mapped to XMP.
+ { kIPTC_DigitalCreateTime, kIPTC_UnmappedText, 11, "", "" }, // Not mapped to XMP.
+ { kIPTC_OriginProgram, kIPTC_UnmappedText, 32, "", "" }, // Not mapped to XMP.
+ { kIPTC_ProgramVersion, kIPTC_UnmappedText, 10, "", "" }, // Not mapped to XMP.
+ { kIPTC_ObjectCycle, kIPTC_UnmappedText, 1, "", "" }, // Not mapped to XMP.
+ { kIPTC_Creator, kIPTC_MapSimple, 32, kXMP_NS_Photoshop, "Author" }, // ! Aliased to dc:creator[1].
+ { kIPTC_CreatorJobtitle, kIPTC_MapSimple, 32, kXMP_NS_Photoshop, "AuthorsPosition" },
+ { kIPTC_City, kIPTC_MapSimple, 32, kXMP_NS_Photoshop, "City" },
+ { kIPTC_Location, kIPTC_MapSimple, 32, kXMP_NS_IPTCCore, "Location" },
+ { kIPTC_State, kIPTC_MapSimple, 32, kXMP_NS_Photoshop, "State" },
+ { kIPTC_CountryCode, kIPTC_MapSimple, 3, kXMP_NS_IPTCCore, "CountryCode" },
+ { kIPTC_Country, kIPTC_MapSimple, 64, kXMP_NS_Photoshop, "Country" },
+ { kIPTC_JobID, kIPTC_MapSimple, 32, kXMP_NS_Photoshop, "TransmissionReference" },
+ { kIPTC_Headline, kIPTC_MapSimple, 256, kXMP_NS_Photoshop, "Headline" },
+ { kIPTC_Provider, kIPTC_MapSimple, 32, kXMP_NS_Photoshop, "Credit" },
+ { kIPTC_Source, kIPTC_MapSimple, 32, kXMP_NS_Photoshop, "Source" },
+ { kIPTC_CopyrightNotice, kIPTC_MapLangAlt, 128, kXMP_NS_DC, "rights" },
+ { kIPTC_Contact, kIPTC_UnmappedText, 128, "", "" }, // Not mapped to XMP.
+ { kIPTC_Description, kIPTC_MapLangAlt, 2000, kXMP_NS_DC, "description" },
+ { kIPTC_DescriptionWriter, kIPTC_MapSimple, 32, kXMP_NS_Photoshop, "CaptionWriter" },
+ { kIPTC_RasterizedCaption, kIPTC_UnmappedBin, 7360, "", "" }, // Not mapped to XMP. ! Binary data!
+ { kIPTC_ImageType, kIPTC_UnmappedText, 2, "", "" }, // Not mapped to XMP.
+ { kIPTC_ImageOrientation, kIPTC_UnmappedText, 1, "", "" }, // Not mapped to XMP.
+ { kIPTC_LanguageID, kIPTC_UnmappedText, 3, "", "" }, // Not mapped to XMP.
+ { kIPTC_AudioType, kIPTC_UnmappedText, 2, "", "" }, // Not mapped to XMP.
+ { kIPTC_AudioSampleRate, kIPTC_UnmappedText, 6, "", "" }, // Not mapped to XMP.
+ { kIPTC_AudioSampleRes, kIPTC_UnmappedText, 2, "", "" }, // Not mapped to XMP.
+ { kIPTC_AudioDuration, kIPTC_UnmappedText, 6, "", "" }, // Not mapped to XMP.
+ { kIPTC_AudioOutcue, kIPTC_UnmappedText, 64, "", "" }, // Not mapped to XMP.
+ { kIPTC_PreviewFormat, kIPTC_UnmappedBin, 2, "", "" }, // Not mapped to XMP. ! Binary data!
+ { kIPTC_PreviewFormatVers, kIPTC_UnmappedText, 2, "", "" }, // Not mapped to XMP. ! Binary data!
+ { kIPTC_PreviewData, kIPTC_UnmappedText, 256000, "", "" }, // Not mapped to XMP. ! Binary data!
+ { 255, kIPTC_MapSpecial, 0, 0, 0 } }; // ! Must be last as a sentinel.
+
+// A combination of the IPTC "Subject Reference System Guidelines" and IIMv4.1 Appendix G.
+const IntellectualGenreMapping kIntellectualGenreMappings[] =
+{ { "001", "Current" },
+ { "002", "Analysis" },
+ { "003", "Archive material" },
+ { "004", "Background" },
+ { "005", "Feature" },
+ { "006", "Forecast" },
+ { "007", "History" },
+ { "008", "Obituary" },
+ { "009", "Opinion" },
+ { "010", "Polls and surveys" },
+ { "010", "Polls & Surveys" },
+ { "011", "Profile" },
+ { "012", "Results listings and statistics" },
+ { "012", "Results Listings & Tables" },
+ { "013", "Side bar and supporting information" },
+ { "013", "Side bar & Supporting information" },
+ { "014", "Summary" },
+ { "015", "Transcript and verbatim" },
+ { "015", "Transcript & Verbatim" },
+ { "016", "Interview" },
+ { "017", "From the scene" },
+ { "017", "From the Scene" },
+ { "018", "Retrospective" },
+ { "019", "Synopsis" },
+ { "019", "Statistics" },
+ { "020", "Update" },
+ { "021", "Wrapup" },
+ { "021", "Wrap-up" },
+ { "022", "Press release" },
+ { "022", "Press Release" },
+ { "023", "Quote" },
+ { "024", "Press-digest" },
+ { "025", "Review" },
+ { "026", "Curtain raiser" },
+ { "027", "Actuality" },
+ { "028", "Question and answer" },
+ { "029", "Music" },
+ { "030", "Response to a question" },
+ { "031", "Raw sound" },
+ { "032", "Scener" },
+ { "033", "Text only" },
+ { "034", "Voicer" },
+ { "035", "Fixture" },
+ { 0, 0 } }; // ! Must be last as a sentinel.
+
+// =================================================================================================
+// FindKnownDataSet
+// ================
+
+static const DataSetCharacteristics* FindKnownDataSet ( XMP_Uns8 id )
+{
+ size_t i = 0;
+
+ while ( kKnownDataSets[i].id < id ) ++i; // The list is short enough for a linear search.
+
+ if ( kKnownDataSets[i].id != id ) return 0;
+ return &kKnownDataSets[i];
+
+} // FindKnownDataSet
+
+// =================================================================================================
+// IPTC_Manager::ParseMemoryDataSets
+// =================================
+//
+// Parse the legacy IIM block, keeping information about all 2:* DataSets and size of other records.
+
+void IPTC_Manager::ParseMemoryDataSets ( const void* data, XMP_Uns32 length, bool copyData /* = true */ )
+{
+ // Get rid of any existing data.
+
+ DataSetMap::iterator dsPos = this->dataSets.begin();
+ DataSetMap::iterator dsEnd = this->dataSets.end();
+
+ for ( ; dsPos != dsEnd; ++dsPos ) this->DisposeLooseValue ( dsPos->second );
+
+ this->dataSets.clear();
+
+ if ( this->ownedContent ) free ( this->iptcContent );
+ this->ownedContent = false; // Set to true later if the content is copied.
+ this->iptcContent = 0;
+ this->iptcLength = 0;
+
+ this->changed = false;
+
+ if ( length == 0 ) return;
+ if ( *((XMP_Uns8*)data) != 0x1C ) XMP_Throw ( "Not valid IPTC, no leading 0x1C", kXMPErr_BadIPTC );
+
+ // Allocate space for the full in-memory data and copy it.
+
+ if ( length > 10*1024*1024 ) XMP_Throw ( "Outrageous length for memory-based IPTC", kXMPErr_BadIPTC );
+ this->iptcLength = length;
+
+ if ( ! copyData ) {
+ this->iptcContent = (XMP_Uns8*)data;
+ } else {
+ this->iptcContent = (XMP_Uns8*) malloc(length);
+ if ( this->iptcContent == 0 ) XMP_Throw ( "Out of memory", kXMPErr_NoMemory );
+ memcpy ( this->iptcContent, data, length ); // AUDIT: Safe, malloc'ed length bytes above.
+ this->ownedContent = true;
+ }
+
+ // Build the map of the 2:* DataSets.
+
+ XMP_Uns8* iptcPtr = this->iptcContent;
+ XMP_Uns8* iptcEnd = iptcPtr + length;
+ XMP_Uns8* iptcLimit = iptcEnd - kMinDataSetSize;
+ XMP_Uns32 dsLen; // ! The large form can have values up to 4GB in length.
+
+ this->utf8Encoding = false;
+
+ bool foundRec2 = false;
+
+ for ( ; iptcPtr <= iptcLimit; iptcPtr += dsLen ) {
+
+ XMP_Uns8* dsPtr = iptcPtr;
+ XMP_Uns8 oneC = *iptcPtr;
+ XMP_Uns8 recNum = *(iptcPtr+1);
+ XMP_Uns8 dsNum = *(iptcPtr+2);
+
+ if ( oneC != 0x1C ) break; // No more DataSets.
+
+ dsLen = GetUns16BE ( iptcPtr+3 ); // ! Compute dsLen before any "continue", needed for loop increment!
+ iptcPtr += 5; // Advance to the data (or extended length).
+
+ if ( (dsLen & 0x8000) != 0 ) {
+ XMP_Assert ( dsLen <= 0xFFFF );
+ XMP_Uns32 lenLen = dsLen & 0x7FFF;
+ if ( iptcPtr > iptcEnd-lenLen ) break; // Bad final DataSet. Throw instead?
+ dsLen = 0;
+ for ( XMP_Uns16 i = 0; i < lenLen; ++i, ++iptcPtr ) {
+ dsLen = (dsLen << 8) + *iptcPtr;
+ }
+ }
+
+ if ( iptcPtr > (iptcEnd - dsLen) ) break; // Bad final DataSet. Throw instead?
+
+ if ( recNum == 0 ) continue; // Should not be a record 0. Throw instead?
+
+ if ( recNum == 1 ) {
+ if ( (dsNum == 90) && (dsLen >= 3) ) {
+ if ( memcmp ( iptcPtr, "\x1B\x25\x47", 3 ) == 0 ) this->utf8Encoding = true;
+ }
+ continue; // Ignore all other record 1 DataSets.
+ }
+
+ if ( recNum == 2 ) {
+ if ( ! foundRec2 ) {
+ foundRec2 = true;
+ this->rec2Offset = dsPtr - this->iptcContent;
+ this->rec2Length = this->iptcLength - this->rec2Offset; // ! In case there are no other records.
+ }
+ } else {
+ this->rec2Length = dsPtr - (this->iptcContent + this->rec2Offset);
+ break; // The records are in ascending order, done.
+ }
+
+ XMP_Assert ( recNum == 2 );
+ if ( dsNum == 0 ) continue; // Ignore 2:00 when reading.
+
+ DataSetInfo dsInfo ( dsNum, dsLen, iptcPtr );
+ DataSetMap::iterator dsPos = this->dataSets.find ( dsNum );
+
+ bool repeatable = false;
+
+ const DataSetCharacteristics* knownDS = FindKnownDataSet ( dsNum );
+
+ if ( (knownDS == 0) || (knownDS->mapForm == kIPTC_MapArray) ) {
+ repeatable = true; // Allow repeats for unknown DataSets.
+ } else if ( dsNum == kIPTC_SubjectCode ) {
+ repeatable = true;
+ }
+
+ if ( repeatable || (dsPos == this->dataSets.end()) ) {
+ DataSetMap::value_type mapValue ( dsNum, dsInfo );
+ (void) this->dataSets.insert ( this->dataSets.upper_bound ( dsNum ), mapValue );
+ } else {
+ this->DisposeLooseValue ( dsPos->second );
+ dsPos->second = dsInfo; // Keep the last copy of illegal repeats.
+ }
+
+ }
+
+} // IPTC_Manager::ParseMemoryDataSets
+
+// =================================================================================================
+// IPTC_Manager::GetDataSet
+// ========================
+
+size_t IPTC_Manager::GetDataSet ( XMP_Uns8 id, DataSetInfo* info, size_t which /* = 0 */ ) const
+{
+
+ DataSetMap::const_iterator dsPos = this->dataSets.lower_bound ( id );
+ if ( (dsPos == this->dataSets.end()) || (id != dsPos->second.id) ) return 0;
+
+ size_t dsCount = this->dataSets.count ( id );
+ if ( which >= dsCount ) return 0; // Valid range for which is 0 .. count-1.
+
+ if ( info != 0 ) {
+ for ( size_t i = 0; i < which; ++i ) ++dsPos; // ??? dsPos += which;
+ *info = dsPos->second;
+ }
+
+ return dsCount;
+
+} // IPTC_Manager::GetDataSet
+
+// =================================================================================================
+// IPTC_Manager::GetDataSet_UTF8
+// =============================
+
+size_t IPTC_Manager::GetDataSet_UTF8 ( XMP_Uns8 id, std::string * utf8Str, size_t which /* = 0 */ ) const
+{
+ DataSetInfo dsInfo;
+ size_t dsCount = GetDataSet ( id, &dsInfo, which );
+ if ( dsCount == 0 ) return 0;
+
+ if ( utf8Str != 0 ) {
+ if ( this->utf8Encoding ) {
+ utf8Str->assign ( (char*)dsInfo.dataPtr, dsInfo.dataLen );
+ } else {
+ ReconcileUtils::LocalToUTF8 ( dsInfo.dataPtr, dsInfo.dataLen, utf8Str );
+ }
+ }
+
+ return dsCount;
+
+} // IPTC_Manager::GetDataSet_UTF8
+
+// =================================================================================================
+// IPTC_Manager::DisposeLooseValue
+// ===============================
+//
+// Dispose of loose values from SetDataSet calls after the last UpdateMemoryDataSets.
+
+// ! Don't try to make the DataSetInfo struct be self-cleaning. It is a primary public type, returned
+// ! from GetDataSet. Making it self-cleaning would get into nasty assignment and pointer ownership
+// ! issues, far worse than doing this explicit cleanup.
+
+void IPTC_Manager::DisposeLooseValue ( DataSetInfo & dsInfo )
+{
+ if ( dsInfo.dataLen == 0 ) return;
+
+ XMP_Uns8* dataBegin = this->iptcContent;
+ XMP_Uns8* dataEnd = dataBegin + this->iptcLength;
+
+ if ( ((XMP_Uns8*)dsInfo.dataPtr < dataBegin) || ((XMP_Uns8*)dsInfo.dataPtr >= dataEnd) ) {
+ free ( (void*) dsInfo.dataPtr );
+ dsInfo.dataPtr = 0;
+ }
+
+} // IPTC_Manager::DisposeLooseValue
+
+// =================================================================================================
+// =================================================================================================
+
+// =================================================================================================
+// IPTC_Writer::~IPTC_Writer
+// =========================
+//
+// Dispose of loose values from SetDataSet calls after the last UpdateMemoryDataSets.
+
+IPTC_Writer::~IPTC_Writer()
+{
+ DataSetMap::iterator dsPos = this->dataSets.begin();
+ DataSetMap::iterator dsEnd = this->dataSets.end();
+
+ for ( ; dsPos != dsEnd; ++dsPos ) this->DisposeLooseValue ( dsPos->second );
+
+} // IPTC_Writer::~IPTC_Writer
+
+// =================================================================================================
+// IPTC_Writer::SetDataSet_UTF8
+// ============================
+
+void IPTC_Writer::SetDataSet_UTF8 ( XMP_Uns8 id, const void* utf8Ptr, XMP_Uns32 utf8Len, long which /* = -1 */ )
+{
+ const DataSetCharacteristics* knownDS = FindKnownDataSet ( id );
+ if ( knownDS == 0 ) XMP_Throw ( "Can only set known IPTC DataSets", kXMPErr_InternalFailure );
+
+ // Decide which character encoding to use and get a temporary pointer to the value.
+
+ XMP_Uns8 * tempPtr;
+ XMP_Uns32 dataLen;
+
+ std::string localStr, rtStr;
+
+ if ( this->utf8Encoding ) {
+
+ // We're already using UTF-8.
+ tempPtr = (XMP_Uns8*) utf8Ptr;
+ dataLen = utf8Len;
+
+ } else {
+
+// *** Disable the round trip loss checking for now. We only use UTF-8 if the input had it.
+
+ ReconcileUtils::UTF8ToLocal ( utf8Ptr, utf8Len, &localStr );
+// ReconcileUtils::LocalToUTF8 ( localStr.data(), localStr.size(), &rtStr );
+
+// if ( (rtStr.size() == utf8Len) && (memcmp ( rtStr.data(), utf8Ptr, utf8Len ) == 0) ) {
+
+ // It round-tripped without loss, keep local encoding.
+ tempPtr = (XMP_Uns8*) localStr.data();
+ dataLen = localStr.size();
+
+// } else {
+
+// // Had round-trip loss, change to UTF-8 for all text DataSets.
+// this->ConvertToUTF8();
+// XMP_Assert ( this->utf8Encoding );
+// tempPtr = (XMP_Uns8*) utf8Ptr;
+// dataLen = utf8Len;
+
+// }
+
+ }
+
+ // Set the value for this DataSet, making a non-transient copy of the value. Respect UTF-8 character
+ // boundaries when truncating. This is easy to check. If the first truncated byte has 10 in the
+ // high order 2 bits then we are in the middle of a UTF-8 multi-byte character.
+ // Back up to just before a byte with 11 in the high order 2 bits.
+
+ if ( dataLen > knownDS->maxLen ) {
+ dataLen = knownDS->maxLen;
+ if ( this->utf8Encoding && ((tempPtr[dataLen] >> 6) == 2) ) {
+ for ( ; (dataLen > 0) && ((tempPtr[dataLen] >> 6) != 3); --dataLen ) {}
+ }
+ }
+
+ DataSetMap::iterator dsPos = this->dataSets.find ( id );
+ long currCount = (long) this->dataSets.count ( id );
+
+ bool repeatable = false;
+
+ if ( knownDS->mapForm == kIPTC_MapArray ) {
+ repeatable = true;
+ } else if ( id == kIPTC_SubjectCode ) {
+ repeatable = true;
+ }
+
+ if ( ! repeatable ) {
+
+ if ( which > 0 ) XMP_Throw ( "Non-repeatable IPTC DataSet", kXMPErr_BadParam );
+
+ } else {
+
+ if ( which < 0 ) which = currCount; // The default is to append.
+
+ if ( which > currCount ) {
+ XMP_Throw ( "Invalid index for IPTC DataSet", kXMPErr_BadParam );
+ } else if ( which == currCount ) {
+ dsPos = this->dataSets.end(); // To make later checks do the right thing.
+ } else {
+ dsPos = this->dataSets.lower_bound ( id );
+ for ( ; which > 0; --which ) ++dsPos;
+ }
+
+ }
+
+ if ( dsPos != this->dataSets.end() ) {
+ if ( (dsPos->second.dataLen == dataLen) && (memcmp ( dsPos->second.dataPtr, tempPtr, dataLen ) == 0) ) {
+ return; // ! New value matches the old, don't update.
+ }
+ }
+
+ XMP_Uns8 * dataPtr = (XMP_Uns8*) malloc ( dataLen );
+ if ( dataPtr == 0 ) XMP_Throw ( "Out of memory", kXMPErr_NoMemory );
+ memcpy ( dataPtr, tempPtr, dataLen ); // AUDIT: Safe, malloc'ed dataLen bytes above.
+
+ DataSetInfo dsInfo ( id, dataLen, dataPtr );
+
+ if ( dsPos != this->dataSets.end() ) {
+ this->DisposeLooseValue ( dsPos->second );
+ dsPos->second = dsInfo;
+ } else {
+ DataSetMap::value_type mapValue ( id, dsInfo );
+ (void) this->dataSets.insert ( this->dataSets.upper_bound ( id ), mapValue );
+ }
+
+ this->changed = true;
+
+} // IPTC_Writer::SetDataSet_UTF8
+
+// =================================================================================================
+// IPTC_Writer::DeleteDataSet
+// ==========================
+
+void IPTC_Writer::DeleteDataSet ( XMP_Uns8 id, long which /* = -1 */ )
+{
+ DataSetMap::iterator dsBegin = this->dataSets.lower_bound ( id ); // Set for which == -1.
+ DataSetMap::iterator dsEnd = this->dataSets.upper_bound ( id );
+
+ if ( dsBegin == dsEnd ) return; // Nothing to delete.
+
+ if ( which >= 0 ) {
+ long currCount = (long) this->dataSets.count ( id );
+ if ( which >= currCount ) return; // Nothing to delete.
+ for ( ; which > 0; --which ) ++dsBegin;
+ dsEnd = dsBegin; ++dsEnd; // ! Can't do "dsEnd = dsBegin+1"!
+ }
+
+ for ( DataSetMap::iterator dsPos = dsBegin; dsPos != dsEnd; ++dsPos ) {
+ this->DisposeLooseValue ( dsPos->second );
+ }
+
+ this->dataSets.erase ( dsBegin, dsEnd );
+ this->changed = true;
+
+} // IPTC_Writer::DeleteDataSet
+
+// =================================================================================================
+// IPTC_Writer::UpdateMemoryDataSets
+// =================================
+//
+// Reconstruct the entire IIM block. Start with DataSet 1:0 and 1:90 if UTF-8 encoding is used,
+// then 2:0, then 2:xx DataSets that have values. This does not include any alignment padding, that
+// is an artifact of some specific wrappers such as Photoshop image resources.
+
+XMP_Uns32 IPTC_Writer::UpdateMemoryDataSets ( void** dataPtr )
+{
+ if ( ! this->changed ) {
+ if ( dataPtr != 0 ) *dataPtr = this->iptcContent;
+ return this->iptcLength;
+ }
+
+ DataSetMap::iterator dsPos;
+ DataSetMap::iterator dsEnd = this->dataSets.end();
+
+// if ( this->utf8Encoding ) { *** Disable round trip loss checking for now. ***
+// if ( ! this->CheckRoundTripLoss() ) this->ConvertToLocal();
+// }
+
+ // Compute the length of the new IIM block, including space for records other than 2. All other
+ // records are preserved as-is, including 1:90. If we ever start changing the encoding, we will
+ // have to remove any existing 1:90 and insert a new one.
+
+ XMP_Uns32 newLength = (5+2); // For 2:0.
+ newLength += (this->iptcLength - rec2Length); // For records other than 2.
+
+ for ( dsPos = this->dataSets.begin(); dsPos != dsEnd; ++dsPos ) {
+ XMP_Uns32 dsLen = dsPos->second.dataLen;
+ newLength += (5 + dsLen);
+ if ( dsLen > 0x7FFF ) newLength += 4; // We always use a 4 byte extended length.
+ }
+
+ // Allocate the new IIM block.
+
+ XMP_Uns8* newContent = (XMP_Uns8*) malloc ( newLength );
+ if ( newContent == 0 ) XMP_Throw ( "Out of memory", kXMPErr_NoMemory );
+
+ XMP_Uns8* dsPtr = newContent;
+
+ XMP_Uns32 prefixLength = this->rec2Offset;
+ XMP_Uns32 suffixOffset = this->rec2Offset + this->rec2Length;
+ XMP_Uns32 suffixLength = this->iptcLength - suffixOffset;
+
+ if ( prefixLength > 0 ) { // Write the records before 2.
+ memcpy ( dsPtr, this->iptcContent, prefixLength ); // AUDIT: Within range of allocation.
+ dsPtr += prefixLength;
+ }
+
+ if ( ! this->utf8Encoding ) {
+ // Start with 2:00 for version 2.
+ // *** We should probably write version 4 all the time. This is a late CS3 change, don't want
+ // *** to risk breaking other apps that might be strict about version checking.
+ memcpy ( dsPtr, "\x1C\x02\x00\x00\x02\x00\x02", (5+2) ); // AUDIT: Within range of allocation.
+ dsPtr += (5+2);
+ } else {
+ // Start with 2:00 for version 4.
+ memcpy ( dsPtr, "\x1C\x02\x00\x00\x02\x00\x04", (5+2) ); // AUDIT: Within range of allocation.
+ dsPtr += (5+2);
+ }
+
+ // Fill in the record 2 DataSets that have values.
+
+ for ( dsPos = this->dataSets.begin(); dsPos != dsEnd; ++dsPos ) {
+
+ DataSetInfo & dsInfo = dsPos->second;
+
+ dsPtr[0] = 0x1C;
+ dsPtr[1] = 2;
+ dsPtr[2] = dsInfo.id;
+ dsPtr += 3;
+
+ XMP_Uns32 dsLen = dsInfo.dataLen;
+ if ( dsLen <= 0x7FFF ) {
+ PutUns16BE ( (XMP_Uns16)dsLen, dsPtr );
+ dsPtr += 2;
+ } else {
+ PutUns16BE ( 0x8004, dsPtr );
+ PutUns32BE ( dsLen, dsPtr+2 );
+ dsPtr += 6;
+ }
+
+ if ( dsLen > (newLength - (dsPtr - newContent)) ) {
+ XMP_Throw ( "Buffer overrun", kXMPErr_InternalFailure );
+ }
+ memcpy ( dsPtr, dsInfo.dataPtr, dsLen ); // AUDIT: Protected by above check.
+ dsPtr += dsLen;
+
+ }
+
+ if ( suffixLength > 0 ) { // Write the records after 2.
+ memcpy ( dsPtr, (this->iptcContent + suffixOffset), suffixLength ); // AUDIT: Within range of allocation.
+ dsPtr += suffixLength;
+ }
+
+ XMP_Assert ( dsPtr == (newContent + newLength) );
+
+ // Parse the new block, it is the best way to reset internal info and rebuild the map.
+
+ this->ParseMemoryDataSets ( newContent, newLength, false ); // Don't make another copy of the content.
+ XMP_Assert ( this->iptcLength == newLength );
+ this->ownedContent = true; // We really do own the new content.
+
+ // Done.
+
+ if ( dataPtr != 0 ) *dataPtr = this->iptcContent;
+ return this->iptcLength;
+
+} // IPTC_Writer::UpdateMemoryDataSets
+
+#if 0 // *** Disable the round trip loss checking for now.
+
+// =================================================================================================
+// IPTC_Writer::ConvertToUTF8
+// ==========================
+//
+// Convert the values of existing text DataSets to UTF-8. For now we only accept text DataSets.
+
+void IPTC_Writer::ConvertToUTF8()
+{
+ XMP_Assert ( ! this->utf8Encoding );
+ std::string utf8Str;
+
+ DataSetMap::iterator dsPos = this->dataSets.begin();
+ DataSetMap::iterator dsEnd = this->dataSets.end();
+
+ for ( ; dsPos != dsEnd; ++dsPos ) {
+
+ DataSetInfo & dsInfo = dsPos->second;
+
+ ReconcileUtils::LocalToUTF8 ( dsInfo.dataPtr, dsInfo.dataLen, &utf8Str );
+ this->DisposeLooseValue ( dsInfo );
+
+ dsInfo.dataLen = utf8Str.size();
+ dsInfo.dataPtr = (XMP_Uns8*) malloc ( dsInfo.dataLen );
+ if ( dsInfo.dataPtr == 0 ) XMP_Throw ( "Out of memory", kXMPErr_NoMemory );
+ memcpy ( dsInfo.dataPtr, utf8Str.data(), dsInfo.dataLen ); // AUDIT: Safe, malloc'ed dataLen bytes above.
+
+ }
+
+ this->utf8Encoding = true;
+
+} // IPTC_Writer::ConvertToUTF8
+
+// =================================================================================================
+// IPTC_Writer::ConvertToLocal
+// ===========================
+//
+// Convert the values of existing text DataSets to local. For now we only accept text DataSets.
+
+void IPTC_Writer::ConvertToLocal()
+{
+ XMP_Assert ( this->utf8Encoding );
+ std::string localStr;
+
+ DataSetMap::iterator dsPos = this->dataSets.begin();
+ DataSetMap::iterator dsEnd = this->dataSets.end();
+
+ for ( ; dsPos != dsEnd; ++dsPos ) {
+
+ DataSetInfo & dsInfo = dsPos->second;
+
+ ReconcileUtils::UTF8ToLocal ( dsInfo.dataPtr, dsInfo.dataLen, &localStr );
+ this->DisposeLooseValue ( dsInfo );
+
+ dsInfo.dataLen = localStr.size();
+ dsInfo.dataPtr = (XMP_Uns8*) malloc ( dsInfo.dataLen );
+ if ( dsInfo.dataPtr == 0 ) XMP_Throw ( "Out of memory", kXMPErr_NoMemory );
+ memcpy ( dsInfo.dataPtr, localStr.data(), dsInfo.dataLen ); // AUDIT: Safe, malloc'ed dataLen bytes above.
+
+ }
+
+ this->utf8Encoding = false;
+
+} // IPTC_Writer::ConvertToLocal
+
+// =================================================================================================
+// IPTC_Writer::CheckRoundTripLoss
+// ===============================
+//
+// See if we still need UTF-8 because of round-trip loss. Returns true if there is loss.
+
+bool IPTC_Writer::CheckRoundTripLoss()
+{
+ XMP_Assert ( this->utf8Encoding );
+ std::string localStr, rtStr;
+
+ DataSetMap::iterator dsPos = this->dataSets.begin();
+ DataSetMap::iterator dsEnd = this->dataSets.end();
+
+ for ( ; dsPos != dsEnd; ++dsPos ) {
+
+ DataSetInfo & dsInfo = dsPos->second;
+
+ XMP_StringPtr utf8Ptr = (XMP_StringPtr) dsInfo.dataPtr;
+ XMP_StringLen utf8Len = dsInfo.dataLen;
+
+ ReconcileUtils::UTF8ToLocal ( utf8Ptr, utf8Len, &localStr );
+ ReconcileUtils::LocalToUTF8 ( localStr.data(), localStr.size(), &rtStr );
+
+ if ( (rtStr.size() != utf8Len) || (memcmp ( rtStr.data(), utf8Ptr, utf8Len ) != 0) ) {
+ return true; // Had round-trip loss, keep UTF-8.
+ }
+
+ }
+
+ return false; // No loss.
+
+} // IPTC_Writer::CheckRoundTripLoss
+
+#endif
diff --git a/source/XMPFiles/FormatSupport/IPTC_Support.hpp b/source/XMPFiles/FormatSupport/IPTC_Support.hpp
new file mode 100644
index 0000000..11ff28e
--- /dev/null
+++ b/source/XMPFiles/FormatSupport/IPTC_Support.hpp
@@ -0,0 +1,302 @@
+#ifndef __IPTC_Support_hpp__
+#define __IPTC_Support_hpp__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "XMP_Environment.h" // ! This must be the first include.
+
+#include <map>
+
+#include "XMP_Const.h"
+#include "XMPFiles_Impl.hpp"
+#include "EndianUtils.hpp"
+
+// =================================================================================================
+/// \file IPTC_Support.hpp
+/// \brief XMPFiles support for IPTC (IIM) DataSets.
+///
+/// This header provides IPTC (IIM) DataSet support specific to the needs of XMPFiles. This is not
+/// intended for general purpose IPTC processing. There is a small tree of derived classes, 1
+/// virtual base class and 2 concrete leaf classes:
+/// \code
+/// IPTC_Manager - The root virtual base class.
+/// IPTC_Reader - A derived concrete leaf class for memory-based read-only access.
+/// IPTC_Writer - A derived concrete leaf class for memory-based read-write access.
+/// \endcode
+///
+/// \c IPTC_Manager declares all of the public methods except for specialized constructors in the
+/// leaf classes. The read-only classes throw an XMP_Error exception for output methods like
+/// \c SetDataSet. They return appropriate values for "safe" methods, \c IsChanged will return false
+/// for example.
+///
+/// The IPTC DataSet organization differs from TIFF tags and Photoshop image resources in allowing
+/// muultiple occurrences for some IDs. The C++ STL multimap is a natural data structure for IPTC.
+///
+/// Support is only provided for DataSet 1:90 to decide if local or UTF-8 text encoding is used, and
+/// the following text valued DataSets: 2:05, 2:10, 2:15, 2:20, 2:25, 2:40, 2:55, 2:80, 2:85, 2:90,
+/// 2:95, 2:101, 2:103, 2:105, 2:110, 2:115, 2:116, 2:120, and 2:122. DataSet 2:00 is ignored when
+/// reading but always written.
+///
+/// \note Unlike the TIFF_Manager and PSIR_Manager class trees, IPTC_Manager only provides in-memory
+/// implementations. The total size of IPTC data is small enough to make this reasonable.
+///
+/// \note These classes are for use only when directly compiled and linked. They should not be
+/// packaged in a DLL by themselves. They do not provide any form of C++ ABI protection.
+// =================================================================================================
+
+
+// =================================================================================================
+// =================================================================================================
+
+enum { // List of recognized 2:* IIM DataSets. The names are from IIMv4 and IPTC4XMP.
+ kIPTC_ObjectType = 3,
+ kIPTC_IntellectualGenre = 4,
+ kIPTC_Title = 5,
+ kIPTC_EditStatus = 7,
+ kIPTC_EditorialUpdate = 8,
+ kIPTC_Urgency = 10,
+ kIPTC_SubjectCode = 12,
+ kIPTC_Category = 15,
+ kIPTC_SuppCategory = 20,
+ kIPTC_FixtureIdentifier = 22,
+ kIPTC_Keyword = 25,
+ kIPTC_ContentLocCode = 26,
+ kIPTC_ContentLocName = 27,
+ kIPTC_ReleaseDate = 30,
+ kIPTC_ReleaseTime = 35,
+ kIPTC_ExpDate = 37,
+ kIPTC_ExpTime = 38,
+ kIPTC_Instructions = 40,
+ kIPTC_ActionAdvised = 42,
+ kIPTC_RefService = 45,
+ kIPTC_RefDate = 47,
+ kIPTC_RefNumber = 50,
+ kIPTC_DateCreated = 55,
+ kIPTC_TimeCreated = 60,
+ kIPTC_DigitalCreateDate = 62,
+ kIPTC_DigitalCreateTime = 63,
+ kIPTC_OriginProgram = 65,
+ kIPTC_ProgramVersion = 70,
+ kIPTC_ObjectCycle = 75,
+ kIPTC_Creator = 80,
+ kIPTC_CreatorJobtitle = 85,
+ kIPTC_City = 90,
+ kIPTC_Location = 92,
+ kIPTC_State = 95,
+ kIPTC_CountryCode = 100,
+ kIPTC_Country = 101,
+ kIPTC_JobID = 103,
+ kIPTC_Headline = 105,
+ kIPTC_Provider = 110,
+ kIPTC_Source = 115,
+ kIPTC_CopyrightNotice = 116,
+ kIPTC_Contact = 118,
+ kIPTC_Description = 120,
+ kIPTC_DescriptionWriter = 122,
+ kIPTC_RasterizedCaption = 125,
+ kIPTC_ImageType = 130,
+ kIPTC_ImageOrientation = 131,
+ kIPTC_LanguageID = 135,
+ kIPTC_AudioType = 150,
+ kIPTC_AudioSampleRate = 151,
+ kIPTC_AudioSampleRes = 152,
+ kIPTC_AudioDuration = 153,
+ kIPTC_AudioOutcue = 154,
+ kIPTC_PreviewFormat = 200,
+ kIPTC_PreviewFormatVers = 201,
+ kIPTC_PreviewData = 202
+};
+
+enum { // Forms of mapping legacy IPTC to XMP.
+ kIPTC_MapSimple, // The XMP is simple, the last DataSet occurrence is kept.
+ kIPTC_MapLangAlt, // The XMP is a LangAlt x-default item, the last DataSet occurrence is kept.
+ kIPTC_MapArray, // The XMP is an unordered array, all DataSets are kept.
+ kIPTC_MapSpecial, // The mapping requires DataSet specific code.
+ kIPTC_UnmappedText, // A text DataSet that is not mapped to XMP.
+ kIPTC_UnmappedBin // A binary DataSet that is not mapped to XMP.
+};
+
+struct DataSetCharacteristics {
+ XMP_Uns8 id;
+ XMP_Uns8 mapForm;
+ size_t maxLen;
+ XMP_StringPtr xmpNS;
+ XMP_StringPtr xmpProp;
+};
+
+extern const DataSetCharacteristics kKnownDataSets[];
+
+struct IntellectualGenreMapping {
+ XMP_StringPtr refNum; // The reference number as a 3 digit string.
+ XMP_StringPtr name; // The intellectual genre name.
+};
+
+extern const IntellectualGenreMapping kIntellectualGenreMappings[];
+
+// =================================================================================================
+// IPTC_Manager
+// ============
+
+class IPTC_Manager {
+public:
+
+ // ---------------------------------------------------------------------------------------------
+ // Types and constants.
+
+ struct DataSetInfo {
+ XMP_Uns8 id;
+ XMP_Uns32 dataLen;
+ XMP_Uns8 * dataPtr; // ! The data is read-only. Raw data pointer, beware of character encoding.
+ DataSetInfo() : id(0), dataLen(0), dataPtr(0) {};
+ DataSetInfo ( XMP_Uns8 _id, XMP_Uns32 _dataLen, XMP_Uns8 * _dataPtr )
+ : id(_id), dataLen(_dataLen), dataPtr(_dataPtr) {};
+ };
+
+ // ---------------------------------------------------------------------------------------------
+ // Parse a binary IPTC (IIM) block.
+
+ void ParseMemoryDataSets ( const void* data, XMP_Uns32 length, bool copyData = true );
+
+ // ---------------------------------------------------------------------------------------------
+ // Get the information about a DataSet. Returns the number of occurrences. The "which" parameter
+ // selects the occurrence, they are numbered from 0 to count-1. Returns 0 if which is too large.
+
+ size_t GetDataSet ( XMP_Uns8 id, DataSetInfo* info, size_t which = 0 ) const;
+
+ // ---------------------------------------------------------------------------------------------
+ // Get the value of a text DataSet as UTF-8. The returned pointer must be treated as read-only.
+ // Calls GetDataSet then does a local to UTF-8 conversion if necessary.
+
+ size_t GetDataSet_UTF8 ( XMP_Uns8 id, std::string * utf8Str, size_t which = 0 ) const;
+
+ // ---------------------------------------------------------------------------------------------
+ // Set the value of a text DataSet from a UTF-8 string. Does a UTF-8 to local conversion if
+ // necessary. If the encoding mode is currently local and this value has round-trip loss, then
+ // the encoding mode will be changed to UTF-8 and all existing values will be converted.
+ // Modifies an existing occurrence if "which" is within range. Adds an occurrence if which
+ // equals the current count, or which is -1 and repeats are allowed. Throws an exception if
+ // which is too large. The dataPtr provides the raw data, text must be in the right encoding.
+
+ virtual void SetDataSet_UTF8 ( XMP_Uns8 id, const void* utf8Ptr, XMP_Uns32 utf8Len, long which = -1 ) = 0;
+
+ // ---------------------------------------------------------------------------------------------
+ // Delete an existing DataSet. Deletes all occurrences if which is -1.
+
+ virtual void DeleteDataSet ( XMP_Uns8 id, long which = -1 ) = 0;
+
+ // ---------------------------------------------------------------------------------------------
+ // Determine if any DataSets are changed.
+
+ virtual bool IsChanged() = 0;
+
+ // ---------------------------------------------------------------------------------------------
+ // Determine if UTF-8 or local text encoding is being used.
+
+ bool UsingUTF8() const { return this->utf8Encoding; };
+
+ // ---------------------------------------------------------------------------------------------
+ // Update the DataSets to reflect the changed values. Returns the new size of the DataSets. The
+ // returned dataPtr must be treated as read only. It exists until the IPTC_Manager destructor
+ // is called. Can be used with read-only instances to get the raw data block info.
+
+ virtual XMP_Uns32 UpdateMemoryDataSets ( void** dataPtr ) = 0;
+
+ // ---------------------------------------------------------------------------------------------
+
+ virtual ~IPTC_Manager() { if ( this->ownedContent ) free ( this->iptcContent ); };
+
+protected:
+
+ enum { kMinDataSetSize = 5 }; // 1+1+1+2
+
+ typedef std::multimap<XMP_Uns16,DataSetInfo> DataSetMap;
+
+ DataSetMap dataSets;
+
+ XMP_Uns8* iptcContent;
+ XMP_Uns32 iptcLength, rec2Offset, rec2Length;
+
+ bool changed;
+ bool ownedContent; // True if IPTC_Manager destructor needs to release the content block.
+ bool utf8Encoding; // True if text values are encoded as UTF-8.
+
+ IPTC_Manager() : iptcContent(0), iptcLength(0), rec2Offset(0), rec2Length(0),
+ changed(false), ownedContent(false), utf8Encoding(false) {};
+
+ void DisposeLooseValue ( DataSetInfo & dsInfo );
+
+}; // IPTC_Manager
+
+
+// =================================================================================================
+// =================================================================================================
+
+
+// =================================================================================================
+// IPTC_Reader
+// ===========
+
+class IPTC_Reader : public IPTC_Manager {
+public:
+
+ IPTC_Reader() {};
+
+ void SetDataSet_UTF8 ( XMP_Uns8 id, const void* utf8Ptr, XMP_Uns32 utf8Len, long which = -1 ) { NotAppropriate(); };
+
+ void DeleteDataSet ( XMP_Uns8 id, long which = -1 ) { NotAppropriate(); };
+
+ bool IsChanged() { return false; };
+
+ XMP_Uns32 UpdateMemoryDataSets ( void** dataPtr )
+ { if ( dataPtr != 0 ) *dataPtr = iptcContent; return iptcLength; };
+
+ virtual ~IPTC_Reader() {};
+
+private:
+
+ static inline void NotAppropriate() { XMP_Throw ( "Not appropriate for IPTC_Reader", kXMPErr_InternalFailure ); };
+
+}; // IPTC_Reader
+
+// =================================================================================================
+// IPTC_Writer
+// ===========
+
+class IPTC_Writer : public IPTC_Manager {
+public:
+
+ void SetDataSet_UTF8 ( XMP_Uns8 id, const void* utf8Ptr, XMP_Uns32 utf8Len, long which = -1 );
+
+ void DeleteDataSet ( XMP_Uns8 id, long which = -1 );
+
+ bool IsChanged() { return changed; };
+
+ XMP_Uns32 UpdateMemoryDataSets ( void** dataPtr );
+
+ IPTC_Writer() {};
+
+ virtual ~IPTC_Writer();
+
+private:
+
+#if 0
+
+ void ConvertToUTF8();
+ void ConvertToLocal();
+
+ bool CheckRoundTripLoss();
+
+#endif // *** Disable the round trip loss checking for now.
+
+}; // IPTC_Writer
+
+// =================================================================================================
+
+#endif // __IPTC_Support_hpp__
diff --git a/source/XMPFiles/FormatSupport/PNG_Support.cpp b/source/XMPFiles/FormatSupport/PNG_Support.cpp
new file mode 100644
index 0000000..ed55dc6
--- /dev/null
+++ b/source/XMPFiles/FormatSupport/PNG_Support.cpp
@@ -0,0 +1,335 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "PNG_Support.hpp"
+
+typedef std::basic_string<unsigned char> filebuffer;
+
+namespace CRC
+{
+ /* Table of CRCs of all 8-bit messages. */
+ static unsigned long crc_table[256];
+
+ /* Flag: has the table been computed? Initially false. */
+ static int crc_table_computed = 0;
+
+ /* Make the table for a fast CRC. */
+ static void make_crc_table(void)
+ {
+ unsigned long c;
+ int n, k;
+
+ for (n = 0; n < 256; n++)
+ {
+ c = (unsigned long) n;
+ for (k = 0; k < 8; k++)
+ {
+ if (c & 1)
+ {
+ c = 0xedb88320L ^ (c >> 1);
+ }
+ else
+ {
+ c = c >> 1;
+ }
+ }
+ crc_table[n] = c;
+ }
+ crc_table_computed = 1;
+ }
+
+ /* Update a running CRC with the bytes buf[0..len-1]--the CRC
+ should be initialized to all 1's, and the transmitted value
+ is the 1's complement of the final running CRC (see the
+ crc() routine below). */
+
+ static unsigned long update_crc(unsigned long crc, unsigned char *buf, int len)
+ {
+ unsigned long c = crc;
+ int n;
+
+ if (!crc_table_computed)
+ {
+ make_crc_table();
+ }
+
+ for (n = 0; n < len; n++)
+ {
+ c = crc_table[(c ^ buf[n]) & 0xff] ^ (c >> 8);
+ }
+
+ return c;
+ }
+
+ /* Return the CRC of the bytes buf[0..len-1]. */
+ static unsigned long crc(unsigned char *buf, int len)
+ {
+ return update_crc(0xffffffffL, buf, len) ^ 0xffffffffL;
+ }
+} // namespace CRC
+
+namespace PNG_Support
+{
+ enum chunkType {
+ // Critical chunks - (shall appear in this order, except PLTE is optional)
+ IHDR = 'IHDR',
+ PLTE = 'PLTE',
+ IDAT = 'IDAT',
+ IEND = 'IEND',
+ // Ancillary chunks - (need not appear in this order)
+ cHRM = 'cHRM',
+ gAMA = 'gAMA',
+ iCCP = 'iCCP',
+ sBIT = 'sBIT',
+ sRGB = 'sRGB',
+ bKGD = 'bKGD',
+ hIST = 'hIST',
+ tRNS = 'tRNS',
+ pHYs = 'pHYs',
+ sPLT = 'sPLT',
+ tIME = 'tIME',
+ iTXt = 'iTXt',
+ tEXt = 'tEXt',
+ zTXt = 'zTXt'
+
+ };
+
+ // =============================================================================================
+
+ long OpenPNG ( LFA_FileRef fileRef, ChunkState & inOutChunkState )
+ {
+ XMP_Uns64 pos = 0;
+ long name;
+ XMP_Uns32 len;
+
+ pos = LFA_Seek ( fileRef, 8, SEEK_SET );
+ if (pos != 8) return 0;
+
+ // read first and following chunks
+ while ( ReadChunk ( fileRef, inOutChunkState, &name, &len, pos) ) {}
+
+ return inOutChunkState.chunks.size();
+
+ }
+
+ // =============================================================================================
+
+ bool ReadChunk ( LFA_FileRef fileRef, ChunkState & inOutChunkState, long * chunkType, XMP_Uns32 * chunkLength, XMP_Uns64 & inOutPosition )
+ {
+ try
+ {
+ XMP_Uns64 startPosition = inOutPosition;
+ long bytesRead;
+ char buffer[4];
+
+ bytesRead = LFA_Read ( fileRef, buffer, 4 );
+ if ( bytesRead != 4 ) return false;
+ inOutPosition += 4;
+ *chunkLength = GetUns32BE(buffer);
+
+ bytesRead = LFA_Read ( fileRef, buffer, 4 );
+ if ( bytesRead != 4 ) return false;
+ inOutPosition += 4;
+ *chunkType = GetUns32BE(buffer);
+
+ inOutPosition += *chunkLength;
+
+ bytesRead = LFA_Read ( fileRef, buffer, 4 );
+ if ( bytesRead != 4 ) return false;
+ inOutPosition += 4;
+ long crc = GetUns32BE(buffer);
+
+ ChunkData newChunk;
+
+ newChunk.pos = startPosition;
+ newChunk.len = *chunkLength;
+ newChunk.type = *chunkType;
+
+ // check for XMP in iTXt-chunk
+ if (newChunk.type == iTXt)
+ {
+ CheckiTXtChunkHeader(fileRef, inOutChunkState, newChunk);
+ }
+
+ inOutChunkState.chunks.push_back ( newChunk );
+
+ LFA_Seek ( fileRef, inOutPosition, SEEK_SET );
+
+ } catch ( ... ) {
+
+ return false;
+
+ }
+
+ return true;
+
+ }
+
+ // =============================================================================================
+
+ bool WriteXMPChunk ( LFA_FileRef fileRef, XMP_Uns32 len, const char* inBuffer )
+ {
+ bool ret = false;
+ unsigned long datalen = (4 + ITXT_HEADER_LEN + len);
+ unsigned char* buffer = new unsigned char[datalen];
+
+ try
+ {
+ size_t pos = 0;
+ memcpy(&buffer[pos], ITXT_CHUNK_TYPE, 4);
+ pos += 4;
+ memcpy(&buffer[pos], ITXT_HEADER_DATA, ITXT_HEADER_LEN);
+ pos += ITXT_HEADER_LEN;
+ memcpy(&buffer[pos], inBuffer, len);
+
+ unsigned long crc_value = MakeUns32BE( CalculateCRC( buffer, datalen ));
+ datalen -= 4;
+ unsigned long len_value = MakeUns32BE( datalen );
+ datalen += 4;
+
+ LFA_Write(fileRef, &len_value, 4);
+ LFA_Write(fileRef, buffer, datalen);
+ LFA_Write(fileRef, &crc_value, 4);
+
+ ret = true;
+ }
+ catch ( ... ) {}
+
+ delete [] buffer;
+
+ return ret;
+ }
+
+ // =============================================================================================
+
+ bool CopyChunk ( LFA_FileRef sourceRef, LFA_FileRef destRef, ChunkData& chunk )
+ {
+ try
+ {
+ LFA_Seek (sourceRef, chunk.pos, SEEK_SET );
+ LFA_Copy (sourceRef, destRef, (chunk.len + 12));
+
+ } catch ( ... ) {
+
+ return false;
+
+ }
+
+ return true;
+ }
+
+ // =============================================================================================
+
+ unsigned long UpdateChunkCRC( LFA_FileRef fileRef, ChunkData& inOutChunkData )
+ {
+ unsigned long ret = 0;
+ unsigned long datalen = (inOutChunkData.len + 4);
+ unsigned char* buffer = new unsigned char[datalen];
+
+ try
+ {
+ LFA_Seek(fileRef, (inOutChunkData.pos + 4), SEEK_SET);
+
+ size_t pos = 0;
+ long bytesRead = LFA_Read ( fileRef, &buffer[pos], (inOutChunkData.len + 4) );
+
+ unsigned long crc = CalculateCRC( buffer, (inOutChunkData.len + 4) );
+ unsigned long crc_value = MakeUns32BE( crc );
+
+ LFA_Seek(fileRef, (inOutChunkData.pos + 4 + 4 + inOutChunkData.len), SEEK_SET);
+ LFA_Write(fileRef, &crc_value, 4);
+
+ ret = crc;
+ }
+ catch ( ... ) {}
+
+ delete [] buffer;
+
+ return ret;
+ }
+
+ // =============================================================================================
+
+ bool CheckIHDRChunkHeader ( ChunkData& inOutChunkData )
+ {
+ return (inOutChunkData.type == IHDR);
+ }
+
+ // =============================================================================================
+
+ unsigned long CheckiTXtChunkHeader ( LFA_FileRef fileRef, ChunkState& inOutChunkState, ChunkData& inOutChunkData )
+ {
+ try
+ {
+ LFA_Seek(fileRef, (inOutChunkData.pos + 8), SEEK_SET);
+
+ char buffer[ITXT_HEADER_LEN];
+ long bytesRead = LFA_Read ( fileRef, buffer, ITXT_HEADER_LEN );
+
+ if (bytesRead == ITXT_HEADER_LEN)
+ {
+ if (memcmp(buffer, ITXT_HEADER_DATA, ITXT_HEADER_LEN) == 0)
+ {
+ // return length of XMP
+ if (inOutChunkData.len > ITXT_HEADER_LEN)
+ {
+ inOutChunkState.xmpPos = inOutChunkData.pos + 8 + ITXT_HEADER_LEN;
+ inOutChunkState.xmpLen = inOutChunkData.len - ITXT_HEADER_LEN;
+ inOutChunkState.xmpChunk = inOutChunkData;
+ inOutChunkData.xmp = true;
+
+ return inOutChunkState.xmpLen;
+ }
+ }
+ }
+ }
+ catch ( ... ) {}
+
+ return 0;
+ }
+
+ bool ReadBuffer ( LFA_FileRef fileRef, XMP_Uns64 & pos, XMP_Uns32 len, char * outBuffer )
+ {
+ try
+ {
+ if ( (fileRef == 0) || (outBuffer == 0) ) return false;
+
+ LFA_Seek (fileRef, pos, SEEK_SET );
+ long bytesRead = LFA_Read ( fileRef, outBuffer, len );
+ if ( XMP_Uns32(bytesRead) != len ) return false;
+
+ return true;
+ }
+ catch ( ... ) {}
+
+ return false;
+ }
+
+ bool WriteBuffer ( LFA_FileRef fileRef, XMP_Uns64 & pos, XMP_Uns32 len, const char * inBuffer )
+ {
+ try
+ {
+ if ( (fileRef == 0) || (inBuffer == 0) ) return false;
+
+ LFA_Seek (fileRef, pos, SEEK_SET );
+ LFA_Write( fileRef, inBuffer, len );
+
+ return true;
+ }
+ catch ( ... ) {}
+
+ return false;
+ }
+
+ unsigned long CalculateCRC( unsigned char* inBuffer, XMP_Uns32 len )
+ {
+ return CRC::update_crc(0xffffffffL, inBuffer, len) ^ 0xffffffffL;
+ }
+
+} // namespace PNG_Support
diff --git a/source/XMPFiles/FormatSupport/PNG_Support.hpp b/source/XMPFiles/FormatSupport/PNG_Support.hpp
new file mode 100644
index 0000000..1a5aaae
--- /dev/null
+++ b/source/XMPFiles/FormatSupport/PNG_Support.hpp
@@ -0,0 +1,74 @@
+#ifndef __PNG_Support_hpp__
+#define __PNG_Support_hpp__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "XMP_Environment.h" // ! This must be the first include.
+
+#include "XMPFiles_Impl.hpp"
+
+#define PNG_SIGNATURE_LEN 8
+#define PNG_SIGNATURE_DATA "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A"
+
+#define ITXT_CHUNK_TYPE "iTXt"
+
+#define ITXT_HEADER_LEN 22
+#define ITXT_HEADER_DATA "XML:com.adobe.xmp\0\0\0\0\0"
+
+namespace PNG_Support
+{
+ class ChunkData
+ {
+ public:
+ ChunkData() : pos(0), len(0), type(0), xmp(false) {}
+ virtual ~ChunkData() {}
+
+ // | length | type | data | crc(type+data) |
+ // | 4 | 4 | val(length) | 4 |
+ //
+ XMP_Uns64 pos; // file offset of chunk
+ XMP_Uns32 len; // length of chunk data
+ long type; // name/type of chunk
+ bool xmp; // iTXt-chunk with XMP ?
+ };
+
+ typedef std::vector<ChunkData> ChunkVector;
+ typedef ChunkVector::iterator ChunkIterator;
+
+ class ChunkState
+ {
+ public:
+ ChunkState() : xmpPos(0), xmpLen(0) {}
+ virtual ~ChunkState() {}
+
+ XMP_Uns64 xmpPos;
+ XMP_Uns32 xmpLen;
+ ChunkData xmpChunk;
+ ChunkVector chunks; /* vector of chunks */
+ };
+
+ long OpenPNG ( LFA_FileRef fileRef, ChunkState& inOutChunkState );
+
+ bool ReadChunk ( LFA_FileRef fileRef, ChunkState& inOutChunkState, long* chunkType, XMP_Uns32* chunkLength, XMP_Uns64& inOutPosition );
+ bool WriteXMPChunk ( LFA_FileRef fileRef, XMP_Uns32 len, const char* inBuffer );
+ bool CopyChunk ( LFA_FileRef sourceRef, LFA_FileRef destRef, ChunkData& chunk );
+ unsigned long UpdateChunkCRC( LFA_FileRef fileRef, ChunkData& inOutChunkData );
+
+ bool CheckIHDRChunkHeader ( ChunkData& inOutChunkData );
+ unsigned long CheckiTXtChunkHeader ( LFA_FileRef fileRef, ChunkState& inOutChunkState, ChunkData& inOutChunkData );
+
+ bool ReadBuffer ( LFA_FileRef fileRef, XMP_Uns64& pos, XMP_Uns32 len, char* outBuffer );
+ bool WriteBuffer ( LFA_FileRef fileRef, XMP_Uns64& pos, XMP_Uns32 len, const char* inBuffer );
+
+ unsigned long CalculateCRC( unsigned char* inBuffer, XMP_Uns32 len );
+
+} // namespace PNG_Support
+
+#endif // __PNG_Support_hpp__
diff --git a/source/XMPFiles/FormatSupport/PSIR_FileWriter.cpp b/source/XMPFiles/FormatSupport/PSIR_FileWriter.cpp
new file mode 100644
index 0000000..c1acfdf
--- /dev/null
+++ b/source/XMPFiles/FormatSupport/PSIR_FileWriter.cpp
@@ -0,0 +1,572 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "PSIR_Support.hpp"
+#include "EndianUtils.hpp"
+
+// =================================================================================================
+/// \file PSIR_FileWriter.cpp
+/// \brief Implementation of the file-based or read-write form of PSIR_Manager.
+// =================================================================================================
+
+// =================================================================================================
+// IsMetadataImgRsrc
+// =================
+//
+// The only image resources of possible interest as metadata have type '8BIM' and IDs:
+// 1008, 1020, 1028, 1034, 1035, 1036, 1058, 1060, 1061
+
+static inline bool IsMetadataImgRsrc ( XMP_Uns16 id )
+{
+
+ if ( (id < 1008) || (id > 1061) ) {
+ return false;
+ } else if ( id >= 1058 ) {
+ if ( id == 1059 ) return false;
+ } else if ( id > 1036 ) {
+ return false;
+ } else if ( id > 1028 ) {
+ if ( id < 1034 ) return false;
+ } else if ( id < 1028 ) {
+ if ( (id != 1008) && (id != 1020) ) return false;
+ }
+
+ return true;
+
+} // IsMetadataImgRsrc
+
+// =================================================================================================
+// PSIR_FileWriter::DeleteExistingInfo
+// ===================================
+//
+// Delete all existing info about image resources.
+
+void PSIR_FileWriter::DeleteExistingInfo()
+{
+ XMP_Assert ( ! (this->memParsed && this->fileParsed) );
+
+ if ( this->memParsed ) {
+ if ( this->ownedContent ) free ( this->memContent );
+ } else {
+ InternalRsrcMap::iterator irPos = this->imgRsrcs.begin();
+ InternalRsrcMap::iterator irEnd = this->imgRsrcs.end();
+ for ( ; irPos != irEnd; ++irPos ) irPos->second.changed = true; // Fool the InternalRsrcInfo destructor.
+ }
+
+ this->imgRsrcs.clear();
+
+ this->memContent = 0;
+ this->memLength = 0;
+
+ this->changed = false;
+ this->memParsed = false;
+ this->fileParsed = false;
+ this->ownedContent = false;
+
+} // PSIR_FileWriter::DeleteExistingInfo
+
+// =================================================================================================
+// PSIR_FileWriter::~PSIR_FileWriter
+// =================================
+//
+// The InternalRsrcInfo destructor will deallocate the data for changed image resources. It does not
+// know whether they are memory-parsed or file-parsed though, so it won't deallocate captured but
+// unchanged file-parsed resources. Mark those as changed to make the destructor deallocate them.
+
+PSIR_FileWriter::~PSIR_FileWriter()
+{
+ XMP_Assert ( ! (this->memParsed && this->fileParsed) );
+
+ if ( this->ownedContent ) {
+ XMP_Assert ( this->memContent != 0 );
+ free ( this->memContent );
+ }
+
+ if ( this->fileParsed ) {
+ InternalRsrcMap::iterator irPos = this->imgRsrcs.begin();
+ InternalRsrcMap::iterator irEnd = this->imgRsrcs.end();
+ for ( ; irPos != irEnd; ++irPos ) {
+ if ( irPos->second.dataPtr != 0 ) irPos->second.changed = true;
+ }
+ }
+
+
+} // PSIR_FileWriter::~PSIR_FileWriter
+
+// =================================================================================================
+// PSIR_FileWriter::GetImgRsrc
+// ===========================
+
+bool PSIR_FileWriter::GetImgRsrc ( XMP_Uns16 id, ImgRsrcInfo* info ) const
+{
+ InternalRsrcMap::const_iterator rsrcPos = this->imgRsrcs.find ( id );
+ if ( rsrcPos == this->imgRsrcs.end() ) return false;
+
+ const InternalRsrcInfo & rsrcInfo = rsrcPos->second;
+
+ if ( info != 0 ) {
+ info->id = rsrcInfo.id;
+ info->dataLen = rsrcInfo.dataLen;
+ info->dataPtr = rsrcInfo.dataPtr;
+ info->origOffset = rsrcInfo.origOffset;
+ }
+
+ return true;
+
+} // PSIR_FileWriter::GetImgRsrc
+
+// =================================================================================================
+// PSIR_FileWriter::SetImgRsrc
+// ===========================
+
+void PSIR_FileWriter::SetImgRsrc ( XMP_Uns16 id, const void* clientPtr, XMP_Uns32 length )
+{
+ InternalRsrcMap::iterator rsrcPos = this->imgRsrcs.find ( id );
+
+ if ( (rsrcPos != this->imgRsrcs.end()) &&
+ (length == rsrcPos->second.dataLen) &&
+ (memcmp ( rsrcPos->second.dataPtr, clientPtr, length ) == 0) ) {
+ return; // ! The value is unchanged, exit.
+ }
+
+ void* dataPtr = malloc ( length );
+ if ( dataPtr == 0 ) XMP_Throw ( "Out of memory", kXMPErr_NoMemory );
+ memcpy ( dataPtr, clientPtr, length ); // AUDIT: Safe, malloc'ed length bytes above.
+
+ if ( rsrcPos == this->imgRsrcs.end() ) {
+
+ // This resource is not yet in the map, create the map entry.
+ InternalRsrcInfo newRsrc ( id, length, dataPtr, (XMP_Uns32)(-1) );
+ newRsrc.changed = true;
+ this->imgRsrcs[id] = newRsrc;
+
+ } else {
+
+ // This resource is in the map, update the existing map entry.
+ InternalRsrcInfo* rsrcInfo = &rsrcPos->second;
+ if ( rsrcInfo->changed && (rsrcInfo->dataPtr != 0) ) free ( rsrcInfo->dataPtr );
+ rsrcInfo->dataPtr = dataPtr;
+ rsrcInfo->dataLen = length;
+ rsrcInfo->changed = true;
+
+ }
+
+ this->changed = true;
+
+} // PSIR_FileWriter::SetImgRsrc
+
+// =================================================================================================
+// PSIR_FileWriter::DeleteImgRsrc
+// ==============================
+
+void PSIR_FileWriter::DeleteImgRsrc ( XMP_Uns16 id )
+{
+ InternalRsrcMap::iterator rsrcPos = this->imgRsrcs.find ( id );
+ if ( rsrcPos == this->imgRsrcs.end() ) return; // Nothing to delete.
+
+ this->imgRsrcs.erase ( id );
+ this->changed = true;
+
+} // PSIR_FileWriter::DeleteImgRsrc
+
+// =================================================================================================
+// PSIR_FileWriter::IsLegacyChanged
+// ================================
+
+bool PSIR_FileWriter::IsLegacyChanged()
+{
+
+ if ( ! this->changed ) return false;
+
+ InternalRsrcMap::iterator irPos = this->imgRsrcs.begin();
+ InternalRsrcMap::iterator irEnd = this->imgRsrcs.end();
+
+ for ( ; irPos != irEnd; ++irPos ) {
+ const InternalRsrcInfo & rsrcInfo = irPos->second;
+ if ( rsrcInfo.changed && (rsrcInfo.id != kPSIR_XMP) ) return true;
+ }
+
+ return false; // Can get here if the XMP is the only thing changed.
+
+} // PSIR_FileWriter::IsLegacyChanged
+
+// =================================================================================================
+// PSIR_FileWriter::ParseMemoryResources
+// =====================================
+
+void PSIR_FileWriter::ParseMemoryResources ( const void* data, XMP_Uns32 length, bool copyData /* = true */ )
+{
+ this->DeleteExistingInfo();
+ this->memParsed = true;
+ if ( length == 0 ) return;
+
+ // Allocate space for the full in-memory data and copy it.
+
+ if ( ! copyData ) {
+ this->memContent = (XMP_Uns8*) data;
+ XMP_Assert ( ! this->ownedContent );
+ } else {
+ if ( length > 100*1024*1024 ) XMP_Throw ( "Outrageous length for memory-based PSIR", kXMPErr_BadPSIR );
+ this->memContent = (XMP_Uns8*) malloc ( length );
+ if ( this->memContent == 0 ) XMP_Throw ( "Out of memory", kXMPErr_NoMemory );
+ memcpy ( this->memContent, data, length ); // AUDIT: Safe, malloc'ed length bytes above.
+ this->ownedContent = true;
+ }
+ this->memLength = length;
+
+ // Capture the info for all of the resources.
+
+ XMP_Uns8* psirPtr = this->memContent;
+ XMP_Uns8* psirEnd = psirPtr + length;
+ XMP_Uns8* psirLimit = psirEnd - kMinImgRsrcSize;
+
+ while ( psirPtr <= psirLimit ) {
+
+ XMP_Uns8* origin = psirPtr; // The beginning of this resource.
+ XMP_Uns32 type = GetUns32BE(psirPtr);
+ XMP_Uns16 id = GetUns16BE(psirPtr+4);
+ psirPtr += 6; // Advance to the resource name.
+
+ XMP_Uns8* namePtr = psirPtr;
+ XMP_Uns16 nameLen = namePtr[0]; // ! The length for the Pascal string, w/ room for "+2".
+ psirPtr += ((nameLen + 2) & 0xFFFE); // ! Round up to an even offset. Yes, +2!
+
+ if ( psirPtr > psirEnd-4 ) break; // Bad image resource. Throw instead?
+
+ XMP_Uns32 dataLen = GetUns32BE(psirPtr);
+ psirPtr += 4; // Advance to the resource data.
+
+ XMP_Uns32 dataOffset = psirPtr - this->memContent;
+ XMP_Uns8* nextRsrc = psirPtr + ((dataLen + 1) & 0xFFFFFFFEUL); // ! Round up to an even offset.
+
+ if ( (dataLen > length) || (psirPtr > psirEnd-dataLen) ) break; // Bad image resource. Throw instead?
+
+ if ( type == k8BIM ) {
+ InternalRsrcInfo newRsrc ( id, dataLen, psirPtr, dataOffset );
+ this->imgRsrcs[id] = newRsrc;
+ if ( nameLen != 0 ) this->imgRsrcs[id].rsrcName = namePtr;
+ } else {
+ XMP_Uns32 rsrcOffset = origin - this->memContent;
+ XMP_Uns32 rsrcLength = nextRsrc - origin; // Includes trailing pad.
+ XMP_Assert ( (rsrcLength & 1) == 0 );
+ this->otherRsrcs.push_back ( OtherRsrcInfo ( rsrcOffset, rsrcLength ) );
+ }
+
+ psirPtr = nextRsrc;
+
+ }
+
+} // PSIR_FileWriter::ParseMemoryResources
+
+// =================================================================================================
+// PSIR_FileWriter::ParseFileResources
+// ===================================
+
+void PSIR_FileWriter::ParseFileResources ( LFA_FileRef fileRef, XMP_Uns32 length )
+{
+ bool ok;
+
+ this->DeleteExistingInfo();
+ this->fileParsed = true;
+ if ( length == 0 ) return;
+
+ // Parse the image resource block.
+
+ IOBuffer ioBuf;
+ ioBuf.filePos = LFA_Seek ( fileRef, 0, SEEK_CUR );
+
+ XMP_Int64 psirOrigin = ioBuf.filePos; // Need this to determine the resource data offsets.
+
+ XMP_Int64 fileEnd = ioBuf.filePos + length;
+
+ while ( (ioBuf.filePos + (ioBuf.ptr - ioBuf.data)) < fileEnd ) {
+
+ ok = CheckFileSpace ( fileRef, &ioBuf, 12 ); // The minimal image resource takes 12 bytes.
+ if ( ! ok ) break; // Bad image resource. Throw instead?
+
+ XMP_Int64 thisRsrcPos = ioBuf.filePos + (ioBuf.ptr - ioBuf.data);
+
+ XMP_Uns32 type = GetUns32BE(ioBuf.ptr);
+ XMP_Uns16 id = GetUns16BE(ioBuf.ptr+4);
+ ioBuf.ptr += 6; // Advance to the resource name.
+
+ XMP_Uns16 nameLen = ioBuf.ptr[0]; // ! The length for the Pascal string, w/ room for "+2".
+ nameLen = (nameLen + 2) & 0xFFFE; // ! Round up to an even total. Yes, +2!
+ ok = CheckFileSpace ( fileRef, &ioBuf, nameLen+4 ); // Get the name and data length.
+ if ( ! ok ) break; // Bad image resource. Throw instead?
+
+ ioBuf.ptr += nameLen; // Move to the data length.
+ XMP_Uns32 dataLen = GetUns32BE(ioBuf.ptr);
+ XMP_Uns32 dataTotal = ((dataLen + 1) & 0xFFFFFFFEUL); // Round up to an even total.
+ ioBuf.ptr += 4; // Advance to the resource data.
+
+ XMP_Int64 thisDataPos = ioBuf.filePos + (ioBuf.ptr - ioBuf.data);
+ XMP_Int64 nextRsrcPos = thisDataPos + dataTotal;
+
+ if ( type != k8BIM ) {
+ XMP_Uns32 fullRsrcLen = (XMP_Uns32) (nextRsrcPos - thisRsrcPos);
+ this->otherRsrcs.push_back ( OtherRsrcInfo ( (XMP_Uns32)thisRsrcPos, fullRsrcLen ) );
+ MoveToOffset ( fileRef, nextRsrcPos, &ioBuf );
+ continue;
+ }
+
+ InternalRsrcInfo newRsrc ( id, dataLen, 0, (XMP_Uns32)thisDataPos );
+ this->imgRsrcs[id] = newRsrc;
+
+ if ( ! IsMetadataImgRsrc ( id ) ) {
+ MoveToOffset ( fileRef, nextRsrcPos, &ioBuf );
+ continue;
+ }
+
+ newRsrc.dataPtr = malloc ( dataLen );
+ if ( newRsrc.dataPtr == 0 ) XMP_Throw ( "Out of memory", kXMPErr_NoMemory );
+
+ try {
+
+ if ( dataTotal <= kIOBufferSize ) {
+ // The image resource data fits within the I/O buffer.
+ ok = CheckFileSpace ( fileRef, &ioBuf, dataTotal );
+ if ( ! ok ) break; // Bad image resource. Throw instead?
+ memcpy ( (void*)newRsrc.dataPtr, ioBuf.ptr, dataLen ); // AUDIT: Safe, malloc'ed dataLen bytes above.
+ ioBuf.ptr += dataTotal; // ! Add the rounded length.
+ } else {
+ // The image resource data is bigger than the I/O buffer.
+ LFA_Seek ( fileRef, (ioBuf.filePos + (ioBuf.ptr - ioBuf.data)), SEEK_SET );
+ LFA_Read ( fileRef, (void*)newRsrc.dataPtr, dataLen );
+ FillBuffer ( fileRef, nextRsrcPos, &ioBuf );
+ }
+
+ this->imgRsrcs[id].dataPtr = newRsrc.dataPtr;
+
+ } catch ( ... ) {
+
+ free ( (void*)newRsrc.dataPtr );
+ throw;
+
+ }
+
+ }
+
+ #if 0
+ {
+ printf ( "\nPSIR_FileWriter::ParseFileResources, count = %d\n", this->imgRsrcs.size() );
+ InternalRsrcMap::iterator irPos = this->imgRsrcs.begin();
+ InternalRsrcMap::iterator irEnd = this->imgRsrcs.end();
+ for ( ; irPos != irEnd; ++irPos ) {
+ InternalRsrcInfo& thisRsrc = irPos->second;
+ printf ( " #%d, dataLen %d, origOffset %d (0x%X)%s\n",
+ thisRsrc.id, thisRsrc.dataLen, thisRsrc.origOffset, thisRsrc.origOffset,
+ (thisRsrc.changed ? ", changed" : "") );
+ }
+ }
+ #endif
+
+} // PSIR_FileWriter::ParseFileResources
+
+// =================================================================================================
+// PSIR_FileWriter::UpdateMemoryResources
+// ======================================
+
+XMP_Uns32 PSIR_FileWriter::UpdateMemoryResources ( void** dataPtr )
+{
+ if ( this->fileParsed ) XMP_Throw ( "Not memory based", kXMPErr_EnforceFailure );
+
+ // Compute the size and allocate the new image resource block.
+
+ XMP_Uns32 newLength = 0;
+
+ InternalRsrcMap::iterator irPos = this->imgRsrcs.begin();
+ InternalRsrcMap::iterator irEnd = this->imgRsrcs.end();
+
+ for ( ; irPos != irEnd; ++irPos ) { // Add in the lengths for the 8BIM resources.
+ const InternalRsrcInfo & rsrcInfo = irPos->second;
+ newLength += 10;
+ newLength += ((rsrcInfo.dataLen + 1) & 0xFFFFFFFEUL);
+ if ( rsrcInfo.rsrcName == 0 ) {
+ newLength += 2;
+ } else {
+ XMP_Uns32 nameLen = rsrcInfo.rsrcName[0];
+ newLength += ((nameLen + 2) & 0xFFFFFFFEUL); // ! Yes, +2.
+ }
+ }
+
+ for ( size_t i = 0; i < this->otherRsrcs.size(); ++i ) { // Add in the non-8BIM resources.
+ newLength += this->otherRsrcs[i].rsrcLength;
+ }
+
+ XMP_Uns8* newContent = (XMP_Uns8*) malloc ( newLength );
+ if ( newContent == 0 ) XMP_Throw ( "Out of memory", kXMPErr_NoMemory );
+
+ // Fill in the new image resource block.
+
+ XMP_Uns8* rsrcPtr = newContent;
+
+ for ( irPos = this->imgRsrcs.begin(); irPos != irEnd; ++irPos ) { // Do the 8BIM resources.
+
+ const InternalRsrcInfo & rsrcInfo = irPos->second;
+
+ PutUns32BE ( k8BIM, rsrcPtr );
+ rsrcPtr += 4;
+ PutUns16BE ( rsrcInfo.id, rsrcPtr );
+ rsrcPtr += 2;
+
+ if ( rsrcInfo.rsrcName == 0 ) {
+ PutUns16BE ( 0, rsrcPtr );
+ rsrcPtr += 2;
+ } else {
+ XMP_Uns32 nameLen = rsrcInfo.rsrcName[0];
+ if ( (nameLen+1) > (newLength - (rsrcPtr - newContent)) ) {
+ XMP_Throw ( "Buffer overrun", kXMPErr_InternalFailure );
+ }
+ memcpy ( rsrcPtr, rsrcInfo.rsrcName, nameLen+1 ); // AUDIT: Protected by the above check.
+ rsrcPtr += nameLen+1;
+ if ( (nameLen & 1) == 0 ) {
+ *rsrcPtr = 0;
+ ++rsrcPtr;
+ }
+ }
+
+ PutUns32BE ( rsrcInfo.dataLen, rsrcPtr );
+ rsrcPtr += 4;
+ if ( rsrcInfo.dataLen > (newLength - (rsrcPtr - newContent)) ) {
+ XMP_Throw ( "Buffer overrun", kXMPErr_InternalFailure );
+ }
+ memcpy ( rsrcPtr, rsrcInfo.dataPtr, rsrcInfo.dataLen ); // AUDIT: Protected by the above check.
+ rsrcPtr += rsrcInfo.dataLen;
+ if ( (rsrcInfo.dataLen & 1) != 0 ) { // Pad to an even length if necessary.
+ *rsrcPtr = 0;
+ ++rsrcPtr;
+ }
+
+ }
+
+ for ( size_t i = 0; i < this->otherRsrcs.size(); ++i ) { // Do the non-8BIM resources.
+ XMP_Uns8* srcPtr = this->memContent + this->otherRsrcs[i].rsrcOffset;
+ XMP_Uns32 srcLen = this->otherRsrcs[i].rsrcLength;
+ if ( srcLen > (newLength - (rsrcPtr - newContent)) ) {
+ XMP_Throw ( "Buffer overrun", kXMPErr_InternalFailure );
+ }
+ memcpy ( rsrcPtr, srcPtr, srcLen ); // AUDIT: Protected by the above check.
+ rsrcPtr += srcLen; // No need to pad, included in the original resource length.
+ }
+
+ XMP_Assert ( rsrcPtr == (newContent + newLength) );
+
+ // Parse the rebuilt image resource block. This is the easiest way to reconstruct the map.
+
+ this->ParseMemoryResources ( newContent, newLength, false );
+ this->ownedContent = true; // ! We really do own it.
+
+ if ( dataPtr != 0 ) *dataPtr = newContent;
+ return newLength;
+
+} // PSIR_FileWriter::UpdateMemoryResources
+
+// =================================================================================================
+// PSIR_FileWriter::UpdateFileResources
+// ====================================
+
+XMP_Uns32 PSIR_FileWriter::UpdateFileResources ( LFA_FileRef sourceRef, LFA_FileRef destRef,
+ IOBuffer * ioBuf, XMP_AbortProc abortProc, void * abortArg )
+{
+ IgnoreParam(ioBuf);
+
+ const bool checkAbort = (abortProc != 0);
+
+ struct RsrcHeader {
+ XMP_Uns32 type;
+ XMP_Uns16 id;
+ XMP_Uns16 name;
+ XMP_Uns32 dataLen;
+ };
+ XMP_Assert ( sizeof(RsrcHeader) == 12 );
+
+ if ( this->memParsed ) XMP_Throw ( "Not file based", kXMPErr_EnforceFailure );
+
+ XMP_Int64 destLenOffset = LFA_Seek ( destRef, 0, SEEK_CUR );
+ XMP_Uns32 destLength = 0;
+
+ LFA_Write ( destRef, &destLength, 4 ); // Write a placeholder for the new PSIR section length.
+
+ #if 0
+ {
+ printf ( "\nPSIR_FileWriter::UpdateFileResources, count = %d\n", this->imgRsrcs.size() );
+ InternalRsrcMap::iterator irPos = this->imgRsrcs.begin();
+ InternalRsrcMap::iterator irEnd = this->imgRsrcs.end();
+ for ( ; irPos != irEnd; ++irPos ) {
+ InternalRsrcInfo& thisRsrc = irPos->second;
+ printf ( " #%d, dataLen %d, origOffset %d (0x%X)%s\n",
+ thisRsrc.id, thisRsrc.dataLen, thisRsrc.origOffset, thisRsrc.origOffset,
+ (thisRsrc.changed ? ", changed" : "") );
+ }
+ }
+ #endif
+
+ // First write all of the '8BIM' resources from the map. Use the internal data if present, else
+ // copy the data from the file. We don't preserve names for these resources, but then Photoshop
+ // itself tosses out all resource names and has no plans to ever support them.
+
+ RsrcHeader outRsrc;
+ outRsrc.type = MakeUns32BE ( k8BIM );
+ outRsrc.name = 0;
+
+ InternalRsrcMap::iterator rsrcPos = this->imgRsrcs.begin();
+ InternalRsrcMap::iterator rsrcEnd = this->imgRsrcs.end();
+
+ // printf ( "\nPSIR_FileWriter::UpdateFileResources - 8BIM resources\n" );
+ for ( ; rsrcPos != rsrcEnd; ++rsrcPos ) {
+
+ InternalRsrcInfo& currRsrc = rsrcPos->second;
+
+ outRsrc.id = MakeUns16BE ( currRsrc.id );
+ outRsrc.dataLen = MakeUns32BE ( currRsrc.dataLen );
+ LFA_Write ( destRef, &outRsrc, sizeof(RsrcHeader) );
+ // printf ( " #%d, offset %d (0x%X), dataLen %d\n", currRsrc.id, destLength, destLength, currRsrc.dataLen );
+
+ if ( currRsrc.dataPtr != 0 ) {
+ LFA_Write ( destRef, currRsrc.dataPtr, currRsrc.dataLen );
+ } else {
+ LFA_Seek ( sourceRef, currRsrc.origOffset, SEEK_SET );
+ LFA_Copy ( sourceRef, destRef, currRsrc.dataLen );
+ }
+
+ destLength += sizeof(RsrcHeader) + currRsrc.dataLen;
+
+ if ( (currRsrc.dataLen & 1) != 0 ) {
+ LFA_Write ( destRef, &outRsrc.name, 1 ); // ! The name contains zero.
+ ++destLength;
+ }
+
+ }
+
+ // Now write all of the non-8BIM resources. Copy the entire resource chunk from the source file.
+
+ // printf ( "\nPSIR_FileWriter::UpdateFileResources - other resources\n" );
+ for ( size_t i = 0; i < this->otherRsrcs.size(); ++i ) {
+ // printf ( " offset %d (0x%X), length %d",
+ // this->otherRsrcs[i].rsrcOffset, this->otherRsrcs[i].rsrcOffset, this->otherRsrcs[i].rsrcLength );
+ LFA_Seek ( sourceRef, this->otherRsrcs[i].rsrcOffset, SEEK_SET );
+ LFA_Copy ( sourceRef, destRef, this->otherRsrcs[i].rsrcLength );
+ destLength += this->otherRsrcs[i].rsrcLength; // Alignment padding is already included.
+ }
+
+ // Write the final PSIR section length, seek back to the end of the file, return the length.
+
+ // printf ( "\nPSIR_FileWriter::UpdateFileResources - final length %d (0x%X)\n", destLength, destLength );
+ LFA_Seek ( destRef, destLenOffset, SEEK_SET );
+ XMP_Uns32 outLen = MakeUns32BE ( destLength );
+ LFA_Write ( destRef, &outLen, 4 );
+ LFA_Seek ( destRef, 0, SEEK_END );
+
+ // *** Not rebuilding the internal map - turns out we never want it, why pay for the I/O.
+ // *** Should probably add an option for all of these cases, memory and file based.
+
+ return destLength;
+
+} // PSIR_FileWriter::UpdateFileResources
diff --git a/source/XMPFiles/FormatSupport/PSIR_MemoryReader.cpp b/source/XMPFiles/FormatSupport/PSIR_MemoryReader.cpp
new file mode 100644
index 0000000..027162c
--- /dev/null
+++ b/source/XMPFiles/FormatSupport/PSIR_MemoryReader.cpp
@@ -0,0 +1,95 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "PSIR_Support.hpp"
+#include "EndianUtils.hpp"
+
+// =================================================================================================
+/// \file PSIR_MemoryReader.cpp
+/// \brief Implementation of the memory-based read-only form of PSIR_Manager.
+// =================================================================================================
+
+// =================================================================================================
+// PSIR_MemoryReader::GetImgRsrc
+// =============================
+
+bool PSIR_MemoryReader::GetImgRsrc ( XMP_Uns16 id, ImgRsrcInfo* info ) const
+{
+ ImgRsrcMap::const_iterator rsrcPos = this->imgRsrcs.find ( id );
+ if ( rsrcPos == this->imgRsrcs.end() ) return false;
+
+ if ( info != 0 ) *info = rsrcPos->second;
+ return true;
+
+} // PSIR_MemoryReader::GetImgRsrc
+
+// =================================================================================================
+// PSIR_MemoryReader::ParseMemoryResources
+// =======================================
+
+void PSIR_MemoryReader::ParseMemoryResources ( const void* data, XMP_Uns32 length, bool copyData /* = true */ )
+{
+ // Get rid of any existing image resources.
+
+ if ( this->ownedContent ) free ( this->psirContent );
+ this->ownedContent = false;
+ this->psirContent = 0;
+ this->psirLength = 0;
+ this->imgRsrcs.clear();
+
+ if ( length == 0 ) return;
+
+ // Allocate space for the full in-memory data and copy it.
+
+ if ( ! copyData ) {
+ this->psirContent = (XMP_Uns8*) data;
+ XMP_Assert ( ! this->ownedContent );
+ } else {
+ if ( length > 100*1024*1024 ) XMP_Throw ( "Outrageous length for memory-based PSIR", kXMPErr_BadPSIR );
+ this->psirContent = (XMP_Uns8*) malloc(length);
+ if ( this->psirContent == 0 ) XMP_Throw ( "Out of memory", kXMPErr_NoMemory );
+ memcpy ( this->psirContent, data, length ); // AUDIT: Safe, malloc'ed length bytes above.
+ this->ownedContent = true;
+ }
+
+ this->psirLength = length;
+
+ // Capture the info for all of the resources.
+
+ XMP_Uns8* psirPtr = this->psirContent;
+ XMP_Uns8* psirEnd = psirPtr + length;
+ XMP_Uns8* psirLimit = psirEnd - kMinImgRsrcSize;
+
+ while ( psirPtr <= psirLimit ) {
+
+ XMP_Uns32 type = GetUns32BE(psirPtr);
+ XMP_Uns16 id = GetUns16BE(psirPtr+4);
+ psirPtr += 6; // Advance to the resource name.
+
+ XMP_Uns16 nameLen = psirPtr[0]; // ! The length for the Pascal string, w/ room for "+2".
+ psirPtr += ((nameLen + 2) & 0xFFFE); // ! Round up to an even offset. Yes, +2!
+
+ if ( psirPtr > psirEnd-4 ) break; // Bad image resource. Throw instead?
+
+ XMP_Uns32 dataLen = GetUns32BE(psirPtr);
+ psirPtr += 4; // Advance to the resource data.
+ XMP_Uns32 psirOffset = psirPtr - this->psirContent;
+
+ if ( (dataLen > length) || (psirPtr > psirEnd-dataLen) ) break; // Bad image resource. Throw instead?
+
+ if ( type == k8BIM ) { // For read-only usage we ignore everything other than '8BIM' resources.
+ ImgRsrcInfo info ( id, dataLen, psirPtr, psirOffset );
+ this->imgRsrcs[id] = info;
+ }
+
+ psirPtr += ((dataLen + 1) & 0xFFFFFFFEUL); // ! Round up to an even offset.
+
+ }
+
+} // PSIR_MemoryReader::ParseMemoryResources
diff --git a/source/XMPFiles/FormatSupport/PSIR_Support.hpp b/source/XMPFiles/FormatSupport/PSIR_Support.hpp
new file mode 100644
index 0000000..91d064b
--- /dev/null
+++ b/source/XMPFiles/FormatSupport/PSIR_Support.hpp
@@ -0,0 +1,289 @@
+#ifndef __PSIR_Support_hpp__
+#define __PSIR_Support_hpp__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "XMP_Environment.h" // ! This must be the first include.
+
+#include <map>
+
+#include "XMP_Const.h"
+#include "XMPFiles_Impl.hpp"
+#include "EndianUtils.hpp"
+
+// =================================================================================================
+/// \file PSIR_Support.hpp
+/// \brief XMPFiles support for Photoshop image resources.
+///
+/// This header provides Photoshop image resource (PSIR) support specific to the needs of XMPFiles.
+/// This is not intended for general purpose PSIR processing. PSIR_Manager is an abstract base
+/// class with 2 concrete derived classes, PSIR_MemoryReader and PSIR_FileWriter.
+///
+/// PSIR_MemoryReader provides read-only support for PSIR streams that are small enough to be kept
+/// entirely in memory. This allows optimizations to reduce heap usage and processing code. It is
+/// sufficient for browsing access to the image resources (mainly the IPTC) in JPEG files. Think of
+/// PSIR_MemoryReader as "memory-based AND read-only".
+///
+/// PSIR_FileWriter is for cases where updates are needed or the PSIR stream is too large to be kept
+/// entirely in memory. Think of PSIR_FileWriter as "file-based OR read-write".
+///
+/// The needs of XMPFiles are well defined metadata access. Only a few image resources are handled.
+/// This is the case for all of the derived classes, even though the memory based ones happen to
+/// have all of the image resources in memory. Being "handled" means being in the image resource
+/// map used by GetImgRsrc. The handled image resources are:
+/// \li 1008 - Ancient caption PString
+/// \li 1020 - Ancient caption string
+/// \li 1028 - IPTC
+/// \li 1034 - Copyrighted flag
+/// \li 1035 - Copyright information URL
+/// \li 1058 - Exif metadata
+/// \li 1060 - XMP
+/// \li 1061 - IPTC digest
+///
+/// \note These classes are for use only when directly compiled and linked. They should not be
+/// packaged in a DLL by themselves. They do not provide any form of C++ ABI protection.
+// =================================================================================================
+
+
+// These aren't inside PSIR_Manager because the static array can't be initialized there.
+
+enum {
+ k8BIM = 0x3842494DUL, // The 4 ASCII characters '8BIM'.
+ kMinImgRsrcSize = 4+2+2+4 // The minimum size for an image resource.
+};
+
+enum { kPSIR_MetadataCount = 9 }; // 1 2 3 4 5 6 7 8 9
+static const XMP_Uns16 kPSIR_MetadataIDs[] = { 1008, 1020, 1028, 1034, 1035, 1036, 1058, 1060, 1061, 0 };
+
+enum {
+ kPSIR_OldCaptionPStr = 1008,
+ kPSIR_OldCaption = 1020,
+ kPSIR_IPTC = 1028,
+ kPSIR_CopyrightFlag = 1034,
+ kPSIR_CopyrightURL = 1035,
+ kPSIR_Thumbnail = 1036,
+ kPSIR_Exif = 1058,
+ kPSIR_XMP = 1060,
+ kPSIR_IPTCDigest = 1061
+};
+
+
+// =================================================================================================
+// =================================================================================================
+
+// NOTE: Although Photoshop image resources have a type and ID, for metadatya we only care about
+// those of type "8BIM". Resources of other types are preserved in files, but can't be individually
+// accessed through the PSIR_Manager API.
+
+// =================================================================================================
+// PSIR_Manager
+// ============
+
+class PSIR_Manager { // The abstract base class.
+public:
+
+ // ---------------------------------------------------------------------------------------------
+ // Types and constants
+
+ struct ImgRsrcInfo {
+ XMP_Uns16 id;
+ XMP_Uns32 dataLen;
+ const void* dataPtr; // ! The data is read-only!
+ XMP_Uns32 origOffset; // The offset (at parse time) of the resource data.
+ ImgRsrcInfo() : id(0), dataLen(0), dataPtr(0), origOffset(0) {};
+ ImgRsrcInfo ( XMP_Uns16 _id, XMP_Uns32 _dataLen, void* _dataPtr, XMP_Uns32 _origOffset )
+ : id(_id), dataLen(_dataLen), dataPtr(_dataPtr), origOffset(_origOffset) {};
+ };
+
+ // The origOffset is the absolute file offset for file parses, the memory block offset for
+ // memory parses. It is the offset of the resource data portion, not the overall resource.
+
+ // ---------------------------------------------------------------------------------------------
+ // Get the information about a "handled" image resource. Returns false if the image resource is
+ // not handled, even if it was present in the parsed input.
+
+ virtual bool GetImgRsrc ( XMP_Uns16 id, ImgRsrcInfo* info ) const = 0;
+
+ // ---------------------------------------------------------------------------------------------
+ // Set the value for an image resource. It can be any resource, even one not originally handled.
+
+ virtual void SetImgRsrc ( XMP_Uns16 id, const void* dataPtr, XMP_Uns32 length ) = 0;
+
+ // ---------------------------------------------------------------------------------------------
+ // Delete an image resource. Does nothing if the image resource does not exist.
+
+ virtual void DeleteImgRsrc ( XMP_Uns16 id ) = 0;
+
+ // ---------------------------------------------------------------------------------------------
+ // Determine if the image resources are changed.
+
+ virtual bool IsChanged() = 0;
+ virtual bool IsLegacyChanged() = 0;
+
+ // ---------------------------------------------------------------------------------------------
+
+ virtual void ParseMemoryResources ( const void* data, XMP_Uns32 length, bool copyData = true ) = 0;
+ virtual void ParseFileResources ( LFA_FileRef fileRef, XMP_Uns32 length ) = 0;
+
+ // ---------------------------------------------------------------------------------------------
+ // Update the image resources to reflect the changed values. Both \c UpdateMemoryResources and
+ // \c UpdateFileResources return the new size of the image resource block. The dataPtr returned
+ // by \c UpdateMemoryResources must be treated as read only. It exists until the PSIR_Manager
+ // destructor is called. UpdateMemoryResources can be used on a read-only instance to get the
+ // raw data block info.
+
+ virtual XMP_Uns32 UpdateMemoryResources ( void** dataPtr ) = 0;
+ virtual XMP_Uns32 UpdateFileResources ( LFA_FileRef sourceRef, LFA_FileRef destRef,
+ IOBuffer * ioBuf, XMP_AbortProc abortProc, void * abortArg ) = 0;
+
+ // ---------------------------------------------------------------------------------------------
+
+ virtual ~PSIR_Manager() {};
+
+protected:
+
+ PSIR_Manager() {};
+
+}; // PSIR_Manager
+
+
+// =================================================================================================
+// =================================================================================================
+
+
+// =================================================================================================
+// PSIR_MemoryReader
+// =================
+
+class PSIR_MemoryReader : public PSIR_Manager { // The leaf class for memory-based read-only access.
+public:
+
+ bool GetImgRsrc ( XMP_Uns16 id, ImgRsrcInfo* info ) const;
+
+ void SetImgRsrc ( XMP_Uns16 id, const void* dataPtr, XMP_Uns32 length ) { NotAppropriate(); };
+
+ void DeleteImgRsrc ( XMP_Uns16 id ) { NotAppropriate(); };
+
+ bool IsChanged() { return false; };
+ bool IsLegacyChanged() { return false; };
+
+ void ParseMemoryResources ( const void* data, XMP_Uns32 length, bool copyData = true );
+ void ParseFileResources ( LFA_FileRef file, XMP_Uns32 length ) { NotAppropriate(); };
+
+ XMP_Uns32 UpdateMemoryResources ( void** dataPtr ) { if ( dataPtr != 0 ) *dataPtr = psirContent; return psirLength; };
+ XMP_Uns32 UpdateFileResources ( LFA_FileRef sourceRef, LFA_FileRef destRef,
+ IOBuffer * ioBuf, XMP_AbortProc abortProc, void * abortArg ) { NotAppropriate(); return 0; };
+
+ PSIR_MemoryReader() : ownedContent(false), psirLength(0), psirContent(0) {};
+
+ virtual ~PSIR_MemoryReader() { if ( this->ownedContent ) free ( this->psirContent ); };
+
+private:
+
+ bool ownedContent;
+
+ XMP_Uns32 psirLength;
+ XMP_Uns8* psirContent;
+
+ typedef std::map<XMP_Uns16,ImgRsrcInfo> ImgRsrcMap;
+
+ ImgRsrcMap imgRsrcs;
+
+ static inline void NotAppropriate() { XMP_Throw ( "Not appropriate for PSIR_Reader", kXMPErr_InternalFailure ); };
+
+}; // PSIR_MemoryReader
+
+
+// =================================================================================================
+// =================================================================================================
+
+
+// =================================================================================================
+// PSIR_FileWriter
+// ===============
+
+class PSIR_FileWriter : public PSIR_Manager { // The leaf class for file-based read-write access.
+public:
+
+ bool GetImgRsrc ( XMP_Uns16 id, ImgRsrcInfo* info ) const;
+
+ void SetImgRsrc ( XMP_Uns16 id, const void* dataPtr, XMP_Uns32 length );
+
+ void DeleteImgRsrc ( XMP_Uns16 id );
+
+ bool IsChanged() { return this->changed; };
+
+ bool IsLegacyChanged();
+
+ void ParseMemoryResources ( const void* data, XMP_Uns32 length, bool copyData = true );
+ void ParseFileResources ( LFA_FileRef file, XMP_Uns32 length );
+
+ XMP_Uns32 UpdateMemoryResources ( void** dataPtr );
+ XMP_Uns32 UpdateFileResources ( LFA_FileRef sourceRef, LFA_FileRef destRef,
+ IOBuffer * ioBuf, XMP_AbortProc abortProc, void * abortArg );
+
+ PSIR_FileWriter() : changed(false), memParsed(false), fileParsed(false),
+ ownedContent(false), memLength(0), memContent(0) {};
+
+ virtual ~PSIR_FileWriter();
+
+ struct InternalRsrcInfo {
+ bool changed;
+ XMP_Uns16 id;
+ XMP_Uns32 dataLen;
+ void* dataPtr; // ! The data is read-only! Null if the value is not captured!
+ XMP_Uns32 origOffset; // The offset (at parse time) of the resource data.
+ XMP_Uns8* rsrcName; // ! A Pascal string. Only in the map for memory-based resources.
+ InternalRsrcInfo() : changed(false), id(0), dataLen(0), dataPtr(0), origOffset(0), rsrcName(0) {};
+ InternalRsrcInfo ( XMP_Uns16 _id, XMP_Uns32 _dataLen, void* _dataPtr, XMP_Uns32 _origOffset )
+ : changed(false), id(_id), dataLen(_dataLen), dataPtr(_dataPtr), origOffset(_origOffset), rsrcName(0) {};
+ ~InternalRsrcInfo()
+ {
+ if ( this->changed && (this->dataPtr != 0) ) free ( this->dataPtr );
+ };
+ void operator= ( const InternalRsrcInfo & in )
+ { // ! Hack to transfer ownership of the data block.
+ this->changed = in.changed;
+ this->id = in.id;
+ this->dataLen = in.dataLen; this->dataPtr = in.dataPtr;
+ this->origOffset = in.origOffset; this->rsrcName = in.rsrcName;
+ *((void**)&in.dataPtr) = 0;
+ };
+ };
+
+ // The origOffset is the absolute file offset for file parses, the memory block offset for
+ // memory parses. It is the offset of the resource data portion, not the overall resource.
+
+private:
+
+ bool changed;
+ bool memParsed, fileParsed;
+ bool ownedContent;
+
+ XMP_Uns32 memLength;
+ XMP_Uns8* memContent;
+
+ typedef std::map<XMP_Uns16,InternalRsrcInfo> InternalRsrcMap;
+ InternalRsrcMap imgRsrcs;
+
+ struct OtherRsrcInfo { // For the resources of types other than "8BIM".
+ XMP_Uns32 rsrcOffset; // The offset of the resource origin, the type field.
+ XMP_Uns32 rsrcLength; // The full length of the resource, offset to the next resource.
+ OtherRsrcInfo() : rsrcOffset(0), rsrcLength(0) {};
+ OtherRsrcInfo ( XMP_Uns32 _rsrcOffset, XMP_Uns32 _rsrcLength )
+ : rsrcOffset(_rsrcOffset), rsrcLength(_rsrcLength) {};
+ };
+ std::vector<OtherRsrcInfo> otherRsrcs;
+
+ void DeleteExistingInfo();
+
+}; // PSIR_FileWriter
+
+#endif // __PSIR_Support_hpp__
diff --git a/source/XMPFiles/FormatSupport/QuickTime_Support.cpp b/source/XMPFiles/FormatSupport/QuickTime_Support.cpp
new file mode 100644
index 0000000..259a9dc
--- /dev/null
+++ b/source/XMPFiles/FormatSupport/QuickTime_Support.cpp
@@ -0,0 +1,79 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "XMP_Environment.h"
+#include "QuickTime_Support.hpp"
+
+#if XMP_MacBuild
+ #include <Movies.h>
+#elif XMP_WinBuild
+ #include "QTML.h"
+ #include "Movies.h"
+#endif
+
+namespace QuickTime_Support
+{
+
+ bool sMainInitOK = false;
+
+ // =============================================================================================
+
+ bool MainInitialize()
+ {
+ OSStatus err = noErr;
+
+ #if XMP_WinBuild
+ err = ::InitializeQTML ( 0 );
+ #endif
+
+ if ( err == noErr ) err = ::EnterMovies();
+ if ( err == noErr ) sMainInitOK = true;
+
+ return sMainInitOK;
+
+ } // MainInitialize
+
+ // =============================================================================================
+
+ void MainTerminate()
+ {
+ ::ExitMovies();
+
+ #if XMP_WinBuild
+ ::TerminateQTML();
+ #endif
+
+ } // MainTerminate
+
+ // =============================================================================================
+
+ bool ThreadInitialize()
+ {
+ OSStatus err = noErr;
+
+ #if XMP_MacBuild
+ err = ::EnterMoviesOnThread ( 0 );
+ #endif
+
+ return (err == noErr);
+
+ } // ThreadInitialize
+
+ // =============================================================================================
+
+ void ThreadTerminate()
+ {
+
+ #if XMP_MacBuild
+ ::ExitMoviesOnThread();
+ #endif
+
+ } // ThreadTerminate
+
+} // namespace QuickTime_Support
diff --git a/source/XMPFiles/FormatSupport/QuickTime_Support.hpp b/source/XMPFiles/FormatSupport/QuickTime_Support.hpp
new file mode 100644
index 0000000..fc265ab
--- /dev/null
+++ b/source/XMPFiles/FormatSupport/QuickTime_Support.hpp
@@ -0,0 +1,27 @@
+#ifndef __QuickTime_Support_hpp__
+#define __QuickTime_Support_hpp__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "XMP_Environment.h" // ! This must be the first include.
+
+namespace QuickTime_Support
+{
+ extern bool sMainInitOK;
+
+ bool MainInitialize(); // For the main thread.
+ void MainTerminate();
+
+ bool ThreadInitialize(); // For background threads.
+ void ThreadTerminate();
+
+} // namespace QuickTime_Support
+
+#endif // __QuickTime_Support_hpp__
diff --git a/source/XMPFiles/FormatSupport/RIFF_Support.cpp b/source/XMPFiles/FormatSupport/RIFF_Support.cpp
new file mode 100644
index 0000000..3b25568
--- /dev/null
+++ b/source/XMPFiles/FormatSupport/RIFF_Support.cpp
@@ -0,0 +1,491 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "RIFF_Support.hpp"
+
+namespace RIFF_Support {
+
+ #define ckidPremierePadding MakeFourCC ('J','U','N','Q')
+ #define formtypeAVIX MakeFourCC ('A', 'V', 'I', 'X')
+
+
+ #ifndef AVIMAXCHUNKSIZE
+ #define AVIMAXCHUNKSIZE ((UInt32) 0x80000000) /* 2 GB */
+ #endif
+
+
+ typedef struct
+ {
+ long id;
+ UInt32 len;
+ } atag;
+
+ // Local function declarations
+ static bool ReadTag ( LFA_FileRef inFileRef, long * outTag, UInt32 * outLength, long * subtype, UInt64 & inOutPosition );
+ static void AddTag ( RiffState & inOutRiffState, long tag, UInt32 len, UInt64 & inOutPosition, long parentID, long parentnum, long subtypeID );
+ static long SubRead ( LFA_FileRef inFileRef, RiffState & inOutRiffState, long parentid, UInt32 parentlen, UInt64 & inOutPosition );
+ static bool ReadChunk ( LFA_FileRef inFileRef, UInt64 & pos, UInt32 len, char * outBuffer );
+
+ #define GetFilePosition(file) LFA_Seek ( file, 0, SEEK_CUR )
+
+ // =============================================================================================
+
+ bool GetMetaData ( LFA_FileRef inFileRef, long tagID, char * outBuffer, unsigned long * outBufferSize )
+ {
+ RiffState riffState;
+
+ long numTags = OpenRIFF ( inFileRef, riffState );
+ if ( numTags == 0 ) return false;
+
+ return GetRIFFChunk ( inFileRef, riffState, tagID, 0, 0, outBuffer, outBufferSize );
+
+ }
+
+ // =============================================================================================
+
+ bool SetMetaData ( LFA_FileRef inFileRef, long riffType, long tagID, const char * inBuffer, unsigned long inBufferSize )
+ {
+ RiffState riffState;
+
+ long numTags = OpenRIFF ( inFileRef, riffState );
+ if ( numTags == 0 ) return false;
+
+ return PutChunk ( inFileRef, riffState, riffType, tagID, inBuffer, inBufferSize );
+
+ }
+
+ // =============================================================================================
+
+ bool MarkChunkAsPadding ( LFA_FileRef inFileRef, RiffState & inOutRiffState, long riffType, long tagID, long subtypeID )
+ {
+ UInt32 len;
+ UInt64 pos;
+ atag tag;
+
+ try {
+
+ bool found = FindChunk ( inOutRiffState, tagID, riffType, subtypeID, NULL, &len, &pos );
+ if ( ! found ) return false;
+
+ if ( subtypeID != 0 ) {
+ pos -= 12;
+ } else {
+ pos -= 8;
+ }
+
+ tag.id = MakeUns32LE ( ckidPremierePadding );
+ LFA_Seek ( inFileRef, pos, SEEK_SET );
+ LFA_Write ( inFileRef, &tag, 4 );
+
+ pos += 8;
+ AddTag ( inOutRiffState, ckidPremierePadding, len, pos, 0, 0, 0 );
+
+ } catch(...) {
+
+ return false; // If a write fails, it throws, so we return false.
+
+ }
+
+ return true;
+ }
+
+ // =============================================================================================
+
+ bool PutChunk ( LFA_FileRef inFileRef, RiffState & inOutRiffState, long riffType, long tagID, const char * inBuffer, UInt32 inBufferSize )
+ {
+ UInt32 len;
+ UInt64 pos;
+ atag tag;
+
+ // Make sure we're writting an even number of bytes. Required by the RIFF specification.
+ XMP_Assert ( (inBufferSize & 1) == 0 );
+
+ try {
+
+ bool found = FindChunk ( inOutRiffState, tagID, 0, 0, NULL, &len, &pos );
+ if ( found ) {
+
+ if ( len == inBufferSize ) {
+ LFA_Seek ( inFileRef, pos, SEEK_SET );
+ LFA_Write ( inFileRef, inBuffer, inBufferSize );
+ return true;
+ }
+
+ pos -= 8;
+ tag.id = MakeUns32LE ( ckidPremierePadding );
+ LFA_Seek ( inFileRef, pos, SEEK_SET );
+ LFA_Write ( inFileRef, &tag, 4 );
+
+ if ( len > inBufferSize ) {
+ pos += 8;
+ AddTag ( inOutRiffState, ckidPremierePadding, len, pos, 0, 0, 0 );
+ }
+
+ }
+
+ } catch ( ... ) {
+
+ // If a write fails, it throws, so we return false
+ return false;
+
+ }
+
+ bool ok = MakeChunk ( inFileRef, inOutRiffState, riffType, (inBufferSize + 8) );
+ if ( ! ok ) return false;
+
+ return WriteChunk ( inFileRef, tagID, inBuffer, inBufferSize );
+
+ }
+
+ // =============================================================================================
+
+ bool RewriteChunk ( LFA_FileRef inFileRef, RiffState & inOutRiffState, long tagID, long parentID, const char * inData )
+ {
+ UInt32 len;
+ UInt64 pos;
+
+ try {
+ if ( FindChunk ( inOutRiffState, tagID, parentID, 0, NULL, &len, &pos ) ) {
+ LFA_Seek ( inFileRef, pos, SEEK_SET );
+ LFA_Write ( inFileRef, inData, len );
+ }
+ } catch ( ... ) {
+ return false;
+ }
+
+ return true;
+
+ }
+
+ // =============================================================================================
+
+ bool MakeChunk ( LFA_FileRef inFileRef, RiffState & inOutRiffState, long riffType, UInt32 len )
+ {
+ long starttag, taglen;
+ UInt32 rifflen, avail;
+ UInt64 pos;
+
+ /* look for top level Premiere padding chunk */
+ starttag = 0;
+ while ( FindChunk ( inOutRiffState, ckidPremierePadding, riffType, 0, &starttag, reinterpret_cast<unsigned long*>(&taglen), &pos ) ) {
+
+ pos -= 8;
+ taglen += 8;
+ long extra = taglen - len;
+ if ( extra < 0 ) continue;
+
+ RiffIterator iter = inOutRiffState.tags.begin();
+ iter += (starttag - 1);
+
+ if ( extra == 0 ) {
+
+ iter->len = 0;
+
+ } else {
+
+ atag pad;
+ UInt64 padpos;
+
+ /* need 8 bytes extra to be able to split it */
+ extra -= 8;
+ if ( extra < 0 ) continue;
+
+ try{
+ padpos = pos + len;
+ LFA_Seek ( inFileRef, padpos, SEEK_SET );
+ pad.id = MakeUns32LE ( ckidPremierePadding );
+ pad.len = MakeUns32LE ( extra );
+ LFA_Write ( inFileRef, &pad, sizeof(pad) );
+ } catch ( ... ) {
+ return false;
+ }
+
+ iter->pos = padpos + 8;
+ iter->len = extra;
+
+ }
+
+ /* seek back to start of original padding chunk */
+ LFA_Seek ( inFileRef, pos, SEEK_SET );
+
+ return true;
+
+ }
+
+ /* can't take padding chunk, so append new chunk to end of file */
+
+ rifflen = inOutRiffState.rifflen + 8;
+ avail = AVIMAXCHUNKSIZE - rifflen;
+
+ LFA_Seek ( inFileRef, 0, SEEK_END );
+ pos = GetFilePosition ( inFileRef );
+
+ if ( avail < len ) {
+
+ /* if needed, create new AVIX chunk */
+ ltag avix;
+
+ avix.id = MakeUns32LE ( FOURCC_RIFF );
+ avix.len = MakeUns32LE ( 4 + len );
+ avix.subid = MakeUns32LE ( formtypeAVIX );
+ LFA_Write(inFileRef, &avix, sizeof(avix));
+
+ pos += 12;
+ AddTag ( inOutRiffState, avix.id, len, pos, 0, 0, 0 );
+
+ } else {
+
+ /* otherwise, rewrite length of last RIFF chunk in file */
+ pos = inOutRiffState.riffpos + 4;
+ rifflen = inOutRiffState.rifflen + len;
+ XMP_Uns32 fileLen = MakeUns32LE ( rifflen );
+ LFA_Seek ( inFileRef, pos, SEEK_SET );
+ LFA_Write ( inFileRef, &fileLen, 4 );
+ inOutRiffState.rifflen = rifflen;
+
+ /* prepare to write data */
+ LFA_Seek ( inFileRef, 0, SEEK_END );
+
+ }
+
+ return true;
+
+ }
+
+ // =============================================================================================
+
+ bool WriteChunk ( LFA_FileRef inFileRef, long tagID, const char * data, UInt32 len )
+ {
+ atag ck;
+ ck.id = MakeUns32LE ( tagID );
+ ck.len = MakeUns32LE ( len );
+
+ try {
+ LFA_Write ( inFileRef, &ck, 8 );
+ LFA_Write ( inFileRef, data, len );
+ } catch ( ... ) {
+ return false;
+ }
+
+ return true;
+ }
+
+ // =============================================================================================
+
+ long OpenRIFF ( LFA_FileRef inFileRef, RiffState & inOutRiffState )
+ {
+ UInt64 pos = 0;
+ long tag, subtype;
+ UInt32 len;
+
+ LFA_Seek ( inFileRef, 0, SEEK_SET );
+
+ // read first tag (always RIFFtype)
+ while ( ReadTag ( inFileRef, &tag, &len, &subtype, pos) ) {
+ if ( tag != FOURCC_RIFF ) break;
+ AddTag ( inOutRiffState, tag, len, pos, 0, 0, subtype );
+ if ( subtype != 0 ) SubRead ( inFileRef, inOutRiffState, subtype, len, pos );
+ }
+
+ return inOutRiffState.tags.size();
+
+ }
+
+ // =============================================================================================
+
+ static bool ReadTag ( LFA_FileRef inFileRef, long * outTag, UInt32 * outLength, long * subtype, UInt64 & inOutPosition )
+ {
+ UInt32 realLength;
+
+ try {
+
+ long bytesRead;
+ bytesRead = LFA_Read ( inFileRef, outTag, 4 );
+ if ( bytesRead == 0 ) return false;
+ *outTag = GetUns32LE ( outTag );
+
+ bytesRead = LFA_Read ( inFileRef, outLength, 4 );
+ if ( bytesRead == 0 ) return false;
+ *outLength = GetUns32LE ( outLength );
+
+ realLength = *outLength;
+ realLength += (realLength & 1); // round up to words
+
+ *subtype = 0;
+
+ if ( (*outTag != FOURCC_LIST) && (*outTag != FOURCC_RIFF) ) {
+
+ inOutPosition = GetFilePosition ( inFileRef );
+ UInt64 tempPos = inOutPosition + realLength;
+ LFA_Seek ( inFileRef, tempPos, SEEK_SET );
+
+ } else {
+
+ bytesRead = LFA_Read ( inFileRef, subtype, 4 );
+ if ( bytesRead == 0 ) return false;
+ *subtype = GetUns32LE ( subtype );
+
+ *outLength -= 4;
+ realLength -= 4;
+
+ // Special case:
+ // Since the 'movi' chunk can contain billions of subchunks, skip over the 'movi' subchunk.
+ //
+ // The 'movi' subtype is added to the list as the TAG.
+ // The subtype is returned empty so nobody will try to parse the subchunks.
+
+ if ( *subtype == listtypeAVIMOVIE ) {
+ inOutPosition = GetFilePosition ( inFileRef );
+ UInt64 tempPos = inOutPosition + realLength;
+ LFA_Seek ( inFileRef, tempPos, SEEK_SET );
+ *outLength += 4;
+ *outTag = *subtype;
+ *subtype = 0;
+ }
+
+ inOutPosition = GetFilePosition ( inFileRef );
+
+ }
+
+ } catch ( ... ) {
+
+ return false;
+
+ }
+
+ return true;
+
+ }
+
+ // =============================================================================================
+
+ static void AddTag ( RiffState & inOutRiffState, long tag, UInt32 len, UInt64 & inOutPosition, long parentID, long parentnum, long subtypeID )
+ {
+ RiffTag newTag;
+
+ newTag.pos = inOutPosition;
+ newTag.tagID = tag;
+ newTag.len = len;
+ newTag.parent = parentnum;
+ newTag.parentID = parentID;
+ newTag.subtypeID = subtypeID;
+
+ inOutRiffState.tags.push_back ( newTag );
+
+ if ( tag == FOURCC_RIFF ) {
+ inOutRiffState.riffpos = inOutPosition - 12;
+ inOutRiffState.rifflen = len + 4;
+ }
+
+ }
+
+ // =============================================================================================
+
+ static long SubRead ( LFA_FileRef inFileRef, RiffState & inOutRiffState, long parentid, UInt32 parentlen, UInt64 & inOutPosition )
+ {
+ long tag;
+ long subtype = 0;
+ long parentnum;
+ UInt32 len, total, childlen;
+ UInt64 oldpos;
+
+ total = 0;
+ parentnum = inOutRiffState.tags.size() - 1;
+
+ while ( parentlen > 0 ) {
+
+ oldpos = inOutPosition;
+ ReadTag ( inFileRef, &tag, &len, &subtype, inOutPosition );
+ AddTag ( inOutRiffState, tag, len, inOutPosition, parentid, parentnum, subtype );
+ len += (len & 1);
+
+ if ( subtype == 0 ) {
+ childlen = 8 + len;
+ } else {
+ childlen = 12 + SubRead ( inFileRef, inOutRiffState, subtype, len, inOutPosition );
+ }
+
+ if ( parentlen < childlen ) parentlen = childlen;
+ parentlen -= childlen;
+ total += childlen;
+
+ }
+
+ return total;
+
+ }
+
+ // =============================================================================================
+
+ bool GetRIFFChunk ( LFA_FileRef inFileRef, RiffState & inOutRiffState, long tagID,
+ long parentID, long subtypeID, char * outBuffer, unsigned long * outBufferSize )
+ {
+ UInt32 len;
+ UInt64 pos;
+
+ bool found = FindChunk ( inOutRiffState, tagID, parentID, subtypeID, 0, &len, &pos );
+ if ( ! found ) return false;
+
+ if ( outBuffer == 0 ) {
+ *outBufferSize = (unsigned long)len;
+ return true; // Found, but not wanted.
+ }
+
+ if ( len > *outBufferSize ) len = *outBufferSize;
+
+ found = ReadChunk ( inFileRef, pos, len, outBuffer );
+ return found;
+
+ }
+
+ // =============================================================================================
+
+ bool FindChunk ( RiffState & inOutRiffState, long tagID, long parentID, long subtypeID,
+ long * startTagIndex, UInt32 * len, UInt64 * pos)
+ {
+ std::vector<RiffTag>::iterator iter = inOutRiffState.tags.begin();
+ std::vector<RiffTag>::iterator endIter = inOutRiffState.tags.end();
+
+ // If we're using the next index, skip the iterator.
+ if ( startTagIndex != 0 ) iter += *startTagIndex;
+
+ for ( ; iter != endIter ; ++iter ) {
+
+ if ( startTagIndex != 0 ) *startTagIndex += 1;
+
+ if ( (parentID!= 0) && (iter->parentID != parentID) ) continue;
+ if ( (tagID != 0) && (iter->tagID != tagID) ) continue;
+ if ( (subtypeID != 0) && (iter->subtypeID != subtypeID) ) continue;
+
+ if ( len != 0 ) *len = iter->len;
+ if ( pos != 0 ) *pos = iter->pos;
+
+ return true;
+
+ }
+
+ return false;
+ }
+
+ // =============================================================================================
+
+ static bool ReadChunk ( LFA_FileRef inFileRef, UInt64 & pos, UInt32 len, char * outBuffer )
+ {
+
+ if ( (inFileRef == 0) || (outBuffer == 0) ) return false;
+
+ LFA_Seek (inFileRef, pos, SEEK_SET );
+ UInt32 bytesRead = LFA_Read ( inFileRef, outBuffer, len );
+ if ( bytesRead != len ) return false;
+
+ return true;
+
+ }
+
+} // namespace RIFF_Support
diff --git a/source/XMPFiles/FormatSupport/RIFF_Support.hpp b/source/XMPFiles/FormatSupport/RIFF_Support.hpp
new file mode 100644
index 0000000..bb63070
--- /dev/null
+++ b/source/XMPFiles/FormatSupport/RIFF_Support.hpp
@@ -0,0 +1,172 @@
+#ifndef __RIFF_Support_hpp__
+#define __RIFF_Support_hpp__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "XMP_Environment.h" // ! This must be the first include.
+
+#include <vector>
+
+#include "XMPFiles_Impl.hpp"
+
+#define MakeFourCC(a,b,c,d) ((long)a | ((long)b << 8) | ((long)c << 16) | ((long)d << 24))
+
+#if XMP_WinBuild
+ #include <vfw.h>
+#else
+ #ifndef FOURCC_RIFF
+ #define FOURCC_RIFF MakeFourCC ('R', 'I', 'F', 'F')
+ #endif
+ #ifndef FOURCC_LIST
+ #define FOURCC_LIST MakeFourCC ('L', 'I', 'S', 'T')
+ #endif
+ #ifndef listtypeAVIMOVIE
+ #define listtypeAVIMOVIE MakeFourCC ('m', 'o', 'v', 'i')
+ #endif
+#endif
+
+namespace RIFF_Support
+{
+ // Some types, if not already defined
+ #ifndef UInt64
+ typedef unsigned long long UInt64;
+ #endif
+ #ifndef UInt32
+ typedef unsigned long UInt32;
+ #endif
+
+ /**
+ ** Obtain the meta-data for the tagID provided.
+ ** Returns true for success
+ */
+ bool GetMetaData ( LFA_FileRef inFileRef, long tagID, char * outBuffer, unsigned long * outBufferSize );
+
+ /**
+ ** Write the meta-data for the tagID provided.
+ ** Returns true for success
+ */
+ bool SetMetaData ( LFA_FileRef inFileRef, long riffType, long tagID, const char * inBuffer, unsigned long inBufferSize );
+
+
+
+ /**
+ ** A class to hold the information
+ ** about a particular chunk.
+ */
+ class RiffTag {
+ public:
+
+ RiffTag() : pos(0), tagID(0), len(0), parent(0), parentID(0), subtypeID(0) {}
+ virtual ~RiffTag() {}
+
+ UInt64 pos; /* file offset of chunk data */
+ long tagID; /* ckid of chunk */
+ UInt32 len; /* length of chunk data */
+ long parent; /* chunk# of parent */
+ long parentID; /* FOURCC of parent */
+ long subtypeID; /* Subtype of the tag (aka LIST ID) */
+
+ };
+
+ typedef std::vector<RiffTag> RiffVector;
+ typedef RiffVector::iterator RiffIterator;
+
+ /**
+ ** A class to hold a table of the parsed
+ ** chunks from a file. Its validity
+ ** expires when new chunks are added.
+ */
+ class RiffState {
+ public:
+
+ RiffState() : riffpos(0), rifflen(0), next(0) {}
+ virtual ~RiffState() {}
+
+ UInt64 riffpos; /* file offset of current RIFF */
+ long rifflen; /* length of RIFF incl. header */
+ long next; /* next one to search */
+ RiffVector tags; /* vector of chunks */
+
+ };
+
+ struct ltag {
+ long id;
+ UInt32 len;
+ long subid;
+ };
+
+ /**
+ ** Read from the RIFF file, and build a table of the chunks
+ ** in the RIFFState class provided.
+ ** Returns the number of chunks found.
+ */
+ long OpenRIFF ( LFA_FileRef inFileRef, RiffState & inOutRiffState );
+
+ /**
+ ** Get a chunk from an existing RIFFState, obtained from
+ ** a call to OpenRIFF.
+ ** If NULL is passed for the outBuffer, the outBufferSize parameter
+ ** will contain the field size if true if returned.
+ **
+ ** Returns true if the chunk is found.
+ */
+ bool GetRIFFChunk ( LFA_FileRef inFileRef, RiffState & inOutRiffState, long tagID, long parentID,
+ long subtypeID, char * outBuffer, unsigned long * outBufferSize );
+
+
+ /**
+ ** The routine finds an existing list and tags it as Padding
+ **
+ ** Returns true if success
+ */
+ bool MarkChunkAsPadding ( LFA_FileRef inFileRef, RiffState & inOutRiffState, long riffType, long tagID, long subtypeID );
+
+
+ /**
+ ** The routine finds an existing location to put the chunk into if
+ ** available, otherwise it creates a new chunk and writes to it.
+ **
+ ** Returns true if success
+ */
+ bool PutChunk ( LFA_FileRef inFileRef, RiffState & inOutRiffState, long riffType, long tagID, const char * inBuffer, UInt32 inBufferSize );
+
+ /**
+ ** Locates the position of a chunk.
+ ** All parameters except the RiffState are optional.
+ **
+ ** Return if found.
+ */
+ bool FindChunk ( RiffState & inOutRiffState, long tagID, long parentID, long subtypeID, long * starttag, UInt32 * len, UInt64 * pos );
+
+ /**
+ ** Low level routine to write a chunk.
+ **
+ ** Returns true if write succeeded.
+ */
+ bool WriteChunk ( LFA_FileRef inFileRef, long tagID, const char * data, UInt32 len );
+
+ /**
+ ** Rewrites data into an existing chunk, not writing the header like WriteChunk
+ **
+ ** Returns true if found and write succeeded.
+ */
+ bool RewriteChunk ( LFA_FileRef inFileRef, RiffState & inOutRiffState, long tagID, long parentID, const char * inData );
+
+ /**
+ ** Attempts to find a location to write a chunk, and if not found, prepares a chunk
+ ** at the end of the file.
+ **
+ ** Returns true if successful.
+ */
+ bool MakeChunk ( LFA_FileRef inFileRef, RiffState & inOutRiffState, long riffType, UInt32 len );
+
+} // namespace RIFF_Support
+
+#endif // __RIFF_Support_hpp__
diff --git a/source/XMPFiles/FormatSupport/ReconcileIPTC.cpp b/source/XMPFiles/FormatSupport/ReconcileIPTC.cpp
new file mode 100644
index 0000000..d04dbea
--- /dev/null
+++ b/source/XMPFiles/FormatSupport/ReconcileIPTC.cpp
@@ -0,0 +1,829 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "XMP_Environment.h" // ! This must be the first include.
+
+#include "Reconcile_Impl.hpp"
+
+#if XMP_WinBuild
+ #pragma warning ( disable : 4800 ) // forcing value to bool 'true' or 'false' (performance warning)
+ #pragma warning ( disable : 4996 ) // '...' was declared deprecated
+#endif
+
+// =================================================================================================
+/// \file ReconcileIPTC.cpp
+/// \brief Utilities to reconcile between XMP and legacy IPTC and PSIR metadata.
+///
+// =================================================================================================
+
+// =================================================================================================
+// NormalizeToCR
+// =============
+
+static inline void NormalizeToCR ( std::string * value )
+{
+ char * strPtr = (char*) value->data();
+ char * strEnd = strPtr + value->size();
+
+ for ( ; strPtr < strEnd; ++strPtr ) {
+ if ( *strPtr == kLF ) *strPtr = kCR;
+ }
+
+} // NormalizeToCR
+
+// =================================================================================================
+// NormalizeToLF
+// =============
+
+static inline void NormalizeToLF ( std::string * value )
+{
+ char * strPtr = (char*) value->data();
+ char * strEnd = strPtr + value->size();
+
+ for ( ; strPtr < strEnd; ++strPtr ) {
+ if ( *strPtr == kCR ) *strPtr = kLF;
+ }
+
+} // NormalizeToLF
+
+// =================================================================================================
+// ComputeIPTCDigest
+// =================
+//
+// Compute a 128 bit (16 byte) MD5 digest of the full IPTC block.
+
+static inline void ComputeIPTCDigest ( IPTC_Manager * iptc, MD5_Digest * digest )
+{
+ MD5_CTX context;
+ void * iptcData;
+ XMP_Uns32 iptcLen;
+
+ iptcLen = iptc->UpdateMemoryDataSets ( &iptcData );
+
+ MD5Init ( &context );
+ MD5Update ( &context, (XMP_Uns8*)iptcData, iptcLen );
+ MD5Final ( *digest, &context );
+
+} // ComputeIPTCDigest;
+
+// =================================================================================================
+// ReconcileUtils::CheckIPTCDigest
+// ===============================
+
+int ReconcileUtils::CheckIPTCDigest ( IPTC_Manager * iptc, const PSIR_Manager & psir )
+{
+ MD5_Digest newDigest;
+ PSIR_Manager::ImgRsrcInfo ir1061;
+
+ ComputeIPTCDigest ( iptc, &newDigest );
+ bool found = psir.GetImgRsrc ( kPSIR_IPTCDigest, &ir1061 );
+
+ if ( ! found ) return kDigestMissing;
+ if ( ir1061.dataLen != 16 ) return kDigestMissing;
+
+ if ( memcmp ( newDigest, ir1061.dataPtr, 16 ) == 0 ) return kDigestMatches;
+ return kDigestDiffers;
+
+} // ReconcileUtils::CheckIPTCDigest
+
+// =================================================================================================
+// ReconcileUtils::SetIPTCDigest
+// ===============================
+
+void ReconcileUtils::SetIPTCDigest ( IPTC_Manager * iptc, PSIR_Manager * psir )
+{
+ MD5_Digest newDigest;
+
+ ComputeIPTCDigest ( iptc, &newDigest );
+ psir->SetImgRsrc ( kPSIR_IPTCDigest, &newDigest, sizeof(newDigest) );
+
+} // ReconcileUtils::SetIPTCDigest
+
+// =================================================================================================
+// =================================================================================================
+
+// =================================================================================================
+// ImportIPTC_Simple
+// =================
+
+static void ImportIPTC_Simple ( const IPTC_Manager & iptc, SXMPMeta * xmp, int digestState,
+ XMP_Uns8 id, const char * xmpNS, const char * xmpProp )
+{
+ if ( digestState == kDigestDiffers ) {
+ xmp->DeleteProperty ( xmpNS, xmpProp );
+ } else {
+ XMP_Assert ( digestState == kDigestMissing );
+ if ( xmp->DoesPropertyExist ( xmpNS, xmpProp ) ) return;
+ }
+
+ std::string utf8Str;
+ size_t count = iptc.GetDataSet_UTF8 ( id, &utf8Str );
+
+ if ( count != 0 ) {
+ NormalizeToLF ( &utf8Str );
+ xmp->SetProperty ( xmpNS, xmpProp, utf8Str.c_str() );
+ }
+
+} // ImportIPTC_Simple
+
+// =================================================================================================
+// ImportIPTC_LangAlt
+// ==================
+
+static void ImportIPTC_LangAlt ( const IPTC_Manager & iptc, SXMPMeta * xmp, int digestState,
+ XMP_Uns8 id, const char * xmpNS, const char * xmpProp )
+{
+ if ( digestState == kDigestDiffers ) {
+ std::string xdItemPath = xmpProp; // Delete just the x-default item, not the whole array.
+ xdItemPath += "[?xml:lang='x-default']";
+ xmp->DeleteProperty ( xmpNS, xdItemPath.c_str() );
+ } else {
+ XMP_Assert ( digestState == kDigestMissing );
+ if ( xmp->DoesPropertyExist ( xmpNS, xmpProp ) ) return; // Check the entire array here.
+ }
+
+ std::string utf8Str;
+
+ size_t count = iptc.GetDataSet_UTF8 ( id, &utf8Str );
+
+ if ( count != 0 ) {
+ NormalizeToLF ( &utf8Str );
+ xmp->SetLocalizedText ( xmpNS, xmpProp, "", "x-default", utf8Str.c_str() );
+ }
+
+} // ImportIPTC_LangAlt
+
+// =================================================================================================
+// ImportIPTC_Array
+// ================
+
+static void ImportIPTC_Array ( const IPTC_Manager & iptc, SXMPMeta * xmp, int digestState,
+ XMP_Uns8 id, const char * xmpNS, const char * xmpProp )
+{
+ if ( digestState == kDigestDiffers ) {
+ xmp->DeleteProperty ( xmpNS, xmpProp );
+ } else {
+ XMP_Assert ( digestState == kDigestMissing );
+ if ( xmp->DoesPropertyExist ( xmpNS, xmpProp ) ) return;
+ }
+
+ std::string utf8Str;
+ size_t count = iptc.GetDataSet ( id, 0 );
+
+ for ( size_t ds = 0; ds < count; ++ds ) {
+ (void) iptc.GetDataSet_UTF8 ( id, &utf8Str, ds );
+ NormalizeToLF ( &utf8Str );
+ xmp->AppendArrayItem ( xmpNS, xmpProp, kXMP_PropArrayIsUnordered, utf8Str.c_str() );
+ }
+
+} // ImportIPTC_Array
+
+// =================================================================================================
+// ImportIPTC_IntellectualGenre
+// ============================
+//
+// Import DataSet 2:04. In the IIM this is a 3 digit number, a colon, and an optional text name.
+// Even though the number is the more formal part, the IPTC4XMP rule is that the name is imported to
+// XMP and the number is dropped. Also, even though IIMv4.1 says that 2:04 is repeatable, the XMP
+// property to which it is mapped is simple.
+
+static void ImportIPTC_IntellectualGenre ( const IPTC_Manager & iptc, SXMPMeta * xmp, int digestState,
+ const char * xmpNS, const char * xmpProp )
+{
+ if ( digestState == kDigestDiffers ) {
+ xmp->DeleteProperty ( xmpNS, xmpProp );
+ } else {
+ XMP_Assert ( digestState == kDigestMissing );
+ if ( xmp->DoesPropertyExist ( xmpNS, xmpProp ) ) return;
+ }
+
+ std::string utf8Str;
+ size_t count = iptc.GetDataSet_UTF8 ( kIPTC_IntellectualGenre, &utf8Str );
+
+ if ( count == 0 ) return;
+ NormalizeToLF ( &utf8Str );
+
+ XMP_StringPtr namePtr = utf8Str.c_str() + 4;
+
+ if ( utf8Str.size() <= 4 ) {
+ // No name in the IIM. Look up the number in our list of known genres.
+ int i;
+ XMP_StringPtr numPtr = utf8Str.c_str();
+ for ( i = 0; kIntellectualGenreMappings[i].refNum != 0; ++i ) {
+ if ( strncmp ( numPtr, kIntellectualGenreMappings[i].refNum, 3 ) == 0 ) break;
+ }
+ if ( kIntellectualGenreMappings[i].refNum == 0 ) return;
+ namePtr = kIntellectualGenreMappings[i].name;
+ }
+
+ xmp->SetProperty ( xmpNS, xmpProp, namePtr );
+
+} // ImportIPTC_IntellectualGenre
+
+// =================================================================================================
+// ImportIPTC_SubjectCode
+// ======================
+//
+// Import all 2:12 DataSets into an unordered array. In the IIM each DataSet is composed of 5 colon
+// separated sections: a provider name, an 8 digit reference number, and 3 optional names for the
+// levels of the reference number hierarchy. The IPTC4XMP mapping rule is that only the reference
+// number is imported to XMP.
+
+static void ImportIPTC_SubjectCode ( const IPTC_Manager & iptc, SXMPMeta * xmp, int digestState,
+ const char * xmpNS, const char * xmpProp )
+{
+ if ( digestState == kDigestDiffers ) {
+ xmp->DeleteProperty ( xmpNS, xmpProp );
+ } else {
+ XMP_Assert ( digestState == kDigestMissing );
+ if ( xmp->DoesPropertyExist ( xmpNS, xmpProp ) ) return;
+ }
+
+ std::string utf8Str;
+ size_t count = iptc.GetDataSet_UTF8 ( kIPTC_SubjectCode, 0 );
+
+ for ( size_t ds = 0; ds < count; ++ds ) {
+
+ (void) iptc.GetDataSet_UTF8 ( kIPTC_SubjectCode, &utf8Str, ds );
+
+ char * refNumPtr = (char*) utf8Str.c_str();
+ for ( ; (*refNumPtr != ':') && (*refNumPtr != 0); ++refNumPtr ) {}
+ if ( *refNumPtr == 0 ) continue; // This DataSet is ill-formed.
+
+ char * refNumEnd = refNumPtr + 1;
+ for ( ; (*refNumEnd != ':') && (*refNumEnd != 0); ++refNumEnd ) {}
+ if ( (refNumEnd - refNumPtr) != 8 ) continue; // This DataSet is ill-formed.
+ *refNumEnd = 0; // Ensure a terminating nul for the reference number portion.
+
+ xmp->AppendArrayItem ( xmpNS, xmpProp, kXMP_PropArrayIsUnordered, refNumPtr );
+
+ }
+
+} // ImportIPTC_SubjectCode
+
+// =================================================================================================
+// ImportIPTC_DateCreated
+// ======================
+//
+// An IPTC (IIM) date is 8 charcters YYYYMMDD. Include the time portion from 2:60 if it is present.
+// The IPTC time is HHMMSSxHHMM, where 'x' is '+' or '-'. Be tolerant of some ill-formed dates and
+// times. Apparently some non-Adobe apps put strings like "YYYY-MM-DD" or "HH:MM:SSxHH:MM" in the
+// IPTC. Allow a missing time zone portion to mean UTC.
+
+static void ImportIPTC_DateCreated ( const IPTC_Manager & iptc, SXMPMeta * xmp, int digestState,
+ const char * xmpNS, const char * xmpProp )
+{
+ if ( digestState == kDigestDiffers ) {
+ xmp->DeleteProperty ( xmpNS, xmpProp );
+ } else {
+ XMP_Assert ( digestState == kDigestMissing );
+ if ( xmp->DoesPropertyExist ( xmpNS, xmpProp ) ) return;
+ }
+
+ // First gather the date portion.
+
+ IPTC_Manager::DataSetInfo dsInfo;
+ size_t count = iptc.GetDataSet ( kIPTC_DateCreated, &dsInfo );
+ if ( count == 0 ) return;
+
+ size_t chPos, digits;
+ XMP_DateTime xmpDate;
+ memset ( &xmpDate, 0, sizeof(xmpDate) );
+
+ for ( chPos = 0, digits = 0; digits < 4; ++digits, ++chPos ) {
+ if ( (chPos >= dsInfo.dataLen) || (dsInfo.dataPtr[chPos] < '0') || (dsInfo.dataPtr[chPos] > '9') ) break;
+ xmpDate.year = (xmpDate.year * 10) + (dsInfo.dataPtr[chPos] - '0');
+ }
+
+ if ( dsInfo.dataPtr[chPos] == '-' ) ++chPos;
+ for ( digits = 0; digits < 2; ++digits, ++chPos ) {
+ if ( (chPos >= dsInfo.dataLen) || (dsInfo.dataPtr[chPos] < '0') || (dsInfo.dataPtr[chPos] > '9') ) break;
+ xmpDate.month = (xmpDate.month * 10) + (dsInfo.dataPtr[chPos] - '0');
+ }
+ if ( xmpDate.month < 1 ) xmpDate.month = 1;
+ if ( xmpDate.month > 12 ) xmpDate.month = 12;
+
+ if ( dsInfo.dataPtr[chPos] == '-' ) ++chPos;
+ for ( digits = 0; digits < 2; ++digits, ++chPos ) {
+ if ( (chPos >= dsInfo.dataLen) || (dsInfo.dataPtr[chPos] < '0') || (dsInfo.dataPtr[chPos] > '9') ) break;
+ xmpDate.day = (xmpDate.day * 10) + (dsInfo.dataPtr[chPos] - '0');
+ }
+ if ( xmpDate.day < 1 ) xmpDate.day = 1;
+ if ( xmpDate.day > 31 ) xmpDate.day = 28; // Close enough.
+
+ if ( chPos != dsInfo.dataLen ) return; // The DataSet is ill-formed.
+
+ // Now add the time portion if present.
+
+ count = iptc.GetDataSet ( kIPTC_TimeCreated, &dsInfo );
+ if ( count != 0 ) {
+
+ for ( chPos = 0, digits = 0; digits < 2; ++digits, ++chPos ) {
+ if ( (chPos >= dsInfo.dataLen) || (dsInfo.dataPtr[chPos] < '0') || (dsInfo.dataPtr[chPos] > '9') ) break;
+ xmpDate.hour = (xmpDate.hour * 10) + (dsInfo.dataPtr[chPos] - '0');
+ }
+ if ( xmpDate.hour < 0 ) xmpDate.hour = 0;
+ if ( xmpDate.hour > 23 ) xmpDate.hour = 23;
+
+ if ( dsInfo.dataPtr[chPos] == ':' ) ++chPos;
+ for ( digits = 0; digits < 2; ++digits, ++chPos ) {
+ if ( (chPos >= dsInfo.dataLen) || (dsInfo.dataPtr[chPos] < '0') || (dsInfo.dataPtr[chPos] > '9') ) break;
+ xmpDate.minute = (xmpDate.minute * 10) + (dsInfo.dataPtr[chPos] - '0');
+ }
+ if ( xmpDate.minute < 0 ) xmpDate.minute = 0;
+ if ( xmpDate.minute > 59 ) xmpDate.minute = 59;
+
+ if ( dsInfo.dataPtr[chPos] == ':' ) ++chPos;
+ for ( digits = 0; digits < 2; ++digits, ++chPos ) {
+ if ( (chPos >= dsInfo.dataLen) || (dsInfo.dataPtr[chPos] < '0') || (dsInfo.dataPtr[chPos] > '9') ) break;
+ xmpDate.second = (xmpDate.second * 10) + (dsInfo.dataPtr[chPos] - '0');
+ }
+ if ( xmpDate.second < 0 ) xmpDate.second = 0;
+ if ( xmpDate.second > 59 ) xmpDate.second = 59;
+
+ if ( dsInfo.dataPtr[chPos] == '+' ) {
+ xmpDate.tzSign = kXMP_TimeEastOfUTC;
+ } else if ( dsInfo.dataPtr[chPos] == '-' ) {
+ xmpDate.tzSign = kXMP_TimeWestOfUTC;
+ } else if ( chPos != dsInfo.dataLen ) {
+ return; // The DataSet is ill-formed.
+ }
+
+ ++chPos; // Move past the time zone sign.
+ for ( chPos = 0, digits = 0; digits < 2; ++digits, ++chPos ) {
+ if ( (chPos >= dsInfo.dataLen) || (dsInfo.dataPtr[chPos] < '0') || (dsInfo.dataPtr[chPos] > '9') ) break;
+ xmpDate.tzHour = (xmpDate.tzHour * 10) + (dsInfo.dataPtr[chPos] - '0');
+ }
+ if ( xmpDate.tzHour < 0 ) xmpDate.tzHour = 0;
+ if ( xmpDate.tzHour > 23 ) xmpDate.tzHour = 23;
+
+ if ( dsInfo.dataPtr[chPos] == ':' ) ++chPos;
+ for ( digits = 0; digits < 2; ++digits, ++chPos ) {
+ if ( (chPos >= dsInfo.dataLen) || (dsInfo.dataPtr[chPos] < '0') || (dsInfo.dataPtr[chPos] > '9') ) break;
+ xmpDate.tzMinute = (xmpDate.tzMinute * 10) + (dsInfo.dataPtr[chPos] - '0');
+ }
+ if ( xmpDate.tzMinute < 0 ) xmpDate.tzMinute = 0;
+ if ( xmpDate.tzMinute > 59 ) xmpDate.tzMinute = 59;
+
+ if ( chPos != dsInfo.dataLen ) return; // The DataSet is ill-formed.
+
+ }
+
+ // Finally, set the XMP property.
+
+ xmp->SetProperty_Date ( xmpNS, xmpProp, xmpDate );
+
+} // ImportIPTC_DateCreated
+
+// =================================================================================================
+// ReconcileUtils::ImportIPTC
+// ==========================
+
+void ReconcileUtils::ImportIPTC ( const IPTC_Manager & iptc, SXMPMeta * xmp, int digestState )
+{
+ if ( digestState == kDigestMatches ) return;
+
+ for ( size_t i = 0; kKnownDataSets[i].id != 255; ++i ) {
+
+ const DataSetCharacteristics & thisDS = kKnownDataSets[i];
+
+ try { // Don't let errors with one stop the others.
+
+ switch ( thisDS.mapForm ) {
+
+ case kIPTC_MapSimple :
+ ImportIPTC_Simple ( iptc, xmp, digestState, thisDS.id, thisDS.xmpNS, thisDS.xmpProp );
+ break;
+
+ case kIPTC_MapLangAlt :
+ ImportIPTC_LangAlt ( iptc, xmp, digestState, thisDS.id, thisDS.xmpNS, thisDS.xmpProp );
+ break;
+
+ case kIPTC_MapArray :
+ ImportIPTC_Array ( iptc, xmp, digestState, thisDS.id, thisDS.xmpNS, thisDS.xmpProp );
+ break;
+
+ case kIPTC_MapSpecial :
+ if ( thisDS.id == kIPTC_IntellectualGenre ) {
+ ImportIPTC_IntellectualGenre ( iptc, xmp, digestState, thisDS.xmpNS, thisDS.xmpProp );
+ } else if ( thisDS.id == kIPTC_SubjectCode ) {
+ ImportIPTC_SubjectCode ( iptc, xmp, digestState, thisDS.xmpNS, thisDS.xmpProp );
+ } else if ( thisDS.id == kIPTC_DateCreated ) {
+ ImportIPTC_DateCreated ( iptc, xmp, digestState, thisDS.xmpNS, thisDS.xmpProp );
+ }
+ break;
+
+ }
+
+ } catch ( ... ) {
+
+ // Do nothing, let other imports proceed.
+ // ? Notify client?
+
+ }
+
+ }
+
+} // ReconcileUtils::ImportIPTC;
+
+// =================================================================================================
+// ReconcileUtils::ImportPSIR
+// ==========================
+//
+// There are only 2 standalone Photoshop image resources for XMP properties:
+// 1034 - Copyright Flag - 0/1 Boolean mapped to xmpRights:Marked.
+// 1035 - Copyright URL - Local OS text mapped to xmpRights:WebStatement.
+
+// ! Photoshop does not use a true/false/missing model for PSIR 1034. Instead it essentially uses a
+// ! yes/don't-know model when importing. A missing or 0 value for PSIR 1034 cause xmpRights:Marked
+// ! to be deleted.
+
+// **** What about 1008 and 1020?
+
+void ReconcileUtils::ImportPSIR ( const PSIR_Manager & psir, SXMPMeta * xmp, int digestState )
+{
+ PSIR_Manager::ImgRsrcInfo rsrcInfo;
+ bool import;
+
+ if ( digestState == kDigestMatches ) return;
+
+ if ( digestState == kDigestDiffers ) {
+ // Delete the mapped XMP. This forces replacement and catches legacy deletions.
+ xmp->DeleteProperty ( kXMP_NS_XMP_Rights, "Marked" );
+ xmp->DeleteProperty ( kXMP_NS_XMP_Rights, "WebStatement" );
+ }
+
+ try { // Don't let errors with one stop the others.
+ import = psir.GetImgRsrc ( kPSIR_CopyrightFlag, &rsrcInfo );
+ if ( import ) import = (! xmp->DoesPropertyExist ( kXMP_NS_XMP_Rights, "Marked" ));
+ if ( import && (rsrcInfo.dataLen == 1) && (*((XMP_Uns8*)rsrcInfo.dataPtr) != 0) ) {
+ xmp->SetProperty_Bool ( kXMP_NS_XMP_Rights, "Marked", true );
+ }
+ } catch ( ... ) {
+ // Do nothing, let other imports proceed.
+ // ? Notify client?
+ }
+
+ try { // Don't let errors with one stop the others.
+ import = psir.GetImgRsrc ( kPSIR_CopyrightURL, &rsrcInfo );
+ if ( import ) import = (! xmp->DoesPropertyExist ( kXMP_NS_XMP_Rights, "WebStatement" ));
+ if ( import ) {
+ std::string utf8;
+ ReconcileUtils::LocalToUTF8 ( rsrcInfo.dataPtr, rsrcInfo.dataLen, &utf8 );
+ xmp->SetProperty ( kXMP_NS_XMP_Rights, "WebStatement", utf8.c_str() );
+ }
+ } catch ( ... ) {
+ // Do nothing, let other imports proceed.
+ // ? Notify client?
+ }
+
+} // ReconcileUtils::ImportPSIR;
+
+// =================================================================================================
+// =================================================================================================
+
+// =================================================================================================
+// ExportIPTC_Simple
+// =================
+
+static void ExportIPTC_Simple ( SXMPMeta * xmp, IPTC_Manager * iptc,
+ const char * xmpNS, const char * xmpProp, XMP_Uns8 id )
+{
+ std::string value;
+ XMP_OptionBits xmpFlags;
+
+ bool found = xmp->GetProperty ( xmpNS, xmpProp, &value, &xmpFlags );
+ if ( ! found ) {
+ iptc->DeleteDataSet ( id );
+ return;
+ }
+
+ if ( ! XMP_PropIsSimple ( xmpFlags ) ) return; // ? Complain? Delete the DataSet?
+
+ NormalizeToCR ( &value );
+
+ size_t iptcCount = iptc->GetDataSet ( id, 0 );
+ if ( iptcCount > 1 ) iptc->DeleteDataSet ( id );
+
+ iptc->SetDataSet_UTF8 ( id, value.c_str(), value.size(), 0 ); // ! Don't append a 2nd DataSet!
+
+} // ExportIPTC_Simple
+
+// =================================================================================================
+// ExportIPTC_LangAlt
+// ==================
+
+static void ExportIPTC_LangAlt ( SXMPMeta * xmp, IPTC_Manager * iptc,
+ const char * xmpNS, const char * xmpProp, XMP_Uns8 id )
+{
+ std::string value;
+ XMP_OptionBits xmpFlags;
+
+ bool found = xmp->GetProperty ( xmpNS, xmpProp, 0, &xmpFlags );
+ if ( ! found ) {
+ iptc->DeleteDataSet ( id );
+ return;
+ }
+
+ if ( ! XMP_ArrayIsAltText ( xmpFlags ) ) return; // ? Complain? Delete the DataSet?
+
+ found = xmp->GetLocalizedText ( xmpNS, xmpProp, "", "x-default", 0, &value, 0 );
+ if ( ! found ) {
+ iptc->DeleteDataSet ( id );
+ return;
+ }
+
+ NormalizeToCR ( &value );
+
+ size_t iptcCount = iptc->GetDataSet ( id, 0 );
+ if ( iptcCount > 1 ) iptc->DeleteDataSet ( id );
+
+ iptc->SetDataSet_UTF8 ( id, value.c_str(), value.size(), 0 ); // ! Don't append a 2nd DataSet!
+
+} // ExportIPTC_LangAlt
+
+// =================================================================================================
+// ExportIPTC_Array
+// ================
+//
+// Array exporting needs a bit of care to preserve the detection of XMP-only updates. If the current
+// XMP and IPTC array sizes differ, delete the entire IPTC and append all new values. If they match,
+// set the individual values in order - which lets SetDataSet apply its no-change optimization.
+
+static void ExportIPTC_Array ( SXMPMeta * xmp, IPTC_Manager * iptc,
+ const char * xmpNS, const char * xmpProp, XMP_Uns8 id )
+{
+ std::string value;
+ XMP_OptionBits xmpFlags;
+
+ bool found = xmp->GetProperty ( xmpNS, xmpProp, 0, &xmpFlags );
+ if ( ! found ) {
+ iptc->DeleteDataSet ( id );
+ return;
+ }
+
+ if ( ! XMP_PropIsArray ( xmpFlags ) ) return; // ? Complain? Delete the DataSet?
+
+ size_t xmpCount = xmp->CountArrayItems ( xmpNS, xmpProp );
+ size_t iptcCount = iptc->GetDataSet ( id, 0 );
+
+ if ( xmpCount != iptcCount ) iptc->DeleteDataSet ( id );
+
+ for ( size_t ds = 0; ds < xmpCount; ++ds ) { // ! XMP arrays are indexed from 1, IPTC from 0.
+
+ (void) xmp->GetArrayItem ( xmpNS, xmpProp, ds+1, &value, &xmpFlags );
+ if ( ! XMP_PropIsSimple ( xmpFlags ) ) continue; // ? Complain?
+
+ NormalizeToCR ( &value );
+
+ iptc->SetDataSet_UTF8 ( id, value.c_str(), value.size(), ds ); // ! Appends if necessary.
+
+ }
+
+} // ExportIPTC_Array
+
+// =================================================================================================
+// ExportIPTC_IntellectualGenre
+// ============================
+//
+// Export DataSet 2:04. In the IIM this is a 3 digit number, a colon, and a text name. Even though
+// the number is the more formal part, the IPTC4XMP rule is that the name is imported to XMP and the
+// number is dropped. Also, even though IIMv4.1 says that 2:04 is repeatable, the XMP property to
+// which it is mapped is simple. Look up the XMP value in a list of known genres to get the number.
+
+static void ExportIPTC_IntellectualGenre ( SXMPMeta * xmp, IPTC_Manager * iptc,
+ const char * xmpNS, const char * xmpProp )
+{
+ std::string xmpValue;
+ XMP_OptionBits xmpFlags;
+
+ bool found = xmp->GetProperty ( xmpNS, xmpProp, &xmpValue, &xmpFlags );
+ if ( ! found ) {
+ iptc->DeleteDataSet ( kIPTC_IntellectualGenre );
+ return;
+ }
+
+ if ( ! XMP_PropIsSimple ( xmpFlags ) ) return; // ? Complain? Delete the DataSet?
+
+ NormalizeToCR ( &xmpValue );
+
+ int i;
+ XMP_StringPtr namePtr = xmpValue.c_str();
+ for ( i = 0; kIntellectualGenreMappings[i].name != 0; ++i ) {
+ if ( strcmp ( namePtr, kIntellectualGenreMappings[i].name ) == 0 ) break;
+ }
+ if ( kIntellectualGenreMappings[i].name == 0 ) return; // Not a known genre, don't export it.
+
+ std::string iimValue = kIntellectualGenreMappings[i].refNum;
+ iimValue += ':';
+ iimValue += xmpValue;
+
+ size_t iptcCount = iptc->GetDataSet ( kIPTC_IntellectualGenre, 0 );
+ if ( iptcCount > 1 ) iptc->DeleteDataSet ( kIPTC_IntellectualGenre );
+
+ iptc->SetDataSet_UTF8 ( kIPTC_IntellectualGenre, iimValue.c_str(), iimValue.size(), 0 ); // ! Don't append a 2nd DataSet!
+
+} // ExportIPTC_IntellectualGenre
+
+// =================================================================================================
+// ExportIPTC_SubjectCode
+// ======================
+//
+// Export 2:12 DataSets from an unordered array. In the IIM each DataSet is composed of 5 colon
+// separated sections: a provider name, an 8 digit reference number, and 3 optional names for the
+// levels of the reference number hierarchy. The IPTC4XMP mapping rule is that only the reference
+// number is imported to XMP. We export with a fixed provider of "IPTC" and no optional names.
+
+static void ExportIPTC_SubjectCode ( SXMPMeta * xmp, IPTC_Manager * iptc,
+ const char * xmpNS, const char * xmpProp )
+{
+ std::string xmpValue, iimValue;
+ XMP_OptionBits xmpFlags;
+
+ bool found = xmp->GetProperty ( xmpNS, xmpProp, 0, &xmpFlags );
+ if ( ! found ) {
+ iptc->DeleteDataSet ( kIPTC_SubjectCode );
+ return;
+ }
+
+ if ( ! XMP_PropIsArray ( xmpFlags ) ) return; // ? Complain? Delete the DataSet?
+
+ size_t xmpCount = xmp->CountArrayItems ( xmpNS, xmpProp );
+ size_t iptcCount = iptc->GetDataSet ( kIPTC_SubjectCode, 0 );
+
+ if ( xmpCount != iptcCount ) iptc->DeleteDataSet ( kIPTC_SubjectCode );
+
+ for ( size_t ds = 0; ds < xmpCount; ++ds ) { // ! XMP arrays are indexed from 1, IPTC from 0.
+
+ (void) xmp->GetArrayItem ( xmpNS, xmpProp, ds+1, &xmpValue, &xmpFlags );
+ if ( ! XMP_PropIsSimple ( xmpFlags ) ) continue; // ? Complain?
+ if ( xmpValue.size() != 8 ) continue; // ? Complain?
+
+ iimValue = "IPTC:";
+ iimValue += xmpValue;
+ iimValue += ":::"; // Add the separating colons for the empty name portions.
+
+ iptc->SetDataSet_UTF8 ( kIPTC_SubjectCode, iimValue.c_str(), iimValue.size(), ds ); // ! Appends if necessary.
+
+ }
+
+} // ExportIPTC_SubjectCode
+
+// =================================================================================================
+// ExportIPTC_DateCreated
+// ======================
+//
+// The IPTC date and time are "YYYYMMDD" and "HHMMSSxHHMM" where 'x' is '+' or '-'. Export the IPTC
+// time only if already present, or if the XMP has a time portion.
+
+static void ExportIPTC_DateCreated ( SXMPMeta * xmp, IPTC_Manager * iptc,
+ const char * xmpNS, const char * xmpProp )
+{
+ std::string xmpStr;
+ XMP_DateTime xmpValue;
+ XMP_OptionBits xmpFlags;
+
+ bool xmpHasTime = false;
+
+ bool found = xmp->GetProperty ( xmpNS, xmpProp, &xmpStr, &xmpFlags );
+ if ( found ) {
+ SXMPUtils::ConvertToDate ( xmpStr.c_str(), &xmpValue );
+ if ( xmpStr.size() > 10 ) xmpHasTime = true; // Date-only values are up to "YYYY-MM-DD".
+ } else {
+ iptc->DeleteDataSet ( kIPTC_DateCreated );
+ iptc->DeleteDataSet ( kIPTC_TimeCreated );
+ return;
+ }
+
+ char iimValue[16];
+
+ // Set the IIM date portion.
+
+ snprintf ( iimValue, sizeof(iimValue), "%.4d%.2d%.2d", // AUDIT: Use of sizeof(iimValue) is safe.
+ xmpValue.year, xmpValue.month, xmpValue.day );
+ if ( iimValue[8] != 0 ) return; // ? Complain? Delete the DataSet?
+
+ size_t iptcCount = iptc->GetDataSet ( kIPTC_DateCreated, 0 );
+ if ( iptcCount > 1 ) iptc->DeleteDataSet ( kIPTC_DateCreated );
+
+ iptc->SetDataSet_UTF8 ( kIPTC_DateCreated, iimValue, 8, 0 ); // ! Don't append a 2nd DataSet!
+
+ // Set the IIM time portion.
+
+ iptcCount = iptc->GetDataSet ( kIPTC_TimeCreated, 0 );
+
+ if ( (iptcCount > 0) || xmpHasTime ) {
+
+ snprintf ( iimValue, sizeof(iimValue), "%.2d%.2d%.2d%c%.2d%.2d", // AUDIT: Use of sizeof(iimValue) is safe.
+ xmpValue.hour, xmpValue.minute, xmpValue.second,
+ ((xmpValue.tzSign == kXMP_TimeWestOfUTC) ? '-' : '+'), xmpValue.tzHour, xmpValue.tzMinute );
+ if ( iimValue[11] != 0 ) return; // ? Complain? Delete the DataSet?
+
+ if ( iptcCount > 1 ) iptc->DeleteDataSet ( kIPTC_TimeCreated );
+
+ iptc->SetDataSet_UTF8 ( kIPTC_TimeCreated, iimValue, 11, 0 ); // ! Don't append a 2nd DataSet!
+
+ }
+
+} // ExportIPTC_DateCreated
+
+// =================================================================================================
+// ReconcileUtils::ExportIPTC
+// ==========================
+
+void ReconcileUtils::ExportIPTC ( SXMPMeta * xmp, IPTC_Manager * iptc )
+{
+
+ for ( size_t i = 0; kKnownDataSets[i].id != 255; ++i ) {
+
+ try { // Don't let errors with one stop the others.
+
+ const DataSetCharacteristics & thisDS = kKnownDataSets[i];
+
+ switch ( thisDS.mapForm ) {
+
+ case kIPTC_MapSimple :
+ ExportIPTC_Simple ( xmp, iptc, thisDS.xmpNS, thisDS.xmpProp, thisDS.id );
+ break;
+
+ case kIPTC_MapLangAlt :
+ ExportIPTC_LangAlt ( xmp, iptc, thisDS.xmpNS, thisDS.xmpProp, thisDS.id );
+ break;
+
+ case kIPTC_MapArray :
+ ExportIPTC_Array ( xmp, iptc, thisDS.xmpNS, thisDS.xmpProp, thisDS.id );
+ break;
+
+ case kIPTC_MapSpecial :
+ if ( thisDS.id == kIPTC_IntellectualGenre ) {
+ ExportIPTC_IntellectualGenre ( xmp, iptc, thisDS.xmpNS, thisDS.xmpProp );
+ } else if ( thisDS.id == kIPTC_SubjectCode ) {
+ ExportIPTC_SubjectCode ( xmp, iptc, thisDS.xmpNS, thisDS.xmpProp );
+ } else if ( thisDS.id == kIPTC_DateCreated ) {
+ ExportIPTC_DateCreated ( xmp, iptc, thisDS.xmpNS, thisDS.xmpProp );
+ }
+ break;
+
+ }
+
+ } catch ( ... ) {
+
+ // Do nothing, let other exports proceed.
+ // ? Notify client?
+
+ }
+
+ }
+
+} // ReconcileUtils::ExportIPTC;
+
+// =================================================================================================
+// ReconcileUtils::ExportPSIR
+// ==========================
+//
+// There are only 2 standalone Photoshop image resources for XMP properties:
+// 1034 - Copyright Flag - 0/1 Boolean mapped to xmpRights:Marked.
+// 1035 - Copyright URL - Local OS text mapped to xmpRights:WebStatement.
+
+// ! Photoshop does not use a true/false/missing model for PSIR 1034. Instead it is always written,
+// ! a missing xmpRights:Marked results in 0 for PSIR 1034.
+
+// ! We don't bother with the CR<->LF normalization for xmpRights:WebStatement. Very little chance
+// ! of having a raw CR character in a URI.
+
+void ReconcileUtils::ExportPSIR ( const SXMPMeta & xmp, PSIR_Manager * psir )
+{
+ bool found;
+ std::string utf8Value;
+
+ try { // Don't let errors with one stop the others.
+ bool copyrighted = false;
+ found = xmp.GetProperty ( kXMP_NS_XMP_Rights, "Marked", &utf8Value, 0 );
+ if ( found ) copyrighted = SXMPUtils::ConvertToBool ( utf8Value );
+ psir->SetImgRsrc ( kPSIR_CopyrightFlag, &copyrighted, 1 );
+ } catch ( ... ) {
+ // Do nothing, let other exports proceed.
+ // ? Notify client?
+ }
+
+ try { // Don't let errors with one stop the others.
+ found = xmp.GetProperty ( kXMP_NS_XMP_Rights, "WebStatement", &utf8Value, 0 );
+ if ( ! found ) {
+ psir->DeleteImgRsrc ( kPSIR_CopyrightURL );
+ } else {
+ std::string localValue;
+ ReconcileUtils::UTF8ToLocal ( utf8Value.c_str(), utf8Value.size(), &localValue );
+ psir->SetImgRsrc ( kPSIR_CopyrightURL, localValue.c_str(), localValue.size() );
+ }
+ } catch ( ... ) {
+ // Do nothing, let other exports proceed.
+ // ? Notify client?
+ }
+
+} // ReconcileUtils::ExportPSIR;
diff --git a/source/XMPFiles/FormatSupport/ReconcileLegacy.cpp b/source/XMPFiles/FormatSupport/ReconcileLegacy.cpp
new file mode 100644
index 0000000..00649c9
--- /dev/null
+++ b/source/XMPFiles/FormatSupport/ReconcileLegacy.cpp
@@ -0,0 +1,191 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "XMP_Environment.h" // ! This must be the first include.
+
+#include "ReconcileLegacy.hpp"
+#include "Reconcile_Impl.hpp"
+
+// =================================================================================================
+/// \file ReconcileLegacy.cpp
+/// \brief Top level parts of utilities to reconcile between XMP and legacy metadata forms such as
+/// TIFF/Exif and IPTC.
+///
+// =================================================================================================
+
+// =================================================================================================
+// ImportJTPtoXMP
+// ==============
+//
+// Import legacy metadata for JPEG, TIFF, and Photoshop files into the XMP. The caller must have
+// already done the file specific processing to select the appropriate sources of the TIFF stream,
+// the Photoshop image resources, and the IPTC.
+
+// ! Note that kLegacyJTP_None does not literally mean no legacy. It means no IPTC-like legacy, i.e.
+// ! stuff that Photoshop pre-7 would reconcile into the IPTC and thus affect the import order below.
+
+void ImportJTPtoXMP ( XMP_FileFormat srcFormat,
+ RecJTP_LegacyPriority lastLegacy,
+ TIFF_Manager * tiff, // ! Need for UserComment and RelatedSoundFile hack.
+ const PSIR_Manager & psir,
+ IPTC_Manager * iptc, // ! Need to call UpdateDataSets.
+ SXMPMeta * xmp,
+ XMP_OptionBits options /* = 0 */ )
+{
+ bool haveXMP = XMP_OptionIsSet ( options, k2XMP_FileHadXMP );
+ bool haveIPTC = XMP_OptionIsSet ( options, k2XMP_FileHadIPTC );
+ bool haveExif = XMP_OptionIsSet ( options, k2XMP_FileHadExif );
+
+ int iptcDigestState = kDigestMatches; // Default is to do no imports.
+ int tiffDigestState = kDigestMatches;
+ int exifDigestState = kDigestMatches;
+
+ if ( ! haveXMP ) {
+
+ // If there is no XMP then what we have differs.
+ if ( haveIPTC) iptcDigestState = kDigestDiffers;
+ if ( haveExif ) tiffDigestState = exifDigestState = kDigestDiffers;
+
+ } else {
+
+ // If there is XMP then check the digests for what we have. No legacy at all means the XMP
+ // is OK, and the CheckXyzDigest routines return true when there is no digest. This matches
+ // Photoshop, and avoids importing when an app adds XMP but does not export to the legacy or
+ // write a digest.
+
+ if ( haveIPTC ) iptcDigestState = ReconcileUtils::CheckIPTCDigest ( iptc, psir );
+ if ( iptcDigestState == kDigestMissing ) {
+ // *** Temporary hack to approximate Photoshop's behavior. Need fully documented policies!
+ tiffDigestState = exifDigestState = kDigestMissing;
+ } else if ( haveExif ) {
+ tiffDigestState = ReconcileUtils::CheckTIFFDigest ( *tiff, *xmp );
+ exifDigestState = ReconcileUtils::CheckExifDigest ( *tiff, *xmp ); // ! Yes, the Exif is in the TIFF stream.
+ }
+
+ }
+
+ if ( lastLegacy > kLegacyJTP_TIFF_IPTC ) {
+ XMP_Throw ( "Invalid JTP legacy priority", kXMPErr_InternalFailure );
+ }
+
+ // A TIFF file with tags 270, 315, or 33432 is currently the only case where the IPTC is less
+ // important than the TIFF/Exif. If there is no IPTC or no TIFF/Exif then the order does not
+ // matter. The order only affects collisions between those 3 TIFF tags and their IPTC counterparts.
+
+ if ( lastLegacy == kLegacyJTP_TIFF_TIFF_Tags ) {
+
+ if ( iptcDigestState != kDigestMatches ) {
+ ReconcileUtils::ImportIPTC ( *iptc, xmp, iptcDigestState );
+ ReconcileUtils::ImportPSIR ( psir, xmp, iptcDigestState );
+ }
+ if ( tiffDigestState != kDigestMatches ) ReconcileUtils::ImportTIFF ( *tiff, xmp, tiffDigestState, srcFormat );
+ if ( exifDigestState != kDigestMatches ) ReconcileUtils::ImportExif ( *tiff, xmp, exifDigestState );
+
+ } else {
+
+ if ( tiffDigestState != kDigestMatches ) ReconcileUtils::ImportTIFF ( *tiff, xmp, tiffDigestState, srcFormat );
+ if ( exifDigestState != kDigestMatches ) ReconcileUtils::ImportExif ( *tiff, xmp, exifDigestState );
+ if ( iptcDigestState != kDigestMatches ) {
+ ReconcileUtils::ImportIPTC ( *iptc, xmp, iptcDigestState );
+ ReconcileUtils::ImportPSIR ( psir, xmp, iptcDigestState );
+ }
+
+ }
+
+ // ! Older versions of Photoshop did not import the UserComment or RelatedSoundFile tags. Note
+ // ! whether the initial XMP has these tags. Don't delete them from the TIFF when saving unless
+ // ! they were in the XMP to begin with. Can't do this in ReconcileUtils::ImportExif, that is
+ // ! only called when the Exif is newer than the XMP.
+
+ tiff->xmpHadUserComment = xmp->DoesPropertyExist ( kXMP_NS_EXIF, "UserComment" );
+ tiff->xmpHadRelatedSoundFile = xmp->DoesPropertyExist ( kXMP_NS_EXIF, "RelatedSoundFile" );
+
+} // ImportJTPtoXMP
+
+// =================================================================================================
+// ExportXMPtoJTP
+// ==============
+
+void ExportXMPtoJTP ( XMP_FileFormat destFormat,
+ SXMPMeta * xmp,
+ TIFF_Manager * tiff,
+ PSIR_Manager * psir,
+ IPTC_Manager * iptc,
+ XMP_OptionBits options /* = 0 */ )
+{
+ XMP_Assert ( xmp != 0 );
+ XMP_Assert ( (destFormat == kXMP_JPEGFile) || (destFormat == kXMP_TIFFFile) || (destFormat == kXMP_PhotoshopFile) );
+
+ // Save the IPTC changed flag specially. SetIPTCDigest will call UpdateMemoryDataSets, which
+ // will clear the IsChanged flag. Also, UpdateMemoryDataSets can be called twice, once for the
+ // general IPTC-in-PSIR case and once for the IPTC-as-TIFF-tag case.
+
+ bool iptcChanged = false;
+
+ // Export the individual metadata items to the legacy forms. The PSIR and IPTC must be done
+ // before the TIFF and Exif. The PSIR and IPTC have side effects that can modify the XMP, and
+ // thus the values written to TIFF and Exif. The side effects are the CR<->LF normalization that
+ // is done to match Photoshop.
+
+ if ( psir != 0) ReconcileUtils::ExportPSIR ( *xmp, psir );
+
+ if ( iptc != 0 ) {
+ ReconcileUtils::ExportIPTC ( xmp, iptc );
+ iptcChanged = iptc->IsChanged(); // ! Do after calling ExportIPTC and before calling SetIPTCDigest.
+ if ( psir != 0 ) ReconcileUtils::SetIPTCDigest ( iptc, psir ); // ! Do always, in case the digest was missing before.
+ }
+
+ if ( tiff != 0 ) {
+ ReconcileUtils::ExportTIFF ( *xmp, tiff );
+ ReconcileUtils::ExportExif ( *xmp, tiff );
+ ReconcileUtils::SetTIFFDigest ( *tiff, xmp ); // ! Do always, in case the digest was missing before.
+ ReconcileUtils::SetExifDigest ( *tiff, xmp ); // ! Do always, in case the digest was missing before.
+ }
+
+ // Now update the collections of metadata, e.g. the IPTC in PSIR 1028 or XMP in TIFF tag 700.
+ // - All of the formats have the IPTC in the PSIR portion.
+ // - JPEG has nothing else special.
+ // - PSD has the XMP and Exif in the PSIR portion.
+ // - TIFF has the XMP, IPTC, and PSIR in primary IFD tags. Yes, a 2nd copy of the IPTC.
+
+ if ( (iptc != 0) && (psir != 0) && iptcChanged ) {
+ void* iptcPtr;
+ XMP_Uns32 iptcLen = iptc->UpdateMemoryDataSets ( &iptcPtr );
+ psir->SetImgRsrc ( kPSIR_IPTC, iptcPtr, iptcLen );
+ }
+
+ if ( destFormat == kXMP_PhotoshopFile ) {
+
+ XMP_Assert ( psir != 0 );
+
+ if ( (tiff != 0) && tiff->IsChanged() ) {
+ void* exifPtr;
+ XMP_Uns32 exifLen = tiff->UpdateMemoryStream ( &exifPtr );
+ psir->SetImgRsrc ( kPSIR_Exif, exifPtr, exifLen );
+ }
+
+ } else if ( destFormat == kXMP_TIFFFile ) {
+
+ XMP_Assert ( tiff != 0 );
+
+ if ( (iptc != 0) && iptcChanged ) {
+ void* iptcPtr;
+ XMP_Uns32 iptcLen = iptc->UpdateMemoryDataSets ( &iptcPtr );
+ tiff->SetTag ( kTIFF_PrimaryIFD, kTIFF_IPTC, kTIFF_UndefinedType, iptcLen, iptcPtr );
+ }
+
+ if ( (psir != 0) && psir->IsChanged() ) {
+ void* psirPtr;
+ XMP_Uns32 psirLen = psir->UpdateMemoryResources ( &psirPtr );
+ tiff->SetTag ( kTIFF_PrimaryIFD, kTIFF_PSIR, kTIFF_UndefinedType, psirLen, psirPtr );
+ }
+
+ }
+
+} // ExportXMPtoJTP
diff --git a/source/XMPFiles/FormatSupport/ReconcileLegacy.hpp b/source/XMPFiles/FormatSupport/ReconcileLegacy.hpp
new file mode 100644
index 0000000..2542309
--- /dev/null
+++ b/source/XMPFiles/FormatSupport/ReconcileLegacy.hpp
@@ -0,0 +1,298 @@
+#ifndef __ReconcileLegacy_hpp__
+#define __ReconcileLegacy_hpp__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "XMP_Environment.h" // ! This must be the first include.
+
+#include "TIFF_Support.hpp"
+#include "PSIR_Support.hpp"
+#include "IPTC_Support.hpp"
+
+// =================================================================================================
+/// \file ReconcileLegacy.hpp
+/// \brief Utilities to reconcile between XMP and legacy metadata forms such as TIFF/Exif and IPTC.
+///
+// =================================================================================================
+
+// ImportJTPtoXMP imports legacy metadata for JPEG, TIFF, and Photoshop files into XMP. The caller
+// must have already done the file specific processing to select the appropriate sources of the TIFF
+// stream, the Photoshop image resources, and the IPTC.
+//
+// The reconciliation logic used here is not identical to that used in Photoshop CS2, but should be
+// similar enough. The details of both approaches are documented in LegacyReconcile.pdf. The logic
+// used by Photoshop is more processor and memory intensive. That overhead is acceptable when
+// opening a file in Photoshop. Client's like Bridge need a lighter weight approach for quick
+// read-only access to the reconciled metadata.
+
+enum { // JTP "last-seen" legacy priorities from Photoshop. Higher numbers are more important.
+ kLegacyJTP_None = 0, // No legacy metadata.
+ kLegacyJTP_JPEG_TIFF_Tags = 1, // A JPEG file with TIFF tags 270, 315, or 33432.
+ kLegacyJTP_PSIR_IPTC = 2, // IPTC from Photoshop image resource 1028.
+ kLegacyJTP_PSIR_OldCaption = 3, // Old caption from Photoshop image resource 1008 or 1020.
+ kLegacyJTP_TIFF_TIFF_Tags = 4, // A TIFF file with TIFF tags 270, 315, or 33432.
+ kLegacyJTP_TIFF_IPTC = 5, // A TIFF file with TIFF tag 33723.
+ kLegacyJTP_Mac_pnot = 6, // KeyW and Desc items from Macintosh pnot 0 resource.
+ kLegacyJTP_ANPA_IPTC = 7 // IPTC from Macintosh ANPA 10000 resource.
+};
+typedef XMP_Uns8 RecJTP_LegacyPriority;
+
+enum { // Bits for the options to ImportJTPtoXMP.
+ k2XMP_FileHadXMP = 0x0001, // Set if the file had an XMP packet.
+ k2XMP_FileHadIPTC = 0x0002, // Set if the file had legacy IPTC.
+ k2XMP_FileHadExif = 0x0004 // Set if the file had legacy Exif.
+};
+
+extern void ImportJTPtoXMP ( XMP_FileFormat srcFormat,
+ RecJTP_LegacyPriority lastLegacy,
+ TIFF_Manager * tiff, // ! Need to modify for UserComment and RelatedSoundFile hack.
+ const PSIR_Manager & psir,
+ IPTC_Manager * iptc, // ! Need to modify for UpdateDataSets.
+ SXMPMeta * xmp,
+ XMP_OptionBits options = 0 );
+
+#if 0 // Activate if we want to support the Mac pnot resource.
+extern void ImportJTPtoXMP ( XMP_FileFormat srcFormat,
+ RecJTP_LegacyPriority lastLegacy,
+ const TIFF_Manager & tiff,
+ const PSIR_Manager & psir,
+ IPTC_Manager * iptc,
+ const void * macKeyW, // The STR# for pnot 0 KeyW item.
+ const std::string & macDesc, // The TEXT for pnot 0 Desc item.
+ SXMPMeta * xmp,
+ XMP_OptionBits options = 0 );
+#endif
+
+// ExportXMPtoJTP exports XMP into legacy metadata for JPEG, TIFF, and Photoshop files.
+
+extern void ExportXMPtoJTP ( XMP_FileFormat destFormat,
+ SXMPMeta * xmp,
+ TIFF_Manager * tiff, // Pass 0 if not wanted.
+ PSIR_Manager * psir, // Pass 0 if not wanted.
+ IPTC_Manager * iptc, // Pass 0 if not wanted.
+ XMP_OptionBits options = 0 );
+
+// =================================================================================================
+// Summary of TIFF/Exif mappings to XMP
+// ====================================
+//
+// The mapping for each tag is driven mainly by the tag ID, and secondarily by the type. E.g. there
+// is no blanket rule that all ASCII tags are mapped to simple strings in XMP. Some, such as
+// SubSecTime or GPSLatitudeRef, are combined with other tags; others, like Flash, are reformated.
+// However, most tags are in fact mapped in an obvious manner based on their type and count.
+//
+// Photoshop practice has been to truncate ASCII tags at the first NUL, not supporting the TIFF
+// specification's notion of multi-part ASCII values.
+//
+// Rational values are mapped to XMP as "num/denom".
+//
+// The tags of UNDEFINED type that are mapped to XMP text are either special cases like ExifVersion
+// or the strings with an explicit encoding like UserComment.
+//
+// Latitude and logitude are mapped to XMP as "DDD,MM,SSk" or "DDD,MM.mmk"; k is N, S, E, or W.
+//
+// Flash struct in XMP separates the Fired, Return, Mode, Function, and RedEyeMode portions of the
+// Exif value. Fired, Function, and RedEyeMode are Boolean; Return and Mode are integers.
+//
+// The OECF/SFR, CFA, and DeviceSettings tables are described in the XMP spec.
+//
+// Instead of iterating through all tags in the various IFDs, it is probably more efficient to have
+// explicit processing for the tags that get special treatment, and a static table listing those
+// that get mapped by type and count. The type and count processing will verify that the actual
+// type and count are as expected, if not the tag is ignored.
+//
+// Here are the primary (0th) IFD tags that get special treatment:
+//
+// 270, 33432 - ASCII mapped to alt-text['x-default']
+// 306 - DateTime master
+// 315 - ASCII mapped to text seq[1]
+//
+// Here are the primary (0th) IFD tags that get mapped by type and count:
+//
+// 256, 257, 258, 259, 262, 271, 272, 274, 277, 282, 283, 284, 296, 301, 305, 318, 319,
+// 529, 530, 531, 532
+//
+// Here are the Exif IFD tags that get special treatment:
+//
+// 34856, 41484 - OECF/SFR table
+// 36864, 40960 - 4 ASCII chars to text
+// 36867, 36868 - DateTime master
+// 37121 - 4 UInt8 to integer seq
+// 37385 - Flash struct
+// 37510 - explicitly encoded text to alt-text['x-default']
+// 41728, 41729 - UInt8 to integer
+// 41730 - CFA table
+// 41995 - DeviceSettings table
+//
+// Here are the Exif IFD tags that get mapped by type and count:
+//
+// 33434, 33437, 34850, 34852, 34855, 37122, 37377, 37378, 37379, 37380, 37381, 37382, 37383, 37384,
+// 37386, 37396, 40961, 40962, 40963, 40964, 41483, 41486, 41487, 41488, 41492, 41493, 41495, 41985,
+// 41986, 41987, 41988, 41989, 41990, 41991, 41992, 41993, 41994, 41996, 42016
+//
+// Here are the GPS IFD tags that get special treatment:
+//
+// 0 - 4 UInt8 to text "n.n.n.n"
+// 2, 4, 20, 22 - Latitude or longitude master
+// 7 - special DateTime master, the time part
+// 27, 28 - explicitly encoded text
+//
+// Here are the GPS IFD tags that get mapped by type and count:
+//
+// 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 23, 24, 25, 26, 30
+// =================================================================================================
+
+// *** What about the Camera Raw tags that MDKit maps:
+// *** 0xFDE8, 0xFDE9, 0xFDEA, 0xFE4C, 0xFE4D, 0xFE4E, 0xFE4F, 0xFE50, 0xFE51, 0xFE52, 0xFE53,
+// *** 0xFE54, 0xFE55, 0xFE56, 0xFE57, 0xFE58
+
+// =================================================================================================
+// Summary of TIFF/Exif mappings from XMP
+// ======================================
+//
+// Only a small number of properties are written back from XMP to TIFF/Exif. Most of the TIFF/Exif
+// tags mapped into XMP are information about the image or capture process, not things that users
+// should be editing. The tags that can be edited and written back to TIFF/Exif are:
+//
+// 270, 274, 282, 283, 296, 305, 306, 315, 33432; 36867, 36868, 37510, 40964
+// =================================================================================================
+
+// =================================================================================================
+// Details of TIFF/Exif mappings
+// =============================
+//
+// General (primary and thumbnail, 0th and 1st) IFD tags
+// tag TIFF type count Name XMP mapping
+//
+// 256 SHORTorLONG 1 ImageWidth integer
+// 257 SHORTorLONG 1 ImageLength integer
+// 258 SHORT 3 BitsPerSample integer seq
+// 259 SHORT 1 Compression integer
+// 262 SHORT 1 PhotometricInterpretation integer
+// 270 ASCII Any ImageDescription text, dc:description['x-default']
+// 271 ASCII Any Make text
+// 272 ASCII Any Model text
+// 274 SHORT 1 Orientation integer
+// 277 SHORT 1 SamplesPerPixel integer
+// 282 RATIONAL 1 XResolution rational
+// 283 RATIONAL 1 YResolution rational
+// 284 SHORT 1 PlanarConfiguration integer
+// 296 SHORT 1 ResolutionUnit integer
+// 301 SHORT 3*256 TransferFunction integer seq
+// 305 ASCII Any Software text, xmp:CreatorTool
+// 306 ASCII 20 DateTime date, master of 37520, xmp:DateTime
+// 315 ASCII Any Artist text, dc:creator[1]
+// 318 RATIONAL 2 WhitePoint rational seq
+// 319 RATIONAL 6 PrimaryChromaticities rational seq
+// 529 RATIONAL 3 YCbCrCoefficients rational seq
+// 530 SHORT 2 YCbCrSubSampling integer seq
+// 531 SHORT 1 YCbCrPositioning integer
+// 532 RATIONAL 6 ReferenceBlackWhite rational seq
+// 33432 ASCII Any Copyright text, dc:rights['x-default']
+//
+// Exif IFD tags
+// tag TIFF type count Name XMP mapping
+//
+// 33434 RATIONAL 1 ExposureTime rational
+// 33437 RATIONAL 1 FNumber rational
+// 34850 SHORT 1 ExposureProgram integer
+// 34852 ASCII Any SpectralSensitivity text
+// 34855 SHORT Any ISOSpeedRatings integer seq
+// 34856 UNDEFINED Any OECF OECF/SFR table
+// 36864 UNDEFINED 4 ExifVersion text, Exif has 4 ASCII chars
+// 36867 ASCII 20 DateTimeOriginal date, master of 37521
+// 36868 ASCII 20 DateTimeDigitized date, master of 37522
+// 37121 UNDEFINED 4 ComponentsConfiguration integer seq, Exif has 4 UInt8
+// 37122 RATIONAL 1 CompressedBitsPerPixel rational
+// 37377 SRATIONAL 1 ShutterSpeedValue rational
+// 37378 RATIONAL 1 ApertureValue rational
+// 37379 SRATIONAL 1 BrightnessValue rational
+// 37380 SRATIONAL 1 ExposureBiasValue rational
+// 37381 RATIONAL 1 MaxApertureValue rational
+// 37382 RATIONAL 1 SubjectDistance rational
+// 37383 SHORT 1 MeteringMode integer
+// 37384 SHORT 1 LightSource integer
+// 37385 SHORT 1 Flash Flash struct
+// 37386 RATIONAL 1 FocalLength rational
+// 37396 SHORT 2..4 SubjectArea integer seq
+// 37510 UNDEFINED Any UserComment text, explicit encoding, exif:UserComment['x-default]
+// 37520 ASCII Any SubSecTime date, with 306
+// 37521 ASCII Any SubSecTimeOriginal date, with 36867
+// 37522 ASCII Any SubSecTimeDigitized date, with 36868
+// 40960 UNDEFINED 4 FlashpixVersion text, Exif has 4 ASCII chars
+// 40961 SHORT 1 ColorSpace integer
+// 40962 SHORTorLONG 1 PixelXDimension integer
+// 40963 SHORTorLONG 1 PixelYDimension integer
+// 40964 ASCII 13 RelatedSoundFile text
+// 41483 RATIONAL 1 FlashEnergy rational
+// 41484 UNDEFINED Any SpatialFrequencyResponse OECF/SFR table
+// 41486 RATIONAL 1 FocalPlaneXResolution rational
+// 41487 RATIONAL 1 FocalPlaneYResolution rational
+// 41488 SHORT 1 FocalPlaneResolutionUnit integer
+// 41492 SHORT 2 SubjectLocation integer seq
+// 41493 RATIONAL 1 ExposureIndex rational
+// 41495 SHORT 1 SensingMethod integer
+// 41728 UNDEFINED 1 FileSource integer, Exif has UInt8
+// 41729 UNDEFINED 1 SceneType integer, Exif has UInt8
+// 41730 UNDEFINED Any CFAPattern CFA table
+// 41985 SHORT 1 CustomRendered integer
+// 41986 SHORT 1 ExposureMode integer
+// 41987 SHORT 1 WhiteBalance integer
+// 41988 RATIONAL 1 DigitalZoomRatio rational
+// 41989 SHORT 1 FocalLengthIn35mmFilm integer
+// 41990 SHORT 1 SceneCaptureType integer
+// 41991 SHORT 1 GainControl integer
+// 41992 SHORT 1 Contrast integer
+// 41993 SHORT 1 Saturation integer
+// 41994 SHORT 1 Sharpness integer
+// 41995 UNDEFINED Any DeviceSettingDescription DeviceSettings table
+// 41996 SHORT 1 SubjectDistanceRange integer
+// 42016 ASCII 33 ImageUniqueID text
+//
+// GPS IFD tags
+// tag TIFF type count Name XMP mapping
+//
+// 0 BYTE 4 GPSVersionID text, "n.n.n.n", Exif has 4 UInt8
+// 1 ASCII 2 GPSLatitudeRef latitude, with 2
+// 2 RATIONAL 3 GPSLatitude latitude, master of 2
+// 3 ASCII 2 GPSLongitudeRef longitude, with 4
+// 4 RATIONAL 3 GPSLongitude longitude, master of 3
+// 5 BYTE 1 GPSAltitudeRef integer
+// 6 RATIONAL 1 GPSAltitude rational
+// 7 RATIONAL 3 GPSTimeStamp date, master of 29
+// 8 ASCII Any GPSSatellites text
+// 9 ASCII 2 GPSStatus text
+// 10 ASCII 2 GPSMeasureMode text
+// 11 RATIONAL 1 GPSDOP rational
+// 12 ASCII 2 GPSSpeedRef text
+// 13 RATIONAL 1 GPSSpeed rational
+// 14 ASCII 2 GPSTrackRef text
+// 15 RATIONAL 1 GPSTrack rational
+// 16 ASCII 2 GPSImgDirectionRef text
+// 17 RATIONAL 1 GPSImgDirection rational
+// 18 ASCII Any GPSMapDatum text
+// 19 ASCII 2 GPSDestLatitudeRef latitude, with 20
+// 20 RATIONAL 3 GPSDestLatitude latitude, master of 19
+// 21 ASCII 2 GPSDestLongitudeRef longitude, with 22
+// 22 RATIONAL 3 GPSDestLongitude logitude, master of 21
+// 23 ASCII 2 GPSDestBearingRef text
+// 24 RATIONAL 1 GPSDestBearing rational
+// 25 ASCII 2 GPSDestDistanceRef text
+// 26 RATIONAL 1 GPSDestDistance rational
+// 27 UNDEFINED Any GPSProcessingMethod text, explicit encoding
+// 28 UNDEFINED Any GPSAreaInformation text, explicit encoding
+// 29 ASCII 11 GPSDateStamp date, with 29
+// 30 SHORT 1 GPSDifferential integer
+//
+// =================================================================================================
+
+// =================================================================================================
+
+#endif // #ifndef __ReconcileLegacy_hpp__
diff --git a/source/XMPFiles/FormatSupport/ReconcileTIFF.cpp b/source/XMPFiles/FormatSupport/ReconcileTIFF.cpp
new file mode 100644
index 0000000..5dbca57
--- /dev/null
+++ b/source/XMPFiles/FormatSupport/ReconcileTIFF.cpp
@@ -0,0 +1,2416 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "XMP_Environment.h" // ! This must be the first include.
+
+#include "Reconcile_Impl.hpp"
+
+#include "UnicodeConversions.hpp"
+
+#include <stdio.h>
+#if XMP_WinBuild
+ #define snprintf _snprintf
+#endif
+
+#if XMP_WinBuild
+ #pragma warning ( disable : 4996 ) // '...' was declared deprecated
+#endif
+
+// =================================================================================================
+/// \file ReconcileTIFF.cpp
+/// \brief Utilities to reconcile between XMP and legacy TIFF/Exif metadata.
+///
+// =================================================================================================
+
+// =================================================================================================
+
+// =================================================================================================
+// Tables of the TIFF/Exif tags that are mapped into XMP. For the most part, the tags have obvious
+// mappings based on their IFD, tag number, type and count. These tables do not list tags that are
+// mapped as subsidiary parts of others, e.g. TIFF SubSecTime or GPS Info GPSDateStamp. Tags that
+// have special mappings are marked by having an empty string for the XMP property name.
+
+// ! These tables have the tags listed in the order of tables 3, 4, 5, and 12 of Exif 2.2, with the
+// ! exception of ImageUniqueID (which is listed at the end of the Exif mappings). This order is
+// ! very important to consistent checking of the legacy status. The NativeDigest properties list
+// ! all possible mapped tags in this order. The NativeDigest strings are compared as a whole, so
+// ! the same tags listed in a different order would compare as different.
+
+// ! The sentinel tag value can't be 0, that is a valid GPS Info tag, 0xFFFF is unused so far.
+
+struct TIFF_MappingToXMP {
+ XMP_Uns16 id;
+ XMP_Uns16 type;
+ XMP_Uns32 count; // Zero means any.
+ const char * name; // The name of the mapped XMP property. The namespace is implicit.
+};
+
+enum { kAnyCount = 0 };
+
+static const TIFF_MappingToXMP sPrimaryIFDMappings[] = {
+ { /* 256 */ kTIFF_ImageWidth, kTIFF_ShortOrLongType, 1, "ImageWidth" },
+ { /* 257 */ kTIFF_ImageLength, kTIFF_ShortOrLongType, 1, "ImageLength" },
+ { /* 258 */ kTIFF_BitsPerSample, kTIFF_ShortType, 3, "BitsPerSample" },
+ { /* 259 */ kTIFF_Compression, kTIFF_ShortType, 1, "Compression" },
+ { /* 262 */ kTIFF_PhotometricInterpretation, kTIFF_ShortType, 1, "PhotometricInterpretation" },
+ { /* 274 */ kTIFF_Orientation, kTIFF_ShortType, 1, "Orientation" },
+ { /* 277 */ kTIFF_SamplesPerPixel, kTIFF_ShortType, 1, "SamplesPerPixel" },
+ { /* 284 */ kTIFF_PlanarConfiguration, kTIFF_ShortType, 1, "PlanarConfiguration" },
+ { /* 530 */ kTIFF_YCbCrSubSampling, kTIFF_ShortType, 2, "YCbCrSubSampling" },
+ { /* 531 */ kTIFF_YCbCrPositioning, kTIFF_ShortType, 1, "YCbCrPositioning" },
+ { /* 282 */ kTIFF_XResolution, kTIFF_RationalType, 1, "XResolution" },
+ { /* 283 */ kTIFF_YResolution, kTIFF_RationalType, 1, "YResolution" },
+ { /* 296 */ kTIFF_ResolutionUnit, kTIFF_ShortType, 1, "ResolutionUnit" },
+ { /* 301 */ kTIFF_TransferFunction, kTIFF_ShortType, 3*256, "TransferFunction" },
+ { /* 318 */ kTIFF_WhitePoint, kTIFF_RationalType, 2, "WhitePoint" },
+ { /* 319 */ kTIFF_PrimaryChromaticities, kTIFF_RationalType, 6, "PrimaryChromaticities" },
+ { /* 529 */ kTIFF_YCbCrCoefficients, kTIFF_RationalType, 3, "YCbCrCoefficients" },
+ { /* 532 */ kTIFF_ReferenceBlackWhite, kTIFF_RationalType, 6, "ReferenceBlackWhite" },
+ { /* 306 */ kTIFF_DateTime, kTIFF_ASCIIType, 20, "" }, // ! Has a special mapping.
+ { /* 270 */ kTIFF_ImageDescription, kTIFF_ASCIIType, kAnyCount, "" }, // ! Has a special mapping.
+ { /* 271 */ kTIFF_Make, kTIFF_ASCIIType, kAnyCount, "Make" },
+ { /* 272 */ kTIFF_Model, kTIFF_ASCIIType, kAnyCount, "Model" },
+ { /* 305 */ kTIFF_Software, kTIFF_ASCIIType, kAnyCount, "Software" }, // Has alias to xmp:CreatorTool.
+ { /* 315 */ kTIFF_Artist, kTIFF_ASCIIType, kAnyCount, "" }, // ! Has a special mapping.
+ { /* 33432 */ kTIFF_Copyright, kTIFF_ASCIIType, kAnyCount, "" },
+ { 0xFFFF, 0, 0, 0 } // ! Must end with sentinel.
+};
+
+static const TIFF_MappingToXMP sExifIFDMappings[] = {
+ { /* 36864 */ kTIFF_ExifVersion, kTIFF_UndefinedType, 4, "" }, // ! Has a special mapping.
+ { /* 40960 */ kTIFF_FlashpixVersion, kTIFF_UndefinedType, 4, "" }, // ! Has a special mapping.
+ { /* 40961 */ kTIFF_ColorSpace, kTIFF_ShortType, 1, "ColorSpace" },
+ { /* 37121 */ kTIFF_ComponentsConfiguration, kTIFF_UndefinedType, 4, "" }, // ! Has a special mapping.
+ { /* 37122 */ kTIFF_CompressedBitsPerPixel, kTIFF_RationalType, 1, "CompressedBitsPerPixel" },
+ { /* 40962 */ kTIFF_PixelXDimension, kTIFF_ShortOrLongType, 1, "PixelXDimension" },
+ { /* 40963 */ kTIFF_PixelYDimension, kTIFF_ShortOrLongType, 1, "PixelYDimension" },
+ { /* 37510 */ kTIFF_UserComment, kTIFF_UndefinedType, kAnyCount, "" }, // ! Has a special mapping.
+ { /* 40964 */ kTIFF_RelatedSoundFile, kTIFF_ASCIIType, 13, "RelatedSoundFile" },
+ { /* 36867 */ kTIFF_DateTimeOriginal, kTIFF_ASCIIType, 20, "" }, // ! Has a special mapping.
+ { /* 36868 */ kTIFF_DateTimeDigitized, kTIFF_ASCIIType, 20, "" }, // ! Has a special mapping.
+ { /* 33434 */ kTIFF_ExposureTime, kTIFF_RationalType, 1, "ExposureTime" },
+ { /* 33437 */ kTIFF_FNumber, kTIFF_RationalType, 1, "FNumber" },
+ { /* 34850 */ kTIFF_ExposureProgram, kTIFF_ShortType, 1, "ExposureProgram" },
+ { /* 34852 */ kTIFF_SpectralSensitivity, kTIFF_ASCIIType, kAnyCount, "SpectralSensitivity" },
+ { /* 34855 */ kTIFF_ISOSpeedRatings, kTIFF_ShortType, kAnyCount, "ISOSpeedRatings" },
+ { /* 34856 */ kTIFF_OECF, kTIFF_UndefinedType, kAnyCount, "" }, // ! Has a special mapping.
+ { /* 37377 */ kTIFF_ShutterSpeedValue, kTIFF_SRationalType, 1, "ShutterSpeedValue" },
+ { /* 37378 */ kTIFF_ApertureValue, kTIFF_RationalType, 1, "ApertureValue" },
+ { /* 37379 */ kTIFF_BrightnessValue, kTIFF_SRationalType, 1, "BrightnessValue" },
+ { /* 37380 */ kTIFF_ExposureBiasValue, kTIFF_SRationalType, 1, "ExposureBiasValue" },
+ { /* 37381 */ kTIFF_MaxApertureValue, kTIFF_RationalType, 1, "MaxApertureValue" },
+ { /* 37382 */ kTIFF_SubjectDistance, kTIFF_RationalType, 1, "SubjectDistance" },
+ { /* 37383 */ kTIFF_MeteringMode, kTIFF_ShortType, 1, "MeteringMode" },
+ { /* 37384 */ kTIFF_LightSource, kTIFF_ShortType, 1, "LightSource" },
+ { /* 37385 */ kTIFF_Flash, kTIFF_ShortType, 1, "" }, // ! Has a special mapping.
+ { /* 37386 */ kTIFF_FocalLength, kTIFF_RationalType, 1, "FocalLength" },
+ { /* 37396 */ kTIFF_SubjectArea, kTIFF_ShortType, kAnyCount, "SubjectArea" }, // ! Actually 2..4.
+ { /* 41483 */ kTIFF_FlashEnergy, kTIFF_RationalType, 1, "FlashEnergy" },
+ { /* 41484 */ kTIFF_SpatialFrequencyResponse, kTIFF_UndefinedType, kAnyCount, "" }, // ! Has a special mapping.
+ { /* 41486 */ kTIFF_FocalPlaneXResolution, kTIFF_RationalType, 1, "FocalPlaneXResolution" },
+ { /* 41487 */ kTIFF_FocalPlaneYResolution, kTIFF_RationalType, 1, "FocalPlaneYResolution" },
+ { /* 41488 */ kTIFF_FocalPlaneResolutionUnit, kTIFF_ShortType, 1, "FocalPlaneResolutionUnit" },
+ { /* 41492 */ kTIFF_SubjectLocation, kTIFF_ShortType, 2, "SubjectLocation" },
+ { /* 41493 */ kTIFF_ExposureIndex, kTIFF_RationalType, 1, "ExposureIndex" },
+ { /* 41495 */ kTIFF_SensingMethod, kTIFF_ShortType, 1, "SensingMethod" },
+ { /* 41728 */ kTIFF_FileSource, kTIFF_UndefinedType, 1, "" }, // ! Has a special mapping.
+ { /* 41729 */ kTIFF_SceneType, kTIFF_UndefinedType, 1, "" }, // ! Has a special mapping.
+ { /* 41730 */ kTIFF_CFAPattern, kTIFF_UndefinedType, kAnyCount, "" }, // ! Has a special mapping.
+ { /* 41985 */ kTIFF_CustomRendered, kTIFF_ShortType, 1, "CustomRendered" },
+ { /* 41986 */ kTIFF_ExposureMode, kTIFF_ShortType, 1, "ExposureMode" },
+ { /* 41987 */ kTIFF_WhiteBalance, kTIFF_ShortType, 1, "WhiteBalance" },
+ { /* 41988 */ kTIFF_DigitalZoomRatio, kTIFF_RationalType, 1, "DigitalZoomRatio" },
+ { /* 41989 */ kTIFF_FocalLengthIn35mmFilm, kTIFF_ShortType, 1, "FocalLengthIn35mmFilm" },
+ { /* 41990 */ kTIFF_SceneCaptureType, kTIFF_ShortType, 1, "SceneCaptureType" },
+ { /* 41991 */ kTIFF_GainControl, kTIFF_ShortType, 1, "GainControl" },
+ { /* 41992 */ kTIFF_Contrast, kTIFF_ShortType, 1, "Contrast" },
+ { /* 41993 */ kTIFF_Saturation, kTIFF_ShortType, 1, "Saturation" },
+ { /* 41994 */ kTIFF_Sharpness, kTIFF_ShortType, 1, "Sharpness" },
+ { /* 41995 */ kTIFF_DeviceSettingDescription, kTIFF_UndefinedType, kAnyCount, "" }, // ! Has a special mapping.
+ { /* 41996 */ kTIFF_SubjectDistanceRange, kTIFF_ShortType, 1, "SubjectDistanceRange" },
+ { /* 42016 */ kTIFF_ImageUniqueID, kTIFF_ASCIIType, 33, "ImageUniqueID" },
+ { 0xFFFF, 0, 0, 0 } // ! Must end with sentinel.
+};
+
+static const TIFF_MappingToXMP sGPSInfoIFDMappings[] = {
+ { /* 0 */ kTIFF_GPSVersionID, kTIFF_ByteType, 4, "" }, // ! Has a special mapping.
+ { /* 2 */ kTIFF_GPSLatitude, kTIFF_RationalType, 3, "" }, // ! Has a special mapping.
+ { /* 4 */ kTIFF_GPSLongitude, kTIFF_RationalType, 3, "" }, // ! Has a special mapping.
+ { /* 5 */ kTIFF_GPSAltitudeRef, kTIFF_ByteType, 1, "GPSAltitudeRef" },
+ { /* 6 */ kTIFF_GPSAltitude, kTIFF_RationalType, 1, "GPSAltitude" },
+ { /* 7 */ kTIFF_GPSTimeStamp, kTIFF_RationalType, 3, "" }, // ! Has a special mapping.
+ { /* 8 */ kTIFF_GPSSatellites, kTIFF_ASCIIType, kAnyCount, "GPSSatellites" },
+ { /* 9 */ kTIFF_GPSStatus, kTIFF_ASCIIType, 2, "GPSStatus" },
+ { /* 10 */ kTIFF_GPSMeasureMode, kTIFF_ASCIIType, 2, "GPSMeasureMode" },
+ { /* 11 */ kTIFF_GPSDOP, kTIFF_RationalType, 1, "GPSDOP" },
+ { /* 12 */ kTIFF_GPSSpeedRef, kTIFF_ASCIIType, 2, "GPSSpeedRef" },
+ { /* 13 */ kTIFF_GPSSpeed, kTIFF_RationalType, 1, "GPSSpeed" },
+ { /* 14 */ kTIFF_GPSTrackRef, kTIFF_ASCIIType, 2, "GPSTrackRef" },
+ { /* 15 */ kTIFF_GPSTrack, kTIFF_RationalType, 1, "GPSTrack" },
+ { /* 16 */ kTIFF_GPSImgDirectionRef, kTIFF_ASCIIType, 2, "GPSImgDirectionRef" },
+ { /* 17 */ kTIFF_GPSImgDirection, kTIFF_RationalType, 1, "GPSImgDirection" },
+ { /* 18 */ kTIFF_GPSMapDatum, kTIFF_ASCIIType, kAnyCount, "GPSMapDatum" },
+ { /* 20 */ kTIFF_GPSDestLatitude, kTIFF_RationalType, 3, "" }, // ! Has a special mapping.
+ { /* 22 */ kTIFF_GPSDestLongitude, kTIFF_RationalType, 3, "" }, // ! Has a special mapping.
+ { /* 23 */ kTIFF_GPSDestBearingRef, kTIFF_ASCIIType, 2, "GPSDestBearingRef" },
+ { /* 24 */ kTIFF_GPSDestBearing, kTIFF_RationalType, 1, "GPSDestBearing" },
+ { /* 25 */ kTIFF_GPSDestDistanceRef, kTIFF_ASCIIType, 2, "GPSDestDistanceRef" },
+ { /* 26 */ kTIFF_GPSDestDistance, kTIFF_RationalType, 1, "GPSDestDistance" },
+ { /* 27 */ kTIFF_GPSProcessingMethod, kTIFF_UndefinedType, kAnyCount, "" }, // ! Has a special mapping.
+ { /* 28 */ kTIFF_GPSAreaInformation, kTIFF_UndefinedType, kAnyCount, "" }, // ! Has a special mapping.
+ { /* 30 */ kTIFF_GPSDifferential, kTIFF_ShortType, 1, "GPSDifferential" },
+ { 0xFFFF, 0, 0, 0 } // ! Must end with sentinel.
+};
+
+// =================================================================================================
+
+static XMP_Uns32 GatherInt ( const char * strPtr, size_t count )
+{
+ XMP_Uns32 value = 0;
+ const char * strEnd = strPtr + count;
+
+ while ( strPtr < strEnd ) {
+ char ch = *strPtr;
+ if ( (ch < '0') || (ch > '9') ) break;
+ value = value*10 + (ch - '0');
+ ++strPtr;
+ }
+
+ return value;
+
+}
+
+// =================================================================================================
+// =================================================================================================
+
+// =================================================================================================
+// ComputeTIFFDigest
+// =================
+//
+// Compute a 128 bit (16 byte) MD5 digest of the mapped TIFF tags and format it as a string like:
+// 256,257,...;A0FCE844924381619820B6F7117C8B83
+// The first portion is a decimal list of the tags from sPrimaryIFDMappings, the last part is the
+// MD5 digest as 32 hex digits using capital A-F.
+
+// ! The order of listing for the tags is crucial for the change comparisons to work!
+
+static void
+ComputeTIFFDigest ( const TIFF_Manager & tiff, std::string * digestStr )
+{
+ MD5_CTX context;
+ MD5_Digest digest;
+ char buffer[40];
+ size_t in, out;
+
+ TIFF_Manager::TagInfo tagInfo;
+
+ MD5Init ( &context );
+ digestStr->clear();
+ digestStr->reserve ( 160 ); // The current length is 134.
+
+ for ( size_t i = 0; sPrimaryIFDMappings[i].id != 0xFFFF; ++i ) {
+ snprintf ( buffer, sizeof(buffer), "%d,", sPrimaryIFDMappings[i].id ); // AUDIT: Use of sizeof(buffer) is safe.
+ digestStr->append ( buffer );
+ bool found = tiff.GetTag ( kTIFF_PrimaryIFD, sPrimaryIFDMappings[i].id, &tagInfo );
+ if ( found ) MD5Update ( &context, (XMP_Uns8*)tagInfo.dataPtr, tagInfo.dataLen );
+ }
+
+ size_t endPos = digestStr->size() - 1;
+ (*digestStr)[endPos] = ';';
+
+ MD5Final ( digest, &context );
+
+ for ( in = 0, out = 0; in < 16; in += 1, out += 2 ) {
+ XMP_Uns8 byte = digest[in];
+ buffer[out] = ReconcileUtils::kHexDigits [ byte >> 4 ];
+ buffer[out+1] = ReconcileUtils::kHexDigits [ byte & 0xF ];
+ }
+ buffer[32] = 0;
+
+ digestStr->append ( buffer );
+
+} // ComputeTIFFDigest;
+
+// =================================================================================================
+// ComputeExifDigest
+// =================
+//
+// Compute a 128 bit (16 byte) MD5 digest of the mapped Exif andf GPS tags and format it as a string like:
+// 36864,40960,...;A0FCE844924381619820B6F7117C8B83
+// The first portion is a decimal list of the tags, the last part is the MD5 digest as 32 hex
+// digits using capital A-F. The listed tags are those from sExifIFDMappings followed by those from
+// sGPSInfoIFDMappings.
+
+// ! The order of listing for the tags is crucial for the change comparisons to work!
+
+static void
+ComputeExifDigest ( const TIFF_Manager & exif, std::string * digestStr )
+{
+ MD5_CTX context;
+ MD5_Digest digest;
+ char buffer[40];
+ size_t in, out;
+
+ TIFF_Manager::TagInfo tagInfo;
+
+ MD5Init ( &context );
+ digestStr->clear();
+ digestStr->reserve ( 440 ); // The current length is 414.
+
+ for ( size_t i = 0; sExifIFDMappings[i].id != 0xFFFF; ++i ) {
+ snprintf ( buffer, sizeof(buffer), "%d,", sExifIFDMappings[i].id ); // AUDIT: Use of sizeof(buffer) is safe.
+ digestStr->append ( buffer );
+ bool found = exif.GetTag ( kTIFF_ExifIFD, sExifIFDMappings[i].id, &tagInfo );
+ if ( found ) MD5Update ( &context, (XMP_Uns8*)tagInfo.dataPtr, tagInfo.dataLen );
+ }
+
+ for ( size_t i = 0; sGPSInfoIFDMappings[i].id != 0xFFFF; ++i ) {
+ snprintf ( buffer, sizeof(buffer), "%d,", sGPSInfoIFDMappings[i].id ); // AUDIT: Use of sizeof(buffer) is safe.
+ digestStr->append ( buffer );
+ bool found = exif.GetTag ( kTIFF_GPSInfoIFD, sGPSInfoIFDMappings[i].id, &tagInfo );
+ if ( found ) MD5Update ( &context, (XMP_Uns8*)tagInfo.dataPtr, tagInfo.dataLen );
+ }
+
+ size_t endPos = digestStr->size() - 1;
+ (*digestStr)[endPos] = ';';
+
+ MD5Final ( digest, &context );
+
+ for ( in = 0, out = 0; in < 16; in += 1, out += 2 ) {
+ XMP_Uns8 byte = digest[in];
+ buffer[out] = ReconcileUtils::kHexDigits [ byte >> 4 ];
+ buffer[out+1] = ReconcileUtils::kHexDigits [ byte & 0xF ];
+ }
+ buffer[32] = 0;
+
+ digestStr->append ( buffer );
+
+} // ComputeExifDigest;
+
+// =================================================================================================
+// ReconcileUtils::CheckTIFFDigest
+// ===============================
+
+int
+ReconcileUtils::CheckTIFFDigest ( const TIFF_Manager & tiff, const SXMPMeta & xmp )
+{
+ std::string newDigest, oldDigest;
+
+ ComputeTIFFDigest ( tiff, &newDigest );
+ bool found = xmp.GetProperty ( kXMP_NS_TIFF, "NativeDigest", &oldDigest, 0 );
+
+ if ( ! found ) return kDigestMissing;
+ if ( newDigest == oldDigest ) return kDigestMatches;
+ return kDigestDiffers;
+
+} // ReconcileUtils::CheckTIFFDigest;
+
+// =================================================================================================
+// ReconcileUtils::CheckExifDigest
+// ===============================
+
+int
+ReconcileUtils::CheckExifDigest ( const TIFF_Manager & tiff, const SXMPMeta & xmp )
+{
+ std::string newDigest, oldDigest;
+
+ ComputeExifDigest ( tiff, &newDigest );
+ bool found = xmp.GetProperty ( kXMP_NS_EXIF, "NativeDigest", &oldDigest, 0 );
+
+ if ( ! found ) return kDigestMissing;
+ if ( newDigest == oldDigest ) return kDigestMatches;
+ return kDigestDiffers;
+
+} // ReconcileUtils::CheckExifDigest;
+
+// =================================================================================================
+// ReconcileUtils::SetTIFFDigest
+// =============================
+
+void
+ReconcileUtils::SetTIFFDigest ( const TIFF_Manager & tiff, SXMPMeta * xmp )
+{
+ std::string newDigest;
+
+ ComputeTIFFDigest ( tiff, &newDigest );
+ xmp->SetProperty ( kXMP_NS_TIFF, "NativeDigest", newDigest.c_str() );
+
+} // ReconcileUtils::SetTIFFDigest;
+
+// =================================================================================================
+// ReconcileUtils::SetExifDigest
+// =============================
+
+void
+ReconcileUtils::SetExifDigest ( const TIFF_Manager & tiff, SXMPMeta * xmp )
+{
+ std::string newDigest;
+
+ ComputeExifDigest ( tiff, &newDigest );
+ xmp->SetProperty ( kXMP_NS_EXIF, "NativeDigest", newDigest.c_str() );
+
+} // ReconcileUtils::SetExifDigest;
+
+// =================================================================================================
+// =================================================================================================
+
+// =================================================================================================
+// ImportSingleTIFF_Short
+// ======================
+
+static void
+ImportSingleTIFF_Short ( const TIFF_Manager::TagInfo & tagInfo, const bool nativeEndian,
+ SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
+{
+ try { // Don't let errors with one stop the others.
+
+ XMP_Uns16 binValue = *((XMP_Uns16*)tagInfo.dataPtr);
+ if ( ! nativeEndian ) binValue = Flip2 ( binValue );
+
+ char strValue[20];
+ snprintf ( strValue, sizeof(strValue), "%hu", binValue ); // AUDIT: Using sizeof(strValue) is safe.
+
+ xmp->SetProperty ( xmpNS, xmpProp, strValue );
+
+ } catch ( ... ) {
+ // Do nothing, let other imports proceed.
+ // ? Notify client?
+ }
+
+} // ImportSingleTIFF_Short
+
+// =================================================================================================
+// ImportSingleTIFF_Long
+// =====================
+
+static void
+ImportSingleTIFF_Long ( const TIFF_Manager::TagInfo & tagInfo, const bool nativeEndian,
+ SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
+{
+ try { // Don't let errors with one stop the others.
+
+ XMP_Uns32 binValue = *((XMP_Uns32*)tagInfo.dataPtr);
+ if ( ! nativeEndian ) binValue = Flip4 ( binValue );
+
+ char strValue[20];
+ snprintf ( strValue, sizeof(strValue), "%lu", binValue ); // AUDIT: Using sizeof(strValue) is safe.
+
+ xmp->SetProperty ( xmpNS, xmpProp, strValue );
+
+ } catch ( ... ) {
+ // Do nothing, let other imports proceed.
+ // ? Notify client?
+ }
+
+} // ImportSingleTIFF_Long
+
+// =================================================================================================
+// ImportSingleTIFF_Rational
+// =========================
+
+static void
+ImportSingleTIFF_Rational ( const TIFF_Manager::TagInfo & tagInfo, const bool nativeEndian,
+ SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
+{
+ try { // Don't let errors with one stop the others.
+
+ XMP_Uns32 * binPtr = (XMP_Uns32*)tagInfo.dataPtr;
+ XMP_Uns32 binNum = binPtr[0];
+ XMP_Uns32 binDenom = binPtr[1];
+ if ( ! nativeEndian ) {
+ binNum = Flip4 ( binNum );
+ binDenom = Flip4 ( binDenom );
+ }
+
+ char strValue[40];
+ snprintf ( strValue, sizeof(strValue), "%lu/%lu", binNum, binDenom ); // AUDIT: Using sizeof(strValue) is safe.
+
+ xmp->SetProperty ( xmpNS, xmpProp, strValue );
+
+ } catch ( ... ) {
+ // Do nothing, let other imports proceed.
+ // ? Notify client?
+ }
+
+} // ImportSingleTIFF_Rational
+
+// =================================================================================================
+// ImportSingleTIFF_SRational
+// ==========================
+
+static void
+ImportSingleTIFF_SRational ( const TIFF_Manager::TagInfo & tagInfo, const bool nativeEndian,
+ SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
+{
+ try { // Don't let errors with one stop the others.
+
+ XMP_Int32 * binPtr = (XMP_Int32*)tagInfo.dataPtr;
+ XMP_Int32 binNum = binPtr[0];
+ XMP_Int32 binDenom = binPtr[1];
+ if ( ! nativeEndian ) {
+ Flip4 ( &binNum );
+ Flip4 ( &binDenom );
+ }
+
+ char strValue[40];
+ snprintf ( strValue, sizeof(strValue), "%ld/%ld", binNum, binDenom ); // AUDIT: Using sizeof(strValue) is safe.
+
+ xmp->SetProperty ( xmpNS, xmpProp, strValue );
+
+ } catch ( ... ) {
+ // Do nothing, let other imports proceed.
+ // ? Notify client?
+ }
+
+} // ImportSingleTIFF_SRational
+
+// =================================================================================================
+// ImportSingleTIFF_ASCII
+// ======================
+
+static void
+ImportSingleTIFF_ASCII ( const TIFF_Manager::TagInfo & tagInfo,
+ SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
+{
+ try { // Don't let errors with one stop the others.
+
+ const char * chPtr = (const char *)tagInfo.dataPtr;
+ const bool hasNul = (chPtr[tagInfo.dataLen-1] == 0);
+ const bool isUTF8 = ReconcileUtils::IsUTF8 ( chPtr, tagInfo.dataLen );
+
+ if ( isUTF8 && hasNul ) {
+ xmp->SetProperty ( xmpNS, xmpProp, chPtr );
+ } else {
+ std::string strValue;
+ if ( isUTF8 ) {
+ strValue.assign ( chPtr, tagInfo.dataLen );
+ } else {
+ ReconcileUtils::LocalToUTF8 ( chPtr, tagInfo.dataLen, &strValue );
+ }
+ xmp->SetProperty ( xmpNS, xmpProp, strValue.c_str() );
+ }
+
+ } catch ( ... ) {
+ // Do nothing, let other imports proceed.
+ // ? Notify client?
+ }
+
+} // ImportSingleTIFF_ASCII
+
+// =================================================================================================
+// ImportSingleTIFF_Byte
+// =====================
+
+static void
+ImportSingleTIFF_Byte ( const TIFF_Manager::TagInfo & tagInfo,
+ SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
+{
+ try { // Don't let errors with one stop the others.
+
+ XMP_Uns8 binValue = *((XMP_Uns8*)tagInfo.dataPtr);
+
+ char strValue[20];
+ snprintf ( strValue, sizeof(strValue), "%hu", binValue ); // AUDIT: Using sizeof(strValue) is safe.
+
+ xmp->SetProperty ( xmpNS, xmpProp, strValue );
+
+ } catch ( ... ) {
+ // Do nothing, let other imports proceed.
+ // ? Notify client?
+ }
+
+} // ImportSingleTIFF_Byte
+
+// =================================================================================================
+// ImportSingleTIFF_SByte
+// ======================
+
+static void
+ImportSingleTIFF_SByte ( const TIFF_Manager::TagInfo & tagInfo,
+ SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
+{
+ try { // Don't let errors with one stop the others.
+
+ XMP_Int8 binValue = *((XMP_Int8*)tagInfo.dataPtr);
+
+ char strValue[20];
+ snprintf ( strValue, sizeof(strValue), "%hd", binValue ); // AUDIT: Using sizeof(strValue) is safe.
+
+ xmp->SetProperty ( xmpNS, xmpProp, strValue );
+
+ } catch ( ... ) {
+ // Do nothing, let other imports proceed.
+ // ? Notify client?
+ }
+
+} // ImportSingleTIFF_SByte
+
+// =================================================================================================
+// ImportSingleTIFF_SShort
+// =======================
+
+static void
+ImportSingleTIFF_SShort ( const TIFF_Manager::TagInfo & tagInfo, const bool nativeEndian,
+ SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
+{
+ try { // Don't let errors with one stop the others.
+
+ XMP_Int16 binValue = *((XMP_Int16*)tagInfo.dataPtr);
+ if ( ! nativeEndian ) Flip2 ( &binValue );
+
+ char strValue[20];
+ snprintf ( strValue, sizeof(strValue), "%hd", binValue ); // AUDIT: Using sizeof(strValue) is safe.
+
+ xmp->SetProperty ( xmpNS, xmpProp, strValue );
+
+ } catch ( ... ) {
+ // Do nothing, let other imports proceed.
+ // ? Notify client?
+ }
+
+} // ImportSingleTIFF_SShort
+
+// =================================================================================================
+// ImportSingleTIFF_SLong
+// ======================
+
+static void
+ImportSingleTIFF_SLong ( const TIFF_Manager::TagInfo & tagInfo, const bool nativeEndian,
+ SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
+{
+ try { // Don't let errors with one stop the others.
+
+ XMP_Int32 binValue = *((XMP_Int32*)tagInfo.dataPtr);
+ if ( ! nativeEndian ) Flip4 ( &binValue );
+
+ char strValue[20];
+ snprintf ( strValue, sizeof(strValue), "%ld", binValue ); // AUDIT: Using sizeof(strValue) is safe.
+
+ xmp->SetProperty ( xmpNS, xmpProp, strValue );
+
+ } catch ( ... ) {
+ // Do nothing, let other imports proceed.
+ // ? Notify client?
+ }
+
+} // ImportSingleTIFF_SLong
+
+// =================================================================================================
+// ImportSingleTIFF_Float
+// ======================
+
+static void
+ImportSingleTIFF_Float ( const TIFF_Manager::TagInfo & tagInfo, const bool nativeEndian,
+ SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
+{
+ try { // Don't let errors with one stop the others.
+
+ float binValue = *((float*)tagInfo.dataPtr);
+ if ( ! nativeEndian ) Flip4 ( &binValue );
+
+ xmp->SetProperty_Float ( xmpNS, xmpProp, binValue );
+
+ } catch ( ... ) {
+ // Do nothing, let other imports proceed.
+ // ? Notify client?
+ }
+
+} // ImportSingleTIFF_Float
+
+// =================================================================================================
+// ImportSingleTIFF_Double
+// =======================
+
+static void
+ImportSingleTIFF_Double ( const TIFF_Manager::TagInfo & tagInfo, const bool nativeEndian,
+ SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
+{
+ try { // Don't let errors with one stop the others.
+
+ double binValue = *((double*)tagInfo.dataPtr);
+ if ( ! nativeEndian ) Flip8 ( &binValue );
+
+ xmp->SetProperty_Float ( xmpNS, xmpProp, binValue ); // ! Yes, SetProperty_Float.
+
+ } catch ( ... ) {
+ // Do nothing, let other imports proceed.
+ // ? Notify client?
+ }
+
+} // ImportSingleTIFF_Double
+
+// =================================================================================================
+// ImportSingleTIFF
+// ================
+
+static void
+ImportSingleTIFF ( const TIFF_Manager::TagInfo & tagInfo, const bool nativeEndian,
+ SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
+{
+
+ // We've got a tag to map to XMP, decide how based on actual type and the expected count. Using
+ // the actual type eliminates a ShortOrLong case. Using the expected count is needed to know
+ // whether to create an XMP array. The actual count for an array could be 1. Put the most
+ // common cases first for better iCache utilization.
+
+ switch ( tagInfo.type ) {
+
+ case kTIFF_ShortType :
+ ImportSingleTIFF_Short ( tagInfo, nativeEndian, xmp, xmpNS, xmpProp );
+ break;
+
+ case kTIFF_LongType :
+ ImportSingleTIFF_Long ( tagInfo, nativeEndian, xmp, xmpNS, xmpProp );
+ break;
+
+ case kTIFF_RationalType :
+ ImportSingleTIFF_Rational ( tagInfo, nativeEndian, xmp, xmpNS, xmpProp );
+ break;
+
+ case kTIFF_SRationalType :
+ ImportSingleTIFF_SRational ( tagInfo, nativeEndian, xmp, xmpNS, xmpProp );
+ break;
+
+ case kTIFF_ASCIIType :
+ ImportSingleTIFF_ASCII ( tagInfo, xmp, xmpNS, xmpProp );
+ break;
+
+ case kTIFF_ByteType :
+ ImportSingleTIFF_Byte ( tagInfo, xmp, xmpNS, xmpProp );
+ break;
+
+ case kTIFF_SByteType :
+ ImportSingleTIFF_SByte ( tagInfo, xmp, xmpNS, xmpProp );
+ break;
+
+ case kTIFF_SShortType :
+ ImportSingleTIFF_SShort ( tagInfo, nativeEndian, xmp, xmpNS, xmpProp );
+ break;
+
+ case kTIFF_SLongType :
+ ImportSingleTIFF_SLong ( tagInfo, nativeEndian, xmp, xmpNS, xmpProp );
+ break;
+
+ case kTIFF_FloatType :
+ ImportSingleTIFF_Float ( tagInfo, nativeEndian, xmp, xmpNS, xmpProp );
+ break;
+
+ case kTIFF_DoubleType :
+ ImportSingleTIFF_Double ( tagInfo, nativeEndian, xmp, xmpNS, xmpProp );
+ break;
+
+ }
+
+} // ImportSingleTIFF
+
+// =================================================================================================
+// =================================================================================================
+
+// =================================================================================================
+// ImportArrayTIFF_Short
+// =====================
+
+static void
+ImportArrayTIFF_Short ( const TIFF_Manager::TagInfo & tagInfo, const bool nativeEndian,
+ SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
+{
+ try { // Don't let errors with one stop the others.
+
+ XMP_Uns16 * binPtr = (XMP_Uns16*)tagInfo.dataPtr;
+
+ for ( size_t i = 0; i < tagInfo.count; ++i, ++binPtr ) {
+
+ XMP_Uns16 binValue = *binPtr;
+ if ( ! nativeEndian ) binValue = Flip2 ( binValue );
+
+ char strValue[20];
+ snprintf ( strValue, sizeof(strValue), "%hu", binValue ); // AUDIT: Using sizeof(strValue) is safe.
+
+ xmp->AppendArrayItem ( xmpNS, xmpProp, kXMP_PropArrayIsOrdered, strValue );
+
+ }
+
+ } catch ( ... ) {
+ // Do nothing, let other imports proceed.
+ // ? Notify client?
+ }
+
+} // ImportArrayTIFF_Short
+
+// =================================================================================================
+// ImportArrayTIFF_Long
+// ====================
+
+static void
+ImportArrayTIFF_Long ( const TIFF_Manager::TagInfo & tagInfo, const bool nativeEndian,
+ SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
+{
+ try { // Don't let errors with one stop the others.
+
+ XMP_Uns32 * binPtr = (XMP_Uns32*)tagInfo.dataPtr;
+
+ for ( size_t i = 0; i < tagInfo.count; ++i, ++binPtr ) {
+
+ XMP_Uns32 binValue = *binPtr;
+ if ( ! nativeEndian ) binValue = Flip4 ( binValue );
+
+ char strValue[20];
+ snprintf ( strValue, sizeof(strValue), "%lu", binValue ); // AUDIT: Using sizeof(strValue) is safe.
+
+ xmp->AppendArrayItem ( xmpNS, xmpProp, kXMP_PropArrayIsOrdered, strValue );
+
+ }
+
+ } catch ( ... ) {
+ // Do nothing, let other imports proceed.
+ // ? Notify client?
+ }
+
+} // ImportArrayTIFF_Long
+
+// =================================================================================================
+// ImportArrayTIFF_Rational
+// ========================
+
+static void
+ImportArrayTIFF_Rational ( const TIFF_Manager::TagInfo & tagInfo, const bool nativeEndian,
+ SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
+{
+ try { // Don't let errors with one stop the others.
+
+ XMP_Uns32 * binPtr = (XMP_Uns32*)tagInfo.dataPtr;
+
+ for ( size_t i = 0; i < tagInfo.count; ++i, binPtr += 2 ) {
+
+ XMP_Uns32 binNum = binPtr[0];
+ XMP_Uns32 binDenom = binPtr[1];
+ if ( ! nativeEndian ) {
+ binNum = Flip4 ( binNum );
+ binDenom = Flip4 ( binDenom );
+ }
+
+ char strValue[40];
+ snprintf ( strValue, sizeof(strValue), "%lu/%lu", binNum, binDenom ); // AUDIT: Using sizeof(strValue) is safe.
+
+ xmp->AppendArrayItem ( xmpNS, xmpProp, kXMP_PropArrayIsOrdered, strValue );
+
+ }
+
+ } catch ( ... ) {
+ // Do nothing, let other imports proceed.
+ // ? Notify client?
+ }
+
+} // ImportArrayTIFF_Rational
+
+// =================================================================================================
+// ImportArrayTIFF_SRational
+// =========================
+
+static void
+ImportArrayTIFF_SRational ( const TIFF_Manager::TagInfo & tagInfo, const bool nativeEndian,
+ SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
+{
+ try { // Don't let errors with one stop the others.
+
+ XMP_Int32 * binPtr = (XMP_Int32*)tagInfo.dataPtr;
+
+ for ( size_t i = 0; i < tagInfo.count; ++i, binPtr += 2 ) {
+
+ XMP_Int32 binNum = binPtr[0];
+ XMP_Int32 binDenom = binPtr[1];
+ if ( ! nativeEndian ) {
+ Flip4 ( &binNum );
+ Flip4 ( &binDenom );
+ }
+
+ char strValue[40];
+ snprintf ( strValue, sizeof(strValue), "%ld/%ld", binNum, binDenom ); // AUDIT: Using sizeof(strValue) is safe.
+
+ xmp->AppendArrayItem ( xmpNS, xmpProp, kXMP_PropArrayIsOrdered, strValue );
+
+ }
+
+ } catch ( ... ) {
+ // Do nothing, let other imports proceed.
+ // ? Notify client?
+ }
+
+} // ImportArrayTIFF_SRational
+
+// =================================================================================================
+// ImportArrayTIFF_ASCII
+// =====================
+
+static void
+ImportArrayTIFF_ASCII ( const TIFF_Manager::TagInfo & tagInfo,
+ SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
+{
+ try { // Don't let errors with one stop the others.
+
+ const char * chPtr = (const char *)tagInfo.dataPtr;
+ const char * chEnd = chPtr + tagInfo.dataLen;
+ const bool hasNul = (chPtr[tagInfo.dataLen-1] == 0);
+ const bool isUTF8 = ReconcileUtils::IsUTF8 ( chPtr, tagInfo.dataLen );
+
+ std::string strValue;
+
+ if ( (! isUTF8) || (! hasNul) ) {
+ if ( isUTF8 ) {
+ strValue.assign ( chPtr, tagInfo.dataLen );
+ } else {
+ ReconcileUtils::LocalToUTF8 ( chPtr, tagInfo.dataLen, &strValue );
+ }
+ chPtr = strValue.c_str();
+ chEnd = chPtr + strValue.size();
+ }
+
+ for ( ; chPtr < chEnd; chPtr += (strlen(chPtr) + 1) ) {
+ xmp->AppendArrayItem ( xmpNS, xmpProp, kXMP_PropArrayIsOrdered, chPtr );
+ }
+
+ } catch ( ... ) {
+ // Do nothing, let other imports proceed.
+ // ? Notify client?
+ }
+
+} // ImportArrayTIFF_ASCII
+
+// =================================================================================================
+// ImportArrayTIFF_Byte
+// ====================
+
+static void
+ImportArrayTIFF_Byte ( const TIFF_Manager::TagInfo & tagInfo,
+ SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
+{
+ try { // Don't let errors with one stop the others.
+
+ XMP_Uns8 * binPtr = (XMP_Uns8*)tagInfo.dataPtr;
+
+ for ( size_t i = 0; i < tagInfo.count; ++i, ++binPtr ) {
+
+ XMP_Uns8 binValue = *binPtr;
+
+ char strValue[20];
+ snprintf ( strValue, sizeof(strValue), "%hu", binValue ); // AUDIT: Using sizeof(strValue) is safe.
+
+ xmp->AppendArrayItem ( xmpNS, xmpProp, kXMP_PropArrayIsOrdered, strValue );
+
+ }
+
+ } catch ( ... ) {
+ // Do nothing, let other imports proceed.
+ // ? Notify client?
+ }
+
+} // ImportArrayTIFF_Byte
+
+// =================================================================================================
+// ImportArrayTIFF_SByte
+// =====================
+
+static void
+ImportArrayTIFF_SByte ( const TIFF_Manager::TagInfo & tagInfo,
+ SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
+{
+ try { // Don't let errors with one stop the others.
+
+ XMP_Int8 * binPtr = (XMP_Int8*)tagInfo.dataPtr;
+
+ for ( size_t i = 0; i < tagInfo.count; ++i, ++binPtr ) {
+
+ XMP_Int8 binValue = *binPtr;
+
+ char strValue[20];
+ snprintf ( strValue, sizeof(strValue), "%hd", binValue ); // AUDIT: Using sizeof(strValue) is safe.
+
+ xmp->AppendArrayItem ( xmpNS, xmpProp, kXMP_PropArrayIsOrdered, strValue );
+
+ }
+
+ } catch ( ... ) {
+ // Do nothing, let other imports proceed.
+ // ? Notify client?
+ }
+
+} // ImportArrayTIFF_SByte
+
+// =================================================================================================
+// ImportArrayTIFF_SShort
+// ======================
+
+static void
+ImportArrayTIFF_SShort ( const TIFF_Manager::TagInfo & tagInfo, const bool nativeEndian,
+ SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
+{
+ try { // Don't let errors with one stop the others.
+
+ XMP_Int16 * binPtr = (XMP_Int16*)tagInfo.dataPtr;
+
+ for ( size_t i = 0; i < tagInfo.count; ++i, ++binPtr ) {
+
+ XMP_Int16 binValue = *binPtr;
+ if ( ! nativeEndian ) Flip2 ( &binValue );
+
+ char strValue[20];
+ snprintf ( strValue, sizeof(strValue), "%hd", binValue ); // AUDIT: Using sizeof(strValue) is safe.
+
+ xmp->AppendArrayItem ( xmpNS, xmpProp, kXMP_PropArrayIsOrdered, strValue );
+
+ }
+
+ } catch ( ... ) {
+ // Do nothing, let other imports proceed.
+ // ? Notify client?
+ }
+
+} // ImportArrayTIFF_SShort
+
+// =================================================================================================
+// ImportArrayTIFF_SLong
+// =====================
+
+static void
+ImportArrayTIFF_SLong ( const TIFF_Manager::TagInfo & tagInfo, const bool nativeEndian,
+ SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
+{
+ try { // Don't let errors with one stop the others.
+
+ XMP_Int32 * binPtr = (XMP_Int32*)tagInfo.dataPtr;
+
+ for ( size_t i = 0; i < tagInfo.count; ++i, ++binPtr ) {
+
+ XMP_Int32 binValue = *binPtr;
+ if ( ! nativeEndian ) Flip4 ( &binValue );
+
+ char strValue[20];
+ snprintf ( strValue, sizeof(strValue), "%ld", binValue ); // AUDIT: Using sizeof(strValue) is safe.
+
+ xmp->AppendArrayItem ( xmpNS, xmpProp, kXMP_PropArrayIsOrdered, strValue );
+
+ }
+
+ } catch ( ... ) {
+ // Do nothing, let other imports proceed.
+ // ? Notify client?
+ }
+
+} // ImportArrayTIFF_SLong
+
+// =================================================================================================
+// ImportArrayTIFF_Float
+// =====================
+
+static void
+ImportArrayTIFF_Float ( const TIFF_Manager::TagInfo & tagInfo, const bool nativeEndian,
+ SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
+{
+ try { // Don't let errors with one stop the others.
+
+ float * binPtr = (float*)tagInfo.dataPtr;
+
+ for ( size_t i = 0; i < tagInfo.count; ++i, ++binPtr ) {
+
+ float binValue = *binPtr;
+ if ( ! nativeEndian ) Flip4 ( &binValue );
+
+ std::string strValue;
+ SXMPUtils::ConvertFromFloat ( binValue, "", &strValue );
+
+ xmp->AppendArrayItem ( xmpNS, xmpProp, kXMP_PropArrayIsOrdered, strValue.c_str() );
+
+ }
+
+ } catch ( ... ) {
+ // Do nothing, let other imports proceed.
+ // ? Notify client?
+ }
+
+} // ImportArrayTIFF_Float
+
+// =================================================================================================
+// ImportArrayTIFF_Double
+// ======================
+
+static void
+ImportArrayTIFF_Double ( const TIFF_Manager::TagInfo & tagInfo, const bool nativeEndian,
+ SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
+{
+ try { // Don't let errors with one stop the others.
+
+ double * binPtr = (double*)tagInfo.dataPtr;
+
+ for ( size_t i = 0; i < tagInfo.count; ++i, ++binPtr ) {
+
+ double binValue = *binPtr;
+ if ( ! nativeEndian ) Flip8 ( &binValue );
+
+ std::string strValue;
+ SXMPUtils::ConvertFromFloat ( binValue, "", &strValue ); // ! Yes, ConvertFromFloat.
+
+ xmp->AppendArrayItem ( xmpNS, xmpProp, kXMP_PropArrayIsOrdered, strValue.c_str() );
+
+ }
+
+ } catch ( ... ) {
+ // Do nothing, let other imports proceed.
+ // ? Notify client?
+ }
+
+} // ImportArrayTIFF_Double
+
+// =================================================================================================
+// ImportArrayTIFF
+// ===============
+
+static void
+ImportArrayTIFF ( const TIFF_Manager::TagInfo & tagInfo, const bool nativeEndian,
+ SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
+{
+
+ // We've got a tag to map to XMP, decide how based on actual type and the expected count. Using
+ // the actual type eliminates a ShortOrLong case. Using the expected count is needed to know
+ // whether to create an XMP array. The actual count for an array could be 1. Put the most
+ // common cases first for better iCache utilization.
+
+ switch ( tagInfo.type ) {
+
+ case kTIFF_ShortType :
+ ImportArrayTIFF_Short ( tagInfo, nativeEndian, xmp, xmpNS, xmpProp );
+ break;
+
+ case kTIFF_LongType :
+ ImportArrayTIFF_Long ( tagInfo, nativeEndian, xmp, xmpNS, xmpProp );
+ break;
+
+ case kTIFF_RationalType :
+ ImportArrayTIFF_Rational ( tagInfo, nativeEndian, xmp, xmpNS, xmpProp );
+ break;
+
+ case kTIFF_SRationalType :
+ ImportArrayTIFF_SRational ( tagInfo, nativeEndian, xmp, xmpNS, xmpProp );
+ break;
+
+ case kTIFF_ASCIIType :
+ ImportArrayTIFF_ASCII ( tagInfo, xmp, xmpNS, xmpProp );
+ break;
+
+ case kTIFF_ByteType :
+ ImportArrayTIFF_Byte ( tagInfo, xmp, xmpNS, xmpProp );
+ break;
+
+ case kTIFF_SByteType :
+ ImportArrayTIFF_SByte ( tagInfo, xmp, xmpNS, xmpProp );
+ break;
+
+ case kTIFF_SShortType :
+ ImportArrayTIFF_SShort ( tagInfo, nativeEndian, xmp, xmpNS, xmpProp );
+ break;
+
+ case kTIFF_SLongType :
+ ImportArrayTIFF_SLong ( tagInfo, nativeEndian, xmp, xmpNS, xmpProp );
+ break;
+
+ case kTIFF_FloatType :
+ ImportArrayTIFF_Float ( tagInfo, nativeEndian, xmp, xmpNS, xmpProp );
+ break;
+
+ case kTIFF_DoubleType :
+ ImportArrayTIFF_Double ( tagInfo, nativeEndian, xmp, xmpNS, xmpProp );
+ break;
+
+ }
+
+} // ImportArrayTIFF
+
+// =================================================================================================
+// ImportTIFF_VerifyImport
+// =======================
+//
+// Decide whether to proceed with the import based on the digest state and presence of the legacy
+// and XMP. Will also delete existing XMP if appropriate.
+
+static bool
+ImportTIFF_VerifyImport ( const TIFF_Manager & tiff, SXMPMeta * xmp, int digestState,
+ XMP_Uns8 tiffIFD, XMP_Uns16 tiffID, const char * xmpNS, const char * xmpProp,
+ TIFF_Manager::TagInfo * tagInfo )
+{
+ bool found = false;
+
+ try { // Don't let errors with one stop the others.
+
+ if ( digestState == kDigestDiffers ) {
+ xmp->DeleteProperty ( xmpNS, xmpProp );
+ } else {
+ XMP_Assert ( digestState == kDigestMissing );
+ if ( xmp->DoesPropertyExist ( xmpNS, xmpProp ) ) return false;
+ }
+
+ found = tiff.GetTag ( tiffIFD, tiffID, tagInfo );
+
+ } catch ( ... ) {
+ found = false;
+ }
+
+ return found;
+
+} // ImportTIFF_VerifyImport
+
+// =================================================================================================
+// ImportTIFF_CheckStandardMapping
+// ===============================
+
+static bool
+ImportTIFF_CheckStandardMapping ( const TIFF_Manager::TagInfo & tagInfo,
+ const TIFF_MappingToXMP & mapInfo )
+{
+ XMP_Assert ( (kTIFF_ByteType <= tagInfo.type) && (tagInfo.type <= kTIFF_LastType) );
+ XMP_Assert ( mapInfo.type <= kTIFF_LastType );
+
+ if ( (tagInfo.type < kTIFF_ByteType) || (tagInfo.type > kTIFF_LastType) ) return false;
+
+ if ( tagInfo.type != mapInfo.type ) {
+ if ( mapInfo.type != kTIFF_ShortOrLongType ) return false;
+ if ( (tagInfo.type != kTIFF_ShortType) && (tagInfo.type != kTIFF_LongType) ) return false;
+ }
+
+ if ( (tagInfo.count != mapInfo.count) && (mapInfo.count != kAnyCount) ) return false;
+
+ return true;
+
+} // ImportTIFF_CheckStandardMapping
+
+// =================================================================================================
+// ImportTIFF_StandardMappings
+// ===========================
+
+static void
+ImportTIFF_StandardMappings ( XMP_Uns8 ifd, const TIFF_Manager & tiff, SXMPMeta * xmp, int digestState )
+{
+ const bool nativeEndian = tiff.IsNativeEndian();
+ TIFF_Manager::TagInfo tagInfo;
+
+ const TIFF_MappingToXMP * mappings = 0;
+ const char * xmpNS = 0;
+
+ if ( ifd == kTIFF_PrimaryIFD ) {
+ mappings = sPrimaryIFDMappings;
+ xmpNS = kXMP_NS_TIFF;
+ } else if ( ifd == kTIFF_ExifIFD ) {
+ mappings = sExifIFDMappings;
+ xmpNS = kXMP_NS_EXIF;
+ } else if ( ifd == kTIFF_GPSInfoIFD ) {
+ mappings = sGPSInfoIFDMappings;
+ xmpNS = kXMP_NS_EXIF; // ! Yes, the GPS Info tags go into the exif: namespace.
+ } else {
+ XMP_Throw ( "Invalid IFD for standard mappings", kXMPErr_InternalFailure );
+ }
+
+ for ( size_t i = 0; mappings[i].id != 0xFFFF; ++i ) {
+
+ try { // Don't let errors with one stop the others.
+
+ const TIFF_MappingToXMP & mapInfo = mappings[i];
+ const bool mapSingle = ((mapInfo.count == 1) || (mapInfo.type == kTIFF_ASCIIType));
+
+ // Skip tags that have special mappings, they are handled individually later. Delete any
+ // existing XMP property before going further. But after the special mapping check since we
+ // don't have the XMP property name for those. This lets legacy deletions propagate and
+ // eliminates any problems with existing XMP property form. Make sure the actual tag has
+ // the expected type and count, ignore it (pretend it is not present) if not.
+
+ if ( mapInfo.name[0] == 0 ) continue; // Skip special mappings.
+
+ bool ok = ImportTIFF_VerifyImport ( tiff, xmp, digestState, ifd, mapInfo.id, xmpNS, mapInfo.name, &tagInfo );
+ if (! ok ) continue;
+
+ XMP_Assert ( tagInfo.type != kTIFF_UndefinedType ); // These have a special mapping.
+ if ( tagInfo.type == kTIFF_UndefinedType ) continue;
+ if ( ! ImportTIFF_CheckStandardMapping ( tagInfo, mapInfo ) ) continue;
+
+ if ( mapSingle ) {
+ ImportSingleTIFF ( tagInfo, nativeEndian, xmp, xmpNS, mapInfo.name );
+ } else {
+ ImportArrayTIFF ( tagInfo, nativeEndian, xmp, xmpNS, mapInfo.name );
+ }
+
+ } catch ( ... ) {
+
+ // Do nothing, let other imports proceed.
+ // ? Notify client?
+
+ }
+
+ }
+
+} // ImportTIFF_StandardMappings
+
+// =================================================================================================
+// =================================================================================================
+
+// =================================================================================================
+// ImportTIFF_Date
+// ===============
+//
+// Convert an Exif 2.2 master date/time tag plus associated fractional seconds to an XMP date/time.
+// The Exif date/time part is a 20 byte ASCII value formatted as "YYYY:MM:DD HH:MM:SS" with a
+// terminating nul. Any of the numeric portions can be blanks if unknown. The fractional seconds
+// are a nul terminated ASCII string with possible space padding. They are literally the fractional
+// part, the digits that would be to the right of the decimal point.
+
+static void
+ImportTIFF_Date ( const TIFF_Manager & tiff, const TIFF_Manager::TagInfo & dateInfo, XMP_Uns16 secID,
+ SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
+{
+ try { // Don't let errors with one stop the others.
+
+ const char * dateStr = (const char *) dateInfo.dataPtr;
+ if ( (dateStr[4] != ':') || (dateStr[7] != ':') ||
+ (dateStr[10] != ' ') || (dateStr[13] != ':') || (dateStr[16] != ':') ) return;
+
+ XMP_DateTime binValue;
+
+ binValue.year = GatherInt ( &dateStr[0], 4 );
+ binValue.month = GatherInt ( &dateStr[5], 2 );
+ binValue.day = GatherInt ( &dateStr[8], 2 );
+ binValue.hour = GatherInt ( &dateStr[11], 2 );
+ binValue.minute = GatherInt ( &dateStr[14], 2 );
+ binValue.second = GatherInt ( &dateStr[17], 2 );
+ binValue.nanoSecond = 0; // Get the fractional seconds later.
+ binValue.tzSign = binValue.tzHour = binValue.tzMinute = 0;
+ SXMPUtils::SetTimeZone ( &binValue ); // Assume local time.
+
+ TIFF_Manager::TagInfo secInfo;
+ bool found = tiff.GetTag ( kTIFF_ExifIFD, secID, &secInfo );
+
+ if ( found && (secInfo.type == kTIFF_ASCIIType) ) {
+ const char * fracPtr = (const char *) secInfo.dataPtr;
+ binValue.nanoSecond = GatherInt ( fracPtr, secInfo.dataLen );
+ size_t digits = 0;
+ for ( ; (('0' <= *fracPtr) && (*fracPtr <= '9')); ++fracPtr ) ++digits;
+ for ( ; digits < 9; ++digits ) binValue.nanoSecond *= 10;
+ }
+
+ xmp->SetProperty_Date ( xmpNS, xmpProp, binValue );
+
+ } catch ( ... ) {
+ // Do nothing, let other imports proceed.
+ // ? Notify client?
+ }
+
+} // ImportTIFF_Date
+
+// =================================================================================================
+// ImportTIFF_LocTextASCII
+// =======================
+
+static void
+ImportTIFF_LocTextASCII ( const TIFF_Manager & tiff, XMP_Uns8 ifd, XMP_Uns16 tagID,
+ SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
+{
+ try { // Don't let errors with one stop the others.
+
+ TIFF_Manager::TagInfo tagInfo;
+
+ bool found = tiff.GetTag ( ifd, tagID, &tagInfo );
+ if ( (! found) || (tagInfo.type != kTIFF_ASCIIType) ) return;
+
+ const char * chPtr = (const char *)tagInfo.dataPtr;
+ const bool hasNul = (chPtr[tagInfo.dataLen-1] == 0);
+ const bool isUTF8 = ReconcileUtils::IsUTF8 ( chPtr, tagInfo.dataLen );
+
+ if ( isUTF8 && hasNul ) {
+ xmp->SetLocalizedText ( xmpNS, xmpProp, "", "x-default", chPtr );
+ } else {
+ std::string strValue;
+ if ( isUTF8 ) {
+ strValue.assign ( chPtr, tagInfo.dataLen );
+ } else {
+ ReconcileUtils::LocalToUTF8 ( chPtr, tagInfo.dataLen, &strValue );
+ }
+ xmp->SetLocalizedText ( xmpNS, xmpProp, "", "x-default", strValue.c_str() );
+ }
+
+ } catch ( ... ) {
+ // Do nothing, let other imports proceed.
+ // ? Notify client?
+ }
+
+} // ImportTIFF_LocTextASCII
+
+// =================================================================================================
+// ImportTIFF_EncodedString
+// ========================
+
+static void
+ImportTIFF_EncodedString ( const TIFF_Manager & tiff, const TIFF_Manager::TagInfo & tagInfo,
+ SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
+{
+ try { // Don't let errors with one stop the others.
+
+ std::string strValue;
+
+ bool ok = tiff.DecodeString ( tagInfo.dataPtr, tagInfo.dataLen, &strValue );
+ if ( ok ) xmp->SetProperty ( xmpNS, xmpProp, strValue.c_str() );
+
+ } catch ( ... ) {
+ // Do nothing, let other imports proceed.
+ // ? Notify client?
+ }
+
+} // ImportTIFF_EncodedString
+
+// =================================================================================================
+// ImportTIFF_Flash
+// ================
+
+static void
+ImportTIFF_Flash ( const TIFF_Manager::TagInfo & tagInfo, bool nativeEndian,
+ SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
+{
+ try { // Don't let errors with one stop the others.
+
+ XMP_Uns16 binValue = *((XMP_Uns16*)tagInfo.dataPtr);
+ if ( ! nativeEndian ) binValue = Flip2 ( binValue );
+
+ bool fired = (bool)(binValue & 1); // Avoid implicit 0/1 conversion.
+ int rtrn = (binValue >> 1) & 3;
+ int mode = (binValue >> 3) & 3;
+ bool function = (bool)((binValue >> 5) & 1);
+ bool redEye = (bool)((binValue >> 6) & 1);
+
+ static const char * sTwoBits[] = { "0", "1", "2", "3" };
+
+ xmp->SetStructField ( kXMP_NS_EXIF, "Flash", kXMP_NS_EXIF, "Fired", (fired ? kXMP_TrueStr : kXMP_FalseStr) );
+ xmp->SetStructField ( kXMP_NS_EXIF, "Flash", kXMP_NS_EXIF, "Return", sTwoBits[rtrn] );
+ xmp->SetStructField ( kXMP_NS_EXIF, "Flash", kXMP_NS_EXIF, "Mode", sTwoBits[mode] );
+ xmp->SetStructField ( kXMP_NS_EXIF, "Flash", kXMP_NS_EXIF, "Function", (function ? kXMP_TrueStr : kXMP_FalseStr) );
+ xmp->SetStructField ( kXMP_NS_EXIF, "Flash", kXMP_NS_EXIF, "RedEyeMode", (redEye ? kXMP_TrueStr : kXMP_FalseStr) );
+
+ } catch ( ... ) {
+ // Do nothing, let other imports proceed.
+ // ? Notify client?
+ }
+
+} // ImportTIFF_Flash
+
+// =================================================================================================
+// ImportTIFF_OECFTable
+// ====================
+//
+// Although the XMP for the OECF and SFR tables is the same, the Exif is not. The OECF table has
+// signed rational values and the SFR table has unsigned.
+
+static void
+ImportTIFF_OECFTable ( const TIFF_Manager::TagInfo & tagInfo, bool nativeEndian,
+ SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
+{
+ try { // Don't let errors with one stop the others.
+
+ const XMP_Uns8 * bytePtr = (XMP_Uns8*)tagInfo.dataPtr;
+ const XMP_Uns8 * byteEnd = bytePtr + tagInfo.dataLen;
+
+ XMP_Uns16 columns = *((XMP_Uns16*)bytePtr);
+ XMP_Uns16 rows = *((XMP_Uns16*)(bytePtr+2));
+ if ( ! nativeEndian ) {
+ columns = Flip2 ( columns );
+ rows = Flip2 ( rows );
+ }
+
+ char buffer[40];
+
+ snprintf ( buffer, sizeof(buffer), "%d", columns ); // AUDIT: Use of sizeof(buffer) is safe.
+ xmp->SetStructField ( xmpNS, xmpProp, kXMP_NS_EXIF, "Columns", buffer );
+ snprintf ( buffer, sizeof(buffer), "%d", rows ); // AUDIT: Use of sizeof(buffer) is safe.
+ xmp->SetStructField ( xmpNS, xmpProp, kXMP_NS_EXIF, "Rows", buffer );
+
+ std::string arrayPath;
+
+ SXMPUtils::ComposeStructFieldPath ( xmpNS, xmpProp, kXMP_NS_EXIF, "Names", &arrayPath );
+
+ bytePtr += 4; // Move to the list of names.
+ for ( size_t i = columns; i > 0; --i ) {
+ size_t nameLen = strlen((XMP_StringPtr)bytePtr) + 1; // ! Include the terminating nul.
+ if ( (bytePtr + nameLen) > byteEnd ) goto BadExif;
+ xmp->AppendArrayItem ( xmpNS, arrayPath.c_str(), kXMP_PropArrayIsOrdered, (XMP_StringPtr)bytePtr );
+ bytePtr += nameLen;
+ }
+
+ if ( (byteEnd - bytePtr) != (8 * columns * rows) ) goto BadExif; // Make sure the values are present.
+ SXMPUtils::ComposeStructFieldPath ( xmpNS, xmpProp, kXMP_NS_EXIF, "Values", &arrayPath );
+
+ XMP_Int32 * binPtr = (XMP_Int32*)bytePtr;
+ for ( size_t i = (columns * rows); i > 0; --i, binPtr += 2 ) {
+
+ XMP_Int32 binNum = binPtr[0];
+ XMP_Int32 binDenom = binPtr[1];
+ if ( ! nativeEndian ) {
+ Flip4 ( &binNum );
+ Flip4 ( &binDenom );
+ }
+
+ snprintf ( buffer, sizeof(buffer), "%ld/%ld", binNum, binDenom ); // AUDIT: Use of sizeof(buffer) is safe.
+
+ xmp->AppendArrayItem ( xmpNS, arrayPath.c_str(), kXMP_PropArrayIsOrdered, buffer );
+
+ }
+
+ return;
+
+ BadExif: // Ignore the tag if the table is ill-formed.
+ xmp->DeleteProperty ( xmpNS, xmpProp );
+ return;
+
+ } catch ( ... ) {
+ // Do nothing, let other imports proceed.
+ // ? Notify client?
+ }
+
+} // ImportTIFF_OECFTable
+
+// =================================================================================================
+// ImportTIFF_SFRTable
+// ===================
+//
+// Although the XMP for the OECF and SFR tables is the same, the Exif is not. The OECF table has
+// signed rational values and the SFR table has unsigned.
+
+static void
+ImportTIFF_SFRTable ( const TIFF_Manager::TagInfo & tagInfo, bool nativeEndian,
+ SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
+{
+ try { // Don't let errors with one stop the others.
+
+ const XMP_Uns8 * bytePtr = (XMP_Uns8*)tagInfo.dataPtr;
+ const XMP_Uns8 * byteEnd = bytePtr + tagInfo.dataLen;
+
+ XMP_Uns16 columns = *((XMP_Uns16*)bytePtr);
+ XMP_Uns16 rows = *((XMP_Uns16*)(bytePtr+2));
+ if ( ! nativeEndian ) {
+ columns = Flip2 ( columns );
+ rows = Flip2 ( rows );
+ }
+
+ char buffer[40];
+
+ snprintf ( buffer, sizeof(buffer), "%d", columns ); // AUDIT: Use of sizeof(buffer) is safe.
+ xmp->SetStructField ( xmpNS, xmpProp, kXMP_NS_EXIF, "Columns", buffer );
+ snprintf ( buffer, sizeof(buffer), "%d", rows ); // AUDIT: Use of sizeof(buffer) is safe.
+ xmp->SetStructField ( xmpNS, xmpProp, kXMP_NS_EXIF, "Rows", buffer );
+
+ std::string arrayPath;
+
+ SXMPUtils::ComposeStructFieldPath ( xmpNS, xmpProp, kXMP_NS_EXIF, "Names", &arrayPath );
+
+ bytePtr += 4; // Move to the list of names.
+ for ( size_t i = columns; i > 0; --i ) {
+ size_t nameLen = strlen((XMP_StringPtr)bytePtr) + 1; // ! Include the terminating nul.
+ if ( (bytePtr + nameLen) > byteEnd ) goto BadExif;
+ xmp->AppendArrayItem ( xmpNS, arrayPath.c_str(), kXMP_PropArrayIsOrdered, (XMP_StringPtr)bytePtr );
+ bytePtr += nameLen;
+ }
+
+ if ( (byteEnd - bytePtr) != (8 * columns * rows) ) goto BadExif; // Make sure the values are present.
+ SXMPUtils::ComposeStructFieldPath ( xmpNS, xmpProp, kXMP_NS_EXIF, "Values", &arrayPath );
+
+ XMP_Uns32 * binPtr = (XMP_Uns32*)bytePtr;
+ for ( size_t i = (columns * rows); i > 0; --i, binPtr += 2 ) {
+
+ XMP_Uns32 binNum = binPtr[0];
+ XMP_Uns32 binDenom = binPtr[1];
+ if ( ! nativeEndian ) {
+ binNum = Flip4 ( binNum );
+ binDenom = Flip4 ( binDenom );
+ }
+
+ snprintf ( buffer, sizeof(buffer), "%lu/%lu", binNum, binDenom ); // AUDIT: Use of sizeof(buffer) is safe.
+
+ xmp->AppendArrayItem ( xmpNS, arrayPath.c_str(), kXMP_PropArrayIsOrdered, buffer );
+
+ }
+
+ return;
+
+ BadExif: // Ignore the tag if the table is ill-formed.
+ xmp->DeleteProperty ( xmpNS, xmpProp );
+ return;
+
+ } catch ( ... ) {
+ // Do nothing, let other imports proceed.
+ // ? Notify client?
+ }
+
+} // ImportTIFF_SFRTable
+
+// =================================================================================================
+// ImportTIFF_CFATable
+// ===================
+
+static void
+ImportTIFF_CFATable ( const TIFF_Manager::TagInfo & tagInfo, bool nativeEndian,
+ SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
+{
+ try { // Don't let errors with one stop the others.
+
+ const XMP_Uns8 * bytePtr = (XMP_Uns8*)tagInfo.dataPtr;
+ const XMP_Uns8 * byteEnd = bytePtr + tagInfo.dataLen;
+
+ XMP_Uns16 columns = *((XMP_Uns16*)bytePtr);
+ XMP_Uns16 rows = *((XMP_Uns16*)(bytePtr+2));
+ if ( ! nativeEndian ) {
+ columns = Flip2 ( columns );
+ rows = Flip2 ( rows );
+ }
+
+ char buffer[20];
+ std::string arrayPath;
+
+ snprintf ( buffer, sizeof(buffer), "%d", columns ); // AUDIT: Use of sizeof(buffer) is safe.
+ xmp->SetStructField ( xmpNS, xmpProp, kXMP_NS_EXIF, "Columns", buffer );
+ snprintf ( buffer, sizeof(buffer), "%d", rows ); // AUDIT: Use of sizeof(buffer) is safe.
+ xmp->SetStructField ( xmpNS, xmpProp, kXMP_NS_EXIF, "Rows", buffer );
+
+ bytePtr += 4; // Move to the matrix of values.
+ if ( (byteEnd - bytePtr) != (columns * rows) ) goto BadExif; // Make sure the values are present.
+
+ SXMPUtils::ComposeStructFieldPath ( xmpNS, xmpProp, kXMP_NS_EXIF, "Values", &arrayPath );
+
+ for ( size_t i = (columns * rows); i > 0; --i, ++bytePtr ) {
+ snprintf ( buffer, sizeof(buffer), "%hu", *bytePtr ); // AUDIT: Use of sizeof(buffer) is safe.
+ xmp->AppendArrayItem ( xmpNS, arrayPath.c_str(), kXMP_PropArrayIsOrdered, buffer );
+ }
+
+ return;
+
+ BadExif: // Ignore the tag if the table is ill-formed.
+ xmp->DeleteProperty ( xmpNS, xmpProp );
+ return;
+
+ } catch ( ... ) {
+ // Do nothing, let other imports proceed.
+ // ? Notify client?
+ }
+
+} // ImportTIFF_CFATable
+
+// =================================================================================================
+// ImportTIFF_DSDTable
+// ===================
+
+static void
+ImportTIFF_DSDTable ( const TIFF_Manager & tiff, const TIFF_Manager::TagInfo & tagInfo,
+ SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
+{
+ try { // Don't let errors with one stop the others.
+
+ const XMP_Uns8 * bytePtr = (XMP_Uns8*)tagInfo.dataPtr;
+ const XMP_Uns8 * byteEnd = bytePtr + tagInfo.dataLen;
+
+ XMP_Uns16 columns = *((XMP_Uns16*)bytePtr);
+ XMP_Uns16 rows = *((XMP_Uns16*)(bytePtr+2));
+ if ( ! tiff.IsNativeEndian() ) {
+ columns = Flip2 ( columns );
+ rows = Flip2 ( rows );
+ }
+
+ char buffer[20];
+
+ snprintf ( buffer, sizeof(buffer), "%d", columns ); // AUDIT: Use of sizeof(buffer) is safe.
+ xmp->SetStructField ( xmpNS, xmpProp, kXMP_NS_EXIF, "Columns", buffer );
+ snprintf ( buffer, sizeof(buffer), "%d", rows ); // AUDIT: Use of sizeof(buffer) is safe.
+ xmp->SetStructField ( xmpNS, xmpProp, kXMP_NS_EXIF, "Rows", buffer );
+
+ std::string arrayPath;
+ SXMPUtils::ComposeStructFieldPath ( xmpNS, xmpProp, kXMP_NS_EXIF, "Settings", &arrayPath );
+
+ bytePtr += 4; // Move to the list of settings.
+ UTF16Unit * utf16Ptr = (UTF16Unit*)bytePtr;
+ UTF16Unit * utf16End = (UTF16Unit*)byteEnd;
+
+ std::string utf8;
+
+ // Figure 17 in the Exif 2.2 spec is unclear. It has counts for rows and columns, but the
+ // settings are listed as 1..n, not as a rectangular matrix. So, ignore the counts and copy
+ // strings until the end of the Exif value.
+
+ while ( utf16Ptr < utf16End ) {
+
+ size_t nameLen = 0;
+ while ( utf16Ptr[nameLen] != 0 ) ++nameLen;
+ ++nameLen; // ! Include the terminating nul.
+ if ( (utf16Ptr + nameLen) > utf16End ) goto BadExif;
+
+ try {
+ FromUTF16 ( utf16Ptr, nameLen, &utf8, tiff.IsBigEndian() );
+ } catch ( ... ) {
+ goto BadExif; // Ignore the tag if there are conversion errors.
+ }
+
+ xmp->AppendArrayItem ( xmpNS, arrayPath.c_str(), kXMP_PropArrayIsOrdered, utf8.c_str() );
+
+ utf16Ptr += nameLen;
+
+ }
+
+ return;
+
+ BadExif: // Ignore the tag if the table is ill-formed.
+ xmp->DeleteProperty ( xmpNS, xmpProp );
+ return;
+
+ } catch ( ... ) {
+ // Do nothing, let other imports proceed.
+ // ? Notify client?
+ }
+
+} // ImportTIFF_DSDTable
+
+// =================================================================================================
+// ImportTIFF_GPSCoordinate
+// ========================
+
+static void
+ImportTIFF_GPSCoordinate ( const TIFF_Manager & tiff, const TIFF_Manager::TagInfo & posInfo,
+ SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
+{
+ try { // Don't let errors with one stop the others.
+
+ const bool nativeEndian = tiff.IsNativeEndian();
+
+ XMP_Uns16 refID = posInfo.id - 1; // ! The GPS refs and coordinates are all tag n and n+1.
+ TIFF_Manager::TagInfo refInfo;
+ bool found = tiff.GetTag ( kTIFF_GPSInfoIFD, refID, &refInfo );
+ if ( (! found) || (refInfo.type != kTIFF_ASCIIType) || (refInfo.count != 2) ) return;
+ char ref = *((char*)refInfo.dataPtr);
+
+ XMP_Uns32 * binPtr = (XMP_Uns32*)posInfo.dataPtr;
+ XMP_Uns32 degNum = binPtr[0];
+ XMP_Uns32 degDenom = binPtr[1];
+ XMP_Uns32 minNum = binPtr[2];
+ XMP_Uns32 minDenom = binPtr[3];
+ XMP_Uns32 secNum = binPtr[4];
+ XMP_Uns32 secDenom = binPtr[5];
+ if ( ! nativeEndian ) {
+ degNum = Flip4 ( degNum );
+ degDenom = Flip4 ( degDenom );
+ minNum = Flip4 ( minNum );
+ minDenom = Flip4 ( minDenom );
+ secNum = Flip4 ( secNum );
+ secDenom = Flip4 ( secDenom );
+ }
+
+ char buffer[40];
+
+ if ( (degDenom == 1) && (minDenom == 1) && (secDenom == 1) ) {
+
+ snprintf ( buffer, sizeof(buffer), "%lu,%lu,%lu%c", degNum, minNum, secNum, ref ); // AUDIT: Using sizeof(buffer is safe.
+
+ } else {
+
+ XMP_Uns32 maxDenom = degDenom;
+ if ( minDenom > degDenom ) maxDenom = minDenom;
+ if ( secDenom > degDenom ) maxDenom = secDenom;
+
+ int fracDigits = 1;
+ while ( maxDenom > 10 ) { ++fracDigits; maxDenom = maxDenom/10; }
+
+ double temp = (double)degNum / (double)degDenom;
+ double degrees = (double)((XMP_Uns32)temp); // Just the integral number of degrees.
+ double minutes = ((temp - degrees) * 60.0) +
+ ((double)minNum / (double)minDenom) +
+ (((double)secNum / (double)secDenom) / 60.0);
+
+ snprintf ( buffer, sizeof(buffer), "%.0f,%.*f%c", degrees, fracDigits, minutes, ref ); // AUDIT: Using sizeof(buffer is safe.
+
+ }
+
+ xmp->SetProperty ( xmpNS, xmpProp, buffer );
+
+ } catch ( ... ) {
+ // Do nothing, let other imports proceed.
+ // ? Notify client?
+ }
+
+} // ImportTIFF_GPSCoordinate
+
+// =================================================================================================
+// ImportTIFF_GPSTimeStamp
+// =======================
+
+static void
+ImportTIFF_GPSTimeStamp ( const TIFF_Manager & tiff, const TIFF_Manager::TagInfo & timeInfo,
+ SXMPMeta * xmp, const char * xmpNS, const char * xmpProp )
+{
+ try { // Don't let errors with one stop the others.
+
+ const bool nativeEndian = tiff.IsNativeEndian();
+
+ bool haveDate;
+ TIFF_Manager::TagInfo dateInfo;
+ haveDate = tiff.GetTag ( kTIFF_GPSInfoIFD, kTIFF_GPSDateStamp, &dateInfo );
+ if ( ! haveDate ) haveDate = tiff.GetTag ( kTIFF_ExifIFD, kTIFF_DateTimeOriginal, &dateInfo );
+ if ( ! haveDate ) haveDate = tiff.GetTag ( kTIFF_ExifIFD, kTIFF_DateTimeDigitized, &dateInfo );
+ if ( ! haveDate ) return;
+
+ const char * dateStr = (const char *) dateInfo.dataPtr;
+ if ( (dateStr[4] != ':') || (dateStr[7] != ':') ) return;
+ if ( (dateStr[10] != 0) && (dateStr[10] != ' ') ) return;
+
+ XMP_Uns32 * binPtr = (XMP_Uns32*)timeInfo.dataPtr;
+ XMP_Uns32 hourNum = binPtr[0];
+ XMP_Uns32 hourDenom = binPtr[1];
+ XMP_Uns32 minNum = binPtr[2];
+ XMP_Uns32 minDenom = binPtr[3];
+ XMP_Uns32 secNum = binPtr[4];
+ XMP_Uns32 secDenom = binPtr[5];
+ if ( ! nativeEndian ) {
+ hourNum = Flip4 ( hourNum );
+ hourDenom = Flip4 ( hourDenom );
+ minNum = Flip4 ( minNum );
+ minDenom = Flip4 ( minDenom );
+ secNum = Flip4 ( secNum );
+ secDenom = Flip4 ( secDenom );
+ }
+
+ double fHour, fMin, fSec, fNano, temp;
+ fSec = (double)secNum / (double)secDenom;
+ temp = (double)minNum / (double)minDenom;
+ fMin = (double)((XMP_Uns32)temp);
+ fSec += (temp - fMin) * 60.0;
+ temp = (double)hourNum / (double)hourDenom;
+ fHour = (double)((XMP_Uns32)temp);
+ fSec += (temp - fHour) * 3600.0;
+ temp = (double)((XMP_Uns32)fSec);
+ fNano = (fSec - temp) * (1000.0*1000.0*1000.0);
+ fSec = temp;
+
+ XMP_DateTime binStamp;
+ binStamp.tzSign = kXMP_TimeIsUTC;
+ binStamp.tzHour = binStamp.tzMinute = 0;
+ binStamp.year = GatherInt ( dateStr, 4 );
+ binStamp.month = GatherInt ( dateStr+5, 2 );
+ binStamp.day = GatherInt ( dateStr+8, 2 );
+ binStamp.hour = (XMP_Int32)fHour;
+ binStamp.minute = (XMP_Int32)fMin;
+ binStamp.second = (XMP_Int32)fSec;
+ binStamp.nanoSecond = (XMP_Int32)fNano;
+
+ xmp->SetProperty_Date ( xmpNS, xmpProp, binStamp );
+
+ } catch ( ... ) {
+ // Do nothing, let other imports proceed.
+ // ? Notify client?
+ }
+
+} // ImportTIFF_GPSTimeStamp
+
+// =================================================================================================
+// =================================================================================================
+
+// =================================================================================================
+// ReconcileUtils::ImportTIFF
+// ==========================
+
+void
+ReconcileUtils::ImportTIFF ( const TIFF_Manager & tiff, SXMPMeta * xmp, int digestState, XMP_FileFormat srcFormat )
+{
+ TIFF_Manager::TagInfo tagInfo;
+ bool ok;
+
+ ImportTIFF_StandardMappings ( kTIFF_PrimaryIFD, tiff, xmp, digestState );
+
+ // 306 DateTime is a date master with 37520 SubSecTime and is mapped to xmp:ModifyDate.
+ ok = ImportTIFF_VerifyImport ( tiff, xmp, digestState, kTIFF_PrimaryIFD, kTIFF_DateTime,
+ kXMP_NS_XMP, "ModifyDate", &tagInfo );
+ if ( ok && (tagInfo.type == kTIFF_ASCIIType) && (tagInfo.count == 20) ) {
+ ImportTIFF_Date ( tiff, tagInfo, kTIFF_SubSecTime, xmp, kXMP_NS_XMP, "ModifyDate" );
+ }
+
+ if ( srcFormat != kXMP_PhotoshopFile ) {
+
+ // ! TIFF tags 270, 315, and 33432 are ignored for Photoshop files.
+
+ XMP_Assert ( (srcFormat == kXMP_JPEGFile) || (srcFormat == kXMP_TIFFFile) );
+
+ // 270 ImageDescription is an ASCII tag and is mapped to dc:description["x-default"].
+ // Call ImportTIFF_VerifyImport using the x-default item path, don't delete the whole array.
+ ok = ImportTIFF_VerifyImport ( tiff, xmp, digestState, kTIFF_PrimaryIFD, kTIFF_ImageDescription,
+ kXMP_NS_DC, "description[?xml:lang='x-default']", &tagInfo );
+ if ( ok ) ImportTIFF_LocTextASCII ( tiff, kTIFF_PrimaryIFD, kTIFF_ImageDescription,
+ xmp, kXMP_NS_DC, "description" );
+
+ // 315 Artist is an ASCII tag and is mapped to dc:creator[*].
+ ok = ImportTIFF_VerifyImport ( tiff, xmp, digestState, kTIFF_PrimaryIFD, kTIFF_Artist,
+ kXMP_NS_DC, "creator", &tagInfo );
+ if ( ok && (tagInfo.type == kTIFF_ASCIIType) ) {
+ ImportArrayTIFF_ASCII ( tagInfo, xmp, kXMP_NS_DC, "creator" );
+ }
+
+ // 33432 Copyright is mapped to dc:rights["x-default"].
+ // Call ImportTIFF_VerifyImport using the x-default item path, don't delete the whole array.
+ ok = ImportTIFF_VerifyImport ( tiff, xmp, digestState, kTIFF_PrimaryIFD, kTIFF_Copyright,
+ kXMP_NS_DC, "rights[?xml:lang='x-default']", &tagInfo );
+ if ( ok ) ImportTIFF_LocTextASCII ( tiff, kTIFF_PrimaryIFD, kTIFF_Copyright, xmp, kXMP_NS_DC, "rights" );
+
+ }
+
+} // ReconcileUtils::ImportTIFF;
+
+// =================================================================================================
+// ReconcileUtils::ImportExif
+// ==========================
+
+void
+ReconcileUtils::ImportExif ( const TIFF_Manager & tiff, SXMPMeta * xmp, int digestState )
+{
+ const bool nativeEndian = tiff.IsNativeEndian();
+
+ TIFF_Manager::TagInfo tagInfo;
+ bool ok;
+
+ ImportTIFF_StandardMappings ( kTIFF_ExifIFD, tiff, xmp, digestState );
+ ImportTIFF_StandardMappings ( kTIFF_GPSInfoIFD, tiff, xmp, digestState );
+
+ // ------------------------------------------------------
+ // Here are the Exif IFD tags that have special mappings:
+
+ // 36864 ExifVersion is 4 "undefined" ASCII characters.
+ ok = ImportTIFF_VerifyImport ( tiff, xmp, digestState, kTIFF_ExifIFD, kTIFF_ExifVersion,
+ kXMP_NS_EXIF, "ExifVersion", &tagInfo );
+ if ( ok && (tagInfo.type == kTIFF_UndefinedType) && (tagInfo.count == 4) ) {
+ char str[5];
+ *((XMP_Uns32*)str) = *((XMP_Uns32*)tagInfo.dataPtr);
+ str[4] = 0;
+ xmp->SetProperty ( kXMP_NS_EXIF, "ExifVersion", str );
+ }
+
+ // 40960 FlashpixVersion is 4 "undefined" ASCII characters.
+ ok = ImportTIFF_VerifyImport ( tiff, xmp, digestState, kTIFF_ExifIFD, kTIFF_FlashpixVersion,
+ kXMP_NS_EXIF, "FlashpixVersion", &tagInfo );
+ if ( ok && (tagInfo.type == kTIFF_UndefinedType) && (tagInfo.count == 4) ) {
+ char str[5];
+ *((XMP_Uns32*)str) = *((XMP_Uns32*)tagInfo.dataPtr);
+ str[4] = 0;
+ xmp->SetProperty ( kXMP_NS_EXIF, "FlashpixVersion", str );
+ }
+
+ // 37121 ComponentsConfiguration is an array of 4 "undefined" UInt8 bytes.
+ ok = ImportTIFF_VerifyImport ( tiff, xmp, digestState, kTIFF_ExifIFD, kTIFF_ComponentsConfiguration,
+ kXMP_NS_EXIF, "ComponentsConfiguration", &tagInfo );
+ if ( ok && (tagInfo.type == kTIFF_UndefinedType) && (tagInfo.count == 4) ) {
+ ImportArrayTIFF_Byte ( tagInfo, xmp, kXMP_NS_EXIF, "ComponentsConfiguration" );
+ }
+
+ // 37510 UserComment is a string with explicit encoding.
+ ok = ImportTIFF_VerifyImport ( tiff, xmp, digestState, kTIFF_ExifIFD, kTIFF_UserComment,
+ kXMP_NS_EXIF, "UserComment", &tagInfo );
+ if ( ok ) {
+ ImportTIFF_EncodedString ( tiff, tagInfo, xmp, kXMP_NS_EXIF, "UserComment" );
+ }
+
+ // 36867 DateTimeOriginal is a date master with 37521 SubSecTimeOriginal.
+ ok = ImportTIFF_VerifyImport ( tiff, xmp, digestState, kTIFF_ExifIFD, kTIFF_DateTimeOriginal,
+ kXMP_NS_EXIF, "DateTimeOriginal", &tagInfo );
+ if ( ok && (tagInfo.type == kTIFF_ASCIIType) && (tagInfo.count == 20) ) {
+ ImportTIFF_Date ( tiff, tagInfo, kTIFF_SubSecTimeOriginal, xmp, kXMP_NS_EXIF, "DateTimeOriginal" );
+ }
+
+ // 36868 DateTimeDigitized is a date master with 37522 SubSecTimeDigitized.
+ ok = ImportTIFF_VerifyImport ( tiff, xmp, digestState, kTIFF_ExifIFD, kTIFF_DateTimeDigitized,
+ kXMP_NS_EXIF, "DateTimeDigitized", &tagInfo );
+ if ( ok && (tagInfo.type == kTIFF_ASCIIType) && (tagInfo.count == 20) ) {
+ ImportTIFF_Date ( tiff, tagInfo, kTIFF_SubSecTimeDigitized, xmp, kXMP_NS_EXIF, "DateTimeDigitized" );
+ }
+
+ // 34856 OECF is an OECF/SFR table.
+ ok = ImportTIFF_VerifyImport ( tiff, xmp, digestState, kTIFF_ExifIFD, kTIFF_OECF,
+ kXMP_NS_EXIF, "OECF", &tagInfo );
+ if ( ok ) {
+ ImportTIFF_OECFTable ( tagInfo, nativeEndian, xmp, kXMP_NS_EXIF, "OECF" );
+ }
+
+ // 37385 Flash is a UInt16 collection of bit fields and is mapped to a struct in XMP.
+ ok = ImportTIFF_VerifyImport ( tiff, xmp, digestState, kTIFF_ExifIFD, kTIFF_Flash,
+ kXMP_NS_EXIF, "Flash", &tagInfo );
+ if ( ok && (tagInfo.type == kTIFF_ShortType) && (tagInfo.count == 1) ) {
+ ImportTIFF_Flash ( tagInfo, nativeEndian, xmp, kXMP_NS_EXIF, "Flash" );
+ }
+
+ // 41484 SpatialFrequencyResponse is an OECF/SFR table.
+ ok = ImportTIFF_VerifyImport ( tiff, xmp, digestState, kTIFF_ExifIFD, kTIFF_SpatialFrequencyResponse,
+ kXMP_NS_EXIF, "SpatialFrequencyResponse", &tagInfo );
+ if ( ok ) {
+ ImportTIFF_SFRTable ( tagInfo, nativeEndian, xmp, kXMP_NS_EXIF, "SpatialFrequencyResponse" );
+ }
+
+ // 41728 FileSource is an "undefined" UInt8.
+ ok = ImportTIFF_VerifyImport ( tiff, xmp, digestState, kTIFF_ExifIFD, kTIFF_FileSource,
+ kXMP_NS_EXIF, "FileSource", &tagInfo );
+ if ( ok && (tagInfo.type == kTIFF_UndefinedType) && (tagInfo.count == 1) ) {
+ ImportSingleTIFF_Byte ( tagInfo, xmp, kXMP_NS_EXIF, "FileSource" );
+ }
+
+ // 41729 SceneType is an "undefined" UInt8.
+ ok = ImportTIFF_VerifyImport ( tiff, xmp, digestState, kTIFF_ExifIFD, kTIFF_SceneType,
+ kXMP_NS_EXIF, "SceneType", &tagInfo );
+ if ( ok && (tagInfo.type == kTIFF_UndefinedType) && (tagInfo.count == 1) ) {
+ ImportSingleTIFF_Byte ( tagInfo, xmp, kXMP_NS_EXIF, "SceneType" );
+ }
+
+ // 41730 CFAPattern is a custom table.
+ ok = ImportTIFF_VerifyImport ( tiff, xmp, digestState, kTIFF_ExifIFD, kTIFF_CFAPattern,
+ kXMP_NS_EXIF, "CFAPattern", &tagInfo );
+ if ( ok ) {
+ ImportTIFF_CFATable ( tagInfo, nativeEndian, xmp, kXMP_NS_EXIF, "CFAPattern" );
+ }
+
+ // 41995 DeviceSettingDescription is a custom table.
+ ok = ImportTIFF_VerifyImport ( tiff, xmp, digestState, kTIFF_ExifIFD, kTIFF_DeviceSettingDescription,
+ kXMP_NS_EXIF, "DeviceSettingDescription", &tagInfo );
+ if ( ok ) {
+ ImportTIFF_DSDTable ( tiff, tagInfo, xmp, kXMP_NS_EXIF, "DeviceSettingDescription" );
+ }
+
+ // ----------------------------------------------------------
+ // Here are the GPS Info IFD tags that have special mappings:
+
+ // 0 GPSVersionID is 4 UInt8 bytes and mapped as "n.n.n.n".
+ ok = ImportTIFF_VerifyImport ( tiff, xmp, digestState, kTIFF_GPSInfoIFD, kTIFF_GPSVersionID,
+ kXMP_NS_EXIF, "GPSVersionID", &tagInfo );
+ if ( ok && (tagInfo.type == kTIFF_ByteType) && (tagInfo.count == 4) ) {
+ const char * strIn = (const char *) tagInfo.dataPtr;
+ char strOut[8];
+ strOut[0] = strIn[0];
+ strOut[2] = strIn[1];
+ strOut[4] = strIn[2];
+ strOut[6] = strIn[3];
+ strOut[1] = strOut[3] = strOut[5] = '.';
+ strOut[7] = 0;
+ xmp->SetProperty ( kXMP_NS_EXIF, "GPSVersionID", strOut );
+ }
+
+ // 2 GPSLatitude is a GPS coordinate master.
+ ok = ImportTIFF_VerifyImport ( tiff, xmp, digestState, kTIFF_GPSInfoIFD, kTIFF_GPSLatitude,
+ kXMP_NS_EXIF, "GPSLatitude", &tagInfo );
+ if ( ok ) {
+ ImportTIFF_GPSCoordinate ( tiff, tagInfo, xmp, kXMP_NS_EXIF, "GPSLatitude" );
+ }
+
+ // 4 GPSLongitude is a GPS coordinate master.
+ ok = ImportTIFF_VerifyImport ( tiff, xmp, digestState, kTIFF_GPSInfoIFD, kTIFF_GPSLongitude,
+ kXMP_NS_EXIF, "GPSLongitude", &tagInfo );
+ if ( ok ) {
+ ImportTIFF_GPSCoordinate ( tiff, tagInfo, xmp, kXMP_NS_EXIF, "GPSLongitude" );
+ }
+
+ // 7 GPSTimeStamp is a UTC time as 3 rationals, mated with the optional GPSDateStamp.
+ ok = ImportTIFF_VerifyImport ( tiff, xmp, digestState, kTIFF_GPSInfoIFD, kTIFF_GPSTimeStamp,
+ kXMP_NS_EXIF, "GPSTimeStamp", &tagInfo );
+ if ( ok && (tagInfo.type == kTIFF_RationalType) && (tagInfo.count == 3) ) {
+ ImportTIFF_GPSTimeStamp ( tiff, tagInfo, xmp, kXMP_NS_EXIF, "GPSTimeStamp" );
+ }
+
+ // 20 GPSDestLatitude is a GPS coordinate master.
+ ok = ImportTIFF_VerifyImport ( tiff, xmp, digestState, kTIFF_GPSInfoIFD, kTIFF_GPSDestLatitude,
+ kXMP_NS_EXIF, "GPSDestLatitude", &tagInfo );
+ if ( ok ) {
+ ImportTIFF_GPSCoordinate ( tiff, tagInfo, xmp, kXMP_NS_EXIF, "GPSDestLatitude" );
+ }
+
+ // 22 GPSDestLongitude is a GPS coordinate master.
+ ok = ImportTIFF_VerifyImport ( tiff, xmp, digestState, kTIFF_GPSInfoIFD, kTIFF_GPSDestLongitude,
+ kXMP_NS_EXIF, "GPSDestLongitude", &tagInfo );
+ if ( ok ) {
+ ImportTIFF_GPSCoordinate ( tiff, tagInfo, xmp, kXMP_NS_EXIF, "GPSDestLongitude" );
+ }
+
+ // 27 GPSProcessingMethod is a string with explicit encoding.
+ ok = ImportTIFF_VerifyImport ( tiff, xmp, digestState, kTIFF_GPSInfoIFD, kTIFF_GPSProcessingMethod,
+ kXMP_NS_EXIF, "GPSProcessingMethod", &tagInfo );
+ if ( ok ) {
+ ImportTIFF_EncodedString ( tiff, tagInfo, xmp, kXMP_NS_EXIF, "GPSProcessingMethod" );
+ }
+
+ // 28 GPSAreaInformation is a string with explicit encoding.
+ ok = ImportTIFF_VerifyImport ( tiff, xmp, digestState, kTIFF_GPSInfoIFD, kTIFF_GPSAreaInformation,
+ kXMP_NS_EXIF, "GPSAreaInformation", &tagInfo );
+ if ( ok ) {
+ ImportTIFF_EncodedString ( tiff, tagInfo, xmp, kXMP_NS_EXIF, "GPSAreaInformation" );
+ }
+
+} // ReconcileUtils::ImportExif;
+
+// =================================================================================================
+// =================================================================================================
+
+// =================================================================================================
+// ExportSingleTIFF_Short
+// ======================
+
+static void
+ExportSingleTIFF_Short ( const SXMPMeta & xmp, const char * xmpNS, const char * xmpProp,
+ TIFF_Manager * tiff, XMP_Uns8 ifd, XMP_Uns16 id )
+{
+ try { // Don't let errors with one stop the others.
+
+ long xmpValue;
+
+ bool foundXMP = xmp.GetProperty_Int ( xmpNS, xmpProp, &xmpValue, 0 );
+ if ( ! foundXMP ) {
+ tiff->DeleteTag ( ifd, id );
+ return;
+ }
+
+ if ( (xmpValue < 0) || (xmpValue > 0xFFFF) ) return; // ? Complain? Peg to limit? Delete the tag?
+
+ tiff->SetTag_Short ( ifd, id, (XMP_Uns16)xmpValue );
+
+ } catch ( ... ) {
+ // Do nothing, let other exports proceed.
+ // ? Notify client?
+ }
+
+} // ExportSingleTIFF_Short
+
+// =================================================================================================
+// ExportSingleTIFF_Rational
+// =========================
+//
+// An XMP (unsigned) rational is supposed to be written as a string "num/denom".
+
+static void
+ExportSingleTIFF_Rational ( const SXMPMeta & xmp, const char * xmpNS, const char * xmpProp,
+ TIFF_Manager * tiff, XMP_Uns8 ifd, XMP_Uns16 id )
+{
+ try { // Don't let errors with one stop the others.
+
+ std::string strValue;
+ XMP_OptionBits xmpFlags;
+
+ bool foundXMP = xmp.GetProperty ( xmpNS, xmpProp, &strValue, &xmpFlags );
+ if ( ! foundXMP ) {
+ tiff->DeleteTag ( ifd, id );
+ return;
+ }
+
+ if ( ! XMP_PropIsSimple ( xmpFlags ) ) return; // ? Complain? Delete the tag?
+
+ XMP_Uns32 newNum, newDenom;
+ const char* partPtr;
+ size_t partLen;
+
+ partPtr = strValue.c_str();
+ for ( partLen = 0; partPtr[partLen] != 0; ++partLen ) {
+ if ( (partPtr[partLen] < '0') || (partPtr[partLen] > '9') ) break;
+ }
+ if ( partLen == 0 ) return; // ? Complain? Delete the tag?
+ newNum = GatherInt ( partPtr, partLen );
+
+ if ( partPtr[partLen] == 0 ) {
+ newDenom = 1; // Tolerate bad XMP that just has the numerator.
+ } else if ( partPtr[partLen] != '/' ) {
+ return; // ? Complain? Delete the tag?
+ } else {
+ partPtr += partLen+1;
+ for ( partLen = 0; partPtr[partLen] != 0; ++partLen ) {
+ if ( (partPtr[partLen] < '0') || (partPtr[partLen] > '9') ) break;
+ }
+ if ( (partLen == 0) || (partPtr[partLen] != 0) ) return; // ? Complain? Delete the tag?
+ newDenom = GatherInt ( partPtr, partLen );
+ }
+
+ tiff->SetTag_Rational ( ifd, id, newNum, newDenom );
+
+ } catch ( ... ) {
+ // Do nothing, let other exports proceed.
+ // ? Notify client?
+ }
+
+} // ExportSingleTIFF_Rational
+
+// =================================================================================================
+// ExportSingleTIFF_ASCII
+// ======================
+
+static void
+ExportSingleTIFF_ASCII ( const SXMPMeta & xmp, const char * xmpNS, const char * xmpProp,
+ TIFF_Manager * tiff, XMP_Uns8 ifd, XMP_Uns16 id )
+{
+ try { // Don't let errors with one stop the others.
+
+ std::string xmpValue;
+ XMP_OptionBits xmpFlags;
+
+ bool foundXMP = xmp.GetProperty ( xmpNS, xmpProp, &xmpValue, &xmpFlags );
+ if ( ! foundXMP ) {
+ tiff->DeleteTag ( ifd, id );
+ return;
+ }
+
+ if ( ! XMP_PropIsSimple ( xmpFlags ) ) return; // ? Complain? Delete the tag?
+
+ tiff->SetTag ( ifd, id, kTIFF_ASCIIType, xmpValue.size()+1, xmpValue.c_str() );
+
+ } catch ( ... ) {
+ // Do nothing, let other exports proceed.
+ // ? Notify client?
+ }
+
+} // ExportSingleTIFF_ASCII
+
+// =================================================================================================
+// ExportArrayTIFF_ASCII
+// =====================
+//
+// Catenate all of the XMP array values into a string with separating nul characters.
+
+static void
+ExportArrayTIFF_ASCII ( const SXMPMeta & xmp, const char * xmpNS, const char * xmpProp,
+ TIFF_Manager * tiff, XMP_Uns8 ifd, XMP_Uns16 id )
+{
+ try { // Don't let errors with one stop the others.
+
+ std::string itemValue, fullValue;
+ XMP_OptionBits xmpFlags;
+
+ bool foundXMP = xmp.GetProperty ( xmpNS, xmpProp, 0, &xmpFlags );
+ if ( ! foundXMP ) {
+ tiff->DeleteTag ( ifd, id );
+ return;
+ }
+
+ if ( ! XMP_PropIsArray ( xmpFlags ) ) return; // ? Complain? Delete the tag?
+
+ size_t count = xmp.CountArrayItems ( xmpNS, xmpProp );
+ for ( size_t i = 1; i <= count; ++i ) { // ! XMP arrays are indexed from 1.
+ (void) xmp.GetArrayItem ( xmpNS, xmpProp, i, &itemValue, &xmpFlags );
+ if ( ! XMP_PropIsSimple ( xmpFlags ) ) continue; // ? Complain?
+ fullValue.append ( itemValue );
+ fullValue.append ( 1, '\x0' );
+ }
+
+ tiff->SetTag ( ifd, id, kTIFF_ASCIIType, fullValue.size(), fullValue.c_str() ); // ! Already have trailing nul.
+
+ } catch ( ... ) {
+ // Do nothing, let other exports proceed.
+ // ? Notify client?
+ }
+
+} // ExportArrayTIFF_ASCII
+
+// =================================================================================================
+// ExportTIFF_Date
+// ===============
+//
+// Convert an XMP date/time to an Exif 2.2 master date/time tag plus associated fractional seconds.
+// The Exif date/time part is a 20 byte ASCII value formatted as "YYYY:MM:DD HH:MM:SS" with a
+// terminating nul. The fractional seconds are a nul terminated ASCII string with possible space
+// padding. They are literally the fractional part, the digits that would be to the right of the
+// decimal point.
+
+static void
+ExportTIFF_Date ( const SXMPMeta & xmp, const char * xmpNS, const char * xmpProp,
+ TIFF_Manager * tiff, XMP_Uns8 mainIFD, XMP_Uns16 mainID, XMP_Uns8 fracIFD, XMP_Uns16 fracID )
+{
+ try { // Don't let errors with one stop the others.
+
+ XMP_DateTime xmpValue;
+
+ bool foundXMP = xmp.GetProperty_Date ( xmpNS, xmpProp, &xmpValue, 0 );
+ if ( ! foundXMP ) {
+ tiff->DeleteTag ( mainIFD, mainID );
+ tiff->DeleteTag ( fracIFD, fracID );
+ return;
+ }
+
+ char buffer[24];
+ snprintf ( buffer, sizeof(buffer), "%.4d:%.2d:%.2d %.2d:%.2d:%.2d", // AUDIT: Use of sizeof(buffer) is safe.
+ xmpValue.year, xmpValue.month, xmpValue.day, xmpValue.hour, xmpValue.minute, xmpValue.second );
+
+ tiff->SetTag_ASCII ( mainIFD, mainID, buffer );
+
+ if ( xmpValue.nanoSecond != 0 ) {
+
+ snprintf ( buffer, sizeof(buffer), "%09d", xmpValue.nanoSecond ); // AUDIT: Use of sizeof(buffer) is safe.
+ for ( size_t i = strlen(buffer)-1; i > 0; --i ) {
+ if ( buffer[i] != '0' ) break;
+ buffer[i] = 0; // Strip trailing zero digits.
+ }
+
+ tiff->SetTag_ASCII ( fracIFD, fracID, buffer );
+
+ }
+
+ } catch ( ... ) {
+ // Do nothing, let other exports proceed.
+ // ? Notify client?
+ }
+
+} // ExportTIFF_Date
+
+// =================================================================================================
+// ExportTIFF_LocTextASCII
+// ======================
+
+static void
+ExportTIFF_LocTextASCII ( const SXMPMeta & xmp, const char * xmpNS, const char * xmpProp,
+ TIFF_Manager * tiff, XMP_Uns8 ifd, XMP_Uns16 id )
+{
+ try { // Don't let errors with one stop the others.
+
+ std::string xmpValue;
+
+ bool foundXMP = xmp.GetLocalizedText ( xmpNS, xmpProp, "", "x-default", 0, &xmpValue, 0 );
+ if ( ! foundXMP ) {
+ tiff->DeleteTag ( ifd, id );
+ return;
+ }
+
+ tiff->SetTag ( ifd, id, kTIFF_ASCIIType, xmpValue.size()+1, xmpValue.c_str() );
+
+ } catch ( ... ) {
+ // Do nothing, let other exports proceed.
+ // ? Notify client?
+ }
+
+} // ExportTIFF_LocTextASCII
+
+// =================================================================================================
+// ExportTIFF_EncodedString
+// ========================
+
+static void
+ExportTIFF_EncodedString ( const SXMPMeta & xmp, const char * xmpNS, const char * xmpProp,
+ TIFF_Manager * tiff, XMP_Uns8 ifd, XMP_Uns16 id )
+{
+ try { // Don't let errors with one stop the others.
+
+ std::string xmpValue;
+ XMP_OptionBits xmpFlags;
+
+ bool foundXMP = xmp.GetProperty ( xmpNS, xmpProp, &xmpValue, &xmpFlags );
+ if ( ! foundXMP ) {
+ tiff->DeleteTag ( ifd, id );
+ return;
+ }
+
+ if ( ! XMP_PropIsSimple ( xmpFlags ) ) return; // ? Complain? Delete the tag?
+
+ XMP_Uns8 encoding = kTIFF_EncodeASCII;
+ for ( size_t i = 0; i < xmpValue.size(); ++i ) {
+ if ( xmpValue[i] >= 0x80 ) {
+ encoding = kTIFF_EncodeUnicode;
+ break;
+ }
+ }
+
+ tiff->SetTag_EncodedString ( ifd, id, xmpValue.c_str(), encoding );
+
+ } catch ( ... ) {
+ // Do nothing, let other exports proceed.
+ // ? Notify client?
+ }
+
+} // ExportTIFF_EncodedString
+
+// =================================================================================================
+// =================================================================================================
+
+// =================================================================================================
+// ReconcileUtils::ExportTIFF
+// ==========================
+//
+// Only a few tags are written back from XMP to the primary IFD, they are each handled explicitly.
+// The writeback tags are:
+// 270 - ImageDescription
+// 274 - Orientation
+// 282 - XResolution
+// 283 - YResolution
+// 296 - ResolutionUnit
+// 305 - Software
+// 306 - DateTime
+// 315 - Artist
+// 33432 - Copyright
+
+// *** need to determine if the XMP has changed - only export when necessary
+
+void
+ReconcileUtils::ExportTIFF ( const SXMPMeta & xmp, TIFF_Manager * tiff )
+{
+
+ ExportTIFF_LocTextASCII ( xmp, kXMP_NS_DC, "description",
+ tiff, kTIFF_PrimaryIFD, kTIFF_ImageDescription );
+
+ ExportSingleTIFF_Short ( xmp, kXMP_NS_TIFF, "Orientation",
+ tiff, kTIFF_PrimaryIFD, kTIFF_Orientation );
+
+ ExportSingleTIFF_Rational ( xmp, kXMP_NS_TIFF, "XResolution",
+ tiff, kTIFF_PrimaryIFD, kTIFF_XResolution );
+
+ ExportSingleTIFF_Rational ( xmp, kXMP_NS_TIFF, "YResolution",
+ tiff, kTIFF_PrimaryIFD, kTIFF_YResolution );
+
+ ExportSingleTIFF_Short ( xmp, kXMP_NS_TIFF, "ResolutionUnit",
+ tiff, kTIFF_PrimaryIFD, kTIFF_ResolutionUnit );
+
+ ExportSingleTIFF_ASCII ( xmp, kXMP_NS_XMP, "CreatorTool",
+ tiff, kTIFF_PrimaryIFD, kTIFF_Software );
+
+ ExportTIFF_Date ( xmp, kXMP_NS_XMP, "ModifyDate",
+ tiff, kTIFF_PrimaryIFD, kTIFF_DateTime, kTIFF_ExifIFD, kTIFF_SubSecTime );
+
+ ExportArrayTIFF_ASCII ( xmp, kXMP_NS_DC, "creator",
+ tiff, kTIFF_PrimaryIFD, kTIFF_Artist );
+
+ ExportTIFF_LocTextASCII ( xmp, kXMP_NS_DC, "rights",
+ tiff, kTIFF_PrimaryIFD, kTIFF_Copyright );
+
+} // ReconcileUtils::ExportTIFF;
+
+// =================================================================================================
+// ReconcileUtils::ExportExif
+// ==========================
+//
+// Only a few tags are written back from XMP to the Exif IFD, they are each handled explicitly.
+// The writeback tags are:
+// 36867 - DateTimeOriginal (plus 37521 SubSecTimeOriginal)
+// 36868 - DateTimeDigitized (plus 37522 SubSecTimeDigitized)
+// 37510 - UserComment
+// 40964 - RelatedSoundFile
+
+// ! Older versions of Photoshop did not import the UserComment or RelatedSoundFile tags. Don't
+// ! export the current XMP unless the original XMP had the tag or the current XMP has the tag.
+// ! That is, don't delete the Exif tag if the XMP never had the property.
+
+void
+ReconcileUtils::ExportExif ( const SXMPMeta & xmp, TIFF_Manager * tiff )
+{
+
+ if ( xmp.DoesPropertyExist ( kXMP_NS_EXIF, "DateTimeOriginal" ) ) {
+ ExportTIFF_Date ( xmp, kXMP_NS_EXIF, "DateTimeOriginal",
+ tiff, kTIFF_ExifIFD, kTIFF_DateTimeOriginal, kTIFF_ExifIFD, kTIFF_SubSecTimeOriginal );
+ }
+
+ if ( xmp.DoesPropertyExist ( kXMP_NS_EXIF, "DateTimeDigitized" ) ) {
+ ExportTIFF_Date ( xmp, kXMP_NS_EXIF, "DateTimeDigitized",
+ tiff, kTIFF_ExifIFD, kTIFF_DateTimeDigitized, kTIFF_ExifIFD, kTIFF_SubSecTimeDigitized );
+ }
+
+ if ( tiff->xmpHadUserComment || xmp.DoesPropertyExist ( kXMP_NS_EXIF, "UserComment" ) ) {
+ ExportTIFF_EncodedString ( xmp, kXMP_NS_EXIF, "UserComment",
+ tiff, kTIFF_ExifIFD, kTIFF_UserComment );
+ }
+
+ if ( tiff->xmpHadRelatedSoundFile || xmp.DoesPropertyExist ( kXMP_NS_EXIF, "RelatedSoundFile" ) ) {
+ ExportSingleTIFF_ASCII ( xmp, kXMP_NS_EXIF, "RelatedSoundFile",
+ tiff, kTIFF_ExifIFD, kTIFF_RelatedSoundFile );
+ }
+
+} // ReconcileUtils::ExportExif;
diff --git a/source/XMPFiles/FormatSupport/Reconcile_Impl.cpp b/source/XMPFiles/FormatSupport/Reconcile_Impl.cpp
new file mode 100644
index 0000000..99339d2
--- /dev/null
+++ b/source/XMPFiles/FormatSupport/Reconcile_Impl.cpp
@@ -0,0 +1,395 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "XMP_Environment.h" // ! This must be the first include.
+
+#include "Reconcile_Impl.hpp"
+
+#include "UnicodeConversions.hpp"
+
+#if XMP_WinBuild
+#elif XMP_MacBuild
+ #include "UnicodeConverter.h"
+#endif
+
+// =================================================================================================
+/// \file Reconcile_Impl.cpp
+/// \brief Implementation utilities for the legacy metadata reconciliation support.
+///
+// =================================================================================================
+
+// =================================================================================================
+// IsASCII
+// =======
+//
+// See if a string is 7 bit ASCII.
+
+static inline bool IsASCII ( const void * strPtr, size_t strLen )
+{
+
+ for ( const XMP_Uns8 * strPos = (XMP_Uns8*)strPtr; strLen > 0; --strLen, ++strPos ) {
+ if ( *strPos >= 0x80 ) return false;
+ }
+
+ return true;
+
+} // IsASCII
+
+// =================================================================================================
+// ReconcileUtils::IsUTF8
+// ======================
+//
+// See if a string contains valid UTF-8. Allow nul bytes, they can appear inside of multi-part Exif
+// strings. We don't use CodePoint_from_UTF8_Multi in UnicodeConversions because it throws an
+// exception for non-Unicode and we don't need to actually compute the code points.
+
+bool ReconcileUtils::IsUTF8 ( const void * utf8Ptr, size_t utf8Len )
+{
+ const XMP_Uns8 * utf8Pos = (XMP_Uns8*)utf8Ptr;
+ const XMP_Uns8 * utf8End = utf8Pos + utf8Len;
+
+ while ( utf8Pos < utf8End ) {
+
+ if ( *utf8Pos < 0x80 ) {
+
+ ++utf8Pos; // ASCII is UTF-8, tolerate nuls.
+
+ } else {
+
+ // -------------------------------------------------------------------------------------
+ // We've got a multibyte UTF-8 character. The first byte has the number of bytes as the
+ // number of high order 1 bits. The remaining bytes must have 1 and 0 as the top 2 bits.
+
+ #if 0 // *** This might be a more effcient way to count the bytes.
+ static XMP_Uns8 kByteCounts[16] = { 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 2, 2, 3, 4 };
+ size_t bytesNeeded = kByteCounts [ *utf8Pos >> 4 ];
+ if ( (bytesNeeded < 2) || ((bytesNeeded == 4) && ((*utf8Pos & 0x08) != 0)) ) return false;
+ if ( (utf8Pos + bytesNeeded) > utf8End ) return false;
+ #endif
+
+ size_t bytesNeeded = 0; // Count the high order 1 bits in the first byte.
+ for ( XMP_Uns8 temp = *utf8Pos; temp > 0x7F; temp = temp << 1 ) ++bytesNeeded;
+ // *** Consider CPU-specific assembly inline, e.g. cntlzw on PowerPC.
+
+ if ( (bytesNeeded < 2) || (bytesNeeded > 4) || ((utf8Pos+bytesNeeded) > utf8End) ) return false;
+
+ for ( --bytesNeeded, ++utf8Pos; bytesNeeded > 0; --bytesNeeded, ++utf8Pos ) {
+ if ( (*utf8Pos >> 6) != 2 ) return false;
+ }
+
+ }
+
+ }
+
+ return true;
+
+} // ReconcileUtils::IsUTF8
+
+// =================================================================================================
+// UTF8ToHostEncoding
+// ==================
+
+#if XMP_WinBuild
+
+ static void UTF8ToWinEncoding ( UINT codePage,
+ const XMP_Uns8 * utf8Ptr, size_t utf8Len, std::string * host )
+ {
+
+ std::string utf16; // WideCharToMultiByte wants native UTF-16.
+ ToUTF16Native ( (UTF8Unit*)utf8Ptr, utf8Len, &utf16 );
+
+ LPCWSTR utf16Ptr = (LPCWSTR) utf16.c_str();
+ size_t utf16Len = utf16.size() / 2;
+
+ int hostLen = WideCharToMultiByte ( codePage, 0, utf16Ptr, utf16Len, 0, 0, 0, 0 );
+ host->assign ( hostLen, ' ' ); // Allocate space for the results.
+
+ (void) WideCharToMultiByte ( codePage, 0, utf16Ptr, utf16Len, (LPSTR)host->data(), hostLen, 0, 0 );
+ XMP_Assert ( hostLen == host->size() );
+
+ } // UTF8ToWinEncoding
+
+#elif XMP_MacBuild
+
+ static void UTF8ToMacEncoding ( TextEncoding & destEncoding,
+ const XMP_Uns8 * utf8Ptr, size_t utf8Len, std::string * host )
+ {
+ OSStatus err;
+
+ UnicodeMapping mappingInfo;
+ mappingInfo.mappingVersion = kUnicodeUseLatestMapping;
+ mappingInfo.otherEncoding = GetTextEncodingBase ( destEncoding );
+ mappingInfo.unicodeEncoding = CreateTextEncoding ( kTextEncodingUnicodeDefault,
+ kUnicodeNoSubset, kUnicodeUTF8Format );
+
+ UnicodeToTextInfo converterInfo;
+ err = CreateUnicodeToTextInfo ( &mappingInfo, &converterInfo );
+ if ( err != noErr ) XMP_Throw ( "CreateUnicodeToTextInfo failed", kXMPErr_ExternalFailure );
+
+ try { // ! Need to call DisposeUnicodeToTextInfo before exiting.
+
+ OptionBits convFlags = kUnicodeUseFallbacksMask |
+ kUnicodeLooseMappingsMask | kUnicodeDefaultDirectionMask;
+ ByteCount bytesRead, bytesWritten;
+
+ enum { kBufferLen = 1000 }; // Ought to be enough in practice, without using too much stack.
+ char buffer [kBufferLen];
+
+ host->reserve ( utf8Len ); // As good a guess as any.
+
+ while ( utf8Len > 0 ) {
+ // Ignore all errors from ConvertFromUnicodeToText. It returns info like "output
+ // buffer full" or "use substitution" as errors.
+ err = ConvertFromUnicodeToText ( converterInfo, utf8Len, (UniChar*)utf8Ptr, convFlags,
+ 0, 0, 0, 0, kBufferLen, &bytesRead, &bytesWritten, buffer );
+ if ( bytesRead == 0 ) break; // Make sure forward progress happens.
+ host->append ( &buffer[0], bytesWritten );
+ utf8Ptr += bytesRead;
+ utf8Len -= bytesRead;
+ }
+
+ DisposeUnicodeToTextInfo ( &converterInfo );
+
+ } catch ( ... ) {
+
+ DisposeUnicodeToTextInfo ( &converterInfo );
+ throw;
+
+ }
+
+ } // UTF8ToMacEncoding
+
+#elif XMP_UNIXBuild
+
+ #error "UTF8ToHostEncoding is not implemented for UNIX"
+ // *** A nice definition of Windows 1252 is at http://www.microsoft.com/globaldev/reference/sbcs/1252.mspx
+ // *** We should code our own conversions for this, and use it for UNIX - unless better POSIX routines exist.
+
+#endif
+
+// =================================================================================================
+// ReconcileUtils::UTF8ToLocal
+// ===========================
+
+void ReconcileUtils::UTF8ToLocal ( const void * _utf8Ptr, size_t utf8Len, std::string * local )
+{
+ const XMP_Uns8* utf8Ptr = (XMP_Uns8*)_utf8Ptr;
+
+ local->erase();
+
+ if ( IsASCII ( utf8Ptr, utf8Len ) ) {
+ local->assign ( (const char *)utf8Ptr, utf8Len );
+ return;
+ }
+
+ #if XMP_WinBuild
+
+ UTF8ToWinEncoding ( CP_ACP, utf8Ptr, utf8Len, local );
+
+ #elif XMP_MacBuild
+
+ OSStatus err;
+
+ TextEncoding localEncoding;
+ err = UpgradeScriptInfoToTextEncoding ( smSystemScript,
+ kTextLanguageDontCare, kTextRegionDontCare, 0, &localEncoding );
+ if ( err != noErr ) XMP_Throw ( "UpgradeScriptInfoToTextEncoding failed", kXMPErr_ExternalFailure );
+
+ UTF8ToMacEncoding ( localEncoding, utf8Ptr, utf8Len, local );
+
+ #elif XMP_UNIXBuild
+
+ #error "UTF8ToLocal is not implemented for UNIX"
+
+ #endif
+
+} // ReconcileUtils::UTF8ToLocal
+
+// =================================================================================================
+// ReconcileUtils::UTF8ToLatin1
+// ============================
+//
+// Actually to the Windows code page 1252 superset of 8859-1.
+
+void ReconcileUtils::UTF8ToLatin1 ( const void * _utf8Ptr, size_t utf8Len, std::string * latin1 )
+{
+ const XMP_Uns8* utf8Ptr = (XMP_Uns8*)_utf8Ptr;
+
+ latin1->erase();
+
+ if ( IsASCII ( utf8Ptr, utf8Len ) ) {
+ latin1->assign ( (const char *)utf8Ptr, utf8Len );
+ return;
+ }
+
+ #if XMP_WinBuild
+
+ UTF8ToWinEncoding ( 1252, utf8Ptr, utf8Len, latin1 );
+
+ #elif XMP_MacBuild
+
+ TextEncoding latin1Encoding;
+ latin1Encoding = CreateTextEncoding ( kTextEncodingWindowsLatin1,
+ kTextEncodingDefaultVariant, kTextEncodingDefaultFormat );
+
+ UTF8ToMacEncoding ( latin1Encoding, utf8Ptr, utf8Len, latin1 );
+
+ #elif XMP_UNIXBuild
+
+ #error "UTF8ToLatin1 is not implemented for UNIX"
+
+ #endif
+
+} // ReconcileUtils::UTF8ToLatin1
+
+// =================================================================================================
+// HostEncodingToUTF8
+// ==================
+
+#if XMP_WinBuild
+
+ static void WinEncodingToUTF8 ( UINT codePage,
+ const XMP_Uns8 * hostPtr, size_t hostLen, std::string * utf8 )
+ {
+
+ size_t utf16Len = MultiByteToWideChar ( codePage, 0, (LPCSTR)hostPtr, hostLen, 0, 0 );
+ std::vector<UTF16Unit> utf16 ( utf16Len, 0 ); // MultiByteToWideChar returns native UTF-16.
+
+ (void) MultiByteToWideChar ( codePage, 0, (LPCSTR)hostPtr, hostLen, (LPWSTR)&utf16[0], utf16Len );
+ FromUTF16Native ( &utf16[0], utf16Len, utf8 );
+
+ } // WinEncodingToUTF8
+
+#elif XMP_MacBuild
+
+ static void MacEncodingToUTF8 ( TextEncoding & srcEncoding,
+ const XMP_Uns8 * hostPtr, size_t hostLen, std::string * utf8 )
+ {
+ OSStatus err;
+
+ UnicodeMapping mappingInfo;
+ mappingInfo.mappingVersion = kUnicodeUseLatestMapping;
+ mappingInfo.otherEncoding = GetTextEncodingBase ( srcEncoding );
+ mappingInfo.unicodeEncoding = CreateTextEncoding ( kTextEncodingUnicodeDefault,
+ kUnicodeNoSubset, kUnicodeUTF8Format );
+
+ TextToUnicodeInfo converterInfo;
+ err = CreateTextToUnicodeInfo ( &mappingInfo, &converterInfo );
+ if ( err != noErr ) XMP_Throw ( "CreateTextToUnicodeInfo failed", kXMPErr_ExternalFailure );
+
+ try { // ! Need to call DisposeTextToUnicodeInfo before exiting.
+
+ ByteCount bytesRead, bytesWritten;
+
+ enum { kBufferLen = 1000 }; // Ought to be enough in practice, without using too much stack.
+ char buffer [kBufferLen];
+
+ utf8->reserve ( hostLen ); // As good a guess as any.
+
+ while ( hostLen > 0 ) {
+ // Ignore all errors from ConvertFromTextToUnicode. It returns info like "output
+ // buffer full" or "use substitution" as errors.
+ err = ConvertFromTextToUnicode ( converterInfo, hostLen, hostPtr, kNilOptions,
+ 0, 0, 0, 0, kBufferLen, &bytesRead, &bytesWritten, (UniChar*)buffer );
+ if ( bytesRead == 0 ) break; // Make sure forward progress happens.
+ utf8->append ( &buffer[0], bytesWritten );
+ hostPtr += bytesRead;
+ hostLen -= bytesRead;
+ }
+
+ DisposeTextToUnicodeInfo ( &converterInfo );
+
+ } catch ( ... ) {
+
+ DisposeTextToUnicodeInfo ( &converterInfo );
+ throw;
+
+ }
+
+ } // MacEncodingToUTF8
+
+#elif XMP_UNIXBuild
+
+ #error "HostEncodingToUTF8 is not implemented for UNIX"
+
+#endif
+
+// =================================================================================================
+// ReconcileUtils::LocalToUTF8
+// ===========================
+
+void ReconcileUtils::LocalToUTF8 ( const void * _localPtr, size_t localLen, std::string * utf8 )
+{
+ const XMP_Uns8* localPtr = (XMP_Uns8*)_localPtr;
+
+ utf8->erase();
+
+ if ( IsASCII ( localPtr, localLen ) ) {
+ utf8->assign ( (const char *)localPtr, localLen );
+ return;
+ }
+
+ #if XMP_WinBuild
+
+ WinEncodingToUTF8 ( CP_ACP, localPtr, localLen, utf8 );
+
+ #elif XMP_MacBuild
+
+ OSStatus err;
+
+ TextEncoding localEncoding;
+ err = UpgradeScriptInfoToTextEncoding ( smSystemScript, kTextLanguageDontCare, kTextRegionDontCare, 0, &localEncoding );
+ if ( err != noErr ) XMP_Throw ( "UpgradeScriptInfoToTextEncoding failed", kXMPErr_ExternalFailure );
+
+ MacEncodingToUTF8 ( localEncoding, localPtr, localLen, utf8 );
+
+ #elif XMP_UNIXBuild
+
+ #error "LocalToUTF8 is not implemented for UNIX"
+
+ #endif
+
+} // ReconcileUtils::LocalToUTF8
+
+// =================================================================================================
+// ReconcileUtils::Latin1ToUTF8
+// ============================
+//
+// Actually from the Windows code page 1252 superset of 8859-1.
+
+void ReconcileUtils::Latin1ToUTF8 ( const void * _latin1Ptr, size_t latin1Len, std::string * utf8 )
+{
+ const XMP_Uns8* latin1Ptr = (XMP_Uns8*)_latin1Ptr;
+
+ utf8->erase();
+
+ if ( IsASCII ( latin1Ptr, latin1Len ) ) {
+ utf8->assign ( (const char *)latin1Ptr, latin1Len );
+ return;
+ }
+
+ #if XMP_WinBuild
+
+ WinEncodingToUTF8 ( 1252, latin1Ptr, latin1Len, utf8 );
+
+ #elif XMP_MacBuild
+
+ TextEncoding latin1Encoding;
+ latin1Encoding = CreateTextEncoding ( kTextEncodingWindowsLatin1,
+ kTextEncodingDefaultVariant, kTextEncodingDefaultFormat );
+
+ MacEncodingToUTF8 ( latin1Encoding, latin1Ptr, latin1Len, utf8 );
+
+ #elif XMP_UNIXBuild
+
+ #error "Latin1ToUTF8 is not implemented for UNIX"
+
+ #endif
+
+} // ReconcileUtils::Latin1ToUTF8
diff --git a/source/XMPFiles/FormatSupport/Reconcile_Impl.hpp b/source/XMPFiles/FormatSupport/Reconcile_Impl.hpp
new file mode 100644
index 0000000..6795d78
--- /dev/null
+++ b/source/XMPFiles/FormatSupport/Reconcile_Impl.hpp
@@ -0,0 +1,63 @@
+#ifndef __Reconcile_Impl_hpp__
+#define __Reconcile_Impl_hpp__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "XMP_Environment.h" // ! This must be the first include.
+
+#include "ReconcileLegacy.hpp"
+#include "MD5.h"
+
+// =================================================================================================
+/// \file Reconcile_Impl.hpp
+/// \brief Implementation utilities for the legacy metadata reconciliation support.
+///
+// =================================================================================================
+
+typedef XMP_Uns8 MD5_Digest[16]; // ! Should be in MD5.h.
+
+enum {
+ kDigestMissing = -1, // A partial import is done, existing XMP is left alone.
+ kDigestDiffers = 0, // A full import is done, existing XMP is deleted or replaced.
+ kDigestMatches = +1 // No importing is done.
+};
+
+namespace ReconcileUtils {
+
+ static const char * kHexDigits = "0123456789ABCDEF";
+
+ bool IsUTF8 ( const void * _utf8Ptr, size_t utf8Len );
+ void UTF8ToLocal ( const void * _utf8Ptr, size_t utf8Len, std::string * local );
+ void UTF8ToLatin1 ( const void * _utf8Ptr, size_t utf8Len, std::string * latin1 );
+ void LocalToUTF8 ( const void * _localPtr, size_t localLen, std::string * utf8 );
+ void Latin1ToUTF8 ( const void * _latin1Ptr, size_t latin1Len, std::string * utf8 );
+ // *** These ought to be with the Unicode conversions.
+
+ int CheckIPTCDigest ( IPTC_Manager * iptc, const PSIR_Manager & psir );
+ int CheckTIFFDigest ( const TIFF_Manager & tiff, const SXMPMeta & xmp );
+ int CheckExifDigest ( const TIFF_Manager & tiff, const SXMPMeta & xmp );
+
+ void SetIPTCDigest ( IPTC_Manager * iptc, PSIR_Manager * psir );
+ void SetTIFFDigest ( const TIFF_Manager & tiff, SXMPMeta * xmp );
+ void SetExifDigest ( const TIFF_Manager & tiff, SXMPMeta * xmp );
+
+ void ImportIPTC ( const IPTC_Manager & iptc, SXMPMeta * xmp, int digestState );
+ void ImportPSIR ( const PSIR_Manager & psir, SXMPMeta * xmp, int digestState );
+ void ImportTIFF ( const TIFF_Manager & tiff, SXMPMeta * xmp, int digestState, XMP_FileFormat srcFormat );
+ void ImportExif ( const TIFF_Manager & tiff, SXMPMeta * xmp, int digestState );
+
+ void ExportIPTC ( SXMPMeta * xmp, IPTC_Manager * iptc ); // ! Has XMP side effects!
+ void ExportPSIR ( const SXMPMeta & xmp, PSIR_Manager * psir );
+ void ExportTIFF ( const SXMPMeta & xmp, TIFF_Manager * tiff );
+ void ExportExif ( const SXMPMeta & xmp, TIFF_Manager * tiff );
+
+}; // ReconcileUtils
+
+#endif // __Reconcile_Impl_hpp__
diff --git a/source/XMPFiles/FormatSupport/TIFF_FileWriter.cpp b/source/XMPFiles/FormatSupport/TIFF_FileWriter.cpp
new file mode 100644
index 0000000..fc8029d
--- /dev/null
+++ b/source/XMPFiles/FormatSupport/TIFF_FileWriter.cpp
@@ -0,0 +1,1966 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "TIFF_Support.hpp"
+
+// =================================================================================================
+/// \file TIFF_FileWriter.cpp
+/// \brief TIFF_FileWriter is used for memory-based read-write access and all file-based access.
+///
+/// \c TIFF_FileWriter is used for memory-based read-write access and all file-based access. The
+/// main internal data structure is the InternalTagMap, a std::map that uses the tag number as the
+/// key and InternalTagInfo as the value. There are 5 of these maps, one for each of the recognized
+/// IFDs. The maps contain an entry for each tag in the IFD, whether we capture the data or not. The
+/// dataPtr and dataLen fields in the InternalTagInfo are zero if the tag is not captured.
+// =================================================================================================
+
+// =================================================================================================
+// TIFF_FileWriter::TIFF_FileWriter
+// ================================
+//
+// Set big endian Get/Put routines so that routines are in place for creating TIFF without a parse.
+// Parsing will reset them to the proper endianness for the stream. Big endian is a good default
+// since JPEG and PSD files are big endian overall.
+
+TIFF_FileWriter::TIFF_FileWriter()
+ : changed(false), memParsed(false), fileParsed(false), ownedStream(false), memStream(0), tiffLength(0)
+{
+
+ XMP_Uns8 bogusTIFF [kEmptyTIFFLength];
+
+ bogusTIFF[0] = 0x4D;
+ bogusTIFF[1] = 0x4D;
+ bogusTIFF[2] = 0x00;
+ bogusTIFF[3] = 0x2A;
+ bogusTIFF[4] = bogusTIFF[5] = bogusTIFF[6] = bogusTIFF[7] = 0x00;
+
+ (void) this->CheckTIFFHeader ( bogusTIFF, sizeof ( bogusTIFF ) );
+
+} // TIFF_FileWriter::TIFF_FileWriter
+
+// =================================================================================================
+// TIFF_FileWriter::~TIFF_FileWriter
+// =================================
+//
+// The InternalTagInfo destructor will deallocate the data for changed tags. It does not know
+// whether they are memory-based or file-based though, so it won't deallocate captured but unchanged
+// file-based tags. Mark those as changed here to make the destructor deallocate them.
+
+TIFF_FileWriter::~TIFF_FileWriter()
+{
+ XMP_Assert ( ! (this->memParsed && this->fileParsed) );
+
+ if ( this->fileParsed && (this->jpegTNailPtr != 0) ) free ( this->jpegTNailPtr );
+ if ( this->ownedStream ) {
+ XMP_Assert ( this->memStream != 0 );
+ free ( this->memStream );
+ }
+
+ if ( this->fileParsed ) {
+ for ( int ifd = 0; ifd < kTIFF_KnownIFDCount; ++ifd ) {
+ InternalTagMap& currTagMap ( this->containedIFDs[ifd].tagMap );
+ InternalTagMap::iterator tagPos = currTagMap.begin();
+ InternalTagMap::iterator tagEnd = currTagMap.end();
+ for ( ; tagPos != tagEnd; ++tagPos ) {
+ if ( tagPos->second.dataPtr != 0 ) tagPos->second.changed = true;
+ }
+ }
+ }
+
+} // TIFF_FileWriter::~TIFF_FileWriter
+
+// =================================================================================================
+// TIFF_FileWriter::DeleteExistingInfo
+// ===================================
+
+void TIFF_FileWriter::DeleteExistingInfo()
+{
+ XMP_Assert ( ! (this->memParsed && this->fileParsed) );
+
+ if ( this->ownedStream ) free ( this->memStream ); // ! Current TIFF might be memory-parsed.
+ this->memStream = 0;
+ this->tiffLength = 0;
+
+ for ( int ifd = 0; ifd < kTIFF_KnownIFDCount; ++ifd ) this->containedIFDs[ifd].clear();
+
+ this->changed = false;
+ this->memParsed = false;
+ this->fileParsed = false;
+ this->ownedStream = false;
+
+} // TIFF_FileWriter::DeleteExistingInfo
+
+// =================================================================================================
+// TIFF_FileWriter::PickIFD
+// ========================
+
+XMP_Uns8 TIFF_FileWriter::PickIFD ( XMP_Uns8 ifd, XMP_Uns16 id )
+{
+ if ( ifd > kTIFF_LastRealIFD ) {
+ if ( ifd != kTIFF_KnownIFD ) XMP_Throw ( "Invalid IFD number", kXMPErr_BadParam );
+ XMP_Throw ( "kTIFF_KnownIFD not yet implemented", kXMPErr_Unimplemented );
+ // *** Likely to stay unimplemented until there is a client need.
+ }
+
+ return ifd;
+
+} // TIFF_FileWriter::PickIFD
+
+// =================================================================================================
+// TIFF_FileWriter::FindTagInIFD
+// =============================
+
+const TIFF_FileWriter::InternalTagInfo* TIFF_FileWriter::FindTagInIFD ( XMP_Uns8 ifd, XMP_Uns16 id ) const
+{
+ ifd = PickIFD ( ifd, id );
+ const InternalTagMap& currIFD = this->containedIFDs[ifd].tagMap;
+
+ InternalTagMap::const_iterator tagPos = currIFD.find ( id );
+ if ( tagPos == currIFD.end() ) return 0;
+ return &tagPos->second;
+
+} // TIFF_FileWriter::FindTagInIFD
+
+// =================================================================================================
+// TIFF_FileWriter::GetIFD
+// =======================
+
+bool TIFF_FileWriter::GetIFD ( XMP_Uns8 ifd, TagInfoMap* ifdMap ) const
+{
+ if ( ifd > kTIFF_LastRealIFD ) XMP_Throw ( "Invalid IFD number", kXMPErr_BadParam );
+ const InternalTagMap& currIFD = this->containedIFDs[ifd].tagMap;
+
+ InternalTagMap::const_iterator tagPos = currIFD.begin();
+ InternalTagMap::const_iterator tagEnd = currIFD.end();
+
+ if ( ifdMap != 0 ) ifdMap->clear();
+ if ( tagPos == tagEnd ) return false; // Empty IFD.
+
+ if ( ifdMap != 0 ) {
+ for ( ; tagPos != tagEnd; ++tagPos ) {
+ const InternalTagInfo& intInfo = tagPos->second;
+ TagInfo extInfo ( intInfo.id, intInfo.type, intInfo.count, intInfo.dataPtr, intInfo.dataLen );
+ (*ifdMap)[intInfo.id] = extInfo;
+ }
+ }
+
+ return true;
+
+} // TIFF_FileWriter::GetIFD
+
+// =================================================================================================
+// TIFF_FileWriter::GetValueOffset
+// ===============================
+
+XMP_Uns32 TIFF_FileWriter::GetValueOffset ( XMP_Uns8 ifd, XMP_Uns16 id ) const
+{
+ const InternalTagInfo* thisTag = this->FindTagInIFD ( ifd, id );
+ if ( (thisTag == 0) || (thisTag->origLen == 0) ) return 0;
+
+ return thisTag->origOffset;
+
+} // TIFF_FileWriter::GetValueOffset
+
+// =================================================================================================
+// TIFF_FileWriter::GetTag
+// =======================
+
+bool TIFF_FileWriter::GetTag ( XMP_Uns8 ifd, XMP_Uns16 id, TagInfo* info ) const
+{
+ const InternalTagInfo* thisTag = this->FindTagInIFD ( ifd, id );
+ if ( thisTag == 0 ) return false;
+
+ if ( info != 0 ) {
+
+ info->id = thisTag->id;
+ info->type = thisTag->type;
+ info->count = thisTag->dataLen / kTIFF_TypeSizes[thisTag->type];
+ info->dataLen = thisTag->dataLen;
+ info->dataPtr = (const void*)(thisTag->dataPtr);
+
+ }
+
+ return true;
+
+} // TIFF_FileWriter::GetTag
+
+// =================================================================================================
+// TIFF_FileWriter::SetTag
+// =======================
+
+void TIFF_FileWriter::SetTag ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns16 type, XMP_Uns32 count, const void* clientPtr )
+{
+ if ( (type < kTIFF_ByteType) || (type > kTIFF_LastType) ) XMP_Throw ( "Invalid TIFF tag type", kXMPErr_BadParam );
+ size_t typeSize = kTIFF_TypeSizes[type];
+ size_t fullSize = count * typeSize;
+
+ ifd = PickIFD ( ifd, id );
+ InternalTagMap& currIFD = this->containedIFDs[ifd].tagMap;
+
+ InternalTagMap::iterator tagPos = currIFD.find ( id );
+ if ( (tagPos != currIFD.end()) &&
+ (type == tagPos->second.type) &&
+ (count == tagPos->second.count) &&
+ (memcmp ( clientPtr, tagPos->second.dataPtr, tagPos->second.dataLen ) == 0) ) {
+ return; // ! The value is unchanged, exit.
+ }
+
+ InternalTagInfo newTag ( id, type, count );
+ newTag.changed = true;
+ newTag.dataLen = count * typeSize;
+
+ if ( newTag.dataLen <= 4 ) {
+ // The data is less than 4 bytes, store it in the dataOrOffset field. Numbers are already flipped.
+ XMP_Assert ( sizeof ( newTag.dataOrOffset ) == 4 );
+ memcpy ( &newTag.dataOrOffset, clientPtr, newTag.dataLen ); // AUDIT: Safe, the length is <= 4.
+ } else {
+ // The data is more than 4 bytes, make a copy.
+ newTag.dataPtr = (XMP_Uns8*) malloc ( newTag.dataLen );
+ if ( newTag.dataPtr == 0 ) XMP_Throw ( "Out of memory", kXMPErr_NoMemory );
+ memcpy ( newTag.dataPtr, clientPtr, newTag.dataLen ); // AUDIT: Safe, malloc'ed newTag.dataLen bytes above.
+ }
+
+ if ( tagPos == currIFD.end() ) {
+ currIFD[id] = newTag;
+ } else {
+ newTag.origLen = tagPos->second.origLen;
+ newTag.origOffset = tagPos->second.origOffset;
+ tagPos->second = newTag; // ! The InternalTagInfo assign operator transfers dataPtr ownership.
+ }
+
+ this->containedIFDs[ifd].changed = true;
+ this->changed = true;
+
+} // TIFF_FileWriter::SetTag
+
+// =================================================================================================
+// TIFF_FileWriter::DeleteTag
+// ==========================
+
+void TIFF_FileWriter::DeleteTag ( XMP_Uns8 ifd, XMP_Uns16 id )
+{
+ ifd = PickIFD ( ifd, id );
+ InternalTagMap& currIFD = this->containedIFDs[ifd].tagMap;
+
+ InternalTagMap::iterator tagPos = currIFD.find ( id );
+ if ( tagPos == currIFD.end() ) return; // ! Don't set the changed flags if the tag didn't exist.
+
+ currIFD.erase ( tagPos );
+ this->containedIFDs[ifd].changed = true;
+ this->changed = true;
+
+} // TIFF_FileWriter::DeleteTag
+
+// =================================================================================================
+// TIFF_FileWriter::GetTag_Integer
+// ===============================
+
+bool TIFF_FileWriter::GetTag_Integer ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns32* data ) const
+{
+ const InternalTagInfo* thisTag = this->FindTagInIFD ( ifd, id );
+ if ( thisTag == 0 ) return false;
+
+ if ( data != 0 ) {
+ if ( thisTag->type == kTIFF_ShortType ) {
+ if ( thisTag->dataLen != 2 ) return false; // Wrong count.
+ *data = this->GetUns16 ( thisTag->dataPtr );
+ } else if ( thisTag->type == kTIFF_LongType ) {
+ if ( thisTag->dataLen != 4 ) return false; // Wrong count.
+ *data = this->GetUns32 ( thisTag->dataPtr );
+ } else {
+ return false;
+ }
+ }
+
+ return true;
+
+} // TIFF_FileWriter::GetTag_Integer
+
+// =================================================================================================
+// TIFF_FileWriter::GetTag_Byte
+// ============================
+
+bool TIFF_FileWriter::GetTag_Byte ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns8* data ) const
+{
+ const InternalTagInfo* thisTag = this->FindTagInIFD ( ifd, id );
+ if ( thisTag == 0 ) return false;
+ if ( (thisTag->type != kTIFF_ByteType) || (thisTag->dataLen != 1) ) return false;
+
+ if ( data != 0 ) *data = *thisTag->dataPtr;
+
+ return true;
+
+} // TIFF_FileWriter::GetTag_Byte
+
+// =================================================================================================
+// TIFF_FileWriter::GetTag_SByte
+// =============================
+
+bool TIFF_FileWriter::GetTag_SByte ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Int8* data ) const
+{
+ const InternalTagInfo* thisTag = this->FindTagInIFD ( ifd, id );
+ if ( thisTag == 0 ) return false;
+ if ( (thisTag->type != kTIFF_SByteType) || (thisTag->dataLen != 1) ) return false;
+
+ if ( data != 0 ) *data = *thisTag->dataPtr;
+
+ return true;
+
+} // TIFF_FileWriter::GetTag_SByte
+
+// =================================================================================================
+// TIFF_FileWriter::GetTag_Short
+// =============================
+
+bool TIFF_FileWriter::GetTag_Short ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns16* data ) const
+{
+ const InternalTagInfo* thisTag = this->FindTagInIFD ( ifd, id );
+ if ( thisTag == 0 ) return false;
+ if ( (thisTag->type != kTIFF_ShortType) || (thisTag->dataLen != 2) ) return false;
+
+ if ( data != 0 ) {
+ *data = this->GetUns16 ( thisTag->dataPtr );
+ }
+
+ return true;
+
+} // TIFF_FileWriter::GetTag_Short
+
+// =================================================================================================
+// TIFF_FileWriter::GetTag_SShort
+// ==============================
+
+bool TIFF_FileWriter::GetTag_SShort ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Int16* data ) const
+{
+ const InternalTagInfo* thisTag = this->FindTagInIFD ( ifd, id );
+ if ( thisTag == 0 ) return false;
+ if ( (thisTag->type != kTIFF_SShortType) || (thisTag->dataLen != 2) ) return false;
+
+ if ( data != 0 ) {
+ *data = (XMP_Int16) this->GetUns16 ( thisTag->dataPtr );
+ }
+
+ return true;
+
+} // TIFF_FileWriter::GetTag_SShort
+
+// =================================================================================================
+// TIFF_FileWriter::GetTag_Long
+// ============================
+
+bool TIFF_FileWriter::GetTag_Long ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns32* data ) const
+{
+ const InternalTagInfo* thisTag = this->FindTagInIFD ( ifd, id );
+ if ( thisTag == 0 ) return false;
+ if ( (thisTag->type != kTIFF_LongType) || (thisTag->dataLen != 4) ) return false;
+
+ if ( data != 0 ) {
+ *data = this->GetUns32 ( thisTag->dataPtr );
+ }
+
+ return true;
+
+} // TIFF_FileWriter::GetTag_Long
+
+// =================================================================================================
+// TIFF_FileWriter::GetTag_SLong
+// =============================
+
+bool TIFF_FileWriter::GetTag_SLong ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Int32* data ) const
+{
+ const InternalTagInfo* thisTag = this->FindTagInIFD ( ifd, id );
+ if ( thisTag == 0 ) return false;
+ if ( (thisTag->type != kTIFF_SLongType) || (thisTag->dataLen != 4) ) return false;
+
+ if ( data != 0 ) {
+ *data = (XMP_Int32) this->GetUns32 ( thisTag->dataPtr );
+ }
+
+ return true;
+
+} // TIFF_FileWriter::GetTag_SLong
+
+// =================================================================================================
+// TIFF_FileWriter::GetTag_Rational
+// ================================
+
+bool TIFF_FileWriter::GetTag_Rational ( XMP_Uns8 ifd, XMP_Uns16 id, Rational* data ) const
+{
+ const InternalTagInfo* thisTag = this->FindTagInIFD ( ifd, id );
+ if ( (thisTag == 0) || (thisTag->dataPtr == 0) ) return false;
+ if ( (thisTag->type != kTIFF_RationalType) || (thisTag->dataLen != 8) ) return false;
+
+ if ( data != 0 ) {
+ XMP_Uns32* dataPtr = (XMP_Uns32*)thisTag->dataPtr;
+ data->num = this->GetUns32 ( dataPtr );
+ data->denom = this->GetUns32 ( dataPtr+1 );
+ }
+
+ return true;
+
+} // TIFF_FileWriter::GetTag_Rational
+
+// =================================================================================================
+// TIFF_FileWriter::GetTag_SRational
+// =================================
+
+bool TIFF_FileWriter::GetTag_SRational ( XMP_Uns8 ifd, XMP_Uns16 id, SRational* data ) const
+{
+ const InternalTagInfo* thisTag = this->FindTagInIFD ( ifd, id );
+ if ( (thisTag == 0) || (thisTag->dataPtr == 0) ) return false;
+ if ( (thisTag->type != kTIFF_SRationalType) || (thisTag->dataLen != 8) ) return false;
+
+ if ( data != 0 ) {
+ XMP_Uns32* dataPtr = (XMP_Uns32*)thisTag->dataPtr;
+ data->num = (XMP_Int32) this->GetUns32 ( dataPtr );
+ data->denom = (XMP_Int32) this->GetUns32 ( dataPtr+1 );
+ }
+
+ return true;
+
+} // TIFF_FileWriter::GetTag_SRational
+
+// =================================================================================================
+// TIFF_FileWriter::GetTag_Float
+// =============================
+
+bool TIFF_FileWriter::GetTag_Float ( XMP_Uns8 ifd, XMP_Uns16 id, float* data ) const
+{
+ const InternalTagInfo* thisTag = this->FindTagInIFD ( ifd, id );
+ if ( thisTag == 0 ) return false;
+ if ( (thisTag->type != kTIFF_FloatType) || (thisTag->dataLen != 4) ) return false;
+
+ if ( data != 0 ) {
+ *data = this->GetFloat ( thisTag->dataPtr );
+ }
+
+ return true;
+
+} // TIFF_FileWriter::GetTag_Float
+
+// =================================================================================================
+// TIFF_FileWriter::GetTag_Double
+// ==============================
+
+bool TIFF_FileWriter::GetTag_Double ( XMP_Uns8 ifd, XMP_Uns16 id, double* data ) const
+{
+ const InternalTagInfo* thisTag = this->FindTagInIFD ( ifd, id );
+ if ( (thisTag == 0) || (thisTag->dataPtr == 0) ) return false;
+ if ( (thisTag->type != kTIFF_DoubleType) || (thisTag->dataLen != 8) ) return false;
+
+ if ( data != 0 ) {
+ double* dataPtr = (double*)thisTag->dataPtr;
+ *data = this->GetDouble ( dataPtr );
+ }
+
+ return true;
+
+} // TIFF_FileWriter::GetTag_Double
+
+// =================================================================================================
+// TIFF_FileWriter::GetTag_ASCII
+// =============================
+
+bool TIFF_FileWriter::GetTag_ASCII ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_StringPtr* dataPtr, XMP_StringLen* dataLen ) const
+{
+ const InternalTagInfo* thisTag = this->FindTagInIFD ( ifd, id );
+ if ( thisTag == 0 ) return false;
+ if ( (thisTag->dataLen > 4) && (thisTag->dataPtr == 0) ) return false;
+ if ( thisTag->type != kTIFF_ASCIIType ) return false;
+
+ if ( dataPtr != 0 ) *dataPtr = (XMP_StringPtr)thisTag->dataPtr;
+ if ( dataLen != 0 ) *dataLen = thisTag->dataLen;
+
+ return true;
+
+} // TIFF_FileWriter::GetTag_ASCII
+
+// =================================================================================================
+// TIFF_FileWriter::GetTag_EncodedString
+// =====================================
+
+bool TIFF_FileWriter::GetTag_EncodedString ( XMP_Uns8 ifd, XMP_Uns16 id, std::string* utf8Str ) const
+{
+ const InternalTagInfo* thisTag = this->FindTagInIFD ( ifd, id );
+ if ( thisTag == 0 ) return false;
+ if ( thisTag->type != kTIFF_UndefinedType ) return false;
+
+ if ( utf8Str == 0 ) return true; // Return true if the converted string is not wanted.
+
+ bool ok = this->DecodeString ( thisTag->dataPtr, thisTag->dataLen, utf8Str );
+ return ok;
+
+} // TIFF_FileWriter::GetTag_EncodedString
+
+// =================================================================================================
+// TIFF_FileWriter::SetTag_EncodedString
+// =====================================
+
+void TIFF_FileWriter::SetTag_EncodedString ( XMP_Uns8 ifd, XMP_Uns16 id, const std::string& utf8Str, XMP_Uns8 encoding )
+{
+
+ XMP_Throw ( "Not yet implemented", kXMPErr_Unimplemented );
+
+} // TIFF_FileWriter::SetTag_EncodedString
+
+// =================================================================================================
+// TIFF_FileWriter::IsLegacyChanged
+// ================================
+
+bool TIFF_FileWriter::IsLegacyChanged()
+{
+
+ if ( ! this->changed ) return false;
+
+ for ( int ifd = 0; ifd < kTIFF_KnownIFDCount; ++ifd ) {
+
+ InternalIFDInfo & thisIFD = this->containedIFDs[ifd];
+ if ( ! thisIFD.changed ) continue;
+
+ InternalTagMap::iterator tagPos;
+ InternalTagMap::iterator tagEnd = thisIFD.tagMap.end();
+
+ for ( tagPos = thisIFD.tagMap.begin(); tagPos != tagEnd; ++tagPos ) {
+ InternalTagInfo & thisTag = tagPos->second;
+ if ( thisTag.changed && (thisTag.id != kTIFF_XMP) ) return true;
+ }
+
+ }
+
+ return false; // Can get here if the XMP tag is the only one changed.
+
+} // TIFF_FileWriter::IsLegacyChanged
+
+// =================================================================================================
+// TIFF_FileWriter::ParseMemoryStream
+// ==================================
+
+void TIFF_FileWriter::ParseMemoryStream ( const void* data, XMP_Uns32 length, bool copyData /* = true */ )
+{
+ this->DeleteExistingInfo();
+ this->memParsed = true;
+ if ( length == 0 ) return;
+
+ // Allocate space for the full in-memory stream and copy it.
+
+ if ( ! copyData ) {
+ XMP_Assert ( ! this->ownedStream );
+ this->memStream = (XMP_Uns8*) data;
+ } else {
+ if ( length > 100*1024*1024 ) XMP_Throw ( "Outrageous length for memory-based TIFF", kXMPErr_BadTIFF );
+ this->memStream = (XMP_Uns8*) malloc(length);
+ if ( this->memStream == 0 ) XMP_Throw ( "Out of memory", kXMPErr_NoMemory );
+ memcpy ( this->memStream, data, length ); // AUDIT: Safe, malloc'ed length bytes above.
+ }
+ this->tiffLength = length;
+
+ // Find and process the primary, Exif, GPS, and Interoperability IFDs.
+
+ XMP_Uns32 primaryIFDOffset = this->CheckTIFFHeader ( this->memStream, length );
+ XMP_Uns32 tnailIFDOffset = 0;
+
+ if ( primaryIFDOffset != 0 ) tnailIFDOffset = this->ProcessMemoryIFD ( primaryIFDOffset, kTIFF_PrimaryIFD );
+
+ const InternalTagInfo* exifIFDTag = this->FindTagInIFD ( kTIFF_PrimaryIFD, kTIFF_ExifIFDPointer );
+ if ( (exifIFDTag != 0) && (exifIFDTag->type == kTIFF_LongType) && (exifIFDTag->dataLen == 4) ) {
+ XMP_Uns32 exifOffset = this->GetUns32 ( &exifIFDTag->dataOrOffset );
+ (void) this->ProcessMemoryIFD ( exifOffset, kTIFF_ExifIFD );
+ }
+
+ const InternalTagInfo* gpsIFDTag = this->FindTagInIFD ( kTIFF_PrimaryIFD, kTIFF_GPSInfoIFDPointer );
+ if ( (gpsIFDTag != 0) && (gpsIFDTag->type == kTIFF_LongType) && (gpsIFDTag->dataLen == 4) ) {
+ XMP_Uns32 gpsOffset = this->GetUns32 ( &gpsIFDTag->dataOrOffset );
+ (void) this->ProcessMemoryIFD ( gpsOffset, kTIFF_GPSInfoIFD );
+ }
+
+ const InternalTagInfo* interopIFDTag = this->FindTagInIFD ( kTIFF_ExifIFD, kTIFF_InteroperabilityIFDPointer );
+ if ( (interopIFDTag != 0) && (interopIFDTag->type == kTIFF_LongType) && (interopIFDTag->dataLen == 4) ) {
+ XMP_Uns32 interopOffset = this->GetUns32 ( &interopIFDTag->dataOrOffset );
+ (void) this->ProcessMemoryIFD ( interopOffset, kTIFF_InteropIFD );
+ }
+
+ // Process the thumbnail IFD. We only do this for Exif-compliant TIFF streams. Extract the
+ // JPEG thumbnail image pointer (tag 513) for later use by GetTNailInfo.
+
+ if ( (tnailIFDOffset != 0) && (! this->containedIFDs[kTIFF_ExifIFD].tagMap.empty()) ) {
+ (void) this->ProcessMemoryIFD ( tnailIFDOffset, kTIFF_TNailIFD );
+ const InternalTagInfo* jpegInfo = FindTagInIFD ( kTIFF_TNailIFD, kTIFF_JPEGInterchangeFormat );
+ if ( jpegInfo != 0 ) {
+ XMP_Uns32 tnailImageOffset = this->GetUns32 ( &jpegInfo->dataOrOffset );
+ this->jpegTNailPtr = (XMP_Uns8*)this->memStream + tnailImageOffset;
+ }
+ }
+
+ #if 0
+ {
+ printf ( "\nExiting TIFF_FileWriter::ParseMemoryStream\n" );
+ for ( int ifd = 0; ifd < kTIFF_KnownIFDCount; ++ifd ) {
+ InternalIFDInfo & thisIFD = this->containedIFDs[ifd];
+ printf ( "\n IFD %d, count %d, mapped %d, offset %d (0x%X), next IFD %d (0x%X)\n",
+ ifd, thisIFD.origCount, thisIFD.tagMap.size(),
+ thisIFD.origOffset, thisIFD.origOffset, thisIFD.origNextIFD, thisIFD.origNextIFD );
+ InternalTagMap::iterator tagPos;
+ InternalTagMap::iterator tagEnd = thisIFD.tagMap.end();
+ for ( tagPos = thisIFD.tagMap.begin(); tagPos != tagEnd; ++tagPos ) {
+ InternalTagInfo & thisTag = tagPos->second;
+ printf ( " Tag %d, dataOrOffset 0x%X, origLen %d, origOffset %d (0x%X)\n",
+ thisTag.id, thisTag.dataOrOffset, thisTag.origLen, thisTag.origOffset, thisTag.origOffset );
+ }
+ }
+ printf ( "\n" );
+ }
+ #endif
+
+} // TIFF_FileWriter::ParseMemoryStream
+
+// =================================================================================================
+// TIFF_FileWriter::ProcessMemoryIFD
+// =================================
+
+XMP_Uns32 TIFF_FileWriter::ProcessMemoryIFD ( XMP_Uns32 ifdOffset, XMP_Uns8 ifd )
+{
+ InternalIFDInfo& ifdInfo ( this->containedIFDs[ifd] );
+
+ if ( (ifdOffset < 8) || (ifdOffset > (this->tiffLength - kEmptyIFDLength)) ) {
+ XMP_Throw ( "Bad IFD offset", kXMPErr_BadTIFF );
+ }
+
+ XMP_Uns8* ifdPtr = this->memStream + ifdOffset;
+ XMP_Uns16 tagCount = this->GetUns16 ( ifdPtr );
+ RawIFDEntry* ifdEntries = (RawIFDEntry*)(ifdPtr+2);
+
+ if ( tagCount >= 0x8000 ) XMP_Throw ( "Outrageous IFD count", kXMPErr_BadTIFF );
+ if ( (ifdOffset + 2 + tagCount*12 + 4) > this->tiffLength ) XMP_Throw ( "Out of bounds IFD", kXMPErr_BadTIFF );
+
+ ifdInfo.origOffset = ifdOffset;
+ ifdInfo.origCount = tagCount;
+
+ for ( size_t i = 0; i < tagCount; ++i ) {
+
+ RawIFDEntry* rawTag = &ifdEntries[i];
+ InternalTagInfo mapTag ( this->GetUns16(&rawTag->id), this->GetUns16(&rawTag->type), this->GetUns32(&rawTag->count) );
+ if ( (mapTag.type < kTIFF_ByteType) || (mapTag.type > kTIFF_LastType) ) continue; // Bad type, skip this tag.
+
+ mapTag.dataLen = mapTag.origLen = mapTag.count * kTIFF_TypeSizes[mapTag.type];
+ mapTag.dataOrOffset = rawTag->dataOrOffset; // Keep the value or offset in stream byte ordering.
+
+ if ( mapTag.dataLen <= 4 ) {
+ mapTag.dataPtr = (XMP_Uns8*) &mapTag.dataOrOffset;
+ mapTag.origOffset = ifdOffset + 2 + (12 * i); // Compute the data offset.
+ } else {
+ mapTag.origOffset = this->GetUns32 ( &rawTag->dataOrOffset ); // Extract the data offset.
+ mapTag.dataPtr = this->memStream + mapTag.origOffset;
+ // printf ( "FW_ProcessMemoryIFD tag %d large value @ %.8X\n", mapTag.id, mapTag.dataPtr );
+ }
+ ifdInfo.tagMap[mapTag.id] = mapTag;
+
+ }
+
+ ifdPtr += (2 + tagCount*12);
+ ifdInfo.origNextIFD = this->GetUns32 ( ifdPtr );
+
+ return ifdInfo.origNextIFD;
+
+} // TIFF_FileWriter::ProcessMemoryIFD
+
+// =================================================================================================
+// CaptureJPEGTNail
+// ================
+//
+// Capture the JPEG image stream for an Exif compressed thumbnail.
+
+static XMP_Uns8* CaptureJPEGTNail ( LFA_FileRef fileRef, IOBuffer* ioBuf, const TIFF_Manager& tiff )
+{
+ bool ok;
+ XMP_Uns8* jpegPtr = 0;
+ XMP_Uns32 jpegOffset, jpegLen;
+
+ ok = tiff.GetTag_Integer ( kTIFF_TNailIFD, kTIFF_JPEGInterchangeFormat, &jpegOffset );
+ if ( ok ) ok = tiff.GetTag_Integer ( kTIFF_TNailIFD, kTIFF_JPEGInterchangeFormatLength, &jpegLen );
+ if ( ! ok ) return 0;
+
+ if ( jpegLen > 1024*1024 ) return 0; // ? XMP_Throw ( "Outrageous JPEG TNail length", kXMPErr_BadTIFF );
+
+ jpegPtr = (XMP_Uns8*) malloc ( jpegLen );
+ if ( jpegPtr == 0 ) XMP_Throw ( "Out of memory", kXMPErr_NoMemory );
+
+ try {
+
+ if ( jpegLen > kIOBufferSize ) {
+ // This value is bigger than the I/O buffer, read it directly and restore the file position.
+ LFA_Seek ( fileRef, jpegOffset, SEEK_SET );
+ LFA_Read ( fileRef, jpegPtr, jpegLen, kLFA_RequireAll );
+ LFA_Seek ( fileRef, (ioBuf->filePos + ioBuf->len), SEEK_SET );
+ } else {
+ // This value can fit in the I/O buffer, so use that.
+ MoveToOffset ( fileRef, jpegOffset, ioBuf );
+ ok = CheckFileSpace ( fileRef, ioBuf, jpegLen );
+ if ( ! ok ) XMP_Throw ( "EOF in data block", kXMPErr_BadTIFF );
+ memcpy ( jpegPtr, ioBuf->ptr, jpegLen ); // AUDIT: Safe, malloc'ed jpegLen bytes above.
+ }
+
+ } catch ( ... ) {
+
+ free ( jpegPtr );
+ throw;
+
+ }
+
+ return jpegPtr;
+
+} // CaptureJPEGTNail
+
+// =================================================================================================
+// TIFF_FileWriter::ParseFileStream
+// ================================
+//
+// The buffered I/O model is worth the logic complexity - as opposed to a simple seek/read for each
+// part of the TIFF stream. The vast majority of real-world TIFFs have the primary IFD, Exif IFD,
+// and all of their interesting tag values within the first 64K of the file. Well, at least before
+// we get around to our edit-by-append approach.
+
+void TIFF_FileWriter::ParseFileStream ( LFA_FileRef fileRef )
+{
+ bool ok;
+ IOBuffer ioBuf;
+
+ this->DeleteExistingInfo();
+ this->fileParsed = true;
+ this->tiffLength = (XMP_Uns32) LFA_Measure ( fileRef );
+ if ( this->tiffLength == 0 ) return;
+
+ // Find and process the primary, Exif, GPS, and Interoperability IFDs.
+
+ ioBuf.filePos = LFA_Seek ( fileRef, 0, SEEK_SET );
+ ok = CheckFileSpace ( fileRef, &ioBuf, 8 );
+ if ( ! ok ) XMP_Throw ( "TIFF too small", kXMPErr_BadTIFF );
+
+ XMP_Uns32 primaryIFDOffset = this->CheckTIFFHeader ( ioBuf.ptr, this->tiffLength );
+ XMP_Uns32 tnailIFDOffset = 0;
+
+ if ( primaryIFDOffset != 0 ) tnailIFDOffset = this->ProcessFileIFD ( kTIFF_PrimaryIFD, primaryIFDOffset, fileRef, &ioBuf );
+
+ const InternalTagInfo* exifIFDTag = this->FindTagInIFD ( kTIFF_PrimaryIFD, kTIFF_ExifIFDPointer );
+ if ( (exifIFDTag != 0) && (exifIFDTag->type == kTIFF_LongType) && (exifIFDTag->count == 1) ) {
+ XMP_Uns32 exifOffset = this->GetUns32 ( &exifIFDTag->dataOrOffset );
+ (void) this->ProcessFileIFD ( kTIFF_ExifIFD, exifOffset, fileRef, &ioBuf );
+ }
+
+ const InternalTagInfo* gpsIFDTag = this->FindTagInIFD ( kTIFF_PrimaryIFD, kTIFF_GPSInfoIFDPointer );
+ if ( (gpsIFDTag != 0) && (gpsIFDTag->type == kTIFF_LongType) && (gpsIFDTag->count == 1) ) {
+ XMP_Uns32 gpsOffset = this->GetUns32 ( &gpsIFDTag->dataOrOffset );
+ (void) this->ProcessFileIFD ( kTIFF_GPSInfoIFD, gpsOffset, fileRef, &ioBuf );
+ }
+
+ const InternalTagInfo* interopIFDTag = this->FindTagInIFD ( kTIFF_ExifIFD, kTIFF_InteroperabilityIFDPointer );
+ if ( (interopIFDTag != 0) && (interopIFDTag->type == kTIFF_LongType) && (interopIFDTag->dataLen == 4) ) {
+ XMP_Uns32 interopOffset = this->GetUns32 ( &interopIFDTag->dataOrOffset );
+ (void) this->ProcessFileIFD ( kTIFF_InteropIFD, interopOffset, fileRef, &ioBuf );
+ }
+
+ // Process the thumbnail IFD. We only do this for Exif-compliant TIFF streams. Do this after
+ // the others since they are often within the first 64K of the file and the thumbnail is not.
+
+ if ( (tnailIFDOffset != 0) && (! this->containedIFDs[kTIFF_ExifIFD].tagMap.empty()) ) {
+ (void) this->ProcessFileIFD ( kTIFF_TNailIFD, tnailIFDOffset, fileRef, &ioBuf );
+ this->jpegTNailPtr = CaptureJPEGTNail ( fileRef, &ioBuf, *this );
+ }
+
+ #if 0
+ {
+ printf ( "\nExiting TIFF_FileWriter::ParseFileStream\n" );
+ for ( int ifd = 0; ifd < kTIFF_KnownIFDCount; ++ifd ) {
+ InternalIFDInfo & thisIFD = this->containedIFDs[ifd];
+ printf ( "\n IFD %d, count %d, mapped %d, offset %d (0x%X), next IFD %d (0x%X)\n",
+ ifd, thisIFD.origCount, thisIFD.tagMap.size(),
+ thisIFD.origOffset, thisIFD.origOffset, thisIFD.origNextIFD, thisIFD.origNextIFD );
+ InternalTagMap::iterator tagPos;
+ InternalTagMap::iterator tagEnd = thisIFD.tagMap.end();
+ for ( tagPos = thisIFD.tagMap.begin(); tagPos != tagEnd; ++tagPos ) {
+ InternalTagInfo & thisTag = tagPos->second;
+ printf ( " Tag %d, dataOrOffset 0x%X, origLen %d, origOffset %d (0x%X)\n",
+ thisTag.id, thisTag.dataOrOffset, thisTag.origLen, thisTag.origOffset, thisTag.origOffset );
+ }
+ }
+ printf ( "\n" );
+ }
+ #endif
+
+} // TIFF_FileWriter::ParseFileStream
+
+// =================================================================================================
+// TIFF_FileWriter::ProcessFileIFD
+// ===============================
+
+XMP_Uns32 TIFF_FileWriter::ProcessFileIFD ( XMP_Uns8 ifd, XMP_Uns32 ifdOffset, LFA_FileRef fileRef, IOBuffer* ioBuf )
+{
+ InternalIFDInfo& ifdInfo ( this->containedIFDs[ifd] );
+
+ MoveToOffset ( fileRef, ifdOffset, ioBuf ); // Move to the start of the IFD.
+
+ bool ok = CheckFileSpace ( fileRef, ioBuf, 2 );
+ if ( ! ok ) XMP_Throw ( "IFD count missing", kXMPErr_BadTIFF );
+ XMP_Uns16 tagCount = this->GetUns16 ( ioBuf->ptr );
+
+ if ( tagCount >= 0x8000 ) XMP_Throw ( "Outrageous IFD count", kXMPErr_BadTIFF );
+ if ( (ifdOffset + 2 + tagCount*12 + 4) > this->tiffLength ) XMP_Throw ( "Out of bounds IFD", kXMPErr_BadTIFF );
+
+ ifdInfo.origOffset = ifdOffset;
+ ifdInfo.origCount = tagCount;
+
+ // ---------------------------------------------------------------------------------------------
+ // First create all of the IFD map entries, capturing short values, and get the next IFD offset.
+ // We're using a std::map for storage, it automatically eliminates duplicates and provides
+ // sorted output. Plus the "map[key] = value" assignment conveniently keeps the last encountered
+ // value, following Photoshop's behavior.
+
+ ioBuf->ptr += 2; // Move to the first IFD entry.
+
+ for ( XMP_Uns16 i = 0; i < tagCount; ++i, ioBuf->ptr += 12 ) {
+
+ if ( ! CheckFileSpace ( fileRef, ioBuf, 12 ) ) XMP_Throw ( "EOF within IFD", kXMPErr_BadTIFF );
+
+ RawIFDEntry* rawTag = (RawIFDEntry*)ioBuf->ptr;
+ InternalTagInfo mapTag ( this->GetUns16(&rawTag->id), this->GetUns16(&rawTag->type), this->GetUns32(&rawTag->count) );
+ if ( (mapTag.type < kTIFF_ByteType) || (mapTag.type > kTIFF_LastType) ) continue; // Bad type, skip this tag.
+
+ mapTag.dataLen = mapTag.origLen = mapTag.count * kTIFF_TypeSizes[mapTag.type];
+ mapTag.dataOrOffset = rawTag->dataOrOffset; // Keep the value or offset in stream byte ordering.
+
+ if ( mapTag.dataLen <= 4 ) {
+ mapTag.dataPtr = (XMP_Uns8*) &mapTag.dataOrOffset;
+ mapTag.origOffset = ifdOffset + 2 + (12 * i); // Compute the data offset.
+ } else {
+ mapTag.origOffset = this->GetUns32 ( &rawTag->dataOrOffset ); // Extract the data offset.
+ }
+ ifdInfo.tagMap[mapTag.id] = mapTag;
+
+ }
+
+ if ( ! CheckFileSpace ( fileRef, ioBuf, 4 ) ) XMP_Throw ( "EOF at next IFD offset", kXMPErr_BadTIFF );
+ ifdInfo.origNextIFD = this->GetUns32 ( ioBuf->ptr );
+
+ // ---------------------------------------------------------------------------------------------
+ // Go back over the tag map and extract the data for large recognized tags. This is done in 2
+ // passes, in order to lessen the typical amount of I/O. On the first pass make sure we have at
+ // least 32K of data following the IFD in the buffer, and extract all of the values in that
+ // portion. This should cover an original file, or the appended values with an appended IFD.
+
+ if ( (ioBuf->limit - ioBuf->ptr) < 32*1024 ) RefillBuffer ( fileRef, ioBuf );
+
+ InternalTagMap::iterator tagPos = ifdInfo.tagMap.begin();
+ InternalTagMap::iterator tagEnd = ifdInfo.tagMap.end();
+
+ const XMP_Uns16* knownTagPtr = sKnownTags[ifd]; // Points into the ordered recognized tag list.
+
+ XMP_Uns32 bufBegin = (XMP_Uns32)ioBuf->filePos; // TIFF stream bounds for the current buffer.
+ XMP_Uns32 bufEnd = bufBegin + ioBuf->len;
+
+ for ( ; tagPos != tagEnd; ++tagPos ) {
+
+ InternalTagInfo* currTag = &tagPos->second;
+
+ if ( currTag->dataLen <= 4 ) continue; // Short values are already in the dataOrOffset field.
+ while ( *knownTagPtr < currTag->id ) ++knownTagPtr;
+ if ( *knownTagPtr != currTag->id ) continue; // Skip unrecognized tags.
+ if ( currTag->dataLen > 1024*1024 ) XMP_Throw ( "Outrageous data length", kXMPErr_BadTIFF );
+
+ if ( (bufBegin <= currTag->origOffset) && ((currTag->origOffset + currTag->dataLen) <= bufEnd) ) {
+ // This value is already fully within the current I/O buffer, copy it.
+ MoveToOffset ( fileRef, currTag->origOffset, ioBuf );
+ currTag->dataPtr = (XMP_Uns8*) malloc ( currTag->dataLen );
+ if ( currTag->dataPtr == 0 ) XMP_Throw ( "No data block", kXMPErr_NoMemory );
+ memcpy ( currTag->dataPtr, ioBuf->ptr, currTag->dataLen ); // AUDIT: Safe, malloc'ed currTag->dataLen bytes above.
+ }
+
+ }
+
+ // ---------------------------------------------------------------------------------------------
+ // Now the second large value pass. This will reposition the I/O buffer as necessary. Hopefully
+ // just once, to pick up the span of data not covered in the first pass.
+
+ tagPos = ifdInfo.tagMap.begin(); // Reset both map/array positions.
+ knownTagPtr = sKnownTags[ifd];
+
+ for ( ; tagPos != tagEnd; ++tagPos ) {
+
+ InternalTagInfo* currTag = &tagPos->second;
+
+ if ( (currTag->dataLen <= 4) || (currTag->dataPtr != 0) ) continue; // Done this tag?
+ while ( *knownTagPtr < currTag->id ) ++knownTagPtr;
+ if ( *knownTagPtr != currTag->id ) continue; // Skip unrecognized tags.
+ if ( currTag->dataLen > 1024*1024 ) XMP_Throw ( "Outrageous data length", kXMPErr_BadTIFF );
+
+ currTag->dataPtr = (XMP_Uns8*) malloc ( currTag->dataLen );
+ if ( currTag->dataPtr == 0 ) XMP_Throw ( "No data block", kXMPErr_NoMemory );
+
+ if ( currTag->dataLen > kIOBufferSize ) {
+ // This value is bigger than the I/O buffer, read it directly and restore the file position.
+ LFA_Seek ( fileRef, currTag->origOffset, SEEK_SET );
+ LFA_Read ( fileRef, currTag->dataPtr, currTag->dataLen, kLFA_RequireAll );
+ LFA_Seek ( fileRef, (ioBuf->filePos + ioBuf->len), SEEK_SET );
+ } else {
+ // This value can fit in the I/O buffer, so use that.
+ MoveToOffset ( fileRef, currTag->origOffset, ioBuf );
+ ok = CheckFileSpace ( fileRef, ioBuf, currTag->dataLen );
+ if ( ! ok ) XMP_Throw ( "EOF in data block", kXMPErr_BadTIFF );
+ memcpy ( currTag->dataPtr, ioBuf->ptr, currTag->dataLen ); // AUDIT: Safe, malloc'ed currTag->dataLen bytes above.
+ }
+
+ }
+
+ // Done, return the next IFD offset.
+
+ return ifdInfo.origNextIFD;
+
+} // TIFF_FileWriter::ProcessFileIFD
+
+// =================================================================================================
+// TIFF_FileWriter::IntegrateFromPShop6
+// ====================================
+//
+// See comments for ProcessPShop6IFD.
+
+void TIFF_FileWriter::IntegrateFromPShop6 ( const void * buriedPtr, size_t buriedLen )
+{
+ TIFF_MemoryReader buriedExif;
+ buriedExif.ParseMemoryStream ( buriedPtr, buriedLen );
+
+ this->ProcessPShop6IFD ( buriedExif, kTIFF_PrimaryIFD );
+ this->ProcessPShop6IFD ( buriedExif, kTIFF_TNailIFD );
+ this->ProcessPShop6IFD ( buriedExif, kTIFF_ExifIFD );
+ this->ProcessPShop6IFD ( buriedExif, kTIFF_GPSInfoIFD );
+
+} // TIFF_FileWriter::IntegrateFromPShop6
+
+// =================================================================================================
+// TIFF_FileWriter::CopyTagToMasterIFD
+// ===================================
+//
+// Create a new master IFD entry from a buried Photoshop 6 IFD entry. Don't try to get clever with
+// large values, just create a new copy. This preserves a clean separation between the memory-based
+// and file-based TIFF processing.
+
+void* TIFF_FileWriter::CopyTagToMasterIFD ( const TagInfo & ps6Tag, InternalIFDInfo * masterIFD )
+{
+ InternalTagInfo newTag ( ps6Tag.id, ps6Tag.type, ps6Tag.count );
+
+ newTag.dataLen = ps6Tag.dataLen;
+
+ if ( newTag.dataLen <= 4 ) {
+ newTag.dataPtr = (XMP_Uns8*) &newTag.dataOrOffset;
+ newTag.dataOrOffset = *((XMP_Uns32*)ps6Tag.dataPtr);
+ } else {
+ XMP_Assert ( newTag.dataOrOffset == 0 );
+ newTag.dataPtr = (XMP_Uns8*) malloc ( newTag.dataLen );
+ if ( newTag.dataPtr == 0 ) XMP_Throw ( "Out of memory", kXMPErr_NoMemory );
+ memcpy ( newTag.dataPtr, ps6Tag.dataPtr, newTag.dataLen ); // AUDIT: Safe, malloc'ed dataLen bytes above.
+ }
+
+ newTag.changed = true; // ! See comments with ProcessPShop6IFD.
+ XMP_Assert ( (newTag.origLen == 0) && (newTag.origOffset == 0) );
+
+ masterIFD->tagMap[newTag.id] = newTag;
+ masterIFD->changed = true;
+
+ return masterIFD->tagMap[newTag.id].dataPtr; // ! Return the address within the map entry for small values.
+
+} // TIFF_FileWriter::CopyTagToMasterIFD
+
+// =================================================================================================
+// FlipCFATable
+// ============
+//
+// The CFA pattern table is trivial, a pair of short counts followed by n*m bytes.
+
+static bool FlipCFATable ( void* voidPtr, XMP_Uns32 tagLen, GetUns16_Proc GetUns16 )
+{
+ if ( tagLen < 4 ) return false;
+
+ XMP_Uns16* u16Ptr = (XMP_Uns16*)voidPtr;
+
+ Flip2 ( &u16Ptr[0] ); // Flip the counts to match the master TIFF.
+ Flip2 ( &u16Ptr[1] );
+
+ XMP_Uns16 columns = GetUns16 ( &u16Ptr[0] ); // Fetch using the master TIFF's routine.
+ XMP_Uns16 rows = GetUns16 ( &u16Ptr[1] );
+
+ if ( tagLen != (XMP_Uns32)(4 + columns*rows) ) return false;
+
+ return true;
+
+} // FlipCFATable
+
+// =================================================================================================
+// FlipDSDTable
+// ============
+//
+// The device settings description table is trivial, a pair of short counts followed by UTF-16
+// strings. So the whole value should be flipped as a sequence of 16 bit items.
+
+// ! The Exif 2.2 description is a bit garbled. It might be wrong. It would be nice to have a real example.
+
+static bool FlipDSDTable ( void* voidPtr, XMP_Uns32 tagLen, GetUns16_Proc GetUns16 )
+{
+ if ( tagLen < 4 ) return false;
+
+ XMP_Uns16* u16Ptr = (XMP_Uns16*)voidPtr;
+ for ( size_t i = tagLen/2; i > 0; --i, ++u16Ptr ) Flip2 ( u16Ptr );
+
+ return true;
+
+} // FlipDSDTable
+
+// =================================================================================================
+// FlipOECFSFRTable
+// ================
+//
+// The OECF and SFR tables have the same layout:
+// 2 short counts, columns and rows
+// c ASCII strings, null terminated, column names
+// c*r rationals
+
+static bool FlipOECFSFRTable ( void* voidPtr, XMP_Uns32 tagLen, GetUns16_Proc GetUns16 )
+{
+ XMP_Uns16* u16Ptr = (XMP_Uns16*)voidPtr;
+
+ Flip2 ( &u16Ptr[0] ); // Flip the data to match the master TIFF.
+ Flip2 ( &u16Ptr[1] );
+
+ XMP_Uns16 columns = GetUns16 ( &u16Ptr[0] ); // Fetch using the master TIFF's routine.
+ XMP_Uns16 rows = GetUns16 ( &u16Ptr[1] );
+
+ XMP_Uns32 minLen = 4 + columns + (8 * columns * rows); // Minimum legit tag size.
+ if ( tagLen < minLen ) return false;
+
+ // Compute the start of the rationals from the end of value. No need to walk through the names.
+ XMP_Uns32* u32Ptr = (XMP_Uns32*) ((XMP_Uns8*)voidPtr + tagLen - (8 * columns * rows));
+
+ for ( size_t i = 2*columns*rows; i > 0; --i, ++u32Ptr ) Flip4 ( u32Ptr );
+
+ return true;
+
+} // FlipOECFSFRTable
+
+// =================================================================================================
+// TIFF_FileWriter::ProcessPShop6IFD
+// =================================
+//
+// Photoshop 6 wrote wacky TIFF files that have much of the Exif metadata buried inside of image
+// resource 1058, which is itself within tag 34377 in the 0th IFD. This routine moves the buried
+// tags up to the parent file. Existing tags are not replaced.
+//
+// While it is tempting to try to directly use the TIFF_MemoryReader's tweaked IFD info, making that
+// visible would compromise implementation separation. Better to pay the modest runtime cost of
+// using the official GetIFD method, letting it build the map.
+//
+// The tags that get moved are marked as being changed, as is the IFD they are moved into, but the
+// overall TIFF_FileWriter object is not. We don't want this integration on its own to force a file
+// update, but a file update should include these changes.
+
+// ! Be careful to not move tags that are the nasty Exif explicit offsets, e.g. the Exif or GPS IFD
+// ! "pointers". These are tags with a LONG type and count of 1, whose value is an offset into the
+// ! buried TIFF stream. We can't reliably plant that offset into the outer IFD structure.
+
+// ! To make things even more fun, the buried Exif might not have the same endianness as the outer!
+
+void TIFF_FileWriter::ProcessPShop6IFD ( const TIFF_MemoryReader& buriedExif, XMP_Uns8 ifd )
+{
+ bool ok, found;
+ TagInfoMap ps6IFD;
+
+ found = buriedExif.GetIFD ( ifd, &ps6IFD );
+ if ( ! found ) return;
+
+ bool needsFlipping = (this->bigEndian != buriedExif.IsBigEndian());
+
+ InternalIFDInfo* masterIFD = &this->containedIFDs[ifd];
+
+ TagInfoMap::const_iterator ps6Pos = ps6IFD.begin();
+ TagInfoMap::const_iterator ps6End = ps6IFD.end();
+
+ for ( ; ps6Pos != ps6End; ++ps6Pos ) {
+
+ // Copy buried tags to the master IFD if they don't already exist there.
+
+ const TagInfo& ps6Tag = ps6Pos->second;
+
+ if ( this->FindTagInIFD ( ifd, ps6Tag.id ) != 0 ) continue; // Keep existing master tags.
+ if ( needsFlipping && (ps6Tag.id == 37500) ) continue; // Don't copy an unflipped MakerNote.
+ if ( (ps6Tag.id == kTIFF_ExifIFDPointer) || // Skip the tags that are explicit offsets.
+ (ps6Tag.id == kTIFF_GPSInfoIFDPointer) ||
+ (ps6Tag.id == kTIFF_JPEGInterchangeFormat) ||
+ (ps6Tag.id == kTIFF_InteroperabilityIFDPointer) ) continue;
+
+ void* voidPtr = CopyTagToMasterIFD ( ps6Tag, masterIFD );
+
+ if ( needsFlipping ) {
+ switch ( ps6Tag.type ) {
+
+ case kTIFF_ByteType:
+ case kTIFF_SByteType:
+ case kTIFF_ASCIIType:
+ // Nothing more to do.
+ break;
+
+ case kTIFF_ShortType:
+ case kTIFF_SShortType:
+ {
+ XMP_Uns16* u16Ptr = (XMP_Uns16*)voidPtr;
+ for ( size_t i = ps6Tag.count; i > 0; --i, ++u16Ptr ) Flip2 ( u16Ptr );
+ }
+ break;
+
+ case kTIFF_LongType:
+ case kTIFF_SLongType:
+ case kTIFF_FloatType:
+ {
+ XMP_Uns32* u32Ptr = (XMP_Uns32*)voidPtr;
+ for ( size_t i = ps6Tag.count; i > 0; --i, ++u32Ptr ) Flip4 ( u32Ptr );
+ }
+ break;
+
+ case kTIFF_RationalType:
+ case kTIFF_SRationalType:
+ {
+ XMP_Uns32* ratPtr = (XMP_Uns32*)voidPtr;
+ for ( size_t i = (2 * ps6Tag.count); i > 0; --i, ++ratPtr ) Flip4 ( ratPtr );
+ }
+ break;
+
+ case kTIFF_DoubleType:
+ {
+ XMP_Uns64* u64Ptr = (XMP_Uns64*)voidPtr;
+ for ( size_t i = ps6Tag.count; i > 0; --i, ++u64Ptr ) Flip8 ( u64Ptr );
+ }
+ break;
+
+ case kTIFF_UndefinedType:
+ // Fix up the few kinds of special tables that Exif 2.2 defines.
+ ok = true; // Keep everything that isn't a special table.
+ if ( ps6Tag.id == kTIFF_CFAPattern ) {
+ ok = FlipCFATable ( voidPtr, ps6Tag.dataLen, this->GetUns16 );
+ } else if ( ps6Tag.id == kTIFF_DeviceSettingDescription ) {
+ ok = FlipDSDTable ( voidPtr, ps6Tag.dataLen, this->GetUns16 );
+ } else if ( (ps6Tag.id == kTIFF_OECF) || (ps6Tag.id == kTIFF_SpatialFrequencyResponse) ) {
+ ok = FlipOECFSFRTable ( voidPtr, ps6Tag.dataLen, this->GetUns16 );
+ }
+ if ( ! ok ) this->DeleteTag ( ifd, ps6Tag.id );
+ break;
+
+ default:
+ // ? XMP_Throw ( "Unexpected tag type", kXMPErr_InternalFailure );
+ this->DeleteTag ( ifd, ps6Tag.id );
+ break;
+
+ }
+ }
+
+ }
+
+} // TIFF_FileWriter::ProcessPShop6IFD
+
+// =================================================================================================
+// TIFF_FileWriter::DetermineAppendInfo
+// ====================================
+
+#ifndef Trace_DetermineAppendInfo
+ #define Trace_DetermineAppendInfo 0
+#endif
+
+XMP_Uns32 TIFF_FileWriter::DetermineAppendInfo ( XMP_Uns32 appendedOrigin,
+ bool appendedIFDs[kTIFF_KnownIFDCount],
+ XMP_Uns32 newIFDOffsets[kTIFF_KnownIFDCount],
+ bool appendAll /* = false */ )
+{
+ XMP_Uns32 appendedLength = 0;
+ XMP_Assert ( (appendedOrigin & 1) == 0 ); // Make sure it is even.
+
+ #if Trace_DetermineAppendInfo
+ {
+ printf ( "\nEntering TIFF_FileWriter::DetermineAppendInfo%s\n", (appendAll ? ", append all" : "") );
+ for ( int ifd = 0; ifd < kTIFF_KnownIFDCount; ++ifd ) {
+ InternalIFDInfo & thisIFD = this->containedIFDs[ifd];
+ printf ( "\n IFD %d, origCount %d, map.size %d, origOffset %d (0x%X), origNextIFD %d (0x%X)",
+ ifd, thisIFD.origCount, thisIFD.tagMap.size(),
+ thisIFD.origOffset, thisIFD.origOffset, thisIFD.origNextIFD, thisIFD.origNextIFD );
+ if ( thisIFD.changed ) printf ( ", changed" );
+ if ( thisIFD.origCount < thisIFD.tagMap.size() ) printf ( ", should get appended" );
+ printf ( "\n" );
+ InternalTagMap::iterator tagPos;
+ InternalTagMap::iterator tagEnd = thisIFD.tagMap.end();
+ for ( tagPos = thisIFD.tagMap.begin(); tagPos != tagEnd; ++tagPos ) {
+ InternalTagInfo & thisTag = tagPos->second;
+ printf ( " Tag %d, dataOrOffset 0x%X, origLen %d, origOffset %d (0x%X)",
+ thisTag.id, thisTag.dataOrOffset, thisTag.origLen, thisTag.origOffset, thisTag.origOffset );
+ if ( thisTag.changed ) printf ( ", changed" );
+ if ( (thisTag.dataLen > thisTag.origLen) && (thisTag.dataLen > 4) ) printf ( ", should get appended" );
+ printf ( "\n" );
+ }
+ }
+ printf ( "\n" );
+ }
+ #endif
+
+ // Determine which of the IFDs will be appended. If the Exif, GPS, or Interoperability IFDs are
+ // appended, set dummy values for their offsets in the "owning" IFD. This must be done first
+ // since this might cause the owning IFD to grow.
+
+ if ( ! appendAll ) {
+ for ( int i = 0; i < kTIFF_KnownIFDCount ;++i ) appendedIFDs[i] = false;
+ } else {
+ for ( int i = 0; i < kTIFF_KnownIFDCount ;++i ) appendedIFDs[i] = (this->containedIFDs[i].tagMap.size() > 0);
+ }
+
+ appendedIFDs[kTIFF_InteropIFD] |= (this->containedIFDs[kTIFF_InteropIFD].origCount <
+ this->containedIFDs[kTIFF_InteropIFD].tagMap.size());
+ if ( appendedIFDs[kTIFF_InteropIFD] ) {
+ this->SetTag_Long ( kTIFF_ExifIFD, kTIFF_InteroperabilityIFDPointer, 0xABADABAD );
+ }
+
+ appendedIFDs[kTIFF_GPSInfoIFD] |= (this->containedIFDs[kTIFF_GPSInfoIFD].origCount <
+ this->containedIFDs[kTIFF_GPSInfoIFD].tagMap.size());
+ if ( appendedIFDs[kTIFF_GPSInfoIFD] ) {
+ this->SetTag_Long ( kTIFF_PrimaryIFD, kTIFF_GPSInfoIFDPointer, 0xABADABAD );
+ }
+
+ appendedIFDs[kTIFF_ExifIFD] |= (this->containedIFDs[kTIFF_ExifIFD].origCount <
+ this->containedIFDs[kTIFF_ExifIFD].tagMap.size());
+ if ( appendedIFDs[kTIFF_ExifIFD] ) {
+ this->SetTag_Long ( kTIFF_PrimaryIFD, kTIFF_ExifIFDPointer, 0xABADABAD );
+ }
+
+ appendedIFDs[kTIFF_TNailIFD] |= (this->containedIFDs[kTIFF_TNailIFD].origCount <
+ this->containedIFDs[kTIFF_TNailIFD].tagMap.size());
+
+ appendedIFDs[kTIFF_PrimaryIFD] |= (this->containedIFDs[kTIFF_PrimaryIFD].origCount <
+ this->containedIFDs[kTIFF_PrimaryIFD].tagMap.size());
+
+ // The appended data (if any) will be a sequence of an IFD followed by its large values.
+ // Determine the new offsets for the appended IFDs and tag values, and the total amount of
+ // appended stuff.
+
+ for ( int ifd = 0; ifd < kTIFF_KnownIFDCount ;++ifd ) {
+
+ InternalIFDInfo& ifdInfo ( this->containedIFDs[ifd] );
+ size_t tagCount = ifdInfo.tagMap.size();
+
+ if ( ! (appendAll | ifdInfo.changed) ) continue;
+ if ( tagCount == 0 ) continue;
+
+ newIFDOffsets[ifd] = ifdInfo.origOffset;
+ if ( appendedIFDs[ifd] ) {
+ newIFDOffsets[ifd] = appendedOrigin + appendedLength;
+ appendedLength += 6 + (12 * tagCount);
+ }
+
+ InternalTagMap::iterator tagPos = ifdInfo.tagMap.begin();
+ InternalTagMap::iterator tagEnd = ifdInfo.tagMap.end();
+
+ for ( ; tagPos != tagEnd; ++tagPos ) {
+
+ InternalTagInfo & currTag ( tagPos->second );
+ if ( (! (appendAll | currTag.changed)) || (currTag.dataLen <= 4) ) continue;
+
+ if ( (currTag.dataLen <= currTag.origLen) && (! appendAll) ) {
+ this->PutUns32 ( currTag.origOffset, &currTag.dataOrOffset ); // Reuse the old space.
+ } else {
+ this->PutUns32 ( (appendedOrigin + appendedLength), &currTag.dataOrOffset ); // Set the appended offset.
+ appendedLength += ((currTag.dataLen + 1) & 0xFFFFFFFEUL); // Round to an even size.
+ }
+
+ }
+
+ }
+
+ // If the Exif, GPS, or Interoperability IFDs get appended, update the tag values for their new offsets.
+
+ if ( appendedIFDs[kTIFF_ExifIFD] ) {
+ this->SetTag_Long ( kTIFF_PrimaryIFD, kTIFF_ExifIFDPointer, newIFDOffsets[kTIFF_ExifIFD] );
+ }
+ if ( appendedIFDs[kTIFF_GPSInfoIFD] ) {
+ this->SetTag_Long ( kTIFF_PrimaryIFD, kTIFF_GPSInfoIFDPointer, newIFDOffsets[kTIFF_GPSInfoIFD] );
+ }
+ if ( appendedIFDs[kTIFF_InteropIFD] ) {
+ this->SetTag_Long ( kTIFF_ExifIFD, kTIFF_InteroperabilityIFDPointer, newIFDOffsets[kTIFF_InteropIFD] );
+ }
+
+ #if Trace_DetermineAppendInfo
+ {
+ printf ( "Exiting TIFF_FileWriter::DetermineAppendInfo\n" );
+ for ( int ifd = 0; ifd < kTIFF_KnownIFDCount; ++ifd ) {
+ InternalIFDInfo & thisIFD = this->containedIFDs[ifd];
+ printf ( "\n IFD %d, origCount %d, map.size %d, origOffset %d (0x%X), origNextIFD %d (0x%X)",
+ ifd, thisIFD.origCount, thisIFD.tagMap.size(),
+ thisIFD.origOffset, thisIFD.origOffset, thisIFD.origNextIFD, thisIFD.origNextIFD );
+ if ( thisIFD.changed ) printf ( ", changed" );
+ if ( appendedIFDs[ifd] ) printf ( ", will be appended at %d (0x%X)", newIFDOffsets[ifd], newIFDOffsets[ifd] );
+ printf ( "\n" );
+ InternalTagMap::iterator tagPos;
+ InternalTagMap::iterator tagEnd = thisIFD.tagMap.end();
+ for ( tagPos = thisIFD.tagMap.begin(); tagPos != tagEnd; ++tagPos ) {
+ InternalTagInfo & thisTag = tagPos->second;
+ printf ( " Tag %d, dataOrOffset 0x%X, origLen %d, origOffset %d (0x%X)",
+ thisTag.id, thisTag.dataOrOffset, thisTag.origLen, thisTag.origOffset, thisTag.origOffset );
+ if ( thisTag.changed ) printf ( ", changed" );
+ if ( (thisTag.dataLen > thisTag.origLen) && (thisTag.dataLen > 4) ) {
+ XMP_Uns32 newOffset = this->GetUns32 ( &thisTag.dataOrOffset );
+ printf ( ", will be appended at %d (0x%X)", newOffset, newOffset );
+ }
+ printf ( "\n" );
+ }
+ }
+ printf ( "\n" );
+ }
+ #endif
+
+ return appendedLength;
+
+} // TIFF_FileWriter::DetermineAppendInfo
+
+// =================================================================================================
+// TIFF_FileWriter::UpdateMemByAppend
+// ==================================
+//
+// Normally we update TIFF in a conservative "by-append" manner. Changes are written in-place where
+// they fit, anything requiring growth is appended to the end and the old space is abandoned. The
+// end for memory-based TIFF is the end of the data block, the end for file-based TIFF is the end of
+// the file. This update-by-append model has the advantage of not perturbing any hidden offsets, a
+// common feature of proprietary MakerNotes.
+//
+// When doing the update-by-append we're only going to be modifying things that have changed. This
+// means IFDs with changed, added, or deleted tags, and large values for changed or added tags. The
+// IFDs and tag values are updated in-place if they fit, leaving holes in the stream if the new
+// value is smaller than the old.
+
+// ** Someday we might want to use the FreeOffsets and FreeByteCounts tags to track free space.
+// ** Probably not a huge win in practice though, and the TIFF spec says they are not recommended
+// ** for general interchange use.
+
+void TIFF_FileWriter::UpdateMemByAppend ( XMP_Uns8** newStream_out, XMP_Uns32* newLength_out,
+ bool appendAll /* = false */, XMP_Uns32 extraSpace /* = 0 */ )
+{
+ bool appendedIFDs[kTIFF_KnownIFDCount];
+ XMP_Uns32 newIFDOffsets[kTIFF_KnownIFDCount];
+ XMP_Uns32 appendedOrigin = ((this->tiffLength + 1) & 0xFFFFFFFEUL); // Start at an even offset.
+ XMP_Uns32 appendedLength = DetermineAppendInfo ( appendedOrigin, appendedIFDs, newIFDOffsets, appendAll );
+
+ // Allocate the new block of memory for the full stream. Copy the original stream. Write the
+ // modified IFDs and values. Finally rebuild the internal IFD info and tag map.
+
+ XMP_Uns32 newLength = appendedOrigin + appendedLength;
+ XMP_Uns8* newStream = (XMP_Uns8*) malloc ( newLength + extraSpace );
+ if ( newStream == 0 ) XMP_Throw ( "Out of memory", kXMPErr_NoMemory );
+
+ memcpy ( newStream, this->memStream, this->tiffLength ); // AUDIT: Safe, malloc'ed newLength bytes above.
+ if ( this->tiffLength < appendedOrigin ) {
+ XMP_Assert ( appendedOrigin == (this->tiffLength + 1) );
+ newStream[this->tiffLength] = 0; // Clear the pad byte.
+ }
+
+ try { // We might get exceptions from the next part and must delete newStream on the way out.
+
+ // Write the modified IFDs and values. Rewrite the full IFD from scratch to make sure the
+ // tags are now unique and sorted. Copy large changed values to their appropriate location.
+
+ XMP_Uns32 appendedOffset = appendedOrigin;
+
+ for ( int ifd = 0; ifd < kTIFF_KnownIFDCount; ++ifd ) {
+
+ InternalIFDInfo& ifdInfo ( this->containedIFDs[ifd] );
+ size_t tagCount = ifdInfo.tagMap.size();
+
+ if ( ! (appendAll | ifdInfo.changed) ) continue;
+ if ( tagCount == 0 ) continue;
+
+ XMP_Uns8* ifdPtr = newStream + newIFDOffsets[ifd];
+
+ if ( appendedIFDs[ifd] ) {
+ XMP_Assert ( newIFDOffsets[ifd] == appendedOffset );
+ appendedOffset += 6 + (12 * tagCount);
+ }
+
+ this->PutUns16 ( (XMP_Uns16)tagCount, ifdPtr );
+ ifdPtr += 2;
+
+ InternalTagMap::iterator tagPos = ifdInfo.tagMap.begin();
+ InternalTagMap::iterator tagEnd = ifdInfo.tagMap.end();
+
+ for ( ; tagPos != tagEnd; ++tagPos ) {
+
+ InternalTagInfo & currTag ( tagPos->second );
+
+ this->PutUns16 ( currTag.id, ifdPtr );
+ ifdPtr += 2;
+ this->PutUns16 ( currTag.type, ifdPtr );
+ ifdPtr += 2;
+ this->PutUns32 ( currTag.count, ifdPtr );
+ ifdPtr += 4;
+
+ *((XMP_Uns32*)ifdPtr) = currTag.dataOrOffset;
+
+ if ( (appendAll | currTag.changed) && (currTag.dataLen > 4) ) {
+
+ XMP_Uns32 valueOffset = this->GetUns32 ( &currTag.dataOrOffset );
+
+ if ( (currTag.dataLen <= currTag.origLen) && (! appendAll) ) {
+ XMP_Assert ( valueOffset == currTag.origOffset );
+ } else {
+ XMP_Assert ( valueOffset == appendedOffset );
+ appendedOffset += ((currTag.dataLen + 1) & 0xFFFFFFFEUL);
+ }
+
+ if ( currTag.dataLen > (newLength - valueOffset) ) XMP_Throw ( "Buffer overrun", kXMPErr_InternalFailure );
+ memcpy ( (newStream + valueOffset), currTag.dataPtr, currTag.dataLen ); // AUDIT: Protected by the above check.
+ if ( (currTag.dataLen & 1) != 0 ) newStream[valueOffset+currTag.dataLen] = 0;
+
+ }
+
+ ifdPtr += 4;
+
+ }
+
+ this->PutUns32 ( ifdInfo.origNextIFD, ifdPtr );
+ ifdPtr += 4;
+
+ }
+
+ XMP_Assert ( appendedOffset == newLength );
+
+ // Back fill the offsets for the primary and thumnbail IFDs, if they are now appended.
+
+ if ( appendedIFDs[kTIFF_PrimaryIFD] ) {
+ this->PutUns32 ( newIFDOffsets[kTIFF_PrimaryIFD], (newStream + 4) );
+ }
+
+ if ( appendedIFDs[kTIFF_TNailIFD] ) {
+ size_t primaryIFDCount = this->containedIFDs[kTIFF_PrimaryIFD].tagMap.size();
+ XMP_Uns32 tnailRefOffset = newIFDOffsets[kTIFF_PrimaryIFD] + 2 + (12 * primaryIFDCount);
+ this->PutUns32 ( newIFDOffsets[kTIFF_TNailIFD], (newStream + tnailRefOffset) );
+ }
+
+ } catch ( ... ) {
+
+ free ( newStream );
+ throw;
+
+ }
+
+ *newStream_out = newStream;
+ *newLength_out = newLength;
+
+} // TIFF_FileWriter::UpdateMemByAppend
+
+// =================================================================================================
+// TIFF_FileWriter::DetermineVisibleLength
+// =======================================
+
+XMP_Uns32 TIFF_FileWriter::DetermineVisibleLength()
+{
+ XMP_Uns32 visibleLength = 8; // Start with the TIFF header size.
+
+ for ( int ifd = 0; ifd < kTIFF_KnownIFDCount; ++ifd ) {
+
+ InternalIFDInfo& ifdInfo ( this->containedIFDs[ifd] );
+ size_t tagCount = ifdInfo.tagMap.size();
+ if ( tagCount == 0 ) continue;
+
+ visibleLength += 6 + (12 * tagCount);
+
+ InternalTagMap::iterator tagPos = ifdInfo.tagMap.begin();
+ InternalTagMap::iterator tagEnd = ifdInfo.tagMap.end();
+
+ for ( ; tagPos != tagEnd; ++tagPos ) {
+ InternalTagInfo & currTag ( tagPos->second );
+ if ( currTag.dataLen > 4 ) visibleLength += ((currTag.dataLen + 1) & 0xFFFFFFFE); // ! Round to even lengths.
+ }
+
+ }
+
+ return visibleLength;
+
+} // TIFF_FileWriter::DetermineVisibleLength
+
+// =================================================================================================
+// TIFF_FileWriter::UpdateMemByRewrite
+// ===================================
+//
+// Normally we update TIFF in a conservative "by-append" manner. Changes are written in-place where
+// they fit, anything requiring growth is appended to the end and the old space is abandoned. The
+// end for memory-based TIFF is the end of the data block, the end for file-based TIFF is the end of
+// the file. This update-by-append model has the advantage of not perturbing any hidden offsets, a
+// common feature of proprietary MakerNotes.
+//
+// The condenseStream parameter can be used to rewrite the full stream instead of appending. This
+// will discard any MakerNote tag and risks breaking offsets that are hidden. This can be necessary
+// though to try to make the TIFF fit in a JPEG file.
+//
+// We don't do most of the actual rewrite here. We set things up so that UpdateMemByAppend can be
+// called to append onto a bare TIFF header. Additional hidden offsets are then handled here.
+//
+// These tags are recognized as being hidden offsets when composing a condensed stream:
+// 273 - StripOffsets, lengths in tag 279
+// 288 - FreeOffsets, lengths in tag 289
+// 324 - TileOffsets, lengths in tag 325
+// 330 - SubIFDs, lengths within the IFDs (Plus subIFD values and possible chaining!)
+// 513 - JPEGInterchangeFormat, length in tag 514
+// 519 - JPEGQTables, each table is 64 bytes
+// 520 - JPEGDCTables, lengths ???
+// 521 - JPEGACTables, lengths ???
+// Some of these will handled and kept, some will be thrown out, some will cause the rewrite to fail.
+//
+// The hidden offsets for the Exif, GPS, and Interoperability IFDs (tags 34665, 34853, and 40965)
+// are handled by the code in DetermineAppendInfo, which is called from UpdateMemByAppend, which is
+// called from here.
+
+// ! So far, a memory-based TIFF rewrite would only be done for the Exif portion of a JPEG file.
+// ! In which case we're probably OK to handle JPEGInterchangeFormat (used for compressed thumbnails)
+// ! and complain about any of the other hidden offset tags.
+
+// tag count type
+
+// 273 n short or long
+// 279 n short or long
+// 288 n long
+// 289 n long
+// 324 n long
+// 325 n short or long
+
+// 330 n long
+
+// 513 1 long
+// 514 1 long
+
+// 519 n long
+// 520 n long
+// 521 n long
+
+static XMP_Uns16 kNoGoTags[] =
+ {
+ kTIFF_StripOffsets, // 273 *** Should be handled?
+ kTIFF_StripByteCounts, // 279 *** Should be handled?
+ kTIFF_FreeOffsets, // 288 *** Should be handled?
+ kTIFF_FreeByteCounts, // 289 *** Should be handled?
+ kTIFF_TileOffsets, // 324 *** Should be handled?
+ kTIFF_TileByteCounts, // 325 *** Should be handled?
+ kTIFF_SubIFDs, // 330 *** Should be handled?
+ kTIFF_JPEGQTables, // 519
+ kTIFF_JPEGDCTables, // 520
+ kTIFF_JPEGACTables, // 521
+ 0xFFFF // Must be last as a sentinel.
+ };
+
+static XMP_Uns16 kBanishedTags[] =
+ {
+ kTIFF_MakerNote, // *** Should someday support MakerNoteSafety.
+ 0xFFFF // Must be last as a sentinel.
+ };
+
+struct SimpleHiddenContentInfo {
+ XMP_Uns8 ifd;
+ XMP_Uns16 offsetTag, lengthTag;
+};
+
+struct SimpleHiddenContentLocations {
+ XMP_Uns32 length, oldOffset, newOffset;
+ SimpleHiddenContentLocations() : length(0), oldOffset(0), newOffset(0) {};
+};
+
+enum { kSimpleHiddenContentCount = 1 };
+
+static const SimpleHiddenContentInfo kSimpleHiddenContentInfo [kSimpleHiddenContentCount] =
+ {
+ { kTIFF_TNailIFD, kTIFF_JPEGInterchangeFormat, kTIFF_JPEGInterchangeFormatLength }
+ };
+
+// -------------------------------------------------------------------------------------------------
+
+void TIFF_FileWriter::UpdateMemByRewrite ( XMP_Uns8** newStream_out, XMP_Uns32* newLength_out )
+{
+ const InternalTagInfo* tagInfo;
+
+ // Check for tags that we don't tolerate because they have data we can't (or refuse to) find.
+
+ for ( XMP_Uns8 ifd = 0; ifd < kTIFF_KnownIFDCount; ++ifd ) {
+ for ( int i = 0; kNoGoTags[i] != 0xFFFF; ++i ) {
+ tagInfo = this->FindTagInIFD ( ifd, kNoGoTags[i] );
+ if ( tagInfo != 0 ) XMP_Throw ( "Tag not tolerated for TIFF rewrite", kXMPErr_Unimplemented );
+ }
+ }
+
+ // Delete unwanted tags.
+
+ for ( XMP_Uns8 ifd = 0; ifd < kTIFF_KnownIFDCount; ++ifd ) {
+ for ( int i = 0; kBanishedTags[i] != 0xFFFF; ++i ) {
+ this->DeleteTag ( ifd, kBanishedTags[i] );
+ }
+ }
+
+ // Make sure the "pointer" tags for the Exif, GPS, and Interop IFDs exist. The order is
+ // important, adding the Interop pointer can cause the Exif IFD to exist.
+
+ if ( ! this->containedIFDs[kTIFF_InteropIFD].tagMap.empty() ) {
+ this->SetTag_Long ( kTIFF_ExifIFD, kTIFF_InteroperabilityIFDPointer, 0xABADABAD );
+ }
+
+ if ( ! this->containedIFDs[kTIFF_GPSInfoIFD].tagMap.empty() ) {
+ this->SetTag_Long ( kTIFF_PrimaryIFD, kTIFF_GPSInfoIFDPointer, 0xABADABAD );
+ }
+
+ if ( ! this->containedIFDs[kTIFF_ExifIFD].tagMap.empty() ) {
+ this->SetTag_Long ( kTIFF_PrimaryIFD, kTIFF_ExifIFDPointer, 0xABADABAD );
+ }
+
+ // Determine the offsets and additional size for the hidden offset content. Set the offset tags
+ // to the new offset.
+
+ XMP_Uns32 hiddenContentLength = 0;
+ XMP_Uns32 hiddenContentOrigin = this->DetermineVisibleLength();
+
+ SimpleHiddenContentLocations hiddenLocations [kSimpleHiddenContentCount];
+
+ for ( int i = 0; i < kSimpleHiddenContentCount; ++i ) {
+
+ const SimpleHiddenContentInfo & hiddenInfo ( kSimpleHiddenContentInfo[i] );
+
+ bool haveLength = this->GetTag_Integer ( hiddenInfo.ifd, hiddenInfo.lengthTag, &hiddenLocations[i].length );
+ bool haveOffset = this->GetTag_Integer ( hiddenInfo.ifd, hiddenInfo.offsetTag, &hiddenLocations[i].oldOffset );
+ if ( haveLength != haveOffset ) XMP_Throw ( "Unpaired simple hidden content tag", kXMPErr_BadTIFF );
+ if ( (! haveLength) || (hiddenLocations[i].length == 0) ) continue;
+
+ hiddenLocations[i].newOffset = hiddenContentOrigin + hiddenContentLength;
+ this->SetTag_Long ( hiddenInfo.ifd, hiddenInfo.offsetTag, hiddenLocations[i].newOffset );
+ hiddenContentLength += ((hiddenLocations[i].length + 1) & 0xFFFFFFFE); // ! Round up for even offsets.
+
+ }
+
+ // Save any old memory stream for the content behind hidden offsets. Setup a bare TIFF header.
+
+ XMP_Uns8* oldStream = this->memStream;
+
+ XMP_Uns8 bareTIFF [8];
+ if ( this->bigEndian ) {
+ bareTIFF[0] = 0x4D; bareTIFF[1] = 0x4D; bareTIFF[2] = 0x00; bareTIFF[3] = 0x2A;
+ } else {
+ bareTIFF[0] = 0x49; bareTIFF[1] = 0x49; bareTIFF[2] = 0x2A; bareTIFF[3] = 0x00;
+ }
+ *((XMP_Uns32*)&bareTIFF[4]) = 0;
+
+ this->memStream = &bareTIFF[0];
+ this->tiffLength = sizeof ( bareTIFF );
+ this->ownedStream = false;
+
+ // Call UpdateMemByAppend to write the new stream, telling it to append everything.
+
+ this->UpdateMemByAppend ( newStream_out, newLength_out, true, hiddenContentLength );
+
+ // Copy the hidden content and update the output stream length;
+
+ XMP_Assert ( *newLength_out == hiddenContentOrigin );
+ *newLength_out += hiddenContentLength;
+
+ for ( int i = 0; i < kSimpleHiddenContentCount; ++i ) {
+
+ if ( hiddenLocations[i].length == 0 ) continue;
+
+ XMP_Uns8* srcPtr = oldStream + hiddenLocations[i].oldOffset;
+ XMP_Uns8* destPtr = *newStream_out + hiddenLocations[i].newOffset;
+ memcpy ( destPtr, srcPtr, hiddenLocations[i].length ); // AUDIT: Safe copy, not user data, computed length.
+
+ }
+
+} // TIFF_FileWriter::UpdateMemByRewrite
+
+// =================================================================================================
+// TIFF_FileWriter::UpdateMemoryStream
+// ===================================
+//
+// Normally we update TIFF in a conservative "by-append" manner. Changes are written in-place where
+// they fit, anything requiring growth is appended to the end and the old space is abandoned. The
+// end for memory-based TIFF is the end of the data block, the end for file-based TIFF is the end of
+// the file. This update-by-append model has the advantage of not perturbing any hidden offsets, a
+// common feature of proprietary MakerNotes.
+//
+// The condenseStream parameter can be used to rewrite the full stream instead of appending. This
+// will discard any MakerNote tags and risks breaking offsets that are hidden. This can be necessary
+// though to try to make the TIFF fit in a JPEG file.
+
+XMP_Uns32 TIFF_FileWriter::UpdateMemoryStream ( void** dataPtr, bool condenseStream /* = false */ )
+{
+ if ( this->fileParsed ) XMP_Throw ( "Not memory based", kXMPErr_EnforceFailure );
+
+ if ( ! this->changed ) {
+ if ( dataPtr != 0 ) *dataPtr = this->memStream;
+ return this->tiffLength;
+ }
+
+ bool nowEmpty = true;
+ for ( size_t i = 0; i < kTIFF_KnownIFDCount; ++i ) {
+ if ( ! this->containedIFDs[i].tagMap.empty() ) {
+ nowEmpty = false;
+ break;
+ }
+ }
+
+ XMP_Uns8* newStream = 0;
+ XMP_Uns32 newLength = 0;
+
+ if ( nowEmpty ) {
+
+ this->DeleteExistingInfo(); // Prepare for an empty reparse.
+
+ } else {
+
+ if ( this->tiffLength == 0 ) { // ! An empty parse does set this->memParsed.
+ condenseStream = true; // Makes "conjured" TIFF take the full rewrite path.
+ }
+
+ if ( condenseStream ) this->changed = true; // A prior regular call would have cleared this->changed.
+
+ if ( condenseStream ) {
+ this->UpdateMemByRewrite ( &newStream, &newLength );
+ } else {
+ this->UpdateMemByAppend ( &newStream, &newLength );
+ }
+
+ }
+
+ // Parse the revised stream. This is the cleanest way to rebuild the tag map.
+
+ this->ParseMemoryStream ( newStream, newLength, kDoNotCopyData );
+ this->ownedStream = true; // ! We really do own the stream.
+
+ if ( dataPtr != 0 ) *dataPtr = this->memStream;
+ return this->tiffLength;
+
+} // TIFF_FileWriter::UpdateMemoryStream
+
+// =================================================================================================
+// TIFF_FileWriter::UpdateFileStream
+// =================================
+//
+// Updating a file stream is done in the same general manner as updating a memory stream, the intro
+// comments for UpdateMemoryStream largely apply. The file update happens in 3 phases:
+// 1. Determine which IFDs will be appended, and the new offsets for the appended IFDs and tags.
+// 2. Do the in-place update for the IFDs and tag values that fit.
+// 3. Append the IFDs and tag values that grow.
+//
+// The file being updated must match the file that was previously parsed. Offsets and lengths saved
+// when parsing are used to decide if something can be updated in-place or must be appended.
+
+// *** The general linked structure of TIFF makes it very difficult to process the file in a single
+// *** sequential pass. This implementation uses a simple seek/write model for the in-place updates.
+// *** In the future we might want to consider creating a map of what gets updated, allowing use of
+// *** a possibly more efficient buffered model.
+
+// ** Someday we might want to use the FreeOffsets and FreeByteCounts tags to track free space.
+// ** Probably not a huge win in practice though, and the TIFF spec says they are not recommended
+// ** for general interchange use.
+
+#ifndef Trace_UpdateFileStream
+ #define Trace_UpdateFileStream 0
+#endif
+
+void TIFF_FileWriter::UpdateFileStream ( LFA_FileRef fileRef )
+{
+ if ( this->memParsed ) XMP_Throw ( "Not file based", kXMPErr_EnforceFailure );
+ if ( ! this->changed ) return;
+
+ XMP_Int64 origLength = LFA_Measure ( fileRef );
+ if ( (origLength >> 32) != 0 ) XMP_Throw ( "TIFF files can't exceed 4GB", kXMPErr_BadTIFF );
+
+ bool appendedIFDs[kTIFF_KnownIFDCount];
+ XMP_Uns32 newIFDOffsets[kTIFF_KnownIFDCount];
+
+ #if Trace_UpdateFileStream
+ printf ( "\nStarting update of TIFF file stream\n" );
+ #endif
+
+ XMP_Uns32 appendedOrigin = (XMP_Uns32)origLength;
+ if ( (appendedOrigin & 1) != 0 ) {
+ ++appendedOrigin; // Start at an even offset.
+ LFA_Seek ( fileRef, 0, SEEK_END );
+ LFA_Write ( fileRef, "\0", 1 );
+ }
+
+ XMP_Uns32 appendedLength = DetermineAppendInfo ( appendedOrigin, appendedIFDs, newIFDOffsets );
+ if ( appendedLength > (0xFFFFFFFFUL - appendedOrigin) ) XMP_Throw ( "TIFF files can't exceed 4GB", kXMPErr_BadTIFF );
+
+ // Do the in-place update for the IFDs and tag values that fit. This part does separate seeks
+ // and writes for the IFDs and values. Things to be updated can be anywhere in the file.
+
+ // *** This might benefit from a map of the in-place updates. This would allow use of a possibly
+ // *** more efficient sequential I/O model. Could even incorporate the safe update file copying.
+
+ for ( int ifd = 0; ifd < kTIFF_KnownIFDCount; ++ifd ) {
+
+ InternalIFDInfo & thisIFD = this->containedIFDs[ifd];
+ if ( ! thisIFD.changed ) continue;
+
+ // In order to get a little bit of locality, write the IFD first then the changed tags that
+ // have large values and fit in-place.
+
+ if ( ! appendedIFDs[ifd] ) {
+ #if Trace_UpdateFileStream
+ printf ( " Updating IFD %d in-place at offset %d (0x%X)\n", ifd, thisIFD.origOffset, thisIFD.origOffset );
+ #endif
+ LFA_Seek ( fileRef, thisIFD.origOffset, SEEK_SET );
+ this->WriteFileIFD ( fileRef, thisIFD );
+ }
+
+ InternalTagMap::iterator tagPos;
+ InternalTagMap::iterator tagEnd = thisIFD.tagMap.end();
+
+ for ( tagPos = thisIFD.tagMap.begin(); tagPos != tagEnd; ++tagPos ) {
+ InternalTagInfo & thisTag = tagPos->second;
+ if ( (! thisTag.changed) || (thisTag.dataLen <= 4) || (thisTag.dataLen > thisTag.origLen) ) continue;
+ #if Trace_UpdateFileStream
+ printf ( " Updating tag %d in IFD %d in-place at offset %d (0x%X)\n", thisTag.id, ifd, thisTag.origOffset, thisTag.origOffset );
+ #endif
+ LFA_Seek ( fileRef, thisTag.origOffset, SEEK_SET );
+ LFA_Write ( fileRef, thisTag.dataPtr, thisTag.dataLen );
+ }
+
+ }
+
+ // Append the IFDs and tag values that grow.
+
+ XMP_Int64 fileEnd = LFA_Seek ( fileRef, 0, SEEK_END );
+ XMP_Assert ( fileEnd == appendedOrigin );
+
+ for ( int ifd = 0; ifd < kTIFF_KnownIFDCount; ++ifd ) {
+
+ InternalIFDInfo & thisIFD = this->containedIFDs[ifd];
+ if ( ! thisIFD.changed ) continue;
+
+ if ( appendedIFDs[ifd] ) {
+ #if Trace_UpdateFileStream
+ printf ( " Updating IFD %d by append at offset %d (0x%X)\n", ifd, newIFDOffsets[ifd], newIFDOffsets[ifd] );
+ #endif
+ XMP_Assert ( newIFDOffsets[ifd] == LFA_Measure(fileRef) );
+ this->WriteFileIFD ( fileRef, thisIFD );
+ }
+
+ InternalTagMap::iterator tagPos;
+ InternalTagMap::iterator tagEnd = thisIFD.tagMap.end();
+
+ for ( tagPos = thisIFD.tagMap.begin(); tagPos != tagEnd; ++tagPos ) {
+ InternalTagInfo & thisTag = tagPos->second;
+ if ( (! thisTag.changed) || (thisTag.dataLen <= 4) || (thisTag.dataLen <= thisTag.origLen) ) continue;
+ #if Trace_UpdateFileStream
+ XMP_Uns32 newOffset = this->GetUns32(&thisTag.dataOrOffset);
+ printf ( " Updating tag %d in IFD %d by append at offset %d (0x%X)\n", thisTag.id, ifd, newOffset, newOffset );
+ #endif
+ XMP_Assert ( this->GetUns32(&thisTag.dataOrOffset) == LFA_Measure(fileRef) );
+ LFA_Write ( fileRef, thisTag.dataPtr, thisTag.dataLen );
+ if ( (thisTag.dataLen & 1) != 0 ) LFA_Write ( fileRef, "\0", 1 );
+ }
+
+ }
+
+ // Back-fill the offsets for the primary and thumnbail IFDs, if they are now appended.
+
+ XMP_Uns32 newOffset;
+
+ if ( appendedIFDs[kTIFF_PrimaryIFD] ) {
+ this->PutUns32 ( newIFDOffsets[kTIFF_PrimaryIFD], &newOffset );
+ #if TraceUpdateFileStream
+ printf ( " Back-filling offset of primary IFD, pointing to %d (0x%X)\n", newOffset, newOffset );
+ #endif
+ LFA_Seek ( fileRef, 4, SEEK_SET );
+ LFA_Write ( fileRef, &newOffset, 4 );
+ }
+
+ InternalIFDInfo & primaryIFD = this->containedIFDs[kTIFF_PrimaryIFD];
+ InternalIFDInfo & tnailIFD = this->containedIFDs[kTIFF_TNailIFD];
+
+ if ( appendedIFDs[kTIFF_TNailIFD] && (primaryIFD.origNextIFD == tnailIFD.origOffset) ) {
+
+ size_t primaryIFDCount = primaryIFD.tagMap.size();
+ XMP_Uns32 tnailRefOffset = newIFDOffsets[kTIFF_PrimaryIFD] + 2 + (12 * primaryIFDCount);
+
+ this->PutUns32 ( newIFDOffsets[kTIFF_TNailIFD], &newOffset );
+ #if TraceUpdateFileStream
+ printf ( " Back-filling offset of thumbnail IFD, offset at %d (0x%X), pointing to %d (0x%X)\n",
+ tnailRefOffset, tnailRefOffset, newOffset, newOffset );
+ #endif
+ LFA_Seek ( fileRef, tnailRefOffset, SEEK_SET );
+ LFA_Write ( fileRef, &newOffset, 4 );
+
+ primaryIFD.origNextIFD = newIFDOffsets[kTIFF_TNailIFD]; // ! Ought to be below, easier here.
+
+ }
+
+ // Reset the changed flags and original length/offset values. This simulates a reparse of the
+ // updated file.
+
+ for ( int ifd = 0; ifd < kTIFF_KnownIFDCount; ++ifd ) {
+
+ InternalIFDInfo & thisIFD = this->containedIFDs[ifd];
+ if ( ! thisIFD.changed ) continue;
+
+ thisIFD.changed = false;
+ thisIFD.origCount = thisIFD.tagMap.size();
+ thisIFD.origOffset = newIFDOffsets[ifd];
+
+ InternalTagMap::iterator tagPos;
+ InternalTagMap::iterator tagEnd = thisIFD.tagMap.end();
+
+ for ( tagPos = thisIFD.tagMap.begin(); tagPos != tagEnd; ++tagPos ) {
+ InternalTagInfo & thisTag = tagPos->second;
+ if ( ! thisTag.changed ) continue;
+ thisTag.changed = false;
+ thisTag.origLen = thisTag.dataLen;
+ if ( thisTag.origLen > 4 ) thisTag.origOffset = this->GetUns32 ( &thisTag.dataOrOffset );
+ }
+
+ }
+
+ this->tiffLength = (XMP_Uns32) LFA_Measure ( fileRef );
+ LFA_Seek ( fileRef, 0, SEEK_END ); // Can't hurt.
+
+ #if Trace_UpdateFileStream
+ printf ( "\nFinished update of TIFF file stream\n" );
+ #endif
+
+} // TIFF_FileWriter::UpdateFileStream
+
+// =================================================================================================
+// TIFF_FileWriter::WriteFileIFD
+// =============================
+
+void TIFF_FileWriter::WriteFileIFD ( LFA_FileRef fileRef, InternalIFDInfo & thisIFD )
+{
+ XMP_Uns16 tagCount;
+ this->PutUns16 ( thisIFD.tagMap.size(), &tagCount );
+ LFA_Write ( fileRef, &tagCount, 2 );
+
+ InternalTagMap::iterator tagPos;
+ InternalTagMap::iterator tagEnd = thisIFD.tagMap.end();
+
+ for ( tagPos = thisIFD.tagMap.begin(); tagPos != tagEnd; ++tagPos ) {
+
+ InternalTagInfo & thisTag = tagPos->second;
+ RawIFDEntry ifdEntry;
+
+ this->PutUns16 ( thisTag.id, &ifdEntry.id );
+ this->PutUns16 ( thisTag.type, &ifdEntry.type );
+ this->PutUns32 ( thisTag.count, &ifdEntry.count );
+ ifdEntry.dataOrOffset = thisTag.dataOrOffset; // ! Already in stream endianness.
+
+ LFA_Write ( fileRef, &ifdEntry, sizeof(ifdEntry) );
+ XMP_Assert ( sizeof(ifdEntry) == 12 );
+
+ }
+
+ XMP_Uns32 nextIFD;
+ this->PutUns32 ( thisIFD.origNextIFD, &nextIFD );
+ LFA_Write ( fileRef, &nextIFD, 4 );
+
+} // TIFF_FileWriter::WriteFileIFD
diff --git a/source/XMPFiles/FormatSupport/TIFF_MemoryReader.cpp b/source/XMPFiles/FormatSupport/TIFF_MemoryReader.cpp
new file mode 100644
index 0000000..d511083
--- /dev/null
+++ b/source/XMPFiles/FormatSupport/TIFF_MemoryReader.cpp
@@ -0,0 +1,610 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "TIFF_Support.hpp"
+
+// =================================================================================================
+/// \file TIFF_MemoryReader.cpp
+/// \brief Implementation of the memory-based read-only TIFF_Manager.
+///
+/// The read-only forms of TIFF_Manager are derived from TIFF_Reader. The GetTag methods are common
+/// implementations in TIFF_Reader. The parsing code is different in the TIFF_MemoryReader and
+/// TIFF_FileReader constructors. There are also separate destructors to release captured info.
+///
+/// The read-only implementations use runtime data that is simple tweaks on the stored form. The
+/// memory-based reader has one block of data for the whole TIFF stream. The file-based reader has
+/// one for each IFD, plus one for the collected non-local data for each IFD. Otherwise the logic
+/// is the same in both cases.
+///
+/// The count for each IFD is extracted and a pointer set to the first entry in each IFD (serving as
+/// a normal C array pointer). The IFD entries are tweaked as follows:
+///
+/// \li The id and type fields are converted to native values.
+/// \li The count field is converted to a native byte count.
+/// \li If the data is not inline the offset is converted to a pointer.
+///
+/// The tag values, whether inline or not, are not converted to native values. The values returned
+/// from the GetTag methods are converted on the fly. The id, type, and count fields are easier to
+/// convert because their types are fixed. They are used more, and more valuable to convert.
+// =================================================================================================
+
+// =================================================================================================
+// TIFF_MemoryReader::SortIFD
+// ==========================
+//
+// Does a fairly simple minded insertion-like sort. This sort is not going to be optimal for edge
+// cases like and IFD with lots of duplicates.
+
+// *** Might be better done using read and write pointers and two loops. The first loop moves out
+// *** of order tags by a modified bubble sort, shifting the middle down one at a time in the loop.
+// *** The first loop stops when a duplicate is hit. The second loop continues by moving the tail
+// *** entries up to the appropriate slot.
+
+void TIFF_MemoryReader::SortIFD ( TweakedIFDInfo* thisIFD )
+{
+
+ XMP_Uns16 tagCount = thisIFD->count;
+ TweakedIFDEntry* ifdEntries = thisIFD->entries;
+ XMP_Uns16 prevTag = ifdEntries[0].id;
+
+ for ( size_t i = 1; i < tagCount; ++i ) {
+
+ XMP_Uns16 thisTag = ifdEntries[i].id;
+
+ if ( thisTag > prevTag ) {
+
+ // In proper order.
+ prevTag = thisTag;
+
+ } else if ( thisTag == prevTag ) {
+
+ // Duplicate tag, keep the 2nd copy, move the tail of the array up, prevTag is unchanged.
+ memcpy ( &ifdEntries[i-1], &ifdEntries[i], 12*(tagCount-i) ); // AUDIT: Safe, moving tail forward, i >= 1.
+ --tagCount;
+ --i; // ! Don't move forward in the array, we've moved the unseen part up.
+
+ } else if ( thisTag < prevTag ) {
+
+ // Out of order, move this tag up, prevTag is unchanged. Might still be a duplicate!
+ XMP_Int32 j; // ! Need a signed value.
+ for ( j = i-1; j >= 0; --j ) {
+ if ( ifdEntries[j].id <= thisTag ) break;
+ }
+
+ if ( (j >= 0) && (ifdEntries[j].id == thisTag) ) {
+
+ // Out of order duplicate, move it to position j, move the tail of the array up.
+ ifdEntries[j] = ifdEntries[i];
+ memcpy ( &ifdEntries[i], &ifdEntries[i+1], 12*(tagCount-(i+1)) ); // AUDIT: Safe, moving tail forward, i >= 1.
+ --tagCount;
+ --i; // ! Don't move forward in the array, we've moved the unseen part up.
+
+ } else {
+
+ // Move the out of order entry to position j+1, move the middle of the array down.
+ TweakedIFDEntry temp = ifdEntries[i];
+ ++j; // ! So the insertion index becomes j.
+ memcpy ( &ifdEntries[j+1], &ifdEntries[j], 12*(i-j) ); // AUDIT: Safe, moving less than i entries to a location before i.
+ ifdEntries[j] = temp;
+
+ }
+
+ }
+
+ }
+
+ thisIFD->count = tagCount; // Save the final count.
+
+} // TIFF_MemoryReader::SortIFD
+
+// =================================================================================================
+// TIFF_MemoryReader::GetIFD
+// =========================
+
+bool TIFF_MemoryReader::GetIFD ( XMP_Uns8 ifd, TagInfoMap* ifdMap ) const
+{
+ if ( ifd > kTIFF_LastRealIFD ) XMP_Throw ( "Invalid IFD requested", kXMPErr_InternalFailure );
+ const TweakedIFDInfo* thisIFD = &containedIFDs[ifd];
+
+ if ( ifdMap != 0 ) ifdMap->clear();
+ if ( thisIFD->count == 0 ) return false;
+
+ if ( ifdMap != 0 ) {
+
+ for ( size_t i = 0; i < thisIFD->count; ++i ) {
+
+ TweakedIFDEntry* thisTag = &(thisIFD->entries[i]);
+
+ TagInfo info ( thisTag->id, thisTag->type, 0, 0, thisTag->bytes );
+ info.count = info.dataLen / kTIFF_TypeSizes[info.type];
+ if ( info.dataLen <= 4 ) {
+ info.dataPtr = &(thisTag->dataOrPtr);
+ } else {
+ info.dataPtr = (const void*)(thisTag->dataOrPtr);
+ }
+
+ (*ifdMap)[info.id] = info;
+
+ }
+
+ }
+
+ return true;
+
+} // TIFF_MemoryReader::GetIFD
+
+// =================================================================================================
+// TIFF_MemoryReader::FindTagInIFD
+// ===============================
+
+const TIFF_MemoryReader::TweakedIFDEntry* TIFF_MemoryReader::FindTagInIFD ( XMP_Uns8 ifd, XMP_Uns16 id ) const
+{
+ if ( ifd == kTIFF_KnownIFD ) {
+ // ... lookup the tag in the known tag map
+ }
+
+ if ( ifd > kTIFF_LastRealIFD ) XMP_Throw ( "Invalid IFD requested", kXMPErr_InternalFailure );
+ const TweakedIFDInfo* thisIFD = &containedIFDs[ifd];
+
+ if ( thisIFD->count == 0 ) return 0;
+
+ XMP_Uns32 spanLength = thisIFD->count;
+ const TweakedIFDEntry* spanBegin = &(thisIFD->entries[0]);
+
+ while ( spanLength > 1 ) {
+
+ XMP_Uns32 halfLength = spanLength >> 1; // Since spanLength > 1, halfLength > 0.
+ const TweakedIFDEntry* spanMiddle = spanBegin + halfLength;
+
+ // There are halfLength entries below spanMiddle, then the spanMiddle entry, then
+ // spanLength-halfLength-1 entries above spanMiddle (which can be none).
+
+ if ( spanMiddle->id == id ) {
+ spanBegin = spanMiddle;
+ break;
+ } else if ( spanMiddle->id > id ) {
+ spanLength = halfLength; // Discard the middle.
+ } else {
+ spanBegin = spanMiddle; // Keep a valid spanBegin for the return check, don't use spanMiddle+1.
+ spanLength -= halfLength;
+ }
+
+ }
+
+ if ( spanBegin->id != id ) spanBegin = 0;
+ return spanBegin;
+
+} // TIFF_MemoryReader::FindTagInIFD
+
+// =================================================================================================
+// TIFF_MemoryReader::GetValueOffset
+// =================================
+
+XMP_Uns32 TIFF_MemoryReader::GetValueOffset ( XMP_Uns8 ifd, XMP_Uns16 id ) const
+{
+ const TweakedIFDEntry* thisTag = this->FindTagInIFD ( ifd, id );
+ if ( thisTag == 0 ) return 0;
+
+ XMP_Uns8 * valuePtr = (XMP_Uns8*) thisTag->dataOrPtr;
+ if ( thisTag->bytes <= 4 ) valuePtr = (XMP_Uns8*) &(thisTag->dataOrPtr);
+
+ return (valuePtr - this->tiffStream);
+
+} // TIFF_MemoryReader::GetValueOffset
+
+// =================================================================================================
+// TIFF_MemoryReader::GetTag
+// =========================
+
+bool TIFF_MemoryReader::GetTag ( XMP_Uns8 ifd, XMP_Uns16 id, TagInfo* info ) const
+{
+ const TweakedIFDEntry* thisTag = this->FindTagInIFD ( ifd, id );
+ if ( thisTag == 0 ) return false;
+
+ if ( info != 0 ) {
+
+ info->id = thisTag->id;
+ info->type = thisTag->type;
+ info->count = thisTag->bytes / kTIFF_TypeSizes[thisTag->type];
+ info->dataLen = thisTag->bytes;
+
+ if ( thisTag->bytes <= 4 ) {
+ info->dataPtr = &(thisTag->dataOrPtr);
+ } else {
+ info->dataPtr = (const void*)(thisTag->dataOrPtr);
+ }
+
+ }
+
+ return true;
+
+} // TIFF_MemoryReader::GetTag
+
+// =================================================================================================
+// TIFF_MemoryReader::GetTag_Integer
+// =================================
+
+bool TIFF_MemoryReader::GetTag_Integer ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns32* data ) const
+{
+ const TweakedIFDEntry* thisTag = this->FindTagInIFD ( ifd, id );
+ if ( thisTag == 0 ) return false;
+
+ if ( data != 0 ) {
+ if ( thisTag->type == kTIFF_ShortType ) {
+ if ( thisTag->bytes != 2 ) return false; // Wrong count.
+ *data = this->GetUns16 ( &(thisTag->dataOrPtr) );
+ } else if ( thisTag->type == kTIFF_LongType ) {
+ if ( thisTag->bytes != 4 ) return false; // Wrong count.
+ *data = this->GetUns32 ( &(thisTag->dataOrPtr) );
+ } else {
+ return false;
+ }
+ }
+
+ return true;
+
+} // TIFF_MemoryReader::GetTag_Integer
+
+// =================================================================================================
+// TIFF_MemoryReader::GetTag_Byte
+// ==============================
+
+bool TIFF_MemoryReader::GetTag_Byte ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns8* data ) const
+{
+ const TweakedIFDEntry* thisTag = this->FindTagInIFD ( ifd, id );
+ if ( thisTag == 0 ) return false;
+ if ( (thisTag->type != kTIFF_ByteType) || (thisTag->bytes != 1) ) return false;
+
+ if ( data != 0 ) {
+ *data = * ( (XMP_Uns8*) (&(thisTag->dataOrPtr)) );
+ }
+
+ return true;
+
+} // TIFF_MemoryReader::GetTag_Byte
+
+// =================================================================================================
+// TIFF_MemoryReader::GetTag_SByte
+// ===============================
+
+bool TIFF_MemoryReader::GetTag_SByte ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Int8* data ) const
+{
+ const TweakedIFDEntry* thisTag = this->FindTagInIFD ( ifd, id );
+ if ( thisTag == 0 ) return false;
+ if ( (thisTag->type != kTIFF_SByteType) || (thisTag->bytes != 1) ) return false;
+
+ if ( data != 0 ) {
+ *data = * ( (XMP_Int8*) (&(thisTag->dataOrPtr)) );
+ }
+
+ return true;
+
+} // TIFF_MemoryReader::GetTag_SByte
+
+// =================================================================================================
+// TIFF_MemoryReader::GetTag_Short
+// ===============================
+
+bool TIFF_MemoryReader::GetTag_Short ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns16* data ) const
+{
+ const TweakedIFDEntry* thisTag = this->FindTagInIFD ( ifd, id );
+ if ( thisTag == 0 ) return false;
+ if ( (thisTag->type != kTIFF_ShortType) || (thisTag->bytes != 2) ) return false;
+
+ if ( data != 0 ) {
+ *data = this->GetUns16 ( &(thisTag->dataOrPtr) );
+ }
+
+ return true;
+
+} // TIFF_MemoryReader::GetTag_Short
+
+// =================================================================================================
+// TIFF_MemoryReader::GetTag_SShort
+// ================================
+
+bool TIFF_MemoryReader::GetTag_SShort ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Int16* data ) const
+{
+ const TweakedIFDEntry* thisTag = this->FindTagInIFD ( ifd, id );
+ if ( thisTag == 0 ) return false;
+ if ( (thisTag->type != kTIFF_SShortType) || (thisTag->bytes != 2) ) return false;
+
+ if ( data != 0 ) {
+ *data = (XMP_Int16) this->GetUns16 ( &(thisTag->dataOrPtr) );
+ }
+
+ return true;
+
+} // TIFF_MemoryReader::GetTag_SShort
+
+// =================================================================================================
+// TIFF_MemoryReader::GetTag_Long
+// ==============================
+
+bool TIFF_MemoryReader::GetTag_Long ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns32* data ) const
+{
+ const TweakedIFDEntry* thisTag = this->FindTagInIFD ( ifd, id );
+ if ( thisTag == 0 ) return false;
+ if ( (thisTag->type != kTIFF_LongType) || (thisTag->bytes != 4) ) return false;
+
+ if ( data != 0 ) {
+ *data = this->GetUns32 ( &(thisTag->dataOrPtr) );
+ }
+
+ return true;
+
+} // TIFF_MemoryReader::GetTag_Long
+
+// =================================================================================================
+// TIFF_MemoryReader::GetTag_SLong
+// ===============================
+
+bool TIFF_MemoryReader::GetTag_SLong ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Int32* data ) const
+{
+ const TweakedIFDEntry* thisTag = this->FindTagInIFD ( ifd, id );
+ if ( thisTag == 0 ) return false;
+ if ( (thisTag->type != kTIFF_SLongType) || (thisTag->bytes != 4) ) return false;
+
+ if ( data != 0 ) {
+ *data = (XMP_Int32) this->GetUns32 ( &(thisTag->dataOrPtr) );
+ }
+
+ return true;
+
+} // TIFF_MemoryReader::GetTag_SLong
+
+// =================================================================================================
+// TIFF_MemoryReader::GetTag_Rational
+// ==================================
+
+bool TIFF_MemoryReader::GetTag_Rational ( XMP_Uns8 ifd, XMP_Uns16 id, Rational* data ) const
+{
+ const TweakedIFDEntry* thisTag = this->FindTagInIFD ( ifd, id );
+ if ( thisTag == 0 ) return false;
+ if ( (thisTag->type != kTIFF_RationalType) || (thisTag->bytes != 8) ) return false;
+
+ if ( data != 0 ) {
+ XMP_Uns32* dataPtr = (XMP_Uns32*)thisTag->dataOrPtr;
+ data->num = this->GetUns32 ( dataPtr );
+ data->denom = this->GetUns32 ( dataPtr+1 );
+ }
+
+ return true;
+
+} // TIFF_MemoryReader::GetTag_Rational
+
+// =================================================================================================
+// TIFF_MemoryReader::GetTag_SRational
+// ===================================
+
+bool TIFF_MemoryReader::GetTag_SRational ( XMP_Uns8 ifd, XMP_Uns16 id, SRational* data ) const
+{
+ const TweakedIFDEntry* thisTag = this->FindTagInIFD ( ifd, id );
+ if ( thisTag == 0 ) return false;
+ if ( (thisTag->type != kTIFF_SRationalType) || (thisTag->bytes != 8) ) return false;
+
+ if ( data != 0 ) {
+ XMP_Uns32* dataPtr = (XMP_Uns32*)thisTag->dataOrPtr;
+ data->num = (XMP_Int32) this->GetUns32 ( dataPtr );
+ data->denom = (XMP_Int32) this->GetUns32 ( dataPtr+1 );
+ }
+
+ return true;
+
+} // TIFF_MemoryReader::GetTag_SRational
+
+// =================================================================================================
+// TIFF_MemoryReader::GetTag_Float
+// ===============================
+
+bool TIFF_MemoryReader::GetTag_Float ( XMP_Uns8 ifd, XMP_Uns16 id, float* data ) const
+{
+ const TweakedIFDEntry* thisTag = this->FindTagInIFD ( ifd, id );
+ if ( thisTag == 0 ) return false;
+ if ( (thisTag->type != kTIFF_FloatType) || (thisTag->bytes != 4) ) return false;
+
+ if ( data != 0 ) {
+ *data = this->GetFloat ( &(thisTag->dataOrPtr) );
+ }
+
+ return true;
+
+} // TIFF_MemoryReader::GetTag_Float
+
+// =================================================================================================
+// TIFF_MemoryReader::GetTag_Double
+// ================================
+
+bool TIFF_MemoryReader::GetTag_Double ( XMP_Uns8 ifd, XMP_Uns16 id, double* data ) const
+{
+ const TweakedIFDEntry* thisTag = this->FindTagInIFD ( ifd, id );
+ if ( thisTag == 0 ) return false;
+ if ( (thisTag->type != kTIFF_DoubleType) || (thisTag->bytes != 8) ) return false;
+
+ if ( data != 0 ) {
+ double* dataPtr = (double*)thisTag->dataOrPtr;
+ *data = this->GetDouble ( dataPtr );
+ }
+
+ return true;
+
+} // TIFF_MemoryReader::GetTag_Double
+
+// =================================================================================================
+// TIFF_MemoryReader::GetTag_ASCII
+// ===============================
+
+bool TIFF_MemoryReader::GetTag_ASCII ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_StringPtr* dataPtr, XMP_StringLen* dataLen ) const
+{
+ const TweakedIFDEntry* thisTag = this->FindTagInIFD ( ifd, id );
+ if ( thisTag == 0 ) return false;
+ if ( thisTag->type != kTIFF_ASCIIType ) return false;
+
+ if ( dataPtr != 0 ) {
+ *dataPtr = (XMP_StringPtr)thisTag->dataOrPtr;
+ if ( thisTag->bytes <= 4 ) *dataPtr = (XMP_StringPtr)(&thisTag->dataOrPtr);
+ }
+
+ if ( dataLen != 0 ) *dataLen = thisTag->bytes;
+
+ return true;
+
+} // TIFF_MemoryReader::GetTag_ASCII
+
+// =================================================================================================
+// TIFF_MemoryReader::GetTag_EncodedString
+// =======================================
+
+bool TIFF_MemoryReader::GetTag_EncodedString ( XMP_Uns8 ifd, XMP_Uns16 id, std::string* utf8Str ) const
+{
+ const TweakedIFDEntry* thisTag = this->FindTagInIFD ( ifd, id );
+ if ( thisTag == 0 ) return false;
+ if ( thisTag->type != kTIFF_UndefinedType ) return false;
+
+ if ( utf8Str == 0 ) return true; // Return true if the converted string is not wanted.
+
+ bool ok = this->DecodeString ( (void*)thisTag->dataOrPtr, thisTag->bytes, utf8Str );
+ return ok;
+
+} // TIFF_MemoryReader::GetTag_EncodedString
+
+// =================================================================================================
+// TIFF_MemoryReader::ParseMemoryStream
+// ====================================
+
+// *** Need to tell TIFF/Exif from TIFF/EP, DNG files are the latter.
+
+void TIFF_MemoryReader::ParseMemoryStream ( const void* data, XMP_Uns32 length, bool copyData /* = true */ )
+{
+ // Get rid of any current TIFF.
+
+ if ( this->ownedStream ) free ( this->tiffStream );
+ this->ownedStream = false;
+ this->tiffStream = 0;
+ this->tiffLength = 0;
+
+ for ( size_t i = 0; i < kTIFF_KnownIFDCount; ++i ) {
+ this->containedIFDs[i].count = 0;
+ this->containedIFDs[i].entries = 0;
+ }
+
+ if ( length == 0 ) return;
+
+ // Allocate space for the full in-memory stream and copy it.
+
+ if ( ! copyData ) {
+ XMP_Assert ( ! this->ownedStream );
+ this->tiffStream = (XMP_Uns8*) data;
+ } else {
+ if ( length > 100*1024*1024 ) XMP_Throw ( "Outrageous length for memory-based TIFF", kXMPErr_BadTIFF );
+ this->tiffStream = (XMP_Uns8*) malloc(length);
+ if ( this->tiffStream == 0 ) XMP_Throw ( "Out of memory", kXMPErr_NoMemory );
+ memcpy ( this->tiffStream, data, length ); // AUDIT: Safe, malloc'ed length bytes above.
+ this->ownedStream = true;
+ }
+
+ this->tiffLength = length;
+
+ // Find and process the primary, Exif, GPS, and Interoperability IFDs.
+
+ XMP_Uns32 primaryIFDOffset = this->CheckTIFFHeader ( this->tiffStream, length );
+ XMP_Uns32 tnailIFDOffset = 0;
+
+ if ( primaryIFDOffset != 0 ) tnailIFDOffset = this->ProcessOneIFD ( primaryIFDOffset, kTIFF_PrimaryIFD );
+
+ const TweakedIFDEntry* exifIFDTag = this->FindTagInIFD ( kTIFF_PrimaryIFD, kTIFF_ExifIFDPointer );
+ if ( (exifIFDTag != 0) && (exifIFDTag->type == kTIFF_LongType) && (exifIFDTag->bytes == 4) ) {
+ XMP_Uns32 exifOffset = this->GetUns32 ( &exifIFDTag->dataOrPtr );
+ (void) this->ProcessOneIFD ( exifOffset, kTIFF_ExifIFD );
+ }
+
+ const TweakedIFDEntry* gpsIFDTag = this->FindTagInIFD ( kTIFF_PrimaryIFD, kTIFF_GPSInfoIFDPointer );
+ if ( (gpsIFDTag != 0) && (gpsIFDTag->type == kTIFF_LongType) && (gpsIFDTag->bytes == 4) ) {
+ XMP_Uns32 gpsOffset = this->GetUns32 ( &gpsIFDTag->dataOrPtr );
+ (void) this->ProcessOneIFD ( gpsOffset, kTIFF_GPSInfoIFD );
+ }
+
+ const TweakedIFDEntry* interopIFDTag = this->FindTagInIFD ( kTIFF_ExifIFD, kTIFF_InteroperabilityIFDPointer );
+ if ( (interopIFDTag != 0) && (interopIFDTag->type == kTIFF_LongType) && (interopIFDTag->bytes == 4) ) {
+ XMP_Uns32 interopOffset = this->GetUns32 ( &interopIFDTag->dataOrPtr );
+ (void) this->ProcessOneIFD ( interopOffset, kTIFF_InteropIFD );
+ }
+
+ // Process the thumbnail IFD. We only do this for Exif-compliant TIFF streams. Extract the
+ // JPEG thumbnail image pointer (tag 513) for later use by GetTNailInfo.
+
+ if ( (tnailIFDOffset != 0) && (this->containedIFDs[kTIFF_ExifIFD].count > 0) ) {
+ (void) this->ProcessOneIFD ( tnailIFDOffset, kTIFF_TNailIFD );
+ const TweakedIFDEntry* jpegInfo = FindTagInIFD ( kTIFF_TNailIFD, kTIFF_JPEGInterchangeFormat );
+ if ( jpegInfo != 0 ) {
+ XMP_Uns32 tnailImageOffset = this->GetUns32 ( &jpegInfo->dataOrPtr );
+ this->jpegTNailPtr = (XMP_Uns8*)this->tiffStream + tnailImageOffset;
+ }
+ }
+
+} // TIFF_MemoryReader::ParseMemoryStream
+
+// =================================================================================================
+// TIFF_MemoryReader::ProcessOneIFD
+// ================================
+
+XMP_Uns32 TIFF_MemoryReader::ProcessOneIFD ( XMP_Uns32 ifdOffset, XMP_Uns8 ifd )
+{
+ TweakedIFDInfo& ifdInfo = this->containedIFDs[ifd];
+
+ if ( (ifdOffset < 8) || (ifdOffset > (this->tiffLength - kEmptyIFDLength)) ) {
+ XMP_Throw ( "Bad IFD offset", kXMPErr_BadTIFF );
+ }
+
+ XMP_Uns8* ifdPtr = this->tiffStream + ifdOffset;
+ XMP_Uns16 ifdCount = this->GetUns16 ( ifdPtr );
+ TweakedIFDEntry* ifdEntries = (TweakedIFDEntry*)(ifdPtr+2);
+
+ if ( ifdCount >= 0x8000 ) XMP_Throw ( "Outrageous IFD count", kXMPErr_BadTIFF );
+ if ( (ifdOffset + 2 + ifdCount*12 + 4) > this->tiffLength ) XMP_Throw ( "Out of bounds IFD", kXMPErr_BadTIFF );
+
+ ifdInfo.count = ifdCount;
+ ifdInfo.entries = ifdEntries;
+
+ XMP_Int32 prevTag = -1; // ! The GPS IFD has a tag 0, so we need a signed initial value.
+ bool needsSorting = false;
+ for ( size_t i = 0; i < ifdCount; ++i ) {
+
+ TweakedIFDEntry* thisEntry = &ifdEntries[i]; // Tweak the IFD entry to be more useful.
+
+ if ( ! this->nativeEndian ) {
+ Flip2 ( &thisEntry->id );
+ Flip2 ( &thisEntry->type );
+ Flip4 ( &thisEntry->bytes );
+ }
+
+ if ( thisEntry->id <= prevTag ) needsSorting = true;
+ prevTag = thisEntry->id;
+
+ if ( (thisEntry->type < kTIFF_ByteType) || (thisEntry->type > kTIFF_LastType) ) continue; // Bad type, skip this tag.
+
+ thisEntry->bytes *= kTIFF_TypeSizes[thisEntry->type];
+ if ( thisEntry->bytes > this->tiffLength ) XMP_Throw ( "Bad TIFF data size", kXMPErr_BadTIFF );
+ if ( thisEntry->bytes > 4 ) {
+ if ( ! this->nativeEndian ) Flip4 ( &thisEntry->dataOrPtr );
+ thisEntry->dataOrPtr += (XMP_Uns32)this->tiffStream;
+ }
+
+ }
+
+ ifdPtr += (2 + ifdCount*12);
+ XMP_Uns32 nextIFDOffset = this->GetUns32 ( ifdPtr );
+
+ if ( needsSorting ) SortIFD ( &ifdInfo ); // ! Don't perturb the ifdCount used to find the next IFD offset.
+
+ return nextIFDOffset;
+
+} // TIFF_MemoryReader::ProcessOneIFD
+
+// =================================================================================================
diff --git a/source/XMPFiles/FormatSupport/TIFF_Support.cpp b/source/XMPFiles/FormatSupport/TIFF_Support.cpp
new file mode 100644
index 0000000..6d1698d
--- /dev/null
+++ b/source/XMPFiles/FormatSupport/TIFF_Support.cpp
@@ -0,0 +1,626 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "TIFF_Support.hpp"
+#include "EndianUtils.hpp"
+
+#include "UnicodeConversions.hpp"
+
+// =================================================================================================
+/// \file TIFF_Support.cpp
+/// \brief Manager for parsing and serializing TIFF streams.
+///
+// =================================================================================================
+
+// =================================================================================================
+// TIFF_Manager::TIFF_Manager
+// ==========================
+
+static bool sFirstCTor = true;
+
+TIFF_Manager::TIFF_Manager()
+ : bigEndian(false), nativeEndian(false), jpegTNailPtr(0),
+ GetUns16(0), GetUns32(0), GetFloat(0), GetDouble(0),
+ PutUns16(0), PutUns32(0), PutFloat(0), PutDouble(0),
+ xmpHadUserComment(false), xmpHadRelatedSoundFile(false)
+{
+
+ if ( sFirstCTor ) {
+ sFirstCTor = false;
+ #if XMP_DebugBuild
+ for ( int ifd = 0; ifd < kTIFF_KnownIFDCount; ++ifd ) { // Make sure the known tag arrays are sorted.
+ for ( const XMP_Uns16* idPtr = sKnownTags[ifd]; *idPtr != 0xFFFF; ++idPtr ) {
+ XMP_Assert ( *idPtr < *(idPtr+1) );
+ }
+ }
+ #endif
+ }
+
+} // TIFF_Manager::TIFF_Manager
+
+// =================================================================================================
+// TIFF_Manager::CheckTIFFHeader
+// =============================
+//
+// Checks the 4 byte TIFF prefix for validity and endianness. Sets the endian flags and the Get
+// function pointers. Returns the 0th IFD offset.
+
+XMP_Uns32 TIFF_Manager::CheckTIFFHeader ( const XMP_Uns8* tiffPtr, XMP_Uns32 length )
+{
+ if ( length < kEmptyTIFFLength ) XMP_Throw ( "The TIFF is too small", kXMPErr_BadTIFF );
+
+ XMP_Uns32 tiffPrefix = (tiffPtr[0] << 24) | (tiffPtr[1] << 16) | (tiffPtr[2] << 8) | (tiffPtr[3]);
+
+ if ( tiffPrefix == kBigEndianPrefix ) {
+ this->bigEndian = true;
+ } else if ( tiffPrefix == kLittleEndianPrefix ) {
+ this->bigEndian = false;
+ } else {
+ XMP_Throw ( "Unrecognized TIFF prefix", kXMPErr_BadTIFF );
+ }
+
+ this->nativeEndian = (this->bigEndian == kBigEndianHost);
+
+ if ( this->bigEndian ) {
+
+ this->GetUns16 = GetUns16BE;
+ this->GetUns32 = GetUns32BE;
+ this->GetFloat = GetFloatBE;
+ this->GetDouble = GetDoubleBE;
+
+ this->PutUns16 = PutUns16BE;
+ this->PutUns32 = PutUns32BE;
+ this->PutFloat = PutFloatBE;
+ this->PutDouble = PutDoubleBE;
+
+ } else {
+
+ this->GetUns16 = GetUns16LE;
+ this->GetUns32 = GetUns32LE;
+ this->GetFloat = GetFloatLE;
+ this->GetDouble = GetDoubleLE;
+
+ this->PutUns16 = PutUns16LE;
+ this->PutUns32 = PutUns32LE;
+ this->PutFloat = PutFloatLE;
+ this->PutDouble = PutDoubleLE;
+
+ }
+
+ XMP_Uns32 mainIFDOffset = this->GetUns32 ( tiffPtr+4 ); // ! Do this after setting the Get/Put procs!
+
+ if ( mainIFDOffset != 0 ) { // Tolerate empty TIFF even though formally invalid.
+ if ( (length < (kEmptyTIFFLength + kEmptyIFDLength)) ||
+ (mainIFDOffset < kEmptyTIFFLength) || (mainIFDOffset > (length - kEmptyIFDLength)) ) {
+ XMP_Throw ( "Invalid primary IFD offset", kXMPErr_BadTIFF );
+ }
+ }
+
+ return mainIFDOffset;
+
+} // TIFF_Manager::CheckTIFFHeader
+
+// =================================================================================================
+// TIFF_Manager::SetTag_Integer
+// ============================
+
+void TIFF_Manager::SetTag_Integer ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns32 data32 )
+{
+
+ if ( data32 > 0xFFFF ) {
+ this->SetTag ( ifd, id, kTIFF_LongType, 1, &data32 );
+ } else {
+ XMP_Uns16 data16 = (XMP_Uns16)data32;
+ this->SetTag ( ifd, id, kTIFF_ShortType, 1, &data16 );
+ }
+
+} // TIFF_Manager::SetTag_Integer
+
+// =================================================================================================
+// TIFF_Manager::SetTag_Byte
+// =========================
+
+void TIFF_Manager::SetTag_Byte ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns8 data )
+{
+
+ this->SetTag ( ifd, id, kTIFF_ByteType, 1, &data );
+
+} // TIFF_Manager::SetTag_Byte
+
+// =================================================================================================
+// TIFF_Manager::SetTag_SByte
+// ==========================
+
+void TIFF_Manager::SetTag_SByte ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Int8 data )
+{
+
+ this->SetTag ( ifd, id, kTIFF_SByteType, 1, &data );
+
+} // TIFF_Manager::SetTag_SByte
+
+// =================================================================================================
+// TIFF_Manager::SetTag_Short
+// ==========================
+
+void TIFF_Manager::SetTag_Short ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns16 clientData )
+{
+ XMP_Uns16 streamData;
+
+ this->PutUns16 ( clientData, &streamData );
+ this->SetTag ( ifd, id, kTIFF_ShortType, 1, &streamData );
+
+} // TIFF_Manager::SetTag_Short
+
+// =================================================================================================
+// TIFF_Manager::SetTag_SShort
+// ===========================
+
+ void TIFF_Manager::SetTag_SShort ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Int16 clientData )
+{
+ XMP_Int16 streamData;
+
+ this->PutUns16 ( (XMP_Uns16)clientData, &streamData );
+ this->SetTag ( ifd, id, kTIFF_SShortType, 1, &streamData );
+
+} // TIFF_Manager::SetTag_SShort
+
+// =================================================================================================
+// TIFF_Manager::SetTag_Long
+// =========================
+
+ void TIFF_Manager::SetTag_Long ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns32 clientData )
+{
+ XMP_Uns32 streamData;
+
+ this->PutUns32 ( clientData, &streamData );
+ this->SetTag ( ifd, id, kTIFF_LongType, 1, &streamData );
+
+} // TIFF_Manager::SetTag_Long
+
+// =================================================================================================
+// TIFF_Manager::SetTag_SLong
+// ==========================
+
+ void TIFF_Manager::SetTag_SLong ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Int32 clientData )
+{
+ XMP_Int32 streamData;
+
+ this->PutUns32 ( (XMP_Uns32)clientData, &streamData );
+ this->SetTag ( ifd, id, kTIFF_SLongType, 1, &streamData );
+
+} // TIFF_Manager::SetTag_SLong
+
+// =================================================================================================
+// TIFF_Manager::SetTag_Rational
+// =============================
+
+struct StreamRational { XMP_Uns32 num, denom; };
+
+ void TIFF_Manager::SetTag_Rational ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns32 clientNum, XMP_Uns32 clientDenom )
+{
+ StreamRational streamData;
+
+ this->PutUns32 ( clientNum, &streamData.num );
+ this->PutUns32 ( clientDenom, &streamData.denom );
+ this->SetTag ( ifd, id, kTIFF_RationalType, 1, &streamData );
+
+} // TIFF_Manager::SetTag_Rational
+
+// =================================================================================================
+// TIFF_Manager::SetTag_SRational
+// ==============================
+
+ void TIFF_Manager::SetTag_SRational ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Int32 clientNum, XMP_Int32 clientDenom )
+{
+ StreamRational streamData;
+
+ this->PutUns32 ( (XMP_Uns32)clientNum, &streamData.num );
+ this->PutUns32 ( (XMP_Uns32)clientDenom, &streamData.denom );
+ this->SetTag ( ifd, id, kTIFF_SRationalType, 1, &streamData );
+
+} // TIFF_Manager::SetTag_SRational
+
+// =================================================================================================
+// TIFF_Manager::SetTag_Float
+// ==========================
+
+ void TIFF_Manager::SetTag_Float ( XMP_Uns8 ifd, XMP_Uns16 id, float clientData )
+{
+ float streamData;
+
+ this->PutFloat ( clientData, &streamData );
+ this->SetTag ( ifd, id, kTIFF_FloatType, 1, &streamData );
+
+} // TIFF_Manager::SetTag_Float
+
+// =================================================================================================
+// TIFF_Manager::SetTag_Double
+// ===========================
+
+ void TIFF_Manager::SetTag_Double ( XMP_Uns8 ifd, XMP_Uns16 id, double clientData )
+{
+ double streamData;
+
+ this->PutDouble ( clientData, &streamData );
+ this->SetTag ( ifd, id, kTIFF_DoubleType, 1, &streamData );
+
+} // TIFF_Manager::SetTag_Double
+
+// =================================================================================================
+// TIFF_Manager::SetTag_ASCII
+// ===========================
+
+void TIFF_Manager::SetTag_ASCII ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_StringPtr data )
+{
+
+ this->SetTag ( ifd, id, kTIFF_ASCIIType, (strlen(data) + 1), data ); // ! Include trailing nul.
+
+} // TIFF_Manager::SetTag_ASCII
+
+// =================================================================================================
+// UTF16_to_UTF8
+// =============
+
+static void UTF16_to_UTF8 ( const UTF16Unit * utf16Ptr, size_t utf16Len, bool bigEndian, std::string * outStr )
+{
+ UTF16_to_UTF8_Proc ToUTF8 = 0;
+ if ( bigEndian ) {
+ ToUTF8 = UTF16BE_to_UTF8;
+ } else {
+ ToUTF8 = UTF16LE_to_UTF8;
+ }
+
+ UTF8Unit buffer [1000];
+ size_t inCount, outCount;
+
+ outStr->erase();
+ outStr->reserve ( utf16Len * 2 ); // As good a guess as any.
+
+ while ( utf16Len > 0 ) {
+ ToUTF8 ( utf16Ptr, utf16Len, buffer, sizeof(buffer), &inCount, &outCount );
+ outStr->append ( (XMP_StringPtr)buffer, outCount );
+ utf16Ptr += inCount;
+ utf16Len -= inCount;
+ }
+
+} // UTF16_to_UTF8
+
+// =================================================================================================
+// TIFF_Manager::DecodeString
+// ==========================
+//
+// Convert an explicitly encoded string to UTF-8. The input must be encoded according to table 6 of
+// the Exif 2.2 specification. The input pointer is to the start of the 8 byte header, the length is
+// the full length. In other words, the pointer and length from the IFD entry. Returns true if the
+// encoding is supported and the conversion succeeds.
+
+// *** JIS encoding is not supported yet. Need a static mapping table from JIS X 208-1990 to Unicode.
+
+bool TIFF_Manager::DecodeString ( const void * encodedPtr, size_t encodedLen, std::string* utf8Str ) const
+{
+ XMP_StringPtr typePtr = (XMP_StringPtr)encodedPtr;
+ XMP_StringPtr valuePtr = typePtr + 8;
+ size_t valueLen = encodedLen - 8;
+
+ utf8Str->erase();
+
+ if ( *typePtr == 'A' ) {
+
+ utf8Str->assign ( valuePtr, valueLen );
+ return true;
+
+ } else if ( *typePtr == 'U' ) {
+
+ try {
+ const UTF16Unit * utf16Ptr = (const UTF16Unit *) valuePtr;
+ size_t utf16Len = valueLen >> 1; // The number of UTF-16 storage units, not bytes.
+ UTF16_to_UTF8 ( utf16Ptr, utf16Len, this->bigEndian, utf8Str );
+ return true;
+ } catch ( ... ) {
+ return false; // Ignore the tag if there are conversion errors.
+ }
+
+ } else if ( *typePtr == 'J' ) {
+
+ return false; // ! Ignore JIS for now.
+
+ }
+
+ return false; // ! Ignore all other encodings.
+
+} // TIFF_Manager::DecodeString
+
+// =================================================================================================
+// UTF8_to_UTF16
+// =============
+
+static void UTF8_to_UTF16 ( const UTF8Unit * utf8Ptr, size_t utf8Len, bool bigEndian, std::string * outStr )
+{
+ UTF8_to_UTF16_Proc ToUTF16 = 0;
+ if ( bigEndian ) {
+ ToUTF16 = UTF8_to_UTF16BE;
+ } else {
+ ToUTF16 = UTF8_to_UTF16LE;
+ }
+
+ enum { kUTF16Len = 1000 };
+ UTF16Unit buffer [kUTF16Len];
+ size_t inCount, outCount;
+
+ outStr->erase();
+ outStr->reserve ( utf8Len * 2 ); // As good a guess as any.
+
+ while ( utf8Len > 0 ) {
+ ToUTF16 ( utf8Ptr, utf8Len, buffer, kUTF16Len, &inCount, &outCount );
+ outStr->append ( (XMP_StringPtr)buffer, outCount*2 );
+ utf8Ptr += inCount;
+ utf8Len -= inCount;
+ }
+
+} // UTF8_to_UTF16
+
+// =================================================================================================
+// TIFF_Manager::EncodeString
+// ==========================
+//
+// Convert a UTF-8 string to an explicitly encoded form according to table 6 of the Exif 2.2
+// specification. Returns true if the encoding is supported and the conversion succeeds.
+
+// *** JIS encoding is not supported yet. Need a static mapping table to JIS X 208-1990 from Unicode.
+
+bool TIFF_Manager::EncodeString ( const std::string& utf8Str, XMP_Uns8 encoding, std::string* encodedStr )
+{
+ encodedStr -> erase();
+
+ if ( encoding == kTIFF_EncodeASCII ) {
+
+ encodedStr->assign ( "ASCII\0\0\0", 8 );
+ XMP_Assert (encodedStr->size() == 8 );
+
+ encodedStr->append ( utf8Str ); // ! Let the caller filter the value. (?)
+
+ return true;
+
+ } else if ( encoding == kTIFF_EncodeUnicode ) {
+
+ encodedStr->assign ( "UNICODE\0", 8 );
+ XMP_Assert (encodedStr->size() == 8 );
+
+ try {
+ std::string temp;
+ UTF8_to_UTF16 ( (const UTF8Unit*)utf8Str.c_str(), utf8Str.size(), this->bigEndian, &temp );
+ encodedStr->append ( temp );
+ return true;
+ } catch ( ... ) {
+ return false; // Ignore the tag if there are conversion errors.
+ }
+
+ } else if ( encoding == kTIFF_EncodeJIS ) {
+
+ XMP_Throw ( "Encoding to JIS is not implemented", kXMPErr_Unimplemented );
+
+ // encodedStr->assign ( "JIS\0\0\0\0\0", 8 );
+ // XMP_Assert (encodedStr->size() == 8 );
+
+ // ...
+
+ // return true;
+
+ } else {
+
+ XMP_Throw ( "Invalid TIFF string encoding", kXMPErr_BadParam );
+
+ }
+
+ return false; // ! Should never get here.
+
+} // TIFF_Manager::EncodeString
+
+// =================================================================================================
+// GetJPEGDimensions
+// =================
+//
+// Get the internal dimensions for a JPEG compressed image. These are the X (width) and Y (height)
+// components of the SOFn marker segment. A 0 value for Y says that the height is in the NL
+// component of the DNL marker segment at the end of the first scan. We'll use the first SOF, in
+// the case of hierarchical JPEG which has multiple frames.
+//
+// For this logic a JPEG stream is:
+// SOI standalone marker
+// Optional marker segments
+// First frame:
+// SOFn marker segment
+// First scan:
+// Optional marker segments
+// SOS marker segment
+// Image data and RST standalone markers
+// Optional DNL marker segment
+// Optional additional scans
+// Optional additional frames
+// EOI standalone marker
+//
+// There is no explicit length for the image data portion of a scan. It ends at the first non-RST
+// marker. So we look no further than the first non-RST marker after the first SOS marker segment.
+// That is the one and only DNL marker segment, if it exists. Hopefully we stop at the first SOFn.
+//
+// The first 5 bytes of the SOFn contents are:
+// Uns8 - ignored here
+// Uns16 - Y, height, big endian
+// Uns16 - X, width, big endian
+//
+// A DNL marker segment contains just 2 bytes of data, the big endian Uns16 number of lines.
+
+static void GetJPEGDimensions ( const void * jpegStream, size_t jpegLength, XMP_Uns32 * width, XMP_Uns32 * height )
+{
+ const XMP_Uns8 * jpegPtr = (const XMP_Uns8 *) jpegStream;
+ const XMP_Uns8 * jpegEnd = jpegPtr + jpegLength;
+
+ XMP_Uns16 marker, length;
+
+ *width = *height = 0; // Assume the worst.
+
+ marker = GetUns16BE ( jpegPtr );
+ if ( marker != 0xFFD8 ) return; // Check for the SOI.
+ jpegPtr += 2;
+
+ // Scan for the first SOFn marker and extract the Y and X components.
+
+ while ( jpegPtr < jpegEnd ) {
+ marker = GetUns16BE ( jpegPtr );
+ if ( ((marker & 0xFFF0) == 0xFFC0) &&
+ (marker != 0xFFC4) && (marker != 0xFFC8) && (marker != 0xFFCC) ) break;
+ jpegPtr += 2;
+ if ( (jpegPtr < jpegEnd) && ((marker & 0xFFF8) != 0xFFD0) &&
+ (marker != 0xFF01) && (marker != 0xFFD8) && (marker != 0xFFD9) ) {
+ jpegPtr += GetUns16BE ( jpegPtr );
+ }
+ }
+
+ if ( jpegPtr >= jpegEnd ) return; // Ran out of data.
+ if ( (marker & 0xFFF0) != 0xFFC0 ) return; // Not an SOFn marker.
+ jpegPtr += 2;
+ length = GetUns16BE ( jpegPtr );
+ if ( length < 7 ) return; // Bad length, the SOFn marker segment is too short.
+
+ *height = GetUns16BE ( jpegPtr+3 );
+ *width = GetUns16BE ( jpegPtr+5 );
+ if ( *height != 0 ) return; // Done if the Y component is non-zero.
+ jpegPtr += length;
+
+ // Need to look for a DNL marker segment. Scan for the first SOS marker.
+
+ while ( jpegPtr < jpegEnd ) {
+ marker = GetUns16BE ( jpegPtr );
+ if ( marker == 0xFFDA ) break;
+ jpegPtr += 2;
+ if ( (jpegPtr < jpegEnd) && ((marker & 0xFFF8) != 0xFFD0) &&
+ (marker != 0xFF01) && (marker != 0xFFD8) && (marker != 0xFFD9) ) {
+ jpegPtr += GetUns16BE ( jpegPtr );
+ }
+ }
+
+ if ( jpegPtr >= jpegEnd ) return; // Ran out of data.
+ if ( marker != 0xFFDA ) return; // Not an SOS marker.
+ jpegPtr += 2;
+ length = GetUns16BE ( jpegPtr );
+ jpegPtr += length;
+
+ // Now look for a non-RST marker. We're in the image data, must scan one byte at a time.
+
+ while ( jpegPtr < jpegEnd ) {
+ if ( *jpegPtr != 0xFF ) {
+ ++jpegPtr;
+ } else {
+ marker = GetUns16BE ( jpegPtr );
+ if ( (0xFF01 <= marker) && (marker <= 0xFFFE) && ((marker & 0xFFF8) != 0xFFD0) ) break;
+ jpegPtr += 2;
+ }
+ }
+
+ if ( jpegPtr >= jpegEnd ) return; // Ran out of data.
+ if ( marker != 0xFFDC ) return; // Not a DNL marker.
+ jpegPtr += 2;
+ length = GetUns16BE ( jpegPtr );
+ if ( length != 4 ) return; // Bad DNL marker segment length.
+
+ *height = GetUns16BE ( jpegPtr+2 );
+
+} // GetJPEGDimensions
+
+// =================================================================================================
+// TIFF_Manager::GetTNailInfo
+// ==========================
+//
+// Gather the info for a native Exif thumbnail, if there is one. We only return full info for a JPEG
+// compressed thumbnail.
+// - There must be at least 2 top level IFDs, the second is the thumbnail.
+// - The Exif IFD must be present.
+// - The thumbnail IFD must have tag 259, Compression.
+// - A JPEG compressed thumbnail must have tags 513 and 514, JPEGInterchangeFormat and JPEGInterchangeFormatLength.
+//
+// Tag 259 (Compression) in the thumbnail IFD defines the thumbnail compression scheme. It is 1 for
+// uncompressed and 6 for JPEG compressed. If the thumbnail is JPEG compressed, then tag 513
+// (JPEGInterchangeFormat) in the thumbnail IFD is the offset of the thumbnail image stream (to the
+// SOI) and tag 514 (JPEGInterchangeFormatLength) is the length of the stream in bytes. Yes,
+// another stupid Exif mistake of putting an explicit offset in the TIFF info (type LONG, count 1)
+// instead of a properly typed data block!
+//
+// The full image dimensions for an Exif-compliant compressed JPEG image are in tags 40962
+// (PixelXDimension) and 40963 (PixelYDimension) of the Exif IFD.
+//
+// The dimensions of an Exif-compliant uncompressed (TIFF) thumbnail are in tags 256 (ImageWidth)
+// and 257 (ImageLength) of the thumbnail IFD. The dimensions of an Exif-compliant compressed
+// (JPEG) thumbnail are within the JPEG stream of the thumbnail. The JPEG dimensions should be in
+// the X (width) and Y (height) components of the SOF marker segment. A 0 value for Y says that the
+// height is in the NL component of the DNL marker segment at the end of the first scan.
+
+bool TIFF_Manager::GetTNailInfo ( XMP_ThumbnailInfo * tnailInfo ) const
+{
+ bool found;
+ XMP_Uns16 compression;
+
+ enum { kUncompressedTNail = 1, kJPEGCompressedTNail = 6 };
+
+ if ( tnailInfo == 0 ) return false;
+
+ // Make sure the required IFDs and tags are present.
+
+ if ( (! this->HasExifIFD()) || (! this->HasThumbnailIFD()) ) return false;
+
+ found = this->GetTag_Short ( kTIFF_TNailIFD, kTIFF_Compression, &compression );
+ if ( ! found ) return false;
+ if ( (compression != kUncompressedTNail) && (compression != kJPEGCompressedTNail) ) return false;
+
+ // Gather the info that depends on the thumbnail format.
+
+ if ( compression == kUncompressedTNail ) {
+
+ // Gather the info for an uncompressed thumbnail. Just the format, width, and height.
+
+ tnailInfo->tnailFormat = kXMP_TIFFTNail;
+ (void) this->GetTag_Integer ( kTIFF_TNailIFD, kTIFF_ImageWidth, &tnailInfo->tnailWidth );
+ (void) this->GetTag_Integer ( kTIFF_TNailIFD, kTIFF_ImageLength, &tnailInfo->tnailHeight );
+
+ } else {
+
+ // Gather the info for a JPEG compressed thumbnail. The JPEG stream pointer is special, the
+ // type/count of tag 513 is LONG/1 - thank once again Exif! The pointer was set when parsing
+ // the TIFF stream. That is when we have to capture the stream for file-based TIFF.
+
+ XMP_Uns32 jpegOffset, jpegLength;
+ found = this->GetTag_Long ( kTIFF_TNailIFD, kTIFF_JPEGInterchangeFormat, &jpegOffset );
+ if ( ! found ) return false;
+ found = this->GetTag_Long ( kTIFF_TNailIFD, kTIFF_JPEGInterchangeFormatLength, &jpegLength );
+ if ( ! found ) return false;
+
+ XMP_Assert ( this->jpegTNailPtr != 0 );
+
+ tnailInfo->tnailFormat = kXMP_JPEGTNail;
+ tnailInfo->tnailImage = this->jpegTNailPtr;
+ tnailInfo->tnailSize = jpegLength;
+
+ GetJPEGDimensions ( tnailInfo->tnailImage, tnailInfo->tnailSize,
+ &tnailInfo->tnailWidth, &tnailInfo->tnailHeight );
+
+ }
+
+ // If we get here there is a thumbnail of some sort. Gether remaining common info.
+
+ (void) this->GetTag_Integer ( kTIFF_ExifIFD, kTIFF_PixelXDimension, &tnailInfo->fullWidth );
+ (void) this->GetTag_Integer ( kTIFF_ExifIFD, kTIFF_PixelYDimension, &tnailInfo->fullHeight );
+ (void) this->GetTag_Short ( kTIFF_PrimaryIFD, kTIFF_Orientation, &tnailInfo->fullOrientation );
+
+ found = this->GetTag_Short ( kTIFF_TNailIFD, kTIFF_Orientation, &tnailInfo->tnailOrientation );
+ if ( ! found ) tnailInfo->tnailOrientation = tnailInfo->fullOrientation;
+
+ return true;
+
+} // TIFF_Manager::GetTNailInfo
+
+// =================================================================================================
diff --git a/source/XMPFiles/FormatSupport/TIFF_Support.hpp b/source/XMPFiles/FormatSupport/TIFF_Support.hpp
new file mode 100644
index 0000000..171c12c
--- /dev/null
+++ b/source/XMPFiles/FormatSupport/TIFF_Support.hpp
@@ -0,0 +1,887 @@
+#ifndef __TIFF_Support_hpp__
+#define __TIFF_Support_hpp__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "XMP_Environment.h" // ! This must be the first include.
+
+#include <map>
+
+#include "XMP_Const.h"
+#include "XMPFiles_Impl.hpp"
+#include "EndianUtils.hpp"
+
+// =================================================================================================
+/// \file TIFF_Support.hpp
+/// \brief XMPFiles support for TIFF streams.
+///
+/// This header provides TIFF stream support specific to the needs of XMPFiles. This is not intended
+/// for general purpose TIFF processing. TIFF_Manager is an abstract base class with 2 concrete
+/// derived classes, TIFF_MemoryReader and TIFF_FileWriter.
+///
+/// TIFF_MemoryReader provides read-only support for TIFF streams that are small enough to be kept
+/// entirely in memory. This allows optimizations to reduce heap usage and processing code. It is
+/// sufficient for browsing access to the Exif metadata in JPEG and Photoshop files. Think of
+/// TIFF_MemoryReader as "memory-based AND read-only". Since the entire TIFF stream is available,
+/// GetTag will return information about any tag in the stream.
+///
+/// TIFF_FileWriter is for cases where updates are needed or the TIFF stream is too large to be kept
+/// entirely in memory. Think of TIFF_FileWriter as "file-based OR read-write". TIFF_FileWriter only
+/// maintains information for tags of interest as metadata.
+///
+/// The needs of XMPFiles are well defined metadata access. Only 5 IFDs are recognized:
+/// \li The 0th IFD, for the primary image, the first one in the outer list of IFDs.
+/// \li The 1st IFD, for an Exif thumbnail, the second one in the outer list of IFDs.
+/// \li The Exif general metadata IFD, from tag 34665 in the primary image IFD.
+/// \li The Exif GPS Info metadata IFD, from tag 34853 in the primary image IFD.
+/// \li The Exif Interoperability IFD, from tag 40965 in the Exif general metadata IFD.
+///
+/// \note In the future we should add support for the non-Exif thumbnails in DNG (TIFF/EP) files.
+///
+/// \note These classes are for use only when directly compiled and linked. They should not be
+/// packaged in a DLL by themselves. They do not provide any form of C++ ABI protection.
+// =================================================================================================
+
+
+// =================================================================================================
+// TIFF IFD and type constants
+// ===========================
+//
+// These aren't inside TIFF_Manager because static data members can't be initialized there.
+
+enum { // Constants for the recognized IFDs.
+ kTIFF_PrimaryIFD = 0, // The primary image IFD, also called the 0th IFD.
+ kTIFF_TNailIFD = 1, // The thumbnail image IFD also called the 1st IFD.
+ kTIFF_ExifIFD = 2, // The Exif general metadata IFD.
+ kTIFF_GPSInfoIFD = 3, // The Exif GPS Info IFD.
+ kTIFF_InteropIFD = 4, // The Exif Interoperability IFD.
+ kTIFF_LastRealIFD = 4,
+ kTIFF_KnownIFDCount = 5,
+ kTIFF_KnownIFD = 9 // The IFD that a tag is known to belong in.
+};
+
+enum { // Constants for the type field of a tag, as defined by TIFF.
+ kTIFF_ShortOrLongType = 0, // ! Not part of the TIFF spec, never in a tag!
+ kTIFF_ByteType = 1,
+ kTIFF_ASCIIType = 2,
+ kTIFF_ShortType = 3,
+ kTIFF_LongType = 4,
+ kTIFF_RationalType = 5,
+ kTIFF_SByteType = 6,
+ kTIFF_UndefinedType = 7,
+ kTIFF_SShortType = 8,
+ kTIFF_SLongType = 9,
+ kTIFF_SRationalType = 10,
+ kTIFF_FloatType = 11,
+ kTIFF_DoubleType = 12,
+ kTIFF_LastType = 12
+};
+
+static const size_t kTIFF_TypeSizes[] = { 0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8 };
+
+static const char * kTIFF_TypeNames[] = { "ShortOrLong", "BYTE", "ASCII", "SHORT", "LONG", "RATIONAL",
+ "SBYTE", "UNDEFINED", "SSHORT", "SLONG", "SRATIONAL",
+ "FLOAT", "DOUBLE" };
+
+enum { // Encodings for SetTag_EncodedString.
+ kTIFF_EncodeUndefined = 0,
+ kTIFF_EncodeASCII = 1,
+ kTIFF_EncodeUnicode = 2, // UTF-16 in the endianness of the TIFF stream.
+ kTIFF_EncodeJIS = 3, // Exif 2.2 uses JIS X 208-1990.
+ kTIFF_EncodeUnknown = 9
+};
+
+// =================================================================================================
+// Recognized TIFF tags
+// ====================
+
+// ---------------------------------------------------------------------------
+// An enum of IDs for all of the tags as potential interest as metadata.
+
+enum {
+
+ // General 0th IFD tags. Some of these can also be in the thumbnail IFD.
+
+ kTIFF_ImageWidth = 256,
+ kTIFF_ImageLength = 257,
+ kTIFF_BitsPerSample = 258,
+ kTIFF_Compression = 259,
+ kTIFF_PhotometricInterpretation = 262,
+ kTIFF_ImageDescription = 270,
+ kTIFF_Make = 271,
+ kTIFF_Model = 272,
+ kTIFF_Orientation = 274,
+ kTIFF_SamplesPerPixel = 277,
+ kTIFF_XResolution = 282,
+ kTIFF_YResolution = 283,
+ kTIFF_PlanarConfiguration = 284,
+ kTIFF_ResolutionUnit = 296,
+ kTIFF_TransferFunction = 301,
+ kTIFF_Software = 305,
+ kTIFF_DateTime = 306,
+ kTIFF_Artist = 315,
+ kTIFF_WhitePoint = 318,
+ kTIFF_PrimaryChromaticities = 319,
+ kTIFF_YCbCrCoefficients = 529,
+ kTIFF_YCbCrSubSampling = 530,
+ kTIFF_YCbCrPositioning = 531,
+ kTIFF_ReferenceBlackWhite = 532,
+ kTIFF_XMP = 700,
+ kTIFF_Copyright = 33432,
+ kTIFF_IPTC = 33723,
+ kTIFF_PSIR = 34377,
+ kTIFF_ExifIFDPointer = 34665,
+ kTIFF_GPSInfoIFDPointer = 34853,
+
+ // Additional thumbnail IFD tags. We also care about 256, 257, and 259 in thumbnails.
+ kTIFF_JPEGInterchangeFormat = 513,
+ kTIFF_JPEGInterchangeFormatLength = 514,
+
+ // Additional tags that need special handling when rewriting memory-based TIFF.
+ kTIFF_StripOffsets = 273,
+ kTIFF_StripByteCounts = 279,
+ kTIFF_FreeOffsets = 288,
+ kTIFF_FreeByteCounts = 289,
+ kTIFF_TileOffsets = 324,
+ kTIFF_TileByteCounts = 325,
+ kTIFF_SubIFDs = 330,
+ kTIFF_JPEGQTables = 519,
+ kTIFF_JPEGDCTables = 520,
+ kTIFF_JPEGACTables = 521,
+
+ // Exif IFD tags.
+
+ kTIFF_ExposureTime = 33434,
+ kTIFF_FNumber = 33437,
+ kTIFF_ExposureProgram = 34850,
+ kTIFF_SpectralSensitivity = 34852,
+ kTIFF_ISOSpeedRatings = 34855,
+ kTIFF_OECF = 34856,
+ kTIFF_ExifVersion = 36864,
+ kTIFF_DateTimeOriginal = 36867,
+ kTIFF_DateTimeDigitized = 36868,
+ kTIFF_ComponentsConfiguration = 37121,
+ kTIFF_CompressedBitsPerPixel = 37122,
+ kTIFF_ShutterSpeedValue = 37377,
+ kTIFF_ApertureValue = 37378,
+ kTIFF_BrightnessValue = 37379,
+ kTIFF_ExposureBiasValue = 37380,
+ kTIFF_MaxApertureValue = 37381,
+ kTIFF_SubjectDistance = 37382,
+ kTIFF_MeteringMode = 37383,
+ kTIFF_LightSource = 37384,
+ kTIFF_Flash = 37385,
+ kTIFF_FocalLength = 37386,
+ kTIFF_SubjectArea = 37396,
+ kTIFF_UserComment = 37510,
+ kTIFF_SubSecTime = 37520,
+ kTIFF_SubSecTimeOriginal = 37521,
+ kTIFF_SubSecTimeDigitized = 37522,
+ kTIFF_FlashpixVersion = 40960,
+ kTIFF_ColorSpace = 40961,
+ kTIFF_PixelXDimension = 40962,
+ kTIFF_PixelYDimension = 40963,
+ kTIFF_RelatedSoundFile = 40964,
+ kTIFF_InteroperabilityIFDPointer = 40965,
+ kTIFF_FlashEnergy = 41483,
+ kTIFF_SpatialFrequencyResponse = 41484,
+ kTIFF_FocalPlaneXResolution = 41486,
+ kTIFF_FocalPlaneYResolution = 41487,
+ kTIFF_FocalPlaneResolutionUnit = 41488,
+ kTIFF_SubjectLocation = 41492,
+ kTIFF_ExposureIndex = 41493,
+ kTIFF_SensingMethod = 41495,
+ kTIFF_FileSource = 41728,
+ kTIFF_SceneType = 41729,
+ kTIFF_CFAPattern = 41730,
+ kTIFF_CustomRendered = 41985,
+ kTIFF_ExposureMode = 41986,
+ kTIFF_WhiteBalance = 41987,
+ kTIFF_DigitalZoomRatio = 41988,
+ kTIFF_FocalLengthIn35mmFilm = 41989,
+ kTIFF_SceneCaptureType = 41990,
+ kTIFF_GainControl = 41991,
+ kTIFF_Contrast = 41992,
+ kTIFF_Saturation = 41993,
+ kTIFF_Sharpness = 41994,
+ kTIFF_DeviceSettingDescription = 41995,
+ kTIFF_SubjectDistanceRange = 41996,
+ kTIFF_ImageUniqueID = 42016,
+
+ kTIFF_MakerNote = 37500, // Gets deleted when rewriting memory-based TIFF.
+
+ // GPS IFD tags.
+
+ kTIFF_GPSVersionID = 0,
+ kTIFF_GPSLatitudeRef = 1,
+ kTIFF_GPSLatitude = 2,
+ kTIFF_GPSLongitudeRef = 3,
+ kTIFF_GPSLongitude = 4,
+ kTIFF_GPSAltitudeRef = 5,
+ kTIFF_GPSAltitude = 6,
+ kTIFF_GPSTimeStamp = 7,
+ kTIFF_GPSSatellites = 8,
+ kTIFF_GPSStatus = 9,
+ kTIFF_GPSMeasureMode = 10,
+ kTIFF_GPSDOP = 11,
+ kTIFF_GPSSpeedRef = 12,
+ kTIFF_GPSSpeed = 13,
+ kTIFF_GPSTrackRef = 14,
+ kTIFF_GPSTrack = 15,
+ kTIFF_GPSImgDirectionRef = 16,
+ kTIFF_GPSImgDirection = 17,
+ kTIFF_GPSMapDatum = 18,
+ kTIFF_GPSDestLatitudeRef = 19,
+ kTIFF_GPSDestLatitude = 20,
+ kTIFF_GPSDestLongitudeRef = 21,
+ kTIFF_GPSDestLongitude = 22,
+ kTIFF_GPSDestBearingRef = 23,
+ kTIFF_GPSDestBearing = 24,
+ kTIFF_GPSDestDistanceRef = 25,
+ kTIFF_GPSDestDistance = 26,
+ kTIFF_GPSProcessingMethod = 27,
+ kTIFF_GPSAreaInformation = 28,
+ kTIFF_GPSDateStamp = 29,
+ kTIFF_GPSDifferential = 30
+
+};
+
+// ------------------------------------------------------------------
+// Sorted arrays of the tags that are recognized in the various IFDs.
+
+static const XMP_Uns16 sKnownPrimaryIFDTags[] =
+{
+ kTIFF_ImageWidth, // 256
+ kTIFF_ImageLength, // 257
+ kTIFF_BitsPerSample, // 258
+ kTIFF_Compression, // 259
+ kTIFF_PhotometricInterpretation, // 262
+ kTIFF_ImageDescription, // 270
+ kTIFF_Make, // 271
+ kTIFF_Model, // 272
+ kTIFF_Orientation, // 274
+ kTIFF_SamplesPerPixel, // 277
+ kTIFF_XResolution, // 282
+ kTIFF_YResolution, // 283
+ kTIFF_PlanarConfiguration, // 284
+ kTIFF_ResolutionUnit, // 296
+ kTIFF_TransferFunction, // 301
+ kTIFF_Software, // 305
+ kTIFF_DateTime, // 306
+ kTIFF_Artist, // 315
+ kTIFF_WhitePoint, // 318
+ kTIFF_PrimaryChromaticities, // 319
+ kTIFF_YCbCrCoefficients, // 529
+ kTIFF_YCbCrSubSampling, // 530
+ kTIFF_YCbCrPositioning, // 531
+ kTIFF_ReferenceBlackWhite, // 532
+ kTIFF_XMP, // 700
+ kTIFF_Copyright, // 33432
+ kTIFF_IPTC, // 33723
+ kTIFF_PSIR, // 34377
+ kTIFF_ExifIFDPointer, // 34665
+ kTIFF_GPSInfoIFDPointer, // 34853
+ 0xFFFF // Must be last as a sentinel.
+};
+
+static const XMP_Uns16 sKnownThumbnailIFDTags[] =
+{
+ kTIFF_ImageWidth, // 256
+ kTIFF_ImageLength, // 257
+ kTIFF_Compression, // 259
+ kTIFF_JPEGInterchangeFormat, // 513
+ kTIFF_JPEGInterchangeFormatLength, // 514
+ 0xFFFF // Must be last as a sentinel.
+};
+
+static const XMP_Uns16 sKnownExifIFDTags[] =
+{
+ kTIFF_ExposureTime, // 33434
+ kTIFF_FNumber, // 33437
+ kTIFF_ExposureProgram, // 34850
+ kTIFF_SpectralSensitivity, // 34852
+ kTIFF_ISOSpeedRatings, // 34855
+ kTIFF_OECF, // 34856
+ kTIFF_ExifVersion, // 36864
+ kTIFF_DateTimeOriginal, // 36867
+ kTIFF_DateTimeDigitized, // 36868
+ kTIFF_ComponentsConfiguration, // 37121
+ kTIFF_CompressedBitsPerPixel, // 37122
+ kTIFF_ShutterSpeedValue, // 37377
+ kTIFF_ApertureValue, // 37378
+ kTIFF_BrightnessValue, // 37379
+ kTIFF_ExposureBiasValue, // 37380
+ kTIFF_MaxApertureValue, // 37381
+ kTIFF_SubjectDistance, // 37382
+ kTIFF_MeteringMode, // 37383
+ kTIFF_LightSource, // 37384
+ kTIFF_Flash, // 37385
+ kTIFF_FocalLength, // 37386
+ kTIFF_SubjectArea, // 37396
+ kTIFF_UserComment, // 37510
+ kTIFF_SubSecTime, // 37520
+ kTIFF_SubSecTimeOriginal, // 37521
+ kTIFF_SubSecTimeDigitized, // 37522
+ kTIFF_FlashpixVersion, // 40960
+ kTIFF_ColorSpace, // 40961
+ kTIFF_PixelXDimension, // 40962
+ kTIFF_PixelYDimension, // 40963
+ kTIFF_RelatedSoundFile, // 40964
+ kTIFF_FlashEnergy, // 41483
+ kTIFF_SpatialFrequencyResponse, // 41484
+ kTIFF_FocalPlaneXResolution, // 41486
+ kTIFF_FocalPlaneYResolution, // 41487
+ kTIFF_FocalPlaneResolutionUnit, // 41488
+ kTIFF_SubjectLocation, // 41492
+ kTIFF_ExposureIndex, // 41493
+ kTIFF_SensingMethod, // 41495
+ kTIFF_FileSource, // 41728
+ kTIFF_SceneType, // 41729
+ kTIFF_CFAPattern, // 41730
+ kTIFF_CustomRendered, // 41985
+ kTIFF_ExposureMode, // 41986
+ kTIFF_WhiteBalance, // 41987
+ kTIFF_DigitalZoomRatio, // 41988
+ kTIFF_FocalLengthIn35mmFilm, // 41989
+ kTIFF_SceneCaptureType, // 41990
+ kTIFF_GainControl, // 41991
+ kTIFF_Contrast, // 41992
+ kTIFF_Saturation, // 41993
+ kTIFF_Sharpness, // 41994
+ kTIFF_DeviceSettingDescription, // 41995
+ kTIFF_SubjectDistanceRange, // 41996
+ kTIFF_ImageUniqueID, // 42016
+ 0xFFFF // Must be last as a sentinel.
+};
+
+static const XMP_Uns16 sKnownGPSInfoIFDTags[] =
+{
+ kTIFF_GPSVersionID, // 0
+ kTIFF_GPSLatitudeRef, // 1
+ kTIFF_GPSLatitude, // 2
+ kTIFF_GPSLongitudeRef, // 3
+ kTIFF_GPSLongitude, // 4
+ kTIFF_GPSAltitudeRef, // 5
+ kTIFF_GPSAltitude, // 6
+ kTIFF_GPSTimeStamp, // 7
+ kTIFF_GPSSatellites, // 8
+ kTIFF_GPSStatus, // 9
+ kTIFF_GPSMeasureMode, // 10
+ kTIFF_GPSDOP, // 11
+ kTIFF_GPSSpeedRef, // 12
+ kTIFF_GPSSpeed, // 13
+ kTIFF_GPSTrackRef, // 14
+ kTIFF_GPSTrack, // 15
+ kTIFF_GPSImgDirectionRef, // 16
+ kTIFF_GPSImgDirection, // 17
+ kTIFF_GPSMapDatum, // 18
+ kTIFF_GPSDestLatitudeRef, // 19
+ kTIFF_GPSDestLatitude, // 20
+ kTIFF_GPSDestLongitudeRef, // 21
+ kTIFF_GPSDestLongitude, // 22
+ kTIFF_GPSDestBearingRef, // 23
+ kTIFF_GPSDestBearing, // 24
+ kTIFF_GPSDestDistanceRef, // 25
+ kTIFF_GPSDestDistance, // 26
+ kTIFF_GPSProcessingMethod, // 27
+ kTIFF_GPSAreaInformation, // 28
+ kTIFF_GPSDateStamp, // 29
+ kTIFF_GPSDifferential, // 30
+ 0xFFFF // Must be last as a sentinel.
+};
+
+static const XMP_Uns16 sKnownInteroperabilityIFDTags[] =
+{
+ // ! Yes, there are none at present.
+ 0xFFFF // Must be last as a sentinel.
+};
+
+// ! Make sure these are in the same order as the IFD enum!
+static const XMP_Uns16* sKnownTags[kTIFF_KnownIFDCount] = { sKnownPrimaryIFDTags,
+ sKnownThumbnailIFDTags,
+ sKnownExifIFDTags,
+ sKnownGPSInfoIFDTags,
+ sKnownInteroperabilityIFDTags };
+
+
+// =================================================================================================
+// =================================================================================================
+
+
+// =================================================================================================
+// TIFF_Manager
+// ============
+
+class TIFF_Manager { // The abstract base class.
+public:
+
+ // ---------------------------------------------------------------------------------------------
+ // Types and constants
+
+ static const XMP_Uns32 kBigEndianPrefix = 0x4D4D002AUL;
+ static const XMP_Uns32 kLittleEndianPrefix = 0x49492A00UL;
+
+ static const size_t kEmptyTIFFLength = 8; // Just the header.
+ static const size_t kEmptyIFDLength = 2 + 4; // Entry count and next-IFD offset.
+ static const size_t kIFDEntryLength = 12;
+
+ struct TagInfo {
+ XMP_Uns16 id;
+ XMP_Uns16 type;
+ XMP_Uns32 count;
+ const void* dataPtr; // ! The data must not be changed! Stream endian format!
+ XMP_Uns32 dataLen; // The length in bytes.
+ TagInfo() : id(0), type(0), count(0), dataPtr(0), dataLen(0) {};
+ TagInfo ( XMP_Uns16 _id, XMP_Uns16 _type, XMP_Uns32 _count, const void* _dataPtr, XMP_Uns32 _dataLen )
+ : id(_id), type(_type), count(_count), dataPtr(_dataPtr), dataLen(_dataLen) {};
+ };
+
+ typedef std::map<XMP_Uns16,TagInfo> TagInfoMap;
+
+ struct Rational { XMP_Uns32 num, denom; };
+ struct SRational { XMP_Int32 num, denom; };
+
+ // ---------------------------------------------------------------------------------------------
+ // The IsXyzEndian methods return the external endianness of the original parsed TIFF stream.
+ // The \c GetTag methods return native endian values, the \c SetTag methods take native values.
+ // The original endianness is preserved in output.
+
+ bool IsBigEndian() const { return this->bigEndian; };
+ bool IsLittleEndian() const { return (! this->bigEndian); };
+ bool IsNativeEndian() const { return this->nativeEndian; };
+
+ // ---------------------------------------------------------------------------------------------
+ // The TIFF_Manager only keeps explicit knowledge of up to 5 IFDs:
+ // - The primary image IFD, also known as the 0th IFD. This must be present.
+ // - A possible thumbnail IFD, also known as the 1st IFD, chained from the primary image IFD.
+ // - A possible Exif general metadata IFD, found from tag 34665 in the primary image IFD.
+ // - A possible Exif GPS metadata IFD, found from tag 34853 in the primary image IFD.
+ // - A possible Exif Interoperability IFD, found from tag 40965 in the Exif general metadata IFD.
+ //
+ // Parsing will silently forget about certain aspects of ill-formed streams. If any tags are
+ // repeated in an IFD, only the last is kept. Any known tags that are in the wrong IFD are
+ // removed. Parsing will sort the tags into ascending order, AppendTIFF and ComposeTIFF will
+ // preserve the sorted order. These fixes do not cause IsChanged to return true, that only
+ // happens if the client makes explicit changes using SetTag or DeleteTag.
+
+ virtual bool HasThumbnailIFD() const = 0;
+ virtual bool HasExifIFD() const = 0;
+ virtual bool HasGPSInfoIFD() const = 0;
+
+ // ---------------------------------------------------------------------------------------------
+ // These are the basic methods to get a map of all of the tags in an IFD, to get or set a tag,
+ // or to delete a tag. The dataPtr returned by \c GetTag is consided read-only, the client must
+ // not change it. The ifd parameter to \c GetIFD must be for one of the recognized actual IFDs.
+ // The ifd parameter for the GetTag or SetTag methods can be a specific IFD of kTIFF_KnownIFD.
+ // Using the specific IFD will be slightly faster, saving a lookup in the known tag map. An
+ // exception is thrown if kTIFF_KnownIFD is passed to GetTag or SetTag and the tag is not known.
+ // \c SetTag replaces an existing tag regardless of type or count. \c DeleteTag deletes a tag,
+ // it is a no-op if the tag does not exist. \c GetValueOffset returns the offset within the
+ // parsed stream of the tag's value. It returns 0 if the tag was not in the parsed input.
+
+ virtual bool GetIFD ( XMP_Uns8 ifd, TagInfoMap* ifdMap ) const = 0;
+
+ virtual bool GetTag ( XMP_Uns8 ifd, XMP_Uns16 id, TagInfo* info ) const = 0;
+
+ virtual void SetTag ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns16 type, XMP_Uns32 count, const void* dataPtr ) = 0;
+
+ virtual void DeleteTag ( XMP_Uns8 ifd, XMP_Uns16 id ) = 0;
+
+ virtual XMP_Uns32 GetValueOffset ( XMP_Uns8 ifd, XMP_Uns16 id ) const = 0;
+
+ // ---------------------------------------------------------------------------------------------
+ // These methods are for tags whose type can be short or long, depending on the actual value.
+ // \c GetTag_Integer returns false if an existing tag's type is not short, or long, or if the
+ // count is not 1. \c SetTag_Integer replaces an existing tag regardless of type or count, the
+ // new tag will have type short or long.
+
+ virtual bool GetTag_Integer ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns32* data ) const = 0;
+
+ void SetTag_Integer ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns32 data );
+
+ // ---------------------------------------------------------------------------------------------
+ // These are customized forms of GetTag that verify the type and return a typed value. False is
+ // returned if the type does not match or if the count is not 1.
+
+ // *** Should also add support for ASCII multi-strings?
+
+ virtual bool GetTag_Byte ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns8* data ) const = 0;
+ virtual bool GetTag_SByte ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Int8* data ) const = 0;
+ virtual bool GetTag_Short ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns16* data ) const = 0;
+ virtual bool GetTag_SShort ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Int16* data ) const = 0;
+ virtual bool GetTag_Long ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns32* data ) const = 0;
+ virtual bool GetTag_SLong ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Int32* data ) const = 0;
+
+ virtual bool GetTag_Rational ( XMP_Uns8 ifd, XMP_Uns16 id, Rational* data ) const = 0;
+ virtual bool GetTag_SRational ( XMP_Uns8 ifd, XMP_Uns16 id, SRational* data ) const = 0;
+
+ virtual bool GetTag_Float ( XMP_Uns8 ifd, XMP_Uns16 id, float* data ) const = 0;
+ virtual bool GetTag_Double ( XMP_Uns8 ifd, XMP_Uns16 id, double* data ) const = 0;
+
+ virtual bool GetTag_ASCII ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_StringPtr* dataPtr, XMP_StringLen* dataLen ) const = 0;
+
+ // ---------------------------------------------------------------------------------------------
+
+ void SetTag_Byte ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns8 data );
+ void SetTag_SByte ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Int8 data );
+ void SetTag_Short ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns16 data );
+ void SetTag_SShort ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Int16 data );
+ void SetTag_Long ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns32 data );
+ void SetTag_SLong ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Int32 data );
+
+ void SetTag_Rational ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns32 num, XMP_Uns32 denom );
+ void SetTag_SRational ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Int32 num, XMP_Int32 denom );
+
+ void SetTag_Float ( XMP_Uns8 ifd, XMP_Uns16 id, float data );
+ void SetTag_Double ( XMP_Uns8 ifd, XMP_Uns16 id, double data );
+
+ void SetTag_ASCII ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_StringPtr dataPtr );
+
+ // ---------------------------------------------------------------------------------------------
+
+ virtual bool GetTag_EncodedString ( XMP_Uns8 ifd, XMP_Uns16 id, std::string* utf8Str ) const = 0;
+ virtual void SetTag_EncodedString ( XMP_Uns8 ifd, XMP_Uns16 id, const std::string& utf8Str, XMP_Uns8 encoding ) = 0;
+
+ bool DecodeString ( const void * encodedPtr, size_t encodedLen, std::string* utf8Str ) const;
+ bool EncodeString ( const std::string& utf8Str, XMP_Uns8 encoding, std::string* encodedStr );
+
+ // ---------------------------------------------------------------------------------------------
+
+ bool GetTNailInfo ( XMP_ThumbnailInfo * tnailInfo ) const;
+
+ // ---------------------------------------------------------------------------------------------
+ // \c IsChanged returns true if a read-write stream has changes that need to be saved. This is
+ // only the case when a \c SetTag method has been called. It is not true for changes related to
+ // parsing normalization such as sorting of tags. \c IsChanged returns false for read-only streams.
+
+ virtual bool IsChanged() = 0;
+
+ // ---------------------------------------------------------------------------------------------
+ // \c IsLegacyChanged returns true if a read-write stream has changes that need to be saved to
+ // tags other than the XMP (tag 700). This only the case when a \c SetTag method has been
+ // called. It is not true for changes related to parsing normalization such as sorting of tags.
+ // \c IsLegacyChanged returns false for read-only streams.
+
+ virtual bool IsLegacyChanged() = 0;
+
+ // ---------------------------------------------------------------------------------------------
+ // \c UpdateMemoryStream is mainly applicable to memory-based read-write streams. It recomposes
+ // the memory stream to incorporate all changes. The new length and data pointer are returned.
+ // \c UpdateMemoryStream can be used with a read-only memory stream to get the raw stream info.
+ //
+ // \c UpdateFileStream updates file-based TIFF. The client must guarantee that the TIFF portion
+ // of the file matches that from the parse in the file-based constructor. Offsets saved from that
+ // parse must still be valid. The open file reference need not be the same, e.g. the client can
+ // be doing a crash-safe update into a temporary copy.
+ //
+ // Both \c UpdateMemoryStream and \c UpdateFileStream use an update-by-append model. Changes are
+ // written in-place where they fit, anything requiring growth is appended to the end and the old
+ // space is abandoned. The end for memory-based TIFF is the end of the data block, the end for
+ // file-based TIFF is the end of the file. This update-by-append model has the advantage of not
+ // perturbing any hidden offsets, a common feature of proprietary MakerNotes.
+ //
+ // The condenseStream parameter to UpdateMemoryStream can be used to rewrite the full stream
+ // instead of appending. This will discard any MakerNote tags and risks breaking offsets that
+ // are hidden. This can be necessary though to try to make the TIFF fit in a JPEG file.
+
+ virtual void ParseMemoryStream ( const void* data, XMP_Uns32 length, bool copyData = true ) = 0;
+ virtual void ParseFileStream ( LFA_FileRef fileRef ) = 0;
+
+ virtual void IntegrateFromPShop6 ( const void * buriedPtr, size_t buriedLen ) = 0;
+
+ virtual XMP_Uns32 UpdateMemoryStream ( void** dataPtr, bool condenseStream = false ) = 0;
+ virtual void UpdateFileStream ( LFA_FileRef fileRef ) = 0;
+
+ // ---------------------------------------------------------------------------------------------
+
+ GetUns16_Proc GetUns16; // Get values from the TIFF stream.
+ GetUns32_Proc GetUns32; // Always native endian on the outside, stream endian in the stream.
+ GetFloat_Proc GetFloat;
+ GetDouble_Proc GetDouble;
+
+ PutUns16_Proc PutUns16; // Put values into the TIFF stream.
+ PutUns32_Proc PutUns32; // Always native endian on the outside, stream endian in the stream.
+ PutFloat_Proc PutFloat;
+ PutDouble_Proc PutDouble;
+
+ virtual ~TIFF_Manager() {};
+
+ // ! Hacks to help the reconciliation code accomodate Photoshop behavior:
+ bool xmpHadUserComment, xmpHadRelatedSoundFile;
+
+protected:
+
+ bool bigEndian, nativeEndian;
+
+ XMP_Uns8 * jpegTNailPtr;
+
+ XMP_Uns32 CheckTIFFHeader ( const XMP_Uns8* tiffPtr, XMP_Uns32 length );
+
+ TIFF_Manager(); // Force clients to use the reader or writer derived classes.
+
+ struct RawIFDEntry {
+ XMP_Uns16 id;
+ XMP_Uns16 type;
+ XMP_Uns32 count;
+ XMP_Uns32 dataOrOffset;
+ };
+
+}; // TIFF_Manager
+
+
+// =================================================================================================
+// =================================================================================================
+
+
+// =================================================================================================
+// TIFF_MemoryReader
+// =================
+
+class TIFF_MemoryReader : public TIFF_Manager { // The derived class for memory-based read-only access.
+public:
+
+ bool HasThumbnailIFD() const { return (containedIFDs[kTIFF_TNailIFD].count != 0); };
+ bool HasExifIFD() const { return (containedIFDs[kTIFF_ExifIFD].count != 0); };
+ bool HasGPSInfoIFD() const { return (containedIFDs[kTIFF_GPSInfoIFD].count != 0); };
+
+ bool GetIFD ( XMP_Uns8 ifd, TagInfoMap* ifdMap ) const;
+
+ bool GetTag ( XMP_Uns8 ifd, XMP_Uns16 id, TagInfo* info ) const;
+
+ void SetTag ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns16 type, XMP_Uns32 count, const void* dataPtr ) { NotAppropriate(); };
+
+ void DeleteTag ( XMP_Uns8 ifd, XMP_Uns16 id ) { NotAppropriate(); };
+
+ XMP_Uns32 GetValueOffset ( XMP_Uns8 ifd, XMP_Uns16 id ) const;
+
+ bool GetTag_Integer ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns32* data ) const;
+
+ bool GetTag_Byte ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns8* data ) const;
+ bool GetTag_SByte ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Int8* data ) const;
+ bool GetTag_Short ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns16* data ) const;
+ bool GetTag_SShort ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Int16* data ) const;
+ bool GetTag_Long ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns32* data ) const;
+ bool GetTag_SLong ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Int32* data ) const;
+
+ bool GetTag_Rational ( XMP_Uns8 ifd, XMP_Uns16 id, Rational* data ) const;
+ bool GetTag_SRational ( XMP_Uns8 ifd, XMP_Uns16 id, SRational* data ) const;
+
+ bool GetTag_Float ( XMP_Uns8 ifd, XMP_Uns16 id, float* data ) const;
+ bool GetTag_Double ( XMP_Uns8 ifd, XMP_Uns16 id, double* data ) const;
+
+ bool GetTag_ASCII ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_StringPtr* dataPtr, XMP_StringLen* dataLen ) const;
+
+ bool GetTag_EncodedString ( XMP_Uns8 ifd, XMP_Uns16 id, std::string* utf8Str ) const;
+
+ void SetTag_EncodedString ( XMP_Uns8 ifd, XMP_Uns16 id, const std::string& utf8Str, XMP_Uns8 encoding ) { NotAppropriate(); };
+
+ bool IsChanged() { return false; };
+ bool IsLegacyChanged() { return false; };
+
+ void ParseMemoryStream ( const void* data, XMP_Uns32 length, bool copyData = true );
+ void ParseFileStream ( LFA_FileRef fileRef ) { NotAppropriate(); };
+
+ void IntegrateFromPShop6 ( const void * buriedPtr, size_t buriedLen ) { NotAppropriate(); };
+
+ XMP_Uns32 UpdateMemoryStream ( void** dataPtr, bool condenseStream = false ) { if ( dataPtr != 0 ) *dataPtr = tiffStream; return tiffLength; };
+ void UpdateFileStream ( LFA_FileRef fileRef ) { NotAppropriate(); };
+
+ TIFF_MemoryReader() : ownedStream(false), tiffStream(0), tiffLength(0) {};
+
+ virtual ~TIFF_MemoryReader() { if ( this->ownedStream ) free ( this->tiffStream ); };
+
+private:
+
+ bool ownedStream;
+
+ XMP_Uns8* tiffStream;
+ XMP_Uns32 tiffLength;
+
+ struct TweakedIFDEntry {
+ XMP_Uns16 id;
+ XMP_Uns16 type;
+ XMP_Uns32 bytes;
+ XMP_Uns32 dataOrPtr;
+ TweakedIFDEntry() : id(0), type(0), bytes(0), dataOrPtr(0) {};
+ };
+
+ struct TweakedIFDInfo {
+ XMP_Uns16 count;
+ TweakedIFDEntry* entries;
+ TweakedIFDInfo() : count(0), entries(0) {};
+ };
+
+ TweakedIFDInfo containedIFDs[kTIFF_KnownIFDCount];
+
+ static void SortIFD ( TweakedIFDInfo* thisIFD );
+
+ XMP_Uns32 ProcessOneIFD ( XMP_Uns32 ifdOffset, XMP_Uns8 ifd );
+
+ const TweakedIFDEntry* FindTagInIFD ( XMP_Uns8 ifd, XMP_Uns16 id ) const;
+
+ static inline void NotAppropriate() { XMP_Throw ( "Not appropriate for TIFF_Reader", kXMPErr_InternalFailure ); };
+
+}; // TIFF_MemoryReader
+
+
+// =================================================================================================
+// =================================================================================================
+
+
+// =================================================================================================
+// TIFF_FileWriter
+// ===============
+
+class TIFF_FileWriter : public TIFF_Manager { // The derived class for file-based or read-write access.
+public:
+
+ bool HasThumbnailIFD() const { return this->containedIFDs[kTIFF_TNailIFD].tagMap.size() != 0; };
+ bool HasExifIFD() const { return this->containedIFDs[kTIFF_ExifIFD].tagMap.size() != 0; };
+ bool HasGPSInfoIFD() const { return this->containedIFDs[kTIFF_GPSInfoIFD].tagMap.size() != 0; };
+
+ bool GetIFD ( XMP_Uns8 ifd, TagInfoMap* ifdMap ) const;
+
+ bool GetTag ( XMP_Uns8 ifd, XMP_Uns16 id, TagInfo* info ) const;
+
+ void SetTag ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns16 type, XMP_Uns32 count, const void* dataPtr );
+
+ void DeleteTag ( XMP_Uns8 ifd, XMP_Uns16 id );
+
+ XMP_Uns32 GetValueOffset ( XMP_Uns8 ifd, XMP_Uns16 id ) const;
+
+ bool GetTag_Integer ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns32* data ) const;
+
+ bool GetTag_Byte ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns8* data ) const;
+ bool GetTag_SByte ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Int8* data ) const;
+ bool GetTag_Short ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns16* data ) const;
+ bool GetTag_SShort ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Int16* data ) const;
+ bool GetTag_Long ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Uns32* data ) const;
+ bool GetTag_SLong ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_Int32* data ) const;
+
+ bool GetTag_Rational ( XMP_Uns8 ifd, XMP_Uns16 id, Rational* data ) const;
+ bool GetTag_SRational ( XMP_Uns8 ifd, XMP_Uns16 id, SRational* data ) const;
+
+ bool GetTag_Float ( XMP_Uns8 ifd, XMP_Uns16 id, float* data ) const;
+ bool GetTag_Double ( XMP_Uns8 ifd, XMP_Uns16 id, double* data ) const;
+
+ bool GetTag_ASCII ( XMP_Uns8 ifd, XMP_Uns16 id, XMP_StringPtr* dataPtr, XMP_StringLen* dataLen ) const;
+
+ bool GetTag_EncodedString ( XMP_Uns8 ifd, XMP_Uns16 id, std::string* utf8Str ) const;
+
+ void SetTag_EncodedString ( XMP_Uns8 ifd, XMP_Uns16 id, const std::string& utf8Str, XMP_Uns8 encoding );
+
+ bool IsChanged() { return this->changed; };
+
+ bool IsLegacyChanged();
+
+ enum { kDoNotCopyData = false };
+
+ void ParseMemoryStream ( const void* data, XMP_Uns32 length, bool copyData = true );
+ void ParseFileStream ( LFA_FileRef fileRef );
+
+ void IntegrateFromPShop6 ( const void * buriedPtr, size_t buriedLen );
+
+ XMP_Uns32 UpdateMemoryStream ( void** dataPtr, bool condenseStream = false );
+ void UpdateFileStream ( LFA_FileRef fileRef );
+
+ TIFF_FileWriter();
+
+ virtual ~TIFF_FileWriter();
+
+private:
+
+ bool changed;
+ bool memParsed, fileParsed;
+ bool ownedStream;
+
+ XMP_Uns8* memStream;
+ XMP_Uns32 tiffLength;
+
+ struct InternalTagInfo {
+ XMP_Uns16 id;
+ XMP_Uns16 type;
+ XMP_Uns32 count;
+ XMP_Uns32 dataLen;
+ XMP_Uns32 dataOrOffset; // Small value or large offset in stream endianness.
+ XMP_Uns8* dataPtr; // Always set, even for small values.
+ XMP_Uns32 origLen; // The original data length in bytes.
+ XMP_Uns32 origOffset; // The original data offset, regardless of length.
+ bool changed;
+ InternalTagInfo() : id(0), type(0), count(0), dataLen(0), dataOrOffset(0), dataPtr(0), origLen(0), origOffset(0), changed(false) {};
+ InternalTagInfo ( XMP_Uns16 _id, XMP_Uns16 _type, XMP_Uns32 _count )
+ : id(_id), type(_type), count(_count), dataLen(0), dataOrOffset(0), dataPtr(0), origLen(0), origOffset(0), changed(false) {};
+ ~InternalTagInfo()
+ {
+ if ( this->changed && (this->dataLen > 4) && (this->dataPtr != 0) ) free ( this->dataPtr );
+ };
+ void operator= ( const InternalTagInfo & in )
+ {
+ // ! Gag! Transfer ownership of the dataPtr!
+ if ( this->changed && (this->dataLen > 4) && (this->dataPtr != 0) ) free ( this->dataPtr );
+ memcpy ( this, &in, sizeof ( InternalTagInfo ) ); // AUDIT: Use of sizeof(InternalTagInfo) is safe.
+ if ( this->dataLen <= 4 ) {
+ this->dataPtr = (XMP_Uns8*) &this->dataOrOffset;
+ } else {
+ *((XMP_Uns8**)&in.dataPtr) = 0; // ! Avoid double calls to free from the destructor!
+ }
+ };
+ };
+
+ typedef std::map<XMP_Uns16,InternalTagInfo> InternalTagMap;
+
+ struct InternalIFDInfo {
+ bool changed;
+ XMP_Uns16 origCount; // Original number of IFD entries.
+ XMP_Uns32 origOffset; // Original stream offset of the IFD.
+ XMP_Uns32 origNextIFD; // Original stream offset of the following IFD.
+ InternalTagMap tagMap;
+ InternalIFDInfo() : changed(false), origCount(0), origOffset(0), origNextIFD(0) {};
+ void clear()
+ {
+ this->changed = false;
+ this->origCount = 0;
+ this->origOffset = this->origNextIFD = 0;
+ this->tagMap.clear();
+ };
+ };
+
+ InternalIFDInfo containedIFDs[kTIFF_KnownIFDCount];
+
+ static XMP_Uns8 PickIFD ( XMP_Uns8 ifd, XMP_Uns16 id );
+ const InternalTagInfo* FindTagInIFD ( XMP_Uns8 ifd, XMP_Uns16 id ) const;
+
+ void DeleteExistingInfo();
+
+ XMP_Uns32 ProcessMemoryIFD ( XMP_Uns32 ifdOffset, XMP_Uns8 ifd );
+ XMP_Uns32 ProcessFileIFD ( XMP_Uns8 ifd, XMP_Uns32 ifdOffset, LFA_FileRef fileRef, IOBuffer* ioBuf );
+
+ void ProcessPShop6IFD ( const TIFF_MemoryReader& buriedExif, XMP_Uns8 ifd );
+
+ static void* CopyTagToMasterIFD ( const TagInfo& ps6Tag, InternalIFDInfo* masterIFD );
+
+ void UpdateMemByAppend ( XMP_Uns8** newStream_out, XMP_Uns32* newLength_out,
+ bool appendAll = false, XMP_Uns32 extraSpace = 0 );
+ void UpdateMemByRewrite ( XMP_Uns8** newStream_out, XMP_Uns32* newLength_out );
+
+ XMP_Uns32 DetermineVisibleLength();
+
+ XMP_Uns32 DetermineAppendInfo ( XMP_Uns32 appendedOrigin,
+ bool appendedIFDs[kTIFF_KnownIFDCount],
+ XMP_Uns32 newIFDOffsets[kTIFF_KnownIFDCount],
+ bool appendAll = false );
+
+ void WriteFileIFD ( LFA_FileRef fileRef, InternalIFDInfo & thisIFD );
+
+}; // TIFF_FileWriter
+
+
+// =================================================================================================
+
+#endif // __TIFF_Support_hpp__
diff --git a/source/XMPFiles/FormatSupport/XMPScanner.cpp b/source/XMPFiles/FormatSupport/XMPScanner.cpp
new file mode 100644
index 0000000..acfdce6
--- /dev/null
+++ b/source/XMPFiles/FormatSupport/XMPScanner.cpp
@@ -0,0 +1,1478 @@
+// =================================================================================================
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+//
+// Adobe patent application tracking #P435, entitled 'Unique markers to simplify embedding data of
+// one format in a file with a different format', inventors: Sean Parent, Greg Gilley.
+// =================================================================================================
+
+#if WIN32
+ // The VC++ debugger can't handle long symbol names.
+ #pragma warning ( disable : 4786 )
+#endif
+
+
+#include "XMPScanner.hpp"
+
+#include <cassert>
+#include <string>
+#include <cstdlib>
+
+#if DEBUG
+ #include <iostream>
+ #include <iomanip>
+ #include <fstream>
+#endif
+
+
+#ifndef UseStringPushBack // VC++ 6.x does not provide push_back for strings!
+ #define UseStringPushBack 0
+#endif
+
+
+using namespace std;
+
+
+// *** Consider Boyer-Moore style search for "<?xpacket begin=". It isn't an obvious win, the
+// *** additional code might be slower than scanning every character. Especially if we will
+// *** read every cache line anyway.
+
+
+// =================================================================================================
+// =================================================================================================
+// class PacketMachine
+// ===================
+//
+// This is the packet recognizer state machine. The top of the machine is FindNextPacket, this
+// calls the specific state components and handles transitions. The states are described by an
+// array of RecognizerInfo records, indexed by the RecognizerKind enumeration. Each RecognizerInfo
+// record has a function that does that state's work, the success and failure transition states,
+// and a string literal that is passed to the state function. The literal lets a common MatchChar
+// or MatchString function be used in several places.
+//
+// The state functions are responsible for consuming input to recognize their particular state.
+// This includes intervening nulls for 16 and 32 bit character forms. For the simplicity, things
+// are treated as essentially little endian and the nulls are not actually checked. The opening
+// '<' is found with a byte-by-byte search, then the number of bytes per character is determined
+// by counting the following nulls. From then on, consuming a character means incrementing the
+// buffer pointer by the number of bytes per character. Thus the buffer pointer only points to
+// the "real" bytes. This also means that the pointer can go off the end of the buffer by a
+// variable amount. The amount of overrun is saved so that the pointer can be positioned at the
+// right byte to start the next buffer.
+//
+// The state functions return a TriState value, eTriYes means the pattern was found, eTriNo means
+// the pattern was definitely not found, eTriMaybe means that the end of the buffer was reached
+// while working through the pattern.
+//
+// When eTriYes is returned, the fBufferPtr data member is left pointing to the "real" byte
+// following the last actual byte. Which might not be addressable memory! This also means that
+// a state function can be entered with nothing available in the buffer. When eTriNo is returned,
+// the fBufferPtr data member is left pointing to the byte that caused the failure. The state
+// machine starts over from the failure byte.
+//
+// The state functions must preserve their internal micro-state before returning eTriMaybe, and
+// resume processing when called with the next buffer. The fPosition data member is used to denote
+// how many actual characters have been consumed. The fNullCount data member is used to denote how
+// many nulls are left before the next actual character.
+
+
+// =================================================================================================
+// PacketMachine
+// =============
+
+XMPScanner::PacketMachine::PacketMachine ( XMP_Int64 bufferOffset, const void * bufferOrigin, XMP_Int64 bufferLength ) :
+
+ // Public members
+ fPacketStart ( 0 ),
+ fPacketLength ( 0 ),
+ fBytesAttr ( -1 ),
+ fCharForm ( eChar8Bit ),
+ fAccess ( ' ' ),
+ fBogusPacket ( false ),
+
+ // Private members
+ fBufferOffset ( bufferOffset ),
+ fBufferOrigin ( (const char *) bufferOrigin ),
+ fBufferPtr ( fBufferOrigin ),
+ fBufferLimit ( fBufferOrigin + bufferLength ),
+ fRecognizer ( eLeadInRecognizer ),
+ fPosition ( 0 ),
+ fBytesPerChar ( 1 ),
+ fBufferOverrun ( 0 ),
+ fQuoteChar ( ' ' )
+
+{
+ /*
+ REVIEW NOTES : Should the buffer stuff be in a class?
+ */
+
+ assert ( bufferOrigin != NULL );
+ assert ( bufferLength != 0 );
+
+} // PacketMachine
+
+
+// =================================================================================================
+// ~PacketMachine
+// ==============
+
+XMPScanner::PacketMachine::~PacketMachine ()
+{
+
+ // An empty placeholder.
+
+} // ~PacketMachine
+
+
+// =================================================================================================
+// AssociateBuffer
+// ===============
+
+void
+XMPScanner::PacketMachine::AssociateBuffer ( XMP_Int64 bufferOffset, const void * bufferOrigin, XMP_Int64 bufferLength )
+{
+
+ fBufferOffset = bufferOffset;
+ fBufferOrigin = (const char *) bufferOrigin;
+ fBufferPtr = fBufferOrigin + fBufferOverrun;
+ fBufferLimit = fBufferOrigin + bufferLength;
+
+} // AssociateBuffer
+
+
+// =================================================================================================
+// ResetMachine
+// ============
+
+void
+XMPScanner::PacketMachine::ResetMachine ()
+{
+
+ fRecognizer = eLeadInRecognizer;
+ fPosition = 0;
+ fBufferOverrun = 0;
+ fCharForm = eChar8Bit;
+ fBytesPerChar = 1;
+ fAccess = ' ';
+ fBytesAttr = -1;
+ fBogusPacket = false;
+
+ fAttrName.erase ( fAttrName.begin(), fAttrName.end() );
+ fAttrValue.erase ( fAttrValue.begin(), fAttrValue.end() );
+ fEncodingAttr.erase ( fEncodingAttr.begin(), fEncodingAttr.end() );
+
+} // ResetMachine
+
+
+// =================================================================================================
+// FindLessThan
+// ============
+
+XMPScanner::PacketMachine::TriState
+XMPScanner::PacketMachine::FindLessThan ( PacketMachine * ths, const char * which )
+{
+
+ if ( *which == 'H' ) {
+
+ // --------------------------------------------------------------------------------
+ // We're looking for the '<' of the header. If we fail there is no packet in this
+ // part of the input, so return eTriNo.
+
+ ths->fCharForm = eChar8Bit; // We might have just failed from a bogus 16 or 32 bit case.
+ ths->fBytesPerChar = 1;
+
+ while ( ths->fBufferPtr < ths->fBufferLimit ) { // Don't skip nulls for the header's '<'!
+ if ( *ths->fBufferPtr == '<' ) break;
+ ths->fBufferPtr++;
+ }
+
+ if ( ths->fBufferPtr >= ths->fBufferLimit ) return eTriNo;
+ ths->fBufferPtr++;
+ return eTriYes;
+
+ } else {
+
+ // --------------------------------------------------------------------------------
+ // We're looking for the '<' of the trailer. We're already inside the packet body,
+ // looking for the trailer. So here if we fail we must return eTriMaybe so that we
+ // keep looking for the trailer in the next buffer.
+
+ const int bytesPerChar = ths->fBytesPerChar;
+
+ while ( ths->fBufferPtr < ths->fBufferLimit ) {
+ if ( *ths->fBufferPtr == '<' ) break;
+ ths->fBufferPtr += bytesPerChar;
+ }
+
+ if ( ths->fBufferPtr >= ths->fBufferLimit ) return eTriMaybe;
+ ths->fBufferPtr += bytesPerChar;
+ return eTriYes;
+
+ }
+
+} // FindLessThan
+
+
+// =================================================================================================
+// MatchString
+// ===========
+
+XMPScanner::PacketMachine::TriState
+XMPScanner::PacketMachine::MatchString ( PacketMachine * ths, const char * literal )
+{
+ const int bytesPerChar = ths->fBytesPerChar;
+ const char * litPtr = literal + ths->fPosition;
+ const int charsToGo = strlen ( literal ) - ths->fPosition;
+ int charsDone = 0;
+
+ while ( (charsDone < charsToGo) && (ths->fBufferPtr < ths->fBufferLimit) ) {
+ if ( *litPtr != *ths->fBufferPtr ) return eTriNo;
+ charsDone++;
+ litPtr++;
+ ths->fBufferPtr += bytesPerChar;
+ }
+
+ if ( charsDone == charsToGo ) return eTriYes;
+ ths->fPosition += charsDone;
+ return eTriMaybe;
+
+} // MatchString
+
+
+// =================================================================================================
+// MatchChar
+// =========
+
+XMPScanner::PacketMachine::TriState
+XMPScanner::PacketMachine::MatchChar ( PacketMachine * ths, const char * literal )
+{
+ const int bytesPerChar = ths->fBytesPerChar;
+
+ if ( ths->fBufferPtr >= ths->fBufferLimit ) return eTriMaybe;
+
+ const char currChar = *ths->fBufferPtr;
+ if ( currChar != *literal ) return eTriNo;
+ ths->fBufferPtr += bytesPerChar;
+ return eTriYes;
+
+} // MatchChar
+
+
+// =================================================================================================
+// MatchOpenQuote
+// ==============
+
+XMPScanner::PacketMachine::TriState
+XMPScanner::PacketMachine::MatchOpenQuote ( PacketMachine * ths, const char * /* unused */ )
+{
+ const int bytesPerChar = ths->fBytesPerChar;
+
+ if ( ths->fBufferPtr >= ths->fBufferLimit ) return eTriMaybe;
+
+ const char currChar = *ths->fBufferPtr;
+ if ( (currChar != '\'') && (currChar != '"') ) return eTriNo;
+ ths->fQuoteChar = currChar;
+ ths->fBufferPtr += bytesPerChar;
+ return eTriYes;
+
+} // MatchOpenQuote
+
+
+// =================================================================================================
+// MatchCloseQuote
+// ===============
+
+XMPScanner::PacketMachine::TriState
+XMPScanner::PacketMachine::MatchCloseQuote ( PacketMachine * ths, const char * /* unused */ )
+{
+
+ return MatchChar ( ths, &ths->fQuoteChar );
+
+} // MatchCloseQuote
+
+
+// =================================================================================================
+// CaptureAttrName
+// ===============
+
+XMPScanner::PacketMachine::TriState
+XMPScanner::PacketMachine::CaptureAttrName ( PacketMachine * ths, const char * /* unused */ )
+{
+ const int bytesPerChar = ths->fBytesPerChar;
+ char currChar;
+
+ if ( ths->fPosition == 0 ) { // Get the first character in the name.
+
+ if ( ths->fBufferPtr >= ths->fBufferLimit ) return eTriMaybe;
+
+ currChar = *ths->fBufferPtr;
+ if ( ths->fAttrName.size() == 0 ) {
+ if ( ! ( ( ('a' <= currChar) && (currChar <= 'z') ) ||
+ ( ('A' <= currChar) && (currChar <= 'Z') ) ||
+ (currChar == '_') || (currChar == ':') ) ) {
+ return eTriNo;
+ }
+ }
+
+ ths->fAttrName.erase ( ths->fAttrName.begin(), ths->fAttrName.end() );
+ #if UseStringPushBack
+ ths->fAttrName.push_back ( currChar );
+ #else
+ ths->fAttrName.insert ( ths->fAttrName.end(), currChar );
+ #endif
+ ths->fBufferPtr += bytesPerChar;
+
+ }
+
+ while ( ths->fBufferPtr < ths->fBufferLimit ) { // Get the remainder of the name.
+
+ currChar = *ths->fBufferPtr;
+ if ( ! ( ( ('a' <= currChar) && (currChar <= 'z') ) ||
+ ( ('A' <= currChar) && (currChar <= 'Z') ) ||
+ ( ('0' <= currChar) && (currChar <= '9') ) ||
+ (currChar == '-') || (currChar == '.') || (currChar == '_') || (currChar == ':') ) ) {
+ break;
+ }
+
+ #if UseStringPushBack
+ ths->fAttrName.push_back ( currChar );
+ #else
+ ths->fAttrName.insert ( ths->fAttrName.end(), currChar );
+ #endif
+ ths->fBufferPtr += bytesPerChar;
+
+ }
+
+ if ( ths->fBufferPtr < ths->fBufferLimit ) return eTriYes;
+ ths->fPosition = ths->fAttrName.size(); // The name might span into the next buffer.
+ return eTriMaybe;
+
+} // CaptureAttrName
+
+
+// =================================================================================================
+// CaptureAttrValue
+// ================
+//
+// Recognize the equal sign and the quoted string value, capture the value along the way.
+
+XMPScanner::PacketMachine::TriState
+XMPScanner::PacketMachine::CaptureAttrValue ( PacketMachine * ths, const char * /* unused */ )
+{
+ const int bytesPerChar = ths->fBytesPerChar;
+ char currChar = 0;
+ TriState result = eTriMaybe;
+
+ if ( ths->fBufferPtr >= ths->fBufferLimit ) return eTriMaybe;
+
+ switch ( ths->fPosition ) {
+
+ case 0 : // The name should haved ended at the '=', nulls already skipped.
+
+ if ( ths->fBufferPtr >= ths->fBufferLimit ) return eTriMaybe;
+ if ( *ths->fBufferPtr != '=' ) return eTriNo;
+ ths->fBufferPtr += bytesPerChar;
+ ths->fPosition = 1;
+ // fall through OK because MatchOpenQuote will check the buffer limit and nulls ...
+
+ case 1 : // Look for the open quote.
+
+ result = MatchOpenQuote ( ths, NULL );
+ if ( result != eTriYes ) return result;
+ ths->fPosition = 2;
+ // fall through OK because the buffer limit and nulls are checked below ...
+
+ default : // Look for the close quote, capturing the value along the way.
+
+ assert ( ths->fPosition == 2 );
+
+ const char quoteChar = ths->fQuoteChar;
+
+ while ( ths->fBufferPtr < ths->fBufferLimit ) {
+ currChar = *ths->fBufferPtr;
+ if ( currChar == quoteChar ) break;
+ #if UseStringPushBack
+ ths->fAttrValue.push_back ( currChar );
+ #else
+ ths->fAttrValue.insert ( ths->fAttrValue.end(), currChar );
+ #endif
+ ths->fBufferPtr += bytesPerChar;
+ }
+
+ if ( ths->fBufferPtr >= ths->fBufferLimit ) return eTriMaybe;
+ assert ( currChar == quoteChar );
+ ths->fBufferPtr += bytesPerChar; // Advance past the closing quote.
+ return eTriYes;
+
+ }
+
+} // CaptureAttrValue
+
+
+// =================================================================================================
+// RecordStart
+// ===========
+//
+// Note that this routine looks at bytes, not logical characters. It has to figure out how many
+// bytes per character there are so that the other recognizers can skip intervening nulls.
+
+XMPScanner::PacketMachine::TriState
+XMPScanner::PacketMachine::RecordStart ( PacketMachine * ths, const char * /* unused */ )
+{
+
+ while ( true ) {
+
+ if ( ths->fBufferPtr >= ths->fBufferLimit ) return eTriMaybe;
+
+ const char currByte = *ths->fBufferPtr;
+
+ switch ( ths->fPosition ) {
+
+ case 0 : // Record the length.
+ assert ( ths->fCharForm == eChar8Bit );
+ assert ( ths->fBytesPerChar == 1 );
+ ths->fPacketStart = ths->fBufferOffset + ((ths->fBufferPtr - 1) - ths->fBufferOrigin);
+ ths->fPacketLength = 0;
+ ths->fPosition = 1;
+ // ! OK to fall through here, we didn't consume a byte in this step.
+
+ case 1 : // Look for the first null byte.
+ if ( currByte != 0 ) return eTriYes; // No nulls found.
+ ths->fCharForm = eChar16BitBig; // Assume 16 bit big endian for now.
+ ths->fBytesPerChar = 2;
+ ths->fBufferPtr++;
+ ths->fPosition = 2;
+ break; // ! Don't fall through, have to check for the end of the buffer between each byte.
+
+ case 2 : // One null was found, look for a second.
+ if ( currByte != 0 ) return eTriYes; // Just one null found.
+ ths->fBufferPtr++;
+ ths->fPosition = 3;
+ break;
+
+ case 3 : // Two nulls were found, look for a third.
+ if ( currByte != 0 ) return eTriNo; // Just two nulls is not valid.
+ ths->fCharForm = eChar32BitBig; // Assume 32 bit big endian for now.
+ ths->fBytesPerChar = 4;
+ ths->fBufferPtr++;
+ return eTriYes;
+ break;
+
+ }
+
+ }
+
+} // RecordStart
+
+
+// =================================================================================================
+// RecognizeBOM
+// ============
+//
+// Recognizing the byte order marker is a surprisingly messy thing to do. It can't be done by the
+// normal string matcher, there are no intervening nulls. There are 4 transitions after the opening
+// quote, the closing quote or one of the three encodings. For the actual BOM there are then 1 or 2
+// following bytes that depend on which of the encodings we're in. Not to mention that the buffer
+// might end at any point.
+//
+// The intervening null count done earlier determined 8, 16, or 32 bits per character, but not the
+// big or little endian nature for the 16/32 bit cases. The BOM must be present for the 16 and 32
+// bit cases in order to determine the endian mode. There are six possible byte sequences for the
+// quoted BOM string, ignoring the differences for quoting with ''' versus '"'.
+//
+// Keep in mind that for the 16 and 32 bit cases there will be nulls for the quote. In the table
+// below the symbol <quote> means just the one byte containing the ''' or '"'. The nulls for the
+// quote character are explicitly shown.
+//
+// <quote> <quote> - 1: No BOM, this must be an 8 bit case.
+// <quote> \xEF \xBB \xBF <quote> - 1.12-13: The 8 bit form.
+//
+// <quote> \xFE \xFF \x00 <quote> - 1.22-23: The 16 bit, big endian form
+// <quote> \x00 \xFF \xFE <quote> - 1.32-33: The 16 bit, little endian form.
+//
+// <quote> \x00 \x00 \xFE \xFF \x00 \x00 \x00 <quote> - 1.32.43-45.56-57: The 32 bit, big endian form.
+// <quote> \x00 \x00 \x00 \xFF \xFE \x00 \x00 <quote> - 1.32.43.54-57: The 32 bit, little endian form.
+
+enum {
+ eBOM_8_1 = 0xEF,
+ eBOM_8_2 = 0xBB,
+ eBOM_8_3 = 0xBF,
+ eBOM_Big_1 = 0xFE,
+ eBOM_Big_2 = 0xFF,
+ eBOM_Little_1 = eBOM_Big_2,
+ eBOM_Little_2 = eBOM_Big_1
+};
+
+XMPScanner::PacketMachine::TriState
+XMPScanner::PacketMachine::RecognizeBOM ( PacketMachine * ths, const char * /* unused */ )
+{
+ const int bytesPerChar = ths->fBytesPerChar;
+
+ while ( true ) { // Handle one character at a time, the micro-state (fPosition) changes for each.
+
+ if ( ths->fBufferPtr >= ths->fBufferLimit ) return eTriMaybe;
+
+ const unsigned char currChar = *ths->fBufferPtr; // ! The BOM bytes look like integers bigger than 127.
+
+ switch ( ths->fPosition ) {
+
+ case 0 : // Look for the opening quote.
+ if ( (currChar != '\'') && (currChar != '"') ) return eTriNo;
+ ths->fQuoteChar = currChar;
+ ths->fBufferPtr++;
+ ths->fPosition = 1;
+ break; // ! Don't fall through, have to check for the end of the buffer between each byte.
+
+ case 1 : // Look at the byte immediately following the opening quote.
+ if ( currChar == ths->fQuoteChar ) { // Closing quote, no BOM character, must be 8 bit.
+ if ( ths->fCharForm != eChar8Bit ) return eTriNo;
+ ths->fBufferPtr += bytesPerChar; // Skip the nulls after the closing quote.
+ return eTriYes;
+ } else if ( currChar == eBOM_8_1 ) { // Start of the 8 bit form.
+ if ( ths->fCharForm != eChar8Bit ) return eTriNo;
+ ths->fBufferPtr++;
+ ths->fPosition = 12;
+ } else if ( currChar == eBOM_Big_1 ) { // Start of the 16 bit big endian form.
+ if ( ths->fCharForm != eChar16BitBig ) return eTriNo;
+ ths->fBufferPtr++;
+ ths->fPosition = 22;
+ } else if ( currChar == 0 ) { // Start of the 16 bit little endian or either 32 bit form.
+ if ( ths->fCharForm == eChar8Bit ) return eTriNo;
+ ths->fBufferPtr++;
+ ths->fPosition = 32;
+ } else {
+ return eTriNo;
+ }
+ break;
+
+ case 12 : // Look for the second byte of the 8 bit form.
+ if ( currChar != eBOM_8_2 ) return eTriNo;
+ ths->fPosition = 13;
+ ths->fBufferPtr++;
+ break;
+
+ case 13 : // Look for the third byte of the 8 bit form.
+ if ( currChar != eBOM_8_3 ) return eTriNo;
+ ths->fPosition = 99;
+ ths->fBufferPtr++;
+ break;
+
+ case 22 : // Look for the second byte of the 16 bit big endian form.
+ if ( currChar != eBOM_Big_2 ) return eTriNo;
+ ths->fPosition = 23;
+ ths->fBufferPtr++;
+ break;
+
+ case 23 : // Look for the null before the closing quote of the 16 bit big endian form.
+ if ( currChar != 0 ) return eTriNo;
+ ths->fBufferPtr++;
+ ths->fPosition = 99;
+ break;
+
+ case 32 : // Look at the second byte of the 16 bit little endian or either 32 bit form.
+ if ( currChar == eBOM_Little_1 ) {
+ ths->fPosition = 33;
+ } else if ( currChar == 0 ) {
+ ths->fPosition = 43;
+ } else {
+ return eTriNo;
+ }
+ ths->fBufferPtr++;
+ break;
+
+ case 33 : // Look for the third byte of the 16 bit little endian form.
+ if ( ths->fCharForm != eChar16BitBig ) return eTriNo; // Null count before assumed big endian.
+ if ( currChar != eBOM_Little_2 ) return eTriNo;
+ ths->fCharForm = eChar16BitLittle;
+ ths->fPosition = 99;
+ ths->fBufferPtr++;
+ break;
+
+ case 43 : // Look at the third byte of either 32 bit form.
+ if ( ths->fCharForm != eChar32BitBig ) return eTriNo; // Null count before assumed big endian.
+ if ( currChar == eBOM_Big_1 ) {
+ ths->fPosition = 44;
+ } else if ( currChar == 0 ) {
+ ths->fPosition = 54;
+ } else {
+ return eTriNo;
+ }
+ ths->fBufferPtr++;
+ break;
+
+ case 44 : // Look for the fourth byte of the 32 bit big endian form.
+ if ( currChar != eBOM_Big_2 ) return eTriNo;
+ ths->fPosition = 45;
+ ths->fBufferPtr++;
+ break;
+
+ case 45 : // Look for the first null before the closing quote of the 32 bit big endian form.
+ if ( currChar != 0 ) return eTriNo;
+ ths->fPosition = 56;
+ ths->fBufferPtr++;
+ break;
+
+ case 54 : // Look for the fourth byte of the 32 bit little endian form.
+ ths->fCharForm = eChar32BitLittle;
+ if ( currChar != eBOM_Little_1 ) return eTriNo;
+ ths->fPosition = 55;
+ ths->fBufferPtr++;
+ break;
+
+ case 55 : // Look for the fifth byte of the 32 bit little endian form.
+ if ( currChar != eBOM_Little_2 ) return eTriNo;
+ ths->fPosition = 56;
+ ths->fBufferPtr++;
+ break;
+
+ case 56 : // Look for the next to last null before the closing quote of the 32 bit forms.
+ if ( currChar != 0 ) return eTriNo;
+ ths->fPosition = 57;
+ ths->fBufferPtr++;
+ break;
+
+ case 57 : // Look for the last null before the closing quote of the 32 bit forms.
+ if ( currChar != 0 ) return eTriNo;
+ ths->fPosition = 99;
+ ths->fBufferPtr++;
+ break;
+
+ default : // Look for the closing quote.
+ assert ( ths->fPosition == 99 );
+ if ( currChar != ths->fQuoteChar ) return eTriNo;
+ ths->fBufferPtr += bytesPerChar; // Skip the nulls after the closing quote.
+ return eTriYes;
+ break;
+
+ }
+
+ }
+
+} // RecognizeBOM
+
+
+// =================================================================================================
+// RecordHeadAttr
+// ==============
+
+XMPScanner::PacketMachine::TriState
+XMPScanner::PacketMachine::RecordHeadAttr ( PacketMachine * ths, const char * /* unused */ )
+{
+
+ if ( ths->fAttrName == "encoding" ) {
+
+ assert ( ths->fEncodingAttr.empty() );
+ ths->fEncodingAttr = ths->fAttrValue;
+
+ } else if ( ths->fAttrName == "bytes" ) {
+
+ long value = 0;
+ int count = ths->fAttrValue.size();
+ int i;
+
+ assert ( ths->fBytesAttr == -1 );
+
+ if ( count > 0 ) { // Allow bytes='' to be the same as no bytes attribute.
+
+ for ( i = 0; i < count; i++ ) {
+ const char currChar = ths->fAttrValue[i];
+ if ( ('0' <= currChar) && (currChar <= '9') ) {
+ value = (value * 10) + (currChar - '0');
+ } else {
+ ths->fBogusPacket = true;
+ value = -1;
+ break;
+ }
+ }
+ ths->fBytesAttr = value;
+
+ if ( CharFormIs16Bit ( ths->fCharForm ) ) {
+ if ( (ths->fBytesAttr & 1) != 0 ) ths->fBogusPacket = true;
+ } else if ( CharFormIs32Bit ( ths->fCharForm ) ) {
+ if ( (ths->fBytesAttr & 3) != 0 ) ths->fBogusPacket = true;
+ }
+
+ }
+
+ }
+
+ ths->fAttrName.erase ( ths->fAttrName.begin(), ths->fAttrName.end() );
+ ths->fAttrValue.erase ( ths->fAttrValue.begin(), ths->fAttrValue.end() );
+
+ return eTriYes;
+
+} // RecordHeadAttr
+
+
+// =================================================================================================
+// CaptureAccess
+// =============
+
+XMPScanner::PacketMachine::TriState
+XMPScanner::PacketMachine::CaptureAccess ( PacketMachine * ths, const char * /* unused */ )
+{
+ const int bytesPerChar = ths->fBytesPerChar;
+
+ while ( true ) {
+
+ if ( ths->fBufferPtr >= ths->fBufferLimit ) return eTriMaybe;
+
+ const char currChar = *ths->fBufferPtr;
+
+ switch ( ths->fPosition ) {
+
+ case 0 : // Look for the opening quote.
+ if ( (currChar != '\'') && (currChar != '"') ) return eTriNo;
+ ths->fQuoteChar = currChar;
+ ths->fBufferPtr += bytesPerChar;
+ ths->fPosition = 1;
+ break; // ! Don't fall through, have to check for the end of the buffer between each byte.
+
+ case 1 : // Look for the 'r' or 'w'.
+ if ( (currChar != 'r') && (currChar != 'w') ) return eTriNo;
+ ths->fAccess = currChar;
+ ths->fBufferPtr += bytesPerChar;
+ ths->fPosition = 2;
+ break;
+
+ default : // Look for the closing quote.
+ assert ( ths->fPosition == 2 );
+ if ( currChar != ths->fQuoteChar ) return eTriNo;
+ ths->fBufferPtr += bytesPerChar;
+ return eTriYes;
+ break;
+
+ }
+
+ }
+
+} // CaptureAccess
+
+
+// =================================================================================================
+// RecordTailAttr
+// ==============
+
+XMPScanner::PacketMachine::TriState
+XMPScanner::PacketMachine::RecordTailAttr ( PacketMachine * ths, const char * /* unused */ )
+{
+
+ // There are no known "general" attributes for the packet trailer.
+
+ ths->fAttrName.erase ( ths->fAttrName.begin(), ths->fAttrName.end() );
+ ths->fAttrValue.erase ( ths->fAttrValue.begin(), ths->fAttrValue.end() );
+
+ return eTriYes;
+
+
+} // RecordTailAttr
+
+
+// =================================================================================================
+// CheckPacketEnd
+// ==============
+//
+// Check for trailing padding and record the packet length. We have trailing padding if the bytes
+// attribute is present and has a value greater than the current length.
+
+XMPScanner::PacketMachine::TriState
+XMPScanner::PacketMachine::CheckPacketEnd ( PacketMachine * ths, const char * /* unused */ )
+{
+ const int bytesPerChar = ths->fBytesPerChar;
+
+ if ( ths->fPosition == 0 ) { // First call, decide if there is trailing padding.
+
+ const XMP_Int64 currLen64 = (ths->fBufferOffset + (ths->fBufferPtr - ths->fBufferOrigin)) - ths->fPacketStart;
+ if ( currLen64 > 0x7FFFFFFF ) throw std::runtime_error ( "Packet length exceeds 2GB-1" );
+ const XMP_Int32 currLength = (XMP_Int32)currLen64;
+
+ if ( (ths->fBytesAttr != -1) && (ths->fBytesAttr != currLength) ) {
+ if ( ths->fBytesAttr < currLength ) {
+ ths->fBogusPacket = true; // The bytes attribute value is too small.
+ } else {
+ ths->fPosition = ths->fBytesAttr - currLength;
+ if ( (ths->fPosition % ths->fBytesPerChar) != 0 ) {
+ ths->fBogusPacket = true; // The padding is not a multiple of the character size.
+ ths->fPosition = (ths->fPosition / ths->fBytesPerChar) * ths->fBytesPerChar;
+ }
+ }
+ }
+
+ }
+
+ while ( ths->fPosition > 0 ) {
+
+ if ( ths->fBufferPtr >= ths->fBufferLimit ) return eTriMaybe;
+
+ const char currChar = *ths->fBufferPtr;
+
+ if ( (currChar != ' ') && (currChar != '\t') && (currChar != '\n') && (currChar != '\r') ) {
+ ths->fBogusPacket = true; // The padding is not whitespace.
+ break; // Stop the packet here.
+ }
+
+ ths->fPosition -= bytesPerChar;
+ ths->fBufferPtr += bytesPerChar;
+
+ }
+
+ const XMP_Int64 currLen64 = (ths->fBufferOffset + (ths->fBufferPtr - ths->fBufferOrigin)) - ths->fPacketStart;
+ if ( currLen64 > 0x7FFFFFFF ) throw std::runtime_error ( "Packet length exceeds 2GB-1" );
+ ths->fPacketLength = (XMP_Int32)currLen64;
+ return eTriYes;
+
+} // CheckPacketEnd
+
+
+// =================================================================================================
+// CheckFinalNulls
+// ===============
+//
+// Do some special case processing for little endian characters. We have to make sure the presumed
+// nulls after the last character actually exist, i.e. that the stream does not end too soon. Note
+// that the prior character scanning has moved the buffer pointer to the address following the last
+// byte of the last character. I.e. we're already past the presumed nulls, so we can't check their
+// content. All we can do is verify that the stream does not end too soon.
+//
+// Doing this check is simple yet subtle. If we're still in the current buffer then the trailing
+// bytes obviously exist. If we're exactly at the end of the buffer then the bytes also exist.
+// The only question is when we're actually past this buffer, partly into the next buffer. This is
+// when "ths->fBufferPtr > ths->fBufferLimit" on entry. For that case we have to wait until we've
+// actually seen enough extra bytes of input.
+//
+// Since the normal buffer processing is already adjusting for this partial character overrun, all
+// that needs to be done here is wait until "ths->fBufferPtr <= ths->fBufferLimit" on entry. In
+// other words, if we're presently too far, ths->fBufferPtr will be adjusted by the amount of the
+// overflow the next time XMPScanner::Scan is called. This might still be too far, so just keep
+// waiting for enough data to pass by.
+//
+// Note that there is a corresponding special case for big endian characters, we must decrement the
+// starting offset by the number of leading nulls. But we don't do that here, we leave it to the
+// outer code. This is because the leading nulls might have been at the exact end of a previous
+// buffer, in which case we have to also decrement the length of that raw data snip.
+
+XMPScanner::PacketMachine::TriState
+XMPScanner::PacketMachine::CheckFinalNulls ( PacketMachine * ths, const char * /* unused */ )
+{
+
+ if ( (ths->fCharForm != eChar8Bit) && CharFormIsLittleEndian ( ths->fCharForm ) ) {
+ if ( ths->fBufferPtr > ths->fBufferLimit ) return eTriMaybe;
+ }
+
+ return eTriYes;
+
+} // CheckFinalNulls
+
+
+// =================================================================================================
+// SetNextRecognizer
+// =================
+
+void
+XMPScanner::PacketMachine::SetNextRecognizer ( RecognizerKind nextRecognizer )
+{
+
+ fRecognizer = nextRecognizer;
+ fPosition = 0;
+
+} // SetNextRecognizer
+
+
+// =================================================================================================
+// FindNextPacket
+// ==============
+
+// *** When we start validating intervening nulls for 2 and 4 bytes characters, throw an exception
+// *** for errors. Don't return eTriNo, that might skip at an optional point.
+
+XMPScanner::PacketMachine::TriState
+XMPScanner::PacketMachine::FindNextPacket ()
+{
+
+ TriState status;
+
+ #define kPacketHead "?xpacket begin="
+ #define kPacketID "W5M0MpCehiHzreSzNTczkc9d"
+ #define kPacketTail "?xpacket end="
+
+ static const RecognizerInfo recognizerTable [eRecognizerCount] = { // ! Would be safer to assign these explicitly.
+
+ // proc successNext failureNext literal
+
+ { NULL, eFailureRecognizer, eFailureRecognizer, NULL}, // eFailureRecognizer
+ { NULL, eSuccessRecognizer, eSuccessRecognizer, NULL}, // eSuccessRecognizer
+
+ { FindLessThan, eHeadStartRecorder, eFailureRecognizer, "H" }, // eLeadInRecognizer
+ { RecordStart, eHeadStartRecognizer, eLeadInRecognizer, NULL }, // eHeadStartRecorder
+ { MatchString, eBOMRecognizer, eLeadInRecognizer, kPacketHead }, // eHeadStartRecognizer
+
+ { RecognizeBOM, eIDTagRecognizer, eLeadInRecognizer, NULL }, // eBOMRecognizer
+
+ { MatchString, eIDOpenRecognizer, eLeadInRecognizer, " id=" }, // eIDTagRecognizer
+ { MatchOpenQuote, eIDValueRecognizer, eLeadInRecognizer, NULL }, // eIDOpenRecognizer
+ { MatchString, eIDCloseRecognizer, eLeadInRecognizer, kPacketID }, // eIDValueRecognizer
+ { MatchCloseQuote, eAttrSpaceRecognizer_1, eLeadInRecognizer, NULL }, // eIDCloseRecognizer
+
+ { MatchChar, eAttrNameRecognizer_1, eHeadEndRecognizer, " " }, // eAttrSpaceRecognizer_1
+ { CaptureAttrName, eAttrValueRecognizer_1, eLeadInRecognizer, NULL }, // eAttrNameRecognizer_1
+ { CaptureAttrValue, eAttrValueRecorder_1, eLeadInRecognizer, NULL }, // eAttrValueRecognizer_1
+ { RecordHeadAttr, eAttrSpaceRecognizer_1, eLeadInRecognizer, NULL }, // eAttrValueRecorder_1
+
+ { MatchString, eBodyRecognizer, eLeadInRecognizer, "?>" }, // eHeadEndRecognizer
+
+ { FindLessThan, eTailStartRecognizer, eBodyRecognizer, "T"}, // eBodyRecognizer
+
+ { MatchString, eAccessValueRecognizer, eBodyRecognizer, kPacketTail }, // eTailStartRecognizer
+ { CaptureAccess, eAttrSpaceRecognizer_2, eBodyRecognizer, NULL }, // eAccessValueRecognizer
+
+ { MatchChar, eAttrNameRecognizer_2, eTailEndRecognizer, " " }, // eAttrSpaceRecognizer_2
+ { CaptureAttrName, eAttrValueRecognizer_2, eBodyRecognizer, NULL }, // eAttrNameRecognizer_2
+ { CaptureAttrValue, eAttrValueRecorder_2, eBodyRecognizer, NULL }, // eAttrValueRecognizer_2
+ { RecordTailAttr, eAttrSpaceRecognizer_2, eBodyRecognizer, NULL }, // eAttrValueRecorder_2
+
+ { MatchString, ePacketEndRecognizer, eBodyRecognizer, "?>" }, // eTailEndRecognizer
+ { CheckPacketEnd, eCloseOutRecognizer, eBodyRecognizer, "" }, // ePacketEndRecognizer
+ { CheckFinalNulls, eSuccessRecognizer, eBodyRecognizer, "" } // eCloseOutRecognizer
+
+ };
+
+ while ( true ) {
+
+ switch ( fRecognizer ) {
+
+ case eFailureRecognizer :
+ return eTriNo;
+
+ case eSuccessRecognizer :
+ return eTriYes;
+
+ default :
+
+ // -------------------------------------------------------------------
+ // For everything else, the normal cases, use the state machine table.
+
+ const RecognizerInfo * thisState = &recognizerTable [fRecognizer];
+
+ status = thisState->proc ( this, thisState->literal );
+
+ switch ( status ) {
+
+ case eTriNo :
+ SetNextRecognizer ( thisState->failureNext );
+ continue;
+
+ case eTriYes :
+ SetNextRecognizer ( thisState->successNext );
+ continue;
+
+ case eTriMaybe :
+ fBufferOverrun = fBufferPtr - fBufferLimit;
+ return eTriMaybe; // Keep this recognizer intact, to be resumed later.
+
+ }
+
+ } // switch ( fRecognizer ) { ...
+
+ } // while ( true ) { ...
+
+} // FindNextPacket
+
+
+// =================================================================================================
+// =================================================================================================
+// class InternalSnip
+// ==================
+
+
+// =================================================================================================
+// InternalSnip
+// ============
+
+XMPScanner::InternalSnip::InternalSnip ( XMP_Int64 offset, XMP_Int64 length )
+{
+
+ fInfo.fOffset = offset;
+ fInfo.fLength = length;
+
+} // InternalSnip
+
+
+// =================================================================================================
+// InternalSnip
+// ============
+
+XMPScanner::InternalSnip::InternalSnip ( const InternalSnip & rhs ) :
+ fInfo ( rhs.fInfo ),
+ fMachine ( NULL )
+{
+
+ assert ( rhs.fMachine.get() == NULL ); // Don't copy a snip with a machine.
+ assert ( (rhs.fInfo.fEncodingAttr == 0) || (*rhs.fInfo.fEncodingAttr == 0) ); // Don't copy a snip with an encoding.
+
+} // InternalSnip
+
+
+// =================================================================================================
+// ~InternalSnip
+// =============
+
+XMPScanner::InternalSnip::~InternalSnip ()
+{
+} // ~InternalSnip
+
+
+
+// =================================================================================================
+// =================================================================================================
+// class XMPScanner
+// ================
+
+
+// =================================================================================================
+// DumpSnipList
+// ============
+
+#if DEBUG
+
+static const char * snipStateName [6] = { "not-seen", "pending", "raw-data", "good-packet", "partial", "bad-packet" };
+
+void
+XMPScanner::DumpSnipList ( const char * title )
+{
+ InternalSnipIterator currPos = fInternalSnips.begin();
+ InternalSnipIterator endPos = fInternalSnips.end();
+
+ cout << endl << title << " snip list: " << fInternalSnips.size() << endl;
+
+ for ( ; currPos != endPos; ++currPos ) {
+ SnipInfo * currSnip = &currPos->fInfo;
+ cout << '\t' << currSnip << ' ' << snipStateName[currSnip->fState] << ' '
+ << currSnip->fOffset << ".." << (currSnip->fOffset + currSnip->fLength - 1)
+ << ' ' << currSnip->fLength << ' ' << endl;
+ }
+} // DumpSnipList
+
+#endif
+
+
+// =================================================================================================
+// PrevSnip and NextSnip
+// =====================
+
+XMPScanner::InternalSnipIterator
+XMPScanner::PrevSnip ( InternalSnipIterator snipPos )
+{
+
+ InternalSnipIterator prev = snipPos;
+ return --prev;
+
+} // PrevSnip
+
+XMPScanner::InternalSnipIterator
+XMPScanner::NextSnip ( InternalSnipIterator snipPos )
+{
+
+ InternalSnipIterator next = snipPos;
+ return ++next;
+
+} // NextSnip
+
+
+// =================================================================================================
+// XMPScanner
+// ==========
+//
+// Initialize the scanner object with one "not seen" snip covering the whole stream.
+
+XMPScanner::XMPScanner ( XMP_Int64 streamLength ) :
+
+ fStreamLength ( streamLength )
+
+{
+ InternalSnip rootSnip ( 0, streamLength );
+
+ if ( streamLength > 0 ) fInternalSnips.push_front ( rootSnip ); // Be nice for empty files.
+ // DumpSnipList ( "New XMPScanner" );
+
+} // XMPScanner
+
+
+// =================================================================================================
+// ~XMPScanner
+// ===========
+
+XMPScanner::~XMPScanner()
+{
+
+} // ~XMPScanner
+
+
+// =================================================================================================
+// GetSnipCount
+// ============
+
+long
+XMPScanner::GetSnipCount ()
+{
+
+ return fInternalSnips.size();
+
+} // GetSnipCount
+
+
+// =================================================================================================
+// StreamAllScanned
+// ================
+
+bool
+XMPScanner::StreamAllScanned ()
+{
+ InternalSnipIterator currPos = fInternalSnips.begin();
+ InternalSnipIterator endPos = fInternalSnips.end();
+
+ for ( ; currPos != endPos; ++currPos ) {
+ if ( currPos->fInfo.fState == eNotSeenSnip ) return false;
+ }
+ return true;
+
+} // StreamAllScanned
+
+
+// =================================================================================================
+// SplitInternalSnip
+// =================
+//
+// Split the given snip into up to 3 pieces. The new pieces are inserted before and after this one
+// in the snip list. The relOffset is the first byte to be kept, it is relative to this snip. If
+// the preceeding or following snips have the same state as this one, just shift the boundaries.
+// I.e. move the contents from one snip to the other, don't create a new snip.
+
+// *** To be thread safe we ought to lock the entire list during manipulation. Let data scanning
+// *** happen in parallel, serialize all mucking with the list.
+
+void
+XMPScanner::SplitInternalSnip ( InternalSnipIterator snipPos, XMP_Int64 relOffset, XMP_Int64 newLength )
+{
+
+ assert ( (relOffset + newLength) > relOffset ); // Check for overflow.
+ assert ( (relOffset + newLength) <= snipPos->fInfo.fLength );
+
+ // -----------------------------------
+ // First deal with the low offset end.
+
+ if ( relOffset > 0 ) {
+
+ InternalSnipIterator prevPos;
+ if ( snipPos != fInternalSnips.begin() ) prevPos = PrevSnip ( snipPos );
+
+ if ( (snipPos != fInternalSnips.begin()) && (snipPos->fInfo.fState == prevPos->fInfo.fState) ) {
+ prevPos->fInfo.fLength += relOffset; // Adjust the preceeding snip.
+ } else {
+ InternalSnip headExcess ( snipPos->fInfo.fOffset, relOffset );
+ headExcess.fInfo.fState = snipPos->fInfo.fState;
+ headExcess.fInfo.fOutOfOrder = snipPos->fInfo.fOutOfOrder;
+ fInternalSnips.insert ( snipPos, headExcess ); // Insert the head piece before the middle piece.
+ }
+
+ snipPos->fInfo.fOffset += relOffset; // Adjust the remainder of this snip.
+ snipPos->fInfo.fLength -= relOffset;
+
+ }
+
+ // ----------------------------------
+ // Now deal with the high offset end.
+
+ if ( newLength < snipPos->fInfo.fLength ) {
+
+ InternalSnipIterator nextPos = NextSnip ( snipPos );
+ const XMP_Int64 tailLength = snipPos->fInfo.fLength - newLength;
+
+ if ( (nextPos != fInternalSnips.end()) && (snipPos->fInfo.fState == nextPos->fInfo.fState) ) {
+ nextPos->fInfo.fOffset -= tailLength; // Adjust the following snip.
+ nextPos->fInfo.fLength += tailLength;
+ } else {
+ InternalSnip tailExcess ( (snipPos->fInfo.fOffset + newLength), tailLength );
+ tailExcess.fInfo.fState = snipPos->fInfo.fState;
+ tailExcess.fInfo.fOutOfOrder = snipPos->fInfo.fOutOfOrder;
+ fInternalSnips.insert ( nextPos, tailExcess ); // Insert the tail piece after the middle piece.
+ }
+
+ snipPos->fInfo.fLength = newLength;
+
+ }
+
+} // SplitInternalSnip
+
+
+// =================================================================================================
+// MergeInternalSnips
+// ==================
+
+XMPScanner::InternalSnipIterator
+XMPScanner::MergeInternalSnips ( InternalSnipIterator firstPos, InternalSnipIterator secondPos )
+{
+
+ firstPos->fInfo.fLength += secondPos->fInfo.fLength;
+ fInternalSnips.erase ( secondPos );
+ return firstPos;
+
+} // MergeInternalSnips
+
+
+// =================================================================================================
+// Scan
+// ====
+
+void
+XMPScanner::Scan ( const void * bufferOrigin, XMP_Int64 bufferOffset, XMP_Int64 bufferLength )
+{
+ XMP_Int64 relOffset;
+
+ #if 0
+ cout << "Scan: @ " << bufferOrigin << ", " << bufferOffset << ", " << bufferLength << endl;
+ #endif
+
+ if ( bufferLength == 0 ) return;
+
+ // ----------------------------------------------------------------
+ // These comparisons are carefully done to avoid overflow problems.
+
+ if ( (bufferOffset >= fStreamLength) ||
+ (bufferLength > (fStreamLength - bufferOffset)) ||
+ (bufferOrigin == 0) ) {
+ throw ScanError ( "Bad origin, offset, or length" );
+ }
+
+ // ----------------------------------------------------------------------------------------------
+ // This buffer must be within a not-seen snip. Find it and split it. The first snip whose whose
+ // end is beyond the buffer must be the enclosing one.
+
+ // *** It would be friendly for rescans for out of order problems to accept any buffer postion.
+
+ const XMP_Int64 endOffset = bufferOffset + bufferLength - 1;
+ InternalSnipIterator snipPos = fInternalSnips.begin();
+
+ while ( endOffset > (snipPos->fInfo.fOffset + snipPos->fInfo.fLength - 1) ) ++ snipPos;
+ if ( snipPos->fInfo.fState != eNotSeenSnip ) throw ScanError ( "Already seen" );
+
+ relOffset = bufferOffset - snipPos->fInfo.fOffset;
+ if ( (relOffset + bufferLength) > snipPos->fInfo.fLength ) throw ScanError ( "Not within existing snip" );
+
+ SplitInternalSnip ( snipPos, relOffset, bufferLength ); // *** If sequential & prev is partial, just tack on,
+
+ // --------------------------------------------------------
+ // Merge this snip with the preceeding snip if appropriate.
+
+ // *** When out of order I/O is supported we have to do something about buffers who's predecessor is not seen.
+
+ if ( snipPos->fInfo.fOffset > 0 ) {
+ InternalSnipIterator prevPos = PrevSnip ( snipPos );
+ if ( prevPos->fInfo.fState == ePartialPacketSnip ) snipPos = MergeInternalSnips ( prevPos, snipPos );
+ }
+
+ // ----------------------------------
+ // Look for packets within this snip.
+
+ snipPos->fInfo.fState = ePendingSnip;
+ PacketMachine* thisMachine = snipPos->fMachine.get();
+ // DumpSnipList ( "Before scan" );
+
+ if ( thisMachine != 0 ) {
+ thisMachine->AssociateBuffer ( bufferOffset, bufferOrigin, bufferLength );
+ } else {
+ // *** snipPos->fMachine.reset ( new PacketMachine ( bufferOffset, bufferOrigin, bufferLength ) ); VC++ lacks reset
+ #if 0
+ snipPos->fMachine = auto_ptr<PacketMachine> ( new PacketMachine ( bufferOffset, bufferOrigin, bufferLength ) );
+ #else
+ {
+ // Some versions of gcc complain about the assignment operator above. This avoids the gcc bug.
+ PacketMachine * pm = new PacketMachine ( bufferOffset, bufferOrigin, bufferLength );
+ auto_ptr<PacketMachine> ap ( pm );
+ snipPos->fMachine = ap;
+ }
+ #endif
+ thisMachine = snipPos->fMachine.get();
+ }
+
+ bool bufferDone = false;
+ while ( ! bufferDone ) {
+
+ PacketMachine::TriState foundPacket = thisMachine->FindNextPacket();
+
+ if ( foundPacket == PacketMachine::eTriNo ) {
+
+ // -----------------------------------------------------------------------
+ // No packet, mark the snip as raw data and get rid of the packet machine.
+ // We're done with this buffer.
+
+ snipPos->fInfo.fState = eRawInputSnip;
+ #if 0
+ snipPos->fMachine = auto_ptr<PacketMachine>(); // *** snipPos->fMachine.reset(); VC++ lacks reset
+ #else
+ {
+ // Some versions of gcc complain about the assignment operator above. This avoids the gcc bug.
+ auto_ptr<PacketMachine> ap ( 0 );
+ snipPos->fMachine = ap;
+ }
+ #endif
+ bufferDone = true;
+
+ } else {
+
+ // ---------------------------------------------------------------------------------------------
+ // Either a full or partial packet. First trim any excess off of the front as a raw input snip.
+ // If this is a partial packet mark the snip and keep the packet machine to be resumed later.
+ // We're done with this buffer, the partial packet by definition extends to the end. If this is
+ // a complete packet first extract the additional information from the packet machine. If there
+ // is leftover data split the snip and transfer the packet machine to the new trailing snip.
+
+ if ( thisMachine->fPacketStart > snipPos->fInfo.fOffset ) {
+
+ // There is data at the front of the current snip that must be trimmed.
+ SnipState savedState = snipPos->fInfo.fState;
+ snipPos->fInfo.fState = eRawInputSnip; // ! So it gets propagated to the trimmed front part.
+ relOffset = thisMachine->fPacketStart - snipPos->fInfo.fOffset;
+ SplitInternalSnip ( snipPos, relOffset, (snipPos->fInfo.fLength - relOffset) );
+ snipPos->fInfo.fState = savedState;
+
+ }
+
+ if ( foundPacket == PacketMachine::eTriMaybe ) {
+
+ // We have only found a partial packet.
+ snipPos->fInfo.fState = ePartialPacketSnip;
+ bufferDone = true;
+
+ } else {
+
+ // We have found a complete packet. Extract all the info for it and split any trailing data.
+
+ InternalSnipIterator packetSnip = snipPos;
+ SnipState packetState = eValidPacketSnip;
+
+ if ( thisMachine->fBogusPacket ) packetState = eBadPacketSnip;
+
+ packetSnip->fInfo.fAccess = thisMachine->fAccess;
+ packetSnip->fInfo.fCharForm = thisMachine->fCharForm;
+ packetSnip->fInfo.fBytesAttr = thisMachine->fBytesAttr;
+ packetSnip->fInfo.fEncodingAttr = thisMachine->fEncodingAttr.c_str();
+ thisMachine->fEncodingAttr.erase ( thisMachine->fEncodingAttr.begin(), thisMachine->fEncodingAttr.end() );
+
+ if ( (thisMachine->fCharForm != eChar8Bit) && CharFormIsBigEndian ( thisMachine->fCharForm ) ) {
+
+ // ------------------------------------------------------------------------------
+ // Handle a special case for big endian characters. The packet machine works as
+ // though things were little endian. The packet starting offset points to the
+ // byte containing the opening '<', and the length includes presumed nulls that
+ // follow the last "real" byte. If the characters are big endian we now have to
+ // decrement the starting offset of the packet, and also decrement the length of
+ // the previous snip.
+ //
+ // Note that we can't do this before the head trimming above in general. The
+ // nulls might have been exactly at the end of a buffer and already in the
+ // previous snip. We are doing this before trimming the tail from the raw snip
+ // containing the packet. We adjust the raw snip's size because it ends with
+ // the input buffer. We don't adjust the packet's size, it is already correct.
+ //
+ // The raw snip (the one before the packet) might entirely disappear. A simple
+ // example of this is when the packet is at the start of the file.
+
+ assert ( packetSnip != fInternalSnips.begin() ); // Leading nulls were trimmed!
+
+ if ( packetSnip != fInternalSnips.begin() ) { // ... but let's program defensibly.
+
+ InternalSnipIterator prevSnip = PrevSnip ( packetSnip );
+ const unsigned int nullsToAdd = ( CharFormIs16Bit ( thisMachine->fCharForm ) ? 1 : 3 );
+
+ assert ( nullsToAdd <= prevSnip->fInfo.fLength );
+ prevSnip->fInfo.fLength -= nullsToAdd;
+ if ( prevSnip->fInfo.fLength == 0 ) (void) fInternalSnips.erase ( prevSnip );
+
+ packetSnip->fInfo.fOffset -= nullsToAdd;
+ packetSnip->fInfo.fLength += nullsToAdd;
+ thisMachine->fPacketStart -= nullsToAdd;
+
+ }
+
+ }
+
+ if ( thisMachine->fPacketLength == snipPos->fInfo.fLength ) {
+
+ // This packet ends exactly at the end of the current snip.
+ #if 0
+ snipPos->fMachine = auto_ptr<PacketMachine>(); // *** snipPos->fMachine.reset(); VC++ lacks reset
+ #else
+ {
+ // Some versions of gcc complain about the assignment operator above. This avoids the gcc bug.
+ auto_ptr<PacketMachine> ap ( 0 );
+ snipPos->fMachine = ap;
+ }
+ #endif
+ bufferDone = true;
+
+ } else {
+
+ // There is trailing data to split from the just found packet.
+ SplitInternalSnip ( snipPos, 0, thisMachine->fPacketLength );
+
+ InternalSnipIterator tailPos = NextSnip ( snipPos );
+
+ tailPos->fMachine = snipPos->fMachine; // auto_ptr assignment - taking ownership
+ thisMachine->ResetMachine ();
+
+ snipPos = tailPos;
+
+ }
+
+ packetSnip->fInfo.fState = packetState; // Do this last to avoid messing up the tail split.
+ // DumpSnipList ( "Found a packet" );
+
+
+ }
+
+ }
+
+ }
+
+ // --------------------------------------------------------
+ // Merge this snip with the preceeding snip if appropriate.
+
+ // *** When out of order I/O is supported we have to check the following snip too.
+
+ if ( (snipPos->fInfo.fOffset > 0) && (snipPos->fInfo.fState == eRawInputSnip) ) {
+ InternalSnipIterator prevPos = PrevSnip ( snipPos );
+ if ( prevPos->fInfo.fState == eRawInputSnip ) snipPos = MergeInternalSnips ( prevPos, snipPos );
+ }
+
+ // DumpSnipList ( "After scan" );
+
+} // Scan
+
+
+// =================================================================================================
+// Report
+// ======
+
+void
+XMPScanner::Report ( SnipInfoVector& snips )
+{
+ const int count = fInternalSnips.size();
+ InternalSnipIterator snipPos = fInternalSnips.begin();
+
+ int s;
+
+ // DumpSnipList ( "Report" );
+
+ snips.erase ( snips.begin(), snips.end() ); // ! Should use snips.clear, but VC++ doesn't have it.
+ snips.reserve ( count );
+
+ for ( s = 0; s < count; s += 1 ) {
+ snips.push_back ( SnipInfo ( snipPos->fInfo.fState, snipPos->fInfo.fOffset, snipPos->fInfo.fLength ) );
+ snips[s] = snipPos->fInfo; // Pick up all of the fields.
+ ++ snipPos;
+ }
+
+} // Report
diff --git a/source/XMPFiles/FormatSupport/XMPScanner.hpp b/source/XMPFiles/FormatSupport/XMPScanner.hpp
new file mode 100644
index 0000000..2c8b6fa
--- /dev/null
+++ b/source/XMPFiles/FormatSupport/XMPScanner.hpp
@@ -0,0 +1,330 @@
+#ifndef __XMPScanner_hpp__
+#define __XMPScanner_hpp__
+
+// =================================================================================================
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+//
+// Adobe patent application tracking #P435, entitled 'Unique markers to simplify embedding data of
+// one format in a file with a different format', inventors: Sean Parent, Greg Gilley.
+// =================================================================================================
+
+#include "XMP_Environment.h" // ! This must be the first include.
+
+#include <list>
+#include <vector>
+#include <string>
+#include <memory>
+#include <stdexcept>
+
+#include "XMP_Const.h"
+
+// =================================================================================================
+// The XMPScanner class is used to scan a stream of input for XMP packets. A scanner object is
+// constructed then fed the input through a series of calls to Scan. Report may be called at any
+// time to get the current knowledge of the input.
+//
+// A packet starts when a valid header is found and ends when a valid trailer is found. If the
+// header contains a "bytes" attribute, additional whitespace must follow.
+//
+// *** RESTRICTIONS: The current implementation of the scanner has the the following restrictions:
+// - The input must be presented in order.
+// - Not fully thread safe, don't make concurrent calls to the same XMPScanner object.
+// =================================================================================================
+
+class XMPScanner {
+public:
+
+ // =============================================================================================
+ // The entire input stream is represented as a series of snips. Each snip defines one portion
+ // of the input stream that either has not been seen, has been seen and contains no packets, is
+ // exactly one packet, or contains the start of an unfinished packet. Adjacent snips with the
+ // same state are merged, so the number of snips is always minimal.
+ //
+ // A newly constructed XMPScanner object has one snip covering the whole input with a state
+ // of "not seen". A block of input that contains a full XMP packet is split into 3 parts: a
+ // (possibly empty) raw input snip, the packet, and another (possibly empty) raw input snip. A
+ // block of input that contains the start of an XMP packet is split into two snips, a (possibly
+ // empty) raw input snip and the packet start; the following snip must be a "not seen" snip.
+ //
+ // It is possible to have ill-formed packets. These have a syntactically valid header and
+ // trailer, but some semantic error. For example, if the "bytes" attribute length does not span
+ // to the end of the trailer, or if the following packet begins within trailing padding.
+
+ enum {
+ eNotSeenSnip, // This snip has not been seen yet.
+ ePendingSnip, // This snip is an input buffer being processed.
+ eRawInputSnip, // This snip is raw input, it doesn't contain any part of an XMP packet.
+ eValidPacketSnip, // This snip is a complete, valid XMP packet.
+ ePartialPacketSnip, // This snip contains the start of a possible XMP packet.
+ eBadPacketSnip // This snip contains a complete, but semantically incorrect XMP packet.
+ };
+ typedef XMP_Uns8 SnipState;
+
+ enum { // The values allow easy testing for 16/32 bit and big/little endian.
+ eChar8Bit = 0,
+ eChar16BitBig = 2,
+ eChar16BitLittle = 3,
+ eChar32BitBig = 4,
+ eChar32BitLittle = 5
+ };
+ typedef XMP_Uns8 CharacterForm;
+
+ enum {
+ eChar16BitMask = 2, // These constant shouldn't be used directly, they are mainly
+ eChar32BitMask = 4, // for the CharFormIsXyz macros below.
+ eCharLittleEndianMask = 1
+ };
+
+ #define CharFormIs16Bit(f) ( ((int)(f) & XMPScanner::eChar16BitMask) != 0 )
+ #define CharFormIs32Bit(f) ( ((int)(f) & XMPScanner::eChar32BitMask) != 0 )
+
+ #define CharFormIsBigEndian(f) ( ((int)(f) & XMPScanner::eCharLittleEndianMask) == 0 )
+ #define CharFormIsLittleEndian(f) ( ((int)(f) & XMPScanner::eCharLittleEndianMask) != 0 )
+
+ struct SnipInfo {
+
+ XMP_Int64 fOffset; // The byte offset of this snip within the input stream.
+ XMP_Int64 fLength; // The length in bytes of this snip.
+ SnipState fState; // The state of this snip.
+ bool fOutOfOrder; // If true, this snip was seen before the one in front of it.
+ char fAccess; // The read-only/read-write access from the end attribute.
+ CharacterForm fCharForm; // How the packet is divided into characters.
+ const char * fEncodingAttr; // The value of the encoding attribute, if any, with nulls removed.
+ XMP_Int64 fBytesAttr; // The value of the bytes attribute, -1 if not present.
+
+ SnipInfo() :
+ fOffset ( 0 ),
+ fLength ( 0 ),
+ fState ( eNotSeenSnip ),
+ fOutOfOrder ( false ),
+ fAccess ( ' ' ),
+ fCharForm ( eChar8Bit ),
+ fEncodingAttr ( "" ),
+ fBytesAttr( -1 )
+ { }
+
+ SnipInfo ( SnipState state, XMP_Int64 offset, XMP_Int64 length ) :
+ fOffset ( offset ),
+ fLength ( length ),
+ fState ( state ),
+ fOutOfOrder ( false ),
+ fAccess ( ' ' ),
+ fCharForm ( eChar8Bit ),
+ fEncodingAttr ( "" ),
+ fBytesAttr( -1 )
+ { }
+
+ };
+
+ typedef std::vector<SnipInfo> SnipInfoVector;
+
+ XMPScanner ( XMP_Int64 streamLength );
+ // Constructs a new XMPScanner object for a stream with the given length.
+
+ ~XMPScanner();
+
+ long GetSnipCount();
+ // Returns the number of snips that the stream has been divided into.
+
+ bool StreamAllScanned();
+ // Returns true if all of the stream has been seen.
+
+ void Scan ( const void * bufferOrigin, XMP_Int64 bufferOffset, XMP_Int64 bufferLength );
+ // Scans the given part of the input, incorporating it in to the known snips.
+ // The bufferOffset is the offset of this block of input relative to the entire stream.
+ // The bufferLength is the length in bytes of this block of input.
+
+ void Report ( SnipInfoVector & snips );
+ // Produces a report of what is known about the input stream.
+
+ class ScanError : public std::logic_error {
+ public:
+ ScanError() throw() : std::logic_error ( "" ) {}
+ explicit ScanError ( const char * message ) throw() : std::logic_error ( message ) {}
+ virtual ~ScanError() throw() {}
+ };
+
+private: // XMPScanner
+
+ class PacketMachine;
+
+ class InternalSnip {
+ public:
+
+ SnipInfo fInfo; // The public info about this snip.
+ std::auto_ptr<PacketMachine> fMachine; // The state machine for "active" snips.
+
+ InternalSnip ( XMP_Int64 offset, XMP_Int64 length );
+ InternalSnip ( const InternalSnip & );
+ ~InternalSnip ();
+
+ }; // InternalSnip
+
+ typedef std::list<InternalSnip> InternalSnipList;
+ typedef InternalSnipList::iterator InternalSnipIterator;
+
+ class PacketMachine {
+ public:
+
+ XMP_Int64 fPacketStart; // Byte offset relative to the entire stream.
+ XMP_Int32 fPacketLength; // Length in bytes to the end of the trailer processing instruction.
+ XMP_Int32 fBytesAttr; // The value of the bytes attribute, -1 if not present.
+ std::string fEncodingAttr; // The value of the encoding attribute, if any, with nulls removed.
+ CharacterForm fCharForm; // How the packet is divided into characters.
+ char fAccess; // The read-only/read-write access from the end attribute.
+ bool fBogusPacket; // True if the packet has an error such as a bad "bytes" attribute value.
+
+ void ResetMachine();
+
+ enum TriState {
+ eTriNo,
+ eTriMaybe,
+ eTriYes
+ };
+
+ TriState FindNextPacket();
+
+ void AssociateBuffer ( XMP_Int64 bufferOffset, const void * bufferOrigin, XMP_Int64 bufferLength );
+
+ PacketMachine ( XMP_Int64 bufferOffset, const void * bufferOrigin, XMP_Int64 bufferLength );
+ ~PacketMachine();
+
+ private: // PacketMachine
+
+ PacketMachine() {}; // ! Hide the default constructor.
+
+ enum RecognizerKind {
+
+ eFailureRecognizer, // Not really recognizers, special states to end one buffer's processing.
+ eSuccessRecognizer,
+
+ eLeadInRecognizer, // Anything up to the next '<'.
+ eHeadStartRecorder, // Save the starting offset, count intervening nulls.
+ eHeadStartRecognizer, // The literal string "?xpacket begin=".
+
+ eBOMRecognizer, // Recognize and record the quoted byte order marker.
+
+ eIDTagRecognizer, // The literal string " id=".
+ eIDOpenRecognizer, // The opening quote for the ID.
+ eIDValueRecognizer, // The literal string "W5M0MpCehiHzreSzNTczkc9d".
+ eIDCloseRecognizer, // The closing quote for the ID.
+
+ eAttrSpaceRecognizer_1, // The space before an attribute.
+ eAttrNameRecognizer_1, // The name of an attribute.
+ eAttrValueRecognizer_1, // The equal sign and quoted string value for an attribute.
+ eAttrValueRecorder_1, // Record the value of an attribute.
+
+ eHeadEndRecognizer, // The string literal "?>".
+
+ eBodyRecognizer, // The packet body, anything up to the next '<'.
+
+ eTailStartRecognizer, // The string literal "?xpacket end=".
+ eAccessValueRecognizer, // Recognize and record the quoted r/w access mode.
+
+ eAttrSpaceRecognizer_2, // The space before an attribute.
+ eAttrNameRecognizer_2, // The name of an attribute.
+ eAttrValueRecognizer_2, // The equal sign and quoted string value for an attribute.
+ eAttrValueRecorder_2, // Record the value of an attribute.
+
+ eTailEndRecognizer, // The string literal "?>".
+ ePacketEndRecognizer, // Look for trailing padding, check and record the packet size.
+ eCloseOutRecognizer, // Look for final nulls for little endian multibyte characters.
+
+ eRecognizerCount
+
+ };
+
+ XMP_Int64 fBufferOffset; // The offset of the data buffer within the input stream.
+ const char * fBufferOrigin; // The starting address of the data buffer for this snip.
+ const char * fBufferPtr; // The current postion in the data buffer.
+ const char * fBufferLimit; // The address one past the last byte in the data buffer.
+
+ RecognizerKind fRecognizer; // Which recognizer is currently active.
+ signed long fPosition; // The internal position within a string literal, etc.
+ unsigned char fBytesPerChar; // The number of bytes per logical character, 1, 2, or 4.
+ unsigned char fBufferOverrun; // Non-zero if suspended while skipping intervening nulls.
+ char fQuoteChar; // The kind of quote seen at the start of a quoted value.
+ std::string fAttrName; // The name for an arbitrary attribute (other than "begin" and "id").
+ std::string fAttrValue; // The value for an arbitrary attribute (other than "begin" and "id").
+
+ void SetNextRecognizer ( RecognizerKind nextRecognizer );
+
+ typedef TriState (* RecognizerProc) ( PacketMachine *, const char * );
+
+ static TriState
+ FindLessThan ( PacketMachine * ths, const char * which );
+
+ static TriState
+ MatchString ( PacketMachine * ths, const char * literal );
+
+ static TriState
+ MatchChar ( PacketMachine * ths, const char * literal );
+
+ static TriState
+ MatchOpenQuote ( PacketMachine * ths, const char * /* unused */ );
+
+ static TriState
+ MatchCloseQuote ( PacketMachine * ths, const char * /* unused */ );
+
+ static TriState
+ CaptureAttrName ( PacketMachine * ths, const char * /* unused */ );
+
+ static TriState
+ CaptureAttrValue ( PacketMachine * ths, const char * /* unused */ );
+
+ static TriState
+ RecordStart ( PacketMachine * ths, const char * /* unused */ );
+
+ static TriState
+ RecognizeBOM ( PacketMachine * ths, const char * /* unused */ );
+
+ static TriState
+ RecordHeadAttr ( PacketMachine * ths, const char * /* unused */ );
+
+ static TriState
+ CaptureAccess ( PacketMachine * ths, const char * /* unused */ );
+
+ static TriState
+ RecordTailAttr ( PacketMachine * ths, const char * /* unused */ );
+
+ static TriState
+ CheckPacketEnd ( PacketMachine * ths, const char * /* unused */ );
+
+ static TriState
+ CheckFinalNulls ( PacketMachine * ths, const char * /* unused */ );
+
+ struct RecognizerInfo {
+ RecognizerProc proc;
+ RecognizerKind successNext;
+ RecognizerKind failureNext;
+ const char * literal;
+ };
+
+ }; // PacketMachine
+
+ XMP_Int64 fStreamLength;
+ InternalSnipList fInternalSnips;
+
+ void
+ SplitInternalSnip ( InternalSnipIterator snipPos, XMP_Int64 relOffset, XMP_Int64 newLength );
+
+ InternalSnipIterator
+ MergeInternalSnips ( InternalSnipIterator firstPos, InternalSnipIterator secondPos );
+
+ InternalSnipIterator
+ PrevSnip ( InternalSnipIterator snipPos );
+
+ InternalSnipIterator
+ NextSnip ( InternalSnipIterator snipPos );
+
+ #if DEBUG
+ void DumpSnipList ( const char * title );
+ #endif
+
+}; // XMPScanner
+
+#endif // __XMPScanner_hpp__
diff --git a/source/XMPFiles/WXMPFiles.cpp b/source/XMPFiles/WXMPFiles.cpp
new file mode 100644
index 0000000..9ce4a47
--- /dev/null
+++ b/source/XMPFiles/WXMPFiles.cpp
@@ -0,0 +1,320 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "XMP_Environment.h"
+#include "XMP_Const.h"
+
+#include "client-glue/WXMPFiles.hpp"
+
+#include "XMPFiles_Impl.hpp"
+#include "XMPFiles.hpp"
+
+#if XMP_WinBuild
+ #if XMP_DebugBuild
+ #pragma warning ( disable : 4297 ) // function assumed not to throw an exception but does
+ #endif
+#endif
+
+#if __cplusplus
+extern "C" {
+#endif
+
+// =================================================================================================
+
+static WXMP_Result voidResult; // Used for functions that don't use the normal result mechanism.
+
+// =================================================================================================
+
+void WXMPFiles_GetVersionInfo_1 ( XMP_VersionInfo * versionInfo )
+{
+ WXMP_Result * wResult = &voidResult; // ! Needed to "fool" the EnterWrapper macro.
+ XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPFiles_GetVersionInfo_1" )
+
+ XMPFiles::GetVersionInfo ( versionInfo );
+
+ XMP_EXIT_WRAPPER_NO_THROW
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void WXMPFiles_Initialize_1 ( WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPFiles_Initialize_1" )
+
+ wResult->int32Result = XMPFiles::Initialize ( 0 );
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void WXMPFiles_Initialize_2 ( XMP_OptionBits options, WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPFiles_Initialize_1" )
+
+ wResult->int32Result = XMPFiles::Initialize ( options );
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void WXMPFiles_Terminate_1()
+{
+ WXMP_Result * wResult = &voidResult; // ! Needed to "fool" the EnterWrapper macro.
+ XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPFiles_Terminate_1" )
+
+ XMPFiles::Terminate();
+
+ XMP_EXIT_WRAPPER_NO_THROW
+}
+
+// =================================================================================================
+
+void WXMPFiles_CTor_1 ( WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPFiles_CTor_1" )
+
+ XMPFiles * newObj = new XMPFiles();
+ ++newObj->clientRefs;
+ XMP_Assert ( newObj->clientRefs == 1 );
+ wResult->ptrResult = newObj;
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void WXMPFiles_UnlockLib_1()
+{
+ WXMP_Result * wResult = &voidResult; // ! Needed to fool the EnterWrapper macro.
+ XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPFiles_UnlockLib_1" )
+
+ XMPFiles::UnlockLib();
+
+ XMP_EXIT_WRAPPER_NO_THROW
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void WXMPFiles_UnlockObj_1 ( XMPFilesRef xmpFilesRef )
+{
+ WXMP_Result * wResult = &voidResult; // ! Needed to fool the EnterWrapper macro.
+ XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPFiles_UnlockObj_1" )
+
+ XMPFiles * thiz = (XMPFiles*)xmpFilesRef;
+ thiz->UnlockObj();
+
+ XMP_EXIT_WRAPPER_NO_THROW
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void WXMPFiles_IncrementRefCount_1 ( XMPFilesRef xmpFilesRef )
+{
+ WXMP_Result * wResult = &voidResult; // ! Needed to "fool" the EnterWrapper macro.
+ XMP_ENTER_WRAPPER ( "WXMPFiles_IncrementRefCount_1" )
+
+ XMPFiles * thiz = (XMPFiles*)xmpFilesRef;
+ ++thiz->clientRefs;
+ XMP_Assert ( thiz->clientRefs > 0 );
+
+ XMP_EXIT_WRAPPER_NO_THROW
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void WXMPFiles_DecrementRefCount_1 ( XMPFilesRef xmpFilesRef )
+{
+ WXMP_Result * wResult = &voidResult; // ! Needed to "fool" the EnterWrapper macro.
+ XMP_ENTER_WRAPPER ( "WXMPFiles_DecrementRefCount_1" )
+
+ XMPFiles * thiz = (XMPFiles*)xmpFilesRef;
+ XMP_Assert ( thiz->clientRefs > 0 );
+ --thiz->clientRefs;
+ if ( thiz->clientRefs <= 0 ) delete ( thiz );
+
+ XMP_EXIT_WRAPPER_NO_THROW
+}
+
+// =================================================================================================
+
+void WXMPFiles_GetFormatInfo_1 ( XMP_FileFormat format,
+ XMP_OptionBits * flags,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPFiles_GetFormatInfo_1" )
+
+ wResult->int32Result = XMPFiles::GetFormatInfo ( format, flags );
+
+ XMP_EXIT_WRAPPER
+}
+
+// =================================================================================================
+
+void WXMPFiles_OpenFile_1 ( XMPFilesRef xmpFilesRef,
+ XMP_StringPtr filePath,
+ XMP_FileFormat format,
+ XMP_OptionBits openFlags,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPFiles_OpenFile_1" )
+ StartPerfCheck ( kAPIPerf_OpenFile, filePath );
+
+ XMPFiles * thiz = (XMPFiles*)xmpFilesRef;
+ bool ok = thiz->OpenFile ( filePath, format, openFlags );
+ wResult->int32Result = ok;
+
+ EndPerfCheck ( kAPIPerf_OpenFile );
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void WXMPFiles_CloseFile_1 ( XMPFilesRef xmpFilesRef,
+ XMP_OptionBits closeFlags,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPFiles_CloseFile_1" )
+ StartPerfCheck ( kAPIPerf_CloseFile, "" );
+
+ XMPFiles * thiz = (XMPFiles*)xmpFilesRef;
+ thiz->CloseFile ( closeFlags );
+
+ EndPerfCheck ( kAPIPerf_CloseFile );
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void WXMPFiles_GetFileInfo_1 ( XMPFilesRef xmpFilesRef,
+ XMP_StringPtr * filePath,
+ XMP_StringLen * filePathLen,
+ XMP_OptionBits * openFlags,
+ XMP_FileFormat * format,
+ XMP_OptionBits * handlerFlags,
+ WXMP_Result * wResult )
+{
+ bool isOpen = false;
+ XMP_ENTER_WRAPPER ( "WXMPFiles_GetFileInfo_1" )
+
+ XMPFiles * thiz = (XMPFiles*)xmpFilesRef;
+ isOpen = thiz->GetFileInfo ( filePath, filePathLen, openFlags, format, handlerFlags );
+ wResult->int32Result = isOpen;
+
+ XMP_EXIT_WRAPPER_KEEP_LOCK ( isOpen )
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void WXMPFiles_SetAbortProc_1 ( XMPFilesRef xmpFilesRef,
+ XMP_AbortProc abortProc,
+ void * abortArg,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPFiles_SetAbortProc_1" )
+
+ XMPFiles * thiz = (XMPFiles*)xmpFilesRef;
+ thiz->SetAbortProc ( abortProc, abortArg );
+
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void WXMPFiles_GetXMP_1 ( XMPFilesRef xmpFilesRef,
+ XMPMetaRef xmpRef,
+ XMP_StringPtr * xmpPacket,
+ XMP_StringLen * xmpPacketLen,
+ XMP_PacketInfo * packetInfo,
+ WXMP_Result * wResult )
+{
+ bool hasXMP = false;
+ XMP_ENTER_WRAPPER ( "WXMPFiles_GetXMP_1" )
+ StartPerfCheck ( kAPIPerf_GetXMP, "" );
+
+ XMPFiles * thiz = (XMPFiles*)xmpFilesRef;
+ if ( xmpRef == 0 ) {
+ hasXMP = thiz->GetXMP ( 0, xmpPacket, xmpPacketLen, packetInfo );
+ } else {
+ SXMPMeta xmpObj ( xmpRef );
+ hasXMP = thiz->GetXMP ( &xmpObj, xmpPacket, xmpPacketLen, packetInfo );
+ }
+ wResult->int32Result = hasXMP;
+
+ EndPerfCheck ( kAPIPerf_GetXMP );
+ XMP_EXIT_WRAPPER_KEEP_LOCK ( hasXMP )
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void WXMPFiles_GetThumbnail_1 ( XMPFilesRef xmpFilesRef,
+ XMP_ThumbnailInfo * tnailInfo, // ! Can be null.
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPFiles_GetThumbnail_1" )
+ StartPerfCheck ( kAPIPerf_GetThumbnail, "" );
+
+ XMPFiles * thiz = (XMPFiles*)xmpFilesRef;
+ bool hasTNail = thiz->GetThumbnail ( tnailInfo );
+ wResult->int32Result = hasTNail;
+
+ EndPerfCheck ( kAPIPerf_GetThumbnail );
+ XMP_EXIT_WRAPPER // ! No need to keep the lock, the tnail info won't change.
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void WXMPFiles_PutXMP_1 ( XMPFilesRef xmpFilesRef,
+ XMPMetaRef xmpRef, // ! Only one of the XMP object or packet are passed.
+ XMP_StringPtr xmpPacket,
+ XMP_StringLen xmpPacketLen,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPFiles_PutXMP_1" )
+ StartPerfCheck ( kAPIPerf_PutXMP, "" );
+
+ XMPFiles * thiz = (XMPFiles*)xmpFilesRef;
+ if ( xmpRef != 0 ) {
+ thiz->PutXMP ( xmpRef );
+ } else {
+ thiz->PutXMP ( xmpPacket, xmpPacketLen );
+ }
+
+ EndPerfCheck ( kAPIPerf_PutXMP );
+ XMP_EXIT_WRAPPER
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void WXMPFiles_CanPutXMP_1 ( XMPFilesRef xmpFilesRef,
+ XMPMetaRef xmpRef, // ! Only one of the XMP object or packet are passed.
+ XMP_StringPtr xmpPacket,
+ XMP_StringLen xmpPacketLen,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_WRAPPER ( "WXMPFiles_CanPutXMP_1" )
+ StartPerfCheck ( kAPIPerf_CanPutXMP, "" );
+
+ XMPFiles * thiz = (XMPFiles*)xmpFilesRef;
+ if ( xmpRef != 0 ) {
+ wResult->int32Result = thiz->CanPutXMP ( xmpRef );
+ } else {
+ wResult->int32Result = thiz->CanPutXMP ( xmpPacket, xmpPacketLen );
+ }
+
+ EndPerfCheck ( kAPIPerf_CanPutXMP );
+ XMP_EXIT_WRAPPER
+}
+
+// =================================================================================================
+
+#if __cplusplus
+}
+#endif
diff --git a/source/XMPFiles/XMPFiles.cpp b/source/XMPFiles/XMPFiles.cpp
new file mode 100644
index 0000000..136feb3
--- /dev/null
+++ b/source/XMPFiles/XMPFiles.cpp
@@ -0,0 +1,1005 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include <vector>
+#include <string.h>
+
+#include "XMPFiles_Impl.hpp"
+#include "UnicodeConversions.hpp"
+#include "QuickTime_Support.hpp"
+
+// These are the official, fully supported handlers.
+#include "FileHandlers/JPEG_Handler.hpp"
+#include "FileHandlers/TIFF_Handler.hpp"
+#include "FileHandlers/PSD_Handler.hpp"
+#include "FileHandlers/InDesign_Handler.hpp"
+#include "FileHandlers/PostScript_Handler.hpp"
+#include "FileHandlers/Scanner_Handler.hpp"
+#include "FileHandlers/MOV_Handler.hpp"
+#include "FileHandlers/MPEG_Handler.hpp"
+#include "FileHandlers/MP3_Handler.hpp"
+#include "FileHandlers/PNG_Handler.hpp"
+#include "FileHandlers/AVI_Handler.hpp"
+#include "FileHandlers/WAV_Handler.hpp"
+
+// =================================================================================================
+/// \file XMPFiles.cpp
+/// \brief High level support to access metadata in files of interest to Adobe applications.
+///
+/// This header ...
+///
+// =================================================================================================
+
+// =================================================================================================
+
+long sXMPFilesInitCount = 0;
+
+#if GatherPerformanceData
+ APIPerfCollection* sAPIPerf = 0;
+#endif
+
+// These are embedded version strings.
+
+#if XMP_DebugBuild
+ #define kXMPFiles_DebugFlag 1
+#else
+ #define kXMPFiles_DebugFlag 0
+#endif
+
+#define kXMPFiles_VersionNumber ( (kXMPFiles_DebugFlag << 31) | \
+ (XMP_API_VERSION_MAJOR << 24) | \
+ (XMP_API_VERSION_MINOR << 16) | \
+ (XMP_API_VERSION_MICRO << 8) )
+
+ #define kXMPFilesName "XMP Files"
+ #define kXMPFiles_VersionMessage kXMPFilesName " " XMP_API_VERSION_STRING
+const char * kXMPFiles_EmbeddedVersion = kXMPFiles_VersionMessage;
+const char * kXMPFiles_EmbeddedCopyright = kXMPFilesName " " kXMP_CopyrightStr;
+
+// =================================================================================================
+
+struct XMPFileHandlerInfo {
+ XMP_FileFormat format;
+ XMP_OptionBits flags;
+ CheckFormatProc checkProc;
+ XMPFileHandlerCTor handlerCTor;
+ XMPFileHandlerInfo() : format(0), flags(0), checkProc(0), handlerCTor(0) {};
+ XMPFileHandlerInfo ( XMP_FileFormat _format, XMP_OptionBits _flags,
+ CheckFormatProc _checkProc, XMPFileHandlerCTor _handlerCTor )
+ : format(_format), flags(_flags), checkProc(_checkProc), handlerCTor(_handlerCTor) {};
+};
+
+typedef std::vector <XMPFileHandlerInfo> XMPFileHandlerTable;
+typedef XMPFileHandlerTable::iterator XMPFileHandlerTablePos;
+
+static XMPFileHandlerTable * sRegisteredHandlers = 0; // ! Only smart handlers are registered!
+
+// =================================================================================================
+
+static XMPFileHandlerTablePos
+FindHandler ( XMP_FileFormat format,
+ std::string & fileExt )
+{
+ if ( (format == kXMP_UnknownFile) && (! fileExt.empty()) ) {
+ for ( int i = 0; kFileExtMap[i].format != 0; ++i ) {
+ if ( fileExt == kFileExtMap[i].ext ) {
+ format = kFileExtMap[i].format;
+ break;
+ }
+ }
+ }
+
+ if ( format == kXMP_UnknownFile ) return sRegisteredHandlers->end();
+
+ XMPFileHandlerTablePos handlerPos = sRegisteredHandlers->begin();
+ for ( ; handlerPos != sRegisteredHandlers->end(); ++handlerPos ) {
+ if ( handlerPos->format == format ) return handlerPos;
+ }
+
+ return sRegisteredHandlers->end();
+
+} // FindHandler
+
+// =================================================================================================
+
+static void
+RegisterXMPFileHandler ( XMP_FileFormat format,
+ XMP_OptionBits flags,
+ CheckFormatProc checkProc,
+ XMPFileHandlerCTor handlerCTor )
+{
+ XMP_Assert ( format != kXMP_UnknownFile );
+ std::string noExt;
+
+ if ( FindHandler ( format, noExt ) != sRegisteredHandlers->end() ) {
+ XMP_Throw ( "Duplicate handler registration", kXMPErr_InternalFailure );
+ }
+
+ if ( (flags & kXMPFiles_CanInjectXMP) && (! (flags & kXMPFiles_CanExpand)) ) {
+ XMP_Throw ( "Inconsistent handler flags", kXMPErr_InternalFailure );
+ }
+
+ sRegisteredHandlers->push_back ( XMPFileHandlerInfo ( format, flags, checkProc, handlerCTor ) );
+
+} // RegisterXMPFileHandler
+
+// =================================================================================================
+
+/* class-static */
+void
+XMPFiles::GetVersionInfo ( XMP_VersionInfo * info )
+{
+
+ memset ( info, 0, sizeof(XMP_VersionInfo) );
+
+ info->major = XMP_API_VERSION_MAJOR;
+ info->minor = XMP_API_VERSION_MINOR;
+ info->micro = XMP_API_VERSION_MICRO;
+ info->isDebug = kXMPFiles_DebugFlag;
+ info->flags = 0; // ! None defined yet.
+ info->message = kXMPFiles_VersionMessage;
+
+} // XMPFiles::GetVersionInfo
+
+// =================================================================================================
+
+static bool sIgnoreQuickTime = false;
+
+/* class static */
+bool
+XMPFiles::Initialize ( XMP_OptionBits options /* = 0 */ )
+{
+ ++sXMPFilesInitCount;
+ if ( sXMPFilesInitCount > 1 ) return true;
+
+ SXMPMeta::Initialize(); // Just in case the client does not.
+
+ #if GatherPerformanceData
+ sAPIPerf = new APIPerfCollection;
+ #endif
+
+ XMP_InitMutex ( &sXMPFilesLock );
+
+ XMP_Uns16 endianInt = 0x00FF;
+ XMP_Uns8 endianByte = *((XMP_Uns8*)&endianInt);
+ if ( kBigEndianHost ) {
+ if ( endianByte != 0 ) XMP_Throw ( "Big endian flag mismatch", kXMPErr_InternalFailure );
+ } else {
+ if ( endianByte != 0xFF ) XMP_Throw ( "Little endian flag mismatch", kXMPErr_InternalFailure );
+ }
+
+ XMP_Assert ( kUTF8_PacketHeaderLen == strlen ( "<?xpacket begin='xxx' id='W5M0MpCehiHzreSzNTczkc9d'" ) );
+ XMP_Assert ( kUTF8_PacketTrailerLen == strlen ( (const char *) kUTF8_PacketTrailer ) );
+
+ sRegisteredHandlers = new XMPFileHandlerTable;
+ sXMPFilesExceptionMessage = new XMP_VarString;
+
+ InitializeUnicodeConversions();
+
+ sIgnoreQuickTime = XMP_OptionIsSet ( options, kXMPFiles_NoQuickTimeInit );
+ if ( ! sIgnoreQuickTime ) {
+ (void) QuickTime_Support::MainInitialize(); // Don't worry about failure, the MOV handler checks that.
+ }
+
+ // ----------------------------------------------------------------------------------
+ // First register the handlers that don't want to open and close the file themselves.
+
+ XMP_Assert ( ! (kJPEG_HandlerFlags & kXMPFiles_HandlerOwnsFile) );
+ RegisterXMPFileHandler ( kXMP_JPEGFile, kJPEG_HandlerFlags, JPEG_CheckFormat, JPEG_MetaHandlerCTor );
+
+ XMP_Assert ( ! (kTIFF_HandlerFlags & kXMPFiles_HandlerOwnsFile) );
+ RegisterXMPFileHandler ( kXMP_TIFFFile, kTIFF_HandlerFlags, TIFF_CheckFormat, TIFF_MetaHandlerCTor );
+
+ XMP_Assert ( ! (kPSD_HandlerFlags & kXMPFiles_HandlerOwnsFile) );
+ RegisterXMPFileHandler ( kXMP_PhotoshopFile, kPSD_HandlerFlags, PSD_CheckFormat, PSD_MetaHandlerCTor );
+
+ XMP_Assert ( ! (kInDesign_HandlerFlags & kXMPFiles_HandlerOwnsFile) );
+ RegisterXMPFileHandler ( kXMP_InDesignFile, kInDesign_HandlerFlags, InDesign_CheckFormat, InDesign_MetaHandlerCTor );
+
+ // ! EPS and PostScript have the same handler, EPS is a proper subset of PostScript.
+ XMP_Assert ( ! (kPostScript_HandlerFlags & kXMPFiles_HandlerOwnsFile) );
+ RegisterXMPFileHandler ( kXMP_EPSFile, kPostScript_HandlerFlags, PostScript_CheckFormat, PostScript_MetaHandlerCTor );
+ RegisterXMPFileHandler ( kXMP_PostScriptFile, kPostScript_HandlerFlags, PostScript_CheckFormat, PostScript_MetaHandlerCTor );
+
+ XMP_Assert ( ! (kPNG_HandlerFlags & kXMPFiles_HandlerOwnsFile) );
+ RegisterXMPFileHandler ( kXMP_PNGFile, kPNG_HandlerFlags, PNG_CheckFormat, PNG_MetaHandlerCTor );
+
+ XMP_Assert ( ! (kAVI_HandlerFlags & kXMPFiles_HandlerOwnsFile) );
+ RegisterXMPFileHandler ( kXMP_AVIFile, kAVI_HandlerFlags, AVI_CheckFormat, AVI_MetaHandlerCTor );
+
+ XMP_Assert ( ! (kWAV_HandlerFlags & kXMPFiles_HandlerOwnsFile) );
+ RegisterXMPFileHandler ( kXMP_WAVFile, kWAV_HandlerFlags, WAV_CheckFormat, WAV_MetaHandlerCTor );
+
+ XMP_Assert ( ! (kMP3_HandlerFlags & kXMPFiles_HandlerOwnsFile) );
+ RegisterXMPFileHandler ( kXMP_MP3File, kMP3_HandlerFlags, MP3_CheckFormat, MP3_MetaHandlerCTor );
+
+ #if XMP_WinBuild
+
+ // Windows-only handlers.
+
+ #endif
+
+ // -----------------------------------------------------------------------------
+ // Now register the handlers that do want to open and close the file themselves.
+
+ XMP_Assert ( kMOV_HandlerFlags & kXMPFiles_HandlerOwnsFile );
+ RegisterXMPFileHandler ( kXMP_MOVFile, kMOV_HandlerFlags, MOV_CheckFormat, MOV_MetaHandlerCTor );
+
+ XMP_Assert ( kMPEG_HandlerFlags & kXMPFiles_HandlerOwnsFile );
+ RegisterXMPFileHandler ( kXMP_MPEGFile, kMPEG_HandlerFlags, MPEG_CheckFormat, MPEG_MetaHandlerCTor );
+
+ // Make sure the embedded info strings are referenced and kept.
+ if ( (kXMPFiles_EmbeddedVersion[0] == 0) || (kXMPFiles_EmbeddedCopyright[0] == 0) ) return false;
+ return true;
+
+} // XMPFiles::Initialize
+
+// =================================================================================================
+
+#if GatherPerformanceData
+
+#if XMP_WinBuild
+ #pragma warning ( disable : 4996 ) // '...' was declared deprecated
+#endif
+
+#include "PerfUtils.cpp"
+
+static void ReportPerformanceData()
+{
+ struct SummaryInfo {
+ size_t callCount;
+ double totalTime;
+ SummaryInfo() : callCount(0), totalTime(0.0) {};
+ };
+
+ SummaryInfo perfSummary [kAPIPerfProcCount];
+
+ XMP_DateTime now;
+ SXMPUtils::CurrentDateTime ( &now );
+ std::string nowStr;
+ SXMPUtils::ConvertFromDate ( now, &nowStr );
+
+ #if XMP_WinBuild
+ #define kPerfLogPath "C:\\XMPFilesPerformanceLog.txt"
+ #else
+ #define kPerfLogPath "/XMPFilesPerformanceLog.txt"
+ #endif
+ FILE * perfLog = fopen ( kPerfLogPath, "ab" );
+ if ( perfLog == 0 ) return;
+
+ fprintf ( perfLog, "\n\n// =================================================================================================\n\n" );
+ fprintf ( perfLog, "XMPFiles performance data\n" );
+ fprintf ( perfLog, " %s\n", kXMPFiles_VersionMessage );
+ fprintf ( perfLog, " Reported at %s\n", nowStr.c_str() );
+ fprintf ( perfLog, " %s\n", PerfUtils::GetTimerInfo() );
+
+ // Gather and report the summary info.
+
+ for ( size_t i = 0; i < sAPIPerf->size(); ++i ) {
+ SummaryInfo& summaryItem = perfSummary [(*sAPIPerf)[i].whichProc];
+ ++summaryItem.callCount;
+ summaryItem.totalTime += (*sAPIPerf)[i].elapsedTime;
+ }
+
+ fprintf ( perfLog, "\nSummary data:\n" );
+
+ for ( size_t i = 0; i < kAPIPerfProcCount; ++i ) {
+ long averageTime = 0;
+ if ( perfSummary[i].callCount != 0 ) {
+ averageTime = (long) (((perfSummary[i].totalTime/perfSummary[i].callCount) * 1000.0*1000.0) + 0.5);
+ }
+ fprintf ( perfLog, " %s, %d total calls, %d average microseconds per call\n",
+ kAPIPerfNames[i], perfSummary[i].callCount, averageTime );
+ }
+
+ fprintf ( perfLog, "\nPer-call data:\n" );
+
+ // Report the info for each call.
+
+ for ( size_t i = 0; i < sAPIPerf->size(); ++i ) {
+ long time = (long) (((*sAPIPerf)[i].elapsedTime * 1000.0*1000.0) + 0.5);
+ fprintf ( perfLog, " %s, %d microSec, ref %.8X, \"%s\"\n",
+ kAPIPerfNames[(*sAPIPerf)[i].whichProc], time,
+ (*sAPIPerf)[i].xmpFilesRef, (*sAPIPerf)[i].extraInfo.c_str() );
+ }
+
+ fclose ( perfLog );
+
+} // ReportAReportPerformanceDataPIPerformance
+
+#endif
+
+// =================================================================================================
+
+#define EliminateGlobal(g) delete ( g ); g = 0
+
+/* class static */
+void
+XMPFiles::Terminate()
+{
+ --sXMPFilesInitCount;
+ if ( sXMPFilesInitCount != 0 ) return;
+
+ if ( ! sIgnoreQuickTime ) QuickTime_Support::MainTerminate();
+
+ #if GatherPerformanceData
+ ReportPerformanceData();
+ EliminateGlobal ( sAPIPerf );
+ #endif
+
+ EliminateGlobal ( sRegisteredHandlers );
+ EliminateGlobal ( sXMPFilesExceptionMessage );
+
+ XMP_TermMutex ( sXMPFilesLock );
+
+ SXMPMeta::Terminate(); // Just in case the client does not.
+
+} // XMPFiles::Terminate
+
+// =================================================================================================
+
+XMPFiles::XMPFiles() :
+ clientRefs(0),
+ format(kXMP_UnknownFile),
+ fileRef(0),
+ openFlags(0),
+ abortProc(0),
+ abortArg(0),
+ handler(0),
+ handlerTemp(0)
+{
+ // Nothing more to do, clientRefs is incremented in wrapper.
+
+} // XMPFiles::XMPFiles
+
+// =================================================================================================
+
+XMPFiles::~XMPFiles()
+{
+ XMP_Assert ( this->clientRefs <= 0 );
+
+ if ( this->handler != 0 ) {
+ delete this->handler;
+ this->handler = 0;
+ }
+ if ( this->fileRef != 0 ) {
+ LFA_Close ( this->fileRef );
+ this->fileRef = 0;
+ }
+
+} // XMPFiles::~XMPFiles
+
+// =================================================================================================
+
+/* class static */
+void
+XMPFiles::UnlockLib()
+{
+
+ // *** Would be better to have the count in an object with the mutex.
+ #if TraceXMPLocking
+ fprintf ( xmpOut, " Unlocking XMPFiles, count = %d\n", sXMPFilesLockCount ); fflush ( xmpOut );
+ #endif
+ --sXMPFilesLockCount;
+ XMP_Assert ( sXMPFilesLockCount == 0 );
+ XMP_ExitCriticalRegion ( sXMPFilesLock );
+
+} // XMPFiles::UnlockLib
+
+// =================================================================================================
+
+void
+XMPFiles::UnlockObj()
+{
+
+ // *** Would be better to have the count in an object with the mutex.
+ #if TraceXMPLocking
+ fprintf ( xmpOut, " Unlocking XMPFiles, count = %d\n", sXMPFilesLockCount ); fflush ( xmpOut );
+ #endif
+ --sXMPFilesLockCount;
+ XMP_Assert ( sXMPFilesLockCount == 0 );
+ XMP_ExitCriticalRegion ( sXMPFilesLock );
+
+} // XMPFiles::UnlockObj
+
+// =================================================================================================
+
+/* class static */
+bool
+XMPFiles::GetFormatInfo ( XMP_FileFormat format,
+ XMP_OptionBits * flags /* = 0 */ )
+{
+ if ( flags == 0 ) flags = &voidOptionBits;
+
+ XMPFileHandlerTablePos handlerPos = sRegisteredHandlers->begin();
+ for ( ; handlerPos != sRegisteredHandlers->end(); ++handlerPos ) {
+ if ( handlerPos->format == format ) {
+ *flags = handlerPos->flags;
+ return true;
+ }
+ }
+
+ return false;
+
+} // XMPFiles::GetFormatInfo
+
+// =================================================================================================
+
+bool
+XMPFiles::OpenFile ( XMP_StringPtr filePath,
+ XMP_FileFormat format /* = kXMP_UnknownFile */,
+ XMP_OptionBits openFlags /* = 0 */ )
+{
+ // *** Check consistency of the option bits, use of kXMPFiles_OpenUseSmartHandler.
+
+ if ( this->handler != 0 ) XMP_Throw ( "File already open", kXMPErr_BadParam );
+
+ // Select the file handler. Don't set the XMPFiles member variables until the end, leave them
+ // clean in case something fails along the way. Use separate handler search loops, filtering on
+ // whether the handler wants to open the file itself.
+
+ // An initial handler is tried based on the format parameter, or the file extension if the
+ // parameter is kXMP_UnknownFile. If that fails, all of the handlers are tried in registration
+ // order. The CheckProc should do as little as possible to determine the format, based on the
+ // actual file content. If that is not possible, use the format hint. The initial CheckProc call
+ // has the presumed format in this->format, the later calls have kXMP_UnknownFile there.
+
+ bool foundHandler = false;
+ LFA_FileRef fileRef = 0;
+
+ char openMode = 'r';
+ if ( openFlags & kXMPFiles_OpenForUpdate ) openMode = 'w';
+
+ XMPFileHandlerTablePos handlerPos = sRegisteredHandlers->end();
+
+ std::string fileExt;
+ size_t extPos = strlen ( filePath );
+ for ( --extPos; extPos > 0; --extPos ) if ( filePath[extPos] == '.' ) break;
+ if ( filePath[extPos] == '.' ) {
+ ++extPos;
+ fileExt.assign ( &filePath[extPos] );
+ for ( size_t i = 0; i < fileExt.size(); ++i ) {
+ if ( ('A' <= fileExt[i]) && (fileExt[i] <= 'Z') ) fileExt[i] += 0x20;
+ }
+ }
+
+ this->format = kXMP_UnknownFile; // Make sure it is preset for later check.
+ this->openFlags = openFlags; // ! The QuickTime support needs the InBackground bit.
+
+ if ( ! (openFlags & kXMPFiles_OpenUsePacketScanning) ) {
+
+ // Try an initial handler based on the format or file extension.
+ handlerPos = FindHandler ( format, fileExt );
+ if ( handlerPos != sRegisteredHandlers->end() ) {
+ if ( ! (handlerPos->flags & kXMPFiles_HandlerOwnsFile) ) fileRef = LFA_Open ( filePath, openMode );
+ this->format = handlerPos->format; // ! Hack to tell the CheckProc this is the first call.
+ foundHandler = handlerPos->checkProc ( handlerPos->format, filePath, fileRef, this );
+ }
+
+ if ( (openFlags & kXMPFiles_OpenStrictly) && (format != kXMP_UnknownFile) && (! foundHandler) ) {
+ return false;
+ }
+
+ // Search the handlers that don't want to open the file themselves. They must be registered first.
+ if ( ! foundHandler ) {
+ if ( fileRef == 0 ) fileRef = LFA_Open ( filePath, openMode );
+ XMP_Assert ( fileRef != 0 ); // LFA_Open must either succeed or throw.
+ for ( handlerPos = sRegisteredHandlers->begin(); handlerPos != sRegisteredHandlers->end(); ++handlerPos ) {
+ if ( handlerPos->flags & kXMPFiles_HandlerOwnsFile ) break;
+ this->format = kXMP_UnknownFile; // ! Hack to tell the CheckProc this is not the first call.
+ foundHandler = handlerPos->checkProc ( handlerPos->format, filePath, fileRef, this );
+ if ( foundHandler ) break; // ! Exit before incrementing handlerPos.
+ }
+ }
+
+ // Search the handlers that do want to open the file themselves. They must be registered last.
+ if ( ! foundHandler ) {
+ LFA_Close ( fileRef );
+ fileRef = 0;
+ for ( ; handlerPos != sRegisteredHandlers->end(); ++handlerPos ) {
+ XMP_Assert ( handlerPos->flags & kXMPFiles_HandlerOwnsFile );
+ this->format = kXMP_UnknownFile; // ! Hack to tell the CheckProc this is not the first call.
+ foundHandler = handlerPos->checkProc ( handlerPos->format, filePath, 0, this );
+ if ( foundHandler ) break; // ! Exit before incrementing handlerPos.
+ }
+ }
+
+ if ( (! foundHandler) && (openFlags & kXMPFiles_OpenUseSmartHandler) ) {
+ return false;
+ }
+
+ }
+
+ // Create the handler object, fill in the XMPFiles member variables, cache the desired file data.
+
+ XMPFileHandlerCTor handlerCTor = 0;
+ XMP_OptionBits handlerFlags = 0;
+
+ if ( foundHandler ) {
+
+ // Found a smart handler.
+ format = handlerPos->format;
+ handlerCTor = handlerPos->handlerCTor;
+ handlerFlags = handlerPos->flags;
+
+ } else {
+
+ // No smart handler, packet scan if appropriate.
+ if ( openFlags & kXMPFiles_OpenLimitedScanning ) {
+ size_t i;
+ for ( i = 0; kKnownScannedFiles[i] != 0; ++i ) {
+ if ( fileExt == kKnownScannedFiles[i] ) break;
+ }
+ if ( kKnownScannedFiles[i] == 0 ) return false;
+ }
+ format = kXMP_UnknownFile;
+ handlerCTor = Scanner_MetaHandlerCTor;
+ handlerFlags = kScanner_HandlerFlags;
+ if ( fileRef == 0 ) fileRef = LFA_Open ( filePath, openMode );
+
+ }
+
+ this->fileRef = fileRef;
+ this->filePath = filePath;
+
+ XMPFileHandler * handler = (*handlerCTor) ( this );
+ XMP_Assert ( handlerFlags == handler->handlerFlags );
+
+ this->handler = handler;
+ if ( this->format == kXMP_UnknownFile ) this->format = format; // ! The CheckProc might have set it.
+
+ handler->CacheFileData();
+
+ if ( ! (openFlags & kXMPFiles_OpenCacheTNail) ) {
+ handler->containsTNail = false; // Make sure GetThumbnail will cleanly return false.
+ handler->processedTNail = true;
+ }
+
+ if ( handler->containsXMP ) {
+ XMP_StringPtr packetStr = handler->xmpPacket.c_str();
+ XMP_StringLen packetLen = handler->xmpPacket.size();
+ if ( packetLen > 0 ) {
+ handler->packetInfo.charForm = GetPacketCharForm ( packetStr, packetLen );
+ handler->packetInfo.padSize = GetPacketPadSize ( packetStr, packetLen );
+ handler->packetInfo.writeable = GetPacketRWMode ( packetStr, packetLen, XMP_GetCharSize ( handler->packetInfo.charForm ) );
+ }
+ }
+
+ if ( (! (openFlags & kXMPFiles_OpenForUpdate)) && (! (handlerFlags & kXMPFiles_HandlerOwnsFile)) ) {
+ // Close the disk file now if opened for read-only access.
+ LFA_Close ( this->fileRef );
+ this->fileRef = 0;
+ }
+
+ return true;
+
+} // XMPFiles::OpenFile
+
+// =================================================================================================
+
+void
+XMPFiles::CloseFile ( XMP_OptionBits closeFlags /* = 0 */ )
+{
+ if ( this->handler == 0 ) return; // Return if there is no open file (not an error).
+
+ bool needsUpdate = this->handler->needsUpdate;
+ XMP_OptionBits handlerFlags = this->handler->handlerFlags;
+
+ // Decide if we're doing a safe update. If so, make sure the handler supports it. All handlers
+ // that don't own the file tolerate safe update using common code below.
+
+ bool doSafeUpdate = XMP_OptionIsSet ( closeFlags, kXMPFiles_UpdateSafely );
+ #if GatherPerformanceData
+ if ( doSafeUpdate ) sAPIPerf->back().extraInfo += ", safe update"; // Client wants safe update.
+ #endif
+
+ if ( ! (this->openFlags & kXMPFiles_OpenForUpdate) ) doSafeUpdate = false;
+ if ( ! needsUpdate ) doSafeUpdate = false;
+
+ bool safeUpdateOK = ( (handlerFlags & kXMPFiles_AllowsSafeUpdate) ||
+ (! (handlerFlags & kXMPFiles_HandlerOwnsFile)) );
+ if ( doSafeUpdate && (! safeUpdateOK) ) {
+ XMP_Throw ( "XMPFiles::CloseFile - Safe update not supported", kXMPErr_Unavailable );
+ }
+
+ // Try really hard to make sure the file is closed and the handler is deleted.
+
+ LFA_FileRef origFileRef = this->fileRef; // Used during crash-safe saves.
+ std::string origFilePath ( this->filePath );
+
+ LFA_FileRef tempFileRef = 0;
+ std::string tempFilePath;
+
+ LFA_FileRef copyFileRef = 0;
+ std::string copyFilePath;
+
+ try {
+
+ if ( (! doSafeUpdate) || (handlerFlags & kXMPFiles_HandlerOwnsFile) ) {
+
+ // Close the file without doing common crash-safe writing. The handler might do it.
+
+ #if GatherPerformanceData
+ if ( needsUpdate ) sAPIPerf->back().extraInfo += ", direct update";
+ #endif
+
+ if ( needsUpdate ) this->handler->UpdateFile ( doSafeUpdate );
+ delete this->handler;
+ this->handler = 0;
+ if ( this->fileRef != 0 ) LFA_Close ( this->fileRef );
+ this->fileRef = 0;
+
+ } else {
+
+ // Update the file in a crash-safe manner. This somewhat convoluted approach preserves
+ // the ownership, permissions, and Mac resources of the final file - at a slightly
+ // higher risk of confusion in the event of a midstream crash.
+
+ if ( handlerFlags & kXMPFiles_CanRewrite ) {
+
+ // The handler can rewrite an entire file based on the original. Do this into a temp
+ // file next to the original, with the same ownership and permissions if possible.
+
+ #if GatherPerformanceData
+ sAPIPerf->back().extraInfo += ", file rewrite";
+ #endif
+
+ CreateTempFile ( origFilePath, &tempFilePath, kCopyMacRsrc );
+ tempFileRef = LFA_Open ( tempFilePath.c_str(), 'w' );
+ this->fileRef = tempFileRef;
+ this->filePath = tempFilePath;
+ this->handler->WriteFile ( origFileRef, origFilePath );
+
+ } else {
+
+ // The handler can only update an existing file. Do a little dance so the final file
+ // is the original, thus preserving ownership, permissions, etc. This does have the
+ // risk that the interim copy under the original name has "current" ownership and
+ // permissions. The dance steps:
+ // - Copy the original file to a temp name.
+ // - Rename the original file to a different temp name.
+ // - Rename the copy file back to the original name.
+ // - Call the handler's UpdateFile method for the "original as temp" file.
+
+ // *** A user abort might leave the copy file under the original name! Need better
+ // *** duplicate code that handles all parts of a file, and for CreateTempFile to
+ // *** preserve ownership and permissions. Then the original can stay put until
+ // *** the final delete/rename.
+
+ #if GatherPerformanceData
+ sAPIPerf->back().extraInfo += ", copy update";
+ #endif
+
+ CreateTempFile ( origFilePath, &copyFilePath, kCopyMacRsrc );
+ copyFileRef = LFA_Open ( copyFilePath.c_str(), 'w' );
+ XMP_Int64 fileSize = LFA_Measure ( origFileRef );
+ LFA_Seek ( origFileRef, 0, SEEK_SET );
+ LFA_Copy ( origFileRef, copyFileRef, fileSize, this->abortProc, this->abortArg );
+
+ LFA_Close ( origFileRef );
+ origFileRef = this->fileRef = 0;
+ LFA_Close ( copyFileRef );
+ copyFileRef = 0;
+
+ CreateTempFile ( origFilePath, &tempFilePath );
+ LFA_Delete ( tempFilePath.c_str() ); // ! Slight risk of name being grabbed before rename.
+ LFA_Rename ( origFilePath.c_str(), tempFilePath.c_str() );
+
+ tempFileRef = LFA_Open ( tempFilePath.c_str(), 'w' );
+ this->fileRef = tempFileRef;
+
+ try {
+ LFA_Rename ( copyFilePath.c_str(), origFilePath.c_str() );
+ } catch ( ... ) {
+ this->fileRef = 0;
+ LFA_Close ( tempFileRef );
+ LFA_Rename ( tempFilePath.c_str(), origFilePath.c_str() );
+ throw;
+ }
+
+ XMP_Assert ( (tempFileRef != 0) && (tempFileRef == this->fileRef) );
+ this->filePath = tempFilePath;
+ this->handler->UpdateFile ( false ); // We're doing the safe update, not the handler.
+
+ }
+
+ delete this->handler;
+ this->handler = 0;
+
+ if ( this->fileRef != 0 ) LFA_Close ( this->fileRef );
+ if ( origFileRef != 0 ) LFA_Close ( origFileRef );
+
+ this->fileRef = 0;
+ origFileRef = 0;
+ tempFileRef = 0;
+
+ LFA_Delete ( origFilePath.c_str() );
+ LFA_Rename ( tempFilePath.c_str(), origFilePath.c_str() );
+
+ }
+
+ } catch ( ... ) {
+
+ // *** Don't delete the temp or copy files, not sure which is best.
+
+ try {
+ if ( this->fileRef != 0 ) LFA_Close ( this->fileRef );
+ } catch ( ... ) { /*Do nothing, throw the outer exception later. */ }
+ try {
+ if ( origFileRef != 0 ) LFA_Close ( origFileRef );
+ } catch ( ... ) { /*Do nothing, throw the outer exception later. */ }
+ try {
+ if ( tempFileRef != 0 ) LFA_Close ( tempFileRef );
+ } catch ( ... ) { /*Do nothing, throw the outer exception later. */ }
+ try {
+ if ( copyFileRef != 0 ) LFA_Close ( copyFileRef );
+ } catch ( ... ) { /*Do nothing, throw the outer exception later. */ }
+ try {
+ if ( this->handler != 0 ) delete this->handler;
+ } catch ( ... ) { /*Do nothing, throw the outer exception later. */ }
+
+ this->handler = 0;
+ this->format = kXMP_UnknownFile;
+ this->fileRef = 0;
+ this->filePath.clear();
+ this->openFlags = 0;
+
+ throw;
+
+ }
+
+ // Clear the XMPFiles member variables.
+
+ this->handler = 0;
+ this->format = kXMP_UnknownFile;
+ this->fileRef = 0;
+ this->filePath.clear();
+ this->openFlags = 0;
+
+} // XMPFiles::CloseFile
+
+// =================================================================================================
+
+bool
+XMPFiles::GetFileInfo ( XMP_StringPtr * filePath /* = 0 */,
+ XMP_StringLen * pathLen /* = 0 */,
+ XMP_OptionBits * openFlags /* = 0 */,
+ XMP_FileFormat * format /* = 0 */,
+ XMP_OptionBits * handlerFlags /* = 0 */ )
+{
+ if ( this->handler == 0 ) return false;
+
+ if ( filePath == 0 ) filePath = &voidStringPtr;
+ if ( pathLen == 0 ) pathLen = &voidStringLen;
+ if ( openFlags == 0 ) openFlags = &voidOptionBits;
+ if ( format == 0 ) format = &voidFileFormat;
+ if ( handlerFlags == 0 ) handlerFlags = &voidOptionBits;
+
+ *filePath = this->filePath.c_str();
+ *pathLen = this->filePath.size();
+ *openFlags = this->openFlags;
+ *format = this->format;
+ *handlerFlags = this->handler->handlerFlags;
+
+ return true;
+
+} // XMPFiles::GetFileInfo
+
+// =================================================================================================
+
+void
+XMPFiles::SetAbortProc ( XMP_AbortProc abortProc,
+ void * abortArg )
+{
+ this->abortProc = abortProc;
+ this->abortArg = abortArg;
+
+ XMP_Assert ( (abortProc != (XMP_AbortProc)0) || (abortArg != (void*)0xDEADBEEF) ); // Hack to test the assert callback.
+
+} // XMPFiles::SetAbortProc
+
+// =================================================================================================
+
+bool
+XMPFiles::GetXMP ( SXMPMeta * xmpObj /* = 0 */,
+ XMP_StringPtr * xmpPacket /* = 0 */,
+ XMP_StringLen * xmpPacketLen /* = 0 */,
+ XMP_PacketInfo * packetInfo /* = 0 */ )
+{
+ if ( this->handler == 0 ) XMP_Throw ( "XMPFiles::GetXMP - No open file", kXMPErr_BadObject );
+
+ if ( ! this->handler->processedXMP ) {
+ try {
+ this->handler->ProcessXMP();
+ } catch ( ... ) {
+ // Return the outputs then rethrow the exception.
+ if ( xmpObj != 0 ) {
+ SXMPUtils::RemoveProperties ( xmpObj, 0, 0, kXMPUtil_DoAllProperties );
+ SXMPUtils::AppendProperties ( this->handler->xmpObj, xmpObj, kXMPUtil_DoAllProperties );
+ }
+ if ( xmpPacket != 0 ) *xmpPacket = this->handler->xmpPacket.c_str();
+ if ( xmpPacketLen != 0 ) *xmpPacketLen = this->handler->xmpPacket.size();
+ if ( packetInfo != 0 ) *packetInfo = this->handler->packetInfo;
+ throw;
+ }
+ }
+
+ if ( ! this->handler->containsXMP ) return false;
+
+ #if 0 // *** See bug 1131815. A better way might be to pass the ref up from here.
+ if ( xmpObj != 0 ) *xmpObj = this->handler->xmpObj.Clone();
+ #else
+ if ( xmpObj != 0 ) {
+ SXMPUtils::RemoveProperties ( xmpObj, 0, 0, kXMPUtil_DoAllProperties );
+ SXMPUtils::AppendProperties ( this->handler->xmpObj, xmpObj, kXMPUtil_DoAllProperties );
+ }
+ #endif
+
+ if ( xmpPacket != 0 ) *xmpPacket = this->handler->xmpPacket.c_str();
+ if ( xmpPacketLen != 0 ) *xmpPacketLen = this->handler->xmpPacket.size();
+ if ( packetInfo != 0 ) *packetInfo = this->handler->packetInfo;
+
+ return true;
+
+} // XMPFiles::GetXMP
+
+// =================================================================================================
+
+bool
+XMPFiles::GetThumbnail ( XMP_ThumbnailInfo * tnailInfo )
+{
+ if ( this->handler == 0 ) XMP_Throw ( "XMPFiles::GetThumbnail - No open file", kXMPErr_BadObject );
+
+ if ( ! (this->handler->handlerFlags & kXMPFiles_ReturnsTNail) ) return false;
+
+ if ( ! this->handler->processedTNail ) this->handler->ProcessTNail();
+ if ( ! this->handler->containsTNail ) return false;
+ if ( tnailInfo != 0 ) *tnailInfo = this->handler->tnailInfo;
+
+ return true;
+
+} // XMPFiles::GetThumbnail
+
+// =================================================================================================
+
+static bool
+DoPutXMP ( XMPFiles * thiz, const SXMPMeta & xmpObj, const bool doIt )
+{
+ // Check some basic conditions to see if the Put should be attempted.
+
+ if ( thiz->handler == 0 ) XMP_Throw ( "XMPFiles::PutXMP - No open file", kXMPErr_BadObject );
+ if ( ! (thiz->openFlags & kXMPFiles_OpenForUpdate) ) {
+ XMP_Throw ( "XMPFiles::PutXMP - Not open for update", kXMPErr_BadObject );
+ }
+
+ XMPFileHandler * handler = thiz->handler;
+ XMP_OptionBits handlerFlags = handler->handlerFlags;
+ XMP_PacketInfo & packetInfo = handler->packetInfo;
+ std::string & xmpPacket = handler->xmpPacket;
+
+ if ( ! handler->processedXMP ) handler->ProcessXMP(); // Might have Open/Put with no GetXMP.
+
+ size_t oldPacketOffset = (size_t)packetInfo.offset;
+ size_t oldPacketLength = packetInfo.length;
+
+ if ( oldPacketOffset == (size_t)kXMPFiles_UnknownOffset ) oldPacketOffset = 0; // ! Simplify checks.
+ if ( oldPacketLength == (size_t)kXMPFiles_UnknownLength ) oldPacketLength = 0;
+
+ bool fileHasPacket = (oldPacketOffset != 0) && (oldPacketLength != 0);
+
+ if ( ! fileHasPacket ) {
+ if ( ! (handlerFlags & kXMPFiles_CanInjectXMP) ) {
+ XMP_Throw ( "XMPFiles::PutXMP - Can't inject XMP", kXMPErr_Unavailable );
+ }
+ if ( handler->stdCharForm == kXMP_CharUnknown ) {
+ XMP_Throw ( "XMPFiles::PutXMP - No standard character form", kXMPErr_InternalFailure );
+ }
+ }
+
+ // Serialize the XMP and update the handler's info.
+
+ XMP_Uns8 charForm = handler->stdCharForm;
+ if ( charForm == kXMP_CharUnknown ) charForm = packetInfo.charForm;
+
+ XMP_OptionBits options = kXMP_UseCompactFormat | XMP_CharToSerializeForm ( charForm );
+ if ( handlerFlags & kXMPFiles_NeedsReadOnlyPacket ) options |= kXMP_ReadOnlyPacket;
+ if ( fileHasPacket && (thiz->format == kXMP_UnknownFile) && (! packetInfo.writeable) ) options |= kXMP_ReadOnlyPacket;
+
+ bool preferInPlace = ((handlerFlags & kXMPFiles_PrefersInPlace) != 0);
+ bool tryInPlace = (fileHasPacket & preferInPlace) || (! (handlerFlags & kXMPFiles_CanExpand));
+
+ if ( handlerFlags & kXMPFiles_UsesSidecarXMP ) tryInPlace = false;
+
+ if ( tryInPlace ) {
+ XMP_Assert ( handler->containsXMP && (oldPacketLength == xmpPacket.size()) );
+ try {
+ xmpObj.SerializeToBuffer ( &xmpPacket, (options | kXMP_ExactPacketLength), oldPacketLength );
+ XMP_Assert ( xmpPacket.size() == oldPacketLength );
+ } catch ( ... ) {
+ if ( preferInPlace ) {
+ tryInPlace = false; // ! Try again, out of place this time.
+ } else {
+ if ( ! doIt ) return false;
+ throw;
+ }
+ }
+ }
+
+ if ( ! tryInPlace ) {
+ try {
+ xmpObj.SerializeToBuffer ( &xmpPacket, options );
+ } catch ( ... ) {
+ if ( ! doIt ) return false;
+ throw;
+ }
+ }
+
+ if ( doIt ) {
+ if ( ! tryInPlace ) packetInfo.offset = kXMPFiles_UnknownOffset;
+ packetInfo.length = xmpPacket.size();
+ packetInfo.padSize = GetPacketPadSize ( xmpPacket.c_str(), xmpPacket.size() );
+ packetInfo.charForm = charForm;
+ handler->xmpObj = xmpObj.Clone();
+ handler->containsXMP = true;
+ handler->processedXMP = true;
+ handler->needsUpdate = true;
+ }
+
+ return true;
+
+} // DoPutXMP
+
+// =================================================================================================
+
+void
+XMPFiles::PutXMP ( const SXMPMeta & xmpObj )
+{
+ (void) DoPutXMP ( this, xmpObj, true );
+
+} // XMPFiles::PutXMP
+
+// =================================================================================================
+
+void
+XMPFiles::PutXMP ( XMP_StringPtr xmpPacket,
+ XMP_StringLen xmpPacketLen /* = kXMP_UseNullTermination */ )
+{
+ SXMPMeta xmpObj ( xmpPacket, xmpPacketLen );
+ this->PutXMP ( xmpObj );
+
+} // XMPFiles::PutXMP
+
+// =================================================================================================
+
+bool
+XMPFiles::CanPutXMP ( const SXMPMeta & xmpObj )
+{
+ if ( this->handler == 0 ) XMP_Throw ( "XMPFiles::CanPutXMP - No open file", kXMPErr_BadObject );
+ if ( ! (this->openFlags & kXMPFiles_OpenForUpdate) ) return false;
+
+ if ( this->handler->handlerFlags & kXMPFiles_CanInjectXMP ) return true;
+ if ( ! this->handler->containsXMP ) return false;
+ if ( this->handler->handlerFlags & kXMPFiles_CanExpand ) return true;
+
+ return DoPutXMP ( this, xmpObj, false );
+
+} // XMPFiles::CanPutXMP
+
+// =================================================================================================
+
+bool
+XMPFiles::CanPutXMP ( XMP_StringPtr xmpPacket,
+ XMP_StringLen xmpPacketLen /* = kXMP_UseNullTermination */ )
+{
+ SXMPMeta xmpObj ( xmpPacket, xmpPacketLen );
+ return this->CanPutXMP ( xmpObj );
+
+} // XMPFiles::CanPutXMP
+
+// =================================================================================================
diff --git a/source/XMPFiles/XMPFiles.hpp b/source/XMPFiles/XMPFiles.hpp
new file mode 100644
index 0000000..36c55f1
--- /dev/null
+++ b/source/XMPFiles/XMPFiles.hpp
@@ -0,0 +1,224 @@
+#ifndef __XMPFiles_hpp__
+#define __XMPFiles_hpp__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include <string>
+
+#define TXMP_STRING_TYPE std::string
+#include "XMP.hpp"
+
+typedef void * LFA_FileRef;
+class XMPFileHandler;
+
+// =================================================================================================
+/// \file XMPFiles.hpp
+/// \brief High level support to access metadata in files of interest to Adobe applications.
+///
+/// This header ...
+///
+// =================================================================================================
+
+// =================================================================================================
+// *** Usage Notes (eventually to become Doxygen comments) ***
+// ===========================================================
+//
+// This is the main part of the internal (DLL side) implementation of XMPFiles. Other parts are
+// the entry point wrappers and the file format handlers. The XMPFiles class distills the client
+// API from TXMPFiles.hpp, removing convenience overloads and substituting a pointer/length pair
+// for output strings.
+//
+// The wrapper functions provide a stable binary interface and perform minor impedance correction
+// between the client template API from TDocMeta.hpp and the DLL's XMPFiles class. The details of
+// the wrappers should be considered private.
+//
+// File handlers are registered during DLL initialization with hard coded calls in Init_XMPFiles.
+// Each file handler provides 2 standalone functions, CheckFormatProc and DocMetaHandlerCTor, plus a
+// class derived from DocMetaHandler. The format and capability flags are passed when registering.
+// This allows the same physical handler to be registered for multiple formats.
+//
+// -------------------------------------------------------------------------------------------------
+//
+// Basic outlines of the processing by the XMPFiles methods:
+//
+// Constructor:
+// - Minimal work to create an empty XMPFiles object, set the ref count to 1.
+//
+// Destructor:
+// - Decrement the ref count, return if greater than zero.
+// - Call LFA_Close if necessary.
+//
+// UnlockLib & UnlockObj:
+// - Release the thread lock. Same for now, no per-object lock.
+//
+// GetFormatInfo:
+// - Return the flags for the registered handler.
+//
+// OpenFile:
+// - The physical file is opened via LFA_OpenFile.
+// - A handler is selected by calling the registered format checkers.
+// - The handler object is created by calling the registered constructor proc.
+//
+// CloseFile:
+// - Return if there is no open file (not an error).
+// - If not a crash-safe update (includes read-only or no update), or the handler owns the file:
+// - Throw an exception if the handler owns the file but does not support safe update.
+// - If the file needs updating, call the handler's UpdateFile method.
+// - else:
+// - If the handler supports file rewrite:
+// - *** This might not preserve ownership and permissions.
+// - Create an empty temp file.
+// - Call the handler's WriteFile method, writing to the temp file.
+// - else
+// - *** This preserves ownership, permissions, and Mac resources.
+// - Copy the original file to a temp name (Mac data fork only).
+// - Rename the original file to a different temp name.
+// - Rename the copy file back to the original name.
+// - Call the handler's UpdateFile method for the "original as temp" file.
+// - Close both the original and temp files.
+// - Delete the file with the original name.
+// - Rename the temp file to the original name.
+// - Delete the handler object.
+// - Call LFA_Close if necessary.
+//
+// GetFileInfo:
+// - Return the file info from the XMPFiles member variables.
+//
+// GetXMP:
+// - Throw an exception if there is no open file.
+// - Call the handler's GetXMP method.
+//
+// PutXMP:
+// - Throw an exception if there is no open file.
+// - Call the handler's PutXMP method.
+//
+// CanPutXMP:
+// - Implement roughly as shown in TXMPFiles.hpp, there is no handler CanPutXMP method.
+//
+// -------------------------------------------------------------------------------------------------
+//
+// The format checker should do nothing but the minimal work to identify the overall file format.
+// In particular it should not look for XMP or other metadata. Note that the format checker has no
+// means to carry state forward, it just returns a yes/no answer about a particular file format.
+//
+// The format checker and file handler should use the LFA_* functions for all I/O. They should not
+// open or close the file themselves unless the handler sets the "handler-owns-file" flag.
+//
+// The format checker is passed the format being checked, allowing one checker to handle multiple
+// formats. It is passed the LFA file ref so that it can do additional reads if necessary. The
+// buffer is from the start of the file, the file will be positioned to the byte following the
+// buffer. The buffer length will be at least 4K, unless the file is smaller in which case it will
+// be the length of the file. This buffer may be reused for additional reads.
+//
+// Identifying some file formats can require checking variable length strings. Doing seeks and reads
+// for each is suboptimal. There are utilities to maintain a rolling buffer and ensure that a given
+// amount of data is available. See the template file handler code for details.
+//
+// -------------------------------------------------------------------------------------------------
+//
+// The file handler has no explicit open and close methods. These are implicit in the handler's
+// constructor and destructor. The file handler should use the XMPFiles member variables for the
+// active file ref (and path if necessary), unless it owns the file. Note that these might change
+// between the open and close in the case of crash-safe updates. Don't copy the XMPFiles member
+// variables in the handler's constructor, save the pointer to the XMPFiles object and access
+// directly as needed.
+//
+// The handler should have an UpdateFile method. This is called from XMPFiles::CloseFile if the
+// file needs to be updated. The handler's destructor must only close the file, not update it.
+// The handler can optionally have a WriteFile method, if it can rewrite the entire file.
+//
+// The handler is free to use its best judgement about caching parts of the file in memory. Overall
+// speed of a single open/get/put/close cycle is probably the best goal, assuming a modern processor
+// with a reasonable (significant but not enormous) amount of RAM.
+//
+// The handler methods will be called in a per-object thread safe manner. Concurrent access might
+// occur for different objects, but not for the same object. The handler's constructor and destructor
+// will always be globally serialized, so they can safely modify global data structures.
+//
+// (Testing issue: What about separate XMPFiles objects accessing the same file?)
+//
+// Handler's must not have any global objects that are heap allocated. Use pointers to objects that
+// are allocated and deleted during the XMPFiles initialization and termination process. Some
+// client apps are very picky about what they detect as memory leaks.
+//
+// static char gSomeBuffer [10*1000]; // OK, not from the heap.
+// static std::string gSomeString; // Not OK, content from the heap.
+// static std::vector<int> gSomeVector; // Not OK, content from the heap.
+// static std::string * gSomeString = 0; // OK, alloc at init, delete at term.
+// static std::vector<int> * gSomeVector = 0; // OK, alloc at init, delete at term.
+//
+// =================================================================================================
+
+class XMPFiles {
+public:
+
+ static void GetVersionInfo ( XMP_VersionInfo * info );
+
+ static bool Initialize ( XMP_OptionBits options = 0 );
+ static void Terminate();
+
+ XMPFiles();
+ virtual ~XMPFiles();
+
+ static void UnlockLib();
+ void UnlockObj();
+
+ static bool GetFormatInfo ( XMP_FileFormat format,
+ XMP_OptionBits * flags = 0 );
+
+ bool OpenFile ( XMP_StringPtr filePath,
+ XMP_FileFormat format = kXMP_UnknownFile,
+ XMP_OptionBits openFlags = 0 );
+
+ void CloseFile ( XMP_OptionBits closeFlags = 0 );
+
+ bool GetFileInfo ( XMP_StringPtr * filePath = 0,
+ XMP_StringLen * filePathLen = 0,
+ XMP_OptionBits * openFlags = 0,
+ XMP_FileFormat * format = 0,
+ XMP_OptionBits * handlerFlags = 0 );
+
+ void SetAbortProc ( XMP_AbortProc abortProc,
+ void * abortArg );
+
+ bool GetXMP ( SXMPMeta * xmpObj = 0,
+ XMP_StringPtr * xmpPacket = 0,
+ XMP_StringLen * xmpPacketLen = 0,
+ XMP_PacketInfo * packetInfo = 0 );
+
+ bool GetThumbnail ( XMP_ThumbnailInfo * tnailInfo );
+
+ void PutXMP ( const SXMPMeta & xmpObj );
+
+ void PutXMP ( XMP_StringPtr xmpPacket,
+ XMP_StringLen xmpPacketLen = kXMP_UseNullTermination );
+
+ bool CanPutXMP ( const SXMPMeta & xmpObj );
+
+ bool CanPutXMP ( XMP_StringPtr xmpPacket,
+ XMP_StringLen xmpPacketLen = kXMP_UseNullTermination );
+
+ // Leave this data public so file handlers can see it.
+
+ XMP_Int32 clientRefs; // ! Must be signed to allow decrement from zero.
+
+ XMP_FileFormat format;
+ LFA_FileRef fileRef; // Non-zero if a file is open.
+ std::string filePath;
+ XMP_OptionBits openFlags;
+ XMPFileHandler * handler; // Non-null if a file is open.
+ void * handlerTemp; // For use between the CheckProc and handler creation.
+
+ XMP_AbortProc abortProc;
+ void * abortArg;
+
+}; // XMPFiles
+
+#endif /* __XMPFiles_hpp__ */
diff --git a/source/XMPFiles/XMPFiles_Impl.cpp b/source/XMPFiles/XMPFiles_Impl.cpp
new file mode 100644
index 0000000..892c280
--- /dev/null
+++ b/source/XMPFiles/XMPFiles_Impl.cpp
@@ -0,0 +1,1210 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "XMPFiles_Impl.hpp"
+
+#if XMP_MacBuild
+ #include <Files.h>
+#elif XMP_WinBuild
+ #include <Windows.h>
+#elif XMP_UNIXBuild
+ #include <fcntl.h>
+ #include <sys/stat.h>
+ #include <unistd.h>
+#endif
+
+using namespace std;
+
+// Internal code should be using #if with XMP_MacBuild, XMP_WinBuild, or XMP_UNIXBuild.
+// This is a sanity check in case of accidental use of *_ENV. Some clients use the poor
+// practice of defining the *_ENV macro with an empty value.
+#if defined ( MAC_ENV )
+ #if ! MAC_ENV
+ #error "MAC_ENV must be defined so that \"#if MAC_ENV\" is true"
+ #endif
+#elif defined ( WIN_ENV )
+ #if ! WIN_ENV
+ #error "WIN_ENV must be defined so that \"#if WIN_ENV\" is true"
+ #endif
+#elif defined ( UNIX_ENV )
+ #if ! UNIX_ENV
+ #error "UNIX_ENV must be defined so that \"#if UNIX_ENV\" is true"
+ #endif
+#endif
+
+// =================================================================================================
+/// \file XMPFiles_Impl.cpp
+/// \brief ...
+///
+/// This file ...
+///
+// =================================================================================================
+
+#if XMP_WinBuild
+ #pragma warning ( disable : 4290 ) // C++ exception specification ignored except to indicate a function is not __declspec(nothrow)
+ #pragma warning ( disable : 4800 ) // forcing value to bool 'true' or 'false' (performance warning)
+#endif
+
+XMP_FileFormat voidFileFormat = 0; // Used as sink for unwanted output parameters.
+XMP_Mutex sXMPFilesLock;
+int sXMPFilesLockCount = 0;
+XMP_VarString * sXMPFilesExceptionMessage = 0;
+
+#if TraceXMPCalls
+ FILE * xmpFilesOut = stderr;
+#endif
+
+// =================================================================================================
+
+const FileExtMapping kFileExtMap[] = // Add all known mappings, multiple mappings (tif, tiff) are OK.
+ { { "pdf", kXMP_PDFFile },
+ { "ps", kXMP_PostScriptFile },
+ { "eps", kXMP_EPSFile },
+
+ { "jpg", kXMP_JPEGFile },
+ { "jpeg", kXMP_JPEGFile },
+ { "jpx", kXMP_JPEG2KFile },
+ { "tif", kXMP_TIFFFile },
+ { "tiff", kXMP_TIFFFile },
+ { "dng", kXMP_TIFFFile }, // DNG files are well behaved TIFF.
+ { "gif", kXMP_GIFFile },
+ { "giff", kXMP_GIFFile },
+ { "png", kXMP_PNGFile },
+
+ { "swf", kXMP_SWFFile },
+ { "flv", kXMP_FLVFile },
+
+ { "aif", kXMP_AIFFFile },
+
+ { "mov", kXMP_MOVFile },
+ { "avi", kXMP_AVIFile },
+ { "cin", kXMP_CINFile },
+ { "wav", kXMP_WAVFile },
+ { "mp3", kXMP_MP3File },
+ { "mp4", kXMP_MPEG4File },
+ { "ses", kXMP_SESFile },
+ { "cel", kXMP_CELFile },
+ { "wma", kXMP_WMAVFile },
+ { "wmv", kXMP_WMAVFile },
+
+ { "mpg", kXMP_MPEGFile },
+ { "mpeg", kXMP_MPEGFile },
+ { "mp2", kXMP_MPEGFile },
+ { "mod", kXMP_MPEGFile },
+ { "m2v", kXMP_MPEGFile },
+ { "mpa", kXMP_MPEGFile },
+ { "mpv", kXMP_MPEGFile },
+ { "m2p", kXMP_MPEGFile },
+ { "m2a", kXMP_MPEGFile },
+ { "m2t", kXMP_MPEGFile },
+ { "mpe", kXMP_MPEGFile },
+ { "vob", kXMP_MPEGFile },
+ { "ms-pvr", kXMP_MPEGFile },
+ { "dvr-ms", kXMP_MPEGFile },
+
+ { "html", kXMP_HTMLFile },
+ { "xml", kXMP_XMLFile },
+ { "txt", kXMP_TextFile },
+ { "text", kXMP_TextFile },
+
+ { "psd", kXMP_PhotoshopFile },
+ { "ai", kXMP_IllustratorFile },
+ { "indd", kXMP_InDesignFile },
+ { "indt", kXMP_InDesignFile },
+ { "aep", kXMP_AEProjectFile },
+ { "aet", kXMP_AEProjTemplateFile },
+ { "ffx", kXMP_AEFilterPresetFile },
+ { "ncor", kXMP_EncoreProjectFile },
+ { "prproj", kXMP_PremiereProjectFile },
+ { "prtl", kXMP_PremiereTitleFile },
+
+ { "", 0 } }; // ! Must be last as a sentinel.
+
+const char * kKnownScannedFiles[] = // Files known to contain XMP but have no smart handling, here or elsewhere.
+ { "gif", // GIF, public format but no smart handler.
+ "ai", // Illustrator, actually a PDF file.
+ "ait", // Illustrator template, actually a PDF file.
+ "svg", // SVG, an XML file.
+ "aet", // After Effects template project file.
+ "ffx", // After Effects filter preset file.
+ "inx", // InDesign interchange, an XML file.
+ "inds", // InDesign snippet, an XML file.
+ "inpk", // InDesign package for GoLive, a text file (not XML).
+ "incd", // InCopy story, an XML file.
+ "inct", // InCopy template, an XML file.
+ "incx", // InCopy interchange, an XML file.
+ "fm", // FrameMaker file, proprietary format.
+ "book", // FrameMaker book, proprietary format.
+ 0 }; // ! Keep a 0 sentinel at the end.
+
+// =================================================================================================
+
+// =================================================================================================
+
+// =================================================================================================
+// LFA implementations for Macintosh
+// =================================
+
+#if XMP_MacBuild
+
+ // ---------------------------------------------------------------------------------------------
+
+ // ! Can't use Apple's 64 bit POSIX functions because frigging MSL has type clashes.
+
+ LFA_FileRef LFA_Open ( const char * fileName, char mode )
+ {
+ XMP_Assert ( (mode == 'r') || (mode == 'w') );
+
+ FSRef fileRef;
+ SInt8 perm = ( (mode == 'r') ? fsRdPerm : fsRdWrPerm );
+ HFSUniStr255 dataForkName;
+ SInt16 refNum;
+
+ OSErr err = FSGetDataForkName ( &dataForkName );
+ if ( err != noErr ) XMP_Throw ( "LFA_Open: FSGetDataForkName failure", kXMPErr_ExternalFailure );
+
+ err = FSPathMakeRef ( (XMP_Uns8*)fileName, &fileRef, 0 );
+ if ( err != noErr ) XMP_Throw ( "LFA_Open: FSPathMakeRef failure", kXMPErr_ExternalFailure );
+
+ err = FSOpenFork ( &fileRef, dataForkName.length, dataForkName.unicode, perm, &refNum );
+ if ( err != noErr ) XMP_Throw ( "LFA_Open: FSOpenFork failure", kXMPErr_ExternalFailure );
+
+ return (LFA_FileRef)refNum;
+
+ } // LFA_Open
+
+ // ---------------------------------------------------------------------------------------------
+
+ LFA_FileRef LFA_Create ( const char * fileName )
+ {
+ // *** Hack: Use fopen to avoid parent/child name separation needed by FSCreateFileUnicode.
+
+ FILE * temp;
+ temp = fopen ( fileName, "r" ); // Make sure the file does not exist.
+ if ( temp != 0 ) {
+ fclose ( temp );
+ XMP_Throw ( "LFA_Create: file already exists", kXMPErr_ExternalFailure );
+ }
+
+ temp = fopen ( fileName, "w" );
+ if ( temp == 0 ) XMP_Throw ( "LFA_Create: fopen failure", kXMPErr_ExternalFailure );
+ fclose ( temp );
+
+ return LFA_Open ( fileName, 'w' );
+
+ } // LFA_Create
+
+ // ---------------------------------------------------------------------------------------------
+
+ void LFA_Delete ( const char * fileName )
+ {
+ int err = remove ( fileName ); // *** Better to use an FS function.
+ if ( err != 0 ) XMP_Throw ( "LFA_Delete: remove failure", kXMPErr_ExternalFailure );
+
+ } // LFA_Delete
+
+ // ---------------------------------------------------------------------------------------------
+
+ void LFA_Rename ( const char * oldName, const char * newName )
+ {
+ int err = rename ( oldName, newName ); // *** Better to use an FS function.
+ if ( err != 0 ) XMP_Throw ( "LFA_Rename: rename failure", kXMPErr_ExternalFailure );
+
+ } // LFA_Rename
+
+ // ---------------------------------------------------------------------------------------------
+
+ LFA_FileRef LFA_OpenRsrc ( const char * fileName, char mode )
+ {
+ XMP_Assert ( (mode == 'r') || (mode == 'w') );
+
+ FSRef fileRef;
+ SInt8 perm = ( (mode == 'r') ? fsRdPerm : fsRdWrPerm );
+ HFSUniStr255 rsrcForkName;
+ SInt16 refNum;
+
+ OSErr err = FSGetResourceForkName ( &rsrcForkName );
+ if ( err != noErr ) XMP_Throw ( "LFA_Open: FSGetResourceForkName failure", kXMPErr_ExternalFailure );
+
+ err = FSPathMakeRef ( (XMP_Uns8*)fileName, &fileRef, 0 );
+ if ( err != noErr ) XMP_Throw ( "LFA_Open: FSPathMakeRef failure", kXMPErr_ExternalFailure );
+
+ err = FSOpenFork ( &fileRef, rsrcForkName.length, rsrcForkName.unicode, perm, &refNum );
+ if ( err != noErr ) XMP_Throw ( "LFA_Open: FSOpenFork failure", kXMPErr_ExternalFailure );
+
+ return (LFA_FileRef)refNum;
+
+ } // LFA_OpenRsrc
+
+ // ---------------------------------------------------------------------------------------------
+
+ void LFA_Close ( LFA_FileRef file )
+ {
+ if ( file == 0 ) return; // Can happen if LFA_Open throws an exception.
+ long refNum = (long)file; // ! Use long to avoid size warnings for SInt16 cast.
+
+ OSErr err = FSCloseFork ( refNum );
+ if ( err != noErr ) XMP_Throw ( "LFA_Close: FSCloseFork failure", kXMPErr_ExternalFailure );
+
+ } // LFA_Close
+
+ // ---------------------------------------------------------------------------------------------
+
+ XMP_Int64 LFA_Seek ( LFA_FileRef file, XMP_Int64 offset, int mode, bool * okPtr )
+ {
+ long refNum = (long)file; // ! Use long to avoid size warnings for SInt16 cast.
+
+ UInt16 posMode;
+ switch ( mode ) {
+ case SEEK_SET :
+ posMode = fsFromStart;
+ break;
+ case SEEK_CUR :
+ posMode = fsFromMark;
+ break;
+ case SEEK_END :
+ posMode = fsFromLEOF;
+ break;
+ default :
+ XMP_Throw ( "Invalid seek mode", kXMPErr_InternalFailure );
+ break;
+ }
+
+ OSErr err;
+ XMP_Int64 newPos;
+
+ err = FSSetForkPosition ( refNum, posMode, offset );
+
+ if ( err == eofErr ) {
+ // FSSetForkPosition does not implicitly grow the file. Grow then seek to the new EOF.
+ err = FSSetForkSize ( refNum, posMode, offset );
+ if ( err == noErr ) err = FSSetForkPosition ( refNum, fsFromLEOF, 0 );
+ }
+
+ if ( err == noErr ) err = FSGetForkPosition ( refNum, &newPos );
+
+ if ( okPtr != 0 ) {
+ *okPtr = (err == noErr);
+ } else {
+ if ( err != noErr ) XMP_Throw ( "LFA_Seek: FSSetForkPosition failure", kXMPErr_ExternalFailure );
+ }
+
+ return newPos;
+
+ } // LFA_Seek
+
+ // ---------------------------------------------------------------------------------------------
+
+ XMP_Int32 LFA_Read ( LFA_FileRef file, void * buffer, XMP_Int32 bytes, bool requireAll )
+ {
+ long refNum = (long)file; // ! Use long to avoid size warnings for SInt16 cast.
+ ByteCount bytesRead;
+
+ OSErr err = FSReadFork ( refNum, fsAtMark, 0, bytes, buffer, &bytesRead );
+ if ( ((err != noErr) && (err != eofErr)) || (requireAll && (bytesRead != (ByteCount)bytes)) ) {
+ // ! FSReadFork returns eofErr for a normal encounter with the end of file.
+ XMP_Throw ( "LFA_Read: FSReadFork failure", kXMPErr_ExternalFailure );
+ }
+
+ return bytesRead;
+
+ } // LFA_Read
+
+ // ---------------------------------------------------------------------------------------------
+
+ void LFA_Write ( LFA_FileRef file, const void * buffer, XMP_Int32 bytes )
+ {
+ long refNum = (long)file; // ! Use long to avoid size warnings for SInt16 cast.
+ ByteCount bytesWritten;
+
+ OSErr err = FSWriteFork ( refNum, fsAtMark, 0, bytes, buffer, &bytesWritten );
+ if ( (err != noErr) | (bytesWritten != (ByteCount)bytes) ) XMP_Throw ( "LFA_Write: FSWriteFork failure", kXMPErr_ExternalFailure );
+
+ } // LFA_Write
+
+ // ---------------------------------------------------------------------------------------------
+
+ void LFA_Flush ( LFA_FileRef file )
+ {
+ long refNum = (long)file; // ! Use long to avoid size warnings for SInt16 cast.
+
+ OSErr err = FSFlushFork ( refNum );
+ if ( err != noErr ) XMP_Throw ( "LFA_Flush: FSFlushFork failure", kXMPErr_ExternalFailure );
+
+ } // LFA_Flush
+
+ // ---------------------------------------------------------------------------------------------
+
+ XMP_Int64 LFA_Measure ( LFA_FileRef file )
+ {
+ long refNum = (long)file; // ! Use long to avoid size warnings for SInt16 cast.
+ XMP_Int64 length;
+
+ OSErr err = FSGetForkSize ( refNum, &length );
+ if ( err != noErr ) XMP_Throw ( "LFA_Measure: FSSetForkSize failure", kXMPErr_ExternalFailure );
+
+ return length;
+
+ } // LFA_Measure
+
+ // ---------------------------------------------------------------------------------------------
+
+ void LFA_Extend ( LFA_FileRef file, XMP_Int64 length )
+ {
+ long refNum = (long)file; // ! Use long to avoid size warnings for SInt16 cast.
+
+ OSErr err = FSSetForkSize ( refNum, fsFromStart, length );
+ if ( err != noErr ) XMP_Throw ( "LFA_Extend: FSSetForkSize failure", kXMPErr_ExternalFailure );
+
+ } // LFA_Extend
+
+ // ---------------------------------------------------------------------------------------------
+
+ void LFA_Truncate ( LFA_FileRef file, XMP_Int64 length )
+ {
+ long refNum = (long)file; // ! Use long to avoid size warnings for SInt16 cast.
+
+ OSErr err = FSSetForkSize ( refNum, fsFromStart, length );
+ if ( err != noErr ) XMP_Throw ( "LFA_Truncate: FSSetForkSize failure", kXMPErr_ExternalFailure );
+
+ } // LFA_Truncate
+
+ // ---------------------------------------------------------------------------------------------
+
+#endif // XMP_MacBuild
+
+// =================================================================================================
+// LFA implementations for Windows
+// ===============================
+
+#if XMP_WinBuild
+
+ // ---------------------------------------------------------------------------------------------
+
+ LFA_FileRef LFA_Open ( const char * fileName, char mode )
+ {
+ XMP_Assert ( (mode == 'r') || (mode == 'w') );
+
+ DWORD access = GENERIC_READ; // Assume read mode.
+ DWORD share = FILE_SHARE_READ;
+
+ if ( mode == 'w' ) {
+ access |= GENERIC_WRITE;
+ share = 0;
+ }
+
+ std::string wideName;
+ const size_t utf8Len = strlen(fileName);
+ const size_t maxLen = 2 * (utf8Len+1);
+
+ wideName.reserve ( maxLen );
+ wideName.assign ( maxLen, ' ' );
+ int wideLen = MultiByteToWideChar ( CP_UTF8, 0, fileName, -1, (LPWSTR)wideName.data(), maxLen );
+ if ( wideLen == 0 ) XMP_Throw ( "LFA_Open: MultiByteToWideChar failure", kXMPErr_ExternalFailure );
+
+ HANDLE fileHandle = CreateFileW ( (LPCWSTR)wideName.data(), access, share, 0, OPEN_EXISTING,
+ (FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS), 0 );
+ if ( fileHandle == INVALID_HANDLE_VALUE ) XMP_Throw ( "LFA_Open: CreateFileW failure", kXMPErr_ExternalFailure );
+
+ return (LFA_FileRef)fileHandle;
+
+ } // LFA_Open
+
+ // ---------------------------------------------------------------------------------------------
+
+ LFA_FileRef LFA_Create ( const char * fileName )
+ {
+ std::string wideName;
+ const size_t utf8Len = strlen(fileName);
+ const size_t maxLen = 2 * (utf8Len+1);
+
+ wideName.reserve ( maxLen );
+ wideName.assign ( maxLen, ' ' );
+ int wideLen = MultiByteToWideChar ( CP_UTF8, 0, fileName, -1, (LPWSTR)wideName.data(), maxLen );
+ if ( wideLen == 0 ) XMP_Throw ( "LFA_Create: MultiByteToWideChar failure", kXMPErr_ExternalFailure );
+
+ HANDLE fileHandle;
+
+ fileHandle = CreateFileW ( (LPCWSTR)wideName.data(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING,
+ (FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS), 0 );
+ if ( fileHandle != INVALID_HANDLE_VALUE ) {
+ CloseHandle ( fileHandle );
+ XMP_Throw ( "LFA_Create: file already exists", kXMPErr_ExternalFailure );
+ }
+
+ fileHandle = CreateFileW ( (LPCWSTR)wideName.data(), (GENERIC_READ | GENERIC_WRITE), 0, 0, CREATE_ALWAYS,
+ (FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS), 0 );
+ if ( fileHandle == INVALID_HANDLE_VALUE ) XMP_Throw ( "LFA_Create: CreateFileW failure", kXMPErr_ExternalFailure );
+
+ return (LFA_FileRef)fileHandle;
+
+ } // LFA_Create
+
+ // ---------------------------------------------------------------------------------------------
+
+ void LFA_Delete ( const char * fileName )
+ {
+ std::string wideName;
+ const size_t utf8Len = strlen(fileName);
+ const size_t maxLen = 2 * (utf8Len+1);
+
+ wideName.reserve ( maxLen );
+ wideName.assign ( maxLen, ' ' );
+ int wideLen = MultiByteToWideChar ( CP_UTF8, 0, fileName, -1, (LPWSTR)wideName.data(), maxLen );
+ if ( wideLen == 0 ) XMP_Throw ( "LFA_Delete: MultiByteToWideChar failure", kXMPErr_ExternalFailure );
+
+ BOOL ok = DeleteFileW ( (LPCWSTR)wideName.data() );
+ if ( ! ok ) XMP_Throw ( "LFA_Delete: DeleteFileW failure", kXMPErr_ExternalFailure );
+
+ } // LFA_Delete
+
+ // ---------------------------------------------------------------------------------------------
+
+ void LFA_Rename ( const char * oldName, const char * newName )
+ {
+ std::string wideOldName, wideNewName;
+ size_t utf8Len = strlen(oldName);
+ if ( utf8Len < strlen(newName) ) utf8Len = strlen(newName);
+ const size_t maxLen = 2 * (utf8Len+1);
+ int wideLen;
+
+ wideOldName.reserve ( maxLen );
+ wideOldName.assign ( maxLen, ' ' );
+ wideLen = MultiByteToWideChar ( CP_UTF8, 0, oldName, -1, (LPWSTR)wideOldName.data(), maxLen );
+ if ( wideLen == 0 ) XMP_Throw ( "LFA_Rename: MultiByteToWideChar failure", kXMPErr_ExternalFailure );
+
+ wideNewName.reserve ( maxLen );
+ wideNewName.assign ( maxLen, ' ' );
+ wideLen = MultiByteToWideChar ( CP_UTF8, 0, newName, -1, (LPWSTR)wideNewName.data(), maxLen );
+ if ( wideLen == 0 ) XMP_Throw ( "LFA_Rename: MultiByteToWideChar failure", kXMPErr_ExternalFailure );
+
+ BOOL ok = MoveFileW ( (LPCWSTR)wideOldName.data(), (LPCWSTR)wideNewName.data() );
+ if ( ! ok ) XMP_Throw ( "LFA_Rename: MoveFileW failure", kXMPErr_ExternalFailure );
+
+ } // LFA_Rename
+
+ // ---------------------------------------------------------------------------------------------
+
+ void LFA_Close ( LFA_FileRef file )
+ {
+ if ( file == 0 ) return; // Can happen if LFA_Open throws an exception.
+ HANDLE fileHandle = (HANDLE)file;
+
+ BOOL ok = CloseHandle ( fileHandle );
+ if ( ! ok ) XMP_Throw ( "LFA_Close: CloseHandle failure", kXMPErr_ExternalFailure );
+
+ } // LFA_Close
+
+ // ---------------------------------------------------------------------------------------------
+
+ XMP_Int64 LFA_Seek ( LFA_FileRef file, XMP_Int64 offset, int mode, bool * okPtr )
+ {
+ HANDLE fileHandle = (HANDLE)file;
+
+ DWORD method;
+ switch ( mode ) {
+ case SEEK_SET :
+ method = FILE_BEGIN;
+ break;
+ case SEEK_CUR :
+ method = FILE_CURRENT;
+ break;
+ case SEEK_END :
+ method = FILE_END;
+ break;
+ default :
+ XMP_Throw ( "Invalid seek mode", kXMPErr_InternalFailure );
+ break;
+ }
+
+ LARGE_INTEGER seekOffset, newPos;
+ seekOffset.QuadPart = offset;
+
+ BOOL ok = SetFilePointerEx ( fileHandle, seekOffset, &newPos, method );
+ if ( okPtr != 0 ) {
+ *okPtr = ok;
+ } else {
+ if ( ! ok ) XMP_Throw ( "LFA_Seek: SetFilePointerEx failure", kXMPErr_ExternalFailure );
+ }
+
+ return newPos.QuadPart;
+
+ } // LFA_Seek
+
+ // ---------------------------------------------------------------------------------------------
+
+ XMP_Int32 LFA_Read ( LFA_FileRef file, void * buffer, XMP_Int32 bytes, bool requireAll )
+ {
+ HANDLE fileHandle = (HANDLE)file;
+ DWORD bytesRead;
+
+ BOOL ok = ReadFile ( fileHandle, buffer, bytes, &bytesRead, 0 );
+ if ( (! ok) || (requireAll && (bytesRead != bytes)) ) XMP_Throw ( "LFA_Read: ReadFile failure", kXMPErr_ExternalFailure );
+
+ return bytesRead;
+
+ } // LFA_Read
+
+ // ---------------------------------------------------------------------------------------------
+
+ void LFA_Write ( LFA_FileRef file, const void * buffer, XMP_Int32 bytes )
+ {
+ HANDLE fileHandle = (HANDLE)file;
+ DWORD bytesWritten;
+
+ BOOL ok = WriteFile ( fileHandle, buffer, bytes, &bytesWritten, 0 );
+ if ( (! ok) || (bytesWritten != bytes) ) XMP_Throw ( "LFA_Write: WriteFile failure", kXMPErr_ExternalFailure );
+
+ } // LFA_Write
+
+ // ---------------------------------------------------------------------------------------------
+
+ void LFA_Flush ( LFA_FileRef file )
+ {
+ HANDLE fileHandle = (HANDLE)file;
+
+ BOOL ok = FlushFileBuffers ( fileHandle );
+ if ( ! ok ) XMP_Throw ( "LFA_Flush: FlushFileBuffers failure", kXMPErr_ExternalFailure );
+
+ } // LFA_Flush
+
+ // ---------------------------------------------------------------------------------------------
+
+ XMP_Int64 LFA_Measure ( LFA_FileRef file )
+ {
+ HANDLE fileHandle = (HANDLE)file;
+ LARGE_INTEGER length;
+
+ BOOL ok = GetFileSizeEx ( fileHandle, &length );
+ if ( ! ok ) XMP_Throw ( "LFA_Measure: GetFileSizeEx failure", kXMPErr_ExternalFailure );
+
+ return length.QuadPart;
+
+ } // LFA_Measure
+
+ // ---------------------------------------------------------------------------------------------
+
+ void LFA_Extend ( LFA_FileRef file, XMP_Int64 length )
+ {
+ HANDLE fileHandle = (HANDLE)file;
+
+ LARGE_INTEGER winLength;
+ winLength.QuadPart = length;
+
+ BOOL ok = SetFilePointerEx ( fileHandle, winLength, 0, FILE_BEGIN );
+ if ( ! ok ) XMP_Throw ( "LFA_Extend: SetFilePointerEx failure", kXMPErr_ExternalFailure );
+ ok = SetEndOfFile ( fileHandle );
+ if ( ! ok ) XMP_Throw ( "LFA_Extend: SetEndOfFile failure", kXMPErr_ExternalFailure );
+
+ } // LFA_Extend
+
+ // ---------------------------------------------------------------------------------------------
+
+ void LFA_Truncate ( LFA_FileRef file, XMP_Int64 length )
+ {
+ HANDLE fileHandle = (HANDLE)file;
+
+ LARGE_INTEGER winLength;
+ winLength.QuadPart = length;
+
+ BOOL ok = SetFilePointerEx ( fileHandle, winLength, 0, FILE_BEGIN );
+ if ( ! ok ) XMP_Throw ( "LFA_Truncate: SetFilePointerEx failure", kXMPErr_ExternalFailure );
+ ok = SetEndOfFile ( fileHandle );
+ if ( ! ok ) XMP_Throw ( "LFA_Truncate: SetEndOfFile failure", kXMPErr_ExternalFailure );
+
+ } // LFA_Truncate
+
+ // ---------------------------------------------------------------------------------------------
+
+#endif // XMP_WinBuild
+
+// =================================================================================================
+// LFA implementations for POSIX
+// =============================
+
+#if XMP_UNIXBuild
+
+ // ---------------------------------------------------------------------------------------------
+
+ // Make sure off_t is 64 bits and signed.
+ static char check_off_t_size [ (sizeof(off_t) == 8) ? 1 : -1 ];
+ // *** No std::numeric_limits? static char check_off_t_sign [ std::numeric_limits<off_t>::is_signed ? -1 : 1 ];
+
+ // ---------------------------------------------------------------------------------------------
+
+ LFA_FileRef LFA_Open ( const char * fileName, char mode )
+ {
+ XMP_Assert ( (mode == 'r') || (mode == 'w') );
+
+ int flags = ((mode == 'r') ? O_RDONLY : O_RDWR); // *** Include O_EXLOCK?
+
+ int descr = open ( fileName, flags, 0 );
+ if ( descr == -1 ) XMP_Throw ( "LFA_Open: open failure", kXMPErr_ExternalFailure );
+
+ return (LFA_FileRef)descr;
+
+ } // LFA_Open
+
+ // ---------------------------------------------------------------------------------------------
+
+ LFA_FileRef LFA_Create ( const char * fileName )
+ {
+ int descr;
+
+ descr = open ( fileName, O_RDONLY, 0 ); // Make sure the file does not exist yet.
+ if ( descr != -1 ) {
+ close ( descr );
+ XMP_Throw ( "LFA_Create: file already exists", kXMPErr_ExternalFailure );
+ }
+
+ descr = open ( fileName, (O_CREAT | O_RDWR), 0 ); // *** Include O_EXCL? O_EXLOCK?
+ if ( descr == -1 ) XMP_Throw ( "LFA_Create: open failure", kXMPErr_ExternalFailure );
+
+ return (LFA_FileRef)descr;
+
+ } // LFA_Create
+
+ // ---------------------------------------------------------------------------------------------
+
+ void LFA_Delete ( const char * fileName )
+ {
+ int err = unlink ( fileName );
+ if ( err != 0 ) XMP_Throw ( "LFA_Delete: unlink failure", kXMPErr_ExternalFailure );
+
+ } // LFA_Delete
+
+ // ---------------------------------------------------------------------------------------------
+
+ void LFA_Rename ( const char * oldName, const char * newName )
+ {
+ int err = rename ( oldName, newName ); // *** POSIX rename clobbers existing destination!
+ if ( err != 0 ) XMP_Throw ( "LFA_Rename: rename failure", kXMPErr_ExternalFailure );
+
+ } // LFA_Rename
+
+ // ---------------------------------------------------------------------------------------------
+
+ void LFA_Close ( LFA_FileRef file )
+ {
+ if ( file == 0 ) return; // Can happen if LFA_Open throws an exception.
+ int descr = (int)file;
+
+ int err = close ( descr );
+ if ( err != 0 ) XMP_Throw ( "LFA_Close: close failure", kXMPErr_ExternalFailure );
+
+ } // LFA_Close
+
+ // ---------------------------------------------------------------------------------------------
+
+ XMP_Int64 LFA_Seek ( LFA_FileRef file, XMP_Int64 offset, int mode, bool * okPtr )
+ {
+ int descr = (int)file;
+
+ off_t newPos = lseek ( descr, offset, mode );
+ if ( okPtr != 0 ) {
+ *okPtr = (newPos != -1);
+ } else {
+ if ( newPos == -1 ) XMP_Throw ( "LFA_Seek: lseek failure", kXMPErr_ExternalFailure );
+ }
+
+ return newPos;
+
+ } // LFA_Seek
+
+ // ---------------------------------------------------------------------------------------------
+
+ XMP_Int32 LFA_Read ( LFA_FileRef file, void * buffer, XMP_Int32 bytes, bool requireAll )
+ {
+ int descr = (int)file;
+
+ ssize_t bytesRead = read ( descr, buffer, bytes );
+ if ( (bytesRead == -1) || (requireAll && (bytesRead != bytes)) ) XMP_Throw ( "LFA_Read: read failure", kXMPErr_ExternalFailure );
+
+ return bytesRead;
+
+ } // LFA_Read
+
+ // ---------------------------------------------------------------------------------------------
+
+ void LFA_Write ( LFA_FileRef file, const void * buffer, XMP_Int32 bytes )
+ {
+ int descr = (int)file;
+
+ ssize_t bytesWritten = write ( descr, buffer, bytes );
+ if ( bytesWritten != bytes ) XMP_Throw ( "LFA_Write: write failure", kXMPErr_ExternalFailure );
+
+ } // LFA_Write
+
+ // ---------------------------------------------------------------------------------------------
+
+ void LFA_Flush ( LFA_FileRef file )
+ {
+ int descr = (int)file;
+
+ int err = fsync ( descr );
+ if ( err != 0 ) XMP_Throw ( "LFA_Flush: fsync failure", kXMPErr_ExternalFailure );
+
+ } // LFA_Flush
+
+ // ---------------------------------------------------------------------------------------------
+
+ XMP_Int64 LFA_Measure ( LFA_FileRef file )
+ {
+ int descr = (int)file;
+
+ off_t currPos = lseek ( descr, 0, SEEK_CUR );
+ off_t length = lseek ( descr, 0, SEEK_END );
+ if ( (currPos == -1) || (length == -1) ) XMP_Throw ( "LFA_Measure: lseek failure", kXMPErr_ExternalFailure );
+ (void) lseek ( descr, currPos, SEEK_SET );
+
+ return length;
+
+ } // LFA_Measure
+
+ // ---------------------------------------------------------------------------------------------
+
+ void LFA_Extend ( LFA_FileRef file, XMP_Int64 length )
+ {
+ int descr = (int)file;
+
+ int err = ftruncate ( descr, length );
+ if ( err != 0 ) XMP_Throw ( "LFA_Extend: ftruncate failure", kXMPErr_ExternalFailure );
+
+ } // LFA_Extend
+
+ // ---------------------------------------------------------------------------------------------
+
+ void LFA_Truncate ( LFA_FileRef file, XMP_Int64 length )
+ {
+ int descr = (int)file;
+
+ int err = ftruncate ( descr, length );
+ if ( err != 0 ) XMP_Throw ( "LFA_Truncate: ftruncate failure", kXMPErr_ExternalFailure );
+
+ } // LFA_Truncate
+
+ // ---------------------------------------------------------------------------------------------
+
+#endif // XMP_UNIXBuild
+
+// =================================================================================================
+
+void LFA_Copy ( LFA_FileRef sourceFile, LFA_FileRef destFile, XMP_Int64 length,
+ XMP_AbortProc abortProc /* = 0 */, void * abortArg /* = 0 */ )
+{
+ enum { kBufferLen = 64*1024 };
+ XMP_Uns8 buffer [kBufferLen];
+
+ const bool checkAbort = (abortProc != 0);
+
+ while ( length > 0 ) {
+ if ( checkAbort && abortProc(abortArg) ) {
+ XMP_Throw ( "LFA_Copy - User abort", kXMPErr_UserAbort );
+ }
+ XMP_Int32 ioCount = kBufferLen;
+ if ( length < kBufferLen ) ioCount = (XMP_Int32)length;
+ LFA_Read ( sourceFile, buffer, ioCount, kLFA_RequireAll );
+ LFA_Write ( destFile, buffer, ioCount );
+ length -= ioCount;
+ }
+
+} // LFA_Copy
+
+// =================================================================================================
+
+static bool CreateNewFile ( const char * newPath, const char * origPath, size_t filePos, bool copyMacRsrc )
+{
+ // Try to create a new file with the same ownership and permissions as some other file.
+ // *** The ownership and permissions are not handled on all platforms.
+
+ #if XMP_MacBuild | XMP_UNIXBuild
+ {
+ FILE * temp = fopen ( newPath, "r" ); // Make sure the file does not exist.
+ if ( temp != 0 ) {
+ fclose ( temp );
+ return false;
+ }
+ }
+ #elif XMP_WinBuild
+ {
+ std::string wideName;
+ const size_t utf8Len = strlen(newPath);
+ const size_t maxLen = 2 * (utf8Len+1);
+ wideName.reserve ( maxLen );
+ wideName.assign ( maxLen, ' ' );
+ int wideLen = MultiByteToWideChar ( CP_UTF8, 0, newPath, -1, (LPWSTR)wideName.data(), maxLen );
+ if ( wideLen == 0 ) return false;
+ HANDLE temp = CreateFileW ( (LPCWSTR)wideName.data(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING,
+ (FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS), 0 );
+ if ( temp != INVALID_HANDLE_VALUE ) {
+ CloseHandle ( temp );
+ return false;
+ }
+ }
+ #endif
+
+ try {
+ LFA_FileRef newFile = LFA_Create ( newPath );
+ LFA_Close ( newFile );
+ } catch ( ... ) {
+ // *** Unfortunate that LFA_Create throws for an existing file.
+ return false;
+ }
+
+ #if XMP_WinBuild
+
+ IgnoreParam(origPath); IgnoreParam(filePos); IgnoreParam(copyMacRsrc);
+
+ // *** Don't handle Windows specific info yet.
+
+ #elif XMP_MacBuild
+
+ IgnoreParam(filePos);
+
+ OSStatus err;
+ FSRef newFSRef, origFSRef; // Copy the "copyable" catalog info, includes the Finder info.
+
+ err = FSPathMakeRef ( (XMP_Uns8*)origPath, &origFSRef, 0 );
+ if ( err != noErr ) XMP_Throw ( "CreateNewFile: FSPathMakeRef failure", kXMPErr_ExternalFailure );
+ err = FSPathMakeRef ( (XMP_Uns8*)newPath, &newFSRef, 0 );
+ if ( err != noErr ) XMP_Throw ( "CreateNewFile: FSPathMakeRef failure", kXMPErr_ExternalFailure );
+
+ FSCatalogInfo catInfo; // *** What about the GetInfo comment? The Finder label?
+ memset ( &catInfo, 0, sizeof(FSCatalogInfo) );
+
+ err = FSGetCatalogInfo ( &origFSRef, kFSCatInfoGettableInfo, &catInfo, 0, 0, 0 );
+ if ( err != noErr ) XMP_Throw ( "CreateNewFile: FSGetCatalogInfo failure", kXMPErr_ExternalFailure );
+ err = FSSetCatalogInfo ( &newFSRef, kFSCatInfoSettableInfo, &catInfo );
+ if ( err != noErr ) XMP_Throw ( "CreateNewFile: FSSetCatalogInfo failure", kXMPErr_ExternalFailure );
+
+ if ( copyMacRsrc ) { // Copy the resource fork as a byte stream.
+ LFA_FileRef origRsrcRef = 0;
+ LFA_FileRef copyRsrcRef = 0;
+ try {
+ origRsrcRef = LFA_OpenRsrc ( origPath, 'r' );
+ XMP_Int64 rsrcSize = LFA_Measure ( origRsrcRef );
+ if ( rsrcSize > 0 ) {
+ copyRsrcRef = LFA_OpenRsrc ( newPath, 'w' );
+ LFA_Copy ( origRsrcRef, copyRsrcRef, rsrcSize, 0, 0 ); // ! Resource fork small enough to not need abort checking.
+ LFA_Close ( copyRsrcRef );
+ }
+ LFA_Close ( origRsrcRef );
+ } catch ( ... ) {
+ if ( origRsrcRef != 0 ) LFA_Close ( origRsrcRef );
+ if ( copyRsrcRef != 0 ) LFA_Close ( copyRsrcRef );
+ throw;
+ }
+ }
+
+
+ #elif XMP_UNIXBuild
+
+ IgnoreParam(filePos); IgnoreParam(copyMacRsrc);
+ // *** Can't use on Mac because of frigging CW POSIX header problems!
+
+ int err, newRef;
+ struct stat origInfo;
+ err = stat ( origPath, &origInfo );
+ if ( err != 0 ) XMP_Throw ( "CreateNewFile: stat failure", kXMPErr_ExternalFailure );
+
+ newRef = open ( newPath, (O_CREAT | O_EXCL | O_RDWR), origInfo.st_mode );
+ if ( newRef != -1 ) {
+ (void) fchown ( newRef, origInfo.st_uid, origInfo.st_gid ); // Tolerate failure.
+ close ( newRef );
+ }
+
+ #endif
+
+ return true;
+
+} // CreateNewFile
+
+// =================================================================================================
+
+void CreateTempFile ( const std::string & origPath, std::string * tempPath, bool copyMacRsrc )
+{
+ // Create an empty temp file next to the source file with the same ownership and permissions.
+ // The temp file has "._nn_" added as a prefix to the file name, where "nn" is a unique
+ // sequence number. The "._" start is important for Bridge, telling it to ignore the file.
+
+ // *** The ownership and permissions are not yet handled.
+
+ #if XMP_WinBuild
+ #define kUseBS true
+ #else
+ #define kUseBS false
+ #endif
+
+ // Break the full path into folder path and file name portions.
+
+ size_t namePos; // The origPath index of the first byte of the file name part.
+
+ for ( namePos = origPath.size(); namePos > 0; --namePos ) {
+ if ( (origPath[namePos] == '/') || (kUseBS && (origPath[namePos] == '\\')) ) {
+ ++namePos;
+ break;
+ }
+ }
+ if ( (origPath[namePos] == '/') || (kUseBS && (origPath[namePos] == '\\')) ) ++namePos;
+ if ( namePos == origPath.size() ) XMP_Throw ( "CreateTempFile: Empty file name part", kXMPErr_InternalFailure );
+
+ std::string folderPath ( origPath, 0, namePos );
+ std::string origName ( origPath, namePos );
+
+ // First try to create a file with "._nn_" added as a file name prefix.
+
+ char tempPrefix[6] = "._nn_";
+
+ tempPath->reserve ( origPath.size() + 5 );
+ tempPath->assign ( origPath, 0, namePos );
+ tempPath->append ( tempPrefix, 5 );
+ tempPath->append ( origName );
+
+ for ( char n1 = '0'; n1 <= '9'; ++n1 ) {
+ (*tempPath)[namePos+2] = n1;
+ for ( char n2 = '0'; n2 <= '9'; ++n2 ) {
+ (*tempPath)[namePos+3] = n2;
+ if ( CreateNewFile ( tempPath->c_str(), origPath.c_str(), namePos, copyMacRsrc ) ) return;
+ }
+ }
+
+ // Now try to create a file with the name "._nn_XMPFilesTemp"
+
+ tempPath->assign ( origPath, 0, namePos );
+ tempPath->append ( tempPrefix, 5 );
+ tempPath->append ( "XMPFilesTemp" );
+
+ for ( char n1 = '0'; n1 <= '9'; ++n1 ) {
+ (*tempPath)[namePos+2] = n1;
+ for ( char n2 = '0'; n2 <= '9'; ++n2 ) {
+ (*tempPath)[namePos+3] = n2;
+ if ( CreateNewFile ( tempPath->c_str(), origPath.c_str(), namePos, copyMacRsrc ) ) return;
+ }
+ }
+
+ XMP_Throw ( "CreateTempFile: Can't find unique name", kXMPErr_InternalFailure );
+
+} // CreateTempFile
+
+// =================================================================================================
+// GetPacketCharForm
+// =================
+//
+// The first character must be U+FEFF or ASCII, typically '<' for an outermost element, initial
+// processing instruction, or XML declaration. The second character can't be U+0000.
+// The possible input sequences are:
+// Cases with U+FEFF
+// EF BB BF -- - UTF-8
+// FE FF -- -- - Big endian UTF-16
+// 00 00 FE FF - Big endian UTF 32
+// FF FE 00 00 - Little endian UTF-32
+// FF FE -- -- - Little endian UTF-16
+// Cases with ASCII
+// nn mm -- -- - UTF-8 -
+// 00 00 00 nn - Big endian UTF-32
+// 00 nn -- -- - Big endian UTF-16
+// nn 00 00 00 - Little endian UTF-32
+// nn 00 -- -- - Little endian UTF-16
+
+XMP_Uns8 GetPacketCharForm ( XMP_StringPtr packetStr, XMP_StringLen packetLen )
+{
+ XMP_Uns8 charForm = kXMP_CharUnknown;
+ XMP_Uns8 * unsBytes = (XMP_Uns8*)packetStr; // ! Make sure comparisons are unsigned.
+
+ if ( packetLen < 4 ) XMP_Throw ( "Can't determine character encoding", kXMPErr_BadXMP );
+
+ if ( unsBytes[0] == 0 ) {
+
+ // These cases are:
+ // 00 nn -- -- - Big endian UTF-16
+ // 00 00 00 nn - Big endian UTF-32
+ // 00 00 FE FF - Big endian UTF 32
+
+ if ( unsBytes[1] != 0 ) {
+ charForm = kXMP_Char16BitBig; // 00 nn
+ } else {
+ if ( (unsBytes[2] == 0) && (unsBytes[3] != 0) ) {
+ charForm = kXMP_Char32BitBig; // 00 00 00 nn
+ } else if ( (unsBytes[2] == 0xFE) && (unsBytes[3] == 0xFF) ) {
+ charForm = kXMP_Char32BitBig; // 00 00 FE FF
+ }
+ }
+
+ } else {
+
+ // These cases are:
+ // FE FF -- -- - Big endian UTF-16, FE isn't valid UTF-8
+ // FF FE 00 00 - Little endian UTF-32, FF isn't valid UTF-8
+ // FF FE -- -- - Little endian UTF-16
+ // nn mm -- -- - UTF-8, includes EF BB BF case
+ // nn 00 00 00 - Little endian UTF-32
+ // nn 00 -- -- - Little endian UTF-16
+
+ if ( unsBytes[0] == 0xFE ) {
+ if ( unsBytes[1] == 0xFF ) charForm = kXMP_Char16BitBig; // FE FF
+ } else if ( unsBytes[0] == 0xFF ) {
+ if ( unsBytes[1] == 0xFE ) {
+ if ( (unsBytes[2] == 0) && (unsBytes[3] == 0) ) {
+ charForm = kXMP_Char32BitLittle; // FF FE 00 00
+ } else {
+ charForm = kXMP_Char16BitLittle; // FF FE
+ }
+ }
+ } else if ( unsBytes[1] != 0 ) {
+ charForm = kXMP_Char8Bit; // nn mm
+ } else {
+ if ( (unsBytes[2] == 0) && (unsBytes[3] == 0) ) {
+ charForm = kXMP_Char32BitLittle; // nn 00 00 00
+ } else {
+ charForm = kXMP_Char16BitLittle; // nn 00
+ }
+ }
+
+ }
+
+ if ( charForm == kXMP_CharUnknown ) XMP_Throw ( "Unknown character encoding", kXMPErr_BadXMP );
+ return charForm;
+
+} // GetPacketCharForm
+
+// =================================================================================================
+// GetPacketRWMode
+// ===============
+
+bool GetPacketRWMode ( XMP_StringPtr packetStr, XMP_StringLen packetLen, size_t charSize )
+{
+ bool isWriteable = false;
+ XMP_StringPtr packetLim = packetStr + packetLen;
+ XMP_StringPtr rwPtr = packetStr + packetLen - 1;
+
+ for ( ; rwPtr >= packetStr; --rwPtr ) if ( *rwPtr == '<' ) break; // Byte at a time, don't know endianness.
+ if ( *rwPtr != '<' ) XMP_Throw ( "Bad packet trailer", kXMPErr_BadXMP );
+
+ for ( ; rwPtr < packetLim; rwPtr += charSize ) if ( *rwPtr == '=' ) break;
+ if ( *rwPtr != '=' ) XMP_Throw ( "Bad packet trailer", kXMPErr_BadXMP );
+
+ rwPtr += (2 * charSize);
+ if ( rwPtr >= packetLim ) XMP_Throw ( "Bad packet trailer", kXMPErr_BadXMP );
+
+ if ( *rwPtr == 'r' ) {
+ isWriteable = false;
+ } else if ( *rwPtr == 'w' ) {
+ isWriteable = true;
+ } else {
+ XMP_Throw ( "Bad packet trailer", kXMPErr_BadXMP );
+ }
+
+ return isWriteable;
+
+} // GetPacketRWMode
+
+// =================================================================================================
+// GetPacketPadSize
+// ================
+
+size_t GetPacketPadSize ( XMP_StringPtr packetStr, XMP_StringLen packetLen )
+{
+ XMP_Int32 padEnd = packetLen - 1; // ! Must be signed.
+ for ( ; padEnd > 0; --padEnd ) if ( packetStr[padEnd] == '<' ) break;
+ if ( padEnd == 0 ) return 0;
+
+ XMP_Int32 padStart = padEnd; // ! Must be signed.
+ for ( ; padStart > 0; --padStart ) if ( packetStr[padStart] == '>' ) break;
+ if ( padStart == 0 ) return 0;
+ ++padStart;
+
+ return (padEnd - padStart);
+
+} // GetPacketPadSize
+
+// =================================================================================================
+// ReadXMPPacket
+// =============
+
+void ReadXMPPacket ( XMPFileHandler * handler )
+{
+ LFA_FileRef fileRef = handler->parent->fileRef;
+ std::string & xmpPacket = handler->xmpPacket;
+ XMP_StringLen packetLen = handler->packetInfo.length;
+
+ if ( packetLen == 0 ) XMP_Throw ( "ReadXMPPacket - No XMP packet", kXMPErr_BadXMP );
+
+ xmpPacket.erase();
+ xmpPacket.reserve ( packetLen );
+ xmpPacket.append ( packetLen, ' ' );
+
+ XMP_StringPtr packetStr = XMP_StringPtr ( xmpPacket.c_str() ); // Don't set until after reserving the space!
+
+ LFA_Seek ( fileRef, handler->packetInfo.offset, SEEK_SET );
+ LFA_Read ( fileRef, (char*)packetStr, packetLen, kLFA_RequireAll );
+
+} // ReadXMPPacket
+
+// =================================================================================================
+// XMPFileHandler::ProcessTNail
+// ============================
+
+void XMPFileHandler::ProcessTNail()
+{
+
+ this->processedTNail = true; // ! Must be overridden by handlers that support thumbnails.
+
+} // XMPFileHandler::ProcessTNail
+
+// =================================================================================================
+// XMPFileHandler::ProcessXMP
+// ==========================
+//
+// This base implementation just parses the XMP. If the derived handler does reconciliation then it
+// must have its own implementation of ProcessXMP.
+
+void XMPFileHandler::ProcessXMP()
+{
+
+ if ( (!this->containsXMP) || this->processedXMP ) return;
+
+ if ( this->handlerFlags & kXMPFiles_CanReconcile ) {
+ XMP_Throw ( "Reconciling file handlers must implement ProcessXMP", kXMPErr_InternalFailure );
+ }
+
+ SXMPUtils::RemoveProperties ( &this->xmpObj, 0, 0, kXMPUtil_DoAllProperties );
+ this->xmpObj.ParseFromBuffer ( this->xmpPacket.c_str(), this->xmpPacket.size() );
+ this->processedXMP = true;
+
+} // XMPFileHandler::ProcessXMP
+
+// =================================================================================================
+
+#if TrackMallocFree
+
+ #undef malloc
+ #undef free
+
+ #define kTrackAddr 0x509DF6
+
+ void* XMPFiles_Malloc ( size_t size )
+ {
+ void* addr = malloc ( size );
+ if ( addr == (void*)kTrackAddr ) {
+ printf ( "XMPFiles_Malloc: allocated %.8X\n", kTrackAddr );
+ }
+ return addr;
+ }
+
+ void XMPFiles_Free ( void* addr )
+ {
+ if ( addr == (void*)kTrackAddr ) {
+ printf ( "XMPFiles_Free: deallocating %.8X\n", kTrackAddr );
+ }
+ free ( addr );
+ }
+
+#endif
+
+// =================================================================================================
diff --git a/source/XMPFiles/XMPFiles_Impl.hpp b/source/XMPFiles/XMPFiles_Impl.hpp
new file mode 100644
index 0000000..0b776d9
--- /dev/null
+++ b/source/XMPFiles/XMPFiles_Impl.hpp
@@ -0,0 +1,517 @@
+#ifndef __XMPFiles_Impl_hpp__
+#define __XMPFiles_Impl_hpp__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2004-2007 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "XMP_Environment.h" // ! Must be the first #include!
+#include "XMP_Const.h"
+#include "XMP_BuildInfo.h"
+#include "EndianUtils.hpp"
+
+#include <string>
+#define TXMP_STRING_TYPE std::string
+#define XMP_INCLUDE_XMPFILES 1
+#include "XMP.hpp"
+
+#include "XMPFiles.hpp"
+
+#include <vector>
+#include <string>
+#include <map>
+
+#include <cassert>
+
+#if XMP_MacBuild
+ #include <Multiprocessing.h>
+#elif XMP_WinBuild
+ #include <Windows.h>
+ #define snprintf _snprintf
+#elif XMP_UNIXBuild
+ #include <pthread.h>
+#endif
+
+// =================================================================================================
+// General global variables and macros
+
+extern long sXMPFilesInitCount;
+
+#ifndef GatherPerformanceData
+ #define GatherPerformanceData 0
+#endif
+
+#if ! GatherPerformanceData
+
+ #define StartPerfCheck(proc,info) /* do nothing */
+ #define EndPerfCheck(proc) /* do nothing */
+
+#else
+
+ #include "PerfUtils.hpp"
+
+ enum {
+ kAPIPerf_OpenFile,
+ kAPIPerf_CloseFile,
+ kAPIPerf_GetXMP,
+ kAPIPerf_GetThumbnail,
+ kAPIPerf_PutXMP,
+ kAPIPerf_CanPutXMP,
+ kAPIPerfProcCount // Last, count of the procs.
+ };
+
+ static const char* kAPIPerfNames[] =
+ { "OpenFile", "CloseFile", "GetXMP", "GetThumbnail", "PutXMP", "CanPutXMP", 0 };
+
+ struct APIPerfItem {
+ XMP_Uns8 whichProc;
+ double elapsedTime;
+ XMPFilesRef xmpFilesRef;
+ std::string extraInfo;
+ APIPerfItem ( XMP_Uns8 proc, double time, XMPFilesRef ref, const char * info )
+ : whichProc(proc), elapsedTime(time), xmpFilesRef(ref), extraInfo(info) {};
+ };
+
+ typedef std::vector<APIPerfItem> APIPerfCollection;
+
+ extern APIPerfCollection* sAPIPerf;
+
+ #define StartPerfCheck(proc,info) \
+ sAPIPerf->push_back ( APIPerfItem ( proc, 0.0, xmpFilesRef, info ) ); \
+ APIPerfItem & thisPerf = sAPIPerf->back(); \
+ PerfUtils::MomentValue startTime, endTime; \
+ try { \
+ startTime = PerfUtils::NoteThisMoment();
+
+ #define EndPerfCheck(proc) \
+ endTime = PerfUtils::NoteThisMoment(); \
+ thisPerf.elapsedTime = PerfUtils::GetElapsedSeconds ( startTime, endTime ); \
+ } catch ( ... ) { \
+ endTime = PerfUtils::NoteThisMoment(); \
+ thisPerf.elapsedTime = PerfUtils::GetElapsedSeconds ( startTime, endTime ); \
+ thisPerf.extraInfo += " ** THROW **"; \
+ throw; \
+ }
+
+#endif
+
+#ifndef TrackMallocFree
+ #define TrackMallocFree 0
+#endif
+
+#if TrackMallocFree
+ #define malloc(size) XMPFiles_Malloc ( size )
+ #define free(addr) XMPFiles_Free ( addr )
+ extern void* XMPFiles_Malloc ( size_t size );
+ extern void XMPFiles_Free ( void* addr );
+#endif
+
+extern XMP_FileFormat voidFileFormat; // Used as sink for unwanted output parameters.
+extern XMP_PacketInfo voidPacketInfo;
+extern void * voidVoidPtr;
+extern XMP_StringPtr voidStringPtr;
+extern XMP_StringLen voidStringLen;
+extern XMP_OptionBits voidOptionBits;
+
+static const XMP_Uns8 * kUTF8_PacketStart = (const XMP_Uns8 *) "<?xpacket begin=";
+static const XMP_Uns8 * kUTF8_PacketID = (const XMP_Uns8 *) "W5M0MpCehiHzreSzNTczkc9d";
+static const size_t kUTF8_PacketHeaderLen = 51; // ! strlen ( "<?xpacket begin='xxx' id='W5M0MpCehiHzreSzNTczkc9d'" )
+
+static const XMP_Uns8 * kUTF8_PacketTrailer = (const XMP_Uns8 *) "<?xpacket end=\"w\"?>";
+static const size_t kUTF8_PacketTrailerLen = 19; // ! strlen ( kUTF8_PacketTrailer )
+
+struct FileExtMapping {
+ XMP_StringPtr ext;
+ XMP_FileFormat format;
+};
+
+extern const FileExtMapping kFileExtMap[];
+extern const char * kKnownScannedFiles[];
+
+#define Uns8Ptr(p) ((XMP_Uns8 *) (p))
+
+#define kTab ((char)0x09)
+#define kLF ((char)0x0A)
+#define kCR ((char)0x0D)
+
+#define IsNewline( ch ) ( ((ch) == kLF) || ((ch) == kCR) )
+#define IsSpaceOrTab( ch ) ( ((ch) == ' ') || ((ch) == kTab) )
+#define IsWhitespace( ch ) ( IsSpaceOrTab ( ch ) || IsNewline ( ch ) )
+
+#define IgnoreParam(p) voidVoidPtr = (void*)&p
+
+// =================================================================================================
+// Support for asserts
+
+#define _MakeStr(p) #p
+#define _NotifyMsg(n,c,f,l) #n " failed: " #c " in " f " at line " _MakeStr(l)
+
+#if ! XMP_DebugBuild
+ #define XMP_Assert(c) ((void) 0)
+#else
+ #define XMP_Assert(c) assert ( c )
+#endif
+
+ #define XMP_Enforce(c) \
+ if ( ! (c) ) { \
+ const char * assert_msg = _NotifyMsg ( XMP_Enforce, (c), __FILE__, __LINE__ ); \
+ XMP_Throw ( assert_msg , kXMPErr_EnforceFailure ); \
+ }
+// =================================================================================================
+// Support for memory leak tracking
+
+#ifndef TrackMallocAndFree
+ #define TrackMallocAndFree 0
+#endif
+
+#if TrackMallocAndFree
+
+ static void* ChattyMalloc ( size_t size )
+ {
+ void* ptr = malloc ( size );
+ fprintf ( stderr, "Malloc %d bytes @ %.8X\n", size, ptr );
+ return ptr;
+ }
+
+ static void ChattyFree ( void* ptr )
+ {
+ fprintf ( stderr, "Free @ %.8X\n", ptr );
+ free ( ptr );
+ }
+
+ #define malloc(s) ChattyMalloc ( s )
+ #define free(p) ChattyFree ( p )
+
+#endif
+
+// =================================================================================================
+// Support for exceptions and thread locking
+
+// *** Local copies of threading and exception macros from XMP_Impl.hpp. XMPFiles needs to use a
+// *** separate thread lock from XMPCore. Eventually this could benefit from being recast into an
+// *** XMPToolkit_Impl that supports separate locks.
+
+typedef std::string XMP_VarString;
+
+#ifndef TraceXMPCalls
+ #define TraceXMPCalls 0
+#endif
+
+#if ! TraceXMPCalls
+
+ #define AnnounceThrow(msg) /* Do nothing. */
+ #define AnnounceCatch(msg) /* Do nothing. */
+
+ #define AnnounceEntry(proc) /* Do nothing. */
+ #define AnnounceNoLock(proc) /* Do nothing. */
+ #define AnnounceExit() /* Do nothing. */
+
+ #define ReportLock() ++sXMPFilesLockCount
+ #define ReportUnlock() --sXMPFilesLockCount
+ #define ReportKeepLock() /* Do nothing. */
+
+#else
+
+ extern FILE * xmpFilesOut;
+
+ #define AnnounceThrow(msg) \
+ fprintf ( xmpFilesOut, "XMP_Throw: %s\n", msg ); fflush ( xmpFilesOut )
+ #define AnnounceCatch(msg) \
+ fprintf ( xmpFilesOut, "Catch in %s: %s\n", procName, msg ); fflush ( xmpFilesOut )
+
+ #define AnnounceEntry(proc) \
+ const char * procName = proc; \
+ fprintf ( xmpFilesOut, "Entering %s\n", procName ); fflush ( xmpFilesOut )
+ #define AnnounceNoLock(proc) \
+ const char * procName = proc; \
+ fprintf ( xmpFilesOut, "Entering %s (no lock)\n", procName ); fflush ( xmpFilesOut )
+ #define AnnounceExit() \
+ fprintf ( xmpFilesOut, "Exiting %s\n", procName ); fflush ( xmpFilesOut )
+
+ #define ReportLock() \
+ ++sXMPFilesLockCount; fprintf ( xmpFilesOut, " Auto lock, count = %d\n", sXMPFilesLockCount ); fflush ( xmpFilesOut )
+ #define ReportUnlock() \
+ --sXMPFilesLockCount; fprintf ( xmpFilesOut, " Auto unlock, count = %d\n", sXMPFilesLockCount ); fflush ( xmpFilesOut )
+ #define ReportKeepLock() \
+ fprintf ( xmpFilesOut, " Keeping lock, count = %d\n", sXMPFilesLockCount ); fflush ( xmpFilesOut )
+
+#endif
+
+#define XMP_Throw(msg,id) { AnnounceThrow ( msg ); throw XMP_Error ( id, msg ); }
+
+// -------------------------------------------------------------------------------------------------
+
+#if XMP_MacBuild
+ typedef MPCriticalRegionID XMP_Mutex;
+#elif XMP_WinBuild
+ typedef CRITICAL_SECTION XMP_Mutex;
+#elif XMP_UNIXBuild
+ typedef pthread_mutex_t XMP_Mutex;
+#endif
+
+extern XMP_Mutex sXMPFilesLock;
+extern int sXMPFilesLockCount; // Keep signed to catch unlock errors.
+extern XMP_VarString * sXMPFilesExceptionMessage;
+
+extern bool XMP_InitMutex ( XMP_Mutex * mutex );
+extern void XMP_TermMutex ( XMP_Mutex & mutex );
+
+extern void XMP_EnterCriticalRegion ( XMP_Mutex & mutex );
+extern void XMP_ExitCriticalRegion ( XMP_Mutex & mutex );
+
+class XMPFiles_AutoMutex {
+public:
+ XMPFiles_AutoMutex() : mutex(&sXMPFilesLock) { XMP_EnterCriticalRegion ( *mutex ); ReportLock(); };
+ ~XMPFiles_AutoMutex() { if ( mutex != 0 ) { ReportUnlock(); XMP_ExitCriticalRegion ( *mutex ); mutex = 0; } };
+ void KeepLock() { ReportKeepLock(); mutex = 0; };
+private:
+ XMP_Mutex * mutex;
+};
+
+// *** Switch to XMPEnterObjectWrapper & XMPEnterStaticWrapper, to allow for per-object locks.
+
+// ! Don't do the initialization check (sXMP_InitCount > 0) for the no-lock case. That macro is used
+// ! by WXMPMeta_Initialize_1.
+
+#define XMP_ENTER_WRAPPER_NO_LOCK(proc) \
+ AnnounceNoLock ( proc ); \
+ XMP_Assert ( (0 <= sXMPFilesLockCount) && (sXMPFilesLockCount <= 1) ); \
+ try { \
+ wResult->errMessage = 0;
+
+#define XMP_ENTER_WRAPPER(proc) \
+ AnnounceEntry ( proc ); \
+ XMP_Assert ( sXMPFilesInitCount > 0 ); \
+ XMP_Assert ( (0 <= sXMPFilesLockCount) && (sXMPFilesLockCount <= 1) ); \
+ try { \
+ XMPFiles_AutoMutex mutex; \
+ wResult->errMessage = 0;
+
+#define XMP_EXIT_WRAPPER \
+ XMP_CATCH_EXCEPTIONS \
+ AnnounceExit();
+
+#define XMP_EXIT_WRAPPER_KEEP_LOCK(keep) \
+ if ( keep ) mutex.KeepLock(); \
+ XMP_CATCH_EXCEPTIONS \
+ AnnounceExit();
+
+#define XMP_EXIT_WRAPPER_NO_THROW \
+ } catch ( ... ) { \
+ AnnounceCatch ( "no-throw catch-all" ); \
+ /* Do nothing. */ \
+ } \
+ AnnounceExit();
+
+#define XMP_CATCH_EXCEPTIONS \
+ } catch ( XMP_Error & xmpErr ) { \
+ wResult->int32Result = xmpErr.GetID(); \
+ wResult->ptrResult = (void*)"XMP"; \
+ wResult->errMessage = xmpErr.GetErrMsg(); \
+ if ( wResult->errMessage == 0 ) wResult->errMessage = ""; \
+ AnnounceCatch ( wResult->errMessage ); \
+ } catch ( std::exception & stdErr ) { \
+ wResult->int32Result = kXMPErr_StdException; \
+ wResult->errMessage = stdErr.what(); \
+ if ( wResult->errMessage == 0 ) wResult->errMessage = ""; \
+ AnnounceCatch ( wResult->errMessage ); \
+ } catch ( ... ) { \
+ wResult->int32Result = kXMPErr_UnknownException; \
+ wResult->errMessage = "Caught unknown exception"; \
+ AnnounceCatch ( wResult->errMessage ); \
+ }
+
+#if XMP_DebugBuild
+ #define RELEASE_NO_THROW /* empty */
+#else
+ #define RELEASE_NO_THROW throw()
+#endif
+
+// =================================================================================================
+// FileHandler declarations
+
+extern void ReadXMPPacket ( XMPFileHandler * handler );
+
+extern XMP_Uns8 GetPacketCharForm ( XMP_StringPtr packetStr, XMP_StringLen packetLen );
+extern size_t GetPacketPadSize ( XMP_StringPtr packetStr, XMP_StringLen packetLen );
+extern bool GetPacketRWMode ( XMP_StringPtr packetStr, XMP_StringLen packetLen, size_t charSize );
+
+class XMPFileHandler { // See XMPFiles.hpp for usage notes.
+public:
+
+ #define DefaultCTorPresets \
+ handlerFlags(0), stdCharForm(kXMP_CharUnknown), \
+ containsTNail(false), processedTNail(false), \
+ containsXMP(false), processedXMP(false), needsUpdate(false)
+
+ XMPFileHandler() : parent(0), DefaultCTorPresets {};
+ XMPFileHandler (XMPFiles * _parent) : parent(_parent), DefaultCTorPresets {};
+
+ virtual ~XMPFileHandler() {}; // ! The specific handler is responsible for tnailInfo.tnailImage.
+
+ virtual void CacheFileData() = 0;
+ virtual void ProcessTNail(); // The default implementation just sets processedTNail to true.
+ virtual void ProcessXMP(); // The default implementation just parses the XMP.
+
+ virtual void UpdateFile ( bool doSafeUpdate ) = 0;
+ virtual void WriteFile ( LFA_FileRef sourceRef, const std::string & sourcePath ) = 0;
+
+ // ! Leave the data members public so common code can see them.
+
+ XMPFiles * parent; // Let's the handler see the file info.
+ XMP_OptionBits handlerFlags; // Capabilities of this handler.
+ XMP_Uns8 stdCharForm; // The standard character form for output.
+
+ bool containsTNail; // True if the file has a native thumbnail.
+ bool processedTNail; // True if the cached thumbnail data has been processed.
+ bool containsXMP; // True if the file has XMP or PutXMP has been called.
+ bool processedXMP; // True if the XMP is parsed and reconciled.
+ bool needsUpdate; // True if the file needs to be updated.
+
+ XMP_PacketInfo packetInfo;
+ std::string xmpPacket;
+ SXMPMeta xmpObj;
+
+ XMP_ThumbnailInfo tnailInfo;
+
+}; // XMPFileHandler
+
+typedef XMPFileHandler * (* XMPFileHandlerCTor) ( XMPFiles * parent );
+
+typedef bool (* CheckFormatProc ) ( XMP_FileFormat format,
+ XMP_StringPtr filePath,
+ LFA_FileRef fileRef,
+ XMPFiles * parent );
+
+// =================================================================================================
+// File I/O support
+
+// *** Change the model of the LFA functions to not throw for "normal" open/create errors.
+// *** Make sure the semantics of open/create/rename are consistent, e.g. about create of existing.
+
+extern LFA_FileRef LFA_Open ( const char * fileName, char openMode ); // Mode is 'r' or 'w'.
+extern LFA_FileRef LFA_Create ( const char * fileName );
+extern void LFA_Delete ( const char * fileName );
+extern void LFA_Rename ( const char * oldName, const char * newName );
+extern void LFA_Close ( LFA_FileRef file );
+extern XMP_Int64 LFA_Seek ( LFA_FileRef file, XMP_Int64 offset, int seekMode, bool * okPtr = 0 );
+extern XMP_Int32 LFA_Read ( LFA_FileRef file, void * buffer, XMP_Int32 bytes, bool requireAll = false );
+extern void LFA_Write ( LFA_FileRef file, const void * buffer, XMP_Int32 bytes );
+extern void LFA_Flush ( LFA_FileRef file );
+extern XMP_Int64 LFA_Measure ( LFA_FileRef file );
+extern void LFA_Extend ( LFA_FileRef file, XMP_Int64 length );
+extern void LFA_Truncate ( LFA_FileRef file, XMP_Int64 length );
+
+#if XMP_MacBuild
+ extern LFA_FileRef LFA_OpenRsrc ( const char * fileName, char openMode ); // Open the Mac resource fork.
+#endif
+
+extern void LFA_Copy ( LFA_FileRef sourceFile, LFA_FileRef destFile, XMP_Int64 length, // Not a primitive.
+ XMP_AbortProc abortProc = 0, void * abortArg = 0 );
+
+extern void CreateTempFile ( const std::string & origPath, std::string * tempPath, bool copyMacRsrc = false );
+enum { kCopyMacRsrc = true };
+
+struct AutoFile { // Provides auto close of files on exit or exception.
+ LFA_FileRef fileRef;
+ AutoFile() : fileRef(0) {};
+ ~AutoFile() { if ( fileRef != 0 ) LFA_Close ( fileRef ); };
+};
+
+enum { kLFA_RequireAll = true }; // Used for requireAll to LFA_Read.
+
+// -------------------------------------------------------------------------------------------------
+
+static inline bool
+CheckBytes ( const void * left, const void * right, size_t length )
+{
+ return (std::memcmp ( left, right, length ) == 0);
+}
+
+// -------------------------------------------------------------------------------------------------
+
+static inline bool
+CheckCString ( const void * left, const void * right )
+{
+ return (std::strcmp ( (char*)left, (char*)right ) == 0);
+}
+
+// -------------------------------------------------------------------------------------------------
+// CheckFileSpace and RefillBuffer
+// -------------------------------
+//
+// There is always a problem in file scanning of managing what you want to check against what is
+// available in a buffer, trying to keep the logic understandable and minimize data movement. The
+// CheckFileSpace and RefillBuffer functions are used here for a standard scanning model.
+//
+// The format scanning routines have an outer, "infinite" loop that looks for file markers. There
+// is a local (on stack) buffer, a pointer to the current position in the buffer, and a pointer for
+// the end of the buffer. The end pointer is just past the end of the buffer, "bufPtr == bufLimit"
+// means you are out of data. The outer loop ends when the necessary markers are found or we reach
+// the end of the file.
+//
+// The filePos is the file offset of the start of the current buffer. This is maintained so that
+// we can tell where the packet is in the file, part of the info returned to the client.
+//
+// At each check CheckFileSpace is used to make sure there is enough data in the buffer for the
+// check to be made. It refills the buffer if necessary, preserving the unprocessed data, setting
+// bufPtr and bufLimit appropriately. If we are too close to the end of the file to make the check
+// a failure status is returned.
+
+enum { kIOBufferSize = 128*1024 };
+
+struct IOBuffer {
+ XMP_Int64 filePos;
+ XMP_Uns8* ptr;
+ XMP_Uns8* limit;
+ size_t len;
+ XMP_Uns8 data [kIOBufferSize];
+ IOBuffer() : filePos(0), ptr(&data[0]), limit(ptr), len(0) {};
+};
+
+static inline void
+FillBuffer ( LFA_FileRef fileRef, XMP_Int64 fileOffset, IOBuffer* ioBuf )
+{
+ ioBuf->filePos = LFA_Seek ( fileRef, fileOffset, SEEK_SET );
+ if ( ioBuf->filePos != fileOffset ) XMP_Throw ( "Seek failure in FillBuffer", kXMPErr_ExternalFailure );
+ ioBuf->len = LFA_Read ( fileRef, &ioBuf->data[0], kIOBufferSize );
+ ioBuf->ptr = &ioBuf->data[0];
+ ioBuf->limit = ioBuf->ptr + ioBuf->len;
+}
+
+static inline void
+MoveToOffset ( LFA_FileRef fileRef, XMP_Int64 fileOffset, IOBuffer* ioBuf )
+{
+ if ( (ioBuf->filePos <= fileOffset) && (fileOffset < (ioBuf->filePos + ioBuf->len)) ) {
+ size_t bufOffset = (size_t)(fileOffset - ioBuf->filePos);
+ ioBuf->ptr = &ioBuf->data[bufOffset];
+ } else {
+ FillBuffer ( fileRef, fileOffset, ioBuf );
+ }
+}
+
+static inline void
+RefillBuffer ( LFA_FileRef fileRef, IOBuffer* ioBuf )
+{
+ ioBuf->filePos += (ioBuf->ptr - &ioBuf->data[0]); // ! Increment before the read.
+ size_t bufTail = ioBuf->limit - ioBuf->ptr; // We'll re-read the tail portion of the buffer.
+ if ( bufTail > 0 ) ioBuf->filePos = LFA_Seek ( fileRef, -((XMP_Int64)bufTail), SEEK_CUR );
+ ioBuf->len = LFA_Read ( fileRef, &ioBuf->data[0], kIOBufferSize );
+ ioBuf->ptr = &ioBuf->data[0];
+ ioBuf->limit = ioBuf->ptr + ioBuf->len;
+}
+
+static inline bool CheckFileSpace ( LFA_FileRef fileRef, IOBuffer* ioBuf, size_t neededLen )
+{
+ if ( size_t(ioBuf->limit - ioBuf->ptr) < size_t(neededLen) ) { // ! Avoid VS.Net compare warnings.
+ RefillBuffer ( fileRef, ioBuf );
+ }
+ return (size_t(ioBuf->limit - ioBuf->ptr) >= size_t(neededLen));
+}
+
+#endif /* __XMPFiles_Impl_hpp__ */
diff --git a/source/common/UnicodeConversions.cpp b/source/common/UnicodeConversions.cpp
new file mode 100644
index 0000000..123c502
--- /dev/null
+++ b/source/common/UnicodeConversions.cpp
@@ -0,0 +1,1665 @@
+// =================================================================================================
+// Copyright 2004-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "XMP_Const.h"
+
+#if UnicodeTestBuild
+ #include <cassert>
+ #include <stdexcept>
+ #define UC_Assert assert
+ #define UC_Throw(m,k) throw std::logic_error ( m )
+#else
+ #define UC_Assert(cond) /* Nothing for now, should be XMP_Assert. */
+ #define UC_Throw(msg,id) throw XMP_Error ( id, msg )
+#endif
+
+#include "UnicodeConversions.hpp"
+
+using namespace std;
+
+// =================================================================================================
+
+// *** Look into using asm inlines, e.g. count-leading bits for multi-byte UTF-8.
+
+CodePoint_to_UTF16_Proc CodePoint_to_UTF16BE = 0;
+CodePoint_to_UTF16_Proc CodePoint_to_UTF16LE = 0;
+
+CodePoint_from_UTF16_Proc CodePoint_from_UTF16BE = 0;
+CodePoint_from_UTF16_Proc CodePoint_from_UTF16LE = 0;
+
+UTF8_to_UTF16_Proc UTF8_to_UTF16BE = 0;
+UTF8_to_UTF16_Proc UTF8_to_UTF16LE = 0;
+UTF8_to_UTF32_Proc UTF8_to_UTF32BE = 0;
+UTF8_to_UTF32_Proc UTF8_to_UTF32LE = 0;
+
+UTF16_to_UTF8_Proc UTF16BE_to_UTF8 = 0;
+UTF16_to_UTF8_Proc UTF16LE_to_UTF8 = 0;
+UTF32_to_UTF8_Proc UTF32BE_to_UTF8 = 0;
+UTF32_to_UTF8_Proc UTF32LE_to_UTF8 = 0;
+
+UTF8_to_UTF16_Proc UTF8_to_UTF16Native = 0;
+UTF8_to_UTF32_Proc UTF8_to_UTF32Native = 0;
+UTF16_to_UTF8_Proc UTF16Native_to_UTF8 = 0;
+UTF32_to_UTF8_Proc UTF32Native_to_UTF8 = 0;
+
+UTF16_to_UTF32_Proc UTF16BE_to_UTF32BE = 0;
+UTF16_to_UTF32_Proc UTF16BE_to_UTF32LE = 0;
+UTF16_to_UTF32_Proc UTF16LE_to_UTF32BE = 0;
+UTF16_to_UTF32_Proc UTF16LE_to_UTF32LE = 0;
+
+UTF32_to_UTF16_Proc UTF32BE_to_UTF16BE = 0;
+UTF32_to_UTF16_Proc UTF32BE_to_UTF16LE = 0;
+UTF32_to_UTF16_Proc UTF32LE_to_UTF16BE = 0;
+UTF32_to_UTF16_Proc UTF32LE_to_UTF16LE = 0;
+
+// -------------------------------------------------------------------------------------------------
+
+static size_t swap32to16Offset = 0; // Offset to "convert" a swapped UTF32 pointer into a swapped UTF16 pointer.
+
+// -------------------------------------------------------------------------------------------------
+
+static void CodePoint_to_UTF16Nat ( const UTF32Unit cpIn, UTF16Unit * utf16Out, const size_t utf16Len, size_t * utf16Written );
+static void CodePoint_to_UTF16Swp ( const UTF32Unit cpIn, UTF16Unit * utf16Out, const size_t utf16Len, size_t * utf16Written );
+
+static void CodePoint_from_UTF16Nat ( const UTF16Unit * utf16In, const size_t utf16Len, UTF32Unit * cpOut, size_t * utf16Read );
+static void CodePoint_from_UTF16Swp ( const UTF16Unit * utf16In, const size_t utf16Len, UTF32Unit * cpOut, size_t * utf16Read );
+
+// -------------------------------------------------------------------------------------------------
+
+static void UTF8_to_UTF16Nat ( const UTF8Unit * utf8In, const size_t utf8Len,
+ UTF16Unit * utf16Out, const size_t utf16Len,
+ size_t * utf8Read, size_t * utf16Written );
+
+static void UTF8_to_UTF16Swp ( const UTF8Unit * utf8In, const size_t utf8Len,
+ UTF16Unit * utf16Out, const size_t utf16Len,
+ size_t * utf8Read, size_t * utf16Written );
+
+static void UTF8_to_UTF32Nat ( const UTF8Unit * utf8In, const size_t utf8Len,
+ UTF32Unit * utf32Out, const size_t utf32Len,
+ size_t * utf8Read, size_t * utf32Written );
+
+static void UTF8_to_UTF32Swp ( const UTF8Unit * utf8In, const size_t utf8Len,
+ UTF32Unit * utf32Out, const size_t utf32Len,
+ size_t * utf8Read, size_t * utf32Written );
+
+// -------------------------------------------------------------------------------------------------
+
+static void UTF16Nat_to_UTF8 ( const UTF16Unit * utf16In, const size_t utf16Len,
+ UTF8Unit * utf8Out, const size_t utf8Len,
+ size_t * utf16Read, size_t * utf8Written );
+
+static void UTF16Swp_to_UTF8 ( const UTF16Unit * utf16In, const size_t utf16Len,
+ UTF8Unit * utf8Out, const size_t utf8Len,
+ size_t * utf16Read, size_t * utf8Written );
+
+static void UTF32Nat_to_UTF8 ( const UTF32Unit * utf32In, const size_t utf32Len,
+ UTF8Unit * utf8Out, const size_t utf8Len,
+ size_t * utf32Read, size_t * utf8Written );
+
+static void UTF32Swp_to_UTF8 ( const UTF32Unit * utf32In, const size_t utf32Len,
+ UTF8Unit * utf8Out, const size_t utf8Len,
+ size_t * utf32Read, size_t * utf8Written );
+
+// -------------------------------------------------------------------------------------------------
+
+static void UTF16Nat_to_UTF32Nat ( const UTF16Unit * utf16In, const size_t utf16Len,
+ UTF32Unit * utf32Out, const size_t utf32Len,
+ size_t * utf16Read, size_t * utf32Written );
+
+static void UTF16Nat_to_UTF32Swp ( const UTF16Unit * utf16In, const size_t utf16Len,
+ UTF32Unit * utf32Out, const size_t utf32Len,
+ size_t * utf16Read, size_t * utf32Written );
+
+static void UTF16Swp_to_UTF32Nat ( const UTF16Unit * utf16In, const size_t utf16Len,
+ UTF32Unit * utf32Out, const size_t utf32Len,
+ size_t * utf16Read, size_t * utf32Written );
+
+static void UTF16Swp_to_UTF32Swp ( const UTF16Unit * utf16In, const size_t utf16Len,
+ UTF32Unit * utf32Out, const size_t utf32Len,
+ size_t * utf16Read, size_t * utf32Written );
+
+// -------------------------------------------------------------------------------------------------
+
+static void UTF32Nat_to_UTF16Nat ( const UTF32Unit * utf32In, const size_t utf32Len,
+ UTF16Unit * utf16Out, const size_t utf16Len,
+ size_t * utf32Read, size_t * utf16Written );
+
+static void UTF32Nat_to_UTF16Swp ( const UTF32Unit * utf32In, const size_t utf32Len,
+ UTF16Unit * utf16Out, const size_t utf16Len,
+ size_t * utf32Read, size_t * utf16Written );
+
+static void UTF32Swp_to_UTF16Nat ( const UTF32Unit * utf32In, const size_t utf32Len,
+ UTF16Unit * utf16Out, const size_t utf16Len,
+ size_t * utf32Read, size_t * utf16Written );
+
+static void UTF32Swp_to_UTF16Swp ( const UTF32Unit * utf32In, const size_t utf32Len,
+ UTF16Unit * utf16Out, const size_t utf16Len,
+ size_t * utf32Read, size_t * utf16Written );
+
+// =================================================================================================
+
+void InitializeUnicodeConversions()
+{
+ UC_Assert ( (sizeof(UTF8Unit) == 1) && (sizeof(UTF16Unit) == 2) && (sizeof(UTF32Unit) == 4) );
+
+ UTF16Unit u16 = 0x00FF;
+ bool bigEndian = (*((UTF8Unit*)&u16) == 0);
+
+ UTF8_to_UTF16Native = UTF8_to_UTF16Nat;
+ UTF8_to_UTF32Native = UTF8_to_UTF32Nat;
+ UTF16Native_to_UTF8 = UTF16Nat_to_UTF8;
+ UTF32Native_to_UTF8 = UTF32Nat_to_UTF8;
+
+ if ( bigEndian ) {
+
+ swap32to16Offset = 0;
+
+ CodePoint_to_UTF16BE = CodePoint_to_UTF16Nat;
+ CodePoint_to_UTF16LE = CodePoint_to_UTF16Swp;
+
+ CodePoint_from_UTF16BE = CodePoint_from_UTF16Nat;
+ CodePoint_from_UTF16LE = CodePoint_from_UTF16Swp;
+
+ UTF8_to_UTF16BE = UTF8_to_UTF16Nat;
+ UTF8_to_UTF16LE = UTF8_to_UTF16Swp;
+ UTF8_to_UTF32BE = UTF8_to_UTF32Nat;
+ UTF8_to_UTF32LE = UTF8_to_UTF32Swp;
+
+ UTF16BE_to_UTF8 = UTF16Nat_to_UTF8;
+ UTF16LE_to_UTF8 = UTF16Swp_to_UTF8;
+ UTF32BE_to_UTF8 = UTF32Nat_to_UTF8;
+ UTF32LE_to_UTF8 = UTF32Swp_to_UTF8;
+
+ UTF16BE_to_UTF32BE = UTF16Nat_to_UTF32Nat;
+ UTF16BE_to_UTF32LE = UTF16Nat_to_UTF32Swp;
+ UTF16LE_to_UTF32BE = UTF16Swp_to_UTF32Nat;
+ UTF16LE_to_UTF32LE = UTF16Swp_to_UTF32Swp;
+
+ UTF32BE_to_UTF16BE = UTF32Nat_to_UTF16Nat;
+ UTF32BE_to_UTF16LE = UTF32Nat_to_UTF16Swp;
+ UTF32LE_to_UTF16BE = UTF32Swp_to_UTF16Nat;
+ UTF32LE_to_UTF16LE = UTF32Swp_to_UTF16Swp;
+
+ } else {
+
+ swap32to16Offset = 1; // ! Offset in UTF16 units!
+
+ CodePoint_to_UTF16BE = CodePoint_to_UTF16Swp;
+ CodePoint_to_UTF16LE = CodePoint_to_UTF16Nat;
+
+ CodePoint_from_UTF16BE = CodePoint_from_UTF16Swp;
+ CodePoint_from_UTF16LE = CodePoint_from_UTF16Nat;
+
+ UTF8_to_UTF16BE = UTF8_to_UTF16Swp;
+ UTF8_to_UTF16LE = UTF8_to_UTF16Nat;
+ UTF8_to_UTF32BE = UTF8_to_UTF32Swp;
+ UTF8_to_UTF32LE = UTF8_to_UTF32Nat;
+
+ UTF16BE_to_UTF8 = UTF16Swp_to_UTF8;
+ UTF16LE_to_UTF8 = UTF16Nat_to_UTF8;
+ UTF32BE_to_UTF8 = UTF32Swp_to_UTF8;
+ UTF32LE_to_UTF8 = UTF32Nat_to_UTF8;
+
+ UTF16BE_to_UTF32BE = UTF16Swp_to_UTF32Swp;
+ UTF16BE_to_UTF32LE = UTF16Swp_to_UTF32Nat;
+ UTF16LE_to_UTF32BE = UTF16Nat_to_UTF32Swp;
+ UTF16LE_to_UTF32LE = UTF16Nat_to_UTF32Nat;
+
+ UTF32BE_to_UTF16BE = UTF32Swp_to_UTF16Swp;
+ UTF32BE_to_UTF16LE = UTF32Swp_to_UTF16Nat;
+ UTF32LE_to_UTF16BE = UTF32Nat_to_UTF16Swp;
+ UTF32LE_to_UTF16LE = UTF32Nat_to_UTF16Nat;
+
+ }
+
+} // InitializeUnicodeConversions
+
+// =================================================================================================
+
+#if XMP_MacBuild && __MWERKS__
+
+ #define UTF16InSwap(inPtr) UTF16Unit ( __lhbrx ( (void*)(inPtr), 0 ) )
+ #define UTF32InSwap(inPtr) UTF32Unit ( __lwbrx ( (void*)(inPtr), 0 ) )
+
+ #define UTF16OutSwap(outPtr,value) __sthbrx ( value, (void*)(outPtr), 0 )
+ #define UTF32OutSwap(outPtr,value) __stwbrx ( value, (void*)(outPtr), 0 )
+
+#else
+
+ static inline UTF16Unit UTF16InSwap ( const UTF16Unit * inPtr )
+ {
+ UTF16Unit inUnit = *inPtr;
+ return (inUnit << 8) | (inUnit >> 8);
+ }
+
+ static inline UTF32Unit UTF32InSwap ( const UTF32Unit * inPtr )
+ {
+ UTF32Unit inUnit = *inPtr;
+ return (inUnit << 24) | ((inUnit << 8) & 0x00FF0000) | ((inUnit >> 8) & 0x0000FF00) | (inUnit >> 24);
+ }
+
+ static inline void UTF16OutSwap ( UTF16Unit * outPtr, const UTF16Unit value )
+ {
+ UTF16Unit outUnit = (value << 8) | (value >> 8);
+ *outPtr = outUnit;
+ }
+
+ static inline void UTF32OutSwap ( UTF32Unit * outPtr, const UTF32Unit value )
+ {
+ UTF32Unit outUnit = (value << 24) | ((value << 8) & 0x00FF0000) | ((value >> 8) & 0x0000FF00) | (value >> 24);
+ *outPtr = outUnit;
+ }
+
+#endif
+
+// =================================================================================================
+
+void SwapUTF16 ( const UTF16Unit * utf16In, UTF16Unit * utf16Out, const size_t utf16Len )
+{
+ for ( size_t i = 0; i < utf16Len; ++i ) utf16Out[i] = UTF16InSwap(utf16In+i);
+}
+
+void SwapUTF32 ( const UTF32Unit * utf32In, UTF32Unit * utf32Out, const size_t utf32Len ) {
+ for ( size_t i = 0; i < utf32Len; ++i ) utf32Out[i] = UTF32InSwap(utf32In+i);
+}
+
+// =================================================================================================
+
+extern void ToUTF16 ( const UTF8Unit * utf8In, size_t utf8Len, std::string * utf16Str, bool bigEndian )
+{
+ UTF8_to_UTF16_Proc Converter = UTF8_to_UTF16LE;
+ if ( bigEndian ) Converter = UTF8_to_UTF16BE;
+
+ enum { kBufferSize = 8*1024 };
+ UTF16Unit u16Buffer[kBufferSize]; // 16K bytes
+ size_t readCount, writeCount;
+
+ utf16Str->erase();
+ utf16Str->reserve ( 2*utf8Len ); // As good a guess as any.
+
+ while ( utf8Len > 0 ) {
+ Converter ( utf8In, utf8Len, u16Buffer, kBufferSize, &readCount, &writeCount );
+ if ( writeCount == 0 ) UC_Throw ( "Incomplete Unicode at end of string", kXMPErr_BadXML );
+ utf16Str->append ( (const char *)u16Buffer, writeCount*2 );
+ utf8In += readCount;
+ utf8Len -= readCount;
+ }
+
+} // ToUTF16
+
+// =================================================================================================
+
+extern void ToUTF16Native ( const UTF8Unit * utf8In, size_t utf8Len, std::string * utf16Str )
+{
+ enum { kBufferSize = 8*1024 };
+ UTF16Unit u16Buffer[kBufferSize]; // 16K bytes
+ size_t readCount, writeCount;
+
+ utf16Str->erase();
+ utf16Str->reserve ( 2*utf8Len ); // As good a guess as any.
+
+ while ( utf8Len > 0 ) {
+ UTF8_to_UTF16Nat ( utf8In, utf8Len, u16Buffer, kBufferSize, &readCount, &writeCount );
+ if ( writeCount == 0 ) UC_Throw ( "Incomplete Unicode at end of string", kXMPErr_BadXML );
+ utf16Str->append ( (const char *)u16Buffer, writeCount*2 );
+ utf8In += readCount;
+ utf8Len -= readCount;
+ }
+
+} // ToUTF16Native
+
+// =================================================================================================
+
+extern void ToUTF32 ( const UTF8Unit * utf8In, size_t utf8Len, std::string * utf32Str, bool bigEndian )
+{
+ UTF8_to_UTF32_Proc Converter = UTF8_to_UTF32LE;
+ if ( bigEndian ) Converter = UTF8_to_UTF32BE;
+
+ enum { kBufferSize = 4*1024 };
+ UTF32Unit u32Buffer[kBufferSize]; // 16K bytes
+ size_t readCount, writeCount;
+
+ utf32Str->erase();
+ utf32Str->reserve ( 4*utf8Len ); // As good a guess as any.
+
+ while ( utf8Len > 0 ) {
+ Converter ( utf8In, utf8Len, u32Buffer, kBufferSize, &readCount, &writeCount );
+ if ( writeCount == 0 ) UC_Throw ( "Incomplete Unicode at end of string", kXMPErr_BadXML );
+ utf32Str->append ( (const char *)u32Buffer, writeCount*4 );
+ utf8In += readCount;
+ utf8Len -= readCount;
+ }
+
+} // ToUTF32
+
+// =================================================================================================
+
+extern void ToUTF32Native ( const UTF8Unit * utf8In, size_t utf8Len, std::string * utf32Str )
+{
+ enum { kBufferSize = 4*1024 };
+ UTF32Unit u32Buffer[kBufferSize]; // 16K bytes
+ size_t readCount, writeCount;
+
+ utf32Str->erase();
+ utf32Str->reserve ( 4*utf8Len ); // As good a guess as any.
+
+ while ( utf8Len > 0 ) {
+ UTF8_to_UTF32Nat ( utf8In, utf8Len, u32Buffer, kBufferSize, &readCount, &writeCount );
+ if ( writeCount == 0 ) UC_Throw ( "Incomplete Unicode at end of string", kXMPErr_BadXML );
+ utf32Str->append ( (const char *)u32Buffer, writeCount*4 );
+ utf8In += readCount;
+ utf8Len -= readCount;
+ }
+
+} // ToUTF32Native
+
+// =================================================================================================
+
+extern void FromUTF16 ( const UTF16Unit * utf16In, size_t utf16Len, std::string * utf8Str, bool bigEndian )
+{
+ UTF16_to_UTF8_Proc Converter = UTF16LE_to_UTF8;
+ if ( bigEndian ) Converter = UTF16BE_to_UTF8;
+
+ enum { kBufferSize = 16*1024 };
+ UTF8Unit u8Buffer[kBufferSize];
+ size_t readCount, writeCount;
+
+ utf8Str->erase();
+ utf8Str->reserve ( 2*utf16Len ); // As good a guess as any.
+
+ while ( utf16Len > 0 ) {
+ Converter ( utf16In, utf16Len, u8Buffer, kBufferSize, &readCount, &writeCount );
+ if ( writeCount == 0 ) UC_Throw ( "Incomplete Unicode at end of string", kXMPErr_BadXML );
+ utf8Str->append ( (const char *)u8Buffer, writeCount );
+ utf16In += readCount;
+ utf16Len -= readCount;
+ }
+
+} // FromUTF16
+
+// =================================================================================================
+
+extern void FromUTF16Native ( const UTF16Unit * utf16In, size_t utf16Len, std::string * utf8Str )
+{
+ enum { kBufferSize = 16*1024 };
+ UTF8Unit u8Buffer[kBufferSize];
+ size_t readCount, writeCount;
+
+ utf8Str->erase();
+ utf8Str->reserve ( 2*utf16Len ); // As good a guess as any.
+
+ while ( utf16Len > 0 ) {
+ UTF16Nat_to_UTF8 ( utf16In, utf16Len, u8Buffer, kBufferSize, &readCount, &writeCount );
+ if ( writeCount == 0 ) UC_Throw ( "Incomplete Unicode at end of string", kXMPErr_BadXML );
+ utf8Str->append ( (const char *)u8Buffer, writeCount );
+ utf16In += readCount;
+ utf16Len -= readCount;
+ }
+
+} // FromUTF16Native
+
+// =================================================================================================
+
+extern void FromUTF32 ( const UTF32Unit * utf32In, size_t utf32Len, std::string * utf8Str, bool bigEndian )
+{
+ UTF32_to_UTF8_Proc Converter = UTF32LE_to_UTF8;
+ if ( bigEndian ) Converter = UTF32BE_to_UTF8;
+
+ enum { kBufferSize = 16*1024 };
+ UTF8Unit u8Buffer[kBufferSize];
+ size_t readCount, writeCount;
+
+ utf8Str->erase();
+ utf8Str->reserve ( 2*utf32Len ); // As good a guess as any.
+
+ while ( utf32Len > 0 ) {
+ Converter ( utf32In, utf32Len, u8Buffer, kBufferSize, &readCount, &writeCount );
+ if ( writeCount == 0 ) UC_Throw ( "Incomplete Unicode at end of string", kXMPErr_BadXML );
+ utf8Str->append ( (const char *)u8Buffer, writeCount );
+ utf32In += readCount;
+ utf32Len -= readCount;
+ }
+
+} // FromUTF32
+
+// =================================================================================================
+
+extern void FromUTF32Native ( const UTF32Unit * utf32In, size_t utf32Len, std::string * utf8Str )
+{
+ enum { kBufferSize = 16*1024 };
+ UTF8Unit u8Buffer[kBufferSize];
+ size_t readCount, writeCount;
+
+ utf8Str->erase();
+ utf8Str->reserve ( 2*utf32Len ); // As good a guess as any.
+
+ while ( utf32Len > 0 ) {
+ UTF32Nat_to_UTF8 ( utf32In, utf32Len, u8Buffer, kBufferSize, &readCount, &writeCount );
+ if ( writeCount == 0 ) UC_Throw ( "Incomplete Unicode at end of string", kXMPErr_BadXML );
+ utf8Str->append ( (const char *)u8Buffer, writeCount );
+ utf32In += readCount;
+ utf32Len -= readCount;
+ }
+
+} // FromUTF32Native
+
+// =================================================================================================
+
+static void CodePoint_to_UTF8_Multi ( const UTF32Unit cpIn, UTF8Unit * utf8Out, const size_t utf8Len, size_t * utf8Written )
+{
+ size_t unitCount = 0;
+
+ if ( cpIn > 0x10FFFF ) UC_Throw ( "Bad UTF-32 - out of range", kXMPErr_BadParam );
+ if ( (0xD800 <= cpIn) && (cpIn <= 0xDFFF) ) UC_Throw ( "Bad UTF-32 - surrogate code point", kXMPErr_BadParam );
+
+ // Compute the number of bytes using 6 data bits each. Then see if the highest order bits will
+ // fit into the leading byte. Write the UTF-8 sequence if there is enough room.
+
+ UTF32Unit temp, mask;
+ size_t bytesNeeded = 0;
+ for ( temp = cpIn; temp != 0; temp = temp >> 6 ) ++bytesNeeded;
+
+ temp = cpIn >> ((bytesNeeded-1)*6); // The highest order data bits.
+ mask = (0x80 >> bytesNeeded) - 1; // Available data bits in the leading byte.
+ if ( temp > mask ) ++bytesNeeded;
+
+ if ( bytesNeeded > utf8Len ) goto Done; // Not enough room for the output.
+ unitCount = bytesNeeded;
+
+ temp = cpIn;
+ for ( --bytesNeeded; bytesNeeded > 0; --bytesNeeded ) {
+ utf8Out[bytesNeeded] = 0x80 | UTF8Unit ( temp & 0x3F );
+ temp = temp >> 6;
+ }
+
+ mask = ~((1 << (8-unitCount)) - 1);
+ utf8Out[0] = UTF8Unit ( mask | temp );
+
+Done:
+ *utf8Written = unitCount;
+ return;
+
+} // CodePoint_to_UTF8_Multi
+
+// =================================================================================================
+
+void CodePoint_to_UTF8 ( const UTF32Unit cpIn, UTF8Unit * utf8Out, const size_t utf8Len, size_t * utf8Written )
+{
+ size_t unitCount = 0;
+
+ UC_Assert ( (utf8Out != 0) && (utf8Written != 0) );
+ if ( utf8Len == 0 ) goto Done;
+ if ( cpIn > 0x7F ) goto MultiByte; // ! Force linear execution path for ASCII.
+
+ if ( utf8Len == 0 ) goto Done;
+ unitCount = 1;
+ *utf8Out = UTF8Unit(cpIn);
+
+Done:
+ *utf8Written = unitCount;
+ return;
+
+MultiByte:
+ CodePoint_to_UTF8_Multi( cpIn, utf8Out, utf8Len, utf8Written );
+ return;
+
+} // CodePoint_to_UTF8
+
+// =================================================================================================
+
+static void CodePoint_from_UTF8_Multi ( const UTF8Unit * utf8In, const size_t utf8Len, UTF32Unit * cpOut, size_t * utf8Read )
+{
+ UTF8Unit inUnit = *utf8In;
+ size_t unitCount = 0;
+ UTF32Unit cp; // ! Avoid gcc complaints about declarations after goto's.
+ const UTF8Unit * utf8Pos;
+
+ // -------------------------------------------------------------------------------------
+ // We've got a multibyte UTF-8 character. The first byte has the number of bytes and the
+ // highest order data bits. The other bytes each add 6 more data bits.
+
+ #if 0 // This might be a more effcient way to count the bytes.
+ static XMP_Uns8 kByteCounts[16] = { 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 2, 2, 3, 4 };
+ size_t bytesNeeded = kByteCounts [ inUnit >> 4 ];
+ if ( (bytesNeeded < 2) || ((bytesNeeded == 4) && ((inUnit & 0x08) != 0)) ) {
+ UC_Throw ( "Invalid UTF-8 sequence length", kXMPErr_BadParam );
+ }
+ #endif
+
+ size_t bytesNeeded = 0; // Count the leading 1 bits in the first byte.
+ for ( UTF8Unit temp = inUnit; temp > 0x7F; temp = temp << 1 ) ++bytesNeeded;
+ // *** Consider CPU-specific assembly inline, e.g. cntlzw on PowerPC.
+
+ if ( (bytesNeeded < 2) || (bytesNeeded > 4) ) UC_Throw ( "Invalid UTF-8 sequence length", kXMPErr_BadParam );
+ if ( bytesNeeded > utf8Len ) goto Done; // Not enough input in this buffer.
+ unitCount = bytesNeeded;
+
+ cp = inUnit & ((1 << (7-unitCount)) - 1); // Isolate the initial data bits in the bottom of cp.
+
+ utf8Pos = utf8In + 1; // We've absorbed the first byte.
+ for ( --bytesNeeded; bytesNeeded > 0; --bytesNeeded, ++utf8Pos ) {
+ inUnit = *utf8Pos;
+ if ( (inUnit & UTF8Unit(0xC0)) != UTF8Unit(0x80) ) UC_Throw ( "Invalid UTF-8 data byte", kXMPErr_BadParam );
+ cp = (cp << 6) | (inUnit & 0x3F);
+ }
+
+ if ( cp >= 0xD800 ) { // Skip the next comparisons most of the time.
+ if ( (0xD800 <= cp) && (cp <= 0xDFFF) ) UC_Throw ( "Bad UTF-8 - surrogate code point", kXMPErr_BadParam );
+ if ( cp > 0x10FFFF ) UC_Throw ( "Bad UTF-8 - out of range", kXMPErr_BadParam );
+ }
+
+ *cpOut = cp; // ! Don't put after Done, don't write if no input.
+
+Done:
+ *utf8Read = unitCount;
+ return;
+
+} // CodePoint_from_UTF8_Multi
+
+// =================================================================================================
+
+void CodePoint_from_UTF8 ( const UTF8Unit * utf8In, const size_t utf8Len, UTF32Unit * cpOut, size_t * utf8Read )
+{
+ UTF8Unit inUnit; // ! Don't read until we know there is input.
+ size_t unitCount = 0;
+
+ UC_Assert ( (utf8In != 0) && (cpOut != 0) && (utf8Read != 0) );
+ if ( utf8Len == 0 ) goto Done;
+ inUnit = *utf8In;
+ if ( inUnit >= 0x80 ) goto MultiByte; // ! Force linear execution path for ASCII.
+
+ unitCount = 1;
+ *cpOut = inUnit; // ! Don't put after Done, don't write if no input.
+
+Done:
+ *utf8Read = unitCount;
+ return;
+
+MultiByte:
+ CodePoint_from_UTF8_Multi ( utf8In, utf8Len, cpOut, utf8Read );
+ return;
+
+} // CodePoint_from_UTF8
+
+// =================================================================================================
+
+static void CodePoint_to_UTF16Nat_Surrogate ( const UTF32Unit cpIn, UTF16Unit * utf16Out, const size_t utf16Len, size_t * utf16Written )
+{
+ size_t unitCount = 0;
+ UTF32Unit temp; // ! Avoid gcc complaints about declarations after goto's.
+
+ if ( cpIn > 0x10FFFF ) UC_Throw ( "Bad UTF-32 - out of range", kXMPErr_BadParam );
+ if ( utf16Len < 2 ) goto Done; // Not enough room for the output.
+
+ unitCount = 2;
+ temp = cpIn - 0x10000;
+ utf16Out[0] = 0xD800 | UTF16Unit ( temp >> 10 );
+ utf16Out[1] = 0xDC00 | UTF16Unit ( temp & 0x3FF );
+
+Done:
+ *utf16Written = unitCount;
+ return;
+
+} // CodePoint_to_UTF16Nat_Surrogate
+
+// =================================================================================================
+
+static void CodePoint_to_UTF16Nat ( const UTF32Unit cpIn, UTF16Unit * utf16Out, const size_t utf16Len, size_t * utf16Written )
+{
+ size_t unitCount = 0;
+
+ UC_Assert ( (utf16Out != 0) && (utf16Written != 0) );
+ if ( utf16Len == 0 ) goto Done;
+ if ( cpIn >= 0xD800 ) goto CheckSurrogate; // ! Force linear execution path for the BMP.
+
+InBMP:
+ unitCount = 1;
+ *utf16Out = UTF16Unit(cpIn);
+
+Done:
+ *utf16Written = unitCount;
+ return;
+
+CheckSurrogate:
+ if ( cpIn > 0xFFFF ) goto SurrogatePair;
+ if ( cpIn > 0xDFFF ) goto InBMP;
+ UC_Throw ( "Bad UTF-32 - surrogate code point", kXMPErr_BadParam );
+
+SurrogatePair:
+ CodePoint_to_UTF16Nat_Surrogate ( cpIn, utf16Out, utf16Len, utf16Written );
+ return;
+
+} // CodePoint_to_UTF16Nat
+
+// =================================================================================================
+
+static void CodePoint_from_UTF16Nat_Surrogate ( const UTF16Unit * utf16In, const size_t utf16Len, UTF32Unit * cpOut, size_t * utf16Read )
+{
+ UTF16Unit hiUnit = *utf16In;
+ size_t unitCount = 0;
+ UTF16Unit loUnit; // ! Avoid gcc complaints about declarations after goto's.
+ UTF32Unit cp;
+
+ // ----------------------------------
+ // We've got a UTF-16 surrogate pair.
+
+ if ( hiUnit > 0xDBFF ) UC_Throw ( "Bad UTF-16 - leading low surrogate", kXMPErr_BadParam );
+ if ( utf16Len < 2 ) goto Done; // Not enough input in this buffer.
+
+ loUnit = *(utf16In+1);
+ if ( (loUnit < 0xDC00) || (0xDFFF < loUnit) ) UC_Throw ( "Bad UTF-16 - missing low surrogate", kXMPErr_BadParam );
+
+ unitCount = 2;
+ cp = (((hiUnit & 0x3FF) << 10) | (loUnit & 0x3FF)) + 0x10000;
+
+ *cpOut = cp; // ! Don't put after Done, don't write if no input.
+
+Done:
+ *utf16Read = unitCount;
+ return;
+
+} // CodePoint_from_UTF16Nat_Surrogate
+
+// =================================================================================================
+
+static void CodePoint_from_UTF16Nat ( const UTF16Unit * utf16In, const size_t utf16Len, UTF32Unit * cpOut, size_t * utf16Read )
+{
+ UTF16Unit inUnit; // ! Don't read until we know there is input.
+ size_t unitCount = 0;
+
+ UC_Assert ( (utf16In != 0) && (cpOut != 0) && (utf16Read != 0) );
+ if ( utf16Len == 0 ) goto Done;
+ inUnit = *utf16In;
+ if ( (0xD800 <= inUnit) && (inUnit <= 0xDFFF) ) goto SurrogatePair; // ! Force linear execution path for the BMP.
+
+ unitCount = 1;
+ *cpOut = inUnit; // ! Don't put after Done, don't write if no input.
+
+Done:
+ *utf16Read = unitCount;
+ return;
+
+SurrogatePair:
+ CodePoint_from_UTF16Nat_Surrogate ( utf16In, utf16Len, cpOut, utf16Read );
+ return;
+
+} // CodePoint_from_UTF16Nat
+
+// =================================================================================================
+
+static void UTF8_to_UTF16Nat ( const UTF8Unit * utf8In, const size_t utf8Len,
+ UTF16Unit * utf16Out, const size_t utf16Len,
+ size_t * utf8Read, size_t * utf16Written )
+{
+ const UTF8Unit * utf8Pos = utf8In;
+ UTF16Unit * utf16Pos = utf16Out;
+
+ size_t utf8Left = utf8Len;
+ size_t utf16Left = utf16Len;
+
+ UC_Assert ( (utf8In != 0) && (utf16Out != 0) && (utf8Read != 0) && (utf16Written != 0) );
+
+ while ( (utf8Left > 0) && (utf16Left > 0) ) {
+
+ // Do a run of ASCII, it copies 1 input unit into 1 output unit.
+ size_t i, limit = utf8Left;
+ if ( limit > utf16Left ) limit = utf16Left;
+ for ( i = 0; i < limit; ++i ) {
+ UTF8Unit inUnit = *utf8Pos;
+ if ( inUnit > 0x7F ) break;
+ *utf16Pos = inUnit;
+ ++utf8Pos;
+ ++utf16Pos;
+ }
+ utf8Left -= i;
+ utf16Left -= i;
+
+ // Do a run of non-ASCII, it copies multiple input units into 1 or 2 output units.
+ while ( (utf8Left > 0) && (utf16Left > 0) ) {
+ UTF32Unit cp;
+ size_t len8, len16;
+ UTF8Unit inUnit = *utf8Pos;
+ if ( inUnit <= 0x7F ) break;
+ CodePoint_from_UTF8_Multi ( utf8Pos, utf8Left, &cp, &len8 );
+ if ( len8 == 0 ) goto Done; // The input buffer ends in the middle of a character.
+ if ( cp <= 0xFFFF ) {
+ *utf16Pos = UTF16Unit(cp);
+ len16 = 1;
+ } else {
+ CodePoint_to_UTF16Nat_Surrogate ( cp, utf16Pos, utf16Left, &len16 );
+ if ( len16 == 0 ) goto Done; // Not enough room in the output buffer.
+ }
+ utf8Left -= len8;
+ utf8Pos += len8;
+ utf16Left -= len16;
+ utf16Pos += len16;
+ }
+
+ }
+
+Done: // Set the output lengths.
+ *utf8Read = utf8Len - utf8Left;
+ *utf16Written = utf16Len - utf16Left;
+
+} // UTF8_to_UTF16Nat
+
+// =================================================================================================
+
+static void UTF8_to_UTF32Nat ( const UTF8Unit * utf8In, const size_t utf8Len,
+ UTF32Unit * utf32Out, const size_t utf32Len,
+ size_t * utf8Read, size_t * utf32Written )
+{
+ const UTF8Unit * utf8Pos = utf8In;
+ UTF32Unit * utf32Pos = utf32Out;
+
+ size_t utf8Left = utf8Len;
+ size_t utf32Left = utf32Len;
+
+ UC_Assert ( (utf8In != 0) && (utf32Out != 0) && (utf8Read != 0) && (utf32Written != 0) );
+
+ while ( (utf8Left > 0) && (utf32Left > 0) ) {
+
+ // Do a run of ASCII, it copies 1 input unit into 1 output unit.
+ size_t i, limit = utf8Left;
+ if ( limit > utf32Left ) limit = utf32Left;
+ for ( i = 0; i < limit; ++i ) {
+ UTF8Unit inUnit = *utf8Pos;
+ if ( inUnit > 0x7F ) break;
+ *utf32Pos = inUnit;
+ ++utf8Pos;
+ ++utf32Pos;
+ }
+ utf8Left -= i;
+ utf32Left -= i;
+
+ // Do a run of non-ASCII, it copies variable input into 1 output unit.
+ while ( (utf8Left > 0) && (utf32Left > 0) ) {
+ size_t len;
+ UTF8Unit inUnit = *utf8Pos;
+ if ( inUnit <= 0x7F ) break;
+ CodePoint_from_UTF8_Multi ( utf8Pos, utf8Left, utf32Pos, &len );
+ if ( len == 0 ) goto Done; // The input buffer ends in the middle of a character.
+ utf8Left -= len;
+ utf8Pos += len;
+ utf32Left -= 1;
+ utf32Pos += 1;
+ }
+
+ }
+
+Done: // Set the output lengths.
+ *utf8Read = utf8Len - utf8Left;
+ *utf32Written = utf32Len - utf32Left;
+
+} // UTF8_to_UTF32Nat
+
+// =================================================================================================
+
+static void UTF16Nat_to_UTF8 ( const UTF16Unit * utf16In, const size_t utf16Len,
+ UTF8Unit * utf8Out, const size_t utf8Len,
+ size_t * utf16Read, size_t * utf8Written )
+{
+ const UTF16Unit * utf16Pos = utf16In;
+ UTF8Unit * utf8Pos = utf8Out;
+
+ size_t utf16Left = utf16Len;
+ size_t utf8Left = utf8Len;
+
+ UC_Assert ( (utf16In != 0) && (utf8Out != 0) && (utf16Read != 0) && (utf8Written != 0) );
+
+ while ( (utf16Left > 0) && (utf8Left > 0) ) {
+
+ // Do a run of ASCII, it copies 1 input unit into 1 output unit.
+ size_t i, limit = utf16Left;
+ if ( limit > utf8Left ) limit = utf8Left;
+ for ( i = 0; i < limit; ++i ) {
+ UTF16Unit inUnit = *utf16Pos;
+ if ( inUnit > 0x7F ) break;
+ *utf8Pos = UTF8Unit(inUnit);
+ ++utf16Pos;
+ ++utf8Pos;
+ }
+ utf16Left -= i;
+ utf8Left -= i;
+
+ // Do a run of non-ASCII inside the BMP, it copies 1 input unit into multiple output units.
+ while ( (utf16Left > 0) && (utf8Left > 0) ) {
+ size_t len8;
+ UTF16Unit inUnit = *utf16Pos;
+ if ( inUnit <= 0x7F ) break;
+ if ( (0xD800 <= inUnit) && (inUnit <= 0xDFFF) ) break;
+ CodePoint_to_UTF8_Multi ( inUnit, utf8Pos, utf8Left, &len8 );
+ if ( len8 == 0 ) goto Done; // Not enough room in the output buffer.
+ utf16Left -= 1;
+ utf16Pos += 1;
+ utf8Left -= len8;
+ utf8Pos += len8;
+ }
+
+ // Do a run of surrogate pairs, it copies 2 input units into multiple output units.
+ while ( (utf16Left > 0) && (utf8Left > 0) ) {
+ UTF32Unit cp;
+ size_t len16, len8;
+ UTF16Unit inUnit = *utf16Pos;
+ if ( (inUnit < 0xD800) || (0xDFFF < inUnit) ) break;
+ CodePoint_from_UTF16Nat_Surrogate ( utf16Pos, utf16Left, &cp, &len16 );
+ if ( len16 == 0 ) goto Done; // The input buffer ends in the middle of a surrogate pair.
+ UC_Assert ( len16 == 2 );
+ CodePoint_to_UTF8_Multi ( cp, utf8Pos, utf8Left, &len8 );
+ if ( len8 == 0 ) goto Done; // Not enough room in the output buffer.
+ utf16Left -= len16;
+ utf16Pos += len16;
+ utf8Left -= len8;
+ utf8Pos += len8;
+ }
+
+ }
+
+Done: // Set the output lengths.
+ *utf16Read = utf16Len - utf16Left;
+ *utf8Written = utf8Len - utf8Left;
+
+} // UTF16Nat_to_UTF8
+
+// =================================================================================================
+
+static void UTF32Nat_to_UTF8 ( const UTF32Unit * utf32In, const size_t utf32Len,
+ UTF8Unit * utf8Out, const size_t utf8Len,
+ size_t * utf32Read, size_t * utf8Written )
+{
+ const UTF32Unit * utf32Pos = utf32In;
+ UTF8Unit * utf8Pos = utf8Out;
+
+ size_t utf32Left = utf32Len;
+ size_t utf8Left = utf8Len;
+
+ UC_Assert ( (utf32In != 0) && (utf8Out != 0) && (utf32Read != 0) && (utf8Written != 0) );
+
+ while ( (utf32Left > 0) && (utf8Left > 0) ) {
+
+ // Do a run of ASCII, it copies 1 input unit into 1 output unit.
+ size_t i, limit = utf32Left;
+ if ( limit > utf8Left ) limit = utf8Left;
+ for ( i = 0; i < limit; ++i ) {
+ UTF32Unit inUnit = *utf32Pos;
+ if ( inUnit > 0x7F ) break;
+ *utf8Pos = UTF8Unit(inUnit);
+ ++utf32Pos;
+ ++utf8Pos;
+ }
+ utf32Left -= i;
+ utf8Left -= i;
+
+ // Do a run of non-ASCII, it copies 1 input unit into multiple output units.
+ while ( (utf32Left > 0) && (utf8Left > 0) ) {
+ size_t len;
+ UTF32Unit inUnit = *utf32Pos;
+ if ( inUnit <= 0x7F ) break;
+ CodePoint_to_UTF8_Multi ( inUnit, utf8Pos, utf8Left, &len );
+ if ( len == 0 ) goto Done; // Not enough room in the output buffer.
+ utf32Left -= 1;
+ utf32Pos += 1;
+ utf8Left -= len;
+ utf8Pos += len;
+ }
+
+ }
+
+Done: // Set the output lengths.
+ *utf32Read = utf32Len - utf32Left;
+ *utf8Written = utf8Len - utf8Left;
+
+} // UTF32Nat_to_UTF8
+
+// =================================================================================================
+
+static void UTF16Nat_to_UTF32Nat ( const UTF16Unit * utf16In, const size_t utf16Len,
+ UTF32Unit * utf32Out, const size_t utf32Len,
+ size_t * utf16Read, size_t * utf32Written )
+{
+ const UTF16Unit * utf16Pos = utf16In;
+ UTF32Unit * utf32Pos = utf32Out;
+
+ size_t utf16Left = utf16Len;
+ size_t utf32Left = utf32Len;
+
+ UC_Assert ( (utf16In != 0) && (utf32Out != 0) && (utf16Read != 0) && (utf32Written != 0) );
+
+ while ( (utf16Left > 0) && (utf32Left > 0) ) {
+
+ // Do a run of BMP, it copies 1 input unit into 1 output unit.
+ size_t i, limit = utf16Left;
+ if ( limit > utf32Left ) limit = utf32Left;
+ for ( i = 0; i < limit; ++i ) {
+ UTF16Unit inUnit = *utf16Pos;
+ if ( (0xD800 <= inUnit) && (inUnit <= 0xDFFF) ) break;
+ *utf32Pos = inUnit;
+ ++utf16Pos;
+ ++utf32Pos;
+ }
+ utf16Left -= i;
+ utf32Left -= i;
+
+ // Do a run of surrogate pairs, it copies 2 input units into 1 output unit.
+ while ( (utf16Left > 0) && (utf32Left > 0) ) {
+ size_t len;
+ UTF16Unit inUnit = *utf16Pos;
+ if ( (inUnit < 0xD800) || (0xDFFF < inUnit) ) break;
+ CodePoint_from_UTF16Nat_Surrogate ( utf16Pos, utf16Left, utf32Pos, &len );
+ if ( len == 0 ) goto Done; // The input buffer ends in the middle of a surrogate pair.
+ UC_Assert ( len == 2 );
+ utf16Left -= len;
+ utf16Pos += len;
+ utf32Left -= 1;
+ utf32Pos += 1;
+ }
+
+ }
+
+Done: // Set the output lengths.
+ *utf16Read = utf16Len - utf16Left;
+ *utf32Written = utf32Len - utf32Left;
+
+} // UTF16Nat_to_UTF32Nat
+
+// =================================================================================================
+
+static void UTF32Nat_to_UTF16Nat ( const UTF32Unit * utf32In, const size_t utf32Len,
+ UTF16Unit * utf16Out, const size_t utf16Len,
+ size_t * utf32Read, size_t * utf16Written )
+{
+ const UTF32Unit * utf32Pos = utf32In;
+ UTF16Unit * utf16Pos = utf16Out;
+
+ size_t utf32Left = utf32Len;
+ size_t utf16Left = utf16Len;
+
+ UC_Assert ( (utf32In != 0) && (utf16Out != 0) && (utf32Read != 0) && (utf16Written != 0) );
+
+ while ( (utf32Left > 0) && (utf16Left > 0) ) {
+
+ // Do a run of BMP, it copies 1 input unit into 1 output unit.
+ size_t i, limit = utf32Left;
+ if ( limit > utf16Left ) limit = utf16Left;
+ for ( i = 0; i < limit; ++i ) {
+ UTF32Unit inUnit = *utf32Pos;
+ if ( inUnit > 0xFFFF ) break;
+ *utf16Pos = UTF16Unit(inUnit);
+ ++utf32Pos;
+ ++utf16Pos;
+ }
+ utf32Left -= i;
+ utf16Left -= i;
+
+ // Do a run of non-BMP, it copies 1 input unit into 2 output units.
+ while ( (utf32Left > 0) && (utf16Left > 0) ) {
+ size_t len;
+ UTF32Unit inUnit = *utf32Pos;
+ if ( inUnit <= 0xFFFF ) break;
+ CodePoint_to_UTF16Nat_Surrogate ( inUnit, utf16Pos, utf16Left, &len );
+ if ( len == 0 ) goto Done; // Not enough room in the output buffer.
+ UC_Assert ( len == 2 );
+ utf32Left -= 1;
+ utf32Pos += 1;
+ utf16Left -= 2;
+ utf16Pos += 2;
+ }
+
+ }
+
+Done: // Set the output lengths.
+ *utf32Read = utf32Len - utf32Left;
+ *utf16Written = utf16Len - utf16Left;
+
+} // UTF32Nat_to_UTF16Nat
+
+// =================================================================================================
+
+static void CodePoint_to_UTF16Swp_Surrogate ( const UTF32Unit cpIn, UTF16Unit * utf16Out, const size_t utf16Len, size_t * utf16Written )
+{
+ size_t unitCount = 0;
+ UTF32Unit temp; // ! Avoid gcc complaints about declarations after goto's.
+
+ if ( cpIn > 0x10FFFF ) UC_Throw ( "Bad UTF-32 - out of range", kXMPErr_BadParam );
+ if ( utf16Len < 2 ) goto Done; // Not enough room for the output.
+
+ unitCount = 2;
+ temp = cpIn - 0x10000;
+ UTF16OutSwap ( &utf16Out[0], (0xD800 | UTF16Unit ( temp >> 10 )) );
+ UTF16OutSwap ( &utf16Out[1], (0xDC00 | UTF16Unit ( temp & 0x3FF)) );
+
+Done:
+ *utf16Written = unitCount;
+ return;
+
+} // CodePoint_to_UTF16Swp_Surrogate
+
+// =================================================================================================
+
+static void CodePoint_to_UTF16Swp ( const UTF32Unit cpIn, UTF16Unit * utf16Out, const size_t utf16Len, size_t * utf16Written )
+{
+ size_t unitCount = 0;
+
+ UC_Assert ( (utf16Out != 0) && (utf16Written != 0) );
+ if ( utf16Len == 0 ) goto Done;
+ if ( cpIn >= 0xD800 ) goto CheckSurrogate; // ! Force linear execution path for the BMP.
+
+InBMP:
+ unitCount = 1;
+ UTF16OutSwap ( utf16Out, UTF16Unit(cpIn) );
+
+Done:
+ *utf16Written = unitCount;
+ return;
+
+CheckSurrogate:
+ if ( cpIn > 0xFFFF ) goto SurrogatePair;
+ if ( cpIn > 0xDFFF ) goto InBMP;
+ UC_Throw ( "Bad UTF-32 - surrogate code point", kXMPErr_BadParam );
+
+SurrogatePair:
+ CodePoint_to_UTF16Swp_Surrogate ( cpIn, utf16Out, utf16Len, utf16Written );
+ return;
+
+} // CodePoint_to_UTF16Swp
+
+// =================================================================================================
+
+static void CodePoint_from_UTF16Swp_Surrogate ( const UTF16Unit * utf16In, const size_t utf16Len, UTF32Unit * cpOut, size_t * utf16Read )
+{
+ UTF16Unit hiUnit = UTF16InSwap(utf16In);
+ size_t unitCount = 0;
+ UTF16Unit loUnit; // ! Avoid gcc complaints about declarations after goto's.
+ UTF32Unit cp;
+
+ // ----------------------------------
+ // We've got a UTF-16 surrogate pair.
+
+ if ( hiUnit > 0xDBFF ) UC_Throw ( "Bad UTF-16 - leading low surrogate", kXMPErr_BadParam );
+ if ( utf16Len < 2 ) goto Done; // Not enough input in this buffer.
+
+ loUnit = UTF16InSwap(utf16In+1);
+ if ( (loUnit < 0xDC00) || (0xDFFF < loUnit) ) UC_Throw ( "Bad UTF-16 - missing low surrogate", kXMPErr_BadParam );
+
+ unitCount = 2;
+ cp = (((hiUnit & 0x3FF) << 10) | (loUnit & 0x3FF)) + 0x10000;
+
+ *cpOut = cp; // ! Don't put after Done, don't write if no input.
+
+Done:
+ *utf16Read = unitCount;
+ return;
+
+} // CodePoint_from_UTF16Swp_Surrogate
+
+// =================================================================================================
+
+static void CodePoint_from_UTF16Swp ( const UTF16Unit * utf16In, const size_t utf16Len, UTF32Unit * cpOut, size_t * utf16Read )
+{
+ UTF16Unit inUnit; // ! Don't read until we know there is input.
+ size_t unitCount = 0;
+
+ UC_Assert ( (utf16In != 0) && (cpOut != 0) && (utf16Read != 0) );
+ if ( utf16Len == 0 ) goto Done;
+ inUnit = UTF16InSwap(utf16In);
+ if ( (0xD800 <= inUnit) && (inUnit <= 0xDFFF) ) goto SurrogatePair; // ! Force linear execution path for the BMP.
+
+ unitCount = 1;
+ *cpOut = inUnit; // ! Don't put after Done, don't write if no input.
+
+Done:
+ *utf16Read = unitCount;
+ return;
+
+SurrogatePair:
+ CodePoint_from_UTF16Swp_Surrogate ( utf16In, utf16Len, cpOut, utf16Read );
+ return;
+
+} // CodePoint_from_UTF16Swp
+
+// =================================================================================================
+
+static void UTF8_to_UTF16Swp ( const UTF8Unit * utf8In, const size_t utf8Len,
+ UTF16Unit * utf16Out, const size_t utf16Len,
+ size_t * utf8Read, size_t * utf16Written )
+{
+ const UTF8Unit * utf8Pos = utf8In;
+ UTF16Unit * utf16Pos = utf16Out;
+
+ size_t utf8Left = utf8Len;
+ size_t utf16Left = utf16Len;
+
+ UC_Assert ( (utf8In != 0) && (utf16Out != 0) && (utf8Read != 0) && (utf16Written != 0) );
+
+ while ( (utf8Left > 0) && (utf16Left > 0) ) {
+
+ // Do a run of ASCII, it copies 1 input unit into 1 output unit.
+ size_t i, limit = utf8Left;
+ if ( limit > utf16Left ) limit = utf16Left;
+ for ( i = 0; i < limit; ++i ) {
+ UTF8Unit inUnit = *utf8Pos;
+ if ( inUnit > 0x7F ) break;
+ *utf16Pos = UTF16Unit(inUnit) << 8; // Better than: UTF16OutSwap ( utf16Pos, inUnit );
+ ++utf8Pos;
+ ++utf16Pos;
+ }
+ utf8Left -= i;
+ utf16Left -= i;
+
+ // Do a run of non-ASCII, it copies multiple input units into 1 or 2 output units.
+ while ( (utf8Left > 0) && (utf16Left > 0) ) {
+ UTF32Unit cp;
+ size_t len8, len16;
+ UTF8Unit inUnit = *utf8Pos;
+ if ( inUnit <= 0x7F ) break;
+ CodePoint_from_UTF8_Multi ( utf8Pos, utf8Left, &cp, &len8 );
+ if ( len8 == 0 ) goto Done; // The input buffer ends in the middle of a character.
+ if ( cp <= 0xFFFF ) {
+ UTF16OutSwap ( utf16Pos, UTF16Unit(cp) );
+ len16 = 1;
+ } else {
+ CodePoint_to_UTF16Swp_Surrogate ( cp, utf16Pos, utf16Left, &len16 );
+ if ( len16 == 0 ) goto Done; // Not enough room in the output buffer.
+ }
+ utf8Left -= len8;
+ utf8Pos += len8;
+ utf16Left -= len16;
+ utf16Pos += len16;
+ }
+
+ }
+
+Done: // Set the output lengths.
+ *utf8Read = utf8Len - utf8Left;
+ *utf16Written = utf16Len - utf16Left;
+
+} // UTF8_to_UTF16Swp
+
+// =================================================================================================
+
+static void UTF8_to_UTF32Swp ( const UTF8Unit * utf8In, const size_t utf8Len,
+ UTF32Unit * utf32Out, const size_t utf32Len,
+ size_t * utf8Read, size_t * utf32Written )
+{
+ const UTF8Unit * utf8Pos = utf8In;
+ UTF32Unit * utf32Pos = utf32Out;
+
+ size_t utf8Left = utf8Len;
+ size_t utf32Left = utf32Len;
+
+ UC_Assert ( (utf8In != 0) && (utf32Out != 0) && (utf8Read != 0) && (utf32Written != 0) );
+
+ while ( (utf8Left > 0) && (utf32Left > 0) ) {
+
+ // Do a run of ASCII, it copies 1 input unit into 1 output unit.
+ size_t i, limit = utf8Left;
+ if ( limit > utf32Left ) limit = utf32Left;
+ for ( i = 0; i < limit; ++i ) {
+ UTF8Unit inUnit = *utf8Pos;
+ if ( inUnit > 0x7F ) break;
+ *utf32Pos = UTF32Unit(inUnit) << 24; // Better than: UTF32OutSwap ( utf32Pos, inUnit );
+ ++utf8Pos;
+ ++utf32Pos;
+ }
+ utf8Left -= i;
+ utf32Left -= i;
+
+ // Do a run of non-ASCII, it copies variable input into 1 output unit.
+ while ( (utf8Left > 0) && (utf32Left > 0) ) {
+ size_t len;
+ UTF32Unit cp;
+ UTF8Unit inUnit = *utf8Pos;
+ if ( inUnit <= 0x7F ) break;
+ CodePoint_from_UTF8_Multi ( utf8Pos, utf8Left, &cp, &len );
+ if ( len == 0 ) goto Done; // The input buffer ends in the middle of a character.
+ UTF32OutSwap ( utf32Pos, cp );
+ utf8Left -= len;
+ utf8Pos += len;
+ utf32Left -= 1;
+ utf32Pos += 1;
+ }
+
+ }
+
+Done: // Set the output lengths.
+ *utf8Read = utf8Len - utf8Left;
+ *utf32Written = utf32Len - utf32Left;
+
+} // UTF8_to_UTF32Swp
+
+// =================================================================================================
+
+static void UTF16Swp_to_UTF8 ( const UTF16Unit * utf16In, const size_t utf16Len,
+ UTF8Unit * utf8Out, const size_t utf8Len,
+ size_t * utf16Read, size_t * utf8Written )
+{
+ const UTF16Unit * utf16Pos = utf16In;
+ UTF8Unit * utf8Pos = utf8Out;
+
+ size_t utf16Left = utf16Len;
+ size_t utf8Left = utf8Len;
+
+ UC_Assert ( (utf16In != 0) && (utf8Out != 0) && (utf16Read != 0) && (utf8Written != 0) );
+
+ while ( (utf16Left > 0) && (utf8Left > 0) ) {
+
+ // Do a run of ASCII, it copies 1 input unit into 1 output unit.
+ size_t i, limit = utf16Left;
+ if ( limit > utf8Left ) limit = utf8Left;
+ for ( i = 0; i < limit; ++i ) {
+ UTF16Unit inUnit = UTF16InSwap(utf16Pos);
+ if ( inUnit > 0x7F ) break;
+ *utf8Pos = UTF8Unit(inUnit);
+ ++utf16Pos;
+ ++utf8Pos;
+ }
+ utf16Left -= i;
+ utf8Left -= i;
+
+ // Do a run of non-ASCII inside the BMP, it copies 1 input unit into multiple output units.
+ while ( (utf16Left > 0) && (utf8Left > 0) ) {
+ size_t len8;
+ UTF16Unit inUnit = UTF16InSwap(utf16Pos);
+ if ( inUnit <= 0x7F ) break;
+ if ( (0xD800 <= inUnit) && (inUnit <= 0xDFFF) ) break;
+ CodePoint_to_UTF8_Multi ( inUnit, utf8Pos, utf8Left, &len8 );
+ if ( len8 == 0 ) goto Done; // Not enough room in the output buffer.
+ utf16Left -= 1;
+ utf16Pos += 1;
+ utf8Left -= len8;
+ utf8Pos += len8;
+ }
+
+ // Do a run of surrogate pairs, it copies 2 input units into multiple output units.
+ while ( (utf16Left > 0) && (utf8Left > 0) ) {
+ UTF32Unit cp;
+ size_t len16, len8;
+ UTF16Unit inUnit = UTF16InSwap(utf16Pos);
+ if ( (inUnit < 0xD800) || (0xDFFF < inUnit) ) break;
+ CodePoint_from_UTF16Swp_Surrogate ( utf16Pos, utf16Left, &cp, &len16 );
+ if ( len16 == 0 ) goto Done; // The input buffer ends in the middle of a surrogate pair.
+ UC_Assert ( len16 == 2 );
+ CodePoint_to_UTF8_Multi ( cp, utf8Pos, utf8Left, &len8 );
+ if ( len8 == 0 ) goto Done; // Not enough room in the output buffer.
+ utf16Left -= len16;
+ utf16Pos += len16;
+ utf8Left -= len8;
+ utf8Pos += len8;
+ }
+
+ }
+
+Done: // Set the output lengths.
+ *utf16Read = utf16Len - utf16Left;
+ *utf8Written = utf8Len - utf8Left;
+
+} // UTF16Swp_to_UTF8
+
+// =================================================================================================
+
+static void UTF32Swp_to_UTF8 ( const UTF32Unit * utf32In, const size_t utf32Len,
+ UTF8Unit * utf8Out, const size_t utf8Len,
+ size_t * utf32Read, size_t * utf8Written )
+{
+ const UTF32Unit * utf32Pos = utf32In;
+ UTF8Unit * utf8Pos = utf8Out;
+
+ size_t utf32Left = utf32Len;
+ size_t utf8Left = utf8Len;
+
+ UC_Assert ( (utf32In != 0) && (utf8Out != 0) && (utf32Read != 0) && (utf8Written != 0) );
+
+ while ( (utf32Left > 0) && (utf8Left > 0) ) {
+
+ // Do a run of ASCII, it copies 1 input unit into 1 output unit.
+ size_t i, limit = utf32Left;
+ if ( limit > utf8Left ) limit = utf8Left;
+ for ( i = 0; i < limit; ++i ) {
+ UTF32Unit cp = UTF32InSwap(utf32Pos);
+ if ( cp > 0x7F ) break;
+ *utf8Pos = UTF8Unit(cp);
+ ++utf32Pos;
+ ++utf8Pos;
+ }
+ utf32Left -= i;
+ utf8Left -= i;
+
+ // Do a run of non-ASCII, it copies 1 input unit into multiple output units.
+ while ( (utf32Left > 0) && (utf8Left > 0) ) {
+ size_t len;
+ UTF32Unit cp = UTF32InSwap(utf32Pos);
+ if ( cp <= 0x7F ) break;
+ CodePoint_to_UTF8_Multi ( cp, utf8Pos, utf8Left, &len );
+ if ( len == 0 ) goto Done; // Not enough room in the output buffer.
+ utf32Left -= 1;
+ utf32Pos += 1;
+ utf8Left -= len;
+ utf8Pos += len;
+ }
+
+ }
+
+Done: // Set the output lengths.
+ *utf32Read = utf32Len - utf32Left;
+ *utf8Written = utf8Len - utf8Left;
+
+} // UTF32Swp_to_UTF8
+
+// =================================================================================================
+
+static void UTF16Swp_to_UTF32Swp ( const UTF16Unit * utf16In, const size_t utf16Len,
+ UTF32Unit * utf32Out, const size_t utf32Len,
+ size_t * utf16Read, size_t * utf32Written )
+{
+ const UTF16Unit * utf16Pos = utf16In;
+ UTF32Unit * utf32Pos = utf32Out;
+
+ size_t utf16Left = utf16Len;
+ size_t utf32Left = utf32Len;
+
+ UC_Assert ( (utf16In != 0) && (utf32Out != 0) && (utf16Read != 0) && (utf32Written != 0) );
+
+ while ( (utf16Left > 0) && (utf32Left > 0) ) {
+
+ // Do a run of BMP, it copies 1 input unit into 1 output unit.
+ size_t i, limit = utf16Left;
+ if ( limit > utf32Left ) limit = utf32Left;
+ for ( i = 0; i < limit; ++i ) {
+ UTF16Unit inUnit = UTF16InSwap(utf16Pos);
+ if ( (0xD800 <= inUnit) && (inUnit <= 0xDFFF) ) break;
+ *utf32Pos = UTF32Unit(*utf16Pos) << 16; // Better than: UTF32OutSwap ( utf32Pos, inUnit );
+ ++utf16Pos;
+ ++utf32Pos;
+ }
+ utf16Left -= i;
+ utf32Left -= i;
+
+ // Do a run of surrogate pairs, it copies 2 input units into 1 output unit.
+ while ( (utf16Left > 0) && (utf32Left > 0) ) {
+ size_t len;
+ UTF32Unit cp;
+ UTF16Unit inUnit = UTF16InSwap(utf16Pos);
+ if ( (inUnit < 0xD800) || (0xDFFF < inUnit) ) break;
+ CodePoint_from_UTF16Swp_Surrogate ( utf16Pos, utf16Left, &cp, &len );
+ if ( len == 0 ) goto Done; // The input buffer ends in the middle of a surrogate pair.
+ UTF32OutSwap ( utf32Pos, cp );
+ UC_Assert ( len == 2 );
+ utf16Left -= len;
+ utf16Pos += len;
+ utf32Left -= 1;
+ utf32Pos += 1;
+ }
+
+ }
+
+Done: // Set the output lengths.
+ *utf16Read = utf16Len - utf16Left;
+ *utf32Written = utf32Len - utf32Left;
+
+} // UTF16Swp_to_UTF32Swp
+
+// =================================================================================================
+
+static void UTF32Swp_to_UTF16Swp ( const UTF32Unit * utf32In, const size_t utf32Len,
+ UTF16Unit * utf16Out, const size_t utf16Len,
+ size_t * utf32Read, size_t * utf16Written )
+{
+ const UTF32Unit * utf32Pos = utf32In;
+ UTF16Unit * utf16Pos = utf16Out;
+
+ size_t utf32Left = utf32Len;
+ size_t utf16Left = utf16Len;
+
+ const size_t k32to16Offset = swap32to16Offset; // ! Make sure compiler treats as an invariant.
+
+ UC_Assert ( (utf32In != 0) && (utf16Out != 0) && (utf32Read != 0) && (utf16Written != 0) );
+
+ while ( (utf32Left > 0) && (utf16Left > 0) ) {
+
+ // Do a run of BMP, it copies 1 input unit into 1 output unit.
+ size_t i, limit = utf32Left;
+ if ( limit > utf16Left ) limit = utf16Left;
+ for ( i = 0; i < limit; ++i ) {
+ UTF32Unit inUnit = UTF32InSwap(utf32Pos);
+ if ( inUnit > 0xFFFF ) break;
+ *utf16Pos = *(((UTF16Unit*)utf32Pos) + k32to16Offset); // Better than: UTF16OutSwap ( utf16Pos, UTF16Unit(inUnit) );
+ ++utf32Pos;
+ ++utf16Pos;
+ }
+ utf32Left -= i;
+ utf16Left -= i;
+
+ // Do a run of non-BMP, it copies 1 input unit into 2 output units.
+ while ( (utf32Left > 0) && (utf16Left > 0) ) {
+ size_t len;
+ UTF32Unit inUnit = UTF32InSwap(utf32Pos);
+ if ( inUnit <= 0xFFFF ) break;
+ CodePoint_to_UTF16Swp_Surrogate ( inUnit, utf16Pos, utf16Left, &len );
+ if ( len == 0 ) goto Done; // Not enough room in the output buffer.
+ UC_Assert ( len == 2 );
+ utf32Left -= 1;
+ utf32Pos += 1;
+ utf16Left -= 2;
+ utf16Pos += 2;
+ }
+
+ }
+
+Done: // Set the output lengths.
+ *utf32Read = utf32Len - utf32Left;
+ *utf16Written = utf16Len - utf16Left;
+
+} // UTF32Swp_to_UTF16Swp
+
+// =================================================================================================
+
+static void UTF16Nat_to_UTF32Swp ( const UTF16Unit * utf16In, const size_t utf16Len,
+ UTF32Unit * utf32Out, const size_t utf32Len,
+ size_t * utf16Read, size_t * utf32Written )
+{
+ const UTF16Unit * utf16Pos = utf16In;
+ UTF32Unit * utf32Pos = utf32Out;
+
+ size_t utf16Left = utf16Len;
+ size_t utf32Left = utf32Len;
+
+ UC_Assert ( (utf16In != 0) && (utf32Out != 0) && (utf16Read != 0) && (utf32Written != 0) );
+
+ while ( (utf16Left > 0) && (utf32Left > 0) ) {
+
+ // Do a run of BMP, it copies 1 input unit into 1 output unit.
+ size_t i, limit = utf16Left;
+ if ( limit > utf32Left ) limit = utf32Left;
+ for ( i = 0; i < limit; ++i ) {
+ UTF16Unit inUnit = *utf16Pos;
+ if ( (0xD800 <= inUnit) && (inUnit <= 0xDFFF) ) break;
+ UTF32OutSwap ( utf32Pos, inUnit );
+ ++utf16Pos;
+ ++utf32Pos;
+ }
+ utf16Left -= i;
+ utf32Left -= i;
+
+ // Do a run of surrogate pairs, it copies 2 input units into 1 output unit.
+ while ( (utf16Left > 0) && (utf32Left > 0) ) {
+ size_t len;
+ UTF32Unit cp;
+ UTF16Unit inUnit = *utf16Pos;
+ if ( (inUnit < 0xD800) || (0xDFFF < inUnit) ) break;
+ CodePoint_from_UTF16Nat_Surrogate ( utf16Pos, utf16Left, &cp, &len );
+ if ( len == 0 ) goto Done; // The input buffer ends in the middle of a surrogate pair.
+ UC_Assert ( len == 2 );
+ UTF32OutSwap ( utf32Pos, cp );
+ utf16Left -= len;
+ utf16Pos += len;
+ utf32Left -= 1;
+ utf32Pos += 1;
+ }
+
+ }
+
+Done: // Set the output lengths.
+ *utf16Read = utf16Len - utf16Left;
+ *utf32Written = utf32Len - utf32Left;
+
+} // UTF16Nat_to_UTF32Swp
+
+// =================================================================================================
+
+static void UTF16Swp_to_UTF32Nat ( const UTF16Unit * utf16In, const size_t utf16Len,
+ UTF32Unit * utf32Out, const size_t utf32Len,
+ size_t * utf16Read, size_t * utf32Written )
+{
+ const UTF16Unit * utf16Pos = utf16In;
+ UTF32Unit * utf32Pos = utf32Out;
+
+ size_t utf16Left = utf16Len;
+ size_t utf32Left = utf32Len;
+
+ UC_Assert ( (utf16In != 0) && (utf32Out != 0) && (utf16Read != 0) && (utf32Written != 0) );
+
+ while ( (utf16Left > 0) && (utf32Left > 0) ) {
+
+ // Do a run of BMP, it copies 1 input unit into 1 output unit.
+ size_t i, limit = utf16Left;
+ if ( limit > utf32Left ) limit = utf32Left;
+ for ( i = 0; i < limit; ++i ) {
+ UTF16Unit inUnit = UTF16InSwap(utf16Pos);
+ if ( (0xD800 <= inUnit) && (inUnit <= 0xDFFF) ) break;
+ *utf32Pos = inUnit;
+ ++utf16Pos;
+ ++utf32Pos;
+ }
+ utf16Left -= i;
+ utf32Left -= i;
+
+ // Do a run of surrogate pairs, it copies 2 input units into 1 output unit.
+ while ( (utf16Left > 0) && (utf32Left > 0) ) {
+ size_t len;
+ UTF16Unit inUnit = UTF16InSwap(utf16Pos);
+ if ( (inUnit < 0xD800) || (0xDFFF < inUnit) ) break;
+ CodePoint_from_UTF16Swp_Surrogate ( utf16Pos, utf16Left, utf32Pos, &len );
+ if ( len == 0 ) goto Done; // The input buffer ends in the middle of a surrogate pair.
+ UC_Assert ( len == 2 );
+ utf16Left -= len;
+ utf16Pos += len;
+ utf32Left -= 1;
+ utf32Pos += 1;
+ }
+
+ }
+
+Done: // Set the output lengths.
+ *utf16Read = utf16Len - utf16Left;
+ *utf32Written = utf32Len - utf32Left;
+
+} // UTF16Swp_to_UTF32Nat
+
+// =================================================================================================
+
+static void UTF32Nat_to_UTF16Swp ( const UTF32Unit * utf32In, const size_t utf32Len,
+ UTF16Unit * utf16Out, const size_t utf16Len,
+ size_t * utf32Read, size_t * utf16Written )
+{
+ const UTF32Unit * utf32Pos = utf32In;
+ UTF16Unit * utf16Pos = utf16Out;
+
+ size_t utf32Left = utf32Len;
+ size_t utf16Left = utf16Len;
+
+ UC_Assert ( (utf32In != 0) && (utf16Out != 0) && (utf32Read != 0) && (utf16Written != 0) );
+
+ while ( (utf32Left > 0) && (utf16Left > 0) ) {
+
+ // Do a run of BMP, it copies 1 input unit into 1 output unit.
+ size_t i, limit = utf32Left;
+ if ( limit > utf16Left ) limit = utf16Left;
+ for ( i = 0; i < limit; ++i ) {
+ UTF32Unit inUnit = *utf32Pos;
+ if ( inUnit > 0xFFFF ) break;
+ UTF16OutSwap ( utf16Pos, UTF16Unit(inUnit) );
+ ++utf32Pos;
+ ++utf16Pos;
+ }
+ utf32Left -= i;
+ utf16Left -= i;
+
+ // Do a run of non-BMP, it copies 1 input unit into 2 output units.
+ while ( (utf32Left > 0) && (utf16Left > 0) ) {
+ size_t len;
+ UTF32Unit inUnit = *utf32Pos;
+ if ( inUnit <= 0xFFFF ) break;
+ CodePoint_to_UTF16Swp_Surrogate ( inUnit, utf16Pos, utf16Left, &len );
+ if ( len == 0 ) goto Done; // Not enough room in the output buffer.
+ UC_Assert ( len == 2 );
+ utf32Left -= 1;
+ utf32Pos += 1;
+ utf16Left -= 2;
+ utf16Pos += 2;
+ }
+
+ }
+
+Done: // Set the output lengths.
+ *utf32Read = utf32Len - utf32Left;
+ *utf16Written = utf16Len - utf16Left;
+
+} // UTF32Nat_to_UTF16Swp
+
+// =================================================================================================
+
+static void UTF32Swp_to_UTF16Nat ( const UTF32Unit * utf32In, const size_t utf32Len,
+ UTF16Unit * utf16Out, const size_t utf16Len,
+ size_t * utf32Read, size_t * utf16Written )
+{
+ const UTF32Unit * utf32Pos = utf32In;
+ UTF16Unit * utf16Pos = utf16Out;
+
+ size_t utf32Left = utf32Len;
+ size_t utf16Left = utf16Len;
+
+ UC_Assert ( (utf32In != 0) && (utf16Out != 0) && (utf32Read != 0) && (utf16Written != 0) );
+
+ while ( (utf32Left > 0) && (utf16Left > 0) ) {
+
+ // Do a run of BMP, it copies 1 input unit into 1 output unit.
+ size_t i, limit = utf32Left;
+ if ( limit > utf16Left ) limit = utf16Left;
+ for ( i = 0; i < limit; ++i ) {
+ UTF32Unit inUnit = UTF32InSwap(utf32Pos);
+ if ( inUnit > 0xFFFF ) break;
+ *utf16Pos = UTF16Unit(inUnit);
+ ++utf32Pos;
+ ++utf16Pos;
+ }
+ utf32Left -= i;
+ utf16Left -= i;
+
+ // Do a run of non-BMP, it copies 1 input unit into 2 output units.
+ while ( (utf32Left > 0) && (utf16Left > 0) ) {
+ size_t len;
+ UTF32Unit inUnit = UTF32InSwap(utf32Pos);
+ if ( inUnit <= 0xFFFF ) break;
+ CodePoint_to_UTF16Nat_Surrogate ( inUnit, utf16Pos, utf16Left, &len );
+ if ( len == 0 ) goto Done; // Not enough room in the output buffer.
+ UC_Assert ( len == 2 );
+ utf32Left -= 1;
+ utf32Pos += 1;
+ utf16Left -= 2;
+ utf16Pos += 2;
+ }
+
+ }
+
+Done: // Set the output lengths.
+ *utf32Read = utf32Len - utf32Left;
+ *utf16Written = utf16Len - utf16Left;
+
+} // UTF32Swp_to_UTF16Nat
+
+// =================================================================================================
diff --git a/source/common/UnicodeConversions.hpp b/source/common/UnicodeConversions.hpp
new file mode 100644
index 0000000..0888300
--- /dev/null
+++ b/source/common/UnicodeConversions.hpp
@@ -0,0 +1,121 @@
+#ifndef __UnicodeConversions_h__
+#define __UnicodeConversions_h__
+
+// =================================================================================================
+// Copyright 2004-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include <string>
+
+// =================================================================================================
+
+#if UnicodeTestBuild
+ typedef unsigned char UTF8Unit;
+ typedef unsigned short UTF16Unit;
+ typedef unsigned long UTF32Unit;
+#else
+ typedef XMP_Uns8 UTF8Unit;
+ typedef XMP_Uns16 UTF16Unit;
+ typedef XMP_Uns32 UTF32Unit;
+#endif
+
+// -------------------------------------------------------------------------------------------------
+
+// ! The UTF16 and UTF32 counts are in storage units, not bytes! CodePoint values are always native.
+
+// *** MIght be better to return a status than throw an exception for errors?
+
+typedef void (*CodePoint_to_UTF16_Proc) ( const UTF32Unit cpIn, UTF16Unit * utf16Out, const size_t utf16Len, size_t * utf16Written );
+
+typedef void (*CodePoint_from_UTF16_Proc) ( const UTF16Unit * utf16In, const size_t utf16Len, UTF32Unit * cpOut, size_t * utf16Read );
+
+typedef void (*UTF8_to_UTF16_Proc) ( const UTF8Unit * utf8In, const size_t utf8Len,
+ UTF16Unit * utf16Out, const size_t utf16Len,
+ size_t * utf8Read, size_t * utf16Written );
+
+typedef void (*UTF8_to_UTF32_Proc) ( const UTF8Unit * utf8In, const size_t utf8Len,
+ UTF32Unit * utf32Out, const size_t utf32Len,
+ size_t * utf8Read, size_t * utf32Written );
+
+typedef void (*UTF16_to_UTF8_Proc) ( const UTF16Unit * utf16In, const size_t utf16Len,
+ UTF8Unit * utf8Out, const size_t utf8Len,
+ size_t * utf16Read, size_t * utf8Written );
+
+typedef void (*UTF32_to_UTF8_Proc) ( const UTF32Unit * utf32In, const size_t utf32Len,
+ UTF8Unit * utf8Out, const size_t utf8Len,
+ size_t * utf32Read, size_t * utf8Written );
+
+typedef void (*UTF16_to_UTF32_Proc) ( const UTF16Unit * utf16In, const size_t utf16Len,
+ UTF32Unit * utf32Out, const size_t utf32Len,
+ size_t * utf16Read, size_t * utf32Written );
+
+typedef void (*UTF32_to_UTF16_Proc) ( const UTF32Unit * utf32In, const size_t utf32Len,
+ UTF16Unit * utf16Out, const size_t utf16Len,
+ size_t * utf32Read, size_t * utf16Written );
+
+// -------------------------------------------------------------------------------------------------
+
+extern void CodePoint_to_UTF8 ( const UTF32Unit cpIn, UTF8Unit * utf8Out, const size_t utf8Len, size_t * utf8Written );
+
+extern void CodePoint_from_UTF8 ( const UTF8Unit * utf8In, const size_t utf8Len, UTF32Unit * cpOut, size_t * utf8Read );
+
+extern CodePoint_to_UTF16_Proc CodePoint_to_UTF16BE;
+extern CodePoint_to_UTF16_Proc CodePoint_to_UTF16LE;
+
+extern CodePoint_from_UTF16_Proc CodePoint_from_UTF16BE;
+extern CodePoint_from_UTF16_Proc CodePoint_from_UTF16LE;
+
+extern UTF8_to_UTF16_Proc UTF8_to_UTF16BE;
+extern UTF8_to_UTF16_Proc UTF8_to_UTF16LE;
+
+extern UTF8_to_UTF32_Proc UTF8_to_UTF32BE;
+extern UTF8_to_UTF32_Proc UTF8_to_UTF32LE;
+
+extern UTF16_to_UTF8_Proc UTF16BE_to_UTF8;
+extern UTF16_to_UTF8_Proc UTF16LE_to_UTF8;
+
+extern UTF32_to_UTF8_Proc UTF32BE_to_UTF8;
+extern UTF32_to_UTF8_Proc UTF32LE_to_UTF8;
+
+extern UTF8_to_UTF16_Proc UTF8_to_UTF16Native;
+extern UTF8_to_UTF32_Proc UTF8_to_UTF32Native;
+
+extern UTF16_to_UTF8_Proc UTF16Native_to_UTF8;
+extern UTF32_to_UTF8_Proc UTF32Native_to_UTF8;
+
+extern UTF16_to_UTF32_Proc UTF16BE_to_UTF32BE;
+extern UTF16_to_UTF32_Proc UTF16BE_to_UTF32LE;
+
+extern UTF16_to_UTF32_Proc UTF16LE_to_UTF32BE;
+extern UTF16_to_UTF32_Proc UTF16LE_to_UTF32LE;
+
+extern UTF32_to_UTF16_Proc UTF32BE_to_UTF16BE;
+extern UTF32_to_UTF16_Proc UTF32BE_to_UTF16LE;
+
+extern UTF32_to_UTF16_Proc UTF32LE_to_UTF16BE;
+extern UTF32_to_UTF16_Proc UTF32LE_to_UTF16LE;
+
+extern void SwapUTF16 ( const UTF16Unit * utf16In, UTF16Unit * utf16Out, const size_t utf16Len );
+extern void SwapUTF32 ( const UTF32Unit * utf32In, UTF32Unit * utf32Out, const size_t utf32Len );
+
+extern void ToUTF16 ( const UTF8Unit * utf8In, size_t utf8Len, std::string * utf16Str, bool bigEndian );
+extern void ToUTF32 ( const UTF8Unit * utf8In, size_t utf8Len, std::string * utf32Str, bool bigEndian );
+
+extern void FromUTF16 ( const UTF16Unit * utf16In, size_t utf16Len, std::string * utf8Str, bool bigEndian );
+extern void FromUTF32 ( const UTF32Unit * utf32In, size_t utf32Len, std::string * utf8Str, bool bigEndian );
+
+extern void ToUTF16Native ( const UTF8Unit * utf8In, size_t utf8Len, std::string * utf16Str );
+extern void ToUTF32Native ( const UTF8Unit * utf8In, size_t utf8Len, std::string * utf32Str );
+
+extern void FromUTF16Native ( const UTF16Unit * utf16In, size_t utf16Len, std::string * utf8Str );
+extern void FromUTF32Native ( const UTF32Unit * utf32In, size_t utf32Len, std::string * utf8Str );
+
+extern void InitializeUnicodeConversions();
+
+// =================================================================================================
+
+#endif // __UnicodeConversions_h__
diff --git a/source/common/UnicodeInlines.incl_cpp b/source/common/UnicodeInlines.incl_cpp
new file mode 100644
index 0000000..8d55bad
--- /dev/null
+++ b/source/common/UnicodeInlines.incl_cpp
@@ -0,0 +1,129 @@
+#ifndef __UnicodeInlines_incl_cpp__
+#define __UnicodeInlines_incl_cpp__
+
+// =================================================================================================
+// Copyright 2002-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "UnicodeConversions.hpp"
+
+// =================================================================================================
+// Inner loop utilities that need to be inlined.
+// =================================================================================================
+
+static inline XMP_Uns32 GetCodePoint ( const XMP_Uns8 ** utf8Str_io )
+{
+ const XMP_Uns8 * u8Ptr = *utf8Str_io;
+ XMP_Uns32 cp;
+ size_t u8Len;
+ CodePoint_from_UTF8 ( u8Ptr, 4, &cp, &u8Len ); // Throws an exception for errors.
+ *utf8Str_io = u8Ptr + u8Len;
+ return cp;
+}
+
+// =================================================================================================
+
+static inline bool IsStartChar_ASCII ( XMP_Uns32 cp )
+{
+ // ASCII starting characters for an XML name.
+ if ( (('a' <= cp) && (cp <= 'z')) || (('A' <= cp) && (cp <= 'Z')) || (cp == '_') ) return true;
+ return false;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+static inline bool IsStartChar_NonASCII ( XMP_Uns32 cp )
+{
+ // Non-ASCII starting characters for an XML name.
+
+ if ( ((0xC0 <= cp) && (cp <= 0xD6)) || ((0xD8 <= cp) && (cp <= 0xF6)) ) return true;
+ if ( ((0xF8 <= cp) && (cp <= 0x2FF)) || ((0x370 <= cp) && (cp <= 0x37D)) ) return true;
+
+ if ( ((0x37F <= cp) && (cp <= 0x1FFF)) || ((0x200C <= cp) && (cp <= 0x200D)) ) return true;
+ if ( ((0x2070 <= cp) && (cp <= 0x218F)) || ((0x2C00 <= cp) && (cp <= 0x2FEF)) ) return true;
+ if ( ((0x3001 <= cp) && (cp <= 0xD7FF)) || ((0xF900 <= cp) && (cp <= 0xFDCF)) ) return true;
+ if ( ((0xFDF0 <= cp) && (cp <= 0xFFFD)) || ((0x10000 <= cp) && (cp <= 0xEFFFF)) ) return true;
+
+ return false;
+
+}
+
+// -------------------------------------------------------------------------------------------------
+
+static inline bool IsOtherChar_ASCII ( XMP_Uns32 cp )
+{
+ // ASCII following characters for an XML name.
+ if ( (('0' <= cp) && (cp <= '9')) || (cp == '-') || (cp == '.') ) return true;
+ return false;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+static inline bool IsOtherChar_NonASCII ( XMP_Uns32 cp )
+{
+ // Non-ASCII following characters for an XML name.
+ if ( (cp == 0xB7) || ((0x300 <= cp) && (cp <= 0x36F)) || ((0x203F <= cp) && (cp <= 0x2040)) ) return true;
+ return false;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+static inline void VerifyUTF8 ( XMP_StringPtr str )
+{
+ const XMP_Uns8 * utf8Str = (XMP_Uns8*)str;
+ while ( *utf8Str != 0 ) {
+ while ( (*utf8Str != 0) && (*utf8Str < 0x80) ) ++utf8Str;
+ if ( *utf8Str >= 0x80 ) (void) GetCodePoint ( &utf8Str ); // Throws for bad UTF-8.
+ }
+}
+
+// -------------------------------------------------------------------------------------------------
+
+static inline void VerifySimpleXMLName ( XMP_StringPtr _nameStart, XMP_StringPtr _nameEnd )
+{
+
+ const XMP_Uns8 * nameStart = (const XMP_Uns8 *) _nameStart;
+ const XMP_Uns8 * nameEnd = (const XMP_Uns8 *) _nameEnd;
+ const XMP_Uns8 * namePos = nameStart;
+ XMP_Uns32 cp;
+
+ // The first character is more restricted.
+
+ if ( nameStart >= nameEnd ) XMP_Throw ( "Empty XML name", kXMPErr_BadXPath );
+
+ cp = *namePos;
+ if ( cp < 0x80 ) {
+ ++namePos;
+ if ( ! IsStartChar_ASCII(cp) ) goto NameError;
+ } else {
+ cp = GetCodePoint ( &namePos );
+ if ( ! IsStartChar_NonASCII(cp) ) goto NameError;
+ }
+
+ // Check the rest of the name.
+
+ while ( namePos < nameEnd ) {
+ cp = *namePos;
+ if ( cp < 0x80 ) {
+ ++namePos;
+ if ( (! IsStartChar_ASCII(cp)) && (! IsOtherChar_ASCII(cp)) ) goto NameError;
+ } else {
+ cp = GetCodePoint ( &namePos );
+ if ( (! IsStartChar_NonASCII(cp)) && (! IsOtherChar_NonASCII(cp)) ) goto NameError;
+ }
+ }
+
+ return;
+
+NameError:
+ XMP_Throw ( "Bad XML name", kXMPErr_BadXPath );
+
+} // VerifySimpleXMLName
+
+// =================================================================================================
+
+#endif // __UnicodeInlines_incl_cpp__
diff --git a/third-party/MD5/MD5.cpp b/third-party/MD5/MD5.cpp
new file mode 100644
index 0000000..b0aca6d
--- /dev/null
+++ b/third-party/MD5/MD5.cpp
@@ -0,0 +1,325 @@
+#include "MD5.h"
+
+#include <cstring>
+
+using namespace std;
+
+/******************************************************************************/
+
+/*
+ MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
+
+ Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All rights
+ reserved.
+
+ License to copy and use this software is granted provided that it is
+ identified as the "RSA Data Security, Inc. MD5 Message-Digest Algorithm" in
+ all material mentioning or referencing this software or this function.
+
+ License is also granted to make and use derivative works provided that such
+ works are identified as "derived from the RSA Data Security, Inc. MD5
+ Message-Digest Algorithm" in all material mentioning or referencing the
+ derived work.
+
+ RSA Data Security, Inc. makes no representations concerning either the
+ merchantability of this software or the suitability of this software for
+ any particular purpose. It is provided "as is" without express or implied
+ warranty of any kind.
+
+ These notices must be retained in any copies of any part of this
+ documentation and/or software.
+*/
+
+/******************************************************************************/
+
+/* Constants for MD5Transform routine. */
+
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+static void MD5Transform (unsigned long [4], unsigned char [64]);
+static void Encode (unsigned char *, unsigned long *, unsigned int);
+static void Decode (unsigned long *, unsigned char *, unsigned int);
+
+static unsigned char PADDING[64] =
+ {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+
+/* F, G, H and I are basic MD5 functions.
+
+ */
+
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits.
+
+ */
+
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+Rotation is separate from addition to prevent recomputation.
+
+ */
+
+#define FF(a, b, c, d, x, s, ac) { \
+ (a) += F ((b), (c), (d)) + (x) + (unsigned long)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define GG(a, b, c, d, x, s, ac) { \
+ (a) += G ((b), (c), (d)) + (x) + (unsigned long)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define HH(a, b, c, d, x, s, ac) { \
+ (a) += H ((b), (c), (d)) + (x) + (unsigned long)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define II(a, b, c, d, x, s, ac) { \
+ (a) += I ((b), (c), (d)) + (x) + (unsigned long)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+
+/* MD5 initialization. Begins an MD5 operation, writing a new context.
+
+ */
+
+void MD5Init (MD5_CTX * context)
+{
+ context->count[0] = context->count[1] = 0;
+
+ /* Load magic initialization constants.
+
+*/
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xefcdab89;
+ context->state[2] = 0x98badcfe;
+ context->state[3] = 0x10325476;
+}
+
+/* MD5 block update operation. Continues an MD5 message-digest
+ operation, processing another message block, and updating the context.
+
+ */
+
+void MD5Update ( MD5_CTX *context, /* context */
+ unsigned char *input, /* input block */
+ unsigned int inputLen) /* length of input block */
+{
+ using namespace std;
+
+ unsigned int i, index, partLen;
+
+ /* Compute number of bytes mod 64 */
+ index = (unsigned int)((context->count[0] >> 3) & 0x3F);
+
+ /* Update number of bits */
+ if ((context->count[0] += ((unsigned long)inputLen << 3))
+ < ((unsigned long)inputLen << 3))
+ context->count[1]++;
+ context->count[1] += ((unsigned long)inputLen >> 29);
+
+ partLen = 64 - index;
+
+ /* Transform as many times as possible.
+
+*/
+ if (inputLen >= partLen) {
+ std::memcpy (&context->buffer[index], input, partLen);
+ MD5Transform (context->state, context->buffer);
+
+ for (i = partLen; i + 63 < inputLen; i += 64)
+ MD5Transform (context->state, &input[i]);
+
+ index = 0;
+ }
+ else
+ i = 0;
+
+ /* Buffer remaining input */
+ std::memcpy (&context->buffer[index], &input[i], inputLen-i);
+
+}
+
+/* MD5 finalization. Ends an MD5 message-digest operation, writing the
+ the message digest and zeroizing the context.
+
+ */
+
+void MD5Final ( unsigned char digest[16], /* message digest */
+ MD5_CTX *context /* context */)
+{
+ unsigned char bits[8];
+ unsigned int index, padLen;
+
+ /* Save number of bits */
+ Encode (bits, context->count, 8);
+
+ /* Pad out to 56 mod 64.
+
+*/
+ index = (unsigned int)((context->count[0] >> 3) & 0x3f);
+ padLen = (index < 56) ? (56 - index) : (120 - index);
+ MD5Update (context, PADDING, padLen);
+
+ /* Append length (before padding) */
+ MD5Update (context, bits, 8);
+ /* Store state in digest */
+ Encode (digest, context->state, 16);
+
+ /* Zeroize sensitive information.
+
+*/
+ memset (context, 0, sizeof (*context));
+}
+
+/* MD5 basic transformation. Transforms state based on block.
+
+ */
+
+static void MD5Transform ( unsigned long state[4],
+ unsigned char block[64])
+{
+ unsigned long a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+
+ Decode (x, block, 64);
+
+ /* Round 1 */
+ FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
+ FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
+ FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
+ FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
+ FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
+ FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
+ FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
+ FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
+ FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
+ FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
+ FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+ FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+ FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+ FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+ FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+ FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+
+ /* Round 2 */
+ GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
+ GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
+ GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+ GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
+ GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
+ GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
+ GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+ GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
+ GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
+ GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+ GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
+ GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
+ GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+ GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
+ GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
+ GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+
+ /* Round 3 */
+ HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
+ HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
+ HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+ HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+ HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
+ HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
+ HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
+ HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+ HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+ HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
+ HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
+ HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
+ HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
+ HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+ HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+ HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
+
+ /* Round 4 */
+ II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
+ II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
+ II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+ II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
+ II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+ II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
+ II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+ II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
+ II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
+ II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+ II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
+ II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+ II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
+ II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+ II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
+ II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
+
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+
+ /* Zeroize sensitive information.
+*/
+ memset (x, 0, sizeof (x));
+}
+
+/* Encodes input (unsigned long) into output (unsigned char). Assumes len is
+ a multiple of 4.
+
+ */
+
+static void Encode ( unsigned char *output,
+ unsigned long *input,
+ unsigned int len)
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4) {
+ output[j] = (unsigned char)(input[i] & 0xff);
+ output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
+ output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
+ output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
+ }
+}
+
+/* Decodes input (unsigned char) into output (unsigned long). Assumes len is
+ a multiple of 4.
+
+ */
+
+static void Decode ( unsigned long *output,
+ unsigned char *input,
+ unsigned int len)
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4)
+ output[i] = ((unsigned long)input[j]) | (((unsigned long)input[j+1]) << 8) |
+ (((unsigned long)input[j+2]) << 16) | (((unsigned long)input[j+3]) << 24);
+}
diff --git a/third-party/MD5/MD5.h b/third-party/MD5/MD5.h
new file mode 100644
index 0000000..666f535
--- /dev/null
+++ b/third-party/MD5/MD5.h
@@ -0,0 +1,46 @@
+#ifndef __MD5_h__
+#define __MD5_h__
+
+/******************************************************************************/
+
+/*
+ MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
+
+ Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All rights
+ reserved.
+
+ License to copy and use this software is granted provided that it is
+ identified as the "RSA Data Security, Inc. MD5 Message-Digest Algorithm" in
+ all material mentioning or referencing this software or this function.
+
+ License is also granted to make and use derivative works provided that such
+ works are identified as "derived from the RSA Data Security, Inc. MD5
+ Message-Digest Algorithm" in all material mentioning or referencing the
+ derived work.
+
+ RSA Data Security, Inc. makes no representations concerning either the
+ merchantability of this software or the suitability of this software for
+ any particular purpose. It is provided "as is" without express or implied
+ warranty of any kind.
+
+ These notices must be retained in any copies of any part of this
+ documentation and/or software.
+*/
+
+/******************************************************************************/
+
+/* MD5 context. */
+struct MD5_CTX
+ {
+ unsigned long state[4]; /* state (ABCD) */
+ unsigned long count[2]; /* number of bits, modulo 2^64 (lsb first) */
+ unsigned char buffer[64]; /* input buffer */
+ };
+
+extern void MD5Init (MD5_CTX *);
+extern void MD5Update (MD5_CTX *, unsigned char *, unsigned int);
+extern void MD5Final(unsigned char [16], MD5_CTX *);
+
+/******************************************************************************/
+
+#endif
diff --git a/third-party/QTDevWin/ReadMe.txt b/third-party/QTDevWin/ReadMe.txt
new file mode 100644
index 0000000..9ec8657
--- /dev/null
+++ b/third-party/QTDevWin/ReadMe.txt
@@ -0,0 +1,12 @@
+The XMP Files handler for .mov files uses QuickTime.
+This will always be available for build and use on Macintosh.
+For Windows, Apple's QuickTime SDK version 7 and above is needed to build XMP Files
+and the public QuickTime Player is needed in order to use XMPFiles for .mov files.
+The QuickTime Player also installs the necessary QuickTime library.
+
+To build XMP Files for Windows, first obtain a copy of the QuickTime SDK for Windows from
+ http://developer.apple.com/sdk/
+
+Unpack the SDK to any convenient location. Copy the contained CIncludes and Libraries folders
+to the XMP development tree under .../third-party/QTWinDev.
+That is, the CIncludes and Libraries folders should appear as siblings of this ReadMe.txt file.
diff --git a/third-party/expat/ReadMe.txt b/third-party/expat/ReadMe.txt
new file mode 100644
index 0000000..7cfef15
--- /dev/null
+++ b/third-party/expat/ReadMe.txt
@@ -0,0 +1,38 @@
+The XMP Toolkit needs an external XML parser. The source from Adobe is written to use Expat,
+although adapters for other parsers can easily be written. The most recent version of Expat used
+with XMP is 2.0.0. To use Expat:
+
+1. Obtain a copy of the Expat distribution. One good place is SourceForge:
+ http://sourceforge.net/projects/expat/
+
+2. Place Expat's lib directory within .../third-party/expat. I.e. as a sibling of this file.
+
+For Expat version 2.0.0 the contents of .../third-party/expat/lib are:
+
+ amigaconfig.h
+ ascii.h
+ asciitab.h
+ expat.dsp
+ expat.h
+ expatw.dsp
+ expatw_static.dsp
+ expat_external.h
+ expat_static.dsp
+ iasciitab.h
+ internal.h
+ latin1tab.h
+ libexpat.def
+ libexpatw.def
+ macconfig.h
+ Makefile.MPW
+ nametab.h
+ utf8tab.h
+ winconfig.h
+ xmlparse.c
+ xmlrole.c
+ xmlrole.h
+ xmltok.c
+ xmltok.h
+ xmltok_impl.c
+ xmltok_impl.h
+ xmltok_ns.c