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