diff options
author | Hubert Figuière <hub@figuiere.net> | 2016-12-07 00:03:00 -0500 |
---|---|---|
committer | Hubert Figuière <hub@figuiere.net> | 2016-12-07 00:04:31 -0500 |
commit | 6071af09b5e263b63e57b28ab8a78484bc65e3fe (patch) | |
tree | 45f97ac82e5582684d889ede0fdacaf2c6eddf2e /samples/source | |
parent | 606a7df73750084a36fe69651e7b672333a76412 (diff) |
Update to XMP SDK CC 2016.07
Diffstat (limited to 'samples/source')
23 files changed, 1995 insertions, 38 deletions
diff --git a/samples/source/AML_AddComponent.cpp b/samples/source/AML_AddComponent.cpp new file mode 100644 index 0000000..2713340 --- /dev/null +++ b/samples/source/AML_AddComponent.cpp @@ -0,0 +1,203 @@ +// ================================================================================================= +// Copyright 2008 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. +// ================================================================================================= + +/** +* Tutorial solution for the AssetRelationships.pdf. Creating generic parts, parts, AssetManager +* for composed document. Demonstrate the use of AddComponent() for composite document and parts. +*/ + +#include <cstdio> +#include <vector> +#include <string> +#include <cstring> +#include <fstream> +#include <iostream> + +// Must be defined to instantiate template classes +#define TXMP_STRING_TYPE std::string + +// Must be defined to give access to XMPFiles +#define XMP_INCLUDE_XMPFILES 0 + +#define ENABLE_NEW_DOM_MODEL 1 + +#include "XMPCore/Interfaces/IXMPDOMImplementationRegistry.h" +#include "XMPCore/Interfaces/IXMPDOMParser.h" +#include "XMPCore/Interfaces/IXMPDOMSerializer.h" +#include "XMPCore/Interfaces/IXMPMetadata.h" +#include "XMPCore/Interfaces/IXMPCoreObjectFactory.h" +#include "XMPCore/Interfaces/IXMPSimpleNode.h" +#include "XMPCore/Interfaces/IXMPStructureNode.h" + +// Ensure XMP templates are instantiated +#include "public/include/XMP.incl_cpp" + +// Provide access to the API +#include "public/include/XMP.hpp" + + +#include "XMPAssetManagement/XMPAssetManagementDefines.h" +#include "XMPAssetManagement/XMPAssetManagementFwdDeclarations.h" +#include "XMPCore/Interfaces/IXMPMetadata.h" +#include "XMPCommon/Interfaces/IUTF8String.h" +#include "XMPAssetManagement/XMPAssetManagement.h" +#include "XMPAssetManagement/Interfaces/IAssetUtilities.h" +#include "XMPAssetManagement/Interfaces/IAssetPart.h" +#include "XMPAssetManagement/Interfaces/IComposedAssetManager.h" +#include "XMPAssetManagement/Interfaces/ICompositionRelationship.h" +#include "XMPCore/Interfaces/IXMPCoreObjectFactory.h" +#include "XMPAssetManagement/XMPAssetManagementFwdDeclarations.h" + +using namespace std; + +static string GetStringFromFile(string& filename) +{ + string buffer; + string line; + + ifstream in(filename); + if (in.is_open()) { + while (getline(in, line)) + buffer = buffer + "\n" + line; + in.close(); + } + return buffer; +} + +void static SerializeIXMPMetadata(NS_XMPCORE::spIXMPMetadata imetadata, string outfile = "") +{ + NS_XMPCORE::spIXMPDOMImplementationRegistry DOMRegistry = NS_XMPCORE::IXMPDOMImplementationRegistry::GetDOMImplementationRegistry(); + NS_XMPCORE::spIXMPDOMSerializer DOMSerializer = DOMRegistry->CreateSerializer("rdf"); + std::string targetfilebuffer = DOMSerializer->Serialize(imetadata)->c_str(); + + //std::cout << targetfilebuffer << std::endl; + + //write into file + if (!outfile.empty()) { + ofstream out(outfile); + if (out.is_open()) { + out << targetfilebuffer; + out.close(); + } + } +} + +NS_XMPCORE::spIXMPMetadata static GetIXMPMetadataFromRDF(string filename) +{ + string buffer = GetStringFromFile(filename); + + NS_XMPCORE::spIXMPDOMImplementationRegistry DOMRegistry = NS_XMPCORE::IXMPDOMImplementationRegistry::GetDOMImplementationRegistry(); + NS_XMPCORE::spIXMPDOMParser DOMParser = DOMRegistry->CreateParser("rdf"); + + NS_XMPCORE::spIXMPMetadata ixmpmeta = DOMParser->Parse(buffer.c_str()); + + return ixmpmeta; + +} + + +/** +* Initializes the toolkit (XMPCore, XMPFiles & XMPAssetManagement and attempts to open a file +* for reading metadata. Initially an attempt to open the file is done with a handler, if this +* fails then the file is opened with packet scanning. Once opened, meta is obtained, from meta +* ixmpmeta (DOM based Metadata object) is get. AssetManagement object is created from composed +* ixmpmeta and a relationship is added into it. And later verifies for the same from ingredient +* entry. +*/ + +int main ( int argc, const char * argv[] ) +{ + string composed_file = "AddBasicPart_InSimpleDocument_input_composite_doc.xmp"; + string component_file = "AddBasicPart_InSimpleDocument_input_component_doc.xmp"; + string composed_out_file = "AddBasicPart_InSimpleDocument_OUTPUT_composite_doc.xmp"; + + if (!SXMPMeta::Initialize()) + { + cout << "Could not initialize toolkit!"; + return -1; + } + + NS_XMPCORE::spIXMPMetadata& component_ixmp_meta = GetIXMPMetadataFromRDF(component_file); + NS_XMPCORE::spIXMPMetadata& composed_ixmp_meta = GetIXMPMetadataFromRDF(composed_file); + // Create the xmp object and get the xmp data + //componentFile.GetXMP(&component_sxmp_meta); + + //Get IXMPMeta from SXMPMetadata + //component_ixmp_meta = component_sxmp_meta.GetIXMPMetadata(); + + //for both the files, metadata has been obtained, get IXMPMeta from SXMPMeta + NS_XMPCORE::pIXMPCoreObjectFactory factoryObj = NS_XMPCORE::IXMPCoreObjectFactory::GetInstance(); + NS_XMPASSETMANAGEMENT::XMPAM_ClientInitialize(); + + //create a standard generic part + NS_XMPASSETMANAGEMENT::spIAssetPart composedassetpart = NS_XMPASSETMANAGEMENT::IAssetPart::CreateStandardGenericPart(NS_XMPASSETMANAGEMENT::IAssetPart_v1::kAssetPartComponentMetadata); + + //create standard generic part + NS_XMPASSETMANAGEMENT::spIAssetPart componentassetpart = NS_XMPASSETMANAGEMENT::IAssetPart::CreateStandardGenericPart(NS_XMPASSETMANAGEMENT::IAssetPart_v1::kAssetPartComponentContent); + + + //Check if composed / component is not trackable, make it + NS_XMPASSETMANAGEMENT::pIAssetUtilities utilityObj = NS_XMPASSETMANAGEMENT::IAssetUtilities::GetAssetUtilities(); + if (utilityObj->IsTrackable(composed_ixmp_meta) == false) + utilityObj->MakeTrackable(composed_ixmp_meta); + + if (utilityObj->IsTrackable(component_ixmp_meta) == false) + utilityObj->MakeTrackable(component_ixmp_meta); + + + //creating ComposedAssetManager + NS_XMPASSETMANAGEMENT::spIComposedAssetManager composedAsset = NS_XMPASSETMANAGEMENT::IComposedAssetManager::CreateComposedAssetManager(composed_ixmp_meta); + + //call AddComponent API (toPart, from ixmpmeta, fromPart) to compose fromPart into composed doc at toPart + const NS_XMPCORE::spcIXMPStructureNode & component = component_ixmp_meta; + + NS_XMPCORE::spcIXMPSimpleNode xmpMMInstanceIDNode = dynamic_pointer_cast<const NS_XMPCORE::IXMPSimpleNode>(component->GetNode(kXMP_NS_XMP_MM, "InstanceID")); + + NS_XMPASSETMANAGEMENT::spICompositionRelationship relationshipNode = composedAsset->AddComponent(composedassetpart, component_ixmp_meta, componentassetpart); + + //verify toPart and ComponentPart form Ingredients entry + NS_XMPASSETMANAGEMENT::spIXMPArrayNode spComposedIngredientsNode = NS_XMPCORE::dynamic_pointer_cast<NS_XMPCORE::IXMPArrayNode>(composed_ixmp_meta->GetNode(kXMP_NS_XMP_MM, "Ingredients")); + NS_XMPCORE::spIXMPStructureNode IngredientEntrynode = NS_XMPCORE::dynamic_pointer_cast<NS_XMPCORE::IXMPStructureNode>(spComposedIngredientsNode->GetNode(1)); + + NS_XMPCORE::spIXMPSimpleNode node = NS_XMPCORE::dynamic_pointer_cast<NS_XMPCORE::IXMPSimpleNode>(IngredientEntrynode->GetNode(kXMP_NS_XMP_ResourceRef, "toPart")); + std::string toPartString = node->GetValue()->c_str(); + node = NS_XMPCORE::dynamic_pointer_cast<NS_XMPCORE::IXMPSimpleNode>(IngredientEntrynode->GetNode(kXMP_NS_XMP_ResourceRef, "fromPart")); + std::string fromPartString = node->GetValue()->c_str(); + + //A relationship is mapping to a single entry in Ingredients. A relationship of composed assest's + //toPart, from ixmpmeta & fromPart has been created, add some more property using the relationship. + relationshipNode->SetComponentFilePath("/basefolder/subfolder/composedpath"); + relationshipNode->SetMappingFunctionName("linear"); + relationshipNode->SetMaskMarkersFlag(NS_XMPASSETMANAGEMENT::ICompositionRelationship::kCompositionMaskMarkersAll); + + //Get the stRef:filePath + node = NS_XMPCORE::dynamic_pointer_cast<NS_XMPCORE::IXMPSimpleNode>(IngredientEntrynode->GetNode(kXMP_NS_XMP_ResourceRef, "filePath")); + std::string filePathString = node->GetValue()->c_str(); + cout << "stRef:filePath is " << filePathString.c_str() << endl; + + //get the stRef:partMapping + node = NS_XMPCORE::dynamic_pointer_cast<NS_XMPCORE::IXMPSimpleNode>(IngredientEntrynode->GetNode(kXMP_NS_XMP_ResourceRef, "partMapping")); + std::string partMappingString = node->GetValue()->c_str(); + cout << "stRef:partMapping is " << partMappingString.c_str() << endl; + + node = NS_XMPCORE::dynamic_pointer_cast<NS_XMPCORE::IXMPSimpleNode>(IngredientEntrynode->GetNode(kXMP_NS_XMP_ResourceRef, "maskMarkers")); + std::string maskMarkersString = node->GetValue()->c_str(); + cout << "stRef:makMarkers is " << maskMarkersString.c_str() << endl; + + //verify the added node from pantry + SerializeIXMPMetadata(composed_ixmp_meta, composed_out_file); + + NS_XMPASSETMANAGEMENT::XMPAM_ClientTerminate(); + + // Terminate the toolkit + SXMPMeta::Terminate(); + + + return 0; +} + diff --git a/samples/source/AML_AddTimePartComponent.cpp b/samples/source/AML_AddTimePartComponent.cpp new file mode 100644 index 0000000..dde904e --- /dev/null +++ b/samples/source/AML_AddTimePartComponent.cpp @@ -0,0 +1,191 @@ +// ================================================================================================= +// Copyright 2008 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. +// ================================================================================================= + +/** +* Tutorial solution for the AssetRelationships.pdf. Demonstration of time part, how it's created, +* it's values are set and how it is added into composed document using AddComponent. +*/ + +#include <cstdio> +#include <vector> +#include <string> +#include <cstring> +#include <fstream> +#include <iostream> + +// Must be defined to instantiate template classes +#define TXMP_STRING_TYPE std::string + +// Must be defined to give access to XMPFiles +#define XMP_INCLUDE_XMPFILES 0 + +#define ENABLE_NEW_DOM_MODEL 1 + +#include "XMPCore/Interfaces/IXMPDOMImplementationRegistry.h" +#include "XMPCore/Interfaces/IXMPDOMParser.h" +#include "XMPCore/Interfaces/IXMPDOMSerializer.h" +#include "XMPCore/Interfaces/IXMPMetadata.h" +#include "XMPCore/Interfaces/IXMPCoreObjectFactory.h" +#include "XMPCore/Interfaces/IXMPSimpleNode.h" +#include "XMPCore/Interfaces/IXMPStructureNode.h" + +// Ensure XMP templates are instantiated +#include "public/include/XMP.incl_cpp" + +// Provide access to the API +#include "public/include/XMP.hpp" + +#include "XMPAssetManagement/XMPAssetManagementDefines.h" +#include "XMPAssetManagement/XMPAssetManagementFwdDeclarations.h" +#include "XMPCore/Interfaces/IXMPMetadata.h" +#include "XMPCommon/Interfaces/IUTF8String.h" +#include "XMPAssetManagement/XMPAssetManagement.h" +#include "XMPAssetManagement/Interfaces/IAssetUtilities.h" +#include "XMPAssetManagement/Interfaces/IAssetPart.h" +//time part +#include "XMPAssetManagement/Interfaces/IAssetTimePart.h" + +#include "XMPAssetManagement/Interfaces/IComposedAssetManager.h" +#include "XMPAssetManagement/Interfaces/ICompositionRelationship.h" +#include "XMPCore/Interfaces/IXMPCoreObjectFactory.h" +#include "XMPAssetManagement/XMPAssetManagementFwdDeclarations.h" + +using namespace std; + +static string GetStringFromFile(string& filename) +{ + string buffer; + string line; + + ifstream in(filename); + if (in.is_open()) { + while (getline(in, line)) + buffer = buffer + "\n" + line; + in.close(); + } + return buffer; +} + +void static SerializeIXMPMetadata(NS_XMPCORE::spIXMPMetadata imetadata, string outfile = "") +{ + NS_XMPCORE::spIXMPDOMImplementationRegistry DOMRegistry = NS_XMPCORE::IXMPDOMImplementationRegistry::GetDOMImplementationRegistry(); + NS_XMPCORE::spIXMPDOMSerializer DOMSerializer = DOMRegistry->CreateSerializer("rdf"); + std::string targetfilebuffer = DOMSerializer->Serialize(imetadata)->c_str(); + + //std::cout << targetfilebuffer << std::endl; + + //write into file + if (!outfile.empty()) { + ofstream out(outfile); + if (out.is_open()) { + out << targetfilebuffer; + out.close(); + } + } +} + +NS_XMPCORE::spIXMPMetadata static GetIXMPMetadataFromRDF(string filename) +{ + string buffer = GetStringFromFile(filename); + + NS_XMPCORE::spIXMPDOMImplementationRegistry DOMRegistry = NS_XMPCORE::IXMPDOMImplementationRegistry::GetDOMImplementationRegistry(); + NS_XMPCORE::spIXMPDOMParser DOMParser = DOMRegistry->CreateParser("rdf"); + + NS_XMPCORE::spIXMPMetadata ixmpmeta = DOMParser->Parse(buffer.c_str()); + + return ixmpmeta; + +} + + + +/** +* Initializes the toolkit (XMPCore, XMPFiles & XMPAssetManagement and attempts to open a file +* for reading metadata. Initially an attempt to open the file is done with a handler, if this +* fails then the file is opened with packet scanning. Once opened, meta is obtained, from meta +* ixmpmeta (DOM based Metadata object) is get. A time part is created, it's values are set, +* and later used in AddComponent for composition. +*/ + +int main(int argc, const char * argv[]) +{ + string composed_file = "AddBasicPart_InSimpleDocument_input_composite_doc.xmp"; + string component_file = "AddBasicPart_InSimpleDocument_input_component_doc.xmp"; + string outfilename = "AML_TimePartAddition_Sample_OutPut.xmp"; + + if (!SXMPMeta::Initialize()) + { + cout << "Could not initialize toolkit!"; + return -1; + } + + NS_XMPCORE::spIXMPMetadata& composed_ixmp_meta = GetIXMPMetadataFromRDF(composed_file); + NS_XMPCORE::spIXMPMetadata& component_ixmp_meta = GetIXMPMetadataFromRDF(component_file); + + + //for both the files, metadata has been obtained, get IXMPMeta from SXMPMeta + NS_XMPCORE::pIXMPCoreObjectFactory factoryObj = NS_XMPCORE::IXMPCoreObjectFactory::GetInstance(); + NS_XMPASSETMANAGEMENT::XMPAM_ClientInitialize(); + + //Check if composed / component is not trackable, make it + NS_XMPASSETMANAGEMENT::pIAssetUtilities utilityObj = NS_XMPASSETMANAGEMENT::IAssetUtilities::GetAssetUtilities(); + if (utilityObj->IsTrackable(composed_ixmp_meta) == false) + utilityObj->MakeTrackable(composed_ixmp_meta); + if (utilityObj->IsTrackable(component_ixmp_meta) == false) + utilityObj->MakeTrackable(component_ixmp_meta); + + //create a time toPart + NS_XMPCOMMON::UInt64 toPartStartFrameCount = 0, toPartStartNumerator = 80, toPartStartBaseRate = 20; + NS_XMPCOMMON::UInt64 toPartDurationFrameCount = 2000, toPartDurationNumerator = 80, toPartDurationBaseRate = 20; + NS_XMPASSETMANAGEMENT::spIAssetTimePart composedassettimepart = NS_XMPASSETMANAGEMENT::IAssetTimePart::CreateStandardTimePart(NS_XMPASSETMANAGEMENT::IAssetPart_v1::kAssetPartComponentMetadata); + composedassettimepart->SetFrameCountDuration(toPartStartFrameCount, toPartDurationFrameCount); + composedassettimepart->SetFrameRateForCountOfFrames(toPartStartNumerator, toPartStartBaseRate); + composedassettimepart->SetFrameRateForStartFrameCount(toPartDurationNumerator, toPartDurationBaseRate); + + //component/fromPart + NS_XMPCOMMON::UInt64 fromPartStartFrameCount = 5000, fromPartStartNumerator = 80, fromPartStartBaseRate = 20; + NS_XMPCOMMON::UInt64 fromPartDurationFrameCount = 2000, fromPartDurationNumerator = 80, fromPartDurationBaseRate = 20; + NS_XMPASSETMANAGEMENT::spIAssetTimePart componentassettimepart = NS_XMPASSETMANAGEMENT::IAssetTimePart::CreateStandardTimePart(NS_XMPASSETMANAGEMENT::IAssetPart_v1::kAssetPartComponentAudio); + componentassettimepart->SetFrameCountDuration(fromPartStartFrameCount, fromPartDurationFrameCount); + componentassettimepart->SetFrameRateForCountOfFrames(fromPartStartNumerator, fromPartStartBaseRate); + componentassettimepart->SetFrameRateForStartFrameCount(fromPartDurationNumerator, fromPartDurationBaseRate); + + //creating ComposedAssetManager + NS_XMPASSETMANAGEMENT::spIComposedAssetManager composedAsset = NS_XMPASSETMANAGEMENT::IComposedAssetManager::CreateComposedAssetManager(composed_ixmp_meta); + + //call AddComponent API (toPart, from ixmpmeta, fromPart) to compose fromPart into composed doc at toPart + //on calling the AddComponent, following will be entry in ingredient + //<stRef:toPart>/metadata/time:0f80s20d2000f80s80 + //<stRef:fromPart>/content/audio/time:5000f80s20d2000f80s80 + //for detail time format refer to XMP Specification Part 2 : Additional Properties sector 1.2.6.4 FrameRate + NS_XMPASSETMANAGEMENT::spICompositionRelationship relationshipNode = composedAsset->AddComponent(composedassettimepart, component_ixmp_meta, componentassettimepart); + //a mapping function + relationshipNode->SetMappingFunctionName("linear"); + + //assuming there are not ingredient entry, if there is fix the index, or iterate using iterator + //verify toPart and ComponentPart form Ingredients entry + NS_XMPASSETMANAGEMENT::spIXMPArrayNode spComposedIngredientsNode = NS_XMPCORE::dynamic_pointer_cast<NS_XMPCORE::IXMPArrayNode>(composed_ixmp_meta->GetNode(kXMP_NS_XMP_MM, "Ingredients")); + NS_XMPCORE::spIXMPStructureNode IngredientEntrynode = NS_XMPCORE::dynamic_pointer_cast<NS_XMPCORE::IXMPStructureNode>(spComposedIngredientsNode->GetNode(1)); + + NS_XMPCORE::spIXMPSimpleNode node = NS_XMPCORE::dynamic_pointer_cast<NS_XMPCORE::IXMPSimpleNode>(IngredientEntrynode->GetNode(kXMP_NS_XMP_ResourceRef, "toPart")); + std::string toPartString = node->GetValue()->c_str(); + node = NS_XMPCORE::dynamic_pointer_cast<NS_XMPCORE::IXMPSimpleNode>(IngredientEntrynode->GetNode(kXMP_NS_XMP_ResourceRef, "fromPart")); + std::string fromPartString = node->GetValue()->c_str(); + + //verify the added node from pantry + + SerializeIXMPMetadata(composed_ixmp_meta, outfilename); + + NS_XMPASSETMANAGEMENT::XMPAM_ClientTerminate(); + + SXMPMeta::Terminate(); + + + return 0; +} + diff --git a/samples/source/AML_SearchAndDeleteComponent.cpp b/samples/source/AML_SearchAndDeleteComponent.cpp new file mode 100644 index 0000000..6fedcf7 --- /dev/null +++ b/samples/source/AML_SearchAndDeleteComponent.cpp @@ -0,0 +1,205 @@ +// ================================================================================================= +// Copyright 2008 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. +// ================================================================================================= + +/** +* Tutorial solution for the AssetRelationships.pdf. An AssetManagement Object is created from +* composed metadata. Then a part is used for deleting all the relationship from composed Asset. +*/ + +#include <cstdio> +#include <vector> +#include <string> +#include <cstring> +#include <fstream> +#include <iostream> + +// Must be defined to instantiate template classes +#define TXMP_STRING_TYPE std::string + +// Must be defined to give access to XMPFiles +#define XMP_INCLUDE_XMPFILES 0 + +#define ENABLE_NEW_DOM_MODEL 1 + +#include "XMPCore/Interfaces/IXMPDOMImplementationRegistry.h" +#include "XMPCore/Interfaces/IXMPDOMParser.h" +#include "XMPCore/Interfaces/IXMPDOMSerializer.h" +#include "XMPCore/Interfaces/IXMPMetadata.h" +#include "XMPCore/Interfaces/IXMPCoreObjectFactory.h" +#include "XMPCore/Interfaces/IXMPSimpleNode.h" +#include "XMPCore/Interfaces/IXMPStructureNode.h" + +// Ensure XMP templates are instantiated +#include "public/include/XMP.incl_cpp" + +// Provide access to the API +#include "public/include/XMP.hpp" + +#include "XMPAssetManagement/XMPAssetManagementDefines.h" +#include "XMPAssetManagement/XMPAssetManagementFwdDeclarations.h" +#include "XMPCore/Interfaces/IXMPMetadata.h" +#include "XMPCommon/Interfaces/IUTF8String.h" +#include "XMPAssetManagement/XMPAssetManagement.h" +#include "XMPAssetManagement/Interfaces/IAssetUtilities.h" +#include "XMPAssetManagement/Interfaces/IAssetPart.h" +#include "XMPAssetManagement/Interfaces/IComposedAssetManager.h" +#include "XMPAssetManagement/Interfaces/ICompositionRelationship.h" +#include "XMPCore/Interfaces/IXMPCoreObjectFactory.h" +#include "XMPAssetManagement/XMPAssetManagementFwdDeclarations.h" + +using namespace std; + +static string GetStringFromFile(string filename) +{ + string buffer; + string line; + + ifstream in(filename); + if (in.is_open()) { + while (getline(in, line)) + buffer = buffer + "\n" + line; + in.close(); + } + else { + cout << "Connot open file for converting into string\n"; + } + return buffer; +} + +void static SerializeIXMPMetadata(NS_XMPCORE::spIXMPMetadata imetadata, string outfile = "") +{ + NS_XMPCORE::spIXMPDOMImplementationRegistry DOMRegistry = NS_XMPCORE::IXMPDOMImplementationRegistry::GetDOMImplementationRegistry(); + NS_XMPCORE::spIXMPDOMSerializer DOMSerializer = DOMRegistry->CreateSerializer("rdf"); + std::string targetfilebuffer = DOMSerializer->Serialize(imetadata)->c_str(); + + //std::cout << targetfilebuffer << std::endl; + + //write into file + if (!outfile.empty()) { + ofstream out(outfile); + if (out.is_open()) { + out << targetfilebuffer; + out.close(); + } + } +} + +NS_XMPCORE::spIXMPMetadata static GetIXMPMetadataFromRDF(string filename) +{ + string buffer = GetStringFromFile(filename); + + NS_XMPCORE::spIXMPDOMImplementationRegistry DOMRegistry = NS_XMPCORE::IXMPDOMImplementationRegistry::GetDOMImplementationRegistry(); + NS_XMPCORE::spIXMPDOMParser DOMParser = DOMRegistry->CreateParser("rdf"); + + NS_XMPCORE::spIXMPMetadata ixmpmeta = DOMParser->Parse(buffer.c_str()); + + return ixmpmeta; + +} + + +/** +* Initializes the toolkit (XMPCore, XMPFiles & XMPAssetManagement and attempts to open a file +* for reading metadata. Initially an attempt to open the file is done with a handler, if this +* fails then the file is opened with packet scanning. Once opened, meta is obtained, from meta +* ixmpmeta (DOM based Metadata object) is get. AssetManagement object is created from composed +* ixmpmeta (the above ixmpmetadata). A part is created and used for search & deletion of that +* part from relationship. +*/ + +int main(int argc, const char * argv[]) +{ + string composed_file = "AML_SearchAndDelete_Sample_Input.xmp"; + string composed_out_file = "AML_SearchAndDelete_Sample_Output.xmp"; + + if (!SXMPMeta::Initialize()) + { + cout << "Could not initialize toolkit!"; + return -1; + } + NS_XMPCORE::spIXMPMetadata& composed_ixmp_meta = GetIXMPMetadataFromRDF(composed_file); + + + //for both the files, metadata has been obtained, get IXMPMeta from SXMPMeta + NS_XMPCORE::pIXMPCoreObjectFactory factoryObj = NS_XMPCORE::IXMPCoreObjectFactory::GetInstance(); + NS_XMPASSETMANAGEMENT::XMPAM_ClientInitialize(); + + //Check if composed / component is not trackable, make it + NS_XMPASSETMANAGEMENT::pIAssetUtilities utilityObj = NS_XMPASSETMANAGEMENT::IAssetUtilities::GetAssetUtilities(); + if (utilityObj->IsTrackable(composed_ixmp_meta) == false) + utilityObj->MakeTrackable(composed_ixmp_meta); + + //composed/toPart + NS_XMPASSETMANAGEMENT::spIAssetPart composedassetpart = NS_XMPASSETMANAGEMENT::IAssetPart::CreateStandardGenericPart(NS_XMPASSETMANAGEMENT::IAssetPart_v1::kAssetPartComponentMetadata); + + //creating ComposedAssetManager + NS_XMPASSETMANAGEMENT::spIComposedAssetManager composedAsset = NS_XMPASSETMANAGEMENT::IComposedAssetManager::CreateComposedAssetManager(composed_ixmp_meta); + + //Get list of all relationship and traverse it + NS_XMPASSETMANAGEMENT::spcICompositionRelationshipList relationshipNodes = composedAsset->GetAllRelationships(); + for (NS_XMPASSETMANAGEMENT::cICompositionRelationshipList::iterator it = relationshipNodes->begin(); it != relationshipNodes->end(); ++it) { + //get part for part specific data + NS_XMPASSETMANAGEMENT::spcIAssetPart assetPart = (*it)->GetComponentPart(); + + switch (assetPart->GetType()) { + case NS_XMPASSETMANAGEMENT::IAssetPart_v1::kAssetPartTypeGeneric: + cout << "Part type is NS_XMPASSETMANAGEMENT::IAssetPart_v1::kAssetPartTypeGeneric"; + break; + case NS_XMPASSETMANAGEMENT::IAssetPart_v1::kAssetPartTypeTime: + cout << "Part type is NS_XMPASSETMANAGEMENT::IAssetPart_v1::kAssetPartTypeTime"; + break; + case NS_XMPASSETMANAGEMENT::IAssetPart_v1::kAssetPartTypeArtboard: + cout << "Part type is NS_XMPASSETMANAGEMENT::IAssetPart_v1::kAssetPartTypeArtboard"; + break; + case NS_XMPASSETMANAGEMENT::IAssetPart_v1::kAssetPartTypeLayer: + cout << "Part type is NS_XMPASSETMANAGEMENT::IAssetPart_v1::kAssetPartTypeLayer"; + break; + case NS_XMPASSETMANAGEMENT::IAssetPart_v1::kAssetPartTypePage: + cout << "Part type is NS_XMPASSETMANAGEMENT::IAssetPart_v1::kAssetPartTypePage"; + break; + default: + ; + } + //get other relationship properties + NS_XMPCOMMON::spcIUTF8String filepath = (*it)->GetComponentFilePath(); + } + + + //call GetRelationships(toPart) to get all relationship which matches a part value, and traverse it + relationshipNodes = composedAsset->GetRelationships(composedassetpart); + for (NS_XMPASSETMANAGEMENT::cICompositionRelationshipList::iterator it = relationshipNodes->begin(); it != relationshipNodes->end(); ++it) { + //get part for part specific data + NS_XMPASSETMANAGEMENT::spcIAssetPart assetPart = (*it)->GetComponentPart(); + + //get other relationship properties + NS_XMPCOMMON::spcIUTF8String filepath = (*it)->GetComponentFilePath(); + } + + ////// Remove relationship which maches the part + composedAsset->RemoveComponents(composedassetpart); + + //Get all the relationship and check verify all the Relationship having the above part must not be present + relationshipNodes = composedAsset->GetAllRelationships(); + for (NS_XMPASSETMANAGEMENT::cICompositionRelationshipList::iterator it = relationshipNodes->begin(); it != relationshipNodes->end(); ++it) { + //get part for part specific data + NS_XMPASSETMANAGEMENT::spcIAssetPart assetPart = (*it)->GetComponentPart(); + + //get other relationship properties + NS_XMPCOMMON::spcIUTF8String filepath = (*it)->GetComponentFilePath(); + } + + //verify the added node from pantry + SerializeIXMPMetadata(composed_ixmp_meta, composed_out_file); + + NS_XMPASSETMANAGEMENT::XMPAM_ClientTerminate(); + + SXMPMeta::Terminate(); + + return 0; +} + diff --git a/samples/source/AML_Trackable.cpp b/samples/source/AML_Trackable.cpp new file mode 100644 index 0000000..091b468 --- /dev/null +++ b/samples/source/AML_Trackable.cpp @@ -0,0 +1,164 @@ +// ================================================================================================= +// Copyright 2008 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. +// ================================================================================================= + +/** +* Tutorial solution for the Walkthrough 1 in the XMP Programmers Guide, Opening files and reading XMP. +* Demonstrates the basic use of the XMPAssetManagement, obtaining XMP from a file and examining it +* for tracking puropose. A document if trackable only if(xmpMM:OriginalDocumentID, xmpMM:DocumentID +* and xmpMM:InstanceID) are present +*/ + +#include <cstdio> +#include <vector> +#include <string> +#include <cstring> +#include <fstream> +#include <iostream> + +// Must be defined to instantiate template classes +#define TXMP_STRING_TYPE std::string + +// Must be defined to give access to XMPFiles +#define XMP_INCLUDE_XMPFILES 0 + +#define ENABLE_NEW_DOM_MODEL 1 + +#include "XMPCore/Interfaces/IXMPDOMImplementationRegistry.h" +#include "XMPCore/Interfaces/IXMPDOMParser.h" +#include "XMPCore/Interfaces/IXMPDOMSerializer.h" +#include "XMPCore/Interfaces/IXMPMetadata.h" +#include "XMPCore/Interfaces/IXMPCoreObjectFactory.h" +#include "XMPCore/Interfaces/IXMPSimpleNode.h" + +// Ensure XMP templates are instantiated +#include "public/include/XMP.incl_cpp" + +// Provide access to the API +#include "public/include/XMP.hpp" + +#include "XMPCore/Interfaces/IXMPMetadata.h" +#include "XMPCommon/Interfaces/IUTF8String.h" +#include "XMPAssetManagement/XMPAssetManagementFwdDeclarations.h" +#include "XMPAssetManagement/XMPAssetManagement.h" +#include "XMPAssetManagement/Interfaces/IAssetUtilities.h" + +using namespace std; + +void static SerializeIXMPMetadata(NS_XMPCORE::spIXMPMetadata imetadata, string outfile = "") +{ + NS_XMPCORE::spIXMPDOMImplementationRegistry DOMRegistry = NS_XMPCORE::IXMPDOMImplementationRegistry::GetDOMImplementationRegistry(); + NS_XMPCORE::spIXMPDOMSerializer DOMSerializer = DOMRegistry->CreateSerializer("rdf"); + std::string targetfilebuffer = DOMSerializer->Serialize(imetadata)->c_str(); + + //std::cout << targetfilebuffer << std::endl; + + //write into file + if (!outfile.empty()) { + ofstream out(outfile); + if (out.is_open()) { + out << targetfilebuffer; + out.close(); + } + } +} + +static string GetStringFromFile(string& filename) +{ + string buffer; + string line; + + ifstream in(filename); + if (in.is_open()) { + while (getline(in, line)) + buffer = buffer + "\n" + line; + in.close(); + } + return buffer; +} + +NS_XMPCORE::spIXMPMetadata static GetIXMPMetadataFromRDF(string filename) +{ + string buffer = GetStringFromFile(filename); + + NS_XMPCORE::spIXMPDOMImplementationRegistry DOMRegistry = NS_XMPCORE::IXMPDOMImplementationRegistry::GetDOMImplementationRegistry(); + NS_XMPCORE::spIXMPDOMParser DOMParser = DOMRegistry->CreateParser("rdf"); + + NS_XMPCORE::spIXMPMetadata ixmpmeta = DOMParser->Parse(buffer.c_str()); + + return ixmpmeta; + +} + +/** +* Initializes the toolkit and attempts to open a file for reading metadata. Initially +* an attempt to open the file is done with a handler, if this fails then the file is opened with +* packet scanning. Once the file is open, it's metadata is obtained. From which a check for IDs +* is done, if missing these IDs are embedded. +*/ +int main ( int argc, const char * argv[] ) +{ + string input_file = "noids_source_input.xmp"; + string output_file = "noids_source_output.xmp"; + + if (!SXMPMeta::Initialize()) + { + cout << "Could not initialize toolkit!"; + return -1; + } + XMP_OptionBits options = 0; + + NS_XMPCORE::spIXMPMetadata ixmpmeta = GetIXMPMetadataFromRDF(input_file); + + NS_XMPCORE::pIXMPCoreObjectFactory factoryObj = NS_XMPCORE::IXMPCoreObjectFactory::GetInstance(); + NS_XMPASSETMANAGEMENT::XMPAM_ClientInitialize(); + + NS_XMPASSETMANAGEMENT::pIAssetUtilities utilityObj = NS_XMPASSETMANAGEMENT::IAssetUtilities::GetAssetUtilities(); + bool isTrackable = utilityObj->IsTrackable(ixmpmeta); + + if (isTrackable) { + cout << "File " << input_file << " is Trackable" << endl; + + NS_XMPCORE::spIXMPSimpleNode node = NS_XMPCORE::dynamic_pointer_cast<NS_XMPCORE::IXMPSimpleNode>(ixmpmeta->GetNode(kXMP_NS_XMP_MM, "OriginalDocumentID")); + if (node) + cout << "xmpMM:OriginalDocumentID is " << node->GetValue()->c_str() << endl; + + node = NS_XMPCORE::dynamic_pointer_cast<NS_XMPCORE::IXMPSimpleNode>(ixmpmeta->GetNode(kXMP_NS_XMP_MM, "DocumentID")); + if (node) + cout << "xmpMM:DocumentID is " << node->GetValue()->c_str() << endl; + + node = NS_XMPCORE::dynamic_pointer_cast<NS_XMPCORE::IXMPSimpleNode>(ixmpmeta->GetNode(kXMP_NS_XMP_MM, "InstanceID")); + if (node) + cout << "xmpMM:InstanceID is " << node->GetValue()->c_str() << endl; + } + else { + bool ret = utilityObj->MakeTrackable(ixmpmeta); + + SerializeIXMPMetadata(ixmpmeta, output_file); //serialize ixmpmeta into o/p file + + if (ret) { + NS_XMPCORE::spIXMPSimpleNode node = NS_XMPCORE::dynamic_pointer_cast<NS_XMPCORE::IXMPSimpleNode>(ixmpmeta->GetNode(kXMP_NS_XMP_MM, "OriginalDocumentID")); + if (node) + cout << "xmpMM:OriginalDocumentID is " << node->GetValue()->c_str() << endl; + + node = NS_XMPCORE::dynamic_pointer_cast<NS_XMPCORE::IXMPSimpleNode>(ixmpmeta->GetNode(kXMP_NS_XMP_MM, "DocumentID")); + if (node) + cout << "xmpMM:DocumentID is " << node->GetValue()->c_str() << endl; + + node = NS_XMPCORE::dynamic_pointer_cast<NS_XMPCORE::IXMPSimpleNode>(ixmpmeta->GetNode(kXMP_NS_XMP_MM, "InstanceID")); + if (node) + cout << "xmpMM:InstanceID is " << node->GetValue()->c_str() << endl; + } + } + + NS_XMPASSETMANAGEMENT::XMPAM_ClientTerminate(); + + SXMPMeta::Terminate(); + + return 0; +} + diff --git a/samples/source/CustomSchema.cpp b/samples/source/CustomSchema.cpp index 1cf0566..3e2beec 100644 --- a/samples/source/CustomSchema.cpp +++ b/samples/source/CustomSchema.cpp @@ -18,6 +18,8 @@ #include <string> #include <cstring> +//#define ENABLE_XMP_CPP_INTERFACE 1 + // Must be defined to instantiate template classes #define TXMP_STRING_TYPE std::string diff --git a/samples/source/CustomSchemaNewDOM.cpp b/samples/source/CustomSchemaNewDOM.cpp new file mode 100644 index 0000000..f8af1cc --- /dev/null +++ b/samples/source/CustomSchemaNewDOM.cpp @@ -0,0 +1,196 @@ +// ================================================================================================= +// Copyright 2008 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. +// ================================================================================================= + +/** +* Tutorial solution for the Walkthrough 3 in the XMP Programmers Guide, Working with custom schema. +* +* Demonstrates how to work with a custom schema that has complex properties. It shows how to access +* and modify properties with complex paths using the path composition utilities from the XMP API +*/ +#include <cstdio> +#include <vector> +#include <string> +#include <cstring> +#include <fstream> +#include <iostream> + +// Must be defined to instantiate template classes +#define TXMP_STRING_TYPE std::string + +// Must be defined to give access to XMPFiles +#define XMP_INCLUDE_XMPFILES 0 + +#define ENABLE_NEW_DOM_MODEL 1 + +// Ensure XMP templates are instantiated +#include "public/include/XMP.incl_cpp" + +// Provide access to the API +#include "public/include/XMP.hpp" + + +#include "XMPCore/Interfaces/IDOMImplementationRegistry.h" +#include "XMPCore/Interfaces/IDOMParser.h" +#include "XMPCore/Interfaces/IDOMSerializer.h" +#include "XMPCore/Interfaces/IMetadata.h" +#include "XMPCore/Interfaces/ICoreObjectFactory.h" +#include "XMPCore/Interfaces/ISimpleNode.h" +#include "XMPCore/Interfaces/IStructureNode.h" +#include "XMPCore/Interfaces/IArrayNode.h" +#include "XMPCore/Interfaces/INameSpacePrefixMap.h" +//#include "XMPCore\Interfaces\IXMPCoreFwdDeclarations.h" +#include "XMPCommon/Interfaces/IUTF8String.h" + + +// Made up namespace URI. Prefix will be xsdkEdit and xsdkUser +const XMP_StringPtr kXMP_NS_SDK_EDIT = "http://ns.adobe/meta/sdk/Edit/"; +const XMP_StringPtr kXMP_NS_SDK_USERS = "http://ns.adobe/meta/sdk/User/"; + +using namespace std; + +/** +* Writes an XMP packet in XML format to a text file +* +* rdf - a pointer to the serialized XMP +* filename - the name of the file to write to +*/ +void writeRDFToFile(string * rdf, string filename) +{ + ofstream outFile; + outFile.open(filename.c_str(), ios::out); + outFile << *rdf; + outFile.close(); +} + +/** +* Registers the namespaces that will be used with the custom schema. Then adds several new +* properties to that schema. The properties are complex, containing nested arrays and structures. +* +* XMPFiles is not used in this sample, hence no external resource is updated with the metadata. The +* created XMP object is serialized and written as RDF to a text file, the XMP object is dumped to +* a text file and the registered namespaces are also dumped to a text file.* +* +*/ +int main(int argc, const char * argv[]) +{ + + if (!SXMPMeta::Initialize()) + { + cout << "Could not initialize toolkit!"; + return -1; + } + + else + { + try + { + /* + AdobeXMPCore::spINameSpacePrefixMap map = AdobeXMPCore::INameSpacePrefixMap::CreateNameSpacePrefixMap(); + map->Insert("xsdkEdit", AdobeXMPCommon::npos, kXMP_NS_SDK_EDIT, AdobeXMPCommon::npos); + map->Insert("xsdkUser", AdobeXMPCommon::npos, kXMP_NS_SDK_USERS, AdobeXMPCommon::npos); + */ + + SXMPMeta::RegisterNamespace(kXMP_NS_SDK_EDIT, "xsdkEdit", NULL); + SXMPMeta::RegisterNamespace(kXMP_NS_SDK_USERS,"xsdkUser", NULL); + + // Adds a user of the document + // 1. Add a new item onto the DocumentUsers array - + // 2. Compose a path to the last element of DocumentUsers array + // 3. Add a value for the User field of the UserDetails structure + // 4. Add a qualifier to the User field. Compose the path and set the value + // 5. Add a value for the DUID field of the UserDetails structure + // 6. Add a Contact property for the ContactDetails field of the UserDetails structure + // 7. Compose a path to the ContactDetails field of the UserDetails structure. + // 8. Create the fields of the ContactDetails structure and provide values + + // Create a top Level array node of DocumentUsers. + AdobeXMPCore::spIMetadata metaNode = AdobeXMPCore::IMetadata::CreateMetadata(); + AdobeXMPCore::spIArrayNode DUarrayNode = AdobeXMPCore::IArrayNode::CreateUnorderedArrayNode(kXMP_NS_SDK_EDIT, AdobeXMPCommon::npos, "DocumentUsers", AdobeXMPCommon::npos); + + // Append the UserDetails struct node as child of DocumentUsers array node + AdobeXMPCore::spIStructureNode DUstructNode1 = AdobeXMPCore::IStructureNode::CreateStructureNode(kXMP_NS_SDK_EDIT, AdobeXMPCommon::npos, "UserDetails", AdobeXMPCommon::npos); + DUarrayNode->AppendNode(DUstructNode1); + + // Create simple nodes with property User and DUID as fields of UserDetails struct node + AdobeXMPCore::spINode UDsimpleNode1 = AdobeXMPCore::ISimpleNode::CreateSimpleNode(kXMP_NS_SDK_USERS, AdobeXMPCommon::npos, "User", AdobeXMPCommon::npos, "John Smith", AdobeXMPCommon::npos); + AdobeXMPCore::spINode UDsimpleNode2 = AdobeXMPCore::ISimpleNode::CreateSimpleNode(kXMP_NS_SDK_USERS, AdobeXMPCommon::npos, "DUID", AdobeXMPCommon::npos, "2", AdobeXMPCommon::npos); + + // Create a structure ContactDetails as field of UserDetails structure + AdobeXMPCore::spIStructureNode UDstructNode3 = AdobeXMPCore::IStructureNode::CreateStructureNode(kXMP_NS_SDK_EDIT, AdobeXMPCommon::npos, "ContactDetails", AdobeXMPCommon::npos); + + // Append all created fields as child of UserDetails struct node + DUstructNode1->AppendNode(UDsimpleNode1); + DUstructNode1->AppendNode(UDsimpleNode2); + DUstructNode1->AppendNode(UDstructNode3); + + // Create an alternative Array E-mail as field of ContactDetails structure + AdobeXMPCore::spIArrayNode CDarrayNode1 = AdobeXMPCore::IArrayNode::CreateAlternativeArrayNode(kXMP_NS_SDK_EDIT, AdobeXMPCommon::npos, "E-Mail", AdobeXMPCommon::npos); + + // Create an unordered Array Telephone as field of ContactDetails structure + AdobeXMPCore::spIArrayNode CDarrayNode2 = AdobeXMPCore::IArrayNode::CreateUnorderedArrayNode(kXMP_NS_SDK_EDIT, AdobeXMPCommon::npos, "Telephone", AdobeXMPCommon::npos); + + // Create simple node with property BaseLocation + AdobeXMPCore::spINode CDsimpleNode3 = AdobeXMPCore::ISimpleNode::CreateSimpleNode(kXMP_NS_SDK_USERS, AdobeXMPCommon::npos, "BaseLocation", AdobeXMPCommon::npos, "London", AdobeXMPCommon::npos); + + // Append all created fields as child of ContactDetails structure + UDstructNode3->AppendNode(CDarrayNode1); + UDstructNode3->AppendNode(CDarrayNode2); + UDstructNode3->AppendNode(CDsimpleNode3); + + //Append items to E-Mail array + CDarrayNode1->AppendNode(AdobeXMPCore::ISimpleNode::CreateSimpleNode(kXMP_NS_SDK_USERS, AdobeXMPCommon::npos, "Mail1", AdobeXMPCommon::npos, "js@adobe.xmp.com", AdobeXMPCommon::npos)); + CDarrayNode1->AppendNode(AdobeXMPCore::ISimpleNode::CreateSimpleNode(kXMP_NS_SDK_USERS, AdobeXMPCommon::npos, "Mail2", AdobeXMPCommon::npos, "js@adobe.home.com", AdobeXMPCommon::npos)); + + //Append items to Telephone array + CDarrayNode2->AppendNode(AdobeXMPCore::ISimpleNode::CreateSimpleNode(kXMP_NS_SDK_USERS, AdobeXMPCommon::npos, "Phone1", AdobeXMPCommon::npos, "89112", AdobeXMPCommon::npos)); + CDarrayNode2->AppendNode(AdobeXMPCore::ISimpleNode::CreateSimpleNode(kXMP_NS_SDK_USERS, AdobeXMPCommon::npos, "Phone2", AdobeXMPCommon::npos, "84432", AdobeXMPCommon::npos)); + + metaNode->AppendNode(DUarrayNode); + + // Create unordered array DocumentEdit + AdobeXMPCore::spIArrayNode DEarrayNode = AdobeXMPCore::IArrayNode::CreateUnorderedArrayNode(kXMP_NS_SDK_EDIT, AdobeXMPCommon::npos, "DocumentEdit", AdobeXMPCommon::npos); + + // Create structure EditDetails as arrayitem of DocumentEdit array + AdobeXMPCore::spIStructureNode DEstructNode1 = AdobeXMPCore::IStructureNode::CreateStructureNode(kXMP_NS_SDK_EDIT, AdobeXMPCommon::npos, "EditDetails", AdobeXMPCommon::npos); + DEarrayNode->AppendNode(DEstructNode1); + + // Obtaining current date and time + XMP_DateTime dt; + SXMPUtils::CurrentDateTime(&dt); + string date; + SXMPUtils::ConvertFromDate(dt, &date); + + // Creating simple node as field of EditDetails structure which will hold the current date + AdobeXMPCore::spINode EDsimpleNode1 = AdobeXMPCore::ISimpleNode::CreateSimpleNode(kXMP_NS_SDK_EDIT, AdobeXMPCommon::npos, "EditDate", AdobeXMPCommon::npos, date.c_str(), AdobeXMPCommon::npos); + + // Creating simple node Edittool as field of EditDetails structre + AdobeXMPCore::spINode EDsimpleNode2 = AdobeXMPCore::ISimpleNode::CreateSimpleNode(kXMP_NS_SDK_EDIT, AdobeXMPCommon::npos, "EditTool", AdobeXMPCommon::npos, "FrameXML", AdobeXMPCommon::npos); + + // Appending fields as child of EditDetails structure node + DEstructNode1->AppendNode(EDsimpleNode1); + DEstructNode1->AppendNode(EDsimpleNode2); + metaNode->AppendNode(DEarrayNode); + + // Write the RDF to a file + cout << "writing RDF to file CS_RDF.txt" << endl; + AdobeXMPCore::spIDOMImplementationRegistry DOMRegistry = AdobeXMPCore::IDOMImplementationRegistry::GetDOMImplementationRegistry(); + AdobeXMPCore::spIDOMSerializer serializer = DOMRegistry->GetSerializer("rdf"); + std::string serializedPacket = serializer->Serialize(metaNode)->c_str(); + writeRDFToFile(&serializedPacket, "CS_RDF.txt"); + + } + catch (XMP_Error & e) + { + cout << "ERROR: " << e.GetErrMsg(); + } + + } + + return 0; + +} diff --git a/samples/source/DumpMainXMP.cpp b/samples/source/DumpMainXMP.cpp index 313665b..abd2604 100644 --- a/samples/source/DumpMainXMP.cpp +++ b/samples/source/DumpMainXMP.cpp @@ -21,6 +21,8 @@ #include <stdexcept> #include <cerrno> +//#define ENABLE_XMP_CPP_INTERFACE 1; + #if XMP_WinBuild #pragma warning ( disable : 4127 ) // conditional expression is constant #pragma warning ( disable : 4996 ) // '...' was declared deprecated diff --git a/samples/source/DumpScannedXMP.cpp b/samples/source/DumpScannedXMP.cpp index 1acbc82..3df2019 100644 --- a/samples/source/DumpScannedXMP.cpp +++ b/samples/source/DumpScannedXMP.cpp @@ -21,6 +21,8 @@ #include <stdexcept> #include <cerrno> +//#define ENABLE_XMP_CPP_INTERFACE 1; + #if XMP_WinBuild #pragma warning ( disable : 4127 ) // conditional expression is constant #pragma warning ( disable : 4996 ) // '...' was declared deprecated @@ -31,7 +33,11 @@ #include "public/include/XMP.hpp" #include "public/include/XMP.incl_cpp" -#include "samples/source/common/XMPScanner.hpp" + +#include "XMPFiles/source/FormatSupport/XMPScanner.hpp" +#include "XMPFiles/source/FormatSupport/XMPScanner.cpp" + + using namespace std; // ================================================================================================= diff --git a/samples/source/ModifyingXMP.cpp b/samples/source/ModifyingXMP.cpp index 67d6f35..b334e70 100644 --- a/samples/source/ModifyingXMP.cpp +++ b/samples/source/ModifyingXMP.cpp @@ -16,6 +16,8 @@ #include <string> #include <cstring> +//#define ENABLE_XMP_CPP_INTERFACE 1; + // Must be defined to instantiate template classes #define TXMP_STRING_TYPE std::string diff --git a/samples/source/ModifyingXMPNewDOM.cpp b/samples/source/ModifyingXMPNewDOM.cpp new file mode 100644 index 0000000..23b9ff4 --- /dev/null +++ b/samples/source/ModifyingXMPNewDOM.cpp @@ -0,0 +1,429 @@ +// ================================================================================================= +// Copyright 2008 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. +// ================================================================================================= + +/** +* Tutorial solution for Walkthrough 2 in the XMP Programmers Guide, Modifying XMP +* Demonstrates how to open a file for update, and modifying the contained XMP before writing it back to the file. +*/ + +#include <cstdio> +#include <vector> +#include <string> +#include <cstring> +#include <fstream> +#include <iostream> + +// Must be defined to instantiate template classes +#define TXMP_STRING_TYPE std::string + +// Must be defined to give access to XMPFiles +#define XMP_INCLUDE_XMPFILES 1 + +#define ENABLE_NEW_DOM_MODEL 1 + +// Ensure XMP templates are instantiated +#include "public/include/XMP.incl_cpp" + +// Provide access to the API +#include "public/include/XMP.hpp" + +#include "XMPCore/Interfaces/IDOMImplementationRegistry.h" +#include "XMPCore/Interfaces/IDOMParser.h" +#include "XMPCore/Interfaces/IDOMSerializer.h" +#include "XMPCore/Interfaces/IMetadata.h" +#include "XMPCore/Interfaces/ICoreObjectFactory.h" +#include "XMPCore/Interfaces/ISimpleNode.h" +#include "XMPCore/Interfaces/IStructureNode.h" +#include "XMPCore/Interfaces/IArrayNode.h" +#include "XMPCore/Interfaces/INameSpacePrefixMap.h" +#include "XMPCommon/Interfaces/IUTF8String.h" +#include "XMPCore/Interfaces/INodeIterator.h" + + +using namespace std; +using namespace AdobeXMPCore; + +void GetLocalizedText(spIArrayNode titleNode, const char* specificLang, const char* genericLang, string lang) +{ + AdobeXMPCore::spINode currItem; + const size_t itemLim = titleNode->ChildCount(); + size_t itemNum; + + spISimpleNode xmlLangQualifierNode, currItemNode; + for (itemNum = 1; itemNum <= itemLim; ++itemNum) + { + currItem = titleNode->GetNodeAtIndex(itemNum); + if (currItem != NULL) + { + xmlLangQualifierNode = currItem->QualifiersIterator()->GetNode()->ConvertToSimpleNode(); + if (!strcmp(xmlLangQualifierNode->GetValue()->c_str(), specificLang)) { + currItemNode = currItem->ConvertToSimpleNode(); + cout << "dc:title in" << " " << lang << " " << currItemNode->GetValue()->c_str() << endl; + return; + } + } + } + + if (*genericLang != 0) + { + // Look for the first partial match with the generic language. + const size_t genericLen = strlen(genericLang); + for (itemNum = 1; itemNum <= itemLim; ++itemNum) { + currItem = titleNode->GetNodeAtIndex(itemNum); + xmlLangQualifierNode = currItem->QualifiersIterator()->GetNode()->ConvertToSimpleNode(); + XMP_StringPtr currLang = xmlLangQualifierNode->GetValue()->c_str(); + const size_t currLangSize = xmlLangQualifierNode->GetValue()->size(); + if ((currLangSize >= genericLen) && + !strncmp(currLang, genericLang, genericLen) && + ((currLangSize == genericLen) || (currLang[genericLen] == '-'))) + { + currItemNode = currItem->ConvertToSimpleNode(); + cout << "dc:title in" << " " << lang << " " << currItemNode->GetValue()->c_str() << endl; + return; + } + } + } + + // Look for an 'x-default' item. + for (itemNum = 1; itemNum <= itemLim; ++itemNum) { + currItem = titleNode->GetNodeAtIndex(itemNum); + xmlLangQualifierNode = currItem->QualifiersIterator()->GetNode()->ConvertToSimpleNode(); + if (!strcmp(xmlLangQualifierNode->GetValue()->c_str(), "x-default")) { + currItemNode = currItem->ConvertToSimpleNode(); + cout << "dc:title in" << " " << lang << " " << currItemNode->GetValue()->c_str() << endl; + return; + } + } + + // Everything failed, choose the first item. + currItem = titleNode->GetNodeAtIndex(1); + currItemNode = currItem->ConvertToSimpleNode(); + cout << "dc:title in" << " " << lang << " " << currItemNode->GetValue() << endl; + return; + +} + + + +/** +* Display some property values to the console +* +* meta - a pointer to the XMP object that will have the properties read +*/ +void displayPropertyValues(AdobeXMPCore::spIMetadata metaNode) +{ + // Read a simple property + AdobeXMPCore::spISimpleNode simpleNode = metaNode->GetSimpleNode(kXMP_NS_XMP, AdobeXMPCommon::npos, "CreatorTool", AdobeXMPCommon::npos); + if (simpleNode != NULL) + { + string simpleNodeValue = simpleNode->GetValue()->c_str(); + cout << "CreatorTool = " << simpleNodeValue << endl; + } + + // Get the first element in the dc:creator array + AdobeXMPCore::spIArrayNode arrayNode = metaNode->GetArrayNode(kXMP_NS_DC, AdobeXMPCommon::npos, "creator", AdobeXMPCommon::npos); + if (arrayNode != NULL) + { + AdobeXMPCore::spISimpleNode arrayNodeChild = arrayNode->GetSimpleNodeAtIndex(1); + if (arrayNodeChild != NULL) + { + string arrayNodeChildValue = arrayNodeChild->GetValue()->c_str(); + cout << "dc:creator[1] = " << arrayNodeChildValue << endl; + } + + AdobeXMPCore::spISimpleNode arrayNodeChild1 = arrayNode->GetSimpleNodeAtIndex(2); + if (arrayNodeChild1 != NULL) + { + string arrayNodeChildValue1 = arrayNodeChild1->GetValue()->c_str(); + cout << "dc:creator[2] = " << arrayNodeChildValue1 << endl; + } + } + + // Get the the entire dc:subject array + AdobeXMPCore::spIArrayNode subjectArray = metaNode->GetArrayNode(kXMP_NS_DC, AdobeXMPCommon::npos, "subject", AdobeXMPCommon::npos); + if (subjectArray != NULL) + { + int arraySize = subjectArray->ChildCount(); + for (int i = 1; i <= arraySize; i++) + { + AdobeXMPCore::spISimpleNode subjectChild = subjectArray->GetSimpleNodeAtIndex(i); + if (subjectChild != NULL) + { + string propValue = subjectChild->GetValue()->c_str(); + cout << "dc:subject[" << i << "] = " << propValue << endl; + } + } + } + // Get the dc:title for English and French + AdobeXMPCore::spIArrayNode titleNode = metaNode->GetArrayNode(kXMP_NS_DC, AdobeXMPCommon::npos, "title", AdobeXMPCommon::npos); + if (titleNode != NULL) + { + GetLocalizedText(titleNode, "en-US", "en", "English"); + GetLocalizedText(titleNode, "fr-FR", "fr", "French"); + } + + // Get dc:MetadataDate + AdobeXMPCore::spISimpleNode dateNode = metaNode->GetSimpleNode(kXMP_NS_XMP, AdobeXMPCommon::npos, "MetadataDate", AdobeXMPCommon::npos); + string date = dateNode->GetValue()->c_str(); + cout << "meta:MetadataDate = " << date << endl; + + + // See if the flash struct exists and see if it was used + AdobeXMPCore::spIStructureNode flashNode = metaNode->GetStructureNode(kXMP_NS_EXIF, AdobeXMPCommon::npos, "Flash", AdobeXMPCommon::npos); + if (flashNode != NULL) + { + AdobeXMPCore::spISimpleNode field = flashNode->GetSimpleNode(kXMP_NS_EXIF, AdobeXMPCommon::npos, "Fired", AdobeXMPCommon::npos); + if (field != NULL) + { + string fieldValue = field->GetValue()->c_str(); + cout << "Flash Used = " << fieldValue << endl; + } + } + + + cout << "----------------------------------------" << endl; +} + +/** +* Creates an XMP object from an RDF string. The string is used to +* to simulate creating and XMP object from multiple input buffers. +* The last call to ParseFromBuffer has no kXMP_ParseMoreBuffers options, +* thereby indicating this is the last input buffer. +*/ +SXMPMeta createXMPFromRDF() +{ + const char * rdf = + "<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/'>" + "<dc:subject>" + "<rdf:Bag>" + "<rdf:li>XMP</rdf:li>" + "<rdf:li>SDK</rdf:li>" + "<rdf:li>Sample</rdf:li>" + "</rdf:Bag>" + "</dc:subject>" + "<dc:format>image/tiff</dc:format>" + "</rdf:Description>" + "</rdf:RDF>"; + + SXMPMeta meta; + // Loop over the rdf string and create the XMP object + // 10 characters at a time + int i; + for (i = 0; i < (long)strlen(rdf) - 10; i += 10) + { + meta.ParseFromBuffer(&rdf[i], 10, kXMP_ParseMoreBuffers); + } + + // The last call has no kXMP_ParseMoreBuffers options, signifying + // this is the last input buffer + meta.ParseFromBuffer(&rdf[i], (XMP_StringLen)strlen(rdf) - i); + return meta; + +} + + +/** +* Writes an XMP packet in XML format to a text file +* +* rdf - a pointer to the serialized XMP +* filename - the name of the file to write to +*/ +void writeRDFToFile(string * rdf, string filename) +{ + ofstream outFile; + outFile.open(filename.c_str(), ios::out); + outFile << *rdf; + outFile.close(); +} + +/** +* Initializes the toolkit and attempts to open a file for updating its metadata.Initially +* an attempt to open the file is done with a handler, if this fails then the file is opened with +* packet scanning.Once the file is open several properties are read and displayed in the console. +* +* Several properties are then modified, first by checking for their existence and then, if they +* exist, by updating their values.The updated properties are then displayed again in the console. +* +* Next a new XMP object is created from an RDF stream, the properties from the new XMP object are +* appended to the original XMP object and the updated properties are displayed in the console for +* last time. +* +* The updated XMP object is then serialized in different formats and written to text files.Lastly, +*the modified XMP is written back to the resource file. +*/ + +int main(int argc, const char * argv[]) +{ + if (argc != 2) // 2 := command and 1 parameter + { + cout << "usage: ModifyingXMP (filename)" << endl; + return 0; + } + + string filename = string(argv[1]); + + if (!SXMPMeta::Initialize()) + { + cout << "Could not initialize toolkit!"; + return -1; + } + + XMP_OptionBits options = 0; +#if UNIX_ENV + options |= kXMPFiles_ServerMode; +#endif + + // Must initialize SXMPFiles before we use it + if (SXMPFiles::Initialize(options)) + { + try + { + // Options to open the file with - open for editing and use a smart handler + XMP_OptionBits opts = kXMPFiles_OpenForUpdate | kXMPFiles_OpenUseSmartHandler; + + bool ok; + SXMPFiles myFile; + std::string status = ""; + + // First we try and open the file + ok = myFile.OpenFile(filename, kXMP_UnknownFile, opts); + if (!ok) + { + status += "No smart handler available for " + filename + "\n"; + status += "Trying packet scanning.\n"; + + // Now try using packet scanning + opts = kXMPFiles_OpenForUpdate | kXMPFiles_OpenUsePacketScanning; + ok = myFile.OpenFile(filename, kXMP_UnknownFile, opts); + } + + // If the file is open then read get the XMP data + if (ok) + { + cout << status << endl; + cout << filename << " is opened successfully" << endl; + + // Create the xmp object and get the xmp data + SXMPMeta meta; + myFile.GetXMP(&meta); + string buffer; + meta.SerializeToBuffer(&buffer); + AdobeXMPCore::spIDOMImplementationRegistry DOMRegistry = AdobeXMPCore::IDOMImplementationRegistry::GetDOMImplementationRegistry(); + AdobeXMPCore::spIDOMParser parser = DOMRegistry->GetParser("rdf"); + AdobeXMPCore::spIMetadata metaNode = parser->Parse(buffer.c_str(), buffer.size()); + + // Display some properties in the console + displayPropertyValues(metaNode); + + /////////////////////////////////////////////////// + // Now modify the XMP + AdobeXMPCore::spISimpleNode simpleNode = metaNode->GetSimpleNode(kXMP_NS_XMP, AdobeXMPCommon::npos, "CreatorTool", AdobeXMPCommon::npos); + + if (simpleNode!=NULL) + simpleNode->SetValue("Updated By XMP SDK", AdobeXMPCommon::npos); + + // Update the MetadataDate + XMP_DateTime dt; + SXMPUtils::CurrentDateTime(&dt); + string date; + SXMPUtils::ConvertFromDate(dt, &date); + AdobeXMPCore::spISimpleNode dateNode = metaNode->GetSimpleNode(kXMP_NS_XMP, AdobeXMPCommon::npos, "MetadataDate", AdobeXMPCommon::npos); + dateNode->SetValue(date.c_str(), AdobeXMPCommon::npos); + + // Add an item onto the dc:creator array + AdobeXMPCore::spIArrayNode arrayNode = metaNode->GetArrayNode(kXMP_NS_DC, AdobeXMPCommon::npos, "creator", AdobeXMPCommon::npos); + + // If the array does not exist, it will be created + if (arrayNode == NULL) + { + AdobeXMPCore::spIArrayNode arrayNode = AdobeXMPCore::IArrayNode::CreateUnorderedArrayNode(kXMP_NS_DC, AdobeXMPCommon::npos, "creator", AdobeXMPCommon::npos); + AdobeXMPCore::spINode creatorChild1 = AdobeXMPCore::ISimpleNode::CreateSimpleNode(kXMP_NS_DC, AdobeXMPCommon::npos, "AuthorName", AdobeXMPCommon::npos, "abc", AdobeXMPCommon::npos); + AdobeXMPCore::spINode creatorChild2 = AdobeXMPCore::ISimpleNode::CreateSimpleNode(kXMP_NS_DC, AdobeXMPCommon::npos, "AnotherAuthorName", AdobeXMPCommon::npos, "xyz", AdobeXMPCommon::npos); + arrayNode->AppendNode(creatorChild1); + arrayNode->AppendNode(creatorChild2); + + } + // If it exists, then just append the nodes to array node + else + { + AdobeXMPCore::spINode creatorChild1 = AdobeXMPCore::ISimpleNode::CreateSimpleNode(kXMP_NS_DC, AdobeXMPCommon::npos, "AuthorName", AdobeXMPCommon::npos, "abc", AdobeXMPCommon::npos); + AdobeXMPCore::spINode creatorChild2 = AdobeXMPCore::ISimpleNode::CreateSimpleNode(kXMP_NS_DC, AdobeXMPCommon::npos, "AnotherAuthorName", AdobeXMPCommon::npos, "xyz", AdobeXMPCommon::npos); + arrayNode->AppendNode(creatorChild1); + arrayNode->AppendNode(creatorChild2); + } + + // Display the properties again to show changes + cout << "After update:" << endl; + displayPropertyValues(metaNode); + + AdobeXMPCore::spIDOMSerializer serializer = DOMRegistry->GetSerializer("rdf"); + AdobeXMPCore:: spcINameSpacePrefixMap defaultMap = AdobeXMPCore::INameSpacePrefixMap::GetDefaultNameSpacePrefixMap(); + std::string serializedPacket = serializer->Serialize(metaNode, defaultMap)->c_str(); + SXMPMeta fileMeta; + fileMeta.ParseFromBuffer(serializedPacket.c_str(), serializedPacket.length()); + + // Create a new XMP object from an RDF string + SXMPMeta rdfMeta = createXMPFromRDF(); + + // Append the newly created properties onto the original XMP object + // This will: + // a) Add ANY new TOP LEVEL properties in the source (rdfMeta) to the destination (fileMeta) + // b) Replace any top level properties in the source with the matching properties from the destination + SXMPUtils::ApplyTemplate(&fileMeta, rdfMeta, kXMPTemplate_AddNewProperties | kXMPTemplate_ReplaceExistingProperties | kXMPTemplate_IncludeInternalProperties); + + // Serialize the packet and write the buffer to a file + // Let the padding be computed and use the default linefeed and indents without limits + string newBuffer; + fileMeta.SerializeToBuffer(&newBuffer); + + // Display the properties again to show changes + cout << "After Appending Properties:" << endl; + AdobeXMPCore::spIMetadata newMetaNode = parser->Parse(newBuffer.c_str(), newBuffer.size()); + displayPropertyValues(newMetaNode); + + // Write the packet to a file as RDF + writeRDFToFile(&newBuffer, filename + "_XMP_RDF.txt"); + + // Check we can put the XMP packet back into the file + if (myFile.CanPutXMP(fileMeta)) + { + // If so then update the file with the modified XMP + myFile.PutXMP(fileMeta); + } + + // Close the SXMPFile. This *must* be called. The XMP is not + // actually written and the disk file is not closed until this call is made. + myFile.CloseFile(); + } + else + { + cout << "Unable to open " << filename << endl; + } + + } + catch (XMP_Error & e) + { + cout << "ERROR: " << e.GetErrMsg() << endl; + } + + // Terminate the toolkit + SXMPFiles::Terminate(); + SXMPMeta::Terminate(); + + } + else + { + cout << "Could not initialize SXMPFiles."; + return -1; + } + + return 0; +} + + diff --git a/samples/source/ReadingXMP.cpp b/samples/source/ReadingXMP.cpp index bfcf56c..fd6da47 100644 --- a/samples/source/ReadingXMP.cpp +++ b/samples/source/ReadingXMP.cpp @@ -17,6 +17,8 @@ #include <string> #include <cstring> +//#define ENABLE_XMP_CPP_INTERFACE 1 + // Must be defined to instantiate template classes #define TXMP_STRING_TYPE std::string @@ -34,6 +36,7 @@ using namespace std; + /** * Client defined callback function to dump XMP to a file. In this case an output file stream is used * to write a buffer, of length bufferSize, to a text file. This callback is called multiple @@ -180,6 +183,8 @@ int main ( int argc, const char * argv[] ) cout << "Flash Used = " << flash << endl; } + + // Dump the current xmp object to a file ofstream dumpFile; dumpFile.open("XMPDump.txt", ios::out); diff --git a/samples/source/ReadingXMPNewDOM.cpp b/samples/source/ReadingXMPNewDOM.cpp new file mode 100644 index 0000000..86b603e --- /dev/null +++ b/samples/source/ReadingXMPNewDOM.cpp @@ -0,0 +1,281 @@ +// ================================================================================================= +// Copyright 2008 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. +// ================================================================================================= + +/** +* Tutorial solution for the Walkthrough 1 in the XMP Programmers Guide, Opening files and reading XMP. +* Demonstrates the basic use of the XMPFiles and XMPCore components, obtaining read-only XMP from a file +* and examining it through the XMP object. +*/ + +#include <cstdio> +#include <vector> +#include <string> +#include <cstring> +#include <fstream> +#include <iostream> + +//#define ENABLE_XMP_CPP_INTERFACE 1; + +// Must be defined to instantiate template classes +#define TXMP_STRING_TYPE std::string + +// Must be defined to give access to XMPFiles +#define XMP_INCLUDE_XMPFILES 1 + +#define ENABLE_NEW_DOM_MODEL 1 + +// Ensure XMP templates are instantiated +#include "public/include/XMP.incl_cpp" + +// Provide access to the API +#include "public/include/XMP.hpp" + +#include "XMPCore/Interfaces/IDOMImplementationRegistry.h" +#include "XMPCore/Interfaces/IDOMParser.h" +#include "XMPCore/Interfaces/IDOMSerializer.h" +#include "XMPCore/Interfaces/IMetadata.h" +#include "XMPCore/Interfaces/ICoreObjectFactory.h" +#include "XMPCore/Interfaces/ISimpleNode.h" +#include "XMPCore/Interfaces/IStructureNode.h" +#include "XMPCore/Interfaces/IArrayNode.h" +#include "XMPCore/Interfaces/INameSpacePrefixMap.h" +#include "XMPCommon/Interfaces/IUTF8String.h" +#include "XMPCore/Interfaces/INodeIterator.h" + +using namespace std; +using namespace AdobeXMPCore; + + +void GetLocalizedText(spIArrayNode titleNode, const char* specificLang, const char* genericLang, string lang) +{ + AdobeXMPCore::spINode currItem; + const size_t itemLim = titleNode->ChildCount(); + size_t itemNum; + + spISimpleNode xmlLangQualifierNode, currItemNode; + for (itemNum = 1; itemNum <= itemLim; ++itemNum) + { + currItem = titleNode->GetNodeAtIndex(itemNum); + if (currItem != NULL) + { + xmlLangQualifierNode = currItem->QualifiersIterator()->GetNode()->ConvertToSimpleNode(); + if (!strcmp(xmlLangQualifierNode->GetValue()->c_str(), specificLang)) { + currItemNode = currItem->ConvertToSimpleNode(); + cout << "dc:title in" <<" " << lang <<" " << currItemNode->GetValue()->c_str() << endl; + return; + } + } + } + + if (*genericLang != 0) + { + // Look for the first partial match with the generic language. + const size_t genericLen = strlen(genericLang); + for (itemNum = 1; itemNum <= itemLim; ++itemNum) { + currItem = titleNode->GetNodeAtIndex(itemNum); + xmlLangQualifierNode = currItem->QualifiersIterator()->GetNode()->ConvertToSimpleNode(); + XMP_StringPtr currLang = xmlLangQualifierNode->GetValue()->c_str(); + const size_t currLangSize = xmlLangQualifierNode->GetValue()->size(); + if ((currLangSize >= genericLen) && + !strncmp(currLang, genericLang, genericLen) && + ((currLangSize == genericLen) || (currLang[genericLen] == '-'))) + { + currItemNode = currItem->ConvertToSimpleNode(); + cout << "dc:title in" <<" " << lang << " " << currItemNode->GetValue()->c_str() << endl; + return; + } + } + } + + // Look for an 'x-default' item. + for (itemNum = 1; itemNum <= itemLim; ++itemNum) { + currItem = titleNode->GetNodeAtIndex(itemNum); + xmlLangQualifierNode = currItem->QualifiersIterator()->GetNode()->ConvertToSimpleNode(); + if (!strcmp(xmlLangQualifierNode->GetValue()->c_str(), "x-default")) { + currItemNode = currItem->ConvertToSimpleNode(); + cout << "dc:title in" <<" " << lang <<" " << currItemNode->GetValue()->c_str() << endl; + return; + } + } + + // Everything failed, choose the first item. + currItem = titleNode->GetNodeAtIndex(1); + currItemNode = currItem->ConvertToSimpleNode(); + cout << "dc:title in" <<" " <<lang << " "<< currItemNode->GetValue() << endl; + return; + +} + + + +void writeRDFToFile(string * rdf, string filename) +{ + ofstream outFile; + outFile.open(filename.c_str(), ios::out); + outFile << *rdf; + outFile.close(); +} + + +/** +* Initializes the toolkit and attempts to open a file for reading metadata.Initially +* an attempt to open the file is done with a handler, if this fails then the file is opened with +* packet scanning.Once the file is open several properties are read and displayed in the console. +* The XMP object is then dumped to a text file and the resource file is closed. +*/ + +int main(int argc, const char * argv[]) +{ + + if (argc != 2) // 2 := command and 1 parameter + { + cout << "usage: ReadingXMP (filename)" << endl; + return 0; + } + + string filename = string(argv[1]); + + if (!SXMPMeta::Initialize()) + { + cout << "Could not initialize toolkit!"; + return -1; + } + XMP_OptionBits options = 0; +#if UNIX_ENV + options |= kXMPFiles_ServerMode; +#endif + // Must initialize SXMPFiles before we use it + if (!SXMPFiles::Initialize(options)) + { + cout << "Could not initialize SXMPFiles."; + return -1; + } + + try + { + // Options to open the file with - read only and use a file handler + XMP_OptionBits opts = kXMPFiles_OpenForRead | kXMPFiles_OpenUseSmartHandler; + + bool ok; + SXMPFiles myFile; + std::string status = ""; + + // First we try and open the file + ok = myFile.OpenFile(filename, kXMP_UnknownFile, opts); + if (!ok) + { + status += "No smart handler available for " + filename + "\n"; + status += "Trying packet scanning.\n"; + + // Now try using packet scanning + opts = kXMPFiles_OpenForUpdate | kXMPFiles_OpenUsePacketScanning; + ok = myFile.OpenFile(filename, kXMP_UnknownFile, opts); + } + + // If the file is open then read the metadata + if (ok) + { + + cout << status << endl; + cout << filename << " is opened successfully" << endl; + // Create the xmp object and get the xmp data + SXMPMeta meta; + myFile.GetXMP(&meta); + string buffer; + meta.SerializeToBuffer(&buffer); + writeRDFToFile(&buffer, "Image1RDF.txt"); + AdobeXMPCore::spIDOMImplementationRegistry DOMRegistry = AdobeXMPCore::IDOMImplementationRegistry::GetDOMImplementationRegistry(); + AdobeXMPCore:: spIDOMParser parser = DOMRegistry->GetParser("rdf"); + AdobeXMPCore ::spIMetadata metaNode = parser->Parse(buffer.c_str(), buffer.size()); + + // Read a simple property + AdobeXMPCore::spISimpleNode simpleNode = metaNode->GetSimpleNode(kXMP_NS_XMP, AdobeXMPCommon::npos, "CreatorTool", AdobeXMPCommon::npos); + if (simpleNode != NULL) + { + string simpleNodeValue = simpleNode->GetValue()->c_str(); + cout << "CreatorTool = " << simpleNodeValue << endl; + } + + // Get the first element in the dc:creator array + AdobeXMPCore::spIArrayNode arrayNode = metaNode->GetArrayNode(kXMP_NS_DC, AdobeXMPCommon::npos, "creator", AdobeXMPCommon::npos); + if (arrayNode != NULL) + { + AdobeXMPCore::spISimpleNode arrayNodeChild = arrayNode->GetSimpleNodeAtIndex(1); + if (arrayNodeChild != NULL) + { + string arrayNodeChildValue = arrayNodeChild->GetValue()->c_str(); + cout << "dc:creator = " << arrayNodeChildValue << endl; + } + } + + // Get the the entire dc:subject array + AdobeXMPCore::spIArrayNode subjectArray = metaNode->GetArrayNode(kXMP_NS_DC, AdobeXMPCommon::npos, "subject", AdobeXMPCommon::npos); + if (subjectArray != NULL) + { + int arraySize = subjectArray->ChildCount(); + for (int i = 1; i <= arraySize; i++) + { + AdobeXMPCore::spISimpleNode subjectChild = subjectArray->GetSimpleNodeAtIndex(i); + if (subjectChild != NULL) + { + string propValue = subjectChild->GetValue()->c_str(); + cout << "dc:subject[" << i << "] = " << propValue << endl; + } + } + } + + // Get the dc:title for English and French + + + AdobeXMPCore::spIArrayNode titleNode = metaNode->GetArrayNode(kXMP_NS_DC, AdobeXMPCommon::npos, "title", AdobeXMPCommon::npos); + if (titleNode != NULL) + { + GetLocalizedText(titleNode, "en-US", "en", "English"); + GetLocalizedText(titleNode, "fr-FR", "fr", "French"); + } + + + + // Get dc:MetadataDate + AdobeXMPCore::spISimpleNode dateNode = metaNode->GetSimpleNode(kXMP_NS_XMP, AdobeXMPCommon::npos, "MetadataDate", AdobeXMPCommon::npos); + string date = dateNode->GetValue()->c_str(); + cout << "meta:MetadataDate = " << date << endl; + + + // See if the flash struct exists and see if it was used + AdobeXMPCore::spIStructureNode flashNode = metaNode->GetStructureNode(kXMP_NS_EXIF, AdobeXMPCommon::npos, "Flash", AdobeXMPCommon::npos); + if (flashNode != NULL) + { + AdobeXMPCore::spISimpleNode field = flashNode->GetSimpleNode(kXMP_NS_EXIF, AdobeXMPCommon::npos, "Fired", AdobeXMPCommon::npos); + if (field != NULL) + { + string fieldValue = field->GetValue()->c_str(); + cout << "Flash Used = " << fieldValue << endl; + } + } + // Close the SXMPFile. The resource file is already closed if it was + // opened as read only but this call must still be made. + myFile.CloseFile(); + + } + else + { + cout << "Unable to open " << filename << endl; + } + } + catch (XMP_Error & e) + { + cout << "ERROR: " << e.GetErrMsg() << endl; + } + + // Terminate the toolkit + SXMPFiles::Terminate(); + SXMPMeta::Terminate(); + + return 0; +} diff --git a/samples/source/UnicodeCorrectness.cpp b/samples/source/UnicodeCorrectness.cpp index 56f121a..2864358 100644 --- a/samples/source/UnicodeCorrectness.cpp +++ b/samples/source/UnicodeCorrectness.cpp @@ -10,6 +10,8 @@ #include <cerrno> #include <stdexcept> +//#define ENABLE_XMP_CPP_INTERFACE 1; + using namespace std; #if WIN_ENV diff --git a/samples/source/UnicodeParseSerialize.cpp b/samples/source/UnicodeParseSerialize.cpp index c3c9865..5f0d463 100644 --- a/samples/source/UnicodeParseSerialize.cpp +++ b/samples/source/UnicodeParseSerialize.cpp @@ -27,6 +27,8 @@ #include "source/UnicodeConversions.hpp" #include "source/UnicodeConversions.cpp" +//#define ENABLE_XMP_CPP_INTERFACE 1; + using namespace std; #if WIN_ENV diff --git a/samples/source/UnicodePerformance.cpp b/samples/source/UnicodePerformance.cpp index d11185c..dac4ecd 100644 --- a/samples/source/UnicodePerformance.cpp +++ b/samples/source/UnicodePerformance.cpp @@ -11,6 +11,8 @@ #include <cerrno> #include <stdexcept> +//#define ENABLE_XMP_CPP_INTERFACE 1; + using namespace std; #if WIN_ENV diff --git a/samples/source/XMPCoreCoverage.cpp b/samples/source/XMPCoreCoverage.cpp index fd1e65a..e1dc30c 100644 --- a/samples/source/XMPCoreCoverage.cpp +++ b/samples/source/XMPCoreCoverage.cpp @@ -27,6 +27,8 @@ #include "public/include/XMP.hpp" #include "public/include/XMP.incl_cpp" +//#define ENABLE_XMP_CPP_INTERFACE 1; + using namespace std; #if WIN_ENV diff --git a/samples/source/XMPFilesCoverage.cpp b/samples/source/XMPFilesCoverage.cpp index 326b19a..c482694 100644 --- a/samples/source/XMPFilesCoverage.cpp +++ b/samples/source/XMPFilesCoverage.cpp @@ -24,6 +24,8 @@ #include "public/include/XMP.hpp" #include "public/include/XMP.incl_cpp" +//#define ENABLE_XMP_CPP_INTERFACE 1; + using namespace std; #if WIN_ENV diff --git a/samples/source/XMPIterations.cpp b/samples/source/XMPIterations.cpp index f93b7d7..7a02a24 100644 --- a/samples/source/XMPIterations.cpp +++ b/samples/source/XMPIterations.cpp @@ -15,6 +15,8 @@ #include <string> #include <cstring> +//#define ENABLE_XMP_CPP_INTERFACE 1; + // Must be defined to instantiate template classes #define TXMP_STRING_TYPE std::string diff --git a/samples/source/common/DumpFile.cpp b/samples/source/common/DumpFile.cpp index 32dd253..4d1e59f 100644 --- a/samples/source/common/DumpFile.cpp +++ b/samples/source/common/DumpFile.cpp @@ -28,7 +28,11 @@ // // DumpFile does depend on XMPCore and the packetscanner from XMPFiles. + #include <stdarg.h> + +#include "source/ExpatAdapter.hpp" + #include "samples/source/common/globals.h" #include "samples/source/common/DumpFile.h" #include "samples/source/common/LargeFileAccess.hpp" @@ -297,12 +301,12 @@ struct JpegMarker { }; typedef std::vector<JpegMarker> JpegMarkers; -static void DumpTIFF ( XMP_Uns8 * tiffContent, XMP_Uns32 tiffLen, XMP_Uns32 fileOffset, const char * label, std::string path ); +static void DumpTIFF ( XMP_Uns8 * tiffContent, XMP_Uns32 tiffLen, XMP_Uns32 fileOffset, const char * label, std::string path, bool isHeaderAbsent = false ); static void DumpTIFF ( const JpegMarkers& psirMarkers, XMP_Uns8 * dataStart, const char * label, std::string path ); static void DumpIPTC ( XMP_Uns8 * iptcOrigin, XMP_Uns32 iptcLen, XMP_Uns32 fileOffset, const char * label ); static void DumpImageResources ( XMP_Uns8 * psirOrigin, XMP_Uns32 psirLen, XMP_Uns32 fileOffset, const char * label ); static void DumpImageResources ( const JpegMarkers& psirMarkers, XMP_Uns8 * dataStart, const char * label ); -static void DumpIFDChain ( XMP_Uns8 * startPtr, XMP_Uns8 * endPtr, XMP_Uns8 * tiffContent, XMP_Uns32 fileOffset, const char * label, std::string path ); +static void DumpIFDChain ( XMP_Uns8 * startPtr, XMP_Uns8 * endPtr, XMP_Uns8 * tiffContent, XMP_Uns32 fileOffset, const char * label, std::string path, bool isHeaderAbsent = false ); // ================================================================================================= @@ -416,10 +420,11 @@ enum { kTIFF_SRational = 10, kTIFF_Float = 11, kTIFF_Double = 12, - kTIFF_TypeEnd + kTIFF_IFD = 13, + kTIFF_TypeEnd = kTIFF_IFD }; -static const int sTIFF_TypeSizes[] = { 0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8 }; +static const int sTIFF_TypeSizes[] = { 0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8, 4 }; static const char * sTIFF_TypeNames[] = { "", "BYTE", "ASCII", "SHORT", "LONG", "RATIONAL", "SBYTE", "UNDEFINED", "SSHORT", "SLONG", "SRATIONAL", "FLOAT", "DOUBLE" }; @@ -958,6 +963,12 @@ static const XMP_Uns32 kISOBrand_mp41 = 0x6D703431UL; static const XMP_Uns32 kISOBrand_mp42 = 0x6D703432UL; static const XMP_Uns32 kISOBrand_avc1 = 0x61766331UL; static const XMP_Uns32 kISOBrand_f4v = 0x66347620UL; +static const XMP_Uns32 kISOBrand_isom = 0x69736F6DUL; +static const XMP_Uns32 kISOBrand_3gp4 = 0x33677034UL; +static const XMP_Uns32 kISOBrand_3g2a = 0x33673261UL; +static const XMP_Uns32 kISOBrand_3g2b = 0x33673262UL; +static const XMP_Uns32 kISOBrand_3g2c = 0x33673263UL; + static const XMP_Uns32 kQTTag_XMP_ = 0x584D505FUL; @@ -1047,6 +1058,11 @@ CheckFileFormat ( const char * filePath, XMP_Uns8 * fileContent, XMP_Int64 fileS case kISOBrand_mp41: case kISOBrand_mp42: case kISOBrand_avc1: + case kISOBrand_isom: + case kISOBrand_3gp4: + case kISOBrand_3g2a: + case kISOBrand_3g2b: + case kISOBrand_3g2c: return kXMP_MPEG4File; break; @@ -1071,6 +1087,11 @@ CheckFileFormat ( const char * filePath, XMP_Uns8 * fileContent, XMP_Int64 fileS if ( LookupFileExtMapping (filePath) == kXMP_MPEGFile ) return kXMP_MPEGFile; if ( LookupFileExtMapping (filePath) == kXMP_MOVFile ) return kXMP_MOVFile; + std::string fileData = (char*)fileContent; + if ( (fileSize > 30) && (int)fileData.find ( "<svg" ) >= 0 ) { + return kXMP_SVGFile; + } + return kXMP_UnknownFile; } // CheckFileFormat @@ -1676,6 +1697,14 @@ DumpOneIFD (int ifdIndex, XMP_Uns8 * ifdPtr, XMP_Uns8 * endPtr, case kTIFF_Double : break; + case kTIFF_IFD: + if ( valueCount == 1 ) { + value32 = TIFF_GetUns32 ( valuePtr ); + tree->addComment ( "hex value = 0x%.8X", value32 ); + tree->changeValue ( "%u", value32 ); + } + break; + default : tree->addComment("** unknown type **"); break; @@ -1732,11 +1761,14 @@ DumpOneIFD (int ifdIndex, XMP_Uns8 * ifdPtr, XMP_Uns8 * endPtr, static void DumpIFDChain (XMP_Uns8 * startPtr, XMP_Uns8 * endPtr, - XMP_Uns8 * tiffContent, XMP_Uns32 fileOrigin, const char * label, std::string path) + XMP_Uns8 * tiffContent, XMP_Uns32 fileOrigin, const char * label, std::string path, bool isHeaderAbsent ) { XMP_Uns8 * ifdPtr = startPtr; XMP_Uns32 ifdOffset = startPtr - tiffContent; + if (isHeaderAbsent) // It's a kind of hack to iterate all the ifdboxes at least once. + ifdOffset = 1; + for (size_t ifdIndex = 0; ifdOffset != 0; ++ifdIndex) { if ((ifdPtr < tiffContent) || (ifdPtr >= endPtr)) { @@ -1757,7 +1789,7 @@ DumpIFDChain (XMP_Uns8 * startPtr, XMP_Uns8 * endPtr, // ================================================================================================= static void -DumpTIFF (XMP_Uns8 * tiffContent, XMP_Uns32 tiffLen, XMP_Uns32 fileOffset, const char * label, std::string path) +DumpTIFF (XMP_Uns8 * tiffContent, XMP_Uns32 tiffLen, XMP_Uns32 fileOffset, const char * label, std::string path, bool isHeaderAbsent) { tree->pushNode("TIFF content from %s", label); // ! TIFF can be nested because of the Photoshop 6 weiredness. Save and restore the procs. @@ -1765,27 +1797,43 @@ DumpTIFF (XMP_Uns8 * tiffContent, XMP_Uns32 tiffLen, XMP_Uns32 fileOffset, const GetUns32_Proc save_GetUns32 = TIFF_GetUns32; GetUns64_Proc save_GetUns64 = TIFF_GetUns64; - if (CheckBytes(tiffContent,"II\x2A\x00",4)) { + XMP_Uns32 ifdOffset = 0; + + if (!isHeaderAbsent) + { + if (CheckBytes(tiffContent, "II\x2A\x00", 4)) { + beTIFF = false; + TIFF_GetUns16 = GetUns16LE; + TIFF_GetUns32 = GetUns32LE; + TIFF_GetUns64 = GetUns64LE; + tree->addComment("Little endian "); + } + else if (CheckBytes(tiffContent, "MM\x00\x2A", 4)) { + beTIFF = true; + TIFF_GetUns16 = GetUns16BE; + TIFF_GetUns32 = GetUns32BE; + TIFF_GetUns64 = GetUns64BE; + tree->addComment("Big endian "); + } + else { + tree->comment("** Missing TIFF image file header tree."); + return; + } + + tree->addComment("TIFF from %s, offset %d (0x%X), size %d", label, fileOffset, fileOffset, tiffLen); + + ifdOffset = TIFF_GetUns32(tiffContent + 4); + } + else + { beTIFF = false; TIFF_GetUns16 = GetUns16LE; TIFF_GetUns32 = GetUns32LE; TIFF_GetUns64 = GetUns64LE; tree->addComment("Little endian "); - } else if (CheckBytes(tiffContent,"MM\x00\x2A",4)) { - beTIFF = true; - TIFF_GetUns16 = GetUns16BE; - TIFF_GetUns32 = GetUns32BE; - TIFF_GetUns64 = GetUns64BE; - tree->addComment("Big endian "); - } else { - tree->comment("** Missing TIFF image file header tree."); - return; } - tree->addComment("TIFF from %s, offset %d (0x%X), size %d", label, fileOffset, fileOffset, tiffLen); - - XMP_Uns32 ifdOffset = TIFF_GetUns32 (tiffContent+4); - DumpIFDChain (tiffContent+ifdOffset, tiffContent+tiffLen, tiffContent, fileOffset, label, path); + DumpIFDChain(tiffContent + ifdOffset, tiffContent + tiffLen, tiffContent, fileOffset, label, path, isHeaderAbsent); TIFF_GetUns16 = save_GetUns16; TIFF_GetUns32 = save_GetUns32; @@ -2017,7 +2065,6 @@ static const XMP_Uns8 kUUID_IPTC[16] = { 0x09, 0xA1, 0x4E, 0x97, 0xC0, 0xB4, 0x42, 0xE0, 0xBE, 0xBF, 0x36, 0xDF, 0x6F, 0x0C, 0xE3, 0x6F }; static const XMP_Uns8 kUUID_PSIR[16] = { 0x2C, 0x4C, 0x01, 0x00, 0x85, 0x04, 0x40, 0xB9, 0xA0, 0x3E, 0x56, 0x21, 0x48, 0xD6, 0xDF, 0xEB }; - // ------------------------------------------------------------------------------------------------- /** @@ -2077,13 +2124,13 @@ DumpISOBoxes ( LFA_FileRef file, XMP_Uns32 maxBoxLen, std::string _isoPath ) // or, uhm, something garbage-ish... if ( LFA_Tell(file) + boxHeaderSize > endOfThisLevel ) { - XMP_Int64 numUnusedBytes = (LFA_Tell(file) + boxHeaderSize - endOfThisLevel); + XMP_Int64 numUnusedBytes = (endOfThisLevel - LFA_Tell(file)); tree->digestString( file, isoPath+"unused", numUnusedBytes, false ); tree->addComment( "'free' since too small for a box" ); bool ok; - LFA_Seek( file, maxBoxLen, SEEK_CUR, &ok ); - assertMsg("skippind to-small space failed (truncated file?)", ok ); + LFA_Seek( file, endOfThisLevel, SEEK_SET, &ok ); + assertMsg("skippind to-small space failed (truncated file?)", ok ); continue; // could just as well: return } @@ -2106,21 +2153,27 @@ DumpISOBoxes ( LFA_FileRef file, XMP_Uns32 maxBoxLen, std::string _isoPath ) break; } - XMP_Uns32 tempBoxType = GetUns32LE(&boxType); - std::string boxString( fromArgs( "%.4s" , &tempBoxType) ); + XMP_Uns32 tempBoxType = GetUns32LE(&boxType); + std::string boxString( fromArgs( "%.4s" , &tempBoxType) ); - // substitute mac-copyright signs with an easier-to-handle "(c)" + if(boxString.size() != 0) + { + // substitute mac-copyright signs with an easier-to-handle "(c)" #if !IOS_ENV - if ( boxString.at(0) == 0xa9 ) + if ( boxString.at(0) == 0xa9 ) #else - if ( boxString.at(0) == 0xffffffa9 ) + if ( boxString.at(0) == 0xffffffa9 ) #endif - boxString = std::string("(c)") + boxString.substr(1); + boxString = std::string("(c)") + boxString.substr(1); + } + else + break; + isoPath = origIsoPath + boxString + "/"; // TEMP // Log::info("pushing %s, endOfThisLevel: 0x%X", isoPath.c_str(), endOfThisLevel ); - // printf ("%s \n", isoPath.c_str()); + // printf ("%s \n", isoPath.c_str()); tree->pushNode( isoPath ); tree->addComment("offset 0x%I64X, size 0x%I64X", boxPos , boxSize); @@ -2317,9 +2370,9 @@ DumpISOBoxes ( LFA_FileRef file, XMP_Uns32 maxBoxLen, std::string _isoPath ) XMP_Int64 endOfTrailingBoxes = LFA_Tell(file) + remainingSize; while ( LFA_Tell(file) < endOfTrailingBoxes ) { - LFA_Tell( file ); - DumpISOBoxes( file, entrySize, isoPath ); - LFA_Tell( file ); + LFA_Tell(file); + DumpISOBoxes( file, entrySize, isoPath ); + LFA_Tell(file); } assertMsg( "did not boil down to zero", LFA_Tell(file) == endOfTrailingBoxes ); @@ -2385,7 +2438,7 @@ DumpISOBoxes ( LFA_FileRef file, XMP_Uns32 maxBoxLen, std::string _isoPath ) } case 0x74727063: // cprt, FULLBOX - if ( isoPath == "moov/udta/cprt/") + if ( isoPath == "moov/udta/cprt/" || isoPath == "moov/uuid/udta/cprt/" ) { digestISOFullBoxExtension( file, isoPath, remainingSize, version, flags ); @@ -2421,6 +2474,18 @@ DumpISOBoxes ( LFA_FileRef file, XMP_Uns32 maxBoxLen, std::string _isoPath ) // (c)-style quicktime boxes and boxes of no interest: default: + if ( (boxType & 0xA9) == 0xA9) // (c)something + { + if ( 0 == isoPath.compare( 0 , 10, "moov/udta/" )) + { // => Quicktime metadata "international text sequence" ( size, language code, value ) + digestInternationalTextSequence( file, isoPath, &remainingSize ); + } else + { + tree->addComment("WARNING: unknown flavor of (c)*** boxes, neither QT nor iTunes"); + } + break; + } + //boxes of no interest: break; } @@ -3385,6 +3450,10 @@ DumpRIFFChunk ( LFA_FileRef file, XMP_Int64 parentEnd, std::string origChunkPath isXMPchunk = true; } + bool isIDITChunk = + ( ( origChunkPath == "RIFF:AVI/LIST:hdrl" || origChunkPath == "RIFF:AVI /LIST:hdrl" ) + && idString == "IDIT" ); + // deal with chunks of interest ///////////////////////////////////////////// // a little prelude for disp chunk if ( isDispChunk ) @@ -3399,7 +3468,7 @@ DumpRIFFChunk ( LFA_FileRef file, XMP_Int64 parentEnd, std::string origChunkPath chunkSize -= 4; } - if ( isListInfo || isListTdat || isDispChunk ) + if (isListInfo || isListTdat || isDispChunk || isIDITChunk) { // dump that string: std::string value; @@ -3501,6 +3570,10 @@ DumpRIFFChunk ( LFA_FileRef file, XMP_Int64 parentEnd, std::string origChunkPath // parse till first \0 std::string description( descriptionBuffer ); + // Dumping the iXML chunk. Needed for testing + // Add iXML chunk as a node to tree + tree->setKeyValue( chunkPath+".ValueOfIXMLChunk", description ); + delete[] descriptionBuffer; tree->addComment("packet end: 0x%llX", LFA_Tell( file ) ); @@ -3940,6 +4013,93 @@ DumpInDesign (LFA_FileRef file, XMP_Uns32 inddLen) // ================================================================================================= +static void +DumpSVGTag ( std::string basePath, XML_NodePtr currentNode ) +{ + if ( currentNode ) + { + tree->pushNode ( basePath + currentNode->name ); + + // Iterating over all XML children. + XML_NodeVector currNodeVector = currentNode->content; + for ( int i = 0; i < currNodeVector.size ( ); i++ ) + { + // Dump all children who are element nodes. + if ( currNodeVector[i]->kind == kElemNode ) + DumpSVGTag ( basePath + currentNode->name + "/", currNodeVector[i] ); + + // Extract the value from datanodes and put in TagMap if it's not yet available. + if ( currNodeVector[i]->kind == kCDataNode && tree->getValue ( basePath + currentNode->name ) == "" ) + tree->updateKeyValue ( basePath + currentNode->name, currNodeVector[i]->value ); + } + } + +} // DumpSVGTag + +// ================================================================================================= + +static void +DumpSVG ( LFA_FileRef file, XMP_Uns32 svgLen ) +{ + // SVG is an XML based format.We consider any file as SVG file if the given file contains a SVG tag. + // Hence CheckFileFormat looks for presence of "<svg" in the file. + // + // For Dumping SVG elements we are using ExpatAdapter. Below code will parse given file using this + // adapter and add different tags in the TagMap tree. + // + // Below is the currently supported structure of known tags for this format. + // <svg> + // <title/> + // <desc/> + // <metadata> + // <x:xmpmeta/> + // <...> + // <...> + // </metadata> + // <...> + // <...> + // </svg> + + ExpatAdapter * pExpatAdapter = XMP_NewExpatAdapter ( false ); + + if ( pExpatAdapter == 0 ) + { + tree->comment ( "ExpatAdapter initialization failed. Cann't parse SVG file." ); + return; + } + + // Allocating big enough memory on heap to read file contents. + XMP_Uns8 *fileContent = new XMP_Uns8[svgLen + 1]; + memset ( fileContent, 0, (svgLen + 1)*sizeof ( XMP_Uns8 ) ); + + // Reading total file in buffer (fileContent) + LFA_Seek ( file, 0, SEEK_SET ); + LFA_Read ( file, fileContent, svgLen + 1, false ); + + // Parsing the file with ExpatAdapter + pExpatAdapter->ParseBuffer ( fileContent, svgLen + 1, false /* not the end */ ); + + // Finding <svg> element and adding to TagMap tree. + XML_NodePtr svgNode = pExpatAdapter->tree.GetNamedElement ( "http://www.w3.org/2000/svg", "svg" ); + DumpSVGTag ( "", svgNode ); + + // De-allocating all the resources. + if ( fileContent ) + { + delete[] fileContent; + fileContent = NULL; + } + + if ( pExpatAdapter ) + { + delete pExpatAdapter; + pExpatAdapter = NULL; + } + +} // DumpSVG + +// ================================================================================================= + #define kSWF_FileAttributesTag 69 #define kSWF_MetadataTag 77 @@ -4788,6 +4948,7 @@ static void DumpID3v22Frames ( LFA_FileRef file, XMP_Uns8 vMajor, XMP_Uns32 fram static void DumpID3v23Frames ( LFA_FileRef file, XMP_Uns8 vMajor, XMP_Uns32 framePos, XMP_Uns32 frameEnd ) { // Dump the frames in an ID3 v2.3 or v2.4 tag. + int iIterator = 0; while ( (framePos < frameEnd) && ((frameEnd - framePos) >= 10) ) { @@ -4879,9 +5040,76 @@ static void DumpID3v23Frames ( LFA_FileRef file, XMP_Uns8 vMajor, XMP_Uns32 fram } } + + else if ( CheckBytes ( frameHead.id , "APIC" , 4 ) ) { - framePos += (sizeof(frameHead) + frameHead.size); + ++iIterator; + unsigned int iOffset = 0; + CaptureFileData ( file , 0 , frameHead.size ); + + char encoding[2]; + memset ( encoding , 0x0 , 2 ); + encoding[0] = sDataPtr[iOffset++]; + tree->setKeyValue ( fromArgs ( "ID3v2:APIC-encodingType_%d" , iIterator ) , encoding ); + char * mimeType = ( char* ) (sDataPtr + iOffset); + iOffset += strlen ( mimeType ) + 1; //1 is for null termination + tree->setKeyValue ( fromArgs ( "ID3v2:APIC-mimeType_%d" , iIterator ) , mimeType ); + + char pictureType[2]; + memset ( pictureType , 0x0 , 2 ); + pictureType[0] = sDataPtr[iOffset++]; + tree->setKeyValue ( fromArgs ( "ID3v2:APIC-pictureType_%1d" , iIterator ) , pictureType ); + + bool bigEndian = PrintID3Encoding ( encoding[0] , (sDataPtr + iOffset) ); + if ( encoding[0] == 0x00 ) { + + XMP_Uns8 * descrPtr = sDataPtr + iOffset; + XMP_Uns8 * valuePtr = descrPtr; + + while ( *valuePtr != 0 ) ++valuePtr; + ++valuePtr; //Null termination + + size_t descrBytes = valuePtr - descrPtr; + tree->setKeyValue ( fromArgs ( "ID3v2:APIC-descr_%d" , iIterator ) , convert8Bit ( descrPtr , false , descrBytes - 1 ).c_str ( ) ); + iOffset += descrBytes; + } + else if ( encoding[0] == 0x01 ) { + + XMP_Uns16 * descrPtr = ( XMP_Uns16* ) (sDataPtr + iOffset); + XMP_Uns16 * valuePtr = descrPtr; + + while ( *valuePtr != 0 ) ++valuePtr; + ++valuePtr; //Null termination + + size_t descrBytes = 2 * (valuePtr - descrPtr); + tree->setKeyValue ( fromArgs ( "ID3v2:APIC-descr_%d" , iIterator ) , convert16Bit ( bigEndian , ( XMP_Uns8* ) (descrPtr + 1) , false , descrBytes - 4 ).c_str ( ) ); + iOffset += descrBytes; + } + + XMP_Uns8 *picPtr = (sDataPtr + iOffset); + unsigned long size_PictureData = frameHead.size - iOffset; + + char picDataSize[8]; + memset ( picDataSize , 0x0 , 8 ); + sprintf ( picDataSize, "%d", size_PictureData ); + + std::string picData; + picData.assign ( ( char* ) picPtr , size_PictureData ); + + tree->setKeyValue ( fromArgs ( "ID3v2:APIC-pictureData_%d" , iIterator ) , picData ); + tree->setKeyValue ( fromArgs ( "ID3v2:APIC-pictureDataSize_%d" , iIterator ) , picDataSize ); + } + + framePos += (sizeof(frameHead) + frameHead.size); + + } + + if ( iIterator ) { + char noOfAPICs[2]; + memset ( noOfAPICs , 0x0 , 2 ); + sprintf ( noOfAPICs , "%d" , iIterator ); + tree->setKeyValue ( "ID3v2:NoOfAPIC" , noOfAPICs ); } if ( framePos < frameEnd ) { @@ -5328,6 +5556,12 @@ void DumpFile::Scan (std::string filename, TagTree &tagTree, bool resetTree) DumpPS ( fileRef, fileLen ); tagTree.popNode(); + } else if ( format == kXMP_SVGFile ) { + + tagTree.pushNode ( "Dumping SVG file" ); + tagTree.addComment ( "size %lld (0x%llx)", fileLen, fileLen ); + DumpSVG ( fileRef, fileLen ); + tagTree.popNode ( ); } else if ( format == kXMP_UnknownFile ) { tagTree.pushNode ( "Unknown format. packet scanning, size %d (0x%X)", fileLen, fileLen ); diff --git a/samples/source/common/TagTree.cpp b/samples/source/common/TagTree.cpp index aa8ca12..761ab22 100644 --- a/samples/source/common/TagTree.cpp +++ b/samples/source/common/TagTree.cpp @@ -118,6 +118,25 @@ void TagTree::setKeyValue(const std::string key,const std::string value, const s Log::info( " setKeyValue( %s |-> %s) [%s]", key.c_str(), value.c_str(), _comment.c_str() ); } +void TagTree::updateKeyValue ( const std::string key, const std::string value, const std::string _comment ) +{ + Node* pCurNode = *nodeStack.rbegin ( ); //current Node + pCurNode->children.push_back ( Node ( key, value, _comment ) ); + + if ( key.size ( ) == 0 ) { // standalone comment? + if ( value.size ( ) != 0 ) // must have no value + Log::error ( "no key but value found." ); + return; // ==> do not add to tag-map + } + + //add to Map ----------------------------------- + lastNode = &*(pCurNode->children.rbegin ( )); + tagMap[key] = lastNode; + + if ( verbose ) + Log::info ( " setKeyValue( %s |-> %s) [%s]", key.c_str ( ), value.c_str ( ), _comment.c_str ( ) ); +} + void TagTree::digest(LFA_FileRef file,const std::string key /*=NULL*/, void* returnValue /*=""*/, XMP_Int32 numOfBytes /*=0*/ ) diff --git a/samples/source/common/TagTree.h b/samples/source/common/TagTree.h index 857b141..9bd46d3 100644 --- a/samples/source/common/TagTree.h +++ b/samples/source/common/TagTree.h @@ -107,6 +107,9 @@ public: //sets a key-value pair and optinal comment. value is also optional and may be set at a later time //can also be used to set pure, standalone comments (using key==value=="") void setKeyValue(const std::string key,const std::string value="", const std::string comment=""); + + //updates the value of key without creating new key, value pairs. + void updateKeyValue ( const std::string key, const std::string value, const std::string comment = "" ); // convenience functions ////////////////////////////////////////////////////////////////// // these functions read bytes (assert in file-length), dump them to screen (as hex or as number) diff --git a/samples/source/common/globals.h b/samples/source/common/globals.h index 8b0d09c..3998476 100644 --- a/samples/source/common/globals.h +++ b/samples/source/common/globals.h @@ -69,8 +69,10 @@ const char AEOEUE_UTF8_CSTRING[]={0xC3, 0x84, 0xC3, 0x96, 0xC3, 0x9C,'\0'}; const std::string AEOEUE_UTF8(AEOEUE_UTF8_CSTRING); const std::string AEOEUE_UTF8_BUGINESE("<C3 84 C3 96 C3 9C>"); + const std::string AEOEUE_UTF8_BUGINESE_EVEN ( "<C3 84 C3 96 C3 9C 00>" ); const std::string AEOEUE_WIN_LOCAL_BUGINESE("<C4 D6 DC>"); + const std::string AEOEUE_WIN_LOCAL_BUGINESE_EVEN ( "<C4 D6 DC 00>" ); const std::string AEOEUE_MAC_LOCAL_BUGINESE("<80 85 86>"); const std::string AEOEUE_WIN_MOJIBAKE_BUGINESE("<E2 82 AC E2 80 A6 E2 80 A0>"); diff --git a/samples/source/dumpfile/main.cpp b/samples/source/dumpfile/main.cpp index bd11b05..c18f6d7 100644 --- a/samples/source/dumpfile/main.cpp +++ b/samples/source/dumpfile/main.cpp @@ -41,6 +41,7 @@ const int DUMPFILEVERSION=2; #include "public/include/XMP.hpp" //NB: no XMP.incl_cpp here on purpose, gets compiled in main... #include "public/include/XMP.incl_cpp" //include in EXACTLY one source file (i.e. main, in Action gets you trouble...) #include "public/include/XMP_Const.h" +#include "source/XML_Node.cpp" //utils #include "samples/source/common/Log.h" |