Coverage Report

Created: 2025-06-13 06:50

/src/freeimage-svn/FreeImage/trunk/Source/LibJXR/jxrgluelib/JXRMeta.c
Line
Count
Source (jump to first uncovered line)
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
0
{
40
0
    ERR err = WMP_errSuccess;
41
0
    FailIf(ofs + n > cb, WMP_errBufferOverflow);
42
0
    memcpy(pbdest, &pb[ofs], n);
43
0
Cleanup:
44
0
    return err;
45
0
}
46
47
48
49
ERR getbfw(const U8* pb, size_t cb, size_t ofs, U16* pw)
50
0
{
51
0
    ERR err = WMP_errSuccess;
52
0
    FailIf(ofs + sizeof(U16) > cb, WMP_errBufferOverflow);
53
0
    *pw = (U16)( pb[ofs] + ( pb[ofs + 1] << 8 ) );
54
0
Cleanup:
55
0
    return err;
56
0
}
57
58
59
60
ERR getbfdw(const U8* pb, size_t cb, size_t ofs, U32* pdw)
61
0
{
62
0
    ERR err = WMP_errSuccess;
63
0
    FailIf(ofs + sizeof(U32) > cb, WMP_errBufferOverflow);
64
0
    *pdw = pb[ofs] + ( pb[ofs + 1] << 8 ) + ( pb[ofs + 2] << 16UL ) + ( pb[ofs + 3] << 24UL );
65
0
Cleanup:
66
0
    return err;
67
0
}
68
69
70
71
ERR getbfwbig(const U8* pb, size_t cb, size_t ofs, U16* pw)
72
0
{
73
0
    ERR err = WMP_errSuccess;
74
0
    FailIf(ofs + sizeof(U16) > cb, WMP_errBufferOverflow);
75
0
    *pw = (U16)( pb[ofs + 1] + ( pb[ofs] << 8 ) );
76
0
Cleanup:
77
0
    return err;
78
0
}
79
80
81
82
ERR getbfdwbig(const U8* pb, size_t cb, size_t ofs, U32* pdw)
83
0
{
84
0
    ERR err = WMP_errSuccess;
85
0
    FailIf(ofs + sizeof(U32) > cb, WMP_errBufferOverflow);
86
0
    *pdw = pb[ofs + 3] + ( pb[ofs + 2] << 8 ) + ( pb[ofs + 1] << 16UL ) + ( pb[ofs] << 24UL );
87
0
Cleanup:
88
0
    return err;
89
0
}
90
91
92
93
ERR getbfwe(const U8* pb, size_t cb, size_t ofs, U16* pw, U8 endian)
94
0
{
95
0
    if ( endian == WMP_INTEL_ENDIAN )
96
0
        return ( getbfw(pb, cb, ofs, pw) );
97
0
    else
98
0
        return ( getbfwbig(pb, cb, ofs, pw) );
99
0
}
100
101
102
103
ERR getbfdwe(const U8* pb, size_t cb, size_t ofs, U32* pdw, U8 endian)
104
0
{
105
0
    if ( endian == WMP_INTEL_ENDIAN )
106
0
        return ( getbfdw(pb, cb, ofs, pdw) );
107
0
    else
108
0
        return ( getbfdwbig(pb, cb, ofs, pdw) );
109
0
}
110
111
112
113
ERR setbfcpy(U8* pb, size_t cb, size_t ofs, const U8* pbset, size_t cbset)
114
0
{
115
0
    ERR err = WMP_errSuccess;
116
0
    FailIf(ofs + cbset > cb, WMP_errBufferOverflow);
117
0
    memcpy(&pb[ofs], pbset, cbset);
118
0
Cleanup:
119
0
    return err;
120
0
}
121
122
123
124
ERR setbfw(U8* pb, size_t cb, size_t ofs, U16 dw)
125
0
{
126
0
    ERR err = WMP_errSuccess;
127
0
    FailIf(ofs + sizeof(U16) > cb, WMP_errBufferOverflow);
128
0
    pb[ofs] = (U8)dw;
129
0
    pb[ofs + 1] = (U8)( dw >> 8 );
130
0
Cleanup:
131
0
    return err;
132
0
}
133
134
135
136
ERR setbfdw(U8* pb, size_t cb, size_t ofs, U32 dw)
137
0
{
138
0
    ERR err = WMP_errSuccess;
139
0
    FailIf(ofs + sizeof(U32) > cb, WMP_errBufferOverflow);
140
0
    pb[ofs] = (U8)dw;
141
0
    pb[ofs + 1] = (U8)( dw >> 8 );
142
0
    pb[ofs + 2] = (U8)( dw >> 16 );
143
0
    pb[ofs + 3] = (U8)( dw >> 24 );
144
0
Cleanup:
145
0
    return err;
146
0
}
147
148
149
150
ERR setbfwbig(U8* pb, size_t cb, size_t ofs, U16 dw)
151
0
{
152
0
    ERR err = WMP_errSuccess;
153
0
    FailIf(ofs + sizeof(U16) > cb, WMP_errBufferOverflow);
154
0
    pb[ofs + 1] = (U8)dw;
155
0
    pb[ofs] = (U8)( dw >> 8 );
156
0
Cleanup:
157
0
    return err;
158
0
}
159
160
161
162
ERR setbfdwbig(U8* pb, size_t cb, size_t ofs, U32 dw)
163
0
{
164
0
    ERR err = WMP_errSuccess;
165
0
    FailIf(ofs + sizeof(U32) > cb, WMP_errBufferOverflow);
166
0
    pb[ofs + 3] = (U8)dw;
167
0
    pb[ofs + 2] = (U8)( dw >> 8 );
168
0
    pb[ofs + 1] = (U8)( dw >> 16 );
169
0
    pb[ofs] = (U8)( dw >> 24 );
170
0
Cleanup:
171
0
    return err;
172
0
}
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
0
{
188
0
    ERR err = WMP_errSuccess;
189
0
    U16 cDir;
190
0
    U16 i;
191
0
    U32 ofsdir;
192
0
    U32 cbifd = 0;
193
0
    U32 cbEXIFIFD = 0;
194
0
    U32 cbGPSInfoIFD = 0;
195
0
    U32 cbInteroperabilityIFD = 0;
196
197
0
    *pcbifd = 0;
198
0
    Call(getbfwe(pbdata, cbdata, ofsifd, &cDir, endian));
199
200
0
    cbifd = sizeof(U16) + cDir * SizeofIFDEntry + sizeof(U32);
201
0
    ofsdir = ofsifd + sizeof(U16);
202
0
    for ( i = 0; i < cDir; i++ )
203
0
    {
204
0
        U16 tag = 0;
205
0
        U16 type = 0;
206
0
        U32 count = 0;
207
0
        U32 value = 0;
208
0
        U32 datasize = 0;
209
210
0
        Call(getbfwe(pbdata, cbdata, ofsdir, &tag, endian));
211
0
        Call(getbfwe(pbdata, cbdata, ofsdir + sizeof(U16), &type, endian));
212
0
        Call(getbfdwe(pbdata, cbdata, ofsdir + 2 * sizeof(U16), &count, endian));
213
0
        Call(getbfdwe(pbdata, cbdata, ofsdir + 2 * sizeof(U16) + sizeof(U32), &value, endian));
214
0
        FailIf(type == 0 || type >= sizeof(IFDEntryTypeSizes) / sizeof(IFDEntryTypeSizes[0]), WMP_errFail);
215
0
        if ( tag == WMP_tagEXIFMetadata )
216
0
        {
217
0
            Call(BufferCalcIFDSize(pbdata, cbdata, value, endian, &cbEXIFIFD));
218
0
        }
219
0
        else if ( tag == WMP_tagGPSInfoMetadata )
220
0
        {
221
0
            Call(BufferCalcIFDSize(pbdata, cbdata, value, endian, &cbGPSInfoIFD));
222
0
        }
223
0
        else if ( tag == WMP_tagInteroperabilityIFD )
224
0
        {
225
0
            Call(BufferCalcIFDSize(pbdata, cbdata, value, endian, &cbInteroperabilityIFD));
226
0
        }
227
0
        else
228
0
        {
229
0
            datasize = IFDEntryTypeSizes[type] * count;
230
0
            if ( datasize > 4 )
231
0
                cbifd += datasize;
232
0
        }
233
0
        ofsdir += SizeofIFDEntry;
234
0
    }
235
0
    if ( cbEXIFIFD != 0 )
236
0
        cbifd += ( cbifd & 1 ) + cbEXIFIFD;
237
0
    if ( cbGPSInfoIFD != 0 )
238
0
        cbifd += ( cbifd & 1 ) + cbGPSInfoIFD;
239
0
    if ( cbInteroperabilityIFD != 0 )
240
0
        cbifd += ( cbifd & 1 ) + cbInteroperabilityIFD;
241
242
0
    *pcbifd = cbifd;
243
244
0
Cleanup:
245
0
    return err;
246
0
}
247
248
249
ERR StreamCalcIFDSize(struct WMPStream* pWS, U32 uIFDOfs, U32 *pcbifd)
250
0
{
251
0
    ERR err = WMP_errSuccess;
252
0
    size_t offCurPos = 0;
253
0
    Bool GetPosOK = FALSE;
254
0
    U16 cDir;
255
0
    U32 i;
256
0
    U32 ofsdir;
257
0
    U32 cbifd = 0;
258
0
    U32 cbEXIFIFD = 0;
259
0
    U32 cbGPSInfoIFD = 0;
260
0
    U32 cbInteroperabilityIFD = 0;
261
262
0
    *pcbifd = 0;
263
0
    Call(pWS->GetPos(pWS, &offCurPos));
264
0
    GetPosOK = TRUE;
265
266
0
    Call(GetUShort(pWS, uIFDOfs, &cDir));
267
0
    cbifd = sizeof(U16) + cDir * SizeofIFDEntry + sizeof(U32);
268
0
    ofsdir = uIFDOfs + sizeof(U16);
269
0
    for ( i = 0; i < cDir; i++ )
270
0
    {
271
0
        U16 tag = 0;
272
0
        U16 type = 0;
273
0
        U32 count = 0;
274
0
        U32 value = 0;
275
0
        U32 datasize = 0;
276
277
0
        Call(GetUShort(pWS, ofsdir, &tag));
278
0
        Call(GetUShort(pWS, ofsdir + sizeof(U16), &type));
279
0
        Call(GetULong(pWS, ofsdir + 2 * sizeof(U16), &count));
280
0
        Call(GetULong(pWS, ofsdir + 2 * sizeof(U16) + sizeof(U32), &value));
281
0
        FailIf(type == 0 || type >= sizeof(IFDEntryTypeSizes) / sizeof(IFDEntryTypeSizes[0]), WMP_errUnsupportedFormat);
282
0
        if ( tag == WMP_tagEXIFMetadata )
283
0
        {
284
0
            Call(StreamCalcIFDSize(pWS, value, &cbEXIFIFD));
285
0
        }
286
0
        else if ( tag == WMP_tagGPSInfoMetadata )
287
0
        {
288
0
            Call(StreamCalcIFDSize(pWS, value, &cbGPSInfoIFD));
289
0
        }
290
0
        else if ( tag == WMP_tagInteroperabilityIFD )
291
0
        {
292
0
            Call(StreamCalcIFDSize(pWS, value, &cbInteroperabilityIFD));
293
0
        }
294
0
        else
295
0
        {
296
0
            datasize = IFDEntryTypeSizes[type] * count;
297
0
            if ( datasize > 4 )
298
0
                cbifd += datasize;
299
0
        }
300
0
        ofsdir += SizeofIFDEntry;
301
0
    }
302
0
    if ( cbEXIFIFD != 0 )
303
0
        cbifd += ( cbifd & 1 ) + cbEXIFIFD;
304
0
    if ( cbGPSInfoIFD != 0 )
305
0
        cbifd += ( cbifd & 1 ) + cbGPSInfoIFD;
306
0
    if ( cbInteroperabilityIFD != 0 )
307
0
        cbifd += ( cbifd & 1 ) + cbInteroperabilityIFD;
308
0
    *pcbifd = cbifd;
309
310
0
Cleanup:
311
0
    if ( GetPosOK )
312
0
        Call(pWS->SetPos(pWS, offCurPos));
313
0
    return ( err );
314
0
}
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
0
{
324
0
    ERR err = WMP_errSuccess;
325
0
    U16 cDir;
326
0
    U16 i;
327
0
    U16 ofsEXIFIFDEntry = 0;
328
0
    U16 ofsGPSInfoIFDEntry = 0;
329
0
    U16 ofsInteroperabilityIFDEntry = 0;
330
0
    U32 ofsEXIFIFD = 0;
331
0
    U32 ofsGPSInfoIFD = 0;
332
0
    U32 ofsInteroperabilityIFD = 0;
333
0
    U32 ofsdstnextdata;
334
0
    U32 ofsdst = *pofsdst;
335
0
    U32 ofssrcdir;
336
0
    U32 ofsdstdir;
337
0
    U32 ofsnextifd;
338
339
0
    Call(getbfwe(pbsrc, cbsrc, ofssrc, &cDir, endian));
340
0
    Call(setbfw(pbdst, cbdst, ofsdst, cDir));
341
0
    ofsnextifd = ofsdst + sizeof(U16) + SizeofIFDEntry * cDir;
342
0
    ofsdstnextdata = ofsnextifd + sizeof(U32);
343
344
0
    ofssrcdir = ofssrc + sizeof(U16);
345
0
    ofsdstdir = ofsdst + sizeof(U16);
346
0
    for ( i = 0; i < cDir; i++ )
347
0
    {
348
0
        U16 tag = 0;
349
0
        U16 type = 0;
350
0
        U32 count = 0;
351
0
        U32 value = 0;
352
0
        U32 size = 0;
353
354
0
        Call(getbfwe(pbsrc, cbsrc, ofssrcdir, &tag, endian));
355
0
        Call(setbfw(pbdst, cbdst, ofsdstdir, tag));
356
357
0
        Call(getbfwe(pbsrc, cbsrc, ofssrcdir + sizeof(U16), &type, endian));
358
0
        Call(setbfw(pbdst, cbdst, ofsdstdir + sizeof(U16), type));
359
360
0
        Call(getbfdwe(pbsrc, cbsrc, ofssrcdir + 2 * sizeof(U16), &count, endian));
361
0
        Call(setbfdw(pbdst, cbdst, ofsdstdir + 2 * sizeof(U16), count));
362
363
0
        Call(getbfdwe(pbsrc, cbsrc, ofssrcdir + 2 * sizeof(U16) + sizeof(U32), &value, endian));
364
0
        Call(setbfdw(pbdst, cbdst, ofsdstdir + 2 * sizeof(U16) + sizeof(U32), 0));
365
366
0
        FailIf(type == 0 || type >= sizeof(IFDEntryTypeSizes) / sizeof(IFDEntryTypeSizes[0]), WMP_errFail);
367
0
        if ( tag == WMP_tagEXIFMetadata )
368
0
        {
369
0
            ofsEXIFIFDEntry = (U16) ofsdstdir;
370
0
            ofsEXIFIFD = value;
371
0
        }
372
0
        else if ( tag == WMP_tagGPSInfoMetadata )
373
0
        {
374
0
            ofsGPSInfoIFDEntry = (U16) ofsdstdir;
375
0
            ofsGPSInfoIFD = value;
376
0
        }
377
0
        else if ( tag == WMP_tagInteroperabilityIFD )
378
0
        {
379
0
            ofsInteroperabilityIFDEntry = (U16) ofsdstdir;
380
0
            ofsInteroperabilityIFD = value;
381
0
        }
382
0
        else
383
0
        {
384
0
            U32 ofsdstdata = ofsdstdir + 2 * sizeof(U16) + sizeof(U32);
385
0
            U32 ofssrcdata = ofssrcdir + 2 * sizeof(U16) + sizeof(U32);
386
0
            size = count * IFDEntryTypeSizes[type];
387
0
            if ( size > 4 )
388
0
            {
389
0
                ofssrcdata = value;
390
0
                Call(setbfdw(pbdst, cbdst, ofsdstdata, ofsdstnextdata));
391
0
                ofsdstdata = ofsdstnextdata;
392
0
                ofsdstnextdata += size;
393
0
            }
394
0
            FailIf(ofssrcdata + size > cbsrc || ofsdstdata + size > cbdst, WMP_errBufferOverflow);
395
0
            if ( size == count || endian == WMP_INTEL_ENDIAN )
396
                // size == count means 8-bit data means endian doesn't matter
397
0
                memcpy(&pbdst[ofsdstdata], &pbsrc[ofssrcdata], size);
398
0
            else
399
0
            {   // big endian source and endian matters
400
0
                U32 j;
401
402
0
                switch ( IFDEntryTypeSizes[type] )
403
0
                {
404
0
                case 2:
405
0
                    for ( j = 0; j < count; j++ )
406
0
                    {
407
0
                        U16 w;
408
0
                        getbfwbig(pbsrc, cbsrc, ofssrcdata + j * sizeof(U16), &w);
409
0
                        setbfw(pbdst, cbdst, ofsdstdata + j * sizeof(U16), w);
410
0
                    }
411
0
                    break;
412
0
                case 8:
413
0
                    if ( type == WMP_typDOUBLE )
414
0
                    {
415
0
                        for ( j = 0; j < count; j++ )
416
0
                        {
417
0
                            U32 dwlo;
418
0
                            U32 dwhi;
419
0
                            getbfdwbig(pbsrc, cbsrc, ofssrcdata + j * 8, &dwhi);
420
0
                            getbfdwbig(pbsrc, cbsrc, ofssrcdata + j * 8 + sizeof(U32), &dwlo);
421
0
                            setbfdw(pbdst, cbdst, ofsdstdata + j * 8, dwlo);
422
0
                            setbfdw(pbdst, cbdst, ofsdstdata + j * 8 + sizeof(U32), dwhi);
423
0
                        }
424
0
                        break;
425
0
                    }
426
0
                    count *= 2;
427
                    // RATIONAL's fall through to be handled as LONG's
428
0
                case 4:
429
0
                    for ( j = 0; j < count; j++ )
430
0
                    {
431
0
                        U32 dw;
432
0
                        getbfdwbig(pbsrc, cbsrc, ofssrcdata + j * sizeof(U32), &dw);
433
0
                        setbfdw(pbdst, cbdst, ofsdstdata + j * sizeof(U32), dw);
434
0
                    }
435
0
                    break;
436
0
                }
437
0
            }
438
0
        }
439
0
        ofssrcdir += SizeofIFDEntry;
440
0
        ofsdstdir += SizeofIFDEntry;
441
0
    }
442
0
    Call(setbfdw(pbdst, cbdst, ofsnextifd, 0));    // no nextIFD
443
444
0
    if ( ofsEXIFIFDEntry != 0 )
445
0
    {
446
0
        ofsdstnextdata += ( ofsdstnextdata & 1 );
447
0
        Call(setbfdw(pbdst, cbdst, ofsEXIFIFDEntry + 2 * sizeof(U16) + sizeof(U32), ofsdstnextdata));
448
0
        Call(BufferCopyIFD(pbsrc, cbsrc, ofsEXIFIFD, endian, pbdst, cbdst, &ofsdstnextdata));
449
0
    }
450
0
    if ( ofsGPSInfoIFDEntry != 0 )
451
0
    {
452
0
        ofsdstnextdata += ( ofsdstnextdata & 1 );
453
0
        Call(setbfdw(pbdst, cbdst, ofsGPSInfoIFDEntry + 2 * sizeof(U16) + sizeof(U32), ofsdstnextdata));
454
0
        Call(BufferCopyIFD(pbsrc, cbsrc, ofsGPSInfoIFD, endian, pbdst, cbdst, &ofsdstnextdata));
455
0
    }
456
0
    if ( ofsInteroperabilityIFDEntry != 0 )
457
0
    {
458
0
        ofsdstnextdata += ( ofsdstnextdata & 1 );
459
0
        Call(setbfdw(pbdst, cbdst, ofsInteroperabilityIFDEntry + 2 * sizeof(U16) + sizeof(U32), ofsdstnextdata));
460
0
        Call(BufferCopyIFD(pbsrc, cbsrc, ofsInteroperabilityIFD, endian, pbdst, cbdst, &ofsdstnextdata));
461
0
    }
462
0
    *pofsdst = ofsdstnextdata;
463
464
0
Cleanup:
465
0
    return err;
466
0
}
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
0
{
476
0
    ERR err = WMP_errSuccess;
477
0
    size_t offCurPos = 0;
478
0
    Bool GetPosOK = FALSE;
479
0
    U16 cDir;
480
0
    U16 i;
481
0
    U16 ofsEXIFIFDEntry = 0;
482
0
    U16 ofsGPSInfoIFDEntry = 0;
483
0
    U16 ofsInteroperabilityIFDEntry = 0;
484
0
    U32 ofsEXIFIFD = 0;
485
0
    U32 ofsGPSInfoIFD = 0;
486
0
    U32 ofsInteroperabilityIFD = 0;
487
0
    U32 ofsdstnextdata;
488
0
    U32 ofsdst = *pofsdst;
489
0
    U32 ofssrcdir;
490
0
    U32 ofsdstdir;
491
0
    U32 ofsnextifd;
492
493
0
    Call(pWS->GetPos(pWS, &offCurPos));
494
0
    GetPosOK = TRUE;
495
496
0
    Call(GetUShort(pWS, ofssrc, &cDir));
497
0
    Call(setbfw(pbdst, cbdst, ofsdst, cDir));
498
499
0
    ofsnextifd = ofsdst + sizeof(U16) + SizeofIFDEntry * cDir;
500
0
    ofsdstnextdata = ofsnextifd + sizeof(U32);
501
502
0
    ofssrcdir = ofssrc + sizeof(U16);
503
0
    ofsdstdir = ofsdst + sizeof(U16);
504
0
    for ( i = 0; i < cDir; i++ )
505
0
    {
506
0
        U16 tag = 0;
507
0
        U16 type = 0;
508
0
        U32 count = 0;
509
0
        U32 value = 0;
510
0
        U32 size = 0;
511
512
0
        Call(GetUShort(pWS, ofssrcdir, &tag));
513
0
        Call(setbfw(pbdst, cbdst, ofsdstdir, tag));
514
515
0
        Call(GetUShort(pWS, ofssrcdir + sizeof(U16), &type));
516
0
        Call(setbfw(pbdst, cbdst, ofsdstdir + sizeof(U16), type));
517
518
0
        Call(GetULong(pWS, ofssrcdir + 2 * sizeof(U16), &count));
519
0
        Call(setbfdw(pbdst, cbdst, ofsdstdir + 2 * sizeof(U16), count));
520
521
0
        Call(GetULong(pWS, ofssrcdir + 2 * sizeof(U16) + sizeof(U32), &value));
522
0
        Call(setbfdw(pbdst, cbdst, ofsdstdir + 2 * sizeof(U16) + sizeof(U32), 0));
523
524
0
        FailIf(type == 0 || type >= sizeof(IFDEntryTypeSizes) / sizeof(IFDEntryTypeSizes[0]), WMP_errFail);
525
0
        if ( tag == WMP_tagEXIFMetadata )
526
0
        {
527
0
            ofsEXIFIFDEntry = (U16) ofsdstdir;
528
0
            ofsEXIFIFD = value;
529
0
        }
530
0
        else if ( tag == WMP_tagGPSInfoMetadata )
531
0
        {
532
0
            ofsGPSInfoIFDEntry = (U16) ofsdstdir;
533
0
            ofsGPSInfoIFD = value;
534
0
        }
535
0
        else if ( tag == WMP_tagInteroperabilityIFD )
536
0
        {
537
0
            ofsInteroperabilityIFDEntry = (U16) ofsdstdir;
538
0
            ofsInteroperabilityIFD = value;
539
0
        }
540
0
        else
541
0
        {
542
0
            U32 ofsdstdata = ofsdstdir + 2 * sizeof(U16) + sizeof(U32);
543
0
            U32 ofssrcdata = ofssrcdir + 2 * sizeof(U16) + sizeof(U32);
544
0
            size = count * IFDEntryTypeSizes[type];
545
0
            if ( size > 4 )
546
0
            {
547
0
                ofssrcdata = value;
548
0
                Call(setbfdw(pbdst, cbdst, ofsdstdata, ofsdstnextdata));
549
0
                ofsdstdata = ofsdstnextdata;
550
0
                ofsdstnextdata += size;
551
0
            }
552
0
            FailIf(ofsdstdata + size > cbdst, WMP_errBufferOverflow);
553
0
            Call(pWS->SetPos(pWS, ofssrcdata));
554
0
            Call(pWS->Read(pWS, &pbdst[ofsdstdata], size));
555
0
        }
556
0
        ofssrcdir += SizeofIFDEntry;
557
0
        ofsdstdir += SizeofIFDEntry;
558
0
    }
559
0
    Call(setbfdw(pbdst, cbdst, ofsnextifd, 0));    // no nextIFD
560
561
0
    if ( ofsEXIFIFDEntry != 0 )
562
0
    {
563
0
        ofsdstnextdata += ( ofsdstnextdata & 1 );
564
0
        Call(setbfdw(pbdst, cbdst, ofsEXIFIFDEntry + 2 * sizeof(U16) + sizeof(U32), ofsdstnextdata));
565
0
        Call(StreamCopyIFD(pWS, ofsEXIFIFD, pbdst, cbdst, &ofsdstnextdata));
566
0
    }
567
0
    if ( ofsGPSInfoIFDEntry != 0 )
568
0
    {
569
0
        ofsdstnextdata += ( ofsdstnextdata & 1 );
570
0
        Call(setbfdw(pbdst, cbdst, ofsGPSInfoIFDEntry + 2 * sizeof(U16) + sizeof(U32), ofsdstnextdata));
571
0
        Call(StreamCopyIFD(pWS, ofsGPSInfoIFD, pbdst, cbdst, &ofsdstnextdata));
572
0
    }
573
0
    if ( ofsInteroperabilityIFDEntry != 0 )
574
0
    {
575
0
        ofsdstnextdata += ( ofsdstnextdata & 1 );
576
0
        Call(setbfdw(pbdst, cbdst, ofsInteroperabilityIFDEntry + 2 * sizeof(U16) + sizeof(U32), ofsdstnextdata));
577
0
        Call(StreamCopyIFD(pWS, ofsInteroperabilityIFD, pbdst, cbdst, &ofsdstnextdata));
578
0
    }
579
0
    *pofsdst = ofsdstnextdata;
580
581
0
Cleanup:
582
0
    if ( GetPosOK )
583
0
        Call(pWS->SetPos(pWS, offCurPos));
584
0
    return err;
585
0
}
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
0
{
595
0
    ERR err = WMP_errSuccess;
596
0
    U8  cVal;
597
598
0
    Call(pWS->SetPos(pWS, offPos));
599
0
    Call(pWS->Read(pWS, &cVal, sizeof(cVal)));
600
0
    puValue[0] = (U16) cVal;
601
0
    Call(pWS->Read(pWS, &cVal, sizeof(cVal)));
602
0
    puValue[0] += ((U16) cVal) << 8;
603
604
0
Cleanup:
605
0
    return err;
606
0
}
607
608
ERR PutUShort(
609
    __in_ecount(1) struct WMPStream* pWS,
610
    size_t offPos,
611
    U16 uValue)
