bool xmp_set_property(XmpPtr xmp, const char *schema, const char *name, const char *value, uint32_t optionBits) { CHECK_PTR(xmp, false); RESET_ERROR; bool ret = false; SXMPMeta *txmp = (SXMPMeta *)xmp; // see bug #16030 // when it is a struct or an array, get prop return an empty string // but it fail if passed an empty string if ((optionBits & (XMP_PROP_VALUE_IS_STRUCT | XMP_PROP_VALUE_IS_ARRAY)) && (*value == 0)) { value = NULL; } try { txmp->SetProperty(schema, name, value, optionBits); ret = true; } catch(const XMP_Error & e) { set_error(e); } catch(...) { } return ret; }
static bool CreatorAtom_SetProperties ( SXMPMeta& xmpObj, const MOV_MetaHandler::CreatorAtomStrings& creatorAtomStrings ) { if ( ! creatorAtomStrings.posixProjectPath.empty() ) { xmpObj.SetStructField ( kXMP_NS_CreatorAtom, "macAtom", kXMP_NS_CreatorAtom, "posixProjectPath", creatorAtomStrings.posixProjectPath, 0 ); } if ( ! creatorAtomStrings.uncProjectPath.empty() ) { xmpObj.SetStructField ( kXMP_NS_CreatorAtom, "windowsAtom", kXMP_NS_CreatorAtom, "uncProjectPath", creatorAtomStrings.uncProjectPath, 0 ); } if ( ! creatorAtomStrings.projectRefType.empty() ) { xmpObj.SetStructField ( kXMP_NS_DM, "projectRef", kXMP_NS_DM, "type", creatorAtomStrings.projectRefType.c_str()); } if ( ! creatorAtomStrings.applicationCode.empty() ) { xmpObj.SetStructField ( kXMP_NS_CreatorAtom, "macAtom", kXMP_NS_CreatorAtom, "applicationCode", creatorAtomStrings.applicationCode, 0 ); } if ( ! creatorAtomStrings.invocationAppleEvent.empty() ) { xmpObj.SetStructField ( kXMP_NS_CreatorAtom, "macAtom", kXMP_NS_CreatorAtom, "invocationAppleEvent", creatorAtomStrings.invocationAppleEvent, 0 ); } if ( ! creatorAtomStrings.extension.empty() ) { xmpObj.SetStructField ( kXMP_NS_CreatorAtom, "windowsAtom", kXMP_NS_CreatorAtom, "extension", creatorAtomStrings.extension, 0 ); } if ( ! creatorAtomStrings.invocationFlags.empty() ) { xmpObj.SetStructField ( kXMP_NS_CreatorAtom, "windowsAtom", kXMP_NS_CreatorAtom, "invocationFlags", creatorAtomStrings.invocationFlags, 0 ); } if ( ! creatorAtomStrings.creatorTool.empty() ) { xmpObj.SetProperty ( kXMP_NS_XMP, "CreatorTool", creatorAtomStrings.creatorTool, 0 ); } return ok; }
int XmpParser::encode( std::string& xmpPacket, const XmpData& xmpData, uint16_t formatFlags, uint32_t padding) { try { if (xmpData.empty()) { xmpPacket.clear(); return 0; } if (!initialize()) { #ifndef SUPPRESS_WARNINGS std::cerr << "XMP Toolkit initialization failed.\n"; #endif return 2; } SXMPMeta meta; for (XmpData::const_iterator i = xmpData.begin(); i != xmpData.end(); ++i) { const std::string ns = XmpProperties::ns(i->groupName()); XMP_OptionBits options = 0; if (i->typeId() == langAlt) { // Encode Lang Alt property const LangAltValue* la = dynamic_cast<const LangAltValue*>(&i->value()); if (la == 0) throw Error(43, i->key()); int idx = 1; // write the default first LangAltValue::ValueType::const_iterator k = la->value_.find("x-default"); if (k != la->value_.end()) { #ifdef DEBUG printNode(ns, i->tagName(), k->second, 0); #endif meta.AppendArrayItem(ns.c_str(), i->tagName().c_str(), kXMP_PropArrayIsAlternate, k->second.c_str()); const std::string item = i->tagName() + "[" + toString(idx++) + "]"; meta.SetQualifier(ns.c_str(), item.c_str(), kXMP_NS_XML, "lang", k->first.c_str()); } for (k = la->value_.begin(); k != la->value_.end(); ++k) { if (k->first == "x-default") continue; #ifdef DEBUG printNode(ns, i->tagName(), k->second, 0); #endif meta.AppendArrayItem(ns.c_str(), i->tagName().c_str(), kXMP_PropArrayIsAlternate, k->second.c_str()); const std::string item = i->tagName() + "[" + toString(idx++) + "]"; meta.SetQualifier(ns.c_str(), item.c_str(), kXMP_NS_XML, "lang", k->first.c_str()); } continue; } // Todo: Xmpdatum should have an XmpValue, not a Value const XmpValue* val = dynamic_cast<const XmpValue*>(&i->value()); assert(val); options = xmpArrayOptionBits(val->xmpArrayType()) | xmpArrayOptionBits(val->xmpStruct()); if ( i->typeId() == xmpBag || i->typeId() == xmpSeq || i->typeId() == xmpAlt) { #ifdef DEBUG printNode(ns, i->tagName(), "", options); #endif meta.SetProperty(ns.c_str(), i->tagName().c_str(), 0, options); for (int idx = 0; idx < i->count(); ++idx) { const std::string item = i->tagName() + "[" + toString(idx + 1) + "]"; #ifdef DEBUG printNode(ns, item, i->toString(idx), 0); #endif meta.SetProperty(ns.c_str(), item.c_str(), i->toString(idx).c_str()); } continue; } if (i->typeId() == xmpText) { if (i->count() == 0) { #ifdef DEBUG printNode(ns, i->tagName(), "", options); #endif meta.SetProperty(ns.c_str(), i->tagName().c_str(), 0, options); } else { #ifdef DEBUG printNode(ns, i->tagName(), i->toString(0), options); #endif meta.SetProperty(ns.c_str(), i->tagName().c_str(), i->toString(0).c_str(), options); } continue; } // Don't let any Xmpdatum go by unnoticed throw Error(38, i->tagName(), TypeInfo::typeName(i->typeId())); } std::string tmpPacket; meta.SerializeToBuffer(&tmpPacket, xmpFormatOptionBits(static_cast<XmpFormatFlags>(formatFlags)), padding); // throws xmpPacket = tmpPacket; return 0; } catch (const XMP_Error& e) { #ifndef SUPPRESS_WARNINGS std::cerr << Error(40, e.GetID(), e.GetErrMsg()) << "\n"; #endif return 3; }} // XmpParser::decode
/** * 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); // Display some properties in the console displayPropertyValues(&meta); /////////////////////////////////////////////////// // Now modify the XMP if(meta.DoesPropertyExist(kXMP_NS_XMP, "CreatorTool")) { // Update xap:CreatorTool - we don't need to set any option bits meta.SetProperty(kXMP_NS_XMP, "CreatorTool", "Updated By XMP SDK", 0); } // Update the Metadata Date XMP_DateTime updatedTime; // Get the current time. This is a UTC time automatically // adjusted for the local time SXMPUtils::CurrentDateTime(&updatedTime); if(meta.DoesPropertyExist(kXMP_NS_XMP, "MetadataDate")) { meta.SetProperty_Date(kXMP_NS_XMP, "MetadataDate", updatedTime, 0); } // Add an item onto the dc:creator array // Note the options used, kXMP_PropArrayIsOrdered, if the array does not exist it will be created meta.AppendArrayItem(kXMP_NS_DC, "creator", kXMP_PropArrayIsOrdered, "Author Name", 0); meta.AppendArrayItem(kXMP_NS_DC, "creator", kXMP_PropArrayIsOrdered, "Another Author Name", 0); // Now update alt-text properties meta.SetLocalizedText(kXMP_NS_DC, "title", "en", "en-US", "An English title"); meta.SetLocalizedText(kXMP_NS_DC, "title", "fr", "fr-FR", "Un titre Francais"); // Display the properties again to show changes cout << "After update:" << endl; displayPropertyValues(&meta); // 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 (meta) // b) Replace any top level properties in the source with the matching properties from the destination SXMPUtils::ApplyTemplate(&meta, rdfMeta, kXMPTemplate_AddNewProperties | kXMPTemplate_ReplaceExistingProperties | kXMPTemplate_IncludeInternalProperties); // Display the properties again to show changes cout << "After Appending Properties:" << endl; displayPropertyValues(&meta); // 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 metaBuffer; meta.SerializeToBuffer(&metaBuffer, 0, 0, "", "", 0); // Write the packet to a file as RDF writeRDFToFile(&metaBuffer, filename+"_XMP_RDF.txt"); // Write the packet to a file but this time as compact RDF XMP_OptionBits outOpts = kXMP_OmitPacketWrapper | kXMP_UseCompactFormat; meta.SerializeToBuffer(&metaBuffer, outOpts); writeRDFToFile(&metaBuffer, filename+"_XMP_RDF_Compact.txt"); // Check we can put the XMP packet back into the file if(myFile.CanPutXMP(meta)) { // If so then update the file with the modified XMP myFile.PutXMP(meta); } // 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; }
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
bool CreatorAtom::Import ( SXMPMeta& xmpObj, LFA_FileRef fileRef, RIFF_Support::RiffState& riffState ) { static const long myProjectLink = MakeFourCC ( 'P','r','m','L' ); unsigned long projectLinkSize; bool ok = RIFF_Support::GetRIFFChunk ( fileRef, riffState, myProjectLink, 0, 0, 0, &projectLinkSize ); if ( ok ) { Embed_ProjectLinkAtom epla; std::string projectPathString; RIFF_Support::GetRIFFChunk ( fileRef, riffState, myProjectLink, 0, 0, (char*) &epla, &projectLinkSize ); if ( ok ) { ProjectLinkAtom_MakeValid ( &epla ); projectPathString = epla.fullPath.name; } if ( ! projectPathString.empty() ) { if ( projectPathString[0] == '/' ) { xmpObj.SetStructField ( kXMP_NS_CreatorAtom, "macAtom", kXMP_NS_CreatorAtom, "posixProjectPath", projectPathString, 0 ); } else if ( projectPathString.substr(0,4) == std::string("\\\\?\\") ) { xmpObj.SetStructField ( kXMP_NS_CreatorAtom, "windowsAtom", kXMP_NS_CreatorAtom, "uncProjectPath", projectPathString, 0 ); } std::string projectTypeString; switch ( epla.exportType ) { case Embed_ExportTypeMovie : projectTypeString = "movie"; break; case Embed_ExportTypeStill : projectTypeString = "still"; break; case Embed_ExportTypeAudio : projectTypeString = "audio"; break; case Embed_ExportTypeCustom : projectTypeString = "custom"; break; } if ( ! projectTypeString.empty() ) { xmpObj.SetStructField ( kXMP_NS_DM, "projectRef", kXMP_NS_DM, "type", projectTypeString.c_str() ); } } } unsigned long creatorAtomSize = 0; ok = RIFF_Support::GetRIFFChunk ( fileRef, riffState, myCreatorAtom, 0, 0, 0, &creatorAtomSize ); if ( ok ) { CR8R_CreatorAtom creatorAtom; ok = RIFF_Support::GetRIFFChunk ( fileRef, riffState, myCreatorAtom, 0, 0, (char*) &creatorAtom, &creatorAtomSize ); if ( ok ) { CreatorAtom_MakeValid ( &creatorAtom ); char buffer[256]; std::string xmpString; sprintf ( buffer, "%d", creatorAtom.creator_codeLu ); xmpString = buffer; xmpObj.SetStructField ( kXMP_NS_CreatorAtom, "macAtom", kXMP_NS_CreatorAtom, "applicationCode", xmpString, 0 ); sprintf ( buffer, "%d", creatorAtom.creator_eventLu ); xmpString = buffer; xmpObj.SetStructField ( kXMP_NS_CreatorAtom, "macAtom", kXMP_NS_CreatorAtom, "invocationAppleEvent", xmpString, 0 ); xmpString = CharsToString ( creatorAtom.creator_extAC, sizeof(creatorAtom.creator_extAC) ); xmpObj.SetStructField ( kXMP_NS_CreatorAtom, "windowsAtom", kXMP_NS_CreatorAtom, "extension", xmpString, 0 ); xmpString = CharsToString ( creatorAtom.creator_flagAC, sizeof(creatorAtom.creator_flagAC) ); xmpObj.SetStructField ( kXMP_NS_CreatorAtom, "windowsAtom", kXMP_NS_CreatorAtom, "invocationFlags", xmpString, 0 ); xmpString = CharsToString ( creatorAtom.creator_nameAC, sizeof(creatorAtom.creator_nameAC) ); xmpObj.SetProperty ( kXMP_NS_XMP, "CreatorTool", xmpString, 0 ); } } return ok; }