コード例 #1
0
ファイル: ReconcileIPTC.cpp プロジェクト: hfiguiere/exempi
static void ExportIPTC_SubjectCode ( const SXMPMeta & xmp, IPTC_Manager * iptc )
{
	std::string    xmpValue, iimValue;
	XMP_OptionBits xmpFlags;

	bool found = xmp.GetProperty ( kXMP_NS_IPTCCore, "SubjectCode", 0, &xmpFlags );
	if ( ! found ) {
		iptc->DeleteDataSet ( kIPTC_SubjectCode );
		return;
	}

	if ( ! XMP_PropIsArray ( xmpFlags ) ) return;	// ? Complain? Delete the DataSet?

	XMP_Index xmpCount  = xmp.CountArrayItems ( kXMP_NS_IPTCCore, "SubjectCode" );
	XMP_Index iptcCount = (XMP_Index) iptc->GetDataSet ( kIPTC_SubjectCode, 0 );

	if ( xmpCount != iptcCount ) iptc->DeleteDataSet ( kIPTC_SubjectCode );

	for ( XMP_Index ds = 0; ds < xmpCount; ++ds ) {	// ! XMP arrays are indexed from 1, IPTC from 0.

		(void) xmp.GetArrayItem ( kXMP_NS_IPTCCore, "SubjectCode", ds+1, &xmpValue, &xmpFlags );
		if ( ! XMP_PropIsSimple ( xmpFlags ) ) continue;	// ? Complain?
		if ( xmpValue.size() != 8 ) continue;	// ? Complain?

		iimValue = "IPTC:";
		iimValue += xmpValue;
		iimValue += ":::";	// Add the separating colons for the empty name portions.

		iptc->SetDataSet_UTF8 ( kIPTC_SubjectCode, iimValue.c_str(), (XMP_Uns32)iimValue.size(), ds );	// ! Appends if necessary.

	}

}	// ExportIPTC_SubjectCode
コード例 #2
0
ファイル: ReconcileIPTC.cpp プロジェクト: hfiguiere/exempi
static void ExportIPTC_Array ( const SXMPMeta & xmp, IPTC_Manager * iptc,
							   const char * xmpNS, const char * xmpProp, XMP_Uns8 id )
{
	std::string    value;
	XMP_OptionBits xmpFlags;

	bool found = xmp.GetProperty ( xmpNS, xmpProp, 0, &xmpFlags );
	if ( ! found ) {
		iptc->DeleteDataSet ( id );
		return;
	}

	if ( ! XMP_PropIsArray ( xmpFlags ) ) return;	// ? Complain? Delete the DataSet?

	XMP_Index xmpCount  = xmp.CountArrayItems ( xmpNS, xmpProp );
	XMP_Index iptcCount = (XMP_Index) iptc->GetDataSet ( id, 0 );

	if ( xmpCount != iptcCount ) iptc->DeleteDataSet ( id );

	for ( XMP_Index ds = 0; ds < xmpCount; ++ds ) {	// ! XMP arrays are indexed from 1, IPTC from 0.

		(void) xmp.GetArrayItem ( xmpNS, xmpProp, ds+1, &value, &xmpFlags );
		if ( ! XMP_PropIsSimple ( xmpFlags ) ) continue;	// ? Complain?

		NormalizeToCR ( &value );

		iptc->SetDataSet_UTF8 ( id, value.c_str(), (XMP_Uns32)value.size(), ds );	// ! Appends if necessary.

	}

}	// ExportIPTC_Array
コード例 #3
0
ファイル: ReconcileIPTC.cpp プロジェクト: hfiguiere/exempi
static void ExportIPTC_IntellectualGenre ( const SXMPMeta & xmp, IPTC_Manager * iptc )
{
	std::string    xmpValue;
	XMP_OptionBits xmpFlags;

	bool found = xmp.GetProperty ( kXMP_NS_IPTCCore, "IntellectualGenre", &xmpValue, &xmpFlags );
	if ( ! found ) {
		iptc->DeleteDataSet ( kIPTC_IntellectualGenre );
		return;
	}

	if ( ! XMP_PropIsSimple ( xmpFlags ) ) return;	// ? Complain? Delete the DataSet?

	NormalizeToCR ( &xmpValue );

	int i;
	XMP_StringPtr namePtr = xmpValue.c_str();
	for ( i = 0; kIntellectualGenreMappings[i].name != 0; ++i ) {
		if ( strcmp ( namePtr, kIntellectualGenreMappings[i].name ) == 0 ) break;
	}
	if ( kIntellectualGenreMappings[i].name == 0 ) return;	// Not a known genre, don't export it.

	std::string iimValue = kIntellectualGenreMappings[i].refNum;
	iimValue += ':';
	iimValue += xmpValue;

	size_t iptcCount = iptc->GetDataSet ( kIPTC_IntellectualGenre, 0 );
	if ( iptcCount > 1 ) iptc->DeleteDataSet ( kIPTC_IntellectualGenre );

	iptc->SetDataSet_UTF8 ( kIPTC_IntellectualGenre, iimValue.c_str(), (XMP_Uns32)iimValue.size(), 0 );	// ! Don't append a 2nd DataSet!

}	// ExportIPTC_IntellectualGenre
コード例 #4
0
ファイル: UnicodeParseSerialize.cpp プロジェクト: SSE4/vmf-1
static void FullUnicodeParse ( FILE * log, const char * encoding, size_t bufferSize,
                               const std::string & packet, const std::string & fullUnicode )
{
	if ( bufferSize > sizeof(sU32) ) {
		fprintf ( log, "#ERROR: FullUnicodeParse buffer overrun for %s, %d byte buffers\n", encoding, bufferSize );
		return;
	}

	SXMPMeta meta;
	try {
		memset ( sU32, -1, sizeof(sU32) );
		for ( size_t i = 0; i < packet.size(); i += bufferSize ) {
			size_t count = bufferSize;
			if ( count > (packet.size() - i) ) count = packet.size() - i;
			memcpy ( sU32, &packet[i], count );
			meta.ParseFromBuffer ( XMP_StringPtr(sU32), count, kXMP_ParseMoreBuffers );
		}
		meta.ParseFromBuffer ( XMP_StringPtr(sU32), 0 );
	} catch ( XMP_Error& excep ) {
		char message [200];
		sprintf ( message, "#ERROR: Full Unicode parsing error for %s, %d byte buffers", encoding, bufferSize );
		PrintXMPErrorInfo ( excep, message );
		return;
	}
	
	std::string value;
	bool found = meta.GetProperty ( kNS1, "FullUnicode", &value, 0 );
	if ( (! found) || (value != fullUnicode) ) fprintf ( log, "#ERROR: Failed to get full Unicode value for %s, %d byte buffers\n", encoding, bufferSize );
	
}	// FullUnicodeParse
コード例 #5
0
ファイル: ReconcileIPTC.cpp プロジェクト: hfiguiere/exempi
static void ExportIPTC_LangAlt ( const SXMPMeta & xmp, IPTC_Manager * iptc,
								 const char * xmpNS, const char * xmpProp, XMP_Uns8 id )
{
	std::string    value;
	XMP_OptionBits xmpFlags;

	bool found = xmp.GetProperty ( xmpNS, xmpProp, 0, &xmpFlags );
	if ( ! found ) {
		iptc->DeleteDataSet ( id );
		return;
	}

	if ( ! XMP_ArrayIsAltText ( xmpFlags ) ) return;	// ? Complain? Delete the DataSet?

	found = xmp.GetLocalizedText ( xmpNS, xmpProp, "", "x-default", 0, &value, 0 );
	if ( ! found ) {
		iptc->DeleteDataSet ( id );
		return;
	}

	NormalizeToCR ( &value );

	size_t iptcCount = iptc->GetDataSet ( id, 0 );
	if ( iptcCount > 1 ) iptc->DeleteDataSet ( id );

	iptc->SetDataSet_UTF8 ( id, value.c_str(), (XMP_Uns32)value.size(), 0 );	// ! Don't append a 2nd DataSet!

}	// ExportIPTC_LangAlt
コード例 #6
0
ファイル: ReconcileIPTC.cpp プロジェクト: hfiguiere/exempi
void PhotoDataUtils::ExportPSIR ( const SXMPMeta & xmp, PSIR_Manager * psir )
{
	bool found;
	std::string utf8Value;

	try {	// Don't let errors with one stop the others.
		found = xmp.GetProperty ( kXMP_NS_XMP_Rights, "Marked", &utf8Value, 0 );
		if ( ! found ) {
			psir->DeleteImgRsrc ( kPSIR_CopyrightFlag );
		} else {
			bool copyrighted = SXMPUtils::ConvertToBool ( utf8Value );
			psir->SetImgRsrc ( kPSIR_CopyrightFlag, &copyrighted, 1 );
		}
	} catch ( ... ) {
		// Do nothing, let other exports proceed.
		// ? Notify client?
	}

	try {	// Don't let errors with one stop the others.
		found = xmp.GetProperty ( kXMP_NS_XMP_Rights, "WebStatement", &utf8Value, 0 );
		if ( ! found ) {
			psir->DeleteImgRsrc ( kPSIR_CopyrightURL );
		} else if ( ! ignoreLocalText ) {
			std::string localValue;
			ReconcileUtils::UTF8ToLocal ( utf8Value.c_str(), utf8Value.size(), &localValue );
			psir->SetImgRsrc ( kPSIR_CopyrightURL, localValue.c_str(), (XMP_Uns32)localValue.size() );
		} else if ( ReconcileUtils::IsASCII ( utf8Value.c_str(), utf8Value.size() ) ) {
			psir->SetImgRsrc ( kPSIR_CopyrightURL, utf8Value.c_str(), (XMP_Uns32)utf8Value.size() );
		} else {
			psir->DeleteImgRsrc ( kPSIR_CopyrightURL );
		}
	} catch ( ... ) {
		// Do nothing, let other exports proceed.
		// ? Notify client?
	}

}	// PhotoDataUtils::ExportPSIR;
コード例 #7
0
ファイル: ASF_Support.cpp プロジェクト: hfiguiere/exempi
bool ASF_LegacyManager::CheckDigest ( const SXMPMeta& xmp )
{
	bool ret = false;

	if ( ! digestComputed ) this->ComputeDigest();

	std::string oldDigest;

	if ( xmp.GetProperty ( kXMP_NS_ASF, "NativeDigest", &oldDigest, 0 ) ) {
		ret = (digestStr == oldDigest);
	}

	return ret;

}
コード例 #8
0
ファイル: exempi.cpp プロジェクト: JanX2/exempi
bool xmp_get_property(XmpPtr xmp, const char *schema, 
					  const char *name, XmpStringPtr property,
					  uint32_t *propsBits)
{
	CHECK_PTR(xmp, false);
	RESET_ERROR;

	bool ret = false;
	try {
		SXMPMeta *txmp = (SXMPMeta *)xmp;
		XMP_OptionBits optionBits;
		ret = txmp->GetProperty(schema, name, STRING(property), 
								&optionBits);
		if(propsBits) {
			*propsBits = optionBits;
		}
	}
	catch(const XMP_Error & e) {
		set_error(e);
	}
	return ret;
}
コード例 #9
0
ファイル: ReadingXMP.cpp プロジェクト: JJWTimmer/Uforia
/**
*	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;
	}
	
	// Must initialize SXMPFiles before we use it
	if ( ! SXMPFiles::Initialize() )
	{
		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);

			bool exists;

			// Read a simple property
			string simpleValue;  //Stores the value for the property
			exists = meta.GetProperty(kXMP_NS_XMP, "CreatorTool", &simpleValue, NULL);
			if(exists)
				cout << "CreatorTool = " << simpleValue << endl;
			else
				simpleValue.clear();

			// Get the first element in the dc:creator array
			string elementValue;
			exists = meta.GetArrayItem(kXMP_NS_DC, "creator", 1, &elementValue, NULL);
			if(exists)
				cout << "dc:creator = " << elementValue << endl;
			else
				elementValue.clear();

			// Get the the entire dc:subject array 
			string propValue;
			int arrSize = meta.CountArrayItems(kXMP_NS_DC, "subject");
			for(int i = 1; i <= arrSize;i++)
			{
				meta.GetArrayItem(kXMP_NS_DC, "subject", i, &propValue, 0);
				cout << "dc:subject[" << i << "] = " << propValue << endl;
			}

			// Get the dc:title for English and French
			string itemValue;
			string actualLang;
			meta.GetLocalizedText(kXMP_NS_DC, "title", "en", "en-US", NULL, &itemValue, NULL);
			cout << "dc:title in English = " << itemValue << endl;

			meta.GetLocalizedText(kXMP_NS_DC, "title", "fr", "fr-FR", NULL, &itemValue, NULL);
			cout << "dc:title in French = " << itemValue << endl;

			// Get dc:MetadataDate
			XMP_DateTime myDate;
			if(meta.GetProperty_Date(kXMP_NS_XMP, "MetadataDate", &myDate, NULL))
			{
				// Convert the date struct into a convenient string and display it
				string myDateStr;
				SXMPUtils::ConvertFromDate(myDate, &myDateStr);
				cout << "meta:MetadataDate = " << myDateStr << endl;						 
			}

			// See if the flash struct exists and see if it was used
			string path, value;
			exists = meta.DoesStructFieldExist(kXMP_NS_EXIF, "Flash", kXMP_NS_EXIF,"Fired");
			if(exists)
			{
				bool flashFired;
				SXMPUtils::ComposeStructFieldPath(kXMP_NS_EXIF, "Flash", kXMP_NS_EXIF, "Fired", &path);
				meta.GetProperty_Bool(kXMP_NS_EXIF, path.c_str(), &flashFired, NULL);
				string flash = (flashFired) ? "True" : "False";

				cout << "Flash Used = " << flash << endl;
			}

			// Dump the current xmp object to a file
			ofstream dumpFile;
			dumpFile.open("XMPDump.txt", ios::out);
			meta.DumpObject(DumpXMPToFile, &dumpFile);
			dumpFile.close();
			cout << endl << "XMP dumped to XMPDump.txt" << 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;
}
コード例 #10
0
ファイル: ASF_Support.cpp プロジェクト: hfiguiere/exempi
int ASF_LegacyManager::ExportLegacy ( const SXMPMeta& xmp )
{
	int changed = 0;
	objectsToExport = 0;
	legacyDiff = 0;

	std::string utf8;
	std::string utf16;
	XMP_OptionBits flags;

	if ( ! broadcastSet ) {
		if ( xmp.GetProperty ( kXMP_NS_XMP, "CreateDate", &utf8, &flags ) ) {
			std::string date;
			ConvertISODateToMSDate ( utf8, &date );
			if ( fields[fieldCreationDate] != date ) {
				legacyDiff += date.size();
				legacyDiff -= fields[fieldCreationDate].size();
				this->SetField ( fieldCreationDate, date );
				objectsToExport |= objectFileProperties;
				changed ++;
			}
		}
	}

	if ( xmp.GetLocalizedText ( kXMP_NS_DC, "title", "", "x-default", 0, &utf8, &flags ) ) {
		NormalizeStringTrailingNull ( utf8 );
		ToUTF16 ( (const UTF8Unit*)utf8.data(), utf8.size(), &utf16, false );
		if ( fields[fieldTitle] != utf16 ) {
			legacyDiff += utf16.size();
			legacyDiff -= fields[fieldTitle].size();
			this->SetField ( fieldTitle, utf16 );
			objectsToExport |= objectContentDescription;
			changed ++;
		}
	}

	utf8.clear();
	SXMPUtils::CatenateArrayItems ( xmp, kXMP_NS_DC, "creator", 0, 0, kXMPUtil_AllowCommas, &utf8 );
	if ( ! utf8.empty() ) {
		NormalizeStringTrailingNull ( utf8 );
		ToUTF16 ( (const UTF8Unit*)utf8.data(), utf8.size(), &utf16, false );
		if ( fields[fieldAuthor] != utf16 ) {
			legacyDiff += utf16.size();
			legacyDiff -= fields[fieldAuthor].size();
			this->SetField ( fieldAuthor, utf16 );
			objectsToExport |= objectContentDescription;
			changed ++;
		}
	}

	if ( xmp.GetLocalizedText ( kXMP_NS_DC, "rights", "", "x-default", 0, &utf8, &flags ) ) {
		NormalizeStringTrailingNull ( utf8 );
		ToUTF16 ( (const UTF8Unit*)utf8.data(), utf8.size(), &utf16, false );
		if ( fields[fieldCopyright] != utf16 ) {
			legacyDiff += utf16.size();
			legacyDiff -= fields[fieldCopyright].size();
			this->SetField ( fieldCopyright, utf16 );
			objectsToExport |= objectContentDescription;
			changed ++;
		}
	}

	if ( xmp.GetLocalizedText ( kXMP_NS_DC, "description", "", "x-default", 0, &utf8, &flags ) ) {
		NormalizeStringTrailingNull ( utf8 );
		ToUTF16 ( (const UTF8Unit*)utf8.data(), utf8.size(), &utf16, false );
		if ( fields[fieldDescription] != utf16 ) {
			legacyDiff += utf16.size();
			legacyDiff -= fields[fieldDescription].size();
			this->SetField ( fieldDescription, utf16 );
			objectsToExport |= objectContentDescription;
			changed ++;
		}
	}

	if ( xmp.GetProperty ( kXMP_NS_XMP_Rights, "WebStatement", &utf8, &flags ) ) {
		NormalizeStringTrailingNull ( utf8 );
		if ( fields[fieldCopyrightURL] != utf8 ) {
			legacyDiff += utf8.size();
			legacyDiff -= fields[fieldCopyrightURL].size();
			this->SetField ( fieldCopyrightURL, utf8 );
			objectsToExport |= objectContentBranding;
			changed ++;
		}
	}

#if ! Exclude_LicenseURL_Recon
	if ( xmp.GetProperty ( kXMP_NS_XMP_Rights, "Certificate", &utf8, &flags ) ) {
		NormalizeStringTrailingNull ( utf8 );
		if ( fields[fieldLicenseURL] != utf8 ) {
			legacyDiff += utf8.size();
			legacyDiff -= fields[fieldLicenseURL].size();
			this->SetField ( fieldLicenseURL, utf8 );
			objectsToExport |= objectContentEncryption;
			changed ++;
		}
	}
#endif

	// find objects, that would need to be created on legacy export
	int newObjects = (objectsToExport & !objectsExisting);

	// calculate minimum storage for new objects, that might be created on export
	if ( newObjects & objectContentDescription )
		legacyDiff += sizeContentDescription;
	if ( newObjects & objectContentBranding )
		legacyDiff += sizeContentBranding;
	if ( newObjects & objectContentEncryption )
		legacyDiff += sizeContentEncryption;

	ComputeDigest();

	return changed;

}
コード例 #11
0
ファイル: UnicodeParseSerialize.cpp プロジェクト: SSE4/vmf-1
static void DoTest ( FILE * log )
{
	SXMPMeta meta;
	size_t u8Count, u32Count;
	SXMPMeta meta8, meta16b, meta16l, meta32b, meta32l;
	std::string u8Packet, u16bPacket, u16lPacket, u32bPacket, u32lPacket;

	InitializeUnicodeConversions();

	// ---------------------------------------------------------------------------------------------

	fprintf ( log, "// ------------------------------------------------\n" );
	fprintf ( log, "// Test basic serialization and parsing using ASCII\n\n" );
	
	// ----------------------------------------------------
	// Create basic ASCII packets in each of the encodings.
	
	meta.ParseFromBuffer ( kSimpleRDF, kXMP_UseNullTermination );
	
	meta.SerializeToBuffer ( &u8Packet,   (kXMP_OmitPacketWrapper | kXMP_EncodeUTF8) );
	meta.SerializeToBuffer ( &u16bPacket, (kXMP_OmitPacketWrapper | kXMP_EncodeUTF16Big) );
	meta.SerializeToBuffer ( &u16lPacket, (kXMP_OmitPacketWrapper | kXMP_EncodeUTF16Little) );
	meta.SerializeToBuffer ( &u32bPacket, (kXMP_OmitPacketWrapper | kXMP_EncodeUTF32Big) );
	meta.SerializeToBuffer ( &u32lPacket, (kXMP_OmitPacketWrapper | kXMP_EncodeUTF32Little) );
	
	#if 0
		FILE* dump;
		dump = fopen ( "u8Packet.txt", "w" );
		fwrite ( u8Packet.c_str(), 1, u8Packet.size(), dump );
		fclose ( dump );
		dump = fopen ( "u16bPacket.txt", "w" );
		fwrite ( u16bPacket.c_str(), 1, u16bPacket.size(), dump );
		fclose ( dump );
		dump = fopen ( "u16lPacket.txt", "w" );
		fwrite ( u16lPacket.c_str(), 1, u16lPacket.size(), dump );
		fclose ( dump );
		dump = fopen ( "u32bPacket.txt", "w" );
		fwrite ( u32bPacket.c_str(), 1, u32bPacket.size(), dump );
		fclose ( dump );
		dump = fopen ( "u32lPacket.txt", "w" );
		fwrite ( u32lPacket.c_str(), 1, u32lPacket.size(), dump );
		fclose ( dump );
	#endif
	
	// Verify the character form. The conversion functions are tested separately.
	
	const char * ptr;
	
	ptr = u8Packet.c_str();
	fprintf ( log, "UTF-8    : %d : %.2X %.2X  \"%.10s...\"\n", u8Packet.size(), *ptr, *(ptr+1), ptr );
	
	ptr = u16bPacket.c_str();
	fprintf ( log, "UTF-16BE : %d : %.2X %.2X %.2X\n", u16bPacket.size(), *ptr, *(ptr+1), *(ptr+2) );
	ptr = u16lPacket.c_str();
	fprintf ( log, "UTF-16LE : %d : %.2X %.2X %.2X\n", u16lPacket.size(), *ptr, *(ptr+1), *(ptr+2) );
	
	ptr = u32bPacket.c_str();
	fprintf ( log, "UTF-32BE : %d : %.2X %.2X %.2X %.2X %.2X\n", u32bPacket.size(), *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4) );
	ptr = u32lPacket.c_str();
	fprintf ( log, "UTF-32LE : %d : %.2X %.2X %.2X %.2X %.2X\n", u32lPacket.size(), *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4) );
	
	fprintf ( log, "\nBasic serialization tests done\n" );
	
	// -------------------------------------------------
	// Verify round trip reparsing of the basic packets.
	
	std::string origDump, rtDump;
	
	 meta.DumpObject ( DumpToString, &origDump );
	fprintf ( log, "Original dump\n%s\n", origDump.c_str() );

	try {
		meta8.ParseFromBuffer   ( u8Packet.c_str(), u8Packet.size() );
		meta16b.ParseFromBuffer ( u16bPacket.c_str(), u16bPacket.size() );
		meta16l.ParseFromBuffer ( u16lPacket.c_str(), u16lPacket.size() );
		meta32b.ParseFromBuffer ( u32bPacket.c_str(), u32bPacket.size() );
		meta32l.ParseFromBuffer ( u32lPacket.c_str(), u32lPacket.size() );
	} catch ( XMP_Error& excep ) {
		PrintXMPErrorInfo ( excep, "## Caught reparsing exception" );
		fprintf ( log, "\n" );
	}
	
	#if 0
		fprintf ( log, "After UTF-8 roundtrip\n" );
		meta8.DumpObject ( DumpToFile, log );
		fprintf ( log, "\nAfter UTF-16 BE roundtrip\n" );
		meta16b.DumpObject ( DumpToFile, log );
		fprintf ( log, "\nAfter UTF-16 LE roundtrip\n" );
		meta16l.DumpObject ( DumpToFile, log );
		fprintf ( log, "\nAfter UTF-32 BE roundtrip\n" );
		meta32b.DumpObject ( DumpToFile, log );
		fprintf ( log, "\nAfter UTF-32 LE roundtrip\n" );
		meta32l.DumpObject ( DumpToFile, log );
	#endif
	
	rtDump.clear();
	meta8.DumpObject ( DumpToString, &rtDump );
	if ( rtDump != origDump ) fprintf ( log, "#ERROR: Roundtrip failure for UTF-8\n%s\n", rtDump.c_str() );

	rtDump.clear();
	meta16b.DumpObject ( DumpToString, &rtDump );
	if ( rtDump != origDump ) fprintf ( log, "#ERROR: Roundtrip failure for UTF-16BE\n%s\n", rtDump.c_str() );

	rtDump.clear();
	meta16l.DumpObject ( DumpToString, &rtDump );
	if ( rtDump != origDump ) fprintf ( log, "#ERROR: Roundtrip failure for UTF-16LE\n%s\n", rtDump.c_str() );

	#if IncludeUTF32

		rtDump.clear();
		meta32b.DumpObject ( DumpToString, &rtDump );
		if ( rtDump != origDump ) fprintf ( log, "#ERROR: Roundtrip failure for UTF-32BE\n%s\n", rtDump.c_str() );

		rtDump.clear();
		meta32l.DumpObject ( DumpToString, &rtDump );
		if ( rtDump != origDump ) fprintf ( log, "#ERROR: Roundtrip failure for UTF-32LE\n%s\n", rtDump.c_str() );

	#endif
	
	fprintf ( log, "Basic round-trip parsing tests done\n\n" );

	// ---------------------------------------------------------------------------------------------
	
	fprintf ( log, "// --------------------------------------------------\n" );
	fprintf ( log, "// Test parse buffering logic using full Unicode data\n\n" );

	// --------------------------------------------------------------------------------------------
	// Construct the packets to parse in all encodings. There is just one property with a value
	// containing all of the Unicode representations. This isn't all of the Unicode characters, but
	// is more than enough to establish correctness of the buffering logic. It is almost everything
	// in the BMP, plus the range U+100000..U+10FFFF beyond the BMP. Doing all Unicode characters
	// takes far to long to execute and does not provide additional confidence. Skip ASCII controls,
	// they are not allowed in XML and get changed to spaces by SetProperty. Skip U+FFFE and U+FFFF,
	// the expat parser rejects them.
	
	#define kTab	0x09
	#define kLF		0x0A
	#define kCR		0x0D
	
	size_t i;
	UTF32Unit cp;
	sU32[0] = kTab; sU32[1] = kLF; sU32[2] = kCR;
	for ( i = 3, cp = 0x20; cp < 0x7F; ++i, ++cp ) sU32[i] = cp;
	for ( cp = 0x80; cp < 0xD800; ++i, ++cp ) sU32[i] = cp;
	for ( cp = 0xE000; cp < 0xFFFE; ++i, ++cp ) sU32[i] = cp;
	for ( cp = 0x100000; cp < 0x110000; ++i, ++cp ) sU32[i] = cp;
	u32Count = i;
	assert ( u32Count == (3 + (0x7F-0x20) + (0xD800-0x80) + (0xFFFE - 0xE000) + (0x110000-0x100000)) );

	if ( kBigEndianHost ) {
		UTF32BE_to_UTF8 ( sU32, u32Count, sU8, sizeof(sU8), &i, &u8Count );
	} else {
		UTF32LE_to_UTF8 ( sU32, u32Count, sU8, sizeof(sU8), &i, &u8Count );
	}
	if ( i != u32Count ) fprintf ( log, "#ERROR: Failed to convert full UTF-32 buffer\n" );
	assert ( u8Count == (3 + (0x7F-0x20) + 2*(0x800-0x80) + 3*(0xD800-0x800) + 3*(0xFFFE - 0xE000) + 4*(0x110000-0x100000)) );
	sU8[u8Count] = 0;
	
	std::string fullUnicode;
	SXMPUtils::RemoveProperties ( &meta, "", "", kXMPUI_DoAllProperties );
	meta.SetProperty ( kNS1, "FullUnicode", XMP_StringPtr(sU8) );
	meta.GetProperty ( kNS1, "FullUnicode", &fullUnicode, 0 );
	if ( (fullUnicode.size() != u8Count) || (fullUnicode != XMP_StringPtr(sU8)) ) {
		fprintf ( log, "#ERROR: Failed to set full UTF-8 value\n" );
		if ( (fullUnicode.size() != u8Count) ) {
			fprintf ( log, "        Size mismatch, want %d, got %d\n", u8Count, fullUnicode.size() );
		} else {
			for ( size_t b = 0; b < u8Count; ++b ) {
				if ( fullUnicode[b] != sU8[b] ) fprintf ( log, "        Byte mismatch at %d\n", b );
			}
		}
	}
	
	u8Packet.clear();
	u16bPacket.clear();
	u16lPacket.clear();
	u32bPacket.clear();
	u32lPacket.clear();
	
	meta.SerializeToBuffer ( &u8Packet,   (kXMP_OmitPacketWrapper | kXMP_EncodeUTF8) );
	meta.SerializeToBuffer ( &u16bPacket, (kXMP_OmitPacketWrapper | kXMP_EncodeUTF16Big) );
	meta.SerializeToBuffer ( &u16lPacket, (kXMP_OmitPacketWrapper | kXMP_EncodeUTF16Little) );
	#if IncludeUTF32
		meta.SerializeToBuffer ( &u32bPacket, (kXMP_OmitPacketWrapper | kXMP_EncodeUTF32Big) );
		meta.SerializeToBuffer ( &u32lPacket, (kXMP_OmitPacketWrapper | kXMP_EncodeUTF32Little) );
	#endif
	
	// ---------------------------------------------------------------------
	// Parse the whole packet as a sanity check, then at a variety of sizes.

	FullUnicodeParse ( log, "UTF-8", u8Packet.size(), u8Packet, fullUnicode );
	FullUnicodeParse ( log, "UTF-16BE", u16bPacket.size(), u16bPacket, fullUnicode );
	FullUnicodeParse ( log, "UTF-16LE", u16lPacket.size(), u16lPacket, fullUnicode );
	#if IncludeUTF32
		FullUnicodeParse ( log, "UTF-32BE", u32bPacket.size(), u32bPacket, fullUnicode );
		FullUnicodeParse ( log, "UTF-32LE", u32lPacket.size(), u32lPacket, fullUnicode );
	#endif
	fprintf ( log, "Full packet, no BOM, buffered parsing tests done\n" );

#if 0	// Skip the partial buffer tests, there seem to be problems, but no client uses partial buffers.

	for ( i = 1; i <= 3; ++i ) {
		FullUnicodeParse ( log, "UTF-8", i, u8Packet, fullUnicode );
		FullUnicodeParse ( log, "UTF-16BE", i, u16bPacket, fullUnicode );
		FullUnicodeParse ( log, "UTF-16LE", i, u16lPacket, fullUnicode );
		#if IncludeUTF32
			FullUnicodeParse ( log, "UTF-32BE", i, u32bPacket, fullUnicode );
			FullUnicodeParse ( log, "UTF-32LE", i, u32lPacket, fullUnicode );
		#endif
		fprintf ( log, "%d byte buffers, no BOM, buffered parsing tests done\n", i );
	}
	
	for ( i = 4; i <= 16; i *= 2 ) {
		FullUnicodeParse ( log, "UTF-8", i, u8Packet, fullUnicode );
		FullUnicodeParse ( log, "UTF-16BE", i, u16bPacket, fullUnicode );
		FullUnicodeParse ( log, "UTF-16LE", i, u16lPacket, fullUnicode );
		#if IncludeUTF32
			FullUnicodeParse ( log, "UTF-32BE", i, u32bPacket, fullUnicode );
			FullUnicodeParse ( log, "UTF-32LE", i, u32lPacket, fullUnicode );
		#endif
		fprintf ( log, "%d byte buffers, no BOM, buffered parsing tests done\n", i );
	}

#endif

	fprintf ( log, "\n" );	

	// -----------------------------------------------------------------------
	// Redo the buffered parsing tests, now with a leading BOM in the packets.

	u8Packet.insert ( 0, "\xEF\xBB\xBF", 3 );
	
	UTF32Unit NatBOM  = 0x0000FEFF;
	UTF32Unit SwapBOM = 0xFFFE0000;
	
	if ( kBigEndianHost ) {
		u16bPacket.insert ( 0, XMP_StringPtr(&NatBOM)+2, 2 );
		u16lPacket.insert ( 0, XMP_StringPtr(&SwapBOM), 2 );
		u32bPacket.insert ( 0, XMP_StringPtr(&NatBOM), 4 );
		u32lPacket.insert ( 0, XMP_StringPtr(&SwapBOM), 4 );
	} else {
		u16lPacket.insert ( 0, XMP_StringPtr(&NatBOM), 2 );
		u16bPacket.insert ( 0, XMP_StringPtr(&SwapBOM)+2, 2 );
		u32lPacket.insert ( 0, XMP_StringPtr(&NatBOM), 4 );
		u32bPacket.insert ( 0, XMP_StringPtr(&SwapBOM), 4 );
	}
	
	FullUnicodeParse ( log, "UTF-8", u8Packet.size(), u8Packet, fullUnicode );
	FullUnicodeParse ( log, "UTF-16BE", u16bPacket.size(), u16bPacket, fullUnicode );
	FullUnicodeParse ( log, "UTF-16LE", u16lPacket.size(), u16lPacket, fullUnicode );
	#if IncludeUTF32
		FullUnicodeParse ( log, "UTF-32BE", u32bPacket.size(), u32bPacket, fullUnicode );
		FullUnicodeParse ( log, "UTF-32LE", u32lPacket.size(), u32lPacket, fullUnicode );
	#endif
	fprintf ( log, "Full packet, leading BOM, buffered parsing tests done\n" );
		
#if 0	// Skip the partial buffer tests, there seem to be problems, but no client uses partial buffers.

	for ( i = 1; i <= 3; ++i ) {
		FullUnicodeParse ( log, "UTF-8", i, u8Packet, fullUnicode );
		FullUnicodeParse ( log, "UTF-16BE", i, u16bPacket, fullUnicode );
		FullUnicodeParse ( log, "UTF-16LE", i, u16lPacket, fullUnicode );
		#if IncludeUTF32
			FullUnicodeParse ( log, "UTF-32BE", i, u32bPacket, fullUnicode );
			FullUnicodeParse ( log, "UTF-32LE", i, u32lPacket, fullUnicode );
		#endif
		fprintf ( log, "%d byte buffers, leading BOM, buffered parsing tests done\n", i );
	}
	
	for ( i = 4; i <= 16; i *= 2 ) {
		FullUnicodeParse ( log, "UTF-8", i, u8Packet, fullUnicode );
		FullUnicodeParse ( log, "UTF-16BE", i, u16bPacket, fullUnicode );
		FullUnicodeParse ( log, "UTF-16LE", i, u16lPacket, fullUnicode );
		#if IncludeUTF32
			FullUnicodeParse ( log, "UTF-32BE", i, u32bPacket, fullUnicode );
			FullUnicodeParse ( log, "UTF-32LE", i, u32lPacket, fullUnicode );
		#endif
		fprintf ( log, "%d byte buffers, leading BOM, buffered parsing tests done\n", i );
	}

#endif

	fprintf ( log, "\n" );	

}	// DoTest
コード例 #12
0
ファイル: MOV_Handler.cpp プロジェクト: JJWTimmer/Uforia
static bool CreatorAtom_Update ( SXMPMeta& xmpObj, 
							     UserData& movieUserData )
{

	// Get Creator Atom XMP values.
	bool found = false;
	std::string posixPathString, uncPathString;
	if ( xmpObj.GetStructField ( kXMP_NS_CreatorAtom, "macAtom", kXMP_NS_CreatorAtom, "posixProjectPath", &posixPathString, 0 ) ) found = true;
	if ( xmpObj.GetStructField ( kXMP_NS_CreatorAtom, "windowsAtom", kXMP_NS_CreatorAtom, "uncProjectPath", &uncPathString, 0 ) ) found = true;

	std::string applicationCodeString, invocationAppleEventString, extensionString, invocationFlagsString, creatorToolString;
	if ( xmpObj.GetStructField ( kXMP_NS_CreatorAtom, "macAtom", kXMP_NS_CreatorAtom, "applicationCode", &applicationCodeString, 0 ) ) found = true;
	if ( xmpObj.GetStructField ( kXMP_NS_CreatorAtom, "macAtom", kXMP_NS_CreatorAtom, "invocationAppleEvent", &invocationAppleEventString, 0 ) ) found = true;
	if ( xmpObj.GetStructField ( kXMP_NS_CreatorAtom, "windowsAtom", kXMP_NS_CreatorAtom, "extension", &extensionString, 0 ) ) found = true;
	if ( xmpObj.GetStructField ( kXMP_NS_CreatorAtom, "windowsAtom", kXMP_NS_CreatorAtom, "invocationFlags", &invocationFlagsString, 0 ) ) found = true;
	if ( xmpObj.GetProperty ( kXMP_NS_XMP, "CreatorTool", &creatorToolString, 0 ) ) found = true;

	// If no Creator Atom information found, don't write anything.
	if ( ! found ) return false;

	// Read Legacy Creator Atom.
	unsigned long creatorAtomSize = 0;
	CR8R_CreatorAtom creatorAtomLegacy;
	CreatorAtom_Initialize ( creatorAtomLegacy );
	bool ok = Mov_ReadCreatorAtom ( movieUserData, &creatorAtomLegacy );

	// Generate new Creator Atom from XMP.
	CR8R_CreatorAtom creatorAtomViaXMP;
	CreatorAtom_Initialize ( creatorAtomViaXMP );

	if ( ! applicationCodeString.empty() ) {
		creatorAtomViaXMP.creator_codeLu = strtoul ( applicationCodeString.c_str(), 0, 0 );
	}
	if ( ! invocationAppleEventString.empty() ) {
		creatorAtomViaXMP.creator_eventLu = strtoul ( invocationAppleEventString.c_str(), 0, 0 );
	}
	if ( ! extensionString.empty() ) {
		strncpy ( creatorAtomViaXMP.creator_extAC, extensionString.c_str(), sizeof(creatorAtomViaXMP.creator_extAC) );
		EnsureFinalNul ( creatorAtomViaXMP.creator_extAC );
	}
	if ( ! invocationFlagsString.empty() ) {
		strncpy ( creatorAtomViaXMP.creator_flagAC, invocationFlagsString.c_str(), sizeof(creatorAtomViaXMP.creator_flagAC) );
		EnsureFinalNul ( creatorAtomViaXMP.creator_flagAC );
	}
	if ( ! creatorToolString.empty() ) {
		strncpy ( creatorAtomViaXMP.creator_nameAC, creatorToolString.c_str(), sizeof(creatorAtomViaXMP.creator_nameAC) );
		EnsureFinalNul ( creatorAtomViaXMP.creator_nameAC );
	}

	// Write Creator Atom.
	if ( ok ) {
		// If there's legacy, update if atom generated from XMP doesn't match legacy.
		if ( memcmp ( &creatorAtomViaXMP, &creatorAtomLegacy, sizeof(CR8R_CreatorAtom) ) != 0 ) {
			ok = Mov_WriteCreatorAtom ( movieUserData, creatorAtomViaXMP, true );
		}
	} else {
		// Write completely new atom from XMP.
		ok = Mov_WriteCreatorAtom ( movieUserData, creatorAtomViaXMP, false );
	}

	return ok;

}
コード例 #13
0
ファイル: RIFF_Support.cpp プロジェクト: JJWTimmer/Uforia
bool CreatorAtom::Update ( SXMPMeta& xmpObj,
						   LFA_FileRef fileRef,
						   long riffType,
						   RIFF_Support::RiffState& riffState )
{

	// Creator Atom related values.
	bool found = false;
	std::string posixPathString, uncPathString;
	if ( xmpObj.GetStructField ( kXMP_NS_CreatorAtom, "macAtom", kXMP_NS_CreatorAtom, "posixProjectPath", &posixPathString, 0 ) ) found = true;
	if ( xmpObj.GetStructField ( kXMP_NS_CreatorAtom, "windowsAtom", kXMP_NS_CreatorAtom, "uncProjectPath", &uncPathString, 0 ) ) found = true;

	std::string applicationCodeString, invocationAppleEventString, extensionString, invocationFlagsString, creatorToolString;
	if ( xmpObj.GetStructField ( kXMP_NS_CreatorAtom, "macAtom", kXMP_NS_CreatorAtom, "applicationCode", &applicationCodeString, 0 ) ) found = true;
	if ( xmpObj.GetStructField ( kXMP_NS_CreatorAtom, "macAtom", kXMP_NS_CreatorAtom, "invocationAppleEvent", &invocationAppleEventString, 0 ) ) found = true;
	if ( xmpObj.GetStructField ( kXMP_NS_CreatorAtom, "windowsAtom", kXMP_NS_CreatorAtom, "extension", &extensionString, 0 ) ) found = true;
	if ( xmpObj.GetStructField ( kXMP_NS_CreatorAtom, "windowsAtom", kXMP_NS_CreatorAtom, "invocationFlags", &invocationFlagsString, 0 ) ) found = true;
	if ( xmpObj.GetProperty ( kXMP_NS_XMP, "CreatorTool", &creatorToolString, 0 ) ) found = true;

	// No Creator Atom information present.
	if ( ! found ) return true;

	// Read Legacy Creator Atom.
	unsigned long creatorAtomSize = 0;
	CR8R_CreatorAtom creatorAtomLegacy;
	CreatorAtom_Initialize ( creatorAtomLegacy );
	bool ok = RIFF_Support::GetRIFFChunk ( fileRef, riffState, myCreatorAtom, 0, 0, 0, &creatorAtomSize );
	if ( ok ) {
		XMP_Assert ( creatorAtomSize == sizeof(CR8R_CreatorAtom) );
		ok = RIFF_Support::GetRIFFChunk ( fileRef, riffState, myCreatorAtom, 0, 0, (char*) &creatorAtomLegacy, &creatorAtomSize );
		CreatorAtom_MakeValid ( &creatorAtomLegacy );
	}

	// Generate new Creator Atom from XMP.
	CR8R_CreatorAtom creatorAtomViaXMP;
	CreatorAtom_Initialize ( creatorAtomViaXMP );
	if ( ! applicationCodeString.empty() ) {
		creatorAtomViaXMP.creator_codeLu = strtoul ( applicationCodeString.c_str(), 0, 0 );
	}
	if ( ! invocationAppleEventString.empty() ) {
		creatorAtomViaXMP.creator_eventLu = strtoul ( invocationAppleEventString.c_str(), 0, 0 );
	}
	if ( ! extensionString.empty() ) {
		strncpy ( creatorAtomViaXMP.creator_extAC, extensionString.c_str(), sizeof(creatorAtomViaXMP.creator_extAC) );
		EnsureFinalNul ( creatorAtomViaXMP.creator_extAC );
	}
	if ( ! invocationFlagsString.empty() ) {
		strncpy ( creatorAtomViaXMP.creator_flagAC, invocationFlagsString.c_str(), sizeof(creatorAtomViaXMP.creator_flagAC) );
		EnsureFinalNul ( creatorAtomViaXMP.creator_flagAC );
	}
	if ( ! creatorToolString.empty() ) {
		strncpy ( creatorAtomViaXMP.creator_nameAC, creatorToolString.c_str(), sizeof(creatorAtomViaXMP.creator_nameAC) );
		EnsureFinalNul ( creatorAtomViaXMP.creator_nameAC );
	}

	// Write new Creator Atom, if necessary.
	if ( memcmp ( &creatorAtomViaXMP, &creatorAtomLegacy, sizeof(CR8R_CreatorAtom) ) != 0 ) {
		CreatorAtom_ToBE ( &creatorAtomViaXMP );
		ok = RIFF_Support::PutChunk ( fileRef, riffState, riffType, myCreatorAtom, (char*)&creatorAtomViaXMP, sizeof(CR8R_CreatorAtom) );
	}

	return ok;

}
コード例 #14
0
ファイル: RIFF_Support.cpp プロジェクト: JanX2/exempi
static void exportXMPtoListChunk( XMP_Uns32 id, XMP_Uns32 containerType, 
						   RIFF_MetaHandler* handler, ContainerChunk** listChunk, Mapping mapping[])
{
	// note: ContainerChunk**: adress of pointer to allow changing the pointer itself (i.e. chunk creation)
	SXMPMeta* xmp = &handler->xmpObj;
	bool listChunkIsNeeded = false; // assume for now
	
	// ! The NUL is optional in WAV to avoid a parsing bug in Audition 3 - can't handle implicit pad byte.
	bool optionalNUL = (handler->parent->format == kXMP_WAVFile);

	for ( int p=0; mapping[p].chunkID != 0; ++p ) {	// go through all potential property mappings

		bool propExists = false;
		std::string value, actualLang;

		switch ( mapping[p].propType ) {

			// get property. if existing, remove from XMP (to avoid redundant storage)
			case prop_TIMEVALUE:
				propExists = xmp->GetStructField ( mapping[p].ns, mapping[p].prop, kXMP_NS_DM, "timeValue", &value, 0 );
				break;

			case prop_LOCALIZED_TEXT:
				propExists = xmp->GetLocalizedText ( mapping[p].ns, mapping[p].prop, "", "x-default", &actualLang, &value, 0);
				if ( actualLang != "x-default" ) propExists = false; // no "x-default" => nothing to reconcile !
				break;

			case prop_ARRAYITEM:
				propExists = xmp->GetArrayItem ( mapping[p].ns, mapping[p].prop, 1, &value, 0 );
				break;

			case prop_SIMPLE:
				propExists = xmp->GetProperty ( mapping[p].ns, mapping[p].prop, &value, 0 );
				break;			

			default:
				XMP_Throw ( "internal error", kXMPErr_InternalFailure );

		}

		if ( ! propExists ) {

			if ( *listChunk != 0 ) (*listChunk)->removeValue ( mapping[p].chunkID );

		} else {

			listChunkIsNeeded = true;
			if ( *listChunk == 0 ) *listChunk = new ContainerChunk ( handler->riffChunks[0], id, containerType );

			valueMap* cm = &(*listChunk)->childmap;			
			valueMapIter result = cm->find( mapping[p].chunkID );
			ValueChunk* propChunk = 0;

			if ( result != cm->end() ) {
				propChunk = result->second;
			} else {
				propChunk = new ValueChunk ( *listChunk, std::string(), mapping[p].chunkID );
			}

			propChunk->SetValue ( value.c_str(), optionalNUL );

		}

	} // for each property

	if ( (! listChunkIsNeeded) && (*listChunk != 0) && ((*listChunk)->children.size() == 0) ) {
		(*listChunk)->parent->replaceChildWithJunk ( *listChunk );
		(*listChunk) = 0; // reset direct Chunk pointer
	}

}
コード例 #15
0
ファイル: RIFF_Support.cpp プロジェクト: JanX2/exempi
// add bwf-bext related data to bext chunk, create if not existing yet.
// * in fact, since bext is fully fixed and known, there can be no unknown subchunks worth keeping:
//    * prepare bext chunk in buffer
//    * value changed/created if needed only, otherways remove chunk
// * remove bext-mapped properties from xmp (non-redundant storage)
// note: ValueChunk**: adress of pointer to allow changing the pointer itself (i.e. chunk creation)
static void exportXMPtoBextChunk( RIFF_MetaHandler* handler, ValueChunk** bextChunk )
{
	// register bext namespace ( if there was no import, this is news, otherwise harmless moot)
	SXMPMeta::RegisterNamespace( kXMP_NS_BWF, "bext:", 0 );

	bool chunkUsed = false; // assume for now
	SXMPMeta* xmp = &handler->xmpObj;

	// prepare buffer, need to know CodingHistory size as the only variable
	XMP_Int32 bextBufferSize = MIN_BEXT_SIZE - 8; // -8 because of header
	std::string value;
	if ( xmp->GetProperty( bextCodingHistory.ns, bextCodingHistory.prop, &value, kXMP_NoOptions ))
	{
		bextBufferSize += ((XMP_StringLen)value.size()) + 1 ; // add to size (and a trailing zero)
	}

	// create and clear buffer
	XMP_Uns8* buffer = new XMP_Uns8[bextBufferSize];
	for (XMP_Int32 i = 0; i < bextBufferSize; i++ )
		buffer[i] = 0;

	// grab props, write into buffer, remove from XMP ///////////////////////////
	// bextDescription ------------------------------------------------
	if ( xmp->GetProperty( bextDescription.ns, bextDescription.prop, &value, kXMP_NoOptions ) )
	{
		setBextField( &value, (XMP_Uns8*) buffer, 0, 256 );
		xmp->DeleteProperty( bextDescription.ns, bextDescription.prop)					;
		chunkUsed = true;
	}
	// bextOriginator -------------------------------------------------
	if ( xmp->GetProperty( bextOriginator.ns , bextOriginator.prop, &value, kXMP_NoOptions ) )
	{
		setBextField( &value, (XMP_Uns8*) buffer, 256, 32 );
		xmp->DeleteProperty( bextOriginator.ns , bextOriginator.prop );
		chunkUsed = true;
	}
	// bextOriginatorRef ----------------------------------------------
	if ( xmp->GetProperty( bextOriginatorRef.ns , bextOriginatorRef.prop, &value, kXMP_NoOptions ) )
	{
		setBextField( &value, (XMP_Uns8*) buffer, 256+32, 32 );
		xmp->DeleteProperty( bextOriginatorRef.ns , bextOriginatorRef.prop );
		chunkUsed = true;
	}
	// bextOriginationDate --------------------------------------------
	if ( xmp->GetProperty( bextOriginationDate.ns , bextOriginationDate.prop, &value, kXMP_NoOptions ) )
	{
		setBextField( &value, (XMP_Uns8*) buffer, 256+32+32, 10 );
		xmp->DeleteProperty( bextOriginationDate.ns , bextOriginationDate.prop );
		chunkUsed = true;
	}
	// bextOriginationTime --------------------------------------------
	if ( xmp->GetProperty( bextOriginationTime.ns , bextOriginationTime.prop, &value, kXMP_NoOptions ) )
	{
		setBextField( &value, (XMP_Uns8*) buffer, 256+32+32+10, 8 );
		xmp->DeleteProperty( bextOriginationTime.ns , bextOriginationTime.prop );
		chunkUsed = true;
	}
	// bextTimeReference ----------------------------------------------
	// thanx to friendly byte order, all 8 bytes can be written in one go:
	if ( xmp->GetProperty( bextTimeReference.ns, bextTimeReference.prop, &value, kXMP_NoOptions ) )
	{
		try
		{
			XMP_Int64 v = SXMPUtils::ConvertToInt64( value.c_str() );
			PutUns64LE( v, &(buffer[256+32+32+10+8] ));
			chunkUsed = true;
		} 	
		catch (XMP_Error& e)
		{
			if ( e.GetID() != kXMPErr_BadParam )
				throw e;         // re-throw on any other error
		}  // 'else' tolerate ( time reference remains 0x00000000 )
		// valid or not, do not store redundantly:
		xmp->DeleteProperty( bextTimeReference.ns, bextTimeReference.prop );
	}

	// bextVersion ----------------------------------------------------
	// set version=1, no matter what.
	PutUns16LE( 1, &(buffer[256+32+32+10+8+8]) );	
	xmp->DeleteProperty( bextVersion.ns, bextVersion.prop );

	// bextUMID -------------------------------------------------------
	if ( xmp->GetProperty( bextUMID.ns, bextUMID.prop, &value, kXMP_NoOptions ) )
	{
		std::string rawStr;
	
		if ( !DecodeFromHexString( value.data(), (XMP_StringLen) value.size(), &rawStr ) )
		{
			delete [] buffer; // important.
			XMP_Throw ( "EncodeFromHexString: illegal umid string. Must contain an even number of 0-9 and uppercase A-F chars.", kXMPErr_BadParam );		
		} 	

		// if UMID is smaller/longer than 64 byte for any reason,
		// truncate/do a partial write (just like for any other bext property)

		memcpy( (char*) &(buffer[256+32+32+10+8+8+2]), rawStr.data(), MIN( 64, rawStr.size() ) );
		xmp->DeleteProperty( bextUMID.ns, bextUMID.prop );
		chunkUsed = true;
	}

	// bextCodingHistory ----------------------------------------------
	if ( xmp->GetProperty( bextCodingHistory.ns, bextCodingHistory.prop, &value, kXMP_NoOptions ) )
	{
		std::string ascii;
		convertToASCII( value.data(), (XMP_StringLen) value.size() , &ascii, (XMP_StringLen) value.size() );
		strncpy( (char*) &(buffer[MIN_BEXT_SIZE-8]), ascii.data(), ascii.size() );
		xmp->DeleteProperty( bextCodingHistory.ns, bextCodingHistory.prop );
		chunkUsed = true;
	}

	// always delete old, recreate if needed
	if ( *bextChunk != 0 )
	{
		(*bextChunk)->parent->replaceChildWithJunk( *bextChunk );
		(*bextChunk) = 0; // clear direct Chunk pointer
	}

	if ( chunkUsed)
		*bextChunk = new ValueChunk( handler->riffChunks.at(0), std::string( (char*)buffer, bextBufferSize ), kChunk_bext );

	delete [] buffer; // important.
}