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