github.com/cellofellow/gopkg@v0.0.0-20140722061823-eec0544a62ad/image/jxr/jxrlib/jxrgluelib/JXRMeta.c (about) 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