1 //*@@@+++@@@@******************************************************************
2 //
3 // Copyright � Microsoft Corp.
4 // All rights reserved.
5 //
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions are met:
8 //
9 // � Redistributions of source code must retain the above copyright notice,
10 // this list of conditions and the following disclaimer.
11 // � Redistributions in binary form must reproduce the above copyright notice,
12 // this list of conditions and the following disclaimer in the documentation
13 // and/or other materials provided with the distribution.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 // POSSIBILITY OF SUCH DAMAGE.
26 //
27 //*@@@---@@@@******************************************************************
28 #include "JXRMeta.h"
29 #include "JXRGlue.h"
30
31
32
33 // read and write big and little endian words/dwords from a buffer on both big and little endian cpu's
34 // with full buffer overflow checking
35
36
37
getbfcpy(U8 * pbdest,const U8 * pb,size_t cb,size_t ofs,U32 n)38 ERR getbfcpy(U8* pbdest, const U8* pb, size_t cb, size_t ofs, U32 n)
39 {
40 ERR err = WMP_errSuccess;
41 FailIf(ofs + n > cb, WMP_errBufferOverflow);
42 memcpy(pbdest, &pb[ofs], n);
43 Cleanup:
44 return err;
45 }
46
47
48
getbfw(const U8 * pb,size_t cb,size_t ofs,U16 * pw)49 ERR getbfw(const U8* pb, size_t cb, size_t ofs, U16* pw)
50 {
51 ERR err = WMP_errSuccess;
52 FailIf(ofs + sizeof(U16) > cb, WMP_errBufferOverflow);
53 *pw = (U16)( pb[ofs] + ( pb[ofs + 1] << 8 ) );
54 Cleanup:
55 return err;
56 }
57
58
59
getbfdw(const U8 * pb,size_t cb,size_t ofs,U32 * pdw)60 ERR getbfdw(const U8* pb, size_t cb, size_t ofs, U32* pdw)
61 {
62 ERR err = WMP_errSuccess;
63 FailIf(ofs + sizeof(U32) > cb, WMP_errBufferOverflow);
64 *pdw = pb[ofs] + ( pb[ofs + 1] << 8 ) + ( pb[ofs + 2] << 16UL ) + ( pb[ofs + 3] << 24UL );
65 Cleanup:
66 return err;
67 }
68
69
70
getbfwbig(const U8 * pb,size_t cb,size_t ofs,U16 * pw)71 ERR getbfwbig(const U8* pb, size_t cb, size_t ofs, U16* pw)
72 {
73 ERR err = WMP_errSuccess;
74 FailIf(ofs + sizeof(U16) > cb, WMP_errBufferOverflow);
75 *pw = (U16)( pb[ofs + 1] + ( pb[ofs] << 8 ) );
76 Cleanup:
77 return err;
78 }
79
80
81
getbfdwbig(const U8 * pb,size_t cb,size_t ofs,U32 * pdw)82 ERR getbfdwbig(const U8* pb, size_t cb, size_t ofs, U32* pdw)
83 {
84 ERR err = WMP_errSuccess;
85 FailIf(ofs + sizeof(U32) > cb, WMP_errBufferOverflow);
86 *pdw = pb[ofs + 3] + ( pb[ofs + 2] << 8 ) + ( pb[ofs + 1] << 16UL ) + ( pb[ofs] << 24UL );
87 Cleanup:
88 return err;
89 }
90
91
92
getbfwe(const U8 * pb,size_t cb,size_t ofs,U16 * pw,U8 endian)93 ERR getbfwe(const U8* pb, size_t cb, size_t ofs, U16* pw, U8 endian)
94 {
95 if ( endian == WMP_INTEL_ENDIAN )
96 return ( getbfw(pb, cb, ofs, pw) );
97 else
98 return ( getbfwbig(pb, cb, ofs, pw) );
99 }
100
101
102
getbfdwe(const U8 * pb,size_t cb,size_t ofs,U32 * pdw,U8 endian)103 ERR getbfdwe(const U8* pb, size_t cb, size_t ofs, U32* pdw, U8 endian)
104 {
105 if ( endian == WMP_INTEL_ENDIAN )
106 return ( getbfdw(pb, cb, ofs, pdw) );
107 else
108 return ( getbfdwbig(pb, cb, ofs, pdw) );
109 }
110
111
112
setbfcpy(U8 * pb,size_t cb,size_t ofs,const U8 * pbset,size_t cbset)113 ERR setbfcpy(U8* pb, size_t cb, size_t ofs, const U8* pbset, size_t cbset)
114 {
115 ERR err = WMP_errSuccess;
116 FailIf(ofs + cbset > cb, WMP_errBufferOverflow);
117 memcpy(&pb[ofs], pbset, cbset);
118 Cleanup:
119 return err;
120 }
121
122
123
setbfw(U8 * pb,size_t cb,size_t ofs,U16 dw)124 ERR setbfw(U8* pb, size_t cb, size_t ofs, U16 dw)
125 {
126 ERR err = WMP_errSuccess;
127 FailIf(ofs + sizeof(U16) > cb, WMP_errBufferOverflow);
128 pb[ofs] = (U8)dw;
129 pb[ofs + 1] = (U8)( dw >> 8 );
130 Cleanup:
131 return err;
132 }
133
134
135
setbfdw(U8 * pb,size_t cb,size_t ofs,U32 dw)136 ERR setbfdw(U8* pb, size_t cb, size_t ofs, U32 dw)
137 {
138 ERR err = WMP_errSuccess;
139 FailIf(ofs + sizeof(U32) > cb, WMP_errBufferOverflow);
140 pb[ofs] = (U8)dw;
141 pb[ofs + 1] = (U8)( dw >> 8 );
142 pb[ofs + 2] = (U8)( dw >> 16 );
143 pb[ofs + 3] = (U8)( dw >> 24 );
144 Cleanup:
145 return err;
146 }
147
148
149
setbfwbig(U8 * pb,size_t cb,size_t ofs,U16 dw)150 ERR setbfwbig(U8* pb, size_t cb, size_t ofs, U16 dw)
151 {
152 ERR err = WMP_errSuccess;
153 FailIf(ofs + sizeof(U16) > cb, WMP_errBufferOverflow);
154 pb[ofs + 1] = (U8)dw;
155 pb[ofs] = (U8)( dw >> 8 );
156 Cleanup:
157 return err;
158 }
159
160
161
setbfdwbig(U8 * pb,size_t cb,size_t ofs,U32 dw)162 ERR setbfdwbig(U8* pb, size_t cb, size_t ofs, U32 dw)
163 {
164 ERR err = WMP_errSuccess;
165 FailIf(ofs + sizeof(U32) > cb, WMP_errBufferOverflow);
166 pb[ofs + 3] = (U8)dw;
167 pb[ofs + 2] = (U8)( dw >> 8 );
168 pb[ofs + 1] = (U8)( dw >> 16 );
169 pb[ofs] = (U8)( dw >> 24 );
170 Cleanup:
171 return err;
172 }
173
174
175
176 //================================================================
177 // BufferCalcIFDSize (arbitrary endian)
178 // StreamCalcIFDSize (little endian)
179 //
180 // count up the number of bytes needed to store the IFD and all
181 // associated data including a subordinate interoperability IFD if any
182 //================================================================
183
184
185
BufferCalcIFDSize(const U8 * pbdata,size_t cbdata,U32 ofsifd,U8 endian,U32 * pcbifd)186 ERR BufferCalcIFDSize(const U8* pbdata, size_t cbdata, U32 ofsifd, U8 endian, U32* pcbifd)
187 {
188 ERR err = WMP_errSuccess;
189 U16 cDir;
190 U16 i;
191 U32 ofsdir;
192 U32 cbifd = 0;
193 U32 cbEXIFIFD = 0;
194 U32 cbGPSInfoIFD = 0;
195 U32 cbInteroperabilityIFD = 0;
196
197 *pcbifd = 0;
198 Call(getbfwe(pbdata, cbdata, ofsifd, &cDir, endian));
199
200 cbifd = sizeof(U16) + cDir * SizeofIFDEntry + sizeof(U32);
201 ofsdir = ofsifd + sizeof(U16);
202 for ( i = 0; i < cDir; i++ )
203 {
204 U16 tag;
205 U16 type;
206 U32 count;
207 U32 value;
208 U32 datasize;
209
210 Call(getbfwe(pbdata, cbdata, ofsdir, &tag, endian));
211 Call(getbfwe(pbdata, cbdata, ofsdir + sizeof(U16), &type, endian));
212 Call(getbfdwe(pbdata, cbdata, ofsdir + 2 * sizeof(U16), &count, endian));
213 Call(getbfdwe(pbdata, cbdata, ofsdir + 2 * sizeof(U16) + sizeof(U32), &value, endian));
214 FailIf(type == 0 || type >= sizeof(IFDEntryTypeSizes) / sizeof(IFDEntryTypeSizes[0]), WMP_errFail);
215 if ( tag == WMP_tagEXIFMetadata )
216 {
217 Call(BufferCalcIFDSize(pbdata, cbdata, value, endian, &cbEXIFIFD));
218 }
219 else if ( tag == WMP_tagGPSInfoMetadata )
220 {
221 Call(BufferCalcIFDSize(pbdata, cbdata, value, endian, &cbGPSInfoIFD));
222 }
223 else if ( tag == WMP_tagInteroperabilityIFD )
224 {
225 Call(BufferCalcIFDSize(pbdata, cbdata, value, endian, &cbInteroperabilityIFD));
226 }
227 else
228 {
229 datasize = IFDEntryTypeSizes[type] * count;
230 if ( datasize > 4 )
231 cbifd += datasize;
232 }
233 ofsdir += SizeofIFDEntry;
234 }
235 if ( cbEXIFIFD != 0 )
236 cbifd += ( cbifd & 1 ) + cbEXIFIFD;
237 if ( cbGPSInfoIFD != 0 )
238 cbifd += ( cbifd & 1 ) + cbGPSInfoIFD;
239 if ( cbInteroperabilityIFD != 0 )
240 cbifd += ( cbifd & 1 ) + cbInteroperabilityIFD;
241
242 *pcbifd = cbifd;
243
244 Cleanup:
245 return err;
246 }
247
248
StreamCalcIFDSize(struct WMPStream * pWS,U32 uIFDOfs,U32 * pcbifd)249 ERR StreamCalcIFDSize(struct WMPStream* pWS, U32 uIFDOfs, U32 *pcbifd)
250 {
251 ERR err = WMP_errSuccess;
252 size_t offCurPos = 0;
253 Bool GetPosOK = FALSE;
254 U16 cDir;
255 U32 i;
256 U32 ofsdir;
257 U32 cbifd = 0;
258 U32 cbEXIFIFD = 0;
259 U32 cbGPSInfoIFD = 0;
260 U32 cbInteroperabilityIFD = 0;
261
262 *pcbifd = 0;
263 Call(pWS->GetPos(pWS, &offCurPos));
264 GetPosOK = TRUE;
265
266 Call(GetUShort(pWS, uIFDOfs, &cDir));
267 cbifd = sizeof(U16) + cDir * SizeofIFDEntry + sizeof(U32);
268 ofsdir = uIFDOfs + sizeof(U16);
269 for ( i = 0; i < cDir; i++ )
270 {
271 U16 tag;
272 U16 type;
273 U32 count;
274 U32 value;
275 U32 datasize;
276
277 Call(GetUShort(pWS, ofsdir, &tag));
278 Call(GetUShort(pWS, ofsdir + sizeof(U16), &type));
279 Call(GetULong(pWS, ofsdir + 2 * sizeof(U16), &count));
280 Call(GetULong(pWS, ofsdir + 2 * sizeof(U16) + sizeof(U32), &value));
281 FailIf(type == 0 || type >= sizeof(IFDEntryTypeSizes) / sizeof(IFDEntryTypeSizes[0]), WMP_errUnsupportedFormat);
282 if ( tag == WMP_tagEXIFMetadata )
283 {
284 Call(StreamCalcIFDSize(pWS, value, &cbEXIFIFD));
285 }
286 else if ( tag == WMP_tagGPSInfoMetadata )
287 {
288 Call(StreamCalcIFDSize(pWS, value, &cbGPSInfoIFD));
289 }
290 else if ( tag == WMP_tagInteroperabilityIFD )
291 {
292 Call(StreamCalcIFDSize(pWS, value, &cbInteroperabilityIFD));
293 }
294 else
295 {
296 datasize = IFDEntryTypeSizes[type] * count;
297 if ( datasize > 4 )
298 cbifd += datasize;
299 }
300 ofsdir += SizeofIFDEntry;
301 }
302 if ( cbEXIFIFD != 0 )
303 cbifd += ( cbifd & 1 ) + cbEXIFIFD;
304 if ( cbGPSInfoIFD != 0 )
305 cbifd += ( cbifd & 1 ) + cbGPSInfoIFD;
306 if ( cbInteroperabilityIFD != 0 )
307 cbifd += ( cbifd & 1 ) + cbInteroperabilityIFD;
308 *pcbifd = cbifd;
309
310 Cleanup:
311 if ( GetPosOK )
312 Call(pWS->SetPos(pWS, offCurPos));
313 return ( err );
314 }
315
316
317
318 // src IFD copied to dst IFD with any nested IFD's
319 // src IFD is arbitrary endian, arbitrary data arrangement
320 // dst IFD is little endian, data arranged in tag order
321 // dst IFD tags are ordered the same as src IFD so src IFD tags must be in order
BufferCopyIFD(const U8 * pbsrc,U32 cbsrc,U32 ofssrc,U8 endian,U8 * pbdst,U32 cbdst,U32 * pofsdst)322 ERR BufferCopyIFD(const U8* pbsrc, U32 cbsrc, U32 ofssrc, U8 endian, U8* pbdst, U32 cbdst, U32* pofsdst)
323 {
324 ERR err = WMP_errSuccess;
325 U16 cDir;
326 U16 i;
327 U16 ofsEXIFIFDEntry = 0;
328 U16 ofsGPSInfoIFDEntry = 0;
329 U16 ofsInteroperabilityIFDEntry = 0;
330 U32 ofsEXIFIFD = 0;
331 U32 ofsGPSInfoIFD = 0;
332 U32 ofsInteroperabilityIFD = 0;
333 U32 ofsdstnextdata;
334 U32 ofsdst = *pofsdst;
335 U32 ofssrcdir;
336 U32 ofsdstdir;
337 U32 ofsnextifd;
338
339 Call(getbfwe(pbsrc, cbsrc, ofssrc, &cDir, endian));
340 Call(setbfw(pbdst, cbdst, ofsdst, cDir));
341 ofsnextifd = ofsdst + sizeof(U16) + SizeofIFDEntry * cDir;
342 ofsdstnextdata = ofsnextifd + sizeof(U32);
343
344 ofssrcdir = ofssrc + sizeof(U16);
345 ofsdstdir = ofsdst + sizeof(U16);
346 for ( i = 0; i < cDir; i++ )
347 {
348 U16 tag;
349 U16 type;
350 U32 count;
351 U32 value;
352 U32 size;
353
354 Call(getbfwe(pbsrc, cbsrc, ofssrcdir, &tag, endian));
355 Call(setbfw(pbdst, cbdst, ofsdstdir, tag));
356
357 Call(getbfwe(pbsrc, cbsrc, ofssrcdir + sizeof(U16), &type, endian));
358 Call(setbfw(pbdst, cbdst, ofsdstdir + sizeof(U16), type));
359
360 Call(getbfdwe(pbsrc, cbsrc, ofssrcdir + 2 * sizeof(U16), &count, endian));
361 Call(setbfdw(pbdst, cbdst, ofsdstdir + 2 * sizeof(U16), count));
362
363 Call(getbfdwe(pbsrc, cbsrc, ofssrcdir + 2 * sizeof(U16) + sizeof(U32), &value, endian));
364 Call(setbfdw(pbdst, cbdst, ofsdstdir + 2 * sizeof(U16) + sizeof(U32), 0));
365
366 FailIf(type == 0 || type >= sizeof(IFDEntryTypeSizes) / sizeof(IFDEntryTypeSizes[0]), WMP_errFail);
367 if ( tag == WMP_tagEXIFMetadata )
368 {
369 ofsEXIFIFDEntry = (U16) ofsdstdir;
370 ofsEXIFIFD = value;
371 }
372 else if ( tag == WMP_tagGPSInfoMetadata )
373 {
374 ofsGPSInfoIFDEntry = (U16) ofsdstdir;
375 ofsGPSInfoIFD = value;
376 }
377 else if ( tag == WMP_tagInteroperabilityIFD )
378 {
379 ofsInteroperabilityIFDEntry = (U16) ofsdstdir;
380 ofsInteroperabilityIFD = value;
381 }
382 else
383 {
384 U32 ofsdstdata = ofsdstdir + 2 * sizeof(U16) + sizeof(U32);
385 U32 ofssrcdata = ofssrcdir + 2 * sizeof(U16) + sizeof(U32);
386 size = count * IFDEntryTypeSizes[type];
387 if ( size > 4 )
388 {
389 ofssrcdata = value;
390 Call(setbfdw(pbdst, cbdst, ofsdstdata, ofsdstnextdata));
391 ofsdstdata = ofsdstnextdata;
392 ofsdstnextdata += size;
393 }
394 FailIf(ofssrcdata + size > cbsrc || ofsdstdata + size > cbdst, WMP_errBufferOverflow);
395 if ( size == count || endian == WMP_INTEL_ENDIAN )
396 // size == count means 8-bit data means endian doesn't matter
397 memcpy(&pbdst[ofsdstdata], &pbsrc[ofssrcdata], size);
398 else
399 { // big endian source and endian matters
400 U32 j;
401
402 switch ( IFDEntryTypeSizes[type] )
403 {
404 case 2:
405 for ( j = 0; j < count; j++ )
406 {
407 U16 w;
408 getbfwbig(pbsrc, cbsrc, ofssrcdata + j * sizeof(U16), &w);
409 setbfw(pbdst, cbdst, ofsdstdata + j * sizeof(U16), w);
410 }
411 break;
412 case 8:
413 if ( type == WMP_typDOUBLE )
414 {
415 for ( j = 0; j < count; j++ )
416 {
417 U32 dwlo;
418 U32 dwhi;
419 getbfdwbig(pbsrc, cbsrc, ofssrcdata + j * 8, &dwhi);
420 getbfdwbig(pbsrc, cbsrc, ofssrcdata + j * 8 + sizeof(U32), &dwlo);
421 setbfdw(pbdst, cbdst, ofsdstdata + j * 8, dwlo);
422 setbfdw(pbdst, cbdst, ofsdstdata + j * 8 + sizeof(U32), dwhi);
423 }
424 break;
425 }
426 count *= 2;
427 // RATIONAL's fall through to be handled as LONG's
428 case 4:
429 for ( j = 0; j < count; j++ )
430 {
431 U32 dw;
432 getbfdwbig(pbsrc, cbsrc, ofssrcdata + j * sizeof(U32), &dw);
433 setbfdw(pbdst, cbdst, ofsdstdata + j * sizeof(U32), dw);
434 }
435 break;
436 }
437 }
438 }
439 ofssrcdir += SizeofIFDEntry;
440 ofsdstdir += SizeofIFDEntry;
441 }
442 Call(setbfdw(pbdst, cbdst, ofsnextifd, 0)); // no nextIFD
443
444 if ( ofsEXIFIFDEntry != 0 )
445 {
446 ofsdstnextdata += ( ofsdstnextdata & 1 );
447 Call(setbfdw(pbdst, cbdst, ofsEXIFIFDEntry + 2 * sizeof(U16) + sizeof(U32), ofsdstnextdata));
448 Call(BufferCopyIFD(pbsrc, cbsrc, ofsEXIFIFD, endian, pbdst, cbdst, &ofsdstnextdata));
449 }
450 if ( ofsGPSInfoIFDEntry != 0 )
451 {
452 ofsdstnextdata += ( ofsdstnextdata & 1 );
453 Call(setbfdw(pbdst, cbdst, ofsGPSInfoIFDEntry + 2 * sizeof(U16) + sizeof(U32), ofsdstnextdata));
454 Call(BufferCopyIFD(pbsrc, cbsrc, ofsGPSInfoIFD, endian, pbdst, cbdst, &ofsdstnextdata));
455 }
456 if ( ofsInteroperabilityIFDEntry != 0 )
457 {
458 ofsdstnextdata += ( ofsdstnextdata & 1 );
459 Call(setbfdw(pbdst, cbdst, ofsInteroperabilityIFDEntry + 2 * sizeof(U16) + sizeof(U32), ofsdstnextdata));
460 Call(BufferCopyIFD(pbsrc, cbsrc, ofsInteroperabilityIFD, endian, pbdst, cbdst, &ofsdstnextdata));
461 }
462 *pofsdst = ofsdstnextdata;
463
464 Cleanup:
465 return err;
466 }
467
468
469
470 // src IFD copied to dst IFD with any nested IFD's
471 // src IFD is little endian, arbitrary data arrangement
472 // dst IFD is little endian, data arranged in tag order
473 // dst IFD tags are ordered the same as src IFD so src IFD tags must be in order
StreamCopyIFD(struct WMPStream * pWS,U32 ofssrc,U8 * pbdst,U32 cbdst,U32 * pofsdst)474 ERR StreamCopyIFD(struct WMPStream* pWS, U32 ofssrc, U8* pbdst, U32 cbdst, U32* pofsdst)
475 {
476 ERR err = WMP_errSuccess;
477 size_t offCurPos = 0;
478 Bool GetPosOK = FALSE;
479 U16 cDir;
480 U16 i;
481 U16 ofsEXIFIFDEntry = 0;
482 U16 ofsGPSInfoIFDEntry = 0;
483 U16 ofsInteroperabilityIFDEntry = 0;
484 U32 ofsEXIFIFD = 0;
485 U32 ofsGPSInfoIFD = 0;
486 U32 ofsInteroperabilityIFD = 0;
487 U32 ofsdstnextdata;
488 U32 ofsdst = *pofsdst;
489 U32 ofssrcdir;
490 U32 ofsdstdir;
491 U32 ofsnextifd;
492
493 Call(pWS->GetPos(pWS, &offCurPos));
494 GetPosOK = TRUE;
495
496 Call(GetUShort(pWS, ofssrc, &cDir));
497 Call(setbfw(pbdst, cbdst, ofsdst, cDir));
498
499 ofsnextifd = ofsdst + sizeof(U16) + SizeofIFDEntry * cDir;
500 ofsdstnextdata = ofsnextifd + sizeof(U32);
501
502 ofssrcdir = ofssrc + sizeof(U16);
503 ofsdstdir = ofsdst + sizeof(U16);
504 for ( i = 0; i < cDir; i++ )
505 {
506 U16 tag;
507 U16 type;
508 U32 count;
509 U32 value;
510 U32 size;
511
512 Call(GetUShort(pWS, ofssrcdir, &tag));
513 Call(setbfw(pbdst, cbdst, ofsdstdir, tag));
514
515 Call(GetUShort(pWS, ofssrcdir + sizeof(U16), &type));
516 Call(setbfw(pbdst, cbdst, ofsdstdir + sizeof(U16), type));
517
518 Call(GetULong(pWS, ofssrcdir + 2 * sizeof(U16), &count));
519 Call(setbfdw(pbdst, cbdst, ofsdstdir + 2 * sizeof(U16), count));
520
521 Call(GetULong(pWS, ofssrcdir + 2 * sizeof(U16) + sizeof(U32), &value));
522 Call(setbfdw(pbdst, cbdst, ofsdstdir + 2 * sizeof(U16) + sizeof(U32), 0));
523
524 FailIf(type == 0 || type >= sizeof(IFDEntryTypeSizes) / sizeof(IFDEntryTypeSizes[0]), WMP_errFail);
525 if ( tag == WMP_tagEXIFMetadata )
526 {
527 ofsEXIFIFDEntry = (U16) ofsdstdir;
528 ofsEXIFIFD = value;
529 }
530 else if ( tag == WMP_tagGPSInfoMetadata )
531 {
532 ofsGPSInfoIFDEntry = (U16) ofsdstdir;
533 ofsGPSInfoIFD = value;
534 }
535 else if ( tag == WMP_tagInteroperabilityIFD )
536 {
537 ofsInteroperabilityIFDEntry = (U16) ofsdstdir;
538 ofsInteroperabilityIFD = value;
539 }
540 else
541 {
542 U32 ofsdstdata = ofsdstdir + 2 * sizeof(U16) + sizeof(U32);
543 U32 ofssrcdata = ofssrcdir + 2 * sizeof(U16) + sizeof(U32);
544 size = count * IFDEntryTypeSizes[type];
545 if ( size > 4 )
546 {
547 ofssrcdata = value;
548 Call(setbfdw(pbdst, cbdst, ofsdstdata, ofsdstnextdata));
549 ofsdstdata = ofsdstnextdata;
550 ofsdstnextdata += size;
551 }
552 FailIf(ofsdstdata + size > cbdst, WMP_errBufferOverflow);
553 Call(pWS->SetPos(pWS, ofssrcdata));
554 Call(pWS->Read(pWS, &pbdst[ofsdstdata], size));
555 }
556 ofssrcdir += SizeofIFDEntry;
557 ofsdstdir += SizeofIFDEntry;
558 }
559 Call(setbfdw(pbdst, cbdst, ofsnextifd, 0)); // no nextIFD
560
561 if ( ofsEXIFIFDEntry != 0 )
562 {
563 ofsdstnextdata += ( ofsdstnextdata & 1 );
564 Call(setbfdw(pbdst, cbdst, ofsEXIFIFDEntry + 2 * sizeof(U16) + sizeof(U32), ofsdstnextdata));
565 Call(StreamCopyIFD(pWS, ofsEXIFIFD, pbdst, cbdst, &ofsdstnextdata));
566 }
567 if ( ofsGPSInfoIFDEntry != 0 )
568 {
569 ofsdstnextdata += ( ofsdstnextdata & 1 );
570 Call(setbfdw(pbdst, cbdst, ofsGPSInfoIFDEntry + 2 * sizeof(U16) + sizeof(U32), ofsdstnextdata));
571 Call(StreamCopyIFD(pWS, ofsGPSInfoIFD, pbdst, cbdst, &ofsdstnextdata));
572 }
573 if ( ofsInteroperabilityIFDEntry != 0 )
574 {
575 ofsdstnextdata += ( ofsdstnextdata & 1 );
576 Call(setbfdw(pbdst, cbdst, ofsInteroperabilityIFDEntry + 2 * sizeof(U16) + sizeof(U32), ofsdstnextdata));
577 Call(StreamCopyIFD(pWS, ofsInteroperabilityIFD, pbdst, cbdst, &ofsdstnextdata));
578 }
579 *pofsdst = ofsdstnextdata;
580
581 Cleanup:
582 if ( GetPosOK )
583 Call(pWS->SetPos(pWS, offCurPos));
584 return err;
585 }
586
587
588
589 //================================================================
590 ERR GetUShort(
591 __in_ecount(1) struct WMPStream* pWS,
592 size_t offPos,
593 __out_ecount(1) U16* puValue)
594 {
595 ERR err = WMP_errSuccess;
596 U8 cVal;
597
598 Call(pWS->SetPos(pWS, offPos));
599 Call(pWS->Read(pWS, &cVal, sizeof(cVal)));
600 puValue[0] = (U16) cVal;
601 Call(pWS->Read(pWS, &cVal, sizeof(cVal)));
602 puValue[0] += ((U16) cVal) << 8;
603
604 Cleanup:
605 return err;
606 }
607
608 ERR PutUShort(
609 __in_ecount(1) struct WMPStream* pWS,
610 size_t offPos,
611 U16 uValue)
612 {
613 ERR err = WMP_errSuccess;
614 U8 cVal = (U8) uValue;
615
616 Call(pWS->SetPos(pWS, offPos));
617 Call(pWS->Write(pWS, &cVal, sizeof(cVal)));
618 cVal = (U8) (uValue >> 8);
619 Call(pWS->Write(pWS, &cVal, sizeof(cVal)));
620
621 Cleanup:
622 return err;
623 }
624
625 ERR GetULong(
626 __in_ecount(1) struct WMPStream* pWS,
627 size_t offPos,
628 __out_ecount(1) U32* puValue)
629 {
630 ERR err = WMP_errSuccess;
631 U8 cVal;
632
633 Call(pWS->SetPos(pWS, offPos));
634 Call(pWS->Read(pWS, &cVal, sizeof(cVal)));
635 puValue[0] = (U32) cVal;
636 Call(pWS->Read(pWS, &cVal, sizeof(cVal)));
637 puValue[0] += ((U32) cVal) << 8;
638 Call(pWS->Read(pWS, &cVal, sizeof(cVal)));
639 puValue[0] += ((U32) cVal) << 16;
640 Call(pWS->Read(pWS, &cVal, sizeof(cVal)));
641 puValue[0] += ((U32) cVal) << 24;
642
643 Cleanup:
644 return err;
645 }
646
647 ERR PutULong(
648 __in_ecount(1) struct WMPStream* pWS,
649 size_t offPos,
650 U32 uValue)
651 {
652 ERR err = WMP_errSuccess;
653 U8 cVal = (U8) uValue;
654
655 Call(pWS->SetPos(pWS, offPos));
656 Call(pWS->Write(pWS, &cVal, sizeof(cVal)));
657 cVal = (U8) (uValue >> 8);
658 Call(pWS->Write(pWS, &cVal, sizeof(cVal)));
659 cVal = (U8) (uValue >> 16);
660 Call(pWS->Write(pWS, &cVal, sizeof(cVal)));
661 cVal = (U8) (uValue >> 24);
662 Call(pWS->Write(pWS, &cVal, sizeof(cVal)));
663
664 Cleanup:
665 return err;
666 }
667
668
669 ERR ReadBinaryData(__in_ecount(1) struct WMPStream* pWS,
670 const __in_win U32 uCount,
671 const __in_win U32 uValue,
672 U8 **ppbData)
673 {
674 ERR err = WMP_errSuccess;
675 U8 *pbData = NULL;
676
677 Call(PKAlloc((void **) &pbData, uCount + 2)); // Allocate buffer to store data with space for an added ascii or unicode null
678 if (uCount <= 4)
679 {
680 unsigned int i;
681 for (i = 0; i < uCount; i++)
682 pbData[i] = ((U8*)&uValue)[i]; // Copy least sig bytes - we assume 'II' type TIFF files
683 }
684 else
685 {
686 size_t offPosPrev;
687
688 Call(pWS->GetPos(pWS, &offPosPrev));
689 Call(pWS->SetPos(pWS, uValue));
690 Call(pWS->Read(pWS, pbData, uCount));
691 Call(pWS->SetPos(pWS, offPosPrev));
692 }
693
694 *ppbData = pbData;
695
696 Cleanup:
697 if (Failed(err))
698 {
699 if (pbData)
700 PKFree((void **) &pbData);
701 }
702 return err;
703 }
704
705
706 ERR ReadPropvar(__in_ecount(1) struct WMPStream* pWS,
707 const __in_win U16 uType,
708 const __in_win U32 uCount,
709 const __in_win U32 uValue,
710 __out_win DPKPROPVARIANT *pvar)
711 {
712 ERR err = WMP_errSuccess;
713 // U8 *pbData = NULL;
714
715 memset(pvar, 0, sizeof(*pvar));
716 if (uCount == 0)
717 goto Cleanup; // Nothing to read in here
718
719 switch (uType)
720 {
721 case WMP_typASCII:
722 pvar->vt = DPKVT_LPSTR;
723 Call(ReadBinaryData(pWS, uCount, uValue, (U8 **) &pvar->VT.pszVal));
724 assert(0 == pvar->VT.pszVal[uCount - 1]); // Check that it's null-terminated
725 // make sure (ReadBinaryData allocated uCount + 2 so this and unicode can have forced nulls)
726 pvar->VT.pszVal[uCount] = 0;
727 break;
728
729 case WMP_typBYTE:
730 case WMP_typUNDEFINED:
731 // Return as regular C array rather than safearray, as this type is sometimes
732 // used to convey unicode (which does not require a count field). Caller knows
733 // uCount and can convert to safearray if necessary.
734 pvar->vt = (DPKVT_BYREF | DPKVT_UI1);
735 Call(ReadBinaryData(pWS, uCount, uValue, &pvar->VT.pbVal));
736 break;
737
738 case WMP_typSHORT:
739 if (1 == uCount)
740 {
741 pvar->vt = DPKVT_UI2;
742 pvar->VT.uiVal = (U16)(uValue & 0x0000FFFF);
743 }
744 else if (2 == uCount)
745 {
746 pvar->vt = DPKVT_UI4;
747 pvar->VT.ulVal = uValue;
748 }
749 else
750 {
751 assert(FALSE); // NYI
752 FailIf(TRUE, WMP_errNotYetImplemented);
753 }
754 break;
755
756 default:
757 assert(FALSE); // Unhandled type
758 FailIf(TRUE, WMP_errNotYetImplemented);
759 break;
760 }
761
762 Cleanup:
763 return err;
764 }
765
766
767 ERR WriteWmpDE(
768 __in_ecount(1) struct WMPStream* pWS,
769 size_t *pOffPos,
770 const __in_ecount(1) WmpDE* pDE,
771 const U8 *pbData,
772 U32 *pcbDataWrittenToOffset)
773 {
774 ERR err = WMP_errSuccess;
775 size_t offPos = *pOffPos;
776
777 assert(-1 != pDE->uCount);
778 assert(-1 != pDE->uValueOrOffset);
779
780 if (pcbDataWrittenToOffset)
781 {
782 assert(pbData); // Makes no sense to provide this arg without pbData
783 *pcbDataWrittenToOffset = 0;
784 }
785
786 Call(PutUShort(pWS, offPos, pDE->uTag)); offPos += 2;
787 Call(PutUShort(pWS, offPos, pDE->uType)); offPos += 2;
788 Call(PutULong(pWS, offPos, pDE->uCount)); offPos += 4;
789
790 switch (pDE->uType)
791 {
792
793 case WMP_typASCII:
794 case WMP_typUNDEFINED:
795 case WMP_typBYTE:
796 if (pDE->uCount <= 4)
797 {
798 U8 pad[4] = {0};
799 Call(pWS->SetPos(pWS, offPos));
800
801 if (NULL == pbData)
802 pbData = (U8*)&pDE->uValueOrOffset;
803
804 Call(pWS->Write(pWS, pbData, pDE->uCount));
805 Call(pWS->Write(pWS, pad, 4 - pDE->uCount)); offPos += 4;
806 }
807 else
808 {
809 Call(PutULong(pWS, offPos, pDE->uValueOrOffset)); offPos += 4;
810
811 // Write the data if requested to do so
812 if (pbData)
813 {
814 Call(pWS->SetPos(pWS, pDE->uValueOrOffset));
815 Call(pWS->Write(pWS, pbData, pDE->uCount));
816 Call(pWS->SetPos(pWS, offPos));
817 *pcbDataWrittenToOffset = pDE->uCount;
818 }
819 }
820 break;
821
822 case WMP_typSHORT:
823 if (pDE->uCount <= 2)
824 {
825 U16 uiShrt1 = 0;
826 U16 uiShrt2 = 0;
827
828 if (NULL == pbData)
829 pbData = (U8*)&pDE->uValueOrOffset;
830
831 if (pDE->uCount > 0)
832 uiShrt1 = *((U16*)pbData);
833
834 if (pDE->uCount > 1)
835 {
836 assert(FALSE); // Untested - remove this assert after this has been tested
837 uiShrt2 = *(U16*)(pbData + 2);
838 }
839
840 Call(PutUShort(pWS, offPos, uiShrt1)); offPos += 2;
841 Call(PutUShort(pWS, offPos, uiShrt2)); offPos += 2;
842 }
843 else
844 {
845 assert(FALSE); // Untested - remove this assert after this has been tested
846 Call(PutULong(pWS, offPos, pDE->uValueOrOffset)); offPos += 4;
847
848 // Write the data if requested to do so
849 if (pbData)
850 {
851 U32 i;
852 Call(pWS->SetPos(pWS, pDE->uValueOrOffset));
853 for (i = 0; i < pDE->uCount; i++)
854 {
855 const U16 uiShort = *(U16*)(pbData + i*sizeof(U16));
856 Call(PutUShort(pWS, offPos, uiShort)); // Write one at a time for endian purposes - but inefficient
857 }
858 Call(pWS->SetPos(pWS, offPos));
859 *pcbDataWrittenToOffset = pDE->uCount * sizeof(U16);
860 }
861
862 }
863 break;
864
865 case WMP_typFLOAT:
866 case WMP_typLONG:
867 if (pDE->uCount <= 1)
868 {
869 if (NULL == pbData)
870 pbData = (U8*)&pDE->uValueOrOffset;
871
872 Call(PutULong(pWS, offPos, *(U32*)pbData)); offPos += 4;
873 }
874 else
875 {
876 assert(FALSE); // Untested - remove this assert after this has been tested
877 Call(PutULong(pWS, offPos, pDE->uValueOrOffset)); offPos += 4;
878
879 // Write the data if requested to do so
880 if (pbData)
881 {
882 U32 i;
883 Call(pWS->SetPos(pWS, pDE->uValueOrOffset));
884 for (i = 0; i < pDE->uCount; i++)
885 {
886 const U32 uLong = *(U32*)(pbData + i*sizeof(U32));
887 Call(PutULong(pWS, offPos, uLong)); // Write one at a time for endian purposes - but inefficient
888 }
889 Call(pWS->SetPos(pWS, offPos));
890 *pcbDataWrittenToOffset = pDE->uCount * sizeof(U32);
891 }
892 }
893 break;
894
895 default:
896 assert(FALSE); // Alert the programmer
897 Call(WMP_errInvalidParameter);
898 break;
899 }
900
901 Cleanup:
902 *pOffPos = offPos;
903 return err;
904 }
905
906