Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/libs/jxr/jxrgluelib/JXRMeta.c
4395 views
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
907