JXRMeta.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905
  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. // read and write big and little endian words/dwords from a buffer on both big and little endian cpu's
  31. // with full buffer overflow checking
  32. ERR getbfcpy(U8* pbdest, const U8* pb, size_t cb, size_t ofs, U32 n)
  33. {
  34. ERR err = WMP_errSuccess;
  35. FailIf(ofs + n > cb, WMP_errBufferOverflow);
  36. memcpy(pbdest, &pb[ofs], n);
  37. Cleanup:
  38. return err;
  39. }
  40. ERR getbfw(const U8* pb, size_t cb, size_t ofs, U16* pw)
  41. {
  42. ERR err = WMP_errSuccess;
  43. FailIf(ofs + sizeof(U16) > cb, WMP_errBufferOverflow);
  44. *pw = (U16)( pb[ofs] + ( pb[ofs + 1] << 8 ) );
  45. Cleanup:
  46. return err;
  47. }
  48. ERR getbfdw(const U8* pb, size_t cb, size_t ofs, U32* pdw)
  49. {
  50. ERR err = WMP_errSuccess;
  51. FailIf(ofs + sizeof(U32) > cb, WMP_errBufferOverflow);
  52. *pdw = pb[ofs] + ( pb[ofs + 1] << 8 ) + ( pb[ofs + 2] << 16UL ) + ( pb[ofs + 3] << 24UL );
  53. Cleanup:
  54. return err;
  55. }
  56. ERR getbfwbig(const U8* pb, size_t cb, size_t ofs, U16* pw)
  57. {
  58. ERR err = WMP_errSuccess;
  59. FailIf(ofs + sizeof(U16) > cb, WMP_errBufferOverflow);
  60. *pw = (U16)( pb[ofs + 1] + ( pb[ofs] << 8 ) );
  61. Cleanup:
  62. return err;
  63. }
  64. ERR getbfdwbig(const U8* pb, size_t cb, size_t ofs, U32* pdw)
  65. {
  66. ERR err = WMP_errSuccess;
  67. FailIf(ofs + sizeof(U32) > cb, WMP_errBufferOverflow);
  68. *pdw = pb[ofs + 3] + ( pb[ofs + 2] << 8 ) + ( pb[ofs + 1] << 16UL ) + ( pb[ofs] << 24UL );
  69. Cleanup:
  70. return err;
  71. }
  72. ERR getbfwe(const U8* pb, size_t cb, size_t ofs, U16* pw, U8 endian)
  73. {
  74. if ( endian == WMP_INTEL_ENDIAN )
  75. return ( getbfw(pb, cb, ofs, pw) );
  76. else
  77. return ( getbfwbig(pb, cb, ofs, pw) );
  78. }
  79. ERR getbfdwe(const U8* pb, size_t cb, size_t ofs, U32* pdw, U8 endian)
  80. {
  81. if ( endian == WMP_INTEL_ENDIAN )
  82. return ( getbfdw(pb, cb, ofs, pdw) );
  83. else
  84. return ( getbfdwbig(pb, cb, ofs, pdw) );
  85. }
  86. ERR setbfcpy(U8* pb, size_t cb, size_t ofs, const U8* pbset, size_t cbset)
  87. {
  88. ERR err = WMP_errSuccess;
  89. FailIf(ofs + cbset > cb, WMP_errBufferOverflow);
  90. memcpy(&pb[ofs], pbset, cbset);
  91. Cleanup:
  92. return err;
  93. }
  94. ERR setbfw(U8* pb, size_t cb, size_t ofs, U16 dw)
  95. {
  96. ERR err = WMP_errSuccess;
  97. FailIf(ofs + sizeof(U16) > cb, WMP_errBufferOverflow);
  98. pb[ofs] = (U8)dw;
  99. pb[ofs + 1] = (U8)( dw >> 8 );
  100. Cleanup:
  101. return err;
  102. }
  103. ERR setbfdw(U8* pb, size_t cb, size_t ofs, U32 dw)
  104. {
  105. ERR err = WMP_errSuccess;
  106. FailIf(ofs + sizeof(U32) > cb, WMP_errBufferOverflow);
  107. pb[ofs] = (U8)dw;
  108. pb[ofs + 1] = (U8)( dw >> 8 );
  109. pb[ofs + 2] = (U8)( dw >> 16 );
  110. pb[ofs + 3] = (U8)( dw >> 24 );
  111. Cleanup:
  112. return err;
  113. }
  114. ERR setbfwbig(U8* pb, size_t cb, size_t ofs, U16 dw)
  115. {
  116. ERR err = WMP_errSuccess;
  117. FailIf(ofs + sizeof(U16) > cb, WMP_errBufferOverflow);
  118. pb[ofs + 1] = (U8)dw;
  119. pb[ofs] = (U8)( dw >> 8 );
  120. Cleanup:
  121. return err;
  122. }
  123. ERR setbfdwbig(U8* pb, size_t cb, size_t ofs, U32 dw)
  124. {
  125. ERR err = WMP_errSuccess;
  126. FailIf(ofs + sizeof(U32) > cb, WMP_errBufferOverflow);
  127. pb[ofs + 3] = (U8)dw;
  128. pb[ofs + 2] = (U8)( dw >> 8 );
  129. pb[ofs + 1] = (U8)( dw >> 16 );
  130. pb[ofs] = (U8)( dw >> 24 );
  131. Cleanup:
  132. return err;
  133. }
  134. //================================================================
  135. // BufferCalcIFDSize (arbitrary endian)
  136. // StreamCalcIFDSize (little endian)
  137. //
  138. // count up the number of bytes needed to store the IFD and all
  139. // associated data including a subordinate interoperability IFD if any
  140. //================================================================
  141. ERR BufferCalcIFDSize(const U8* pbdata, size_t cbdata, U32 ofsifd, U8 endian, U32* pcbifd)
  142. {
  143. ERR err = WMP_errSuccess;
  144. U16 cDir;
  145. U16 i;
  146. U32 ofsdir;
  147. U32 cbifd = 0;
  148. U32 cbEXIFIFD = 0;
  149. U32 cbGPSInfoIFD = 0;
  150. U32 cbInteroperabilityIFD = 0;
  151. *pcbifd = 0;
  152. Call(getbfwe(pbdata, cbdata, ofsifd, &cDir, endian));
  153. cbifd = sizeof(U16) + cDir * SizeofIFDEntry + sizeof(U32);
  154. ofsdir = ofsifd + sizeof(U16);
  155. for ( i = 0; i < cDir; i++ )
  156. {
  157. U16 tag;
  158. U16 type;
  159. U32 count;
  160. U32 value;
  161. U32 datasize;
  162. Call(getbfwe(pbdata, cbdata, ofsdir, &tag, endian));
  163. Call(getbfwe(pbdata, cbdata, ofsdir + sizeof(U16), &type, endian));
  164. Call(getbfdwe(pbdata, cbdata, ofsdir + 2 * sizeof(U16), &count, endian));
  165. Call(getbfdwe(pbdata, cbdata, ofsdir + 2 * sizeof(U16) + sizeof(U32), &value, endian));
  166. FailIf(type == 0 || type >= sizeof(IFDEntryTypeSizes) / sizeof(IFDEntryTypeSizes[0]), WMP_errFail);
  167. if ( tag == WMP_tagEXIFMetadata )
  168. {
  169. Call(BufferCalcIFDSize(pbdata, cbdata, value, endian, &cbEXIFIFD));
  170. }
  171. else if ( tag == WMP_tagGPSInfoMetadata )
  172. {
  173. Call(BufferCalcIFDSize(pbdata, cbdata, value, endian, &cbGPSInfoIFD));
  174. }
  175. else if ( tag == WMP_tagInteroperabilityIFD )
  176. {
  177. Call(BufferCalcIFDSize(pbdata, cbdata, value, endian, &cbInteroperabilityIFD));
  178. }
  179. else
  180. {
  181. datasize = IFDEntryTypeSizes[type] * count;
  182. if ( datasize > 4 )
  183. cbifd += datasize;
  184. }
  185. ofsdir += SizeofIFDEntry;
  186. }
  187. if ( cbEXIFIFD != 0 )
  188. cbifd += ( cbifd & 1 ) + cbEXIFIFD;
  189. if ( cbGPSInfoIFD != 0 )
  190. cbifd += ( cbifd & 1 ) + cbGPSInfoIFD;
  191. if ( cbInteroperabilityIFD != 0 )
  192. cbifd += ( cbifd & 1 ) + cbInteroperabilityIFD;
  193. *pcbifd = cbifd;
  194. Cleanup:
  195. return err;
  196. }
  197. ERR StreamCalcIFDSize(struct WMPStream* pWS, U32 uIFDOfs, U32 *pcbifd)
  198. {
  199. ERR err = WMP_errSuccess;
  200. size_t offCurPos = 0;
  201. Bool GetPosOK = FALSE;
  202. U16 cDir;
  203. U32 i;
  204. U32 ofsdir;
  205. U32 cbifd = 0;
  206. U32 cbEXIFIFD = 0;
  207. U32 cbGPSInfoIFD = 0;
  208. U32 cbInteroperabilityIFD = 0;
  209. *pcbifd = 0;
  210. Call(pWS->GetPos(pWS, &offCurPos));
  211. GetPosOK = TRUE;
  212. Call(GetUShort(pWS, uIFDOfs, &cDir));
  213. cbifd = sizeof(U16) + cDir * SizeofIFDEntry + sizeof(U32);
  214. ofsdir = uIFDOfs + sizeof(U16);
  215. for ( i = 0; i < cDir; i++ )
  216. {
  217. U16 tag;
  218. U16 type;
  219. U32 count;
  220. U32 value;
  221. U32 datasize;
  222. Call(GetUShort(pWS, ofsdir, &tag));
  223. Call(GetUShort(pWS, ofsdir + sizeof(U16), &type));
  224. Call(GetULong(pWS, ofsdir + 2 * sizeof(U16), &count));
  225. Call(GetULong(pWS, ofsdir + 2 * sizeof(U16) + sizeof(U32), &value));
  226. FailIf(type == 0 || type >= sizeof(IFDEntryTypeSizes) / sizeof(IFDEntryTypeSizes[0]), WMP_errUnsupportedFormat);
  227. if ( tag == WMP_tagEXIFMetadata )
  228. {
  229. Call(StreamCalcIFDSize(pWS, value, &cbEXIFIFD));
  230. }
  231. else if ( tag == WMP_tagGPSInfoMetadata )
  232. {
  233. Call(StreamCalcIFDSize(pWS, value, &cbGPSInfoIFD));
  234. }
  235. else if ( tag == WMP_tagInteroperabilityIFD )
  236. {
  237. Call(StreamCalcIFDSize(pWS, value, &cbInteroperabilityIFD));
  238. }
  239. else
  240. {
  241. datasize = IFDEntryTypeSizes[type] * count;
  242. if ( datasize > 4 )
  243. cbifd += datasize;
  244. }
  245. ofsdir += SizeofIFDEntry;
  246. }
  247. if ( cbEXIFIFD != 0 )
  248. cbifd += ( cbifd & 1 ) + cbEXIFIFD;
  249. if ( cbGPSInfoIFD != 0 )
  250. cbifd += ( cbifd & 1 ) + cbGPSInfoIFD;
  251. if ( cbInteroperabilityIFD != 0 )
  252. cbifd += ( cbifd & 1 ) + cbInteroperabilityIFD;
  253. *pcbifd = cbifd;
  254. Cleanup:
  255. if ( GetPosOK )
  256. Call(pWS->SetPos(pWS, offCurPos));
  257. return ( err );
  258. }
  259. // src IFD copied to dst IFD with any nested IFD's
  260. // src IFD is arbitrary endian, arbitrary data arrangement
  261. // dst IFD is little endian, data arranged in tag order
  262. // dst IFD tags are ordered the same as src IFD so src IFD tags must be in order
  263. ERR BufferCopyIFD(const U8* pbsrc, U32 cbsrc, U32 ofssrc, U8 endian, U8* pbdst, U32 cbdst, U32* pofsdst)
  264. {
  265. ERR err = WMP_errSuccess;
  266. U16 cDir;
  267. U16 i;
  268. U16 ofsEXIFIFDEntry = 0;
  269. U16 ofsGPSInfoIFDEntry = 0;
  270. U16 ofsInteroperabilityIFDEntry = 0;
  271. U32 ofsEXIFIFD = 0;
  272. U32 ofsGPSInfoIFD = 0;
  273. U32 ofsInteroperabilityIFD = 0;
  274. U32 ofsdstnextdata;
  275. U32 ofsdst = *pofsdst;
  276. U32 ofssrcdir;
  277. U32 ofsdstdir;
  278. U32 ofsnextifd;
  279. Call(getbfwe(pbsrc, cbsrc, ofssrc, &cDir, endian));
  280. Call(setbfw(pbdst, cbdst, ofsdst, cDir));
  281. ofsnextifd = ofsdst + sizeof(U16) + SizeofIFDEntry * cDir;
  282. ofsdstnextdata = ofsnextifd + sizeof(U32);
  283. ofssrcdir = ofssrc + sizeof(U16);
  284. ofsdstdir = ofsdst + sizeof(U16);
  285. for ( i = 0; i < cDir; i++ )
  286. {
  287. U16 tag;
  288. U16 type;
  289. U32 count;
  290. U32 value;
  291. U32 size;
  292. Call(getbfwe(pbsrc, cbsrc, ofssrcdir, &tag, endian));
  293. Call(setbfw(pbdst, cbdst, ofsdstdir, tag));
  294. Call(getbfwe(pbsrc, cbsrc, ofssrcdir + sizeof(U16), &type, endian));
  295. Call(setbfw(pbdst, cbdst, ofsdstdir + sizeof(U16), type));
  296. Call(getbfdwe(pbsrc, cbsrc, ofssrcdir + 2 * sizeof(U16), &count, endian));
  297. Call(setbfdw(pbdst, cbdst, ofsdstdir + 2 * sizeof(U16), count));
  298. Call(getbfdwe(pbsrc, cbsrc, ofssrcdir + 2 * sizeof(U16) + sizeof(U32), &value, endian));
  299. Call(setbfdw(pbdst, cbdst, ofsdstdir + 2 * sizeof(U16) + sizeof(U32), 0));
  300. FailIf(type == 0 || type >= sizeof(IFDEntryTypeSizes) / sizeof(IFDEntryTypeSizes[0]), WMP_errFail);
  301. if ( tag == WMP_tagEXIFMetadata )
  302. {
  303. ofsEXIFIFDEntry = (U16) ofsdstdir;
  304. ofsEXIFIFD = value;
  305. }
  306. else if ( tag == WMP_tagGPSInfoMetadata )
  307. {
  308. ofsGPSInfoIFDEntry = (U16) ofsdstdir;
  309. ofsGPSInfoIFD = value;
  310. }
  311. else if ( tag == WMP_tagInteroperabilityIFD )
  312. {
  313. ofsInteroperabilityIFDEntry = (U16) ofsdstdir;
  314. ofsInteroperabilityIFD = value;
  315. }
  316. else
  317. {
  318. U32 ofsdstdata = ofsdstdir + 2 * sizeof(U16) + sizeof(U32);
  319. U32 ofssrcdata = ofssrcdir + 2 * sizeof(U16) + sizeof(U32);
  320. size = count * IFDEntryTypeSizes[type];
  321. if ( size > 4 )
  322. {
  323. ofssrcdata = value;
  324. Call(setbfdw(pbdst, cbdst, ofsdstdata, ofsdstnextdata));
  325. ofsdstdata = ofsdstnextdata;
  326. ofsdstnextdata += size;
  327. }
  328. FailIf(ofssrcdata + size > cbsrc || ofsdstdata + size > cbdst, WMP_errBufferOverflow);
  329. if ( size == count || endian == WMP_INTEL_ENDIAN )
  330. // size == count means 8-bit data means endian doesn't matter
  331. memcpy(&pbdst[ofsdstdata], &pbsrc[ofssrcdata], size);
  332. else
  333. { // big endian source and endian matters
  334. U32 j;
  335. switch ( IFDEntryTypeSizes[type] )
  336. {
  337. case 2:
  338. for ( j = 0; j < count; j++ )
  339. {
  340. U16 w;
  341. getbfwbig(pbsrc, cbsrc, ofssrcdata + j * sizeof(U16), &w);
  342. setbfw(pbdst, cbdst, ofsdstdata + j * sizeof(U16), w);
  343. }
  344. break;
  345. case 8:
  346. if ( type == WMP_typDOUBLE )
  347. {
  348. for ( j = 0; j < count; j++ )
  349. {
  350. U32 dwlo;
  351. U32 dwhi;
  352. getbfdwbig(pbsrc, cbsrc, ofssrcdata + j * 8, &dwhi);
  353. getbfdwbig(pbsrc, cbsrc, ofssrcdata + j * 8 + sizeof(U32), &dwlo);
  354. setbfdw(pbdst, cbdst, ofsdstdata + j * 8, dwlo);
  355. setbfdw(pbdst, cbdst, ofsdstdata + j * 8 + sizeof(U32), dwhi);
  356. }
  357. break;
  358. }
  359. count *= 2;
  360. // RATIONAL's fall through to be handled as LONG's
  361. case 4:
  362. for ( j = 0; j < count; j++ )
  363. {
  364. U32 dw;
  365. getbfdwbig(pbsrc, cbsrc, ofssrcdata + j * sizeof(U32), &dw);
  366. setbfdw(pbdst, cbdst, ofsdstdata + j * sizeof(U32), dw);
  367. }
  368. break;
  369. }
  370. }
  371. }
  372. ofssrcdir += SizeofIFDEntry;
  373. ofsdstdir += SizeofIFDEntry;
  374. }
  375. Call(setbfdw(pbdst, cbdst, ofsnextifd, 0)); // no nextIFD
  376. if ( ofsEXIFIFDEntry != 0 )
  377. {
  378. ofsdstnextdata += ( ofsdstnextdata & 1 );
  379. Call(setbfdw(pbdst, cbdst, ofsEXIFIFDEntry + 2 * sizeof(U16) + sizeof(U32), ofsdstnextdata));
  380. Call(BufferCopyIFD(pbsrc, cbsrc, ofsEXIFIFD, endian, pbdst, cbdst, &ofsdstnextdata));
  381. }
  382. if ( ofsGPSInfoIFDEntry != 0 )
  383. {
  384. ofsdstnextdata += ( ofsdstnextdata & 1 );
  385. Call(setbfdw(pbdst, cbdst, ofsGPSInfoIFDEntry + 2 * sizeof(U16) + sizeof(U32), ofsdstnextdata));
  386. Call(BufferCopyIFD(pbsrc, cbsrc, ofsGPSInfoIFD, endian, pbdst, cbdst, &ofsdstnextdata));
  387. }
  388. if ( ofsInteroperabilityIFDEntry != 0 )
  389. {
  390. ofsdstnextdata += ( ofsdstnextdata & 1 );
  391. Call(setbfdw(pbdst, cbdst, ofsInteroperabilityIFDEntry + 2 * sizeof(U16) + sizeof(U32), ofsdstnextdata));
  392. Call(BufferCopyIFD(pbsrc, cbsrc, ofsInteroperabilityIFD, endian, pbdst, cbdst, &ofsdstnextdata));
  393. }
  394. *pofsdst = ofsdstnextdata;
  395. Cleanup:
  396. return err;
  397. }
  398. // src IFD copied to dst IFD with any nested IFD's
  399. // src IFD is little endian, arbitrary data arrangement
  400. // dst IFD is little endian, data arranged in tag order
  401. // dst IFD tags are ordered the same as src IFD so src IFD tags must be in order
  402. ERR StreamCopyIFD(struct WMPStream* pWS, U32 ofssrc, U8* pbdst, U32 cbdst, U32* pofsdst)
  403. {
  404. ERR err = WMP_errSuccess;
  405. size_t offCurPos = 0;
  406. Bool GetPosOK = FALSE;
  407. U16 cDir;
  408. U16 i;
  409. U16 ofsEXIFIFDEntry = 0;
  410. U16 ofsGPSInfoIFDEntry = 0;
  411. U16 ofsInteroperabilityIFDEntry = 0;
  412. U32 ofsEXIFIFD = 0;
  413. U32 ofsGPSInfoIFD = 0;
  414. U32 ofsInteroperabilityIFD = 0;
  415. U32 ofsdstnextdata;
  416. U32 ofsdst = *pofsdst;
  417. U32 ofssrcdir;
  418. U32 ofsdstdir;
  419. U32 ofsnextifd;
  420. Call(pWS->GetPos(pWS, &offCurPos));
  421. GetPosOK = TRUE;
  422. Call(GetUShort(pWS, ofssrc, &cDir));
  423. Call(setbfw(pbdst, cbdst, ofsdst, cDir));
  424. ofsnextifd = ofsdst + sizeof(U16) + SizeofIFDEntry * cDir;
  425. ofsdstnextdata = ofsnextifd + sizeof(U32);
  426. ofssrcdir = ofssrc + sizeof(U16);
  427. ofsdstdir = ofsdst + sizeof(U16);
  428. for ( i = 0; i < cDir; i++ )
  429. {
  430. U16 tag;
  431. U16 type;
  432. U32 count;
  433. U32 value;
  434. U32 size;
  435. Call(GetUShort(pWS, ofssrcdir, &tag));
  436. Call(setbfw(pbdst, cbdst, ofsdstdir, tag));
  437. Call(GetUShort(pWS, ofssrcdir + sizeof(U16), &type));
  438. Call(setbfw(pbdst, cbdst, ofsdstdir + sizeof(U16), type));
  439. Call(GetULong(pWS, ofssrcdir + 2 * sizeof(U16), &count));
  440. Call(setbfdw(pbdst, cbdst, ofsdstdir + 2 * sizeof(U16), count));
  441. Call(GetULong(pWS, ofssrcdir + 2 * sizeof(U16) + sizeof(U32), &value));
  442. Call(setbfdw(pbdst, cbdst, ofsdstdir + 2 * sizeof(U16) + sizeof(U32), 0));
  443. FailIf(type == 0 || type >= sizeof(IFDEntryTypeSizes) / sizeof(IFDEntryTypeSizes[0]), WMP_errFail);
  444. if ( tag == WMP_tagEXIFMetadata )
  445. {
  446. ofsEXIFIFDEntry = (U16) ofsdstdir;
  447. ofsEXIFIFD = value;
  448. }
  449. else if ( tag == WMP_tagGPSInfoMetadata )
  450. {
  451. ofsGPSInfoIFDEntry = (U16) ofsdstdir;
  452. ofsGPSInfoIFD = value;
  453. }
  454. else if ( tag == WMP_tagInteroperabilityIFD )
  455. {
  456. ofsInteroperabilityIFDEntry = (U16) ofsdstdir;
  457. ofsInteroperabilityIFD = value;
  458. }
  459. else
  460. {
  461. U32 ofsdstdata = ofsdstdir + 2 * sizeof(U16) + sizeof(U32);
  462. U32 ofssrcdata = ofssrcdir + 2 * sizeof(U16) + sizeof(U32);
  463. size = count * IFDEntryTypeSizes[type];
  464. if ( size > 4 )
  465. {
  466. ofssrcdata = value;
  467. Call(setbfdw(pbdst, cbdst, ofsdstdata, ofsdstnextdata));
  468. ofsdstdata = ofsdstnextdata;
  469. ofsdstnextdata += size;
  470. }
  471. FailIf(ofsdstdata + size > cbdst, WMP_errBufferOverflow);
  472. Call(pWS->SetPos(pWS, ofssrcdata));
  473. Call(pWS->Read(pWS, &pbdst[ofsdstdata], size));
  474. }
  475. ofssrcdir += SizeofIFDEntry;
  476. ofsdstdir += SizeofIFDEntry;
  477. }
  478. Call(setbfdw(pbdst, cbdst, ofsnextifd, 0)); // no nextIFD
  479. if ( ofsEXIFIFDEntry != 0 )
  480. {
  481. ofsdstnextdata += ( ofsdstnextdata & 1 );
  482. Call(setbfdw(pbdst, cbdst, ofsEXIFIFDEntry + 2 * sizeof(U16) + sizeof(U32), ofsdstnextdata));
  483. Call(StreamCopyIFD(pWS, ofsEXIFIFD, pbdst, cbdst, &ofsdstnextdata));
  484. }
  485. if ( ofsGPSInfoIFDEntry != 0 )
  486. {
  487. ofsdstnextdata += ( ofsdstnextdata & 1 );
  488. Call(setbfdw(pbdst, cbdst, ofsGPSInfoIFDEntry + 2 * sizeof(U16) + sizeof(U32), ofsdstnextdata));
  489. Call(StreamCopyIFD(pWS, ofsGPSInfoIFD, pbdst, cbdst, &ofsdstnextdata));
  490. }
  491. if ( ofsInteroperabilityIFDEntry != 0 )
  492. {
  493. ofsdstnextdata += ( ofsdstnextdata & 1 );
  494. Call(setbfdw(pbdst, cbdst, ofsInteroperabilityIFDEntry + 2 * sizeof(U16) + sizeof(U32), ofsdstnextdata));
  495. Call(StreamCopyIFD(pWS, ofsInteroperabilityIFD, pbdst, cbdst, &ofsdstnextdata));
  496. }
  497. *pofsdst = ofsdstnextdata;
  498. Cleanup:
  499. if ( GetPosOK )
  500. Call(pWS->SetPos(pWS, offCurPos));
  501. return err;
  502. }
  503. //================================================================
  504. ERR GetUShort(
  505. __in_ecount(1) struct WMPStream* pWS,
  506. size_t offPos,
  507. __out_ecount(1) U16* puValue)
  508. {
  509. ERR err = WMP_errSuccess;
  510. U8 cVal;
  511. Call(pWS->SetPos(pWS, offPos));
  512. Call(pWS->Read(pWS, &cVal, sizeof(cVal)));
  513. puValue[0] = (U16) cVal;
  514. Call(pWS->Read(pWS, &cVal, sizeof(cVal)));
  515. puValue[0] += ((U16) cVal) << 8;
  516. Cleanup:
  517. return err;
  518. }
  519. ERR PutUShort(
  520. __in_ecount(1) struct WMPStream* pWS,
  521. size_t offPos,
  522. U16 uValue)
  523. {
  524. ERR err = WMP_errSuccess;
  525. U8 cVal = (U8) uValue;
  526. Call(pWS->SetPos(pWS, offPos));
  527. Call(pWS->Write(pWS, &cVal, sizeof(cVal)));
  528. cVal = (U8) (uValue >> 8);
  529. Call(pWS->Write(pWS, &cVal, sizeof(cVal)));
  530. Cleanup:
  531. return err;
  532. }
  533. ERR GetULong(
  534. __in_ecount(1) struct WMPStream* pWS,
  535. size_t offPos,
  536. __out_ecount(1) U32* puValue)
  537. {
  538. ERR err = WMP_errSuccess;
  539. U8 cVal;
  540. Call(pWS->SetPos(pWS, offPos));
  541. Call(pWS->Read(pWS, &cVal, sizeof(cVal)));
  542. puValue[0] = (U32) cVal;
  543. Call(pWS->Read(pWS, &cVal, sizeof(cVal)));
  544. puValue[0] += ((U32) cVal) << 8;
  545. Call(pWS->Read(pWS, &cVal, sizeof(cVal)));
  546. puValue[0] += ((U32) cVal) << 16;
  547. Call(pWS->Read(pWS, &cVal, sizeof(cVal)));
  548. puValue[0] += ((U32) cVal) << 24;
  549. Cleanup:
  550. return err;
  551. }
  552. ERR PutULong(
  553. __in_ecount(1) struct WMPStream* pWS,
  554. size_t offPos,
  555. U32 uValue)
  556. {
  557. ERR err = WMP_errSuccess;
  558. U8 cVal = (U8) uValue;
  559. Call(pWS->SetPos(pWS, offPos));
  560. Call(pWS->Write(pWS, &cVal, sizeof(cVal)));
  561. cVal = (U8) (uValue >> 8);
  562. Call(pWS->Write(pWS, &cVal, sizeof(cVal)));
  563. cVal = (U8) (uValue >> 16);
  564. Call(pWS->Write(pWS, &cVal, sizeof(cVal)));
  565. cVal = (U8) (uValue >> 24);
  566. Call(pWS->Write(pWS, &cVal, sizeof(cVal)));
  567. Cleanup:
  568. return err;
  569. }
  570. ERR ReadBinaryData(__in_ecount(1) struct WMPStream* pWS,
  571. const __in_win U32 uCount,
  572. const __in_win U32 uValue,
  573. U8 **ppbData)
  574. {
  575. ERR err = WMP_errSuccess;
  576. U8 *pbData = NULL;
  577. Call(PKAlloc((void **) &pbData, uCount + 2)); // Allocate buffer to store data with space for an added ascii or unicode null
  578. if (uCount <= 4)
  579. {
  580. unsigned int i;
  581. for (i = 0; i < uCount; i++)
  582. pbData[i] = ((U8*)&uValue)[i]; // Copy least sig bytes - we assume 'II' type TIFF files
  583. }
  584. else
  585. {
  586. size_t offPosPrev;
  587. Call(pWS->GetPos(pWS, &offPosPrev));
  588. Call(pWS->SetPos(pWS, uValue));
  589. Call(pWS->Read(pWS, pbData, uCount));
  590. Call(pWS->SetPos(pWS, offPosPrev));
  591. }
  592. *ppbData = pbData;
  593. Cleanup:
  594. if (Failed(err))
  595. {
  596. if (pbData)
  597. PKFree((void **) &pbData);
  598. }
  599. return err;
  600. }
  601. ERR ReadPropvar(__in_ecount(1) struct WMPStream* pWS,
  602. const __in_win U16 uType,
  603. const __in_win U32 uCount,
  604. const __in_win U32 uValue,
  605. __out_win DPKPROPVARIANT *pvar)
  606. {
  607. ERR err = WMP_errSuccess;
  608. // U8 *pbData = NULL;
  609. memset(pvar, 0, sizeof(*pvar));
  610. if (uCount == 0)
  611. goto Cleanup; // Nothing to read in here
  612. switch (uType)
  613. {
  614. case WMP_typASCII:
  615. pvar->vt = DPKVT_LPSTR;
  616. Call(ReadBinaryData(pWS, uCount, uValue, (U8 **) &pvar->VT.pszVal));
  617. assert(0 == pvar->VT.pszVal[uCount - 1]); // Check that it's null-terminated
  618. // make sure (ReadBinaryData allocated uCount + 2 so this and unicode can have forced nulls)
  619. pvar->VT.pszVal[uCount] = 0;
  620. break;
  621. case WMP_typBYTE:
  622. case WMP_typUNDEFINED:
  623. // Return as regular C array rather than safearray, as this type is sometimes
  624. // used to convey unicode (which does not require a count field). Caller knows
  625. // uCount and can convert to safearray if necessary.
  626. pvar->vt = (DPKVT_BYREF | DPKVT_UI1);
  627. Call(ReadBinaryData(pWS, uCount, uValue, &pvar->VT.pbVal));
  628. break;
  629. case WMP_typSHORT:
  630. if (1 == uCount)
  631. {
  632. pvar->vt = DPKVT_UI2;
  633. pvar->VT.uiVal = (U16)(uValue & 0x0000FFFF);
  634. }
  635. else if (2 == uCount)
  636. {
  637. pvar->vt = DPKVT_UI4;
  638. pvar->VT.ulVal = uValue;
  639. }
  640. else
  641. {
  642. assert(FALSE); // NYI
  643. FailIf(TRUE, WMP_errNotYetImplemented);
  644. }
  645. break;
  646. default:
  647. assert(FALSE); // Unhandled type
  648. FailIf(TRUE, WMP_errNotYetImplemented);
  649. break;
  650. }
  651. Cleanup:
  652. return err;
  653. }
  654. ERR WriteWmpDE(
  655. __in_ecount(1) struct WMPStream* pWS,
  656. size_t *pOffPos,
  657. const __in_ecount(1) WmpDE* pDE,
  658. const U8 *pbData,
  659. U32 *pcbDataWrittenToOffset)
  660. {
  661. ERR err = WMP_errSuccess;
  662. size_t offPos = *pOffPos;
  663. assert(-1 != pDE->uCount);
  664. assert(-1 != pDE->uValueOrOffset);
  665. if (pcbDataWrittenToOffset)
  666. {
  667. assert(pbData); // Makes no sense to provide this arg without pbData
  668. *pcbDataWrittenToOffset = 0;
  669. }
  670. Call(PutUShort(pWS, offPos, pDE->uTag)); offPos += 2;
  671. Call(PutUShort(pWS, offPos, pDE->uType)); offPos += 2;
  672. Call(PutULong(pWS, offPos, pDE->uCount)); offPos += 4;
  673. switch (pDE->uType)
  674. {
  675. case WMP_typASCII:
  676. case WMP_typUNDEFINED:
  677. case WMP_typBYTE:
  678. if (pDE->uCount <= 4)
  679. {
  680. U8 pad[4] = {0};
  681. Call(pWS->SetPos(pWS, offPos));
  682. if (NULL == pbData)
  683. pbData = (U8*)&pDE->uValueOrOffset;
  684. Call(pWS->Write(pWS, pbData, pDE->uCount));
  685. Call(pWS->Write(pWS, pad, 4 - pDE->uCount)); offPos += 4;
  686. }
  687. else
  688. {
  689. Call(PutULong(pWS, offPos, pDE->uValueOrOffset)); offPos += 4;
  690. // Write the data if requested to do so
  691. if (pbData)
  692. {
  693. Call(pWS->SetPos(pWS, pDE->uValueOrOffset));
  694. Call(pWS->Write(pWS, pbData, pDE->uCount));
  695. Call(pWS->SetPos(pWS, offPos));
  696. *pcbDataWrittenToOffset = pDE->uCount;
  697. }
  698. }
  699. break;
  700. case WMP_typSHORT:
  701. if (pDE->uCount <= 2)
  702. {
  703. U16 uiShrt1 = 0;
  704. U16 uiShrt2 = 0;
  705. if (NULL == pbData)
  706. pbData = (U8*)&pDE->uValueOrOffset;
  707. if (pDE->uCount > 0)
  708. uiShrt1 = *((U16*)pbData);
  709. if (pDE->uCount > 1)
  710. {
  711. assert(FALSE); // Untested - remove this assert after this has been tested
  712. uiShrt2 = *(U16*)(pbData + 2);
  713. }
  714. Call(PutUShort(pWS, offPos, uiShrt1)); offPos += 2;
  715. Call(PutUShort(pWS, offPos, uiShrt2)); offPos += 2;
  716. }
  717. else
  718. {
  719. assert(FALSE); // Untested - remove this assert after this has been tested
  720. Call(PutULong(pWS, offPos, pDE->uValueOrOffset)); offPos += 4;
  721. // Write the data if requested to do so
  722. if (pbData)
  723. {
  724. U32 i;
  725. Call(pWS->SetPos(pWS, pDE->uValueOrOffset));
  726. for (i = 0; i < pDE->uCount; i++)
  727. {
  728. const U16 uiShort = *(U16*)(pbData + i*sizeof(U16));
  729. Call(PutUShort(pWS, offPos, uiShort)); // Write one at a time for endian purposes - but inefficient
  730. }
  731. Call(pWS->SetPos(pWS, offPos));
  732. *pcbDataWrittenToOffset = pDE->uCount * sizeof(U16);
  733. }
  734. }
  735. break;
  736. case WMP_typFLOAT:
  737. case WMP_typLONG:
  738. if (pDE->uCount <= 1)
  739. {
  740. if (NULL == pbData)
  741. pbData = (U8*)&pDE->uValueOrOffset;
  742. Call(PutULong(pWS, offPos, *(U32*)pbData)); offPos += 4;
  743. }
  744. else
  745. {
  746. assert(FALSE); // Untested - remove this assert after this has been tested
  747. Call(PutULong(pWS, offPos, pDE->uValueOrOffset)); offPos += 4;
  748. // Write the data if requested to do so
  749. if (pbData)
  750. {
  751. U32 i;
  752. Call(pWS->SetPos(pWS, pDE->uValueOrOffset));
  753. for (i = 0; i < pDE->uCount; i++)
  754. {
  755. const U32 uLong = *(U32*)(pbData + i*sizeof(U32));
  756. Call(PutULong(pWS, offPos, uLong)); // Write one at a time for endian purposes - but inefficient
  757. }
  758. Call(pWS->SetPos(pWS, offPos));
  759. *pcbDataWrittenToOffset = pDE->uCount * sizeof(U32);
  760. }
  761. }
  762. break;
  763. default:
  764. assert(FALSE); // Alert the programmer
  765. Call(WMP_errInvalidParameter);
  766. break;
  767. }
  768. Cleanup:
  769. *pOffPos = offPos;
  770. return err;
  771. }