// ================================================================================================= // Copyright Adobe // Copyright 2015 Adobe // All Rights Reserved // // NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms // of the Adobe license agreement accompanying it. // ================================================================================================= #define IMPLEMENTATION_HEADERS_CAN_BE_INCLUDED 1 #include "XMPCore/ImplHeaders/DOMParserImpl.h" #include "XMPCore/ImplHeaders/ClientDOMParserWrapperImpl.h" #undef IMPLEMENTATION_HEADERS_CAN_BE_INCLUDED #include "XMPCommon/Interfaces/IError_I.h" #include "XMPCore/XMPCoreErrorCodes.h" #include "XMPCore/Interfaces/IArrayNode_I.h" #include "XMPCore/Interfaces/IMetadata_I.h" #include "XMPCore/Interfaces/INodeIterator.h" #include "XMPCommon/Interfaces/ISharedMutex.h" #include "XMPCommon/Utilities/AutoSharedLock.h" #include "XMPCommon/Utilities/TSmartPointers_I.h" namespace AdobeXMPCore_Int { DOMParserImpl::DOMParserImpl() : mSharedMutex( ISharedMutex::CreateSharedMutex() ) { } spIDOMParser APICALL DOMParserImpl::Clone() const { DOMParserImpl * cloned = clone(); if ( cloned ) { AutoSharedLock lock( mSharedMutex ); cloned->mTreatKeyAsCaseInsensitiveCharBuffer = mTreatKeyAsCaseInsensitiveCharBuffer; cloned->mAllowDifferentValueTypesForExistingEntries = mAllowDifferentValueTypesForExistingEntries; if ( mKeysSet ) cloned->mKeysSet = new KeysSet( mKeysSet->begin(), mKeysSet->end() ); if ( mKeyValueTypeMap ) cloned->mKeyValueTypeMap = new keyValueTypeMap( mKeyValueTypeMap->begin(), mKeyValueTypeMap->end() ); for ( auto it = mMap.begin(), itEnd = mMap.end(); it != itEnd; ++it ) { cloned->mMap[ it->first ] = it->second; } } return MakeUncheckedSharedPointer( cloned, __FILE__, __LINE__, true ); } spIMetadata APICALL DOMParserImpl::Parse( const char * buffer, sizet bufferLength ) { auto node = ParseAsNode( buffer, bufferLength ); if ( node ) { switch ( node->GetNodeType() ) { case INode::kNTSimple: case INode::kNTArray: { spIMetadata meta = IMetadata::CreateMetadata(); meta->AppendNode( node ); return meta; } break; case INode::kNTStructure: { pIMetadata meta( NULL ); try { meta = node->GetInterfacePointer< IMetadata >(); } catch ( spcIError err ) { meta = NULL; } if ( meta ) { return MakeUncheckedSharedPointer( meta, __FILE__, __LINE__ ); } else { spIMetadata spMeta = IMetadata::CreateMetadata(); spMeta->AppendNode( node ); return spMeta; } } break; default: NOTIFY_ERROR( IError::kEDGeneral, kGECInternalFailure, "Unhandled situation occured", IError::kESOperationFatal, false, false ); } } return spIMetadata(); } static void AppendAsChildren( const spINode & contextNode, const spINode & parsedNode ) { if ( !contextNode ) NOTIFY_ERROR( IError::kEDParser, kPECInvalidContextNode, "Context Node is invalid", IError::kESOperationFatal, false, false ); auto contextNodeType = contextNode->GetNodeType(); if ( contextNodeType != INode::kNTStructure && contextNodeType != INode::kNTArray ) NOTIFY_ERROR( IError::kEDParser, kPECContextNodeIsNonComposite, "Context Node is non composite", IError::kESOperationFatal, true, static_cast< sizet >( contextNodeType ) ); pICompositeNode compositeContextNode = contextNode->GetInterfacePointer< ICompositeNode >(); pIMetadata meta( NULL ); try { meta = parsedNode->GetInterfacePointer< IMetadata >(); } catch ( spcIError err ) { meta = NULL; } if ( meta ) { auto it = meta->Iterator(); while ( it ) { auto childNode = it->GetNode(); it = it->Next(); childNode = meta->GetIMetadata_I()->RemoveNode( childNode->GetNameSpace(), childNode->GetName() ); compositeContextNode->AppendNode( childNode ); } } else { compositeContextNode->AppendNode( parsedNode ); } } static void ReplaceChildren( pIArrayNode contextArrayNode, const spINode & parsedNode ) { contextArrayNode->Clear(); pIMetadata meta( NULL ); try { meta = parsedNode->GetInterfacePointer< IMetadata >(); } catch ( spcIError err ) { meta = NULL; } if ( meta ) { auto it = meta->Iterator(); while ( it ) { auto childNode = it->GetNode(); it = it->Next(); childNode = meta->GetIMetadata_I()->RemoveNode( childNode->GetNameSpace(), childNode->GetName() ); contextArrayNode->AppendNode( childNode ); } } else { contextArrayNode->AppendNode( parsedNode ); } } static void ReplaceChildren( pIStructureNode contextStructureNode, const spINode & parsedNode ) { pIMetadata meta( NULL ); try { meta = parsedNode->GetInterfacePointer< IMetadata >(); } catch ( spcIError err ) { meta = NULL; } if ( meta ) { auto it = meta->Iterator(); while ( it ) { auto childNode = it->GetNode(); it = it->Next(); childNode = meta->GetIMetadata_I()->RemoveNode( childNode->GetNameSpace(), childNode->GetName() ); contextStructureNode->ReplaceNode( childNode ); } } else { contextStructureNode->ReplaceNode( parsedNode ); } } static void ReplaceChildren( const spINode & contextNode, const spINode & parsedNode ) { if ( !contextNode ) NOTIFY_ERROR( IError::kEDParser, kPECInvalidContextNode, "Context Node is invalid", IError::kESOperationFatal, false, false ); auto contextNodeType = contextNode->GetNodeType(); if ( contextNodeType != INode::kNTStructure && contextNodeType != INode::kNTArray ) NOTIFY_ERROR( IError::kEDParser, kPECContextNodeIsNonComposite, "Context Node is non composite", IError::kESOperationFatal, true, static_cast< sizet >( contextNodeType ) ); switch ( contextNodeType ) { case INode::kNTArray: ReplaceChildren( contextNode->GetInterfacePointer< IArrayNode >(), parsedNode ); break; case INode::kNTStructure: ReplaceChildren( contextNode->GetInterfacePointer< IStructureNode >(), parsedNode ); break; default: NOTIFY_ERROR( IError::kEDParser, kPECContextNodeIsNonComposite, "Context Node is non composite", IError::kESOperationFatal,true, static_cast< sizet >( contextNodeType ) ); break; } } static void AppendOrReplaceChildren( pIStructureNode contextStructureNode, const spINode & parsedNode ) { pIMetadata meta( NULL ); try { meta = parsedNode->GetInterfacePointer< IMetadata >(); } catch ( spcIError err ) { meta = NULL; } if ( meta ) { auto it = meta->Iterator(); while ( it ) { auto childNode = it->GetNode(); it = it->Next(); childNode = meta->GetIMetadata_I()->RemoveNode( childNode->GetNameSpace(), childNode->GetName() ); if ( contextStructureNode->GetIStructureNode_I()->GetNode( childNode->GetNameSpace(), childNode->GetName() ) ) contextStructureNode->ReplaceNode( childNode ); else contextStructureNode->AppendNode( childNode ); } } else { if ( contextStructureNode->GetIStructureNode_I()->GetNode( parsedNode->GetNameSpace(), parsedNode->GetName() ) ) contextStructureNode->ReplaceNode( parsedNode ); else contextStructureNode->AppendNode( parsedNode ); } } static void AppendOrReplaceChildren( const spINode & contextNode, const spINode & parsedNode ) { if ( !contextNode ) NOTIFY_ERROR( IError::kEDParser, kPECInvalidContextNode, "Context Node is invalid", IError::kESOperationFatal, false, false ); auto contextNodeType = contextNode->GetNodeType(); if ( contextNodeType != INode::kNTStructure && contextNodeType != INode::kNTArray ) NOTIFY_ERROR( IError::kEDParser, kPECContextNodeIsNonComposite, "Context Node is non composite", IError::kESOperationFatal, true, static_cast< sizet >( contextNodeType ) ); switch ( contextNodeType ) { case INode::kNTArray: ReplaceChildren( contextNode->GetInterfacePointer< IArrayNode >(), parsedNode ); break; case INode::kNTStructure: AppendOrReplaceChildren( contextNode->GetInterfacePointer< IStructureNode >(), parsedNode ); break; default: NOTIFY_ERROR( IError::kEDParser, kPECContextNodeIsNonComposite, "Context Node is non composite", IError::kESOperationFatal, true, static_cast< sizet >( contextNodeType ) ); break; } } static void InsertBefore( const spINode & contextNode, const spINode & parsedNode ) { if ( !contextNode ) NOTIFY_ERROR( IError::kEDParser, kPECInvalidContextNode, "Context Node is invalid", IError::kESOperationFatal, false, false ); if ( !contextNode->IsArrayItem() ) NOTIFY_ERROR( IError::kEDParser, kPECContextNodeParentIsNonArray, "Context Node's Parent is non array node", IError::kESOperationFatal, false, false ); pIMetadata meta( NULL ); try { meta = parsedNode->GetInterfacePointer< IMetadata >(); } catch ( spcIError err ) { meta = NULL; } pIArrayNode parentArrayNode = contextNode->GetINode_I()->GetRawParentPointer()->GetInterfacePointer< IArrayNode >(); if ( meta ) { auto it = meta->Iterator(); while ( it ) { auto childNode = it->GetNode(); it = it->Next(); childNode = meta->GetIMetadata_I()->RemoveNode( childNode->GetNameSpace(), childNode->GetName() ); parentArrayNode->InsertNodeAtIndex( childNode, contextNode->GetIndex() ); } } else { parentArrayNode->InsertNodeAtIndex( parsedNode, contextNode->GetIndex() ); } } static void InsertAfter( const spINode & contextNode, const spINode & parsedNode ) { if ( !contextNode ) NOTIFY_ERROR( IError::kEDParser, kPECInvalidContextNode, "Context Node is invalid", IError::kESOperationFatal, false, false ); if ( !contextNode->IsArrayItem() ) NOTIFY_ERROR( IError::kEDParser, kPECContextNodeParentIsNonArray, "Context Node's Parent is non array node", IError::kESOperationFatal, false, false ); pIMetadata meta( NULL ); try { meta = parsedNode->GetInterfacePointer< IMetadata >(); } catch ( spcIError err ) { meta = NULL; } pIArrayNode parentArrayNode = contextNode->GetINode_I()->GetRawParentPointer()->GetInterfacePointer< IArrayNode >(); if ( meta ) { auto it = meta->Iterator(); sizet index = contextNode->GetIndex() + 1; while ( it ) { auto childNode = it->GetNode(); it = it->Next(); childNode = meta->GetIMetadata_I()->RemoveNode( childNode->GetNameSpace(), childNode->GetName() ); parentArrayNode->InsertNodeAtIndex( childNode, index ); index = childNode->GetIndex() + 1; } } else { parentArrayNode->InsertNodeAtIndex( parsedNode, contextNode->GetIndex() + 1 ); } } static void ReplaceNode( spINode & node, const spINode & parsedNode ) { if ( node && node->IsArrayItem() && node->GetNodeType() != parsedNode->GetNodeType() ) { NOTIFY_ERROR( IError::kEDDataModel, kDMECArrayItemTypeDifferent, "node type is different than what currently array can hold", IError_v1::kESOperationFatal, true, static_cast< sizet >( node->GetNodeType() ), true, static_cast< sizet >( parsedNode->GetNodeType() ) ); } node = parsedNode; } void APICALL DOMParserImpl::ParseWithSpecificAction( const char * buffer, sizet bufferLength, eActionType actionType, spINode & node ) { auto parsedNode = ParseAsNode( buffer, bufferLength ); if ( parsedNode ) { switch ( actionType ) { case kATAppendAsChildren: AppendAsChildren( node, parsedNode ); break; case kATReplaceChildren: ReplaceChildren( node, parsedNode ); break; case kATAppendOrReplaceChildren: AppendOrReplaceChildren( node, parsedNode ); break; case kATInsertBefore: InsertBefore( node, parsedNode ); break; case kATInsertAfter: InsertAfter( node, parsedNode ); break; case kATReplace: ReplaceNode( node, parsedNode ); break; default: NOTIFY_ERROR( IError::kEDGeneral, kGECNotImplemented, "Not yet implemented", IError::kESOperationFatal, true, static_cast< sizet >( actionType ) ); } } } spISharedMutex APICALL DOMParserImpl::GetMutex() const { return mSharedMutex; } AdobeXMPCore::spIDOMParser IDOMParser_I::CreateDOMParser( pIClientDOMParser_base clientDOMParser ) { return MakeUncheckedSharedPointer( new ClientDOMParserWrapperImpl( clientDOMParser ), __FILE__, __LINE__, true ); } void DOMParserImpl::SetErrorCallback(XMPMeta::ErrorCallbackInfo * ec) { mGenericErrorCallbackPtr = ec; } }