void P2_MetaHandler::UpdateFile ( bool doSafeUpdate ) { if ( ! this->needsUpdate ) return; this->needsUpdate = false; // Make sure only called once. XMP_Assert ( this->parent->UsesLocalIO() ); // Update the internal legacy XML tree if we have one, and set the digest in the XMP. bool updateLegacyXML = false; P2_Clip* p2Clip = 0; XML_NodePtr clipMetadata = 0; if ( this->p2ClipManager.IsValidP2() ) { p2Clip=this->p2ClipManager.GetManagedClip(); clipMetadata = p2Clip->GetClipMetadataNode(); if ( clipMetadata != 0 ) { bool xmpFound; std::string xmpValue; XML_Node * xmlNode; xmpFound = this->xmpObj.GetLocalizedText ( kXMP_NS_DC, "title", "", "x-default", 0, &xmpValue, 0 ); if ( xmpFound && p2Clip->GetClipContentNode()) { xmlNode = this->ForceChildElement ( p2Clip->GetClipContentNode(), "ClipName", 3, false ); if ( xmpValue != xmlNode->GetLeafContentValue() ) { xmlNode->SetLeafContentValue ( xmpValue.c_str() ); updateLegacyXML = true; } } xmpFound = this->xmpObj.GetArrayItem ( kXMP_NS_DC, "creator", 1, &xmpValue, 0 ); if ( xmpFound ) { xmlNode = this->ForceChildElement ( clipMetadata , "Access", 3, false ); // "Creator" must be first child of "Access" node else Panasonic P2 Viewer gives an error. xmlNode = this->ForceChildElement ( xmlNode, "Creator", 4 , true); if ( xmpValue != xmlNode->GetLeafContentValue() ) { xmlNode->SetLeafContentValue ( xmpValue.c_str() ); updateLegacyXML = true; } } } // Half the startTimeCode frame number value in XML if require so std::string xmpStartTimeCode; bool isTimecodeExists = this->xmpObj.GetStructField(kXMP_NS_DM, "startTimecode", kXMP_NS_DM, "timeValue", &xmpStartTimeCode, 0); if (isTimecodeExists) { std::string frameFormat; this->xmpObj.GetStructField(kXMP_NS_DM, "startTimecode", kXMP_NS_DM, "timeFormat", &frameFormat, 0); if (frameFormat == "50Timecode" || frameFormat == "5994DropTimecode" || frameFormat == "5994NonDropTimecode") { p2Clip = this->p2ClipManager.GetManagedClip(); XMP_StringPtr p2NS = p2Clip->GetP2RootNode()->ns.c_str(); XML_NodePtr legacyVideoContext = p2Clip->GetEssenceListNode(); if (legacyVideoContext != 0) { legacyVideoContext = legacyVideoContext->GetNamedElement(p2NS, "Video"); XML_NodePtr legacyProp = legacyVideoContext->GetNamedElement(p2NS, "StartTimecode"); if ((legacyProp != 0) && legacyProp->IsLeafContentNode()) { AdjustTimeCode( xmpStartTimeCode, true ); if (xmpStartTimeCode != legacyProp->GetLeafContentValue()) { legacyProp->SetLeafContentValue(xmpStartTimeCode.c_str()); updateLegacyXML = true; } } } } } std::string newDigest; this->p2ClipManager.GetManagedClip()->CreateDigest ( &newDigest ); this->xmpObj.SetStructField ( kXMP_NS_XMP, "NativeDigests", kXMP_NS_XMP, "P2", newDigest.c_str(), kXMP_DeleteExisting ); } this->xmpObj.SerializeToBuffer ( &this->xmpPacket, this->GetSerializeOptions() ); // ----------------------------------------------------------------------- // Update the XMP file first, don't let legacy XML failures block the XMP. std::string xmpPath; this->MakeClipFilePath ( &xmpPath, ".XMP" ); bool haveXMP = Host_IO::Exists ( xmpPath.c_str() ); if ( ! haveXMP ) { XMP_Assert ( this->parent->ioRef == 0 ); Host_IO::Create ( xmpPath.c_str() ); this->parent->ioRef = XMPFiles_IO::New_XMPFiles_IO ( xmpPath.c_str(), Host_IO::openReadWrite ); if ( this->parent->ioRef == 0 ) XMP_Throw ( "Failure opening P2 XMP file", kXMPErr_ExternalFailure ); } XMP_IO* xmpFile = this->parent->ioRef; XMP_Assert ( xmpFile != 0 ); XIO::ReplaceTextFile ( xmpFile, this->xmpPacket, (haveXMP & doSafeUpdate) ); // -------------------------------------------- // Now update the legacy XML file if necessary. if ( updateLegacyXML ) { std::string legacyXML, xmlPath; /*bug # 3217688: xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance namespace must be defined at the root node "P2Main" in legacy XML else Panasonic P2 Viewer gives an error. So we are adding a dummy attribute with this namespace to clipContent/clipMetadata (whichever is non-null) before serializing the XML tree. We are also undoing it below after serialization.*/ XML_Node *parentNode = AddXSINamespace(p2Clip->GetClipContentNode(), clipMetadata); p2Clip->SerializeP2ClipContent ( legacyXML ); if(parentNode){ // Remove the dummy attribute added to clipContent/clipMetadata. delete parentNode->attrs[parentNode->attrs.size()-1]; parentNode->attrs.pop_back(); } this->MakeClipFilePath ( &xmlPath, ".XML" ); bool haveXML = Host_IO::Exists ( xmlPath.c_str() ); if ( ! haveXML ) Host_IO::Create ( xmlPath.c_str() ); Host_IO::FileRef hostRef = Host_IO::Open ( xmlPath.c_str(), Host_IO::openReadWrite ); if ( hostRef == Host_IO::noFileRef ) XMP_Throw ( "Failure opening P2 legacy XML file", kXMPErr_ExternalFailure ); XMPFiles_IO origXML ( hostRef, xmlPath.c_str(), Host_IO::openReadWrite ); XIO::ReplaceTextFile ( &origXML, legacyXML, (haveXML & doSafeUpdate) ); origXML.Close(); } } // P2_MetaHandler::UpdateFile