1 // =================================================================================================
2 // ADOBE SYSTEMS INCORPORATED
3 // Copyright 2010 Adobe Systems Incorporated
4 // All Rights Reserved
5 //
6 // NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
7 // of the Adobe license agreement accompanying it.
8 // =================================================================================================
9
10 #include "public/include/XMP_Environment.h" // ! XMP_Environment.h must be the first included header.
11 #include "public/include/XMP_Const.h"
12
13 #include "XMPFiles/source/FileHandlers/WAVE_Handler.hpp"
14 #include "XMPFiles/source/FormatSupport/WAVE/WAVEBehavior.h"
15 #include "XMPFiles/source/FormatSupport/WAVE/WAVEReconcile.h"
16 #include "XMPFiles/source/NativeMetadataSupport/MetadataSet.h"
17 #include "source/XIO.hpp"
18
19 using namespace IFF_RIFF;
20
21 // =================================================================================================
22 /// \file WAVE_Handler.cpp
23 /// \brief File format handler for WAVE.
24 // =================================================================================================
25
26
27 // =================================================================================================
28 // WAVE_MetaHandlerCTor
29 // ====================
30
WAVE_MetaHandlerCTor(XMPFiles * parent)31 XMPFileHandler * WAVE_MetaHandlerCTor ( XMPFiles * parent )
32 {
33 return new WAVE_MetaHandler ( parent );
34 }
35
36 // =================================================================================================
37 // WAVE_CheckFormat
38 // ===============
39 //
40 // Checks if the given file is a valid WAVE file.
41 // The first 12 bytes are checked. The first 4 must be "RIFF"
42 // Bytes 8 to 12 must be "WAVE"
43
WAVE_CheckFormat(XMP_FileFormat,XMP_StringPtr,XMP_IO * file,XMPFiles *)44 bool WAVE_CheckFormat ( XMP_FileFormat /*format*/,
45 XMP_StringPtr /*filePath*/,
46 XMP_IO* file,
47 XMPFiles* /*parent*/ )
48 {
49 // Reset file pointer position
50 file->Rewind();
51
52 XMP_Uns8 buffer[12];
53 XMP_Int32 got = file->Read ( buffer, 12 );
54 // Reset file pointer position
55 file->Rewind();
56
57 // Need to have at least ID, size and Type of first chunk
58 if ( got < 12 )
59 {
60 return false;
61 }
62
63 XMP_Uns32 type = WAVE_MetaHandler::whatRIFFFormat( buffer );
64 if ( type != kChunk_RIFF && type != kChunk_RF64 )
65 {
66 return false;
67 }
68
69 const BigEndian& endian = BigEndian::getInstance();
70 if ( endian.getUns32(&buffer[8]) == kType_WAVE )
71 {
72 return true;
73 }
74
75 return false;
76 } // WAVE_CheckFormat
77
78
79 // =================================================================================================
80 // WAVE_MetaHandler::whatRIFFFormat
81 // ===============
82
whatRIFFFormat(XMP_Uns8 * buffer)83 XMP_Uns32 WAVE_MetaHandler::whatRIFFFormat( XMP_Uns8* buffer )
84 {
85 XMP_Uns32 type = 0;
86
87 const BigEndian& endian = BigEndian::getInstance();
88
89 if( buffer != 0 )
90 {
91 if( endian.getUns32( buffer ) == kChunk_RIFF )
92 {
93 type = kChunk_RIFF;
94 }
95 else if( endian.getUns32( buffer ) == kChunk_RF64 )
96 {
97 type = kChunk_RF64;
98 }
99 }
100
101 return type;
102 } // whatRIFFFormat
103
104
105 // Static inits
106
107 // ChunkIdentifier
108 // RIFF:WAVE/PMX_
109 const ChunkIdentifier WAVE_MetaHandler::kRIFFXMP[2] = { { kChunk_RIFF, kType_WAVE }, { kChunk_XMP, kType_NONE} };
110 // RIFF:WAVE/LIST:INFO
111 const ChunkIdentifier WAVE_MetaHandler::kRIFFInfo[2] = { { kChunk_RIFF, kType_WAVE }, { kChunk_LIST, kType_INFO } };
112 // RIFF:WAVE/DISP
113 const ChunkIdentifier WAVE_MetaHandler::kRIFFDisp[2] = { { kChunk_RIFF, kType_WAVE }, { kChunk_DISP, kType_NONE } };
114 // RIFF:WAVE/BEXT
115 const ChunkIdentifier WAVE_MetaHandler::kRIFFBext[2] = { { kChunk_RIFF, kType_WAVE }, { kChunk_bext, kType_NONE } };
116 // RIFF:WAVE/cart
117 const ChunkIdentifier WAVE_MetaHandler::kRIFFCart[2] = { { kChunk_RIFF, kType_WAVE }, { kChunk_cart, kType_NONE } };
118 // cr8r is not yet required for WAVE
119 // RIFF:WAVE/Cr8r
120 // const ChunkIdentifier WAVE_MetaHandler::kWAVECr8r[2] = { { kChunk_RIFF, kType_WAVE }, { kChunk_Cr8r, kType_NONE } };
121 // RIFF:WAVE/iXML
122 const ChunkIdentifier WAVE_MetaHandler::kRIFFiXML[2] = { { kChunk_RIFF, kType_WAVE }, { kChunk_iXML, kType_NONE } };
123 // RF64:WAVE/PMX_
124 const ChunkIdentifier WAVE_MetaHandler::kRF64XMP[2] = { { kChunk_RF64, kType_WAVE }, { kChunk_XMP, kType_NONE} };
125 // RF64:WAVE/LIST:INFO
126 const ChunkIdentifier WAVE_MetaHandler::kRF64Info[2] = { { kChunk_RF64, kType_WAVE }, { kChunk_LIST, kType_INFO } };
127 // RF64:WAVE/DISP
128 const ChunkIdentifier WAVE_MetaHandler::kRF64Disp[2] = { { kChunk_RF64, kType_WAVE }, { kChunk_DISP, kType_NONE } };
129 // RF64:WAVE/BEXT
130 const ChunkIdentifier WAVE_MetaHandler::kRF64Bext[2] = { { kChunk_RF64, kType_WAVE }, { kChunk_bext, kType_NONE } };
131 // RF64:WAVE/cart
132 const ChunkIdentifier WAVE_MetaHandler::kRF64Cart[2] = { { kChunk_RF64, kType_WAVE }, { kChunk_cart, kType_NONE } };
133 // cr8r is not yet required for WAVE
134 // RF64:WAVE/Cr8r
135 // const ChunkIdentifier WAVE_MetaHandler::kRF64Cr8r[2] = { { kChunk_RF64, kType_WAVE }, { kChunk_Cr8r, kType_NONE } };
136 const ChunkIdentifier WAVE_MetaHandler::kRF64iXML[2] = { { kChunk_RF64, kType_WAVE }, { kChunk_iXML, kType_NONE } };
137
138 // =================================================================================================
139 // WAVE_MetaHandler::WAVE_MetaHandler
140 // ================================
141
WAVE_MetaHandler(XMPFiles * _parent)142 WAVE_MetaHandler::WAVE_MetaHandler ( XMPFiles * _parent )
143 : mChunkController(NULL), mChunkBehavior(NULL),
144 mINFOMeta(), mBEXTMeta(), mCartMeta(), mDISPMeta(), miXMLMeta(),
145 mXMPChunk(NULL), mINFOChunk(NULL),
146 mBEXTChunk(NULL), mCartChunk(NULL), mDISPChunk(NULL), miXMLChunk(NULL)
147 {
148 this->parent = _parent;
149 this->handlerFlags = kWAVE_HandlerFlags;
150 this->stdCharForm = kXMP_Char8Bit;
151
152 this->mChunkBehavior = new WAVEBehavior();
153 this->mChunkController = new ChunkController( mChunkBehavior, false );
154 miXMLMeta.SetErrorCallback( &parent->errorCallback );
155
156 } // WAVE_MetaHandler::WAVE_MetaHandler
157
158
159 // =================================================================================================
160 // WAVE_MetaHandler::~WAVE_MetaHandler
161 // =================================
162
~WAVE_MetaHandler()163 WAVE_MetaHandler::~WAVE_MetaHandler()
164 {
165 if( mChunkController != NULL )
166 {
167 delete mChunkController;
168 }
169
170 if( mChunkBehavior != NULL )
171 {
172 delete mChunkBehavior;
173 }
174 } // WAVE_MetaHandler::~WAVE_MetaHandler
175
176
177 // =================================================================================================
178 // WAVE_MetaHandler::CacheFileData
179 // ==============================
180
CacheFileData()181 void WAVE_MetaHandler::CacheFileData()
182 {
183 // Need to determine the file type, need the first four bytes of the file
184
185 // Reset file pointer position
186 this->parent->ioRef->Rewind();
187
188 XMP_Uns8 buffer[4];
189 #if XMP_DebugBuild
190 XMP_Int32 got =
191 #endif
192 this->parent->ioRef->Read ( buffer, 4 );
193 XMP_Assert( got == 4 );
194
195 XMP_Uns32 type = WAVE_MetaHandler::whatRIFFFormat( buffer );
196 XMP_Assert( type == kChunk_RIFF || type == kChunk_RF64 );
197
198 // Reset file pointer position
199 this->parent->ioRef->Rewind();
200
201 // Add the relevant chunk paths for the determined RIFF format
202 if( type == kChunk_RIFF )
203 {
204 mWAVEXMPChunkPath.append( kRIFFXMP, SizeOfCIArray(kRIFFXMP) );
205 mWAVEInfoChunkPath.append( kRIFFInfo, SizeOfCIArray(kRIFFInfo) );
206 mWAVEDispChunkPath.append( kRIFFDisp, SizeOfCIArray(kRIFFDisp) );
207 mWAVEiXMLChunkPath.append( kRIFFiXML, SizeOfCIArray(kRIFFiXML) );
208 mWAVEBextChunkPath.append( kRIFFBext, SizeOfCIArray(kRIFFBext) );
209 mWAVECartChunkPath.append( kRIFFCart, SizeOfCIArray(kRIFFCart) );
210 // cr8r is not yet required for WAVE
211 //mWAVECr8rChunkPath.append( kWAVECr8r, SizeOfCIArray(kWAVECr8r) );
212 }
213 else // RF64
214 {
215 mWAVEXMPChunkPath.append( kRF64XMP, SizeOfCIArray(kRF64XMP) );
216 mWAVEInfoChunkPath.append( kRF64Info, SizeOfCIArray(kRF64Info) );
217 mWAVEDispChunkPath.append( kRF64Disp, SizeOfCIArray(kRF64Disp) );
218 mWAVEiXMLChunkPath.append( kRF64iXML, SizeOfCIArray(kRF64iXML) );
219 mWAVEBextChunkPath.append( kRF64Bext, SizeOfCIArray(kRF64Bext) );
220 mWAVECartChunkPath.append( kRF64Cart, SizeOfCIArray(kRF64Cart) );
221 // cr8r is not yet required for WAVE
222 //mWAVECr8rChunkPath.append( kRF64Cr8r, SizeOfCIArray(kRF64Cr8r) );
223 }
224
225 mChunkController->addChunkPath( mWAVEXMPChunkPath );
226 mChunkController->addChunkPath( mWAVEInfoChunkPath );
227 mChunkController->addChunkPath( mWAVEDispChunkPath );
228 mChunkController->addChunkPath( mWAVEiXMLChunkPath );
229 mChunkController->addChunkPath( mWAVEBextChunkPath );
230 mChunkController->addChunkPath( mWAVECartChunkPath );
231 // cr8r is not yet required for WAVE
232 //mChunkController->addChunkPath( mWAVECr8rChunkPath );
233
234 // Parse the given file
235 // Throws exception if the file cannot be parsed
236 mChunkController->parseFile( this->parent->ioRef, &this->parent->openFlags );
237
238 // Retrieve the file type, it must have at least FORM:WAVE
239 std::vector<XMP_Uns32> typeList = mChunkController->getTopLevelTypes();
240
241 // If file is neither WAVE, throw exception
242 XMP_Validate( typeList.at(0) == kType_WAVE , "File is not of type WAVE", kXMPErr_BadFileFormat );
243
244 // Check if the file contains XMP (last if there are duplicates)
245 mXMPChunk = mChunkController->getChunk( mWAVEXMPChunkPath, true );
246
247
248 // Retrieve XMP packet info
249 if( mXMPChunk != NULL )
250 {
251 this->packetInfo.length = static_cast<XMP_Int32>(mXMPChunk->getSize());
252 this->packetInfo.charForm = kXMP_Char8Bit;
253 this->packetInfo.writeable = true;
254
255 // Get actual the XMP packet
256 this->xmpPacket.assign ( mXMPChunk->getString( this->packetInfo.length) );
257
258 // set state
259 this->containsXMP = true;
260 }
261 } // WAVE_MetaHandler::CacheFileData
262
263
264 // =================================================================================================
265 // WAVE_MetaHandler::ProcessXMP
266 // ============================
267
ProcessXMP()268 void WAVE_MetaHandler::ProcessXMP()
269 {
270 // Must be done only once
271 if ( this->processedXMP )
272 {
273 return;
274 }
275 // Set the status at start, in case something goes wrong in this method
276 this->processedXMP = true;
277
278 // Parse the XMP
279 if ( ! this->xmpPacket.empty() ) {
280
281 XMP_Assert ( this->containsXMP );
282
283 FillPacketInfo ( this->xmpPacket, &this->packetInfo );
284
285 this->xmpObj.ParseFromBuffer ( this->xmpPacket.c_str(), (XMP_StringLen)this->xmpPacket.size() );
286
287 this->containsXMP = true;
288 }
289
290 // Then import native properties
291 MetadataSet metaSet;
292 WAVEReconcile recon;
293
294 // Parse the WAVE metadata object with values
295
296 const XMP_Uns8* buffer = NULL; // temporary buffer
297 XMP_Uns64 size = 0;
298 // Get LIST:INFO legacy chunk
299 mINFOChunk = mChunkController->getChunk( mWAVEInfoChunkPath, true );
300 if( mINFOChunk != NULL )
301 {
302 size = mINFOChunk->getData( &buffer );
303 mINFOMeta.parse( buffer, size );
304 }
305
306 // Parse Bext legacy chunk
307 mBEXTChunk = mChunkController->getChunk( mWAVEBextChunkPath, true );
308 if( mBEXTChunk != NULL )
309 {
310 size = mBEXTChunk->getData( &buffer );
311 mBEXTMeta.parse( buffer, size );
312 }
313
314 // Parse cart legacy chunk
315 mCartChunk = mChunkController->getChunk( mWAVECartChunkPath, true );
316 if( mCartChunk != NULL )
317 {
318 size = mCartChunk->getData( &buffer );
319 mCartMeta.parse( buffer, size );
320 }
321
322 // Parse DISP legacy chunk
323 const std::vector<IChunkData*>& disps = mChunkController->getChunks( mWAVEDispChunkPath );
324
325 if( ! disps.empty() )
326 {
327 for( std::vector<IChunkData*>::const_reverse_iterator iter=disps.rbegin(); iter!=disps.rend(); iter++ )
328 {
329 size = (*iter)->getData( &buffer );
330
331 if( DISPMetadata::isValidDISP( buffer, size ) )
332 {
333 mDISPChunk = (*iter);
334 break;
335 }
336 }
337 }
338
339 if( mDISPChunk != NULL )
340 {
341 size = mDISPChunk->getData( &buffer );
342 mDISPMeta.parse( buffer, size );
343 }
344
345 //cr8r is not yet required for WAVE
346 //// Parse Cr8r legacy chunk
347 //mCr8rChunk = mChunkController->getChunk( mWAVECr8rChunkPath );
348 //if( mCr8rChunk != NULL )
349 //{
350 // size = mCr8rChunk->getData( &buffer );
351 // mCr8rMeta.parse( buffer, size );
352 //}
353
354 // Parse iXML legacy chunk
355 miXMLChunk = mChunkController->getChunk( mWAVEiXMLChunkPath, true );
356 if( miXMLChunk != NULL )
357 {
358 size = miXMLChunk->getData( &buffer );
359 miXMLMeta.parse( buffer, size );
360 }
361
362 // app legacy to the metadata list
363 metaSet.append( &mINFOMeta );
364 metaSet.append( &miXMLMeta );
365 metaSet.append( &mBEXTMeta );
366 metaSet.append( &mCartMeta );
367 metaSet.append( &mDISPMeta );
368
369 // cr8r is not yet required for WAVE
370 // metaSet.append( &mCr8rMeta );
371
372 // Do the import
373 if( recon.importToXMP( this->xmpObj, metaSet ) )
374 {
375 // Remember if anything has changed
376 this->containsXMP = true;
377 }
378
379 } // WAVE_MetaHandler::ProcessXMP
380
381
382 // =================================================================================================
383 // RIFF_MetaHandler::UpdateFile
384 // ===========================
385
UpdateFile(bool doSafeUpdate)386 void WAVE_MetaHandler::UpdateFile ( bool doSafeUpdate )
387 {
388 if ( ! this->needsUpdate ) { // If needsUpdate is set then at least the XMP changed.
389 return;
390 }
391
392 if ( doSafeUpdate )
393 {
394 XMP_Throw ( "WAVE_MetaHandler::UpdateFile: Safe update not supported", kXMPErr_Unavailable );
395 }
396
397 // Export XMP to legacy chunks. Create/delete them if necessary
398 MetadataSet metaSet;
399 WAVEReconcile recon;
400
401 metaSet.append( &mINFOMeta );
402 metaSet.append( &miXMLMeta );
403 metaSet.append( &mBEXTMeta );
404 metaSet.append( &mCartMeta );
405 metaSet.append( &mDISPMeta );
406
407 // cr8r is not yet required for WAVE
408 // metaSet.append( &mCr8rMeta );
409
410 // If anything changes, update/create/delete the legacy chunks
411 if( recon.exportFromXMP( metaSet, this->xmpObj ) )
412 {
413 if ( mINFOMeta.hasChanged( ))
414 {
415 updateLegacyChunk( &mINFOChunk, kChunk_LIST, kType_INFO, mINFOMeta );
416 }
417
418 if ( mBEXTMeta.hasChanged( ))
419 {
420 updateLegacyChunk( &mBEXTChunk, kChunk_bext, kType_NONE, mBEXTMeta );
421 }
422
423 if ( mCartMeta.hasChanged( ))
424 {
425 updateLegacyChunk( &mCartChunk, kChunk_cart, kType_NONE, mCartMeta );
426 }
427
428 if ( mDISPMeta.hasChanged( ))
429 {
430 updateLegacyChunk( &mDISPChunk, kChunk_DISP, kType_NONE, mDISPMeta );
431 }
432
433 //cr8r is not yet required for WAVE
434 //if ( mCr8rMeta.hasChanged( ))
435 //{
436 // updateLegacyChunk( &mCr8rChunk, kChunk_Cr8r, kType_NONE, mCr8rMeta );
437 //}
438
439 if ( miXMLMeta.hasChanged( ))
440 {
441 updateLegacyChunk( &miXMLChunk, kChunk_iXML, kType_NONE, miXMLMeta );
442 }
443 }
444
445 //update/create XMP chunk
446 if( this->containsXMP )
447 {
448 this->xmpObj.SerializeToBuffer ( &(this->xmpPacket) );
449
450 if( mXMPChunk != NULL )
451 {
452 mXMPChunk->setData( reinterpret_cast<const XMP_Uns8 *>(this->xmpPacket.c_str()), this->xmpPacket.length() );
453 }
454 else // create XMP chunk
455 {
456 mXMPChunk = mChunkController->createChunk( kChunk_XMP, kType_NONE );
457 mXMPChunk->setData( reinterpret_cast<const XMP_Uns8 *>(this->xmpPacket.c_str()), this->xmpPacket.length() );
458 mChunkController->insertChunk( mXMPChunk );
459 }
460 }
461 // XMP Packet is never completely removed from the file.
462
463 XMP_ProgressTracker* progressTracker=this->parent->progressTracker;
464 // local progess tracking required because for Handlers incapable of
465 // kXMPFiles_CanRewrite XMPFiles call this Update method after making
466 // a copy of the orignal file
467 bool localProgressTracking=false;
468 if ( progressTracker != 0 )
469 {
470 if ( ! progressTracker->WorkInProgress() )
471 {
472 localProgressTracking = true;
473 progressTracker->BeginWork ();
474 }
475 }
476 //write tree back to file
477 mChunkController->writeFile( this->parent->ioRef ,progressTracker);
478 if ( localProgressTracking && progressTracker != 0 ) progressTracker->WorkComplete();
479
480 this->needsUpdate = false; // Make sure this is only called once.
481 } // WAVE_MetaHandler::UpdateFile
482
483
updateLegacyChunk(IChunkData ** chunk,XMP_Uns32 chunkID,XMP_Uns32 chunkType,IMetadata & legacyData)484 void WAVE_MetaHandler::updateLegacyChunk( IChunkData **chunk, XMP_Uns32 chunkID, XMP_Uns32 chunkType, IMetadata &legacyData )
485 {
486 // If there is a legacy value, update/create the appropriate chunk
487 if( ! legacyData.isEmpty() )
488 {
489 XMP_Uns8* buffer = NULL;
490 XMP_Uns64 size = legacyData.serialize( &buffer );
491
492 if( *chunk != NULL )
493 {
494 (*chunk)->setData( buffer, size, false );
495 }
496 else
497 {
498 *chunk = mChunkController->createChunk( chunkID, chunkType );
499 (*chunk)->setData( buffer, size, false );
500 mChunkController->insertChunk( *chunk );
501 }
502
503 delete[] buffer;
504 }
505 else //delete chunk if existing
506 {
507 mChunkController->removeChunk ( *chunk );
508 }
509 }//updateLegacyChunk
510
511
512 // =================================================================================================
513 // RIFF_MetaHandler::WriteFile
514 // ==========================
515
WriteTempFile(XMP_IO *)516 void WAVE_MetaHandler::WriteTempFile ( XMP_IO* /*tempRef*/ )
517 {
518 XMP_Throw( "WAVE_MetaHandler::WriteTempFile is not Implemented!", kXMPErr_Unimplemented );
519 }//WAVE_MetaHandler::WriteFile
520