// ================================================================================================= // Copyright Adobe // Copyright 2014 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/ArrayNodeImpl.h" #include "XMPCore/ImplHeaders/TNodeIteratorImpl.h" #undef IMPLEMENTATION_HEADERS_CAN_BE_INCLUDED #include "XMPCommon/Interfaces/IError_I.h" #include "XMPCore/XMPCoreErrorCodes.h" #include "XMPCommon/Interfaces/IUTF8String_I.h" #include "XMPCommon/Utilities/AutoSharedLock.h" #include "XMPCore/Interfaces/INodeIterator_I.h" #include "XMPCommon/Utilities/TSmartPointers_I.h" namespace AdobeXMPCore_Int { // All virtual functions ArrayNodeImpl::ArrayNodeImpl( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength, eArrayForm arrayForm ) : NodeImpl( nameSpace, nameSpaceLength, name, nameLength ) , mArrayForm( arrayForm ) {} IArrayNode_v1::eArrayForm APICALL ArrayNodeImpl::GetArrayForm() const { return mArrayForm; } INode_v1::eNodeType APICALL ArrayNodeImpl::GetChildNodeType() const { AutoSharedLock lock( mSharedMutex ); if ( mChildren.size() != 0 ) return mChildren[ 0 ]->GetNodeType(); return kNTAll; } spINode APICALL ArrayNodeImpl::GetNodeAtIndex( sizet index ) { sizet actualIndex = index - 1; AutoSharedLock lock( mSharedMutex ); if ( actualIndex < mChildren.size() ) { return MakeUncheckedSharedPointer( mChildren.at( actualIndex ).get(), __FILE__, __LINE__ ); } return spINode_I(); } void APICALL ArrayNodeImpl::InsertNodeAtIndex( const spINode & node, sizet index ) { sizet actualIndex = index - 1; { AutoSharedLock lock( mSharedMutex ); if ( actualIndex > mChildren.size() ) NOTIFY_ERROR( IError_base::kEDGeneral, kGECIndexOutOfBounds, "Trying to insert a node at an invalid index", IError_v1::kESOperationFatal, true, index, true, static_cast< sizet >( mChildren.size() ) ); } bool goAhead = CheckSuitabilityToBeUsedAsChildNode( node ); if ( goAhead ) { AutoSharedLock lock( mSharedMutex, true ); auto it = mChildren.begin(); std::advance( it, actualIndex ); it = mChildren.insert( it, MakeUncheckedSharedPointer( node.get(), __FILE__, __LINE__ ) ); pINode_I node_I = node->GetINode_I(); node_I->SetIndex( index ); node_I->ChangeParent( this ); std::advance( it, 1 ); for ( auto endIt = mChildren.end(); it != endIt; ++it ) { ( *it )->GetINode_I()->SetIndex( ++index ); } } } spINode APICALL ArrayNodeImpl::RemoveNodeAtIndex( sizet index ) { spINode node = GetNodeAtIndex( index ); if ( node ) { sizet actualIndex = index - 1; AutoSharedLock lock( mSharedMutex, true ); auto it = mChildren.begin(); std::advance( it, actualIndex ); it = mChildren.erase( it ); node->GetINode_I()->ChangeParent( NULL ); for ( auto endIt = mChildren.end(); it != endIt; ++it ) { ( *it )->GetINode_I()->SetIndex( index++ ); } } return node; } spINode APICALL ArrayNodeImpl::ReplaceNodeAtIndex( const spINode & node, sizet index ) { if ( CheckSuitabilityToBeUsedAsChildNode( node ) && GetNodeAtIndex( index ) ) { auto retValue = RemoveNodeAtIndex( index ); InsertNodeAtIndex( node, index ); return retValue; } else { NOTIFY_ERROR( IError_v1::kEDGeneral, kGECIndexOutOfBounds, "Trying to replace a node at an invalid index", IError_v1::kESOperationFatal, true, index, true, static_cast< sizet >( mChildren.size() ) ); } return spINode(); } void APICALL ArrayNodeImpl::AppendNode( const spINode & node ) { InsertNodeAtIndex( node, ChildCount() + 1 ); } spINodeIterator APICALL ArrayNodeImpl::Iterator() { AutoSharedLock lock( mSharedMutex ); auto beginIt = mChildren.begin(), endIt = mChildren.end(); if ( beginIt == endIt ) return spINodeIterator(); else return MakeUncheckedSharedPointer( new TNodeIteratorImpl< NodeVector::iterator >( beginIt, endIt ), __FILE__, __LINE__, true ); } sizet APICALL ArrayNodeImpl::ChildCount() const __NOTHROW__ { AutoSharedLock lock( mSharedMutex ); return mChildren.size(); } spIArrayNode APICALL ArrayNodeImpl::ConvertToArrayNode() { return MakeUncheckedSharedPointer( this, __FILE__, __LINE__ ); } INode_v1::eNodeType APICALL ArrayNodeImpl::GetNodeType() const { return kNTArray; } bool APICALL ArrayNodeImpl::HasContent() const { AutoSharedLock lock( mSharedMutex ); return mChildren.size() > 0; } void APICALL ArrayNodeImpl::ClearContents() { AutoSharedLock lock( mSharedMutex, true ); for ( auto it = mChildren.begin(), itEnd = mChildren.end(); it != itEnd; ++it ) { ( *it )->GetINode_I()->ChangeParent( NULL ); } mChildren.clear(); } spINode APICALL ArrayNodeImpl::CloneContents( bool ignoreEmptyNodes, bool ignoreNodesWithOnlyQualifiers, sizet qualifiersCount ) const { spIArrayNode newNode; if ( ignoreEmptyNodes && mChildren.size() == 0 ) { if ( ignoreNodesWithOnlyQualifiers && qualifiersCount == 0 ) return newNode; } newNode = IArrayNode_I::CreateArrayNode( mNameSpace, mName, mArrayForm ); for ( auto it = mChildren.begin(), endIt = mChildren.end(); it != endIt; ++it ) { spINode childNode = ( *it )->Clone( ignoreEmptyNodes, ignoreNodesWithOnlyQualifiers ); if ( childNode ) { newNode->AppendNode( childNode ); } } if ( ignoreEmptyNodes && newNode->ChildCount() == 0 ) { if ( ignoreNodesWithOnlyQualifiers ) return spINode(); else if ( !ignoreNodesWithOnlyQualifiers && qualifiersCount == 0 ) return spINode(); } return newNode; } void ArrayNodeImpl::resetChangesForChildren() const { AutoSharedLock lock( mSharedMutex ); for ( auto it = mChildren.begin(), itEnd = mChildren.end(); it != itEnd; ++it ) { ( *it )->AcknowledgeChanges(); } } bool ArrayNodeImpl::CheckSuitabilityToBeUsedAsChildNode( const spcINode & node ) const { bool result = CompositeNodeImpl::CheckSuitabilityToBeUsedAsChildNode( node ); if ( !result ) return false; eNodeType currentChildType = GetChildNodeType(); if ( currentChildType == kNTAll || currentChildType == node->GetNodeType() ) return true; else { NOTIFY_ERROR( IError_v1::kEDDataModel, kDMECArrayItemTypeDifferent, "node type is different than what currently array can hold", IError_v1::kESOperationFatal, true, static_cast< uint64 >( currentChildType ), true, static_cast< uint64 >( node->GetNodeType() ) ); } return false; } spIArrayNode IArrayNode_I::CreateArrayNode( const spcIUTF8String & nameSpace, const spcIUTF8String & name, eArrayForm arrayForm ) { return MakeUncheckedSharedPointer( new ArrayNodeImpl( nameSpace ? nameSpace->c_str() : NULL, nameSpace ? nameSpace->size() : 0, name ? name->c_str() : NULL, name ? name->size() : 0, arrayForm ), __FILE__, __LINE__, true ); } template<> spINode TNodeIteratorImpl< ArrayNodeImpl::NodeVector::iterator >::GetNodeFromIterator( const ArrayNodeImpl::NodeVector::iterator & it ) const { return MakeUncheckedSharedPointer( it->get(), __FILE__, __LINE__, false ); } } #if BUILDING_XMPCORE_LIB || SOURCE_COMPILING_XMPCORE_LIB namespace AdobeXMPCore { using namespace AdobeXMPCore_Int; spIArrayNode IArrayNode_v1::MakeShared( pIArrayNode_base ptr ) { if ( !ptr ) return spIArrayNode(); pIArrayNode p = IArrayNode::GetInterfaceVersion() > 1 ? ptr->GetInterfacePointer< IArrayNode >() : ptr; return MakeUncheckedSharedPointer( p, __FILE__, __LINE__, false ); } spIArrayNode IArrayNode_v1::CreateUnorderedArrayNode( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength ) { return MakeUncheckedSharedPointer( new ArrayNodeImpl( nameSpace, nameSpaceLength, name, nameLength, IArrayNode::kAFUnordered ), __FILE__, __LINE__, true ); } spIArrayNode IArrayNode_v1::CreateOrderedArrayNode( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength ) { return MakeUncheckedSharedPointer( new ArrayNodeImpl( nameSpace, nameSpaceLength, name, nameLength, IArrayNode::kAFOrdered ), __FILE__, __LINE__, true ); } spIArrayNode IArrayNode_v1::CreateAlternativeArrayNode( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength ) { return MakeUncheckedSharedPointer( new ArrayNodeImpl( nameSpace, nameSpaceLength, name, nameLength, IArrayNode::kAFAlternative ), __FILE__, __LINE__, true ); } } #endif // BUILDING_XMPCORE_LIB || SOURCE_COMPILING_XMPCORE_LIB