612
0
{
613
0
    ERR err = WMP_errSuccess;
614
0
    U8  cVal = (U8) uValue;
615
616
0
    Call(pWS->SetPos(pWS, offPos));
617
0
    Call(pWS->Write(pWS, &cVal, sizeof(cVal)));
618
0
    cVal = (U8) (uValue >> 8);
619
0
    Call(pWS->Write(pWS, &cVal, sizeof(cVal)));
620
621
0
Cleanup:
622
0
    return err;
623
0
}
624
625
ERR GetULong(
626
    __in_ecount(1) struct WMPStream* pWS,
627
    size_t offPos,
628
    __out_ecount(1) U32* puValue)
629
0
{
630
0
    ERR err = WMP_errSuccess;
631
0
    U8  cVal = 0;
632
633
0
    Call(pWS->SetPos(pWS, offPos));
634
0
    Call(pWS->Read(pWS, &cVal, sizeof(cVal)));
635
0
    puValue[0] = (U32) cVal;
636
0
    Call(pWS->Read(pWS, &cVal, sizeof(cVal)));
637
0
    puValue[0] += ((U32) cVal) << 8;
638
0
    Call(pWS->Read(pWS, &cVal, sizeof(cVal)));
639
0
    puValue[0] += ((U32) cVal) << 16;
640
0
    Call(pWS->Read(pWS, &cVal, sizeof(cVal)));
641
0
    puValue[0] += ((U32) cVal) << 24;
642
 
643
0
Cleanup:
644
0
    return err;
645
0
}
646
647
ERR PutULong(
648
    __in_ecount(1) struct WMPStream* pWS,
649
    size_t offPos,
650
    U32 uValue)
