1 #ifndef __XIO_hpp__
2 #define __XIO_hpp__ 1
3 
4 // =================================================================================================
5 // ADOBE SYSTEMS INCORPORATED
6 // Copyright 2010 Adobe Systems Incorporated
7 // All Rights Reserved
8 //
9 // NOTICE:  Adobe permits you to use, modify, and distribute this file in accordance with the terms
10 // of the Adobe license agreement accompanying it.
11 // =================================================================================================
12 
13 #include "public/include/XMP_Environment.h"	// ! XMP_Environment.h must be the first included header.
14 
15 #include "public/include/XMP_Const.h"
16 #include "public/include/XMP_IO.hpp"
17 
18 #include "source/Host_IO.hpp"
19 #include "source/EndianUtils.hpp"
20 
21 #include <string>
22 
23 // =================================================================================================
24 // Support for I/O
25 // ===============
26 
27 namespace XIO {
28 
29 	// =============================================================================================
30 	// Internal utilities layered on top of the abstract XMP_IO and XMPFiles_IO classes.
31 	// =================================================================================
32 
33 	void SplitLeafName ( std::string * path, std::string * leafName );
34 	void SplitFileExtension ( std::string * path, std::string * fileExt , bool lowercase=true);
35 
36 	void ReplaceTextFile ( XMP_IO* textFile, const std::string & newContent, bool doSafeUpdate );
37 
38 	extern void Copy ( XMP_IO* sourceFile, XMP_IO* destFile, XMP_Int64 length,
39 					   XMP_AbortProc abortProc = 0, void* abortArg = 0 );
40 
41 	extern void Move ( XMP_IO* sourceFile, XMP_Int64 sourceOffset,
42 					   XMP_IO* destFile, XMP_Int64 destOffset,
43 					   XMP_Int64 length, XMP_AbortProc abortProc = 0, void* abortArg = 0 );
44 
CheckFileSpace(XMP_IO * file,XMP_Int64 length)45 	static inline bool CheckFileSpace ( XMP_IO* file, XMP_Int64 length )
46 	{
47 		XMP_Int64 remaining = file->Length() - file->Offset();
48 		return (length <= remaining);
49 	}
50 
51 	// *** Need to absorb more of the utilities like FolderInfo, GetFileMode.
52 
53 	// =============================================================================================
54 	// Inline utilities for endian-oriented reads and writes of numerbers.
55 	// ===================================================================
56 
57 	// -------------------------------------
58 	// Unsigned forms that do the real work.
59 
ReadUns8(XMP_IO * file)60 	static inline XMP_Uns8 ReadUns8 ( XMP_IO* file )
61 	{
62 		XMP_Uns8 value;
63 		file->ReadAll ( &value, 1 );
64 		return value;
65 	}
66 
ReadUns16_BE(XMP_IO * file)67 	static inline XMP_Uns16 ReadUns16_BE ( XMP_IO* file )
68 	{
69 		XMP_Uns16 value;
70 		file->ReadAll ( &value, 2 );
71 		return MakeUns16BE ( value );
72 	}
73 
ReadUns16_LE(XMP_IO * file)74 	static inline XMP_Uns16 ReadUns16_LE ( XMP_IO* file )
75 	{
76 		XMP_Uns16 value;
77 		file->ReadAll ( &value, 2 );
78 		return MakeUns16LE ( value );
79 	}
80 
ReadUns32_BE(XMP_IO * file)81 	static inline XMP_Uns32 ReadUns32_BE ( XMP_IO* file )
82 	{
83 		XMP_Uns32 value;
84 		file->ReadAll ( &value, 4 );
85 		return MakeUns32BE ( value );
86 	}
87 
ReadUns32_LE(XMP_IO * file)88 	static inline XMP_Uns32 ReadUns32_LE ( XMP_IO* file )
89 	{
90 		XMP_Uns32 value;
91 		file->ReadAll ( &value, 4 );
92 		return MakeUns32LE ( value );
93 	}
94 
ReadUns64_BE(XMP_IO * file)95 	static inline XMP_Uns64 ReadUns64_BE ( XMP_IO* file )
96 	{
97 		XMP_Uns64 value;
98 		file->ReadAll ( &value, 8 );
99 		return MakeUns64BE ( value );
100 	}
101 
ReadUns64_LE(XMP_IO * file)102 	static inline XMP_Uns64 ReadUns64_LE ( XMP_IO* file )
103 	{
104 		XMP_Uns64 value;
105 		file->ReadAll ( &value, 8 );
106 		return MakeUns64LE ( value );
107 	}
108 
PeekUns8(XMP_IO * file)109 	static inline XMP_Uns8 PeekUns8 ( XMP_IO* file )
110 	{
111 		XMP_Uns8 value = XIO::ReadUns8 ( file );
112 		file->Seek ( -1, kXMP_SeekFromCurrent );
113 		return value;
114 	}
115 
PeekUns16_BE(XMP_IO * file)116 	static inline XMP_Uns16 PeekUns16_BE ( XMP_IO* file )
117 	{
118 		XMP_Uns16 value = XIO::ReadUns16_BE ( file );
119 		file->Seek ( -2, kXMP_SeekFromCurrent );
120 		return value;
121 	}
122 
PeekUns16_LE(XMP_IO * file)123 	static inline XMP_Uns16 PeekUns16_LE ( XMP_IO* file )
124 	{
125 		XMP_Uns16 value = XIO::ReadUns16_LE ( file );
126 		file->Seek ( -2, kXMP_SeekFromCurrent );
127 		return value;
128 	}
129 
PeekUns32_BE(XMP_IO * file)130 	static inline XMP_Uns32 PeekUns32_BE ( XMP_IO* file )
131 	{
132 		XMP_Uns32 value = XIO::ReadUns32_BE ( file );
133 		file->Seek ( -4, kXMP_SeekFromCurrent );
134 		return value;
135 	}
136 
PeekUns32_LE(XMP_IO * file)137 	static inline XMP_Uns32 PeekUns32_LE ( XMP_IO* file )
138 	{
139 		XMP_Uns32 value = XIO::ReadUns32_LE ( file );
140 		file->Seek ( -4, kXMP_SeekFromCurrent );
141 		return value;
142 	}
143 
PeekUns64_BE(XMP_IO * file)144 	static inline XMP_Uns64 PeekUns64_BE ( XMP_IO* file )
145 	{
146 		XMP_Uns64 value = XIO::ReadUns64_BE ( file );
147 		file->Seek ( -8, kXMP_SeekFromCurrent );
148 		return value;
149 	}
150 
PeekUns64_LE(XMP_IO * file)151 	static inline XMP_Uns64 PeekUns64_LE ( XMP_IO* file )
152 	{
153 		XMP_Uns64 value = XIO::ReadUns64_LE ( file );
154 		file->Seek ( -8, kXMP_SeekFromCurrent );
155 		return value;
156 	}
157 
WriteUns8(XMP_IO * file,XMP_Uns8 value)158 	static inline void WriteUns8 ( XMP_IO* file, XMP_Uns8 value )
159 	{
160 		file->Write ( &value, 1 );
161 	}
162 
WriteUns16_BE(XMP_IO * file,XMP_Uns16 value)163 	static inline void WriteUns16_BE ( XMP_IO* file, XMP_Uns16 value )
164 	{
165 		XMP_Uns16 v = MakeUns16BE ( value );
166 		file->Write ( &v, 2 );
167 	}
168 
WriteUns16_LE(XMP_IO * file,XMP_Uns16 value)169 	static inline void WriteUns16_LE ( XMP_IO* file, XMP_Uns16 value )
170 	{
171 		XMP_Uns16 v = MakeUns16LE ( value );
172 		file->Write ( &v, 2 );
173 	}
174 
WriteUns32_BE(XMP_IO * file,XMP_Uns32 value)175 	static inline void WriteUns32_BE ( XMP_IO* file, XMP_Uns32 value )
176 	{
177 		XMP_Uns32 v = MakeUns32BE ( value );
178 		file->Write ( &v, 4 );
179 	}
180 
WriteUns32_LE(XMP_IO * file,XMP_Uns32 value)181 	static inline void WriteUns32_LE ( XMP_IO* file, XMP_Uns32 value )
182 	{
183 		XMP_Uns32 v = MakeUns32LE ( value );
184 		file->Write ( &v, 4 );
185 	}
186 
WriteUns64_BE(XMP_IO * file,XMP_Uns64 value)187 	static inline void WriteUns64_BE ( XMP_IO* file, XMP_Uns64 value )
188 	{
189 		XMP_Uns64 v = MakeUns64BE ( value );
190 		file->Write ( &v, 8 );
191 	}
192 
WriteUns64_LE(XMP_IO * file,XMP_Uns64 value)193 	static inline void WriteUns64_LE ( XMP_IO* file, XMP_Uns64 value )
194 	{
195 		XMP_Uns64 v = MakeUns64LE ( value );
196 		file->Write ( &v, 8 );
197 	}
198 
199 	// ------------------------------------------------------------------
200 	// Signed forms that just cast to unsigned and use the unsigned call.
201 
ReadInt8(XMP_IO * file)202 	static inline XMP_Int8 ReadInt8 ( XMP_IO* file )
203 	{
204 		return (XMP_Int8) XIO::ReadUns8 ( file );
205 	}
206 
ReadInt16_BE(XMP_IO * file)207 	static inline XMP_Int16 ReadInt16_BE ( XMP_IO* file )
208 	{
209 		return (XMP_Int16) XIO::ReadUns16_BE ( file );
210 	}
211 
ReadInt16_LE(XMP_IO * file)212 	static inline XMP_Int16 ReadInt16_LE ( XMP_IO* file )
213 	{
214 		return (XMP_Int16) XIO::ReadUns16_LE ( file );
215 	}
216 
ReadInt32_BE(XMP_IO * file)217 	static inline XMP_Int32 ReadInt32_BE ( XMP_IO* file )
218 	{
219 		return (XMP_Int32) XIO::ReadUns32_BE ( file );
220 	}
221 
ReadInt32_LE(XMP_IO * file)222 	static inline XMP_Int32 ReadInt32_LE ( XMP_IO* file )
223 	{
224 		return (XMP_Int32) XIO::ReadUns32_LE ( file );
225 	}
226 
ReadInt64_BE(XMP_IO * file)227 	static inline XMP_Int64 ReadInt64_BE ( XMP_IO* file )
228 	{
229 		return (XMP_Int64) XIO::ReadUns64_BE ( file );
230 	}
231 
ReadInt64_LE(XMP_IO * file)232 	static inline XMP_Int64 ReadInt64_LE ( XMP_IO* file )
233 	{
234 		return (XMP_Int64) XIO::ReadUns64_LE ( file );
235 	}
236 
PeekInt8(XMP_IO * file)237 	static inline XMP_Int8 PeekInt8 ( XMP_IO* file )
238 	{
239 		return (XMP_Int8) XIO::PeekUns8 ( file );
240 	}
241 
PeekInt16_BE(XMP_IO * file)242 	static inline XMP_Int16 PeekInt16_BE ( XMP_IO* file )
243 	{
244 		return (XMP_Int16) XIO::PeekUns16_BE ( file );
245 	}
246 
PeekInt16_LE(XMP_IO * file)247 	static inline XMP_Int16 PeekInt16_LE ( XMP_IO* file )
248 	{
249 		return (XMP_Int16) XIO::PeekUns16_LE ( file );
250 	}
251 
PeekInt32_BE(XMP_IO * file)252 	static inline XMP_Int32 PeekInt32_BE ( XMP_IO* file )
253 	{
254 		return (XMP_Int32) XIO::PeekUns32_BE ( file );
255 	}
256 
PeekInt32_LE(XMP_IO * file)257 	static inline XMP_Int32 PeekInt32_LE ( XMP_IO* file )
258 	{
259 		return (XMP_Int32) XIO::PeekUns32_LE ( file );
260 	}
261 
PeekInt64_BE(XMP_IO * file)262 	static inline XMP_Int64 PeekInt64_BE ( XMP_IO* file )
263 	{
264 		return (XMP_Int64) XIO::PeekUns64_BE ( file );
265 	}
266 
PeekInt64_LE(XMP_IO * file)267 	static inline XMP_Int64 PeekInt64_LE ( XMP_IO* file )
268 	{
269 		return (XMP_Int64) XIO::PeekUns64_LE ( file );
270 	}
271 
WriteInt8(XMP_IO * file,XMP_Int8 value)272 	static inline void WriteInt8 ( XMP_IO* file, XMP_Int8 value )
273 	{
274 		XIO::WriteUns8 ( file, (XMP_Uns8)value );
275 	}
276 
WriteInt16_BE(XMP_IO * file,XMP_Int16 value)277 	static inline void WriteInt16_BE ( XMP_IO* file, XMP_Int16 value )
278 	{
279 		XIO::WriteUns16_BE ( file, (XMP_Uns16)value );
280 	}
281 
WriteInt16_LE(XMP_IO * file,XMP_Int16 value)282 	static inline void WriteInt16_LE ( XMP_IO* file, XMP_Int16 value )
283 	{
284 		XIO::WriteUns16_LE ( file, (XMP_Uns16)value );
285 	}
286 
WriteInt32_BE(XMP_IO * file,XMP_Int32 value)287 	static inline void WriteInt32_BE ( XMP_IO* file, XMP_Int32 value )
288 	{
289 		XIO::WriteUns32_BE ( file, (XMP_Uns32)value );
290 	}
291 
WriteInt32_LE(XMP_IO * file,XMP_Int32 value)292 	static inline void WriteInt32_LE ( XMP_IO* file, XMP_Int32 value )
293 	{
294 		XIO::WriteUns32_LE ( file, (XMP_Uns32)value );
295 	}
296 
WriteInt64_BE(XMP_IO * file,XMP_Int64 value)297 	static inline void WriteInt64_BE ( XMP_IO* file, XMP_Int64 value )
298 	{
299 		XIO::WriteUns64_BE ( file, (XMP_Uns64)value );
300 	}
301 
WriteInt64_LE(XMP_IO * file,XMP_Int64 value)302 	static inline void WriteInt64_LE ( XMP_IO* file, XMP_Int64 value )
303 	{
304 		XIO::WriteUns64_LE ( file, (XMP_Uns64)value );
305 	}
306 
307 };
308 
309 // =================================================================================================
310 
311 // **********************************************************************************************
312 // I/O buffer used in JPEG, PSD, and TIFF handlers. Discredited, a mistake, do not use elsewhere.
313 // **********************************************************************************************
314 
315 // -------------------------------------------------------------------------------------------------
316 // CheckFileSpace and RefillBuffer
317 // -------------------------------
318 //
319 // There is always a problem in file scanning of managing what you want to check against what is
320 // available in a buffer, trying to keep the logic understandable and minimize data movement. The
321 // CheckFileSpace and RefillBuffer functions are used here for a standard scanning model.
322 //
323 // The format scanning routines have an outer, "infinite" loop that looks for file markers. There
324 // is a local (on stack) buffer, a pointer to the current position in the buffer, and a pointer for
325 // the end of the buffer. The end pointer is just past the end of the buffer, "bufPtr == bufLimit"
326 // means you are out of data. The outer loop ends when the necessary markers are found or we reach
327 // the end of the file.
328 //
329 // The filePos is the file offset of the start of the current buffer. This is maintained so that
330 // we can tell where the packet is in the file, part of the info returned to the client.
331 //
332 // At each check CheckFileSpace is used to make sure there is enough data in the buffer for the
333 // check to be made. It refills the buffer if necessary, preserving the unprocessed data, setting
334 // bufPtr and bufLimit appropriately. If we are too close to the end of the file to make the check
335 // a failure status is returned.
336 
337 enum { kIOBufferSize = 128*1024 };
338 
339 struct IOBuffer {
340 	XMP_Int64 filePos;
341 	XMP_Uns8* ptr;
342 	XMP_Uns8* limit;
343 	size_t    len;
344 	XMP_Uns8  data [kIOBufferSize];
IOBufferIOBuffer345 	IOBuffer() : filePos(0), ptr(&data[0]), limit(ptr), len(0) {};
346 };
347 
FillBuffer(XMP_IO * fileRef,XMP_Int64 fileOffset,IOBuffer * ioBuf)348 static inline void FillBuffer ( XMP_IO* fileRef, XMP_Int64 fileOffset, IOBuffer* ioBuf )
349 {
350 	ioBuf->filePos = fileRef->Seek ( fileOffset, kXMP_SeekFromStart );
351 	if ( ioBuf->filePos != fileOffset ) {
352 		throw XMP_Error ( kXMPErr_ExternalFailure, "Seek failure in FillBuffer" );
353 	}
354 	ioBuf->len = fileRef->Read ( &ioBuf->data[0], kIOBufferSize );
355 	ioBuf->ptr = &ioBuf->data[0];
356 	ioBuf->limit = ioBuf->ptr + ioBuf->len;
357 }
358 
MoveToOffset(XMP_IO * fileRef,XMP_Int64 fileOffset,IOBuffer * ioBuf)359 static inline void MoveToOffset ( XMP_IO* fileRef, XMP_Int64 fileOffset, IOBuffer* ioBuf )
360 {
361 	if ( (ioBuf->filePos <= fileOffset) && (fileOffset < (XMP_Int64)(ioBuf->filePos + ioBuf->len)) ) {
362 		size_t bufOffset = (size_t)(fileOffset - ioBuf->filePos);
363 		ioBuf->ptr = &ioBuf->data[bufOffset];
364 	} else {
365 		FillBuffer ( fileRef, fileOffset, ioBuf );
366 	}
367 }
368 
RefillBuffer(XMP_IO * fileRef,IOBuffer * ioBuf)369 static inline void RefillBuffer ( XMP_IO* fileRef, IOBuffer* ioBuf )
370 {
371 	// Refill including part of the current data, seek back to the new buffer origin and read.
372 	ioBuf->filePos += (ioBuf->ptr - &ioBuf->data[0]);	// ! Increment before the read.
373 	size_t bufTail = ioBuf->limit - ioBuf->ptr;	// We'll re-read the tail portion of the buffer.
374 	if ( bufTail > 0 ) ioBuf->filePos = fileRef->Seek ( -((XMP_Int64)bufTail), kXMP_SeekFromCurrent );
375 	ioBuf->len = fileRef->Read ( &ioBuf->data[0], kIOBufferSize );
376 	ioBuf->ptr = &ioBuf->data[0];
377 	ioBuf->limit = ioBuf->ptr + ioBuf->len;
378 }
379 
CheckFileSpace(XMP_IO * fileRef,IOBuffer * ioBuf,size_t neededLen)380 static inline bool CheckFileSpace ( XMP_IO* fileRef, IOBuffer* ioBuf, size_t neededLen )
381 {
382 	if ( size_t(ioBuf->limit - ioBuf->ptr) < size_t(neededLen) ) {	// ! Avoid VS.Net compare warnings.
383 		RefillBuffer ( fileRef, ioBuf );
384 	}
385 	return (size_t(ioBuf->limit - ioBuf->ptr) >= size_t(neededLen));
386 }
387 
388 #endif	// __XIO_hpp__
389