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 #ifndef _IChunkBehavior_h_
11 #define _IChunkBehavior_h_
12 
13 #include "public/include/XMP_Environment.h"	// ! This must be the first include.
14 #include "public/include/XMP_Const.h"
15 #include "public/include/XMP_IO.hpp"
16 #include <vector>
17 
18 namespace IFF_RIFF
19 {
20 
21 /**
22 	The IChunkBehavior is an interface that provides access to algorithm
23 	for the read and write process of IFF/RIFF formated streams.
24 	A file format specific instance based on this interface gets injected into
25 	the class ChunkController and offers format specific algorithm wherever
26 	the processing of a certain file format differs from the general specification
27 	of RIFF/IFF.
28 	That is e.g. the RF64 format where it is possible that the size value of the
29 	top level chunk doesn't represent the real size. Or AVI, where are special rules
30 	if the size of a chunk exceed the 4GB border.
31 */
32 
33 class IChunkContainer;
34 class Chunk;
35 struct ChunkIdentifier;
36 class ChunkPath;
37 
38 class IChunkBehavior
39 {
40 public:
IChunkBehavior()41 			 IChunkBehavior() : mMovablePaths(NULL) {}
~IChunkBehavior()42 	virtual ~IChunkBehavior() {};
43 
44 	/**
45 	 * Set list of chunk paths of chunks that might be moved within the hierarchy
46 	 */
setMovablePaths(std::vector<ChunkPath> * paths)47 	inline void setMovablePaths( std::vector<ChunkPath>* paths )		{ mMovablePaths = paths; }
48 
49 	/**
50 		Validate the passed in size value, identify the valid size if the passed in isn't valid
51 		and return the valid size.
52 		throw an exception if the passed in size isn't valid and there's no way to identify a
53 		valid size.
54 
55 		@param	size	Size value
56 		@param	id		Identifier of chunk
57 		@param	tree	Chunk tree
58 		@param	stream	Stream handle
59 
60 		@return		Valid size value.
61 	*/
62 	virtual	XMP_Uns64		getRealSize( const XMP_Uns64 size, const ChunkIdentifier& id, IChunkContainer& tree, XMP_IO* stream )	= 0;
63 
64 	/**
65 		Return the maximum size of a single chunk, i.e. the maximum size of a top-level chunk.
66 
67 		@return		Maximum size
68 	*/
69 	virtual XMP_Uns64		getMaxChunkSize() const																							= 0;
70 
71 	/**
72 		Return true if the passed identifier is valid for top-level chunks of a certain format.
73 
74 		@param	id			Chunk identifier
75 		@param	chunkNo		order number of top-level chunk
76 		@return				true, if passed id is a valid top-level chunk
77 	*/
78 	virtual	bool			isValidTopLevelChunk( const ChunkIdentifier& id, XMP_Uns32 chunkNo )											= 0;
79 
80 	/**
81 		Fix the hierarchy of chunks depending ones based on size changes of one or more chunks
82 		and second based on format specific rules.
83 		Throw an exception if the hierarchy can't be fixed.
84 
85 		@param	tree		Vector of root chunks.
86 	*/
87 	virtual	void			fixHierarchy( IChunkContainer& tree )																			= 0;
88 
89 	/**
90 		Insert a new chunk into the hierarchy of chunks. The behavior needs to decide the position
91 		of the new chunk and has to do the insertion.
92 
93 		@param	tree	Chunk tree
94 		@param	chunk	New chunk
95 	*/
96 	virtual	void			insertChunk( IChunkContainer& tree, Chunk& chunk )																= 0;
97 
98 	/**
99 		Remove the chunk described by the passed ChunkPath.
100 
101 		@param	tree	Chunk tree
102 		@param	path	Path to the chunk that needs to be removed
103 
104 		@return			true if the chunk was removed and need to be deleted
105 	*/
106 	virtual	bool			removeChunk( IChunkContainer& tree, Chunk& chunk )																= 0;
107 
108 protected:
109 		/**
110 		Create a FREE chunk.
111 		If the chunkSize is smaller than the header+type - size then create an annotation chunk.
112 		If the passed size is odd, then add a pad byte.
113 
114 		@param chunkSize	Total size including header
115 		@return				New FREE chunk
116 	*/
117 	virtual Chunk*			createFREE( XMP_Uns64 chunkSize )																				= 0;
118 
119 	/**
120 		Check if the passed chunk is a FREE chunk.
121 		(Could be also a small annotation chunk with zero bytes in its data)
122 
123 		@param	chunk	A chunk
124 
125 		@return			true if the passed chunk is a FREE chunk
126 	*/
127 	virtual XMP_Bool		isFREEChunk( const Chunk& chunk ) const																			= 0;
128 
129 	/**
130 		Return the minimum size of a FREE chunk
131 	*/
132 	virtual XMP_Uns64		getMinFREESize( ) const
133 																																			= 0;
134 protected:
135 	/************************************************************************/
136 	/* END of Interface. The following are helper functions for all derived */
137 	/* Behavior Classes                                                     */
138 	/************************************************************************/
139 
140 	/**
141 		Find a FREE chunk with the passed total size (including header). If the FREE chunk is found then
142 		take care of the fact that is has to be that large (or larger) then the minimum size of a FREE chunk.
143 		The method takes also into account that the passed size probably not includes a pad byte
144 
145 		@param	tree			Parent tree
146 		@param	requiredSize	Required total size (including header)
147 
148 		@return					Index of found FREE chunk
149 	*/
150 	XMP_Int32		findFREEChunk( const IChunkContainer& tree, XMP_Uns64 requiredSize );
151 
152 	/**
153 		May we move a chunk of passed id/type
154 
155 		@param	identifier		id and type of chunk
156 		@return					true if such a chunk might be moved within the tree
157 	*/
158 	bool			isMovable( const Chunk& chunk ) const;
159 
160 	/**
161 		Validate recursively the offset values of all chunks.
162 		Throws an exception if there is any discrepancy with the calculated offset.
163 
164 		@param	tree			(Sub-)tree of chunks
165 		@param	startOffset		First offset in the (sub-)tree
166 	*/
167 	void			validateOffsets( IChunkContainer& tree, XMP_Uns64 startOffset = 0 );
168 
169 	/**
170 		Retrieve the free space at the passed position in the child list of the parent tree.
171 		If there's a FREE chunk then return it.
172 
173 		@param outFreeBytes		On return it takes the number of free bytes
174 		@param tree				Parent tree
175 		@param index			Position in the child list of the parent tree
176 
177 		@return					FREE chunk if available
178 	*/
179 	Chunk*			getFreeSpace( XMP_Int64& outFreeBytes, const IChunkContainer& tree, XMP_Uns32 index ) const ;
180 
181 	/**
182 		Try to arrange all chunks of the source tree at their current location.
183 		The method looks for FREE chunk around or for size changes of the chunks around and try that space.
184 		If a chunk can't be arrange at its location it is moved to the end of the destination tree.
185 
186 		@param srcTree		Tree that consists of the chunks that needs to be arranged
187 		@param destTree		Tree where chunks are added to if they can't be arranged
188 
189 		@return				Index of last proceeded chunk
190 		*/
191 	void			arrangeChunksInPlace( IChunkContainer& srcTree, IChunkContainer& destTree );
192 
193 	/**
194 		This method proceeds the list of Chunks of the source tree in the passed range and looks for FREE chunks
195 		in the destination tree to move the source chunks to.
196 		Source tree and destination tree could be one and the same but it's not required. If both trees are the
197 		same then it's not allowed to cross source and destination ranges.
198 
199 		@param srcTree		Tree that consists of the chunks that needs to be arranged
200 		@param destTree		Tree where the method looks for FREE chunks
201 		@param srcStart		Start index within the source tree
202 		@param srcEnd		End index within the source tree (if booth, srcStart and srcEnd are zero then the complete list
203 							of the source tree is proceeded)
204 		@param destStart	Start index within the destination tree
205 		@param destEnd		End index within the destination tree (if booth, destStart and destEnd are zero then the complete list
206 							of the destination tree is proceeded)
207 	*/
208 	void	 		arrangeChunksInTree( IChunkContainer& srcTree, IChunkContainer& destTree );
209 
210 	/**
211 		Try to merge existing FREE chunks at the passed position in the child list
212 		of the passed parent tree.
213 		The algorithm looks at the position, before the position and after the position.
214 
215 		@param tree			Parent tree
216 		@param index		Position in the child list of the parent tree
217 
218 		@return				FREE chunk if available at the passed position (in case of a merge
219 							the merged FREE chunk)
220 	*/
221 	Chunk*			mergeFreeChunks( IChunkContainer& tree, XMP_Uns32 index );
222 
223 	/**
224 		Move a range of chunks from one container to another starting at the start index up to the
225 		end of the srcTree.
226 
227 		@param srcTree		Source container
228 		@param destTree		Destination container
229 		@param start		Start index of source container
230 	 */
231 	void			moveChunks( IChunkContainer& srcTree, IChunkContainer& destTree, XMP_Uns32 start );
232 
233 private:
234 	std::vector<ChunkPath>*	 mMovablePaths;
235 };
236 
237 } // IChunkBehavior
238 
239 #endif
240