651
0
{
652
0
    ERR err = WMP_errSuccess;
653
0
    U8  cVal = (U8) uValue;
654
655
0
    Call(pWS->SetPos(pWS, offPos));
656
0
    Call(pWS->Write(pWS, &cVal, sizeof(cVal)));
657
0
    cVal = (U8) (uValue >> 8);
658
0
    Call(pWS->Write(pWS, &cVal, sizeof(cVal)));
659
0
    cVal = (U8) (uValue >> 16);
660
0
    Call(pWS->Write(pWS, &cVal, sizeof(cVal)));
661
0
    cVal = (U8) (uValue >> 24);
662
0
    Call(pWS->Write(pWS, &cVal, sizeof(cVal)));
663
664
0
Cleanup:
665
0
    return err;
666
0
}
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
0
{
674
0
    ERR err = WMP_errSuccess;
675
0
    U8 *pbData = NULL;
676
677
0
    Call(PKAlloc((void **) &pbData, uCount + 2)); // Allocate buffer to store data with space for an added ascii or unicode null
678
0
    if (uCount <= 4)
679
0
    {
680
0
        unsigned int i;
681
0
        for (i = 0; i < uCount; i++)
682
0
            pbData[i] = ((U8*)&uValue)[i]; // Copy least sig bytes - we assume 'II' type TIFF files
683
0
    }
684
0
    else
685
0
    {
686
0
        size_t offPosPrev = 0;
687
688
0
        Call(pWS->GetPos(pWS, &offPosPrev));
689
0
        Call(pWS->SetPos(pWS, uValue));
690
0
        Call(pWS->Read(pWS, pbData, uCount));
691
0
        Call(pWS->SetPos(pWS, offPosPrev));
692
0
    }
693
694
0
    *ppbData = pbData;
695
696
0
Cleanup:
697
0
    if (Failed(err))
698
0
    {
699
0
        if (pbData)
700
0
            PKFree((void **) &pbData);
701
0
    }
702
0
    return err;
703
0
}
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
0
{
712
0
    ERR err = WMP_errSuccess;
713
    // U8 *pbData = NULL;
714
715
0
    memset(pvar, 0, sizeof(*pvar));
716
0
    if (uCount == 0)
717
0
        goto Cleanup; // Nothing to read in here
718
719
0
    switch (uType)
720
0
    {
721
0
        case WMP_typASCII:
722
0
            pvar->vt = DPKVT_LPSTR;
723
0
            Call(ReadBinaryData(pWS, uCount, uValue, (U8 **) &pvar->VT.pszVal));
724
0
            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
0
            pvar->VT.pszVal[uCount] = 0;
727
0
            break;
728
729
0
        case WMP_typBYTE:
730
0
        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
0
            pvar->vt = (DPKVT_BYREF | DPKVT_UI1);
735
0
            Call(ReadBinaryData(pWS, uCount, uValue, &pvar->VT.pbVal));
736
0
            break;
737
738
0
        case WMP_typSHORT:
739
0
            if (1 == uCount)
740
0
            {
741
0
                pvar->vt = DPKVT_UI2;
742
0
                pvar->VT.uiVal = (U16)(uValue & 0x0000FFFF);
743
0
            }
744
0
            else if (2 == uCount)
745
0
            {
746
0
                pvar->vt = DPKVT_UI4;
747
0
                pvar->VT.ulVal = uValue;
748
0
            }
749
0
            else
750
0
            {
751
0
                assert(FALSE); // NYI
752
0
                FailIf(TRUE, WMP_errNotYetImplemented);
753
0
            }
754
0
            break;
755
756
0
        default:
757
0
            assert(FALSE); // Unhandled type
758
0
            FailIf(TRUE, WMP_errNotYetImplemented);
759
0
            break;
760
0
    }
761
762
0
Cleanup:
763
0
    return err;
764
0
}
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
0
{
774
0
    ERR err = WMP_errSuccess;
775
0
    size_t offPos = *pOffPos;
776
777
0
    assert(-1 != pDE->uCount);
778
0
    assert(-1 != pDE->uValueOrOffset);
779
780
0
    if (pcbDataWrittenToOffset)
781
0
    {
782
0
        assert(pbData); // Makes no sense to provide this arg without pbData
783
0
        *pcbDataWrittenToOffset = 0;
784
0
    }
785
786
0
    Call(PutUShort(pWS, offPos, pDE->uTag)); offPos += 2;
787
0
    Call(PutUShort(pWS, offPos, pDE->uType)); offPos += 2;
788
0
    Call(PutULong(pWS, offPos, pDE->uCount)); offPos += 4;
789
790
0
    switch (pDE->uType)
791
0
    {
792
793
0
        case WMP_typASCII:
794
0
        case WMP_typUNDEFINED:
795
0
        case WMP_typBYTE:
796
0
            if (pDE->uCount <= 4)
797
0
            {
798
0
                U8 pad[4] = {0};
799
0
                Call(pWS->SetPos(pWS, offPos));
800
801
0
                if (NULL == pbData)
802
0
                    pbData = (U8*)&pDE->uValueOrOffset;
803
804
0
                Call(pWS->Write(pWS, pbData, pDE->uCount));
805
0
                Call(pWS->Write(pWS, pad, 4 - pDE->uCount)); offPos += 4;
806
0
            }
807
0
            else
808
0
            {
809
0
                Call(PutULong(pWS, offPos, pDE->uValueOrOffset)); offPos += 4;
810
811
                // Write the data if requested to do so
812
0
                if (pbData)
813
0
                {
814
0
                    Call(pWS->SetPos(pWS, pDE->uValueOrOffset));
815
0
                    Call(pWS->Write(pWS, pbData, pDE->uCount));
816
0
                    Call(pWS->SetPos(pWS, offPos));
817
0
                    *pcbDataWrittenToOffset = pDE->uCount;
818
0
                }
819
0
            }
820
0
            break;
821
822
0
        case WMP_typSHORT:
823
0
            if (pDE->uCount <= 2)
824
0
            {
825
0
                U16 uiShrt1 = 0;
826
0
                U16 uiShrt2 = 0;
827
828
0
                if (NULL == pbData)
829
0
                    pbData = (U8*)&pDE->uValueOrOffset;
830
831
0
                if (pDE->uCount > 0)
832
0
                    uiShrt1 = *((U16*)pbData);
833
834
0
                if (pDE->uCount > 1)
835
0
                {
836
0
                    assert(FALSE); // Untested - remove this assert after this has been tested
837
0
                    uiShrt2 = *(U16*)(pbData + 2);
838
0
                }
839
840
0
                Call(PutUShort(pWS, offPos, uiShrt1)); offPos += 2;
841
0
                Call(PutUShort(pWS, offPos, uiShrt2)); offPos += 2;
842
0
            }
843
0
            else
844
0
            {
845
0
                assert(FALSE); // Untested - remove this assert after this has been tested
846
0
                Call(PutULong(pWS, offPos, pDE->uValueOrOffset)); offPos += 4;
847
848
                // Write the data if requested to do so
849
0
                if (pbData)
850
0
                {
851
0
                    U32 i;
852
0
                    Call(pWS->SetPos(pWS, pDE->uValueOrOffset));
853
0
                    for (i = 0; i < pDE->uCount; i++)
854
0
                    {
855
0
                        const U16 uiShort = *(U16*)(pbData + i*sizeof(U16));
856
0
                        Call(PutUShort(pWS, offPos, uiShort)); // Write one at a time for endian purposes - but inefficient
857
0
                    }
858
0
                    Call(pWS->SetPos(pWS, offPos));
859
0
                    *pcbDataWrittenToOffset = pDE->uCount * sizeof(U16);
860
0
                }
861
862
0
            }
863
0
            break;
864
865
0
        case WMP_typFLOAT:
866
0
        case WMP_typLONG:
867
0
            if (pDE->uCount <= 1)
868
0
            {
869
0
                if (NULL == pbData)
870
0
                    pbData = (U8*)&pDE->uValueOrOffset;
871
872
0
                Call(PutULong(pWS, offPos, *(U32*)pbData)); offPos += 4;
873
0
            }
874
0
            else
875
0
            {
876
0
                assert(FALSE); // Untested - remove this assert after this has been tested
877
0
                Call(PutULong(pWS, offPos, pDE->uValueOrOffset)); offPos += 4;
878
879
                // Write the data if requested to do so
880
0
                if (pbData)
881
0
                {
882
0
                    U32 i;
883
0
                    Call(pWS->SetPos(pWS, pDE->uValueOrOffset));
884
0
                    for (i = 0; i < pDE->uCount; i++)
885
0
                    {
886
0
                        const U32 uLong = *(U32*)(pbData + i*sizeof(U32));
887
0
                        Call(PutULong(pWS, offPos, uLong)); // Write one at a time for endian purposes - but inefficient
888
0
                    }
889
0
                    Call(pWS->SetPos(pWS, offPos));
890
0
                    *pcbDataWrittenToOffset = pDE->uCount * sizeof(U32);
891
0
                }
892
0
            }
893
0
            break;
894
895
0
        default:
896
0
            assert(FALSE); // Alert the programmer
897
0
            Call(WMP_errInvalidParameter);
898
0
            break;
899
0
    }
900
901
0
Cleanup:
902
0
    *pOffPos = offPos;
903
0
    return err;
904
0
}
905