1 
2 //*@@@+++@@@@******************************************************************
3 //
4 // Copyright � Microsoft Corp.
5 // All rights reserved.
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions are met:
9 //
10 // � Redistributions of source code must retain the above copyright notice,
11 //   this list of conditions and the following disclaimer.
12 // � Redistributions in binary form must reproduce the above copyright notice,
13 //   this list of conditions and the following disclaimer in the documentation
14 //   and/or other materials provided with the distribution.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 // POSSIBILITY OF SUCH DAMAGE.
27 //
28 //*@@@---@@@@******************************************************************
29 #include <limits.h>
30 #include <JXRGlue.h>
31 
32 
33 static const char szHDPhotoFormat[] = "<dc:format>image/vnd.ms-photo</dc:format>";
34 const U32 IFDEntryTypeSizes[] = { 0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8 };
35 const U32 SizeofIFDEntry = sizeof(struct IFDEntry);
36 
37 
CalcMetadataSizeLPSTR(const DPKPROPVARIANT var,U16 * pcInactiveMetadata,U32 * pcbOffsetSize,U32 * pcbCount)38 void CalcMetadataSizeLPSTR(const DPKPROPVARIANT var,
39                            U16 *pcInactiveMetadata,
40                            U32 *pcbOffsetSize,
41                            U32 *pcbCount)
42 {
43     if (DPKVT_EMPTY != var.vt)
44     {
45         U32 uiLenWithNull = (U32)strlen(var.VT.pszVal) + 1; // +1 for NULL;
46         assert(DPKVT_LPSTR == var.vt);
47 
48         // We only use offset if size > 4
49         if (uiLenWithNull > 4)
50             *pcbOffsetSize += uiLenWithNull;
51 
52         if (pcbCount)
53             *pcbCount = uiLenWithNull;
54     }
55     else
56         *pcInactiveMetadata += 1;
57 }
58 
CalcMetadataSizeLPWSTR(const DPKPROPVARIANT var,U16 * pcInactiveMetadata,U32 * pcbOffsetSize,U32 * pcbCount)59 void CalcMetadataSizeLPWSTR(const DPKPROPVARIANT var,
60                             U16 *pcInactiveMetadata,
61                             U32 *pcbOffsetSize,
62                             U32 *pcbCount)
63 {
64     if (DPKVT_EMPTY != var.vt)
65     {
66         U32 uiCBWithNull = sizeof(U16) * ((U32)wcslen((wchar_t *) var.VT.pwszVal) + 1); // +1 for NULL term;
67         assert(DPKVT_LPWSTR == var.vt);
68 
69         // We only use offset if size > 4
70         if (uiCBWithNull > 4)
71             *pcbOffsetSize += uiCBWithNull;
72 
73         if (pcbCount)
74             *pcbCount = uiCBWithNull;
75     }
76     else
77         *pcInactiveMetadata += 1;
78 }
79 
CalcMetadataSizeUI2(const DPKPROPVARIANT var,U16 * pcInactiveMetadata,U32 * pcbMetadataSize)80 void CalcMetadataSizeUI2(const DPKPROPVARIANT var,
81                          U16 *pcInactiveMetadata,
82                          U32 *pcbMetadataSize)
83 {
84     UNREFERENCED_PARAMETER( pcbMetadataSize );
85     if (DPKVT_EMPTY != var.vt)
86     {
87         assert(DPKVT_UI2 == var.vt);
88         // This is a single UI2, so it will not be written via offset, but rather as value
89     }
90     else
91         *pcInactiveMetadata += 1;
92 }
93 
CalcMetadataSizeUI4(const DPKPROPVARIANT var,U16 * pcInactiveMetadata,U32 * pcbContainer)94 void CalcMetadataSizeUI4(const DPKPROPVARIANT var,
95                          U16 *pcInactiveMetadata,
96                          U32 *pcbContainer)
97 {
98     UNREFERENCED_PARAMETER( pcbContainer );
99     if (DPKVT_EMPTY != var.vt)
100     {
101         assert(DPKVT_UI4 == var.vt);
102         // This is a single UI4, so it will not be written via offset, but rather as value
103     }
104     else
105         *pcInactiveMetadata += 1;
106 }
107 
CalcMetadataOffsetSize(PKImageEncode * pIE,U16 * pcInactiveMetadata,U32 * pcbMetadataSize)108 ERR CalcMetadataOffsetSize(PKImageEncode* pIE,
109                            U16 *pcInactiveMetadata,
110                            U32 *pcbMetadataSize)
111 {
112     ERR err = WMP_errSuccess;
113 
114     CalcMetadataSizeLPSTR(pIE->sDescMetadata.pvarImageDescription, pcInactiveMetadata, pcbMetadataSize, NULL);
115     CalcMetadataSizeLPSTR(pIE->sDescMetadata.pvarCameraMake, pcInactiveMetadata, pcbMetadataSize, NULL);
116     CalcMetadataSizeLPSTR(pIE->sDescMetadata.pvarCameraModel, pcInactiveMetadata, pcbMetadataSize, NULL);
117     CalcMetadataSizeLPSTR(pIE->sDescMetadata.pvarSoftware, pcInactiveMetadata, pcbMetadataSize, NULL);
118     CalcMetadataSizeLPSTR(pIE->sDescMetadata.pvarDateTime, pcInactiveMetadata, pcbMetadataSize, NULL);
119     CalcMetadataSizeLPSTR(pIE->sDescMetadata.pvarArtist, pcInactiveMetadata, pcbMetadataSize, NULL);
120     CalcMetadataSizeLPSTR(pIE->sDescMetadata.pvarCopyright, pcInactiveMetadata, pcbMetadataSize, NULL);
121     CalcMetadataSizeUI2(pIE->sDescMetadata.pvarRatingStars, pcInactiveMetadata, pcbMetadataSize);
122     CalcMetadataSizeUI2(pIE->sDescMetadata.pvarRatingValue, pcInactiveMetadata, pcbMetadataSize);
123     CalcMetadataSizeLPWSTR(pIE->sDescMetadata.pvarCaption, pcInactiveMetadata, pcbMetadataSize, NULL);
124     CalcMetadataSizeLPSTR(pIE->sDescMetadata.pvarDocumentName, pcInactiveMetadata, pcbMetadataSize, NULL);
125     CalcMetadataSizeLPSTR(pIE->sDescMetadata.pvarPageName, pcInactiveMetadata, pcbMetadataSize, NULL);
126     CalcMetadataSizeUI4(pIE->sDescMetadata.pvarPageNumber, pcInactiveMetadata, pcbMetadataSize);
127     CalcMetadataSizeLPSTR(pIE->sDescMetadata.pvarHostComputer, pcInactiveMetadata, pcbMetadataSize, NULL);
128 
129     return err;
130 }
131 
132 
CopyDescMetadata(DPKPROPVARIANT * pvarDst,const DPKPROPVARIANT varSrc)133 ERR CopyDescMetadata(DPKPROPVARIANT *pvarDst,
134                      const DPKPROPVARIANT varSrc)
135 {
136     ERR err = WMP_errSuccess;
137     size_t  uiSize;
138 
139     pvarDst->vt = varSrc.vt;
140     switch (varSrc.vt)
141     {
142         case DPKVT_LPSTR:
143             pvarDst->vt = DPKVT_LPSTR;
144             uiSize = strlen(varSrc.VT.pszVal) + 1;
145             Call(PKAlloc((void **) &pvarDst->VT.pszVal, uiSize));
146             memcpy(pvarDst->VT.pszVal, varSrc.VT.pszVal, uiSize);
147             break;
148 
149         case DPKVT_LPWSTR:
150             pvarDst->vt = DPKVT_LPWSTR;
151             uiSize = sizeof(U16) * (wcslen((wchar_t *) varSrc.VT.pwszVal) + 1); // +1 for NULL term
152             Call(PKAlloc((void **) &pvarDst->VT.pszVal, uiSize));
153             memcpy(pvarDst->VT.pwszVal, varSrc.VT.pwszVal, uiSize);
154             break;
155 
156         case DPKVT_UI2:
157             pvarDst->VT.uiVal = varSrc.VT.uiVal;
158             break;
159 
160         case DPKVT_UI4:
161             pvarDst->VT.ulVal = varSrc.VT.ulVal;
162             break;
163 
164         default:
165             assert(FALSE); // This case is not handled
166             FailIf(TRUE, WMP_errNotYetImplemented);
167 
168             // *** FALL THROUGH ***
169 
170         case DPKVT_EMPTY:
171             memset(pvarDst, 0, sizeof(*pvarDst));
172             assert(DPKVT_EMPTY == pvarDst->vt);
173             break;
174     }
175 
176 Cleanup:
177     return err;
178 }
179 
180 
FreeDescMetadata(DPKPROPVARIANT * pvar)181 void FreeDescMetadata(DPKPROPVARIANT *pvar)
182 {
183     switch (pvar->vt)
184     {
185         case DPKVT_LPSTR:
186             PKFree((void **) &pvar->VT.pszVal);
187             break;
188 
189         case DPKVT_LPWSTR:
190             PKFree((void **) &pvar->VT.pwszVal);
191             break;
192 
193         default:
194             assert(FALSE); // This case is not handled
195             break;
196 
197         case DPKVT_EMPTY:
198         case DPKVT_UI2:
199         case DPKVT_UI4:
200             break;
201     }
202 }
203 
204 
WriteDescMetadata(PKImageEncode * pIE,const DPKPROPVARIANT var,WmpDE * pwmpDE,U32 * puiCurrDescMetadataOffset,size_t * poffPos)205 ERR WriteDescMetadata(PKImageEncode *pIE,
206                       const DPKPROPVARIANT var,
207                       WmpDE *pwmpDE,
208                       U32 *puiCurrDescMetadataOffset,
209                       size_t *poffPos)
210 {
211     ERR err = WMP_errSuccess;
212     WmpDEMisc* pDEMisc = &pIE->WMP.wmiDEMisc;
213     struct WMPStream* pWS = pIE->pStream;
214     U32 uiMetadataOffsetSize = 0;
215     U32 uiCount = 0;
216     U32 uiDataWrittenToOffset = 0;
217     U16 uiTemp = 0;
218 
219     if (0 == pDEMisc->uDescMetadataOffset || 0 == pDEMisc->uDescMetadataByteCount)
220         goto Cleanup; // Nothing to do here
221 
222     // Sanity check before - can be equal due to remaining metadata being DPKVT_EMPTY
223     assert(*puiCurrDescMetadataOffset <= pDEMisc->uDescMetadataByteCount);
224 
225     switch (var.vt)
226     {
227         case DPKVT_EMPTY:
228             break;
229 
230         case DPKVT_LPSTR:
231             CalcMetadataSizeLPSTR(var, &uiTemp, &uiMetadataOffsetSize, &uiCount);
232             pwmpDE->uCount = uiCount;
233             pwmpDE->uValueOrOffset = pDEMisc->uDescMetadataOffset + *puiCurrDescMetadataOffset;
234             Call(WriteWmpDE(pWS, poffPos, pwmpDE, (U8*)var.VT.pszVal, &uiDataWrittenToOffset));
235             break;
236 
237         case DPKVT_LPWSTR:
238             CalcMetadataSizeLPWSTR(var, &uiTemp, &uiMetadataOffsetSize, &uiCount);
239             pwmpDE->uCount = uiCount;
240             pwmpDE->uValueOrOffset = pDEMisc->uDescMetadataOffset + *puiCurrDescMetadataOffset;
241             Call(WriteWmpDE(pWS, poffPos, pwmpDE, (U8*)var.VT.pwszVal, &uiDataWrittenToOffset));
242             break;
243 
244         case DPKVT_UI2:
245             CalcMetadataSizeUI2(var, &uiTemp, &uiMetadataOffsetSize);
246             pwmpDE->uCount = 1;
247             pwmpDE->uValueOrOffset = var.VT.uiVal;
248             Call(WriteWmpDE(pWS, poffPos, pwmpDE, NULL, NULL));
249             break;
250 
251         case DPKVT_UI4:
252             CalcMetadataSizeUI4(var, &uiTemp, &uiMetadataOffsetSize);
253             pwmpDE->uCount = 1;
254             pwmpDE->uValueOrOffset = var.VT.ulVal;
255             Call(WriteWmpDE(pWS, poffPos, pwmpDE, NULL, NULL));
256             break;
257 
258         default:
259             assert(FALSE); // This case is not handled
260             FailIf(TRUE, WMP_errNotYetImplemented);
261             break;
262     }
263 
264     *puiCurrDescMetadataOffset += uiDataWrittenToOffset;
265 
266     // Sanity check after
267     assert(*puiCurrDescMetadataOffset <= pDEMisc->uDescMetadataByteCount); // Can be equal
268 
269 Cleanup:
270     return err;
271 }
272 
273 
274 
275 //================================================================
276 // PKImageEncode_WMP
277 //================================================================
WriteContainerPre(PKImageEncode * pIE)278 ERR WriteContainerPre(
279     PKImageEncode* pIE)
280 {
281     ERR err = WMP_errSuccess;
282     const U32 OFFSET_OF_PFD = 0x20;
283     struct WMPStream* pWS = pIE->pStream;
284     WmpDEMisc* pDEMisc = &pIE->WMP.wmiDEMisc;
285     PKPixelInfo PI;
286     size_t offPos = 0;
287 
288     U8 IIMM[2] = {'\x49', '\x49'};
289     // const U32 cbWmpDEMisc = OFFSET_OF_PFD;
290     U32 cbMetadataOffsetSize = 0;
291     U16 cInactiveMetadata = 0;
292     U32 uiCurrDescMetadataOffset = 0;
293 
294     static WmpDE wmpDEs[] =
295     {
296         {WMP_tagDocumentName, WMP_typASCII, 1, (U32) -1},     // Descriptive metadata
297         {WMP_tagImageDescription, WMP_typASCII, 1, (U32) -1}, // Descriptive metadata
298         {WMP_tagCameraMake, WMP_typASCII, 1, (U32) -1},       // Descriptive metadata
299         {WMP_tagCameraModel, WMP_typASCII, 1, (U32) -1},      // Descriptive metadata
300         {WMP_tagPageName, WMP_typASCII, 1, (U32) -1},         // Descriptive metadata
301         {WMP_tagPageNumber, WMP_typSHORT, 2, (U32) -1},       // Descriptive metadata
302         {WMP_tagSoftware, WMP_typASCII, 1, (U32) -1},         // Descriptive metadata
303         {WMP_tagDateTime, WMP_typASCII, 1, (U32) -1},         // Descriptive metadata
304         {WMP_tagArtist, WMP_typASCII, 1, (U32) -1},           // Descriptive metadata
305         {WMP_tagHostComputer, WMP_typASCII, 1, (U32) -1},     // Descriptive metadata
306         {WMP_tagRatingStars, WMP_typSHORT, 1, (U32) -1},      // Descriptive metadata
307         {WMP_tagRatingValue, WMP_typSHORT, 1, (U32) -1},      // Descriptive metadata
308         {WMP_tagCopyright, WMP_typASCII, 1, (U32) -1},        // Descriptive metadata
309         {WMP_tagCaption, WMP_typBYTE, 1, (U32) -1},           // Descriptive metadata
310 
311         {WMP_tagXMPMetadata, WMP_typBYTE, 1, (U32) -1},
312         {WMP_tagIPTCNAAMetadata, WMP_typBYTE, 1, (U32) -1},
313         {WMP_tagPhotoshopMetadata, WMP_typBYTE, 1, (U32) -1},
314         {WMP_tagEXIFMetadata, WMP_typLONG, 1, (U32) -1},
315         {WMP_tagIccProfile, WMP_typUNDEFINED, 1, (U32) -1},
316         {WMP_tagGPSInfoMetadata, WMP_typLONG, 1, (U32) -1},
317 
318         {WMP_tagPixelFormat, WMP_typBYTE, 16, (U32) -1},
319         {WMP_tagTransformation, WMP_typLONG, 1, (U32) -1},
320         {WMP_tagImageWidth, WMP_typLONG, 1, (U32) -1},
321         {WMP_tagImageHeight, WMP_typLONG, 1, (U32) -1},
322         {WMP_tagWidthResolution, WMP_typFLOAT, 1, (U32) -1},
323         {WMP_tagHeightResolution, WMP_typFLOAT, 1, (U32) -1},
324         {WMP_tagImageOffset, WMP_typLONG, 1, (U32) -1},
325         {WMP_tagImageByteCount, WMP_typLONG, 1, (U32) -1},
326         {WMP_tagAlphaOffset, WMP_typLONG, 1, (U32) -1},
327         {WMP_tagAlphaByteCount, WMP_typLONG, 1, (U32) -1},
328     };
329     U16 cWmpDEs = sizeof(wmpDEs) / sizeof(wmpDEs[0]);
330     WmpDE wmpDE = {0};
331     size_t i = 0;
332 
333     U8* pbEXIFMetadata = NULL;
334     U8* pbGPSInfoMetadata = NULL;
335 
336     // const unsigned char Zero[0x20] = { 0 };
337     const unsigned char Zero[sizeof(struct IFDEntry) * sizeof(wmpDEs) / sizeof(wmpDEs[0]) + sizeof(U32)] = { 0 };
338     assert(SizeofIFDEntry * sizeof(wmpDEs) / sizeof(wmpDEs[0]) + sizeof(U32) > 0x20);
339 
340     //================
341     Call(pWS->GetPos(pWS, &offPos));
342     FailIf(0 != offPos, WMP_errUnsupportedFormat);
343 
344     //================
345     // Header (8 bytes)
346     Call(pWS->Write(pWS, IIMM, sizeof(IIMM))); offPos += 2;
347     Call(PutUShort(pWS, offPos, 0x01bc)); offPos += 2;
348     Call(PutULong(pWS, offPos, (U32)OFFSET_OF_PFD)); offPos += 4;
349 
350     //================
351     // Write overflow area
352     pDEMisc->uOffPixelFormat = (U32)offPos;
353     PI.pGUIDPixFmt = &pIE->guidPixFormat;
354     PixelFormatLookup(&PI, LOOKUP_FORWARD);
355 
356     //Call(pWS->Write(pWS, PI.pGUIDPixFmt, sizeof(*PI.pGUIDPixFmt))); offPos += 16;
357     /** following code is endian-agnostic **/
358     {
359         unsigned char *pGuid = (unsigned char *) &pIE->guidPixFormat;
360         Call(PutULong(pWS, offPos, ((U32 *)pGuid)[0]));
361         Call(PutUShort(pWS, offPos + 4, ((U16 *)(pGuid + 4))[0]));
362         Call(PutUShort(pWS, offPos + 6, ((U16 *)(pGuid + 6))[0]));
363         Call(pWS->Write(pWS, pGuid + 8, 8));
364         offPos += 16;
365     }
366 
367     //================
368     // Tally up space required for descriptive metadata
369     Call(CalcMetadataOffsetSize(pIE, &cInactiveMetadata, &cbMetadataOffsetSize));
370     cWmpDEs -= cInactiveMetadata;
371 
372     //================
373     // PFD
374     assert (offPos <= OFFSET_OF_PFD); // otherwise stuff is overwritten
375     if (offPos < OFFSET_OF_PFD)
376         Call(pWS->Write(pWS, Zero, OFFSET_OF_PFD - offPos));
377     offPos = (size_t)OFFSET_OF_PFD;
378 
379     if (!pIE->WMP.bHasAlpha || pIE->WMP.wmiSCP.uAlphaMode != 2) //no planar alpha
380         cWmpDEs -= 2;
381 
382     if (0 == pIE->cbXMPMetadataByteCount)
383         cWmpDEs -= 1; // No XMP metadata
384 
385     if (0 == pIE->cbIPTCNAAMetadataByteCount)
386         cWmpDEs -= 1; // No IPTCNAA metadata
387 
388     if (0 == pIE->cbPhotoshopMetadataByteCount)
389         cWmpDEs -= 1; // No Photoshop metadata
390 
391     if (0 == pIE->cbEXIFMetadataByteCount)
392         cWmpDEs -= 1; // No EXIF metadata
393 
394     if (0 == pIE->cbColorContext)
395         cWmpDEs -= 1; // No color context
396 
397     if (0 == pIE->cbGPSInfoMetadataByteCount)
398         cWmpDEs -= 1; // No GPSInfo metadata
399 
400     pDEMisc->uImageOffset = (U32)(offPos + sizeof(U16) + SizeofIFDEntry * cWmpDEs + sizeof(U32));
401 
402     if (cbMetadataOffsetSize > 0)
403     {
404         pDEMisc->uDescMetadataByteCount = cbMetadataOffsetSize;
405         pDEMisc->uDescMetadataOffset = pDEMisc->uImageOffset;
406         pDEMisc->uImageOffset += cbMetadataOffsetSize;
407     }
408 
409     if (pIE->cbXMPMetadataByteCount > 0)
410     {
411         pDEMisc->uXMPMetadataOffset = pDEMisc->uImageOffset;
412         pDEMisc->uImageOffset += pIE->cbXMPMetadataByteCount;
413     }
414 
415     if (pIE->cbIPTCNAAMetadataByteCount > 0)
416     {
417         pDEMisc->uIPTCNAAMetadataOffset = pDEMisc->uImageOffset;
418         pDEMisc->uImageOffset += pIE->cbIPTCNAAMetadataByteCount;
419     }
420 
421     if (pIE->cbPhotoshopMetadataByteCount > 0)
422     {
423         pDEMisc->uPhotoshopMetadataOffset = pDEMisc->uImageOffset;
424         pDEMisc->uImageOffset += pIE->cbPhotoshopMetadataByteCount;
425     }
426 
427     if (pIE->cbEXIFMetadataByteCount > 0)
428     {
429         pDEMisc->uEXIFMetadataOffset = pDEMisc->uImageOffset;
430         pDEMisc->uImageOffset += (pDEMisc->uImageOffset & 1);
431         pDEMisc->uImageOffset += pIE->cbEXIFMetadataByteCount;
432     }
433 
434     if (pIE->cbColorContext > 0)
435     {
436         pDEMisc->uColorProfileOffset = pDEMisc->uImageOffset;
437         pDEMisc->uImageOffset += pIE->cbColorContext;
438     }
439 
440     if (pIE->cbGPSInfoMetadataByteCount > 0)
441     {
442         pDEMisc->uGPSInfoMetadataOffset = pDEMisc->uImageOffset;
443         pDEMisc->uImageOffset += (pDEMisc->uImageOffset & 1);
444         pDEMisc->uImageOffset += pIE->cbGPSInfoMetadataByteCount;
445     }
446 
447     Call(PutUShort(pWS, offPos, cWmpDEs)); offPos += 2;
448     Call(pWS->Write(pWS, Zero, SizeofIFDEntry * cWmpDEs + sizeof(U32)));
449 
450     //================
451     wmpDE = wmpDEs[i++];
452     assert(WMP_tagDocumentName == wmpDE.uTag);
453     Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarDocumentName, &wmpDE,
454         &uiCurrDescMetadataOffset, &offPos));
455 
456     wmpDE = wmpDEs[i++];
457     assert(WMP_tagImageDescription == wmpDE.uTag);
458     Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarImageDescription, &wmpDE,
459         &uiCurrDescMetadataOffset, &offPos));
460 
461     wmpDE = wmpDEs[i++];
462     assert(WMP_tagCameraMake == wmpDE.uTag);
463     Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarCameraMake, &wmpDE,
464         &uiCurrDescMetadataOffset, &offPos));
465 
466     wmpDE = wmpDEs[i++];
467     assert(WMP_tagCameraModel == wmpDE.uTag);
468     Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarCameraModel, &wmpDE,
469         &uiCurrDescMetadataOffset, &offPos));
470 
471     wmpDE = wmpDEs[i++];
472     assert(WMP_tagPageName == wmpDE.uTag);
473     Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarPageName, &wmpDE,
474         &uiCurrDescMetadataOffset, &offPos));
475 
476     wmpDE = wmpDEs[i++];
477     assert(WMP_tagPageNumber == wmpDE.uTag);
478     Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarPageNumber, &wmpDE,
479         &uiCurrDescMetadataOffset, &offPos));
480 
481     wmpDE = wmpDEs[i++];
482     assert(WMP_tagSoftware == wmpDE.uTag);
483     Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarSoftware, &wmpDE,
484         &uiCurrDescMetadataOffset, &offPos));
485 
486     wmpDE = wmpDEs[i++];
487     assert(WMP_tagDateTime == wmpDE.uTag);
488     Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarDateTime, &wmpDE,
489         &uiCurrDescMetadataOffset, &offPos));
490 
491     wmpDE = wmpDEs[i++];
492     assert(WMP_tagArtist == wmpDE.uTag);
493     Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarArtist, &wmpDE,
494         &uiCurrDescMetadataOffset, &offPos));
495 
496     wmpDE = wmpDEs[i++];
497     assert(WMP_tagHostComputer == wmpDE.uTag);
498     Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarHostComputer, &wmpDE,
499         &uiCurrDescMetadataOffset, &offPos));
500 
501     wmpDE = wmpDEs[i++];
502     assert(WMP_tagRatingStars == wmpDE.uTag);
503     Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarRatingStars, &wmpDE,
504         &uiCurrDescMetadataOffset, &offPos));
505 
506     wmpDE = wmpDEs[i++];
507     assert(WMP_tagRatingValue == wmpDE.uTag);
508     Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarRatingValue, &wmpDE,
509         &uiCurrDescMetadataOffset, &offPos));
510 
511     wmpDE = wmpDEs[i++];
512     assert(WMP_tagCopyright == wmpDE.uTag);
513     Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarCopyright, &wmpDE,
514         &uiCurrDescMetadataOffset, &offPos));
515 
516     wmpDE = wmpDEs[i++];
517     assert(WMP_tagCaption == wmpDE.uTag);
518     Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarCaption, &wmpDE,
519         &uiCurrDescMetadataOffset, &offPos));
520 
521     // XMP Metadata
522     wmpDE = wmpDEs[i++];
523     assert(WMP_tagXMPMetadata == wmpDE.uTag);
524     if (pIE->cbXMPMetadataByteCount > 0)
525     {
526         U32 uiTemp;
527         wmpDE.uCount = pIE->cbXMPMetadataByteCount;
528         wmpDE.uValueOrOffset = pDEMisc->uXMPMetadataOffset;
529         Call(WriteWmpDE(pWS, &offPos, &wmpDE, pIE->pbXMPMetadata, &uiTemp));
530     }
531 
532     // IPTCNAA Metadata
533     wmpDE = wmpDEs[i++];
534     assert(WMP_tagIPTCNAAMetadata == wmpDE.uTag);
535     if (pIE->cbIPTCNAAMetadataByteCount > 0)
536     {
537         U32 uiTemp;
538         wmpDE.uCount = pIE->cbIPTCNAAMetadataByteCount;
539         wmpDE.uValueOrOffset = pDEMisc->uIPTCNAAMetadataOffset;
540         Call(WriteWmpDE(pWS, &offPos, &wmpDE, pIE->pbIPTCNAAMetadata, &uiTemp));
541     }
542 
543     // Photoshop Metadata
544     wmpDE = wmpDEs[i++];
545     assert(WMP_tagPhotoshopMetadata == wmpDE.uTag);
546     if (pIE->cbPhotoshopMetadataByteCount > 0)
547     {
548         U32 uiTemp;
549         wmpDE.uCount = pIE->cbPhotoshopMetadataByteCount;
550         wmpDE.uValueOrOffset = pDEMisc->uPhotoshopMetadataOffset;
551         Call(WriteWmpDE(pWS, &offPos, &wmpDE, pIE->pbPhotoshopMetadata, &uiTemp));
552     }
553 
554     // EXIF Metadata
555     wmpDE = wmpDEs[i++];
556     assert(WMP_tagEXIFMetadata == wmpDE.uTag);
557     if (pIE->cbEXIFMetadataByteCount > 0)
558     {
559         U32 uiTemp;
560         if ((pDEMisc->uEXIFMetadataOffset & 1) != 0)
561         {
562             Call(pWS->SetPos(pWS, pDEMisc->uEXIFMetadataOffset));
563             Call(pWS->Write(pWS, Zero, 1));
564         }
565         pDEMisc->uEXIFMetadataOffset += (pDEMisc->uEXIFMetadataOffset & 1);
566         wmpDE.uValueOrOffset = pDEMisc->uEXIFMetadataOffset;
567         Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL));
568 
569         Call(PKAlloc((void **) &pbEXIFMetadata, pIE->cbEXIFMetadataByteCount));
570         uiTemp = pDEMisc->uEXIFMetadataOffset;
571         Call(BufferCopyIFD(pIE->pbEXIFMetadata, pIE->cbEXIFMetadataByteCount, 0, WMP_INTEL_ENDIAN,
572             pbEXIFMetadata - uiTemp, uiTemp + pIE->cbEXIFMetadataByteCount, &uiTemp));
573         Call(pWS->SetPos(pWS, pDEMisc->uEXIFMetadataOffset));
574         Call(pWS->Write(pWS, pbEXIFMetadata, pIE->cbEXIFMetadataByteCount));
575     }
576 
577     // ICC Profile
578     wmpDE = wmpDEs[i++];
579     assert(WMP_tagIccProfile == wmpDE.uTag);
580     if (pIE->cbColorContext > 0)
581     {
582         U32 uiTemp;
583         wmpDE.uCount = pIE->cbColorContext;
584         wmpDE.uValueOrOffset = pDEMisc->uColorProfileOffset;
585         Call(WriteWmpDE(pWS, &offPos, &wmpDE, pIE->pbColorContext, &uiTemp));
586     }
587 
588     // GPSInfo Metadata
589     wmpDE = wmpDEs[i++];
590     assert(WMP_tagGPSInfoMetadata == wmpDE.uTag);
591     if (pIE->cbGPSInfoMetadataByteCount > 0)
592     {
593         U32 uiTemp;
594         if ((pDEMisc->uGPSInfoMetadataOffset & 1) != 0)
595         {
596             Call(pWS->SetPos(pWS, pDEMisc->uGPSInfoMetadataOffset));
597             Call(pWS->Write(pWS, Zero, 1));
598         }
599         pDEMisc->uGPSInfoMetadataOffset += (pDEMisc->uGPSInfoMetadataOffset & 1);
600         wmpDE.uValueOrOffset = pDEMisc->uGPSInfoMetadataOffset;
601         Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL));
602 
603         Call(PKAlloc((void **) &pbGPSInfoMetadata, pIE->cbGPSInfoMetadataByteCount));
604         uiTemp = pDEMisc->uGPSInfoMetadataOffset;
605         Call(BufferCopyIFD(pIE->pbGPSInfoMetadata, pIE->cbGPSInfoMetadataByteCount, 0, WMP_INTEL_ENDIAN,
606             pbGPSInfoMetadata - uiTemp, uiTemp + pIE->cbGPSInfoMetadataByteCount, &uiTemp));
607         Call(pWS->SetPos(pWS, pDEMisc->uGPSInfoMetadataOffset));
608         Call(pWS->Write(pWS, pbGPSInfoMetadata, pIE->cbGPSInfoMetadataByteCount));
609     }
610 
611     wmpDE = wmpDEs[i++];
612     assert(WMP_tagPixelFormat == wmpDE.uTag);
613     wmpDE.uValueOrOffset = pDEMisc->uOffPixelFormat;
614     Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL));
615 
616     wmpDE = wmpDEs[i++];
617     assert(WMP_tagTransformation == wmpDE.uTag);
618     wmpDE.uValueOrOffset = pIE->WMP.oOrientation;
619     Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL));
620 
621     wmpDE = wmpDEs[i++];
622     assert(WMP_tagImageWidth == wmpDE.uTag);
623     wmpDE.uValueOrOffset = pIE->uWidth;
624     Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL));
625 
626     wmpDE = wmpDEs[i++];
627     assert(WMP_tagImageHeight == wmpDE.uTag);
628     wmpDE.uValueOrOffset = pIE->uHeight;
629     Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL));
630 
631     wmpDE = wmpDEs[i++];
632     assert(WMP_tagWidthResolution == wmpDE.uTag);
633     *((float *) &wmpDE.uValueOrOffset) = pIE->fResX;
634     Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL));
635 
636     wmpDE = wmpDEs[i++];
637     assert(WMP_tagHeightResolution == wmpDE.uTag);
638     *((float *) &wmpDE.uValueOrOffset) = pIE->fResY;
639     Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL));
640 
641     wmpDE = wmpDEs[i++];
642     assert(WMP_tagImageOffset == wmpDE.uTag);
643     wmpDE.uValueOrOffset = pDEMisc->uImageOffset;
644     Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL));
645 
646     // fix up in WriteContainerPost()
647     wmpDE = wmpDEs[i++];
648     assert(WMP_tagImageByteCount == wmpDE.uTag);
649     pDEMisc->uOffImageByteCount = (U32)offPos;
650     wmpDE.uValueOrOffset = 0;
651     Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL));
652 
653     if (pIE->WMP.bHasAlpha && pIE->WMP.wmiSCP.uAlphaMode == 2)
654     {
655         // fix up in WriteContainerPost()
656         wmpDE = wmpDEs[i++];
657         assert(WMP_tagAlphaOffset == wmpDE.uTag);
658         pDEMisc->uOffAlphaOffset = (U32)offPos;
659         wmpDE.uValueOrOffset = 0;
660         Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL));
661 
662         // fix up in WriteContainerPost()
663         wmpDE = wmpDEs[i++];
664         assert(WMP_tagAlphaByteCount == wmpDE.uTag);
665         pDEMisc->uOffAlphaByteCount = (U32)offPos;
666         wmpDE.uValueOrOffset = 0;
667         Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL));
668     }
669 
670     //================
671     Call(PutULong(pWS, offPos, 0)); offPos += 4;
672 
673     assert(0 == (offPos & 1));
674     if (pDEMisc->uColorProfileOffset > 0 || pDEMisc->uDescMetadataOffset > 0 ||
675         pDEMisc->uXMPMetadataOffset > 0 || pDEMisc->uIPTCNAAMetadataOffset > 0 ||
676         pDEMisc->uPhotoshopMetadataOffset > 0 || pDEMisc->uEXIFMetadataOffset > 0 ||
677         pDEMisc->uGPSInfoMetadataOffset > 0)
678     {
679         assert(pDEMisc->uColorProfileOffset == offPos ||
680                pDEMisc->uDescMetadataOffset == offPos ||
681                pDEMisc->uXMPMetadataOffset == offPos ||
682                pDEMisc->uIPTCNAAMetadataOffset == offPos ||
683                pDEMisc->uPhotoshopMetadataOffset == offPos ||
684                pDEMisc->uEXIFMetadataOffset == offPos ||
685                pDEMisc->uGPSInfoMetadataOffset == offPos);
686 
687         // OK, now skip to image offset
688         Call(pWS->SetPos(pWS, pDEMisc->uImageOffset));
689         offPos = pDEMisc->uImageOffset;
690     }
691     assert(pDEMisc->uImageOffset == offPos);
692 
693 Cleanup:
694     if (pbEXIFMetadata != NULL)
695         PKFree((void **) &pbEXIFMetadata);
696     if (pbGPSInfoMetadata != NULL)
697         PKFree((void **) &pbGPSInfoMetadata);
698     return err;
699 }
700 
701 
702 
WriteContainerPost(PKImageEncode * pIE)703 ERR WriteContainerPost(
704     PKImageEncode* pIE)
705 {
706     ERR err = WMP_errSuccess;
707 
708     struct WMPStream* pWS = pIE->pStream;
709     WmpDEMisc* pDEMisc = &pIE->WMP.wmiDEMisc;
710     size_t offPos;
711 
712     WmpDE deImageByteCount = {WMP_tagImageByteCount, WMP_typLONG,  1, 0};
713     WmpDE deAlphaOffset     = {WMP_tagAlphaOffset, WMP_typLONG,  1, 0};
714     WmpDE deAlphaByteCount  = {WMP_tagAlphaByteCount, WMP_typLONG,  1, 0};
715 
716     deImageByteCount.uValueOrOffset = pIE->WMP.nCbImage;
717     offPos = pDEMisc->uOffImageByteCount;
718     Call(WriteWmpDE(pWS, &offPos, &deImageByteCount, NULL, NULL));
719 
720     //Alpha
721     if (pIE->WMP.bHasAlpha && pIE->WMP.wmiSCP.uAlphaMode == 2)
722     {
723         deAlphaOffset.uValueOrOffset = pIE->WMP.nOffAlpha;
724         offPos = pDEMisc->uOffAlphaOffset;
725         Call(WriteWmpDE(pWS, &offPos, &deAlphaOffset, NULL, NULL));
726 
727         deAlphaByteCount.uValueOrOffset = pIE->WMP.nCbAlpha + pIE->WMP.nOffAlpha;
728         offPos = pDEMisc->uOffAlphaByteCount;
729         Call(WriteWmpDE(pWS, &offPos, &deAlphaByteCount, NULL, NULL));
730     }
731 
732 Cleanup:
733     return err;
734 }
735 
736 
737 //================================================
PKImageEncode_Initialize_WMP(PKImageEncode * pIE,struct WMPStream * pStream,void * pvParam,size_t cbParam)738 ERR PKImageEncode_Initialize_WMP(
739     PKImageEncode* pIE,
740     struct WMPStream* pStream,
741     void* pvParam,
742     size_t cbParam)
743 {
744     ERR err = WMP_errSuccess;
745 
746     FailIf(sizeof(pIE->WMP.wmiSCP) != cbParam, WMP_errInvalidArgument);
747 
748     pIE->WMP.wmiSCP = *(CWMIStrCodecParam*)pvParam;
749     pIE->WMP.wmiSCP_Alpha = *(CWMIStrCodecParam*)pvParam;
750     pIE->pStream = pStream;
751 
752     pIE->WMP.wmiSCP.pWStream = pIE->pStream;
753     pIE->WMP.wmiSCP_Alpha.pWStream = pIE->pStream;
754 
755 Cleanup:
756     return err;
757 }
758 
PKImageEncode_Terminate_WMP(PKImageEncode * pIE)759 ERR PKImageEncode_Terminate_WMP(
760     PKImageEncode* pIE)
761 {
762     ERR err = WMP_errSuccess;
763     UNREFERENCED_PARAMETER( pIE );
764     return err;
765 }
766 
767 
PKImageEncode_EncodeContent_Init(PKImageEncode * pIE,PKPixelInfo PI,U32 cLine,U8 * pbPixels,U32 cbStride)768 ERR PKImageEncode_EncodeContent_Init(
769     PKImageEncode* pIE,
770     PKPixelInfo PI,
771     U32 cLine,
772     U8* pbPixels,
773     U32 cbStride)
774 {
775     ERR err = WMP_errSuccess;
776 
777     // init codec
778     pIE->WMP.wmiI.cWidth = pIE->uWidth;
779     pIE->WMP.wmiI.cHeight = pIE->uHeight;
780     pIE->WMP.wmiI.bdBitDepth = PI.bdBitDepth;
781     pIE->WMP.wmiI.cBitsPerUnit = PI.cbitUnit;
782     pIE->WMP.wmiI.bRGB = !(PI.grBit & PK_pixfmtBGR);
783     pIE->WMP.wmiI.cfColorFormat = PI.cfColorFormat;
784     pIE->WMP.wmiI.oOrientation = pIE->WMP.oOrientation;
785 
786     // Set the fPaddedUserBuffer if the following conditions are met
787     if (0 == ((size_t)pbPixels % 128) &&        // Frame buffer is aligned to 128-byte boundary
788         0 == (pIE->uWidth % 16) &&              // Horizontal resolution is multiple of 16
789         0 == (cLine % 16) &&                    // Vertical resolution is multiple of 16
790         0 == (cbStride % 128))                  // Stride is a multiple of 128 bytes
791     {
792         pIE->WMP.wmiI.fPaddedUserBuffer = TRUE;
793         // Note that there are additional conditions in strenc_x86.c's strEncOpt
794         // which could prevent optimization from being engaged
795     }
796 
797     //if (pIE->WMP.bHasAlpha)
798     //{
799     //    pIE->WMP.wmiSCP.cChannel = PI.cChannel - 1;
800     //    pIE->WMP.wmiI.cfColorFormat = PI.cfStripAlpha;
801     //}
802     //else
803 
804     if(PI.cfColorFormat == NCOMPONENT && (!(PI.grBit & PK_pixfmtHasAlpha)))//N-channel without Alpha
805         pIE->WMP.wmiSCP.cChannel = PI.cChannel;
806     else
807         pIE->WMP.wmiSCP.cChannel = PI.cChannel - 1;//other formats and (N-channel + Alpha)
808 
809     pIE->idxCurrentLine = 0;
810 
811     pIE->WMP.wmiSCP.fMeasurePerf = TRUE;
812     FailIf(ICERR_OK != ImageStrEncInit(&pIE->WMP.wmiI, &pIE->WMP.wmiSCP, &pIE->WMP.ctxSC), WMP_errFail);
813 
814 Cleanup:
815     return err;
816 }
817 
PKImageEncode_EncodeContent_Encode(PKImageEncode * pIE,U32 cLine,U8 * pbPixels,U32 cbStride)818 ERR PKImageEncode_EncodeContent_Encode(
819     PKImageEncode* pIE,
820     U32 cLine,
821     U8* pbPixels,
822     U32 cbStride)
823 {
824     ERR err = WMP_errSuccess;
825     U32 i = 0;
826 
827     //================================
828     for (i = 0; i < cLine; i += 16)
829     {
830 		Bool f420 = ( pIE->WMP.wmiI.cfColorFormat == YUV_420 ||
831 					  (pIE->WMP.wmiSCP.bYUVData && pIE->WMP.wmiSCP.cfColorFormat==YUV_420) );
832         CWMImageBufferInfo wmiBI = { 0 };
833         wmiBI.pv = pbPixels + cbStride * i / (f420 ? 2 : 1);
834         wmiBI.cLine = min(16, cLine - i);
835         wmiBI.cbStride = cbStride;
836         FailIf(ICERR_OK != ImageStrEncEncode(pIE->WMP.ctxSC, &wmiBI), WMP_errFail);
837     }
838     pIE->idxCurrentLine += cLine;
839 
840 Cleanup:
841     return err;
842 }
843 
PKImageEncode_EncodeContent_Term(PKImageEncode * pIE)844 ERR PKImageEncode_EncodeContent_Term(PKImageEncode* pIE)
845 {
846     ERR err = WMP_errSuccess;
847 
848     FailIf(ICERR_OK != ImageStrEncTerm(pIE->WMP.ctxSC), WMP_errFail);
849 
850 Cleanup:
851     return err;
852 }
853 
PKImageEncode_EncodeContent(PKImageEncode * pIE,PKPixelInfo PI,U32 cLine,U8 * pbPixels,U32 cbStride)854 ERR PKImageEncode_EncodeContent(
855     PKImageEncode* pIE,
856     PKPixelInfo PI,
857     U32 cLine,
858     U8* pbPixels,
859     U32 cbStride)
860 {
861     ERR err = WMP_errSuccess;
862     size_t offPos = 0;
863 
864     Call(pIE->pStream->GetPos(pIE->pStream, &offPos));
865     pIE->WMP.nOffImage = (Long)offPos;
866 
867     Call(PKImageEncode_EncodeContent_Init(pIE, PI, cLine, pbPixels, cbStride));
868     Call(PKImageEncode_EncodeContent_Encode(pIE, cLine, pbPixels, cbStride));
869     Call(PKImageEncode_EncodeContent_Term(pIE));
870 
871     Call(pIE->pStream->GetPos(pIE->pStream, &offPos));
872     pIE->WMP.nCbImage = (Long)offPos - pIE->WMP.nOffImage;
873 
874 Cleanup:
875     return err;
876 }
877 
878 
PKImageEncode_EncodeAlpha_Init(PKImageEncode * pIE,PKPixelInfo PI,U32 cLine,U8 * pbPixels,U32 cbStride)879 ERR PKImageEncode_EncodeAlpha_Init(
880     PKImageEncode* pIE,
881     PKPixelInfo PI,
882     U32 cLine,
883     U8* pbPixels,
884     U32 cbStride)
885 {
886     ERR err = WMP_errSuccess;
887 
888     UNREFERENCED_PARAMETER( cLine );
889     UNREFERENCED_PARAMETER( pbPixels );
890     UNREFERENCED_PARAMETER( cbStride );
891 
892     pIE->WMP.wmiI_Alpha = pIE->WMP.wmiI;
893 
894     pIE->WMP.wmiI_Alpha.cWidth = pIE->uWidth;
895     pIE->WMP.wmiI_Alpha.cHeight = pIE->uHeight;
896     pIE->WMP.wmiI_Alpha.bdBitDepth = PI.bdBitDepth;
897     pIE->WMP.wmiI_Alpha.cBitsPerUnit = PI.cbitUnit;
898     pIE->WMP.wmiI_Alpha.bRGB = !(PI.grBit & PK_pixfmtBGR);
899     pIE->WMP.wmiI.oOrientation = pIE->WMP.oOrientation;
900 //    pIE->WMP.wmiI_Alpha.cLeadingPadding += pIE->WMP.wmiSCP.cChannel;
901 //    pIE->WMP.wmiI_Alpha.cLeadingPadding += PI.cChannel - 1;
902 
903     switch (pIE->WMP.wmiI.bdBitDepth)
904     {
905         case BD_8:
906             pIE->WMP.wmiI_Alpha.cLeadingPadding += (pIE->WMP.wmiI.cBitsPerUnit >> 3) - 1;
907             break;
908 
909         case BD_16:
910         case BD_16S:
911         case BD_16F:
912             pIE->WMP.wmiI_Alpha.cLeadingPadding += (pIE->WMP.wmiI.cBitsPerUnit >> 3) / sizeof(U16) - 1;
913             break;
914 
915         case BD_32:
916         case BD_32S:
917         case BD_32F:
918             pIE->WMP.wmiI_Alpha.cLeadingPadding += (pIE->WMP.wmiI.cBitsPerUnit >> 3) / sizeof(float) - 1;
919             break;
920 
921         case BD_5:
922         case BD_10:
923         case BD_565:
924         default:
925             break;
926     }
927 
928 //    pIE->WMP.wmiSCP_Alpha.uAlphaMode = 1;
929 
930 
931     //assert(pIE->WMP.wmiI_Alpha.cfColorFormat == CF_RGB); // only RGBA is supported for now!
932     pIE->WMP.wmiI_Alpha.cfColorFormat = Y_ONLY;
933 
934     pIE->WMP.wmiSCP_Alpha.cfColorFormat = Y_ONLY;
935 
936     pIE->idxCurrentLine = 0;
937     pIE->WMP.wmiSCP_Alpha.fMeasurePerf = TRUE;
938     FailIf(ICERR_OK != ImageStrEncInit(&pIE->WMP.wmiI_Alpha, &pIE->WMP.wmiSCP_Alpha, &pIE->WMP.ctxSC_Alpha), WMP_errFail);
939 
940 Cleanup:
941     return err;
942 }
943 
PKImageEncode_EncodeAlpha_Encode(PKImageEncode * pIE,U32 cLine,U8 * pbPixels,U32 cbStride)944 ERR PKImageEncode_EncodeAlpha_Encode(
945     PKImageEncode* pIE,
946     U32 cLine,
947     U8* pbPixels,
948     U32 cbStride)
949 {
950     ERR err = WMP_errSuccess;
951     U32 i = 0;
952 
953     //================================
954     for (i = 0; i < cLine; i += 16)
955     {
956         CWMImageBufferInfo wmiBI = { 0 };
957         wmiBI.pv = pbPixels + cbStride * i;
958         wmiBI.cLine = min(16, cLine - i);
959         wmiBI.cbStride = cbStride;
960         FailIf(ICERR_OK != ImageStrEncEncode(pIE->WMP.ctxSC_Alpha, &wmiBI), WMP_errFail);
961     }
962     pIE->idxCurrentLine += cLine;
963 
964 Cleanup:
965     return err;
966 }
967 
PKImageEncode_EncodeAlpha_Term(PKImageEncode * pIE)968 ERR PKImageEncode_EncodeAlpha_Term(PKImageEncode* pIE)
969 {
970     ERR err = WMP_errSuccess;
971 
972     FailIf(ICERR_OK != ImageStrEncTerm(pIE->WMP.ctxSC_Alpha), WMP_errFail);
973 
974 Cleanup:
975     return err;
976 }
977 
PKImageEncode_EncodeAlpha(PKImageEncode * pIE,PKPixelInfo PI,U32 cLine,U8 * pbPixels,U32 cbStride)978 ERR PKImageEncode_EncodeAlpha(
979     PKImageEncode* pIE,
980     PKPixelInfo PI,
981     U32 cLine,
982     U8* pbPixels,
983     U32 cbStride)
984 {
985     ERR err = WMP_errSuccess;
986     size_t offPos = 0;
987 
988     Call(pIE->pStream->GetPos(pIE->pStream, &offPos));
989     if ((offPos & 1) != 0)
990     {
991         // Make the mark even if it is odd by inserting a pad byte
992         char zero = 0;
993         Call(pIE->pStream->Write(pIE->pStream, &zero, 1));
994         offPos++;
995     }
996     pIE->WMP.nOffAlpha = (Long)offPos;
997 
998     Call(PKImageEncode_EncodeAlpha_Init(pIE, PI, cLine, pbPixels, cbStride));
999     Call(PKImageEncode_EncodeAlpha_Encode(pIE, cLine, pbPixels, cbStride));
1000     Call(PKImageEncode_EncodeAlpha_Term(pIE));
1001 
1002     Call(pIE->pStream->GetPos(pIE->pStream, &offPos));
1003     pIE->WMP.nCbAlpha = (Long)offPos - pIE->WMP.nOffAlpha;
1004 
1005 Cleanup:
1006     return err;
1007 }
1008 
1009 
1010 
SetMetadata(PKImageEncode * pIE,const U8 * pbMetadata,U32 cbMetadata,U8 ** pbSet,U32 * pcbSet)1011 static ERR SetMetadata(PKImageEncode *pIE, const U8 *pbMetadata, U32 cbMetadata, U8** pbSet, U32* pcbSet)
1012 {
1013     ERR err = WMP_errSuccess;
1014 
1015     // Fail if the caller called us after we've already written the header out
1016     if (pIE->fHeaderDone)
1017     {
1018         assert(FALSE); // Message to programmer
1019         err = WMP_errOutOfSequence;
1020         goto Cleanup;
1021     }
1022 
1023     // Make a copy of the metadata
1024     PKFree((void **) pbSet);
1025     *pcbSet = 0;
1026 
1027     Call(PKAlloc((void **) pbSet, cbMetadata));
1028     memcpy(*pbSet, pbMetadata, cbMetadata);
1029     *pcbSet = cbMetadata;
1030 
1031 Cleanup:
1032     return err;
1033 }
1034 
1035 
1036 
PKImageEncode_SetColorContext_WMP(PKImageEncode * pIE,const U8 * pbColorContext,U32 cbColorContext)1037 ERR PKImageEncode_SetColorContext_WMP(PKImageEncode *pIE,
1038                                       const U8 *pbColorContext,
1039                                       U32 cbColorContext)
1040 {
1041     return SetMetadata(pIE, pbColorContext, cbColorContext, &pIE->pbColorContext, &pIE->cbColorContext);
1042 }
1043 
1044 
1045 
PKImageEncode_SetXMPMetadata_WMP(PKImageEncode * pIE,const U8 * pbXMPMetadata,U32 cbXMPMetadata)1046 ERR PKImageEncode_SetXMPMetadata_WMP(PKImageEncode *pIE, const U8 *pbXMPMetadata, U32 cbXMPMetadata)
1047 {   // same as the other Set's, but make sure dc:format is <dc:format>image/vnd.ms-photo</dc:format>
1048     ERR err = WMP_errSuccess;
1049     char* pbTemp = 0;
1050     U32 cbTemp;
1051     char* pszFormatBegin;
1052     // const char* pszXMPMetadata = (const char*)pbXMPMetadata;
1053     size_t cbBuffer;
1054 
1055     // Fail if the caller called us after we've already written the header out
1056     FailIf(pIE->fHeaderDone, WMP_errOutOfSequence);
1057 
1058     // Free any previously set XMP metadata
1059     PKFree((void **) &pIE->pbXMPMetadata);
1060     pIE->cbXMPMetadataByteCount = 0;
1061 
1062     // allocate a block big enough for data passed in plus added trailing null plus added HD Photo dc:format
1063     // there may already be a trailing null (but ps doesn't seem to)
1064     // there may already be a dc:format we will replace with HD Photo's
1065     // but anyway this block will be large enough guaranteed
1066     cbBuffer = cbXMPMetadata + 1 + sizeof("<dc:format>") - 1 + sizeof("</dc:format>") - 1 + sizeof(szHDPhotoFormat) - 1;
1067     Call(PKAlloc((void **) &pbTemp, cbBuffer));
1068     memcpy(pbTemp, pbXMPMetadata, cbXMPMetadata); // Make a copy of the metadata
1069     pbTemp[cbXMPMetadata] = '\0';
1070     cbXMPMetadata = (U32)strlen(pbTemp);
1071     pszFormatBegin = strstr(pbTemp, "<dc:format>");
1072     if ( pszFormatBegin != 0 )
1073     {
1074         char* pszFormatEnd;
1075         const char* pszLessThan;
1076 
1077         pszFormatEnd = strstr(pszFormatBegin, "</dc:format>");
1078         FailIf(pszFormatEnd == 0, WMP_errFail);
1079         pszLessThan = strchr(pszFormatBegin + sizeof("<dc:format>") - 1, '<');
1080         FailIf(pszLessThan != pszFormatEnd, WMP_errFail);
1081         pszFormatEnd += sizeof("</dc:format>") - 1;
1082 
1083         // photoshop doesn't put a trailing null, so we don't either
1084         // hd and tiff don't put a trailing null, so we don't either
1085         cbTemp = cbXMPMetadata - (U32) ( pszFormatEnd - pszFormatBegin ) + sizeof(szHDPhotoFormat) - 1;
1086         assert(cbTemp <= cbBuffer);
1087         FailIf(0 != STRCPY_SAFE(pszFormatBegin,
1088             cbBuffer - (pszFormatBegin - pbTemp),
1089             szHDPhotoFormat),
1090             WMP_errBufferOverflow);
1091         memcpy(pszFormatBegin + sizeof(szHDPhotoFormat) - 1, pbXMPMetadata + ( pszFormatEnd - pbTemp ),
1092             cbXMPMetadata - ( pszFormatEnd - pbTemp ));
1093     }
1094     else
1095     {
1096         cbTemp = cbXMPMetadata;
1097     }
1098 
1099     pIE->pbXMPMetadata = (U8 *) pbTemp;
1100     pIE->cbXMPMetadataByteCount = cbTemp;
1101     return ( err );
1102 
1103 Cleanup:
1104     PKFree((void **) &pbTemp);
1105     pIE->cbXMPMetadataByteCount = 0;
1106     return err;
1107 }
1108 
1109 
1110 
PKImageEncode_SetEXIFMetadata_WMP(PKImageEncode * pIE,const U8 * pbEXIFMetadata,U32 cbEXIFMetadata)1111 ERR PKImageEncode_SetEXIFMetadata_WMP(PKImageEncode *pIE, const U8 *pbEXIFMetadata, U32 cbEXIFMetadata)
1112 {
1113     return SetMetadata(pIE, pbEXIFMetadata, cbEXIFMetadata,
1114         &pIE->pbEXIFMetadata, &pIE->cbEXIFMetadataByteCount);
1115 }
1116 
1117 
1118 
PKImageEncode_SetGPSInfoMetadata_WMP(PKImageEncode * pIE,const U8 * pbGPSInfoMetadata,U32 cbGPSInfoMetadata)1119 ERR PKImageEncode_SetGPSInfoMetadata_WMP(PKImageEncode *pIE, const U8 *pbGPSInfoMetadata, U32 cbGPSInfoMetadata)
1120 {
1121     return SetMetadata(pIE, pbGPSInfoMetadata, cbGPSInfoMetadata,
1122         &pIE->pbGPSInfoMetadata, &pIE->cbGPSInfoMetadataByteCount);
1123 }
1124 
1125 
1126 
PKImageEncode_SetIPTCNAAMetadata_WMP(PKImageEncode * pIE,const U8 * pbIPTCNAAMetadata,U32 cbIPTCNAAMetadata)1127 ERR PKImageEncode_SetIPTCNAAMetadata_WMP(PKImageEncode *pIE, const U8 *pbIPTCNAAMetadata, U32 cbIPTCNAAMetadata)
1128 {
1129     return SetMetadata(pIE, pbIPTCNAAMetadata, cbIPTCNAAMetadata,
1130         &pIE->pbIPTCNAAMetadata, &pIE->cbIPTCNAAMetadataByteCount);
1131 }
1132 
1133 
1134 
PKImageEncode_SetPhotoshopMetadata_WMP(PKImageEncode * pIE,const U8 * pbPhotoshopMetadata,U32 cbPhotoshopMetadata)1135 ERR PKImageEncode_SetPhotoshopMetadata_WMP(PKImageEncode *pIE, const U8 *pbPhotoshopMetadata, U32 cbPhotoshopMetadata)
1136 {
1137     return SetMetadata(pIE, pbPhotoshopMetadata, cbPhotoshopMetadata,
1138         &pIE->pbPhotoshopMetadata, &pIE->cbPhotoshopMetadataByteCount);
1139 }
1140 
1141 
1142 
PKImageEncode_SetDescriptiveMetadata_WMP(PKImageEncode * pIE,const DESCRIPTIVEMETADATA * pSrcMeta)1143 ERR PKImageEncode_SetDescriptiveMetadata_WMP(PKImageEncode *pIE, const DESCRIPTIVEMETADATA *pSrcMeta)
1144 {
1145     ERR                     err = WMP_errSuccess;
1146     DESCRIPTIVEMETADATA    *pDstMeta = &pIE->sDescMetadata;
1147 
1148     // Fail if the caller called us after we've already written the header out
1149     if (pIE->fHeaderDone)
1150     {
1151         assert(FALSE); // Message to programmer
1152         FailIf(TRUE, WMP_errOutOfSequence);
1153     }
1154 
1155     // Make a copy of the descriptive metadata
1156     Call(CopyDescMetadata(&pDstMeta->pvarImageDescription, pSrcMeta->pvarImageDescription));
1157     Call(CopyDescMetadata(&pDstMeta->pvarCameraMake, pSrcMeta->pvarCameraMake));
1158     Call(CopyDescMetadata(&pDstMeta->pvarCameraModel, pSrcMeta->pvarCameraModel));
1159     Call(CopyDescMetadata(&pDstMeta->pvarSoftware, pSrcMeta->pvarSoftware));
1160     Call(CopyDescMetadata(&pDstMeta->pvarDateTime, pSrcMeta->pvarDateTime));
1161     Call(CopyDescMetadata(&pDstMeta->pvarArtist, pSrcMeta->pvarArtist));
1162     Call(CopyDescMetadata(&pDstMeta->pvarCopyright, pSrcMeta->pvarCopyright));
1163     Call(CopyDescMetadata(&pDstMeta->pvarRatingStars, pSrcMeta->pvarRatingStars));
1164     Call(CopyDescMetadata(&pDstMeta->pvarRatingValue, pSrcMeta->pvarRatingValue));
1165     Call(CopyDescMetadata(&pDstMeta->pvarCaption, pSrcMeta->pvarCaption));
1166     Call(CopyDescMetadata(&pDstMeta->pvarDocumentName, pSrcMeta->pvarDocumentName));
1167     Call(CopyDescMetadata(&pDstMeta->pvarPageName, pSrcMeta->pvarPageName));
1168     Call(CopyDescMetadata(&pDstMeta->pvarPageNumber, pSrcMeta->pvarPageNumber));
1169     Call(CopyDescMetadata(&pDstMeta->pvarHostComputer, pSrcMeta->pvarHostComputer));
1170 
1171 Cleanup:
1172     return err;
1173 }
1174 
1175 
1176 
PKImageEncode_WritePixels_WMP(PKImageEncode * pIE,U32 cLine,U8 * pbPixels,U32 cbStride)1177 ERR PKImageEncode_WritePixels_WMP(
1178     PKImageEncode* pIE,
1179     U32 cLine,
1180     U8* pbPixels,
1181     U32 cbStride)
1182 {
1183     ERR err = WMP_errSuccess;
1184     // U32 i = 0;
1185     PKPixelInfo PI;
1186 
1187     // Performing non-banded encode
1188     assert(BANDEDENCSTATE_UNINITIALIZED == pIE->WMP.eBandedEncState);
1189     pIE->WMP.eBandedEncState = BANDEDENCSTATE_NONBANDEDENCODE;
1190 
1191     PI.pGUIDPixFmt = &pIE->guidPixFormat;
1192     PixelFormatLookup(&PI, LOOKUP_FORWARD);
1193     pIE->WMP.bHasAlpha = !!(PI.grBit & PK_pixfmtHasAlpha);
1194 
1195     if (!pIE->fHeaderDone)
1196     {
1197         // write metadata
1198         Call(WriteContainerPre(pIE));
1199 
1200         pIE->fHeaderDone = !FALSE;
1201     }
1202 
1203 /*    if (pIE->WMP.bHasAlpha && pIE->WMP.wmiSCP.uAlphaMode == 2){
1204         pIE->WMP.wmiSCP_Alpha = pIE->WMP.wmiSCP;
1205     }
1206 */
1207     Call(PKImageEncode_EncodeContent(pIE, PI, cLine, pbPixels, cbStride));
1208     if (pIE->WMP.bHasAlpha && pIE->WMP.wmiSCP.uAlphaMode == 2){//planar alpha
1209         Call(PKImageEncode_EncodeAlpha(pIE, PI, cLine, pbPixels, cbStride));
1210     }
1211 
1212     Call(WriteContainerPost(pIE));
1213 
1214 Cleanup:
1215     return err;
1216 }
1217 
1218 
PKImageEncode_WritePixelsBandedBegin_WMP(PKImageEncode * pIE,struct WMPStream * pPATempFile)1219 ERR PKImageEncode_WritePixelsBandedBegin_WMP(PKImageEncode* pIE, struct WMPStream *pPATempFile)
1220 {
1221     ERR err = WMP_errSuccess;
1222 
1223     // Just make sure that we are in the correct state to begin a banded decode
1224     assert(BANDEDENCSTATE_UNINITIALIZED == pIE->WMP.eBandedEncState);
1225     pIE->WMP.eBandedEncState = BANDEDENCSTATE_INIT;
1226 
1227     // Save the planar alpha tempfile for future use
1228     pIE->WMP.pPATempFile = pPATempFile;
1229 
1230 //Cleanup:
1231     return err;
1232 }
1233 
PKImageEncode_WritePixelsBanded_WMP(PKImageEncode * pIE,U32 cLine,U8 * pbPixels,U32 cbStride,Bool fLastCall)1234 ERR PKImageEncode_WritePixelsBanded_WMP(PKImageEncode* pIE, U32 cLine, U8* pbPixels, U32 cbStride, Bool fLastCall)
1235 {
1236     ERR err = WMP_errSuccess;
1237     PKPixelInfo PI = {0};
1238     Bool fPI = FALSE;
1239     BANDEDENCSTATE eEncStateOrig = pIE->WMP.eBandedEncState;
1240     struct WMPStream *pPATempFile = pIE->WMP.pPATempFile;
1241 
1242     // Unless this is the last call, reject inputs which are not multiples of 16
1243     FailIf(!fLastCall && 0 != cLine % 16, WMP_errMustBeMultipleOf16LinesUntilLastCall);
1244 
1245     if (!pIE->fHeaderDone || BANDEDENCSTATE_INIT == pIE->WMP.eBandedEncState)
1246     {
1247         PI.pGUIDPixFmt = &pIE->guidPixFormat;
1248         PixelFormatLookup(&PI, LOOKUP_FORWARD);
1249         pIE->WMP.bHasAlpha = !!(PI.grBit & PK_pixfmtHasAlpha);
1250         fPI = TRUE;
1251 
1252         // Check if this is planar alpha: banded encode requires temp file
1253         if (pIE->WMP.bHasAlpha && pIE->WMP.wmiSCP.uAlphaMode == 2)
1254         {
1255             FailIf(NULL == pPATempFile, WMP_errPlanarAlphaBandedEncRequiresTempFile);
1256         }
1257     }
1258 
1259     if (!pIE->fHeaderDone)
1260     {
1261         // write metadata
1262         assert(fPI);
1263         Call(WriteContainerPre(pIE));
1264         pIE->fHeaderDone = !FALSE;
1265     }
1266 
1267     if (BANDEDENCSTATE_INIT == pIE->WMP.eBandedEncState)
1268     {
1269         // Record start of main content for future call to WriteContainerPost
1270         size_t offPos;
1271         Call(pIE->pStream->GetPos(pIE->pStream, &offPos));
1272         pIE->WMP.nOffImage = (Long)offPos;
1273 
1274         assert(fPI);
1275         Call(PKImageEncode_EncodeContent_Init(pIE, PI, cLine, pbPixels, cbStride));
1276         pIE->WMP.eBandedEncState = BANDEDENCSTATE_ENCODING;
1277     }
1278 
1279     Call(PKImageEncode_EncodeContent_Encode(pIE, cLine, pbPixels, cbStride));
1280     if (pIE->WMP.bHasAlpha && pIE->WMP.wmiSCP.uAlphaMode == 2)
1281     {
1282         //planar alpha
1283         if (BANDEDENCSTATE_INIT == eEncStateOrig)
1284         {
1285             size_t  offStart;
1286 
1287             // We assume the following which allows us to avoid saving state
1288             Call(pPATempFile->GetPos(pPATempFile, &offStart));
1289             assert(0 == offStart);
1290             assert(pIE->WMP.wmiSCP_Alpha.pWStream == pIE->WMP.wmiSCP.pWStream);
1291 
1292             // For planar alpha, we write the file to a temp file
1293             pIE->WMP.wmiSCP_Alpha.pWStream = pPATempFile;
1294             Call(PKImageEncode_EncodeAlpha_Init(pIE, PI, cLine, pbPixels, cbStride));
1295         }
1296 
1297         Call(PKImageEncode_EncodeAlpha_Encode(pIE, cLine, pbPixels, cbStride));
1298     }
1299 
1300 Cleanup:
1301     return err;
1302 }
1303 
PKImageEncode_WritePixelsBandedEnd_WMP(PKImageEncode * pIE)1304 ERR PKImageEncode_WritePixelsBandedEnd_WMP(PKImageEncode* pIE)
1305 {
1306     ERR err = WMP_errSuccess;
1307     struct WMPStream *pMainStream = pIE->WMP.wmiSCP.pWStream;
1308     size_t offAlpha;
1309 
1310     assert(BANDEDENCSTATE_ENCODING == pIE->WMP.eBandedEncState);
1311 
1312     // Finish off main content, update its length ptr for WriteContainerPost
1313     Call(PKImageEncode_EncodeContent_Term(pIE));
1314     Call(pMainStream->GetPos(pIE->pStream, &offAlpha));
1315     pIE->WMP.nCbImage = (Long)offAlpha - pIE->WMP.nOffImage;
1316 
1317     if (pIE->WMP.bHasAlpha && pIE->WMP.wmiSCP.uAlphaMode == 2)
1318     {
1319         size_t cbAlpha;
1320         size_t cbBytesCopied;
1321         struct WMPStream *pAlphaStream = pIE->WMP.wmiSCP_Alpha.pWStream;
1322 
1323         assert(pAlphaStream != pMainStream); // Otherwise we didn't use a temp file
1324 
1325         // Close it up - this causes write to temp file
1326         Call(PKImageEncode_EncodeAlpha_Term(pIE));
1327 
1328         // Calculate size of alpha bitstream and its new offset
1329         Call(pAlphaStream->GetPos(pAlphaStream, &cbAlpha));
1330 
1331         // Copy alpha bitstream to end of main stream
1332         cbBytesCopied = 0;
1333         Call(pAlphaStream->SetPos(pAlphaStream, 0));
1334         while (cbBytesCopied < cbAlpha)
1335         {
1336             char rgbBuf[TEMPFILE_COPYBUF_SIZE];
1337             size_t cbCopy;
1338 
1339             cbCopy = min(sizeof(rgbBuf), cbAlpha - cbBytesCopied);
1340             Call(pAlphaStream->Read(pAlphaStream, rgbBuf, cbCopy));
1341             Call(pMainStream->Write(pMainStream, rgbBuf, cbCopy));
1342 
1343             cbBytesCopied += cbCopy;
1344         }
1345         assert(cbBytesCopied == cbAlpha);
1346 
1347         // Update alpha offset/length for WriteContainerPost
1348         pIE->WMP.nOffAlpha = (Long)offAlpha;
1349         pIE->WMP.nCbAlpha = (Long)cbAlpha;
1350     }
1351 
1352     Call(WriteContainerPost(pIE));
1353 
1354 Cleanup:
1355     return err;
1356 }
1357 
1358 
PKImageEncode_Transcode_WMP(PKImageEncode * pIE,PKImageDecode * pID,CWMTranscodingParam * pParam)1359 ERR PKImageEncode_Transcode_WMP(
1360     PKImageEncode* pIE,
1361     PKImageDecode* pID,
1362     CWMTranscodingParam* pParam)
1363 {
1364     ERR err = WMP_errSuccess;
1365     Float fResX = 0, fResY = 0;
1366     PKPixelFormatGUID pixGUID = {0};
1367     CWMTranscodingParam tcParamAlpha;
1368     size_t offPos = 0;
1369     Bool fPlanarAlpha;
1370     PKPixelInfo PI;
1371 
1372     struct WMPStream* pWSDec = NULL;
1373     struct WMPStream* pWSEnc= pIE->pStream;
1374 
1375     // pass through metadata
1376     Call(pID->GetPixelFormat(pID, &pixGUID));
1377     Call(pIE->SetPixelFormat(pIE, pixGUID));
1378 
1379     Call(pIE->SetSize(pIE, (I32)pParam->cWidth, (I32)pParam->cHeight));
1380 
1381     Call(pID->GetResolution(pID, &fResX, &fResY));
1382     Call(pIE->SetResolution(pIE, fResX, fResY));
1383 
1384     PI.pGUIDPixFmt = &pIE->guidPixFormat;
1385     PixelFormatLookup(&PI, LOOKUP_FORWARD);
1386     pIE->WMP.bHasAlpha = !!(PI.grBit & PK_pixfmtHasAlpha) && (2 == pParam->uAlphaMode);
1387     assert(0 == pIE->WMP.bHasAlpha || (pParam->uAlphaMode == 2)); // Decode alpha mode does not match encode alpha mode!
1388 
1389     // Check for any situations where transcoder is being asked to convert alpha - we can't do this
1390     // NOTE: Decoder's bHasAlpha parameter really means, "has PLANAR alpha"
1391     PI.pGUIDPixFmt = &pixGUID;
1392     PixelFormatLookup(&PI, LOOKUP_FORWARD);
1393     FailIf(0 == (PI.grBit & PK_pixfmtHasAlpha) && pParam->uAlphaMode != 0,
1394         WMP_errAlphaModeCannotBeTranscoded); // Destination is planar/interleaved, src has no alpha
1395     FailIf(!!(PI.grBit & PK_pixfmtHasAlpha) && 2 == pParam->uAlphaMode &&
1396         FALSE == pID->WMP.bHasAlpha, WMP_errAlphaModeCannotBeTranscoded);  // Destination is planar, src is interleaved
1397     FailIf(!!(PI.grBit & PK_pixfmtHasAlpha) && 3 == pParam->uAlphaMode &&
1398         pID->WMP.bHasAlpha, WMP_errAlphaModeCannotBeTranscoded);  // Destination is interleaved, src is planar
1399     assert(/*pParam->uAlphaMode >= 0 &&*/ pParam->uAlphaMode <= 3); // All the above statements make this assumption
1400 
1401     fPlanarAlpha = pIE->WMP.bHasAlpha && (2 == pParam->uAlphaMode);
1402 
1403     // write matadata
1404     Call(WriteContainerPre(pIE));
1405 
1406     // Copy transcoding params for alpha (codec changes the struct)
1407     if (fPlanarAlpha)
1408         tcParamAlpha = *pParam;
1409 
1410     // write compressed bitstream
1411     Call(pID->GetRawStream(pID, &pWSDec));
1412 
1413     FailIf(ICERR_OK != WMPhotoTranscode(pWSDec, pWSEnc, pParam), WMP_errFail);
1414     Call(pIE->pStream->GetPos(pIE->pStream, &offPos));
1415     pIE->WMP.nCbImage = (Long)offPos - pIE->WMP.nOffImage;
1416 
1417     if (fPlanarAlpha)
1418     {
1419         pIE->WMP.nOffAlpha = (Long)offPos;
1420 
1421         // Cue the stream to alpha block
1422         assert(pID->WMP.wmiDEMisc.uAlphaOffset > 0);
1423         Call(pWSDec->SetPos(pWSDec, pID->WMP.wmiDEMisc.uAlphaOffset));
1424 
1425         FailIf(ICERR_OK != WMPhotoTranscode(pWSDec, pWSEnc, &tcParamAlpha), WMP_errFail);
1426         Call(pIE->pStream->GetPos(pIE->pStream, &offPos));
1427         pIE->WMP.nCbAlpha = (Long)offPos - pIE->WMP.nOffAlpha;
1428     }
1429 
1430     // fixup matadata
1431     Call(WriteContainerPost(pIE));
1432 
1433 Cleanup:
1434     return err;
1435 }
1436 
PKImageEncode_CreateNewFrame_WMP(PKImageEncode * pIE,void * pvParam,size_t cbParam)1437 ERR PKImageEncode_CreateNewFrame_WMP(
1438     PKImageEncode* pIE,
1439     void* pvParam,
1440     size_t cbParam)
1441 {
1442     ERR err = WMP_errSuccess;
1443 
1444     UNREFERENCED_PARAMETER( pIE );
1445     UNREFERENCED_PARAMETER( pvParam );
1446     UNREFERENCED_PARAMETER( cbParam );
1447 
1448     Call(WMP_errNotYetImplemented);
1449 
1450 Cleanup:
1451     return err;
1452 }
1453 
PKImageEncode_Release_WMP(PKImageEncode ** ppIE)1454 ERR PKImageEncode_Release_WMP(
1455     PKImageEncode** ppIE)
1456 {
1457     ERR err = WMP_errSuccess;
1458 
1459     PKImageEncode *pIE = *ppIE;
1460     pIE->pStream->Close(&pIE->pStream);
1461 
1462     PKFree((void **) &pIE->pbColorContext);
1463     pIE->cbColorContext = 0;
1464     PKFree((void **) &pIE->pbXMPMetadata);
1465     pIE->cbXMPMetadataByteCount = 0;
1466     PKFree((void **) &pIE->pbEXIFMetadata);
1467     pIE->cbEXIFMetadataByteCount = 0;
1468     PKFree((void **) &pIE->pbGPSInfoMetadata);
1469     pIE->cbGPSInfoMetadataByteCount = 0;
1470     PKFree((void **) &pIE->pbIPTCNAAMetadata);
1471     pIE->cbIPTCNAAMetadataByteCount = 0;
1472     PKFree((void **) &pIE->pbPhotoshopMetadata);
1473     pIE->cbPhotoshopMetadataByteCount = 0;
1474 
1475     // Free descriptive metadata
1476     FreeDescMetadata(&pIE->sDescMetadata.pvarImageDescription);
1477     FreeDescMetadata(&pIE->sDescMetadata.pvarCameraMake);
1478     FreeDescMetadata(&pIE->sDescMetadata.pvarCameraModel);
1479     FreeDescMetadata(&pIE->sDescMetadata.pvarSoftware);
1480     FreeDescMetadata(&pIE->sDescMetadata.pvarDateTime);
1481     FreeDescMetadata(&pIE->sDescMetadata.pvarArtist);
1482     FreeDescMetadata(&pIE->sDescMetadata.pvarCopyright);
1483     FreeDescMetadata(&pIE->sDescMetadata.pvarRatingStars);
1484     FreeDescMetadata(&pIE->sDescMetadata.pvarRatingValue);
1485     FreeDescMetadata(&pIE->sDescMetadata.pvarCaption);
1486     FreeDescMetadata(&pIE->sDescMetadata.pvarDocumentName);
1487     FreeDescMetadata(&pIE->sDescMetadata.pvarPageName);
1488     FreeDescMetadata(&pIE->sDescMetadata.pvarPageNumber);
1489     FreeDescMetadata(&pIE->sDescMetadata.pvarHostComputer);
1490 
1491     Call(PKFree((void **) ppIE));
1492 
1493 Cleanup:
1494     return err;
1495 }
1496 
1497 //----------------------------------------------------------------
PKImageEncode_Create_WMP(PKImageEncode ** ppIE)1498 ERR PKImageEncode_Create_WMP(PKImageEncode** ppIE)
1499 {
1500     ERR err = WMP_errSuccess;
1501 
1502     PKImageEncode* pIE = NULL;
1503 
1504     Call(PKImageEncode_Create(ppIE));
1505 
1506     pIE = *ppIE;
1507     pIE->Initialize = PKImageEncode_Initialize_WMP;
1508     pIE->Terminate = PKImageEncode_Terminate_WMP;
1509     pIE->SetColorContext = PKImageEncode_SetColorContext_WMP;
1510     pIE->SetDescriptiveMetadata = PKImageEncode_SetDescriptiveMetadata_WMP;
1511     pIE->WritePixels = PKImageEncode_WritePixels_WMP;
1512 
1513     pIE->WritePixelsBandedBegin = PKImageEncode_WritePixelsBandedBegin_WMP;
1514     pIE->WritePixelsBanded = PKImageEncode_WritePixelsBanded_WMP;
1515     pIE->WritePixelsBandedEnd = PKImageEncode_WritePixelsBandedEnd_WMP;
1516 
1517     pIE->Transcode = PKImageEncode_Transcode_WMP;
1518     pIE->CreateNewFrame = PKImageEncode_CreateNewFrame_WMP;
1519     pIE->Release = PKImageEncode_Release_WMP;
1520 	pIE->bWMP = TRUE;
1521 
1522 Cleanup:
1523     return err;
1524 }
1525 
1526 
1527 //================================================================
1528 // PKImageDecode_WMP
1529 //================================================================
ParsePFDEntry(PKImageDecode * pID,U16 uTag,U16 uType,U32 uCount,U32 uValue)1530 ERR ParsePFDEntry(
1531     PKImageDecode* pID,
1532     U16 uTag,
1533     U16 uType,
1534     U32 uCount,
1535     U32 uValue)
1536 {
1537     ERR err = WMP_errSuccess;
1538     ERR errTmp = WMP_errSuccess;
1539     PKPixelInfo PI;
1540     struct WMPStream* pWS = pID->pStream;
1541     // size_t offPos = 0;
1542 
1543     union uf{
1544         U32 uVal;
1545         Float fVal;
1546     }ufValue = {0};
1547 
1548     //================================
1549     switch (uTag)
1550     {
1551         case WMP_tagPixelFormat:
1552         {
1553             unsigned char *pGuid = (unsigned char *) &pID->guidPixFormat;
1554             /** following code is endian-agnostic **/
1555             Call(GetULong(pWS, uValue, (U32 *)pGuid));
1556             Call(GetUShort(pWS, uValue + 4, (unsigned short *)(pGuid + 4)));
1557             Call(GetUShort(pWS, uValue + 6, (unsigned short *)(pGuid + 6)));
1558             Call(pWS->Read(pWS, pGuid + 8, 8));
1559 
1560             PI.pGUIDPixFmt = &pID->guidPixFormat;
1561             PixelFormatLookup(&PI, LOOKUP_FORWARD);
1562 
1563             pID->WMP.bHasAlpha = !!(PI.grBit & PK_pixfmtHasAlpha);
1564             pID->WMP.wmiI.cBitsPerUnit = PI.cbitUnit;
1565             pID->WMP.wmiI.bRGB = !(PI.grBit & PK_pixfmtBGR);
1566 
1567             break;
1568         }
1569 
1570         case WMP_tagTransformation:
1571             FailIf(1 != uCount, WMP_errUnsupportedFormat);
1572             assert(uValue < O_MAX);
1573             pID->WMP.fOrientationFromContainer = TRUE;
1574             pID->WMP.oOrientationFromContainer = uValue;
1575             break;
1576 
1577         case WMP_tagImageWidth:
1578             FailIf(0 == uValue, WMP_errUnsupportedFormat);
1579             break;
1580 
1581         case WMP_tagImageHeight:
1582             FailIf(0 == uValue, WMP_errUnsupportedFormat);
1583             break;
1584 
1585         case WMP_tagImageOffset:
1586             FailIf(1 != uCount, WMP_errUnsupportedFormat);
1587             pID->WMP.wmiDEMisc.uImageOffset = uValue;
1588             break;
1589 
1590         case WMP_tagImageByteCount:
1591             FailIf(1 != uCount, WMP_errUnsupportedFormat);
1592             pID->WMP.wmiDEMisc.uImageByteCount = uValue;
1593             break;
1594 
1595         case WMP_tagAlphaOffset:
1596             FailIf(1 != uCount, WMP_errUnsupportedFormat);
1597             pID->WMP.wmiDEMisc.uAlphaOffset = uValue;
1598             break;
1599 
1600         case WMP_tagAlphaByteCount:
1601             FailIf(1 != uCount, WMP_errUnsupportedFormat);
1602             pID->WMP.wmiDEMisc.uAlphaByteCount = uValue;
1603             break;
1604 
1605         case WMP_tagWidthResolution:
1606             FailIf(1 != uCount, WMP_errUnsupportedFormat);
1607             ufValue.uVal = uValue;
1608             pID->fResX = ufValue.fVal;
1609             break;
1610 
1611         case WMP_tagHeightResolution:
1612             FailIf(1 != uCount, WMP_errUnsupportedFormat);
1613             ufValue.uVal = uValue;
1614             pID->fResY = ufValue.fVal;
1615             break;
1616 
1617         case WMP_tagIccProfile:
1618             pID->WMP.wmiDEMisc.uColorProfileByteCount = uCount;
1619             pID->WMP.wmiDEMisc.uColorProfileOffset = uValue;
1620             break;
1621 
1622         case WMP_tagXMPMetadata:
1623             pID->WMP.wmiDEMisc.uXMPMetadataByteCount = uCount;
1624             pID->WMP.wmiDEMisc.uXMPMetadataOffset = uValue;
1625             break;
1626 
1627         case WMP_tagEXIFMetadata:
1628             pID->WMP.wmiDEMisc.uEXIFMetadataOffset = uValue;
1629             CallIgnoreError(errTmp, StreamCalcIFDSize(pWS, uValue, &pID->WMP.wmiDEMisc.uEXIFMetadataByteCount));
1630             break;
1631 
1632         case WMP_tagGPSInfoMetadata:
1633             pID->WMP.wmiDEMisc.uGPSInfoMetadataOffset = uValue;
1634             CallIgnoreError(errTmp, StreamCalcIFDSize(pWS, uValue, &pID->WMP.wmiDEMisc.uGPSInfoMetadataByteCount));
1635             break;
1636 
1637         case WMP_tagIPTCNAAMetadata:
1638             pID->WMP.wmiDEMisc.uIPTCNAAMetadataByteCount = uCount;
1639             pID->WMP.wmiDEMisc.uIPTCNAAMetadataOffset = uValue;
1640             break;
1641 
1642         case WMP_tagPhotoshopMetadata:
1643             pID->WMP.wmiDEMisc.uPhotoshopMetadataByteCount = uCount;
1644             pID->WMP.wmiDEMisc.uPhotoshopMetadataOffset = uValue;
1645             break;
1646 
1647         case WMP_tagCompression:
1648         case WMP_tagImageType:
1649         case WMP_tagImageDataDiscard:
1650         case WMP_tagAlphaDataDiscard:
1651             break;
1652 
1653         // Descriptive Metadata
1654         case WMP_tagImageDescription:
1655             CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue,
1656                 &pID->WMP.sDescMetadata.pvarImageDescription));
1657             assert(DPKVT_LPSTR == pID->WMP.sDescMetadata.pvarImageDescription.vt);
1658             break;
1659 
1660         case WMP_tagCameraMake:
1661             CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue,
1662                 &pID->WMP.sDescMetadata.pvarCameraMake));
1663             assert(DPKVT_LPSTR == pID->WMP.sDescMetadata.pvarCameraMake.vt);
1664             break;
1665 
1666         case WMP_tagCameraModel:
1667             CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue,
1668                 &pID->WMP.sDescMetadata.pvarCameraModel));
1669             assert(DPKVT_LPSTR == pID->WMP.sDescMetadata.pvarCameraModel.vt);
1670             break;
1671 
1672         case WMP_tagSoftware:
1673             CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue,
1674                 &pID->WMP.sDescMetadata.pvarSoftware));
1675             assert(DPKVT_LPSTR == pID->WMP.sDescMetadata.pvarSoftware.vt);
1676             break;
1677 
1678         case WMP_tagDateTime:
1679             CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue,
1680                 &pID->WMP.sDescMetadata.pvarDateTime));
1681             assert(DPKVT_LPSTR == pID->WMP.sDescMetadata.pvarDateTime.vt);
1682             break;
1683 
1684         case WMP_tagArtist:
1685             CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue,
1686                 &pID->WMP.sDescMetadata.pvarArtist));
1687             assert(DPKVT_LPSTR == pID->WMP.sDescMetadata.pvarArtist.vt);
1688             break;
1689 
1690         case WMP_tagCopyright:
1691             CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue,
1692                 &pID->WMP.sDescMetadata.pvarCopyright));
1693             assert(DPKVT_LPSTR == pID->WMP.sDescMetadata.pvarCopyright.vt);
1694             break;
1695 
1696         case WMP_tagRatingStars:
1697             CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue,
1698                 &pID->WMP.sDescMetadata.pvarRatingStars));
1699             assert(DPKVT_UI2 == pID->WMP.sDescMetadata.pvarRatingStars.vt);
1700             break;
1701 
1702         case WMP_tagRatingValue:
1703             CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue,
1704                 &pID->WMP.sDescMetadata.pvarRatingValue));
1705             assert(DPKVT_UI2 == pID->WMP.sDescMetadata.pvarRatingValue.vt);
1706             break;
1707 
1708         case WMP_tagCaption:
1709             CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue,
1710                 &pID->WMP.sDescMetadata.pvarCaption));
1711             assert((DPKVT_BYREF | DPKVT_UI1) == pID->WMP.sDescMetadata.pvarCaption.vt);
1712 
1713             // Change type from C-style byte array to LPWSTR
1714             assert((U8*)pID->WMP.sDescMetadata.pvarCaption.VT.pwszVal ==
1715                 pID->WMP.sDescMetadata.pvarCaption.VT.pbVal);
1716             assert(0 == pID->WMP.sDescMetadata.pvarCaption.VT.pwszVal[uCount/sizeof(U16) - 1]); // Confirm null-term
1717             //  make sure null term (ReadPropvar allocated enough space for this)
1718             pID->WMP.sDescMetadata.pvarCaption.VT.pwszVal[uCount/sizeof(U16)] = 0;
1719             pID->WMP.sDescMetadata.pvarCaption.vt = DPKVT_LPWSTR;
1720             break;
1721 
1722         case WMP_tagDocumentName:
1723             CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue,
1724                 &pID->WMP.sDescMetadata.pvarDocumentName));
1725             assert(DPKVT_LPSTR == pID->WMP.sDescMetadata.pvarDocumentName.vt);
1726             break;
1727 
1728         case WMP_tagPageName:
1729             CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue,
1730                 &pID->WMP.sDescMetadata.pvarPageName));
1731             assert(DPKVT_LPSTR == pID->WMP.sDescMetadata.pvarPageName.vt);
1732             break;
1733 
1734         case WMP_tagPageNumber:
1735             CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue,
1736                 &pID->WMP.sDescMetadata.pvarPageNumber));
1737             assert(DPKVT_UI4 == pID->WMP.sDescMetadata.pvarPageNumber.vt);
1738             break;
1739 
1740         case WMP_tagHostComputer:
1741             CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue,
1742                 &pID->WMP.sDescMetadata.pvarHostComputer));
1743             assert(DPKVT_LPSTR == pID->WMP.sDescMetadata.pvarHostComputer.vt);
1744             break;
1745 
1746         default:
1747             fprintf(stderr, "Unrecognized WMPTag: %d(%#x), %d, %d, %#x" CRLF,
1748                 (int)uTag, (int)uTag, (int)uType, (int)uCount, (int)uValue);
1749             break;
1750     }
1751 
1752 Cleanup:
1753     return err;
1754 }
1755 
ParsePFD(PKImageDecode * pID,size_t offPos,U16 cEntry)1756 ERR ParsePFD(
1757     PKImageDecode* pID,
1758     size_t offPos,
1759     U16 cEntry)
1760 {
1761     ERR err = WMP_errSuccess;
1762     struct WMPStream* pWS = pID->pStream;
1763     U16 i = 0;
1764 
1765     for (i = 0; i < cEntry; ++i)
1766     {
1767         U16 uTag = 0;
1768         U16 uType = 0;
1769         U32 uCount = 0;
1770         U32 uValue = 0;
1771 
1772         Call(GetUShort(pWS, offPos, &uTag)); offPos += 2;
1773         Call(GetUShort(pWS, offPos, &uType)); offPos += 2;
1774         Call(GetULong(pWS, offPos, &uCount)); offPos += 4;
1775         Call(GetULong(pWS, offPos, &uValue)); offPos += 4;
1776 
1777         Call(ParsePFDEntry(pID, uTag, uType, uCount, uValue));
1778     }
1779 
1780     pID->WMP.bHasAlpha = ((pID->WMP.bHasAlpha) && (pID->WMP.wmiDEMisc.uAlphaOffset != 0) && (pID->WMP.wmiDEMisc.uAlphaByteCount != 0));//has planar alpha
1781 
1782 Cleanup:
1783     return err;
1784 }
1785 
ReadContainer(PKImageDecode * pID)1786 ERR ReadContainer(
1787     PKImageDecode* pID)
1788 {
1789     ERR err = WMP_errSuccess;
1790 
1791     struct WMPStream* pWS = pID->pStream;
1792     size_t offPos = 0;
1793 
1794     char szSig[2] = {0};
1795     U16 uWmpID = 0;
1796     U32 offPFD = 0;
1797     U16 cPFDEntry = 0;
1798     U8 bVersion;
1799 
1800     //================================
1801     Call(pWS->GetPos(pWS, &offPos));
1802     FailIf(0 != offPos, WMP_errUnsupportedFormat);
1803 
1804     //================================
1805     // Header
1806     Call(pWS->Read(pWS, szSig, sizeof(szSig))); offPos += 2;
1807     FailIf(szSig != strstr(szSig, "II"), WMP_errUnsupportedFormat);
1808 
1809     Call(GetUShort(pWS, offPos, &uWmpID)); offPos += 2;
1810     FailIf(WMP_valWMPhotoID != (0x00FF & uWmpID), WMP_errUnsupportedFormat);
1811 
1812     // We accept version 00 and version 01 bitstreams - all others rejected
1813     bVersion = (0xFF00 & uWmpID) >> 8;
1814     FailIf(bVersion != 0 && bVersion != 1, WMP_errUnsupportedFormat);
1815 
1816     Call(GetULong(pWS, offPos, &offPFD)); offPos += 4;
1817 
1818     //================================
1819     // PFD
1820     offPos = (size_t)offPFD;
1821     Call(GetUShort(pWS, offPos, &cPFDEntry)); offPos += 2;
1822     FailIf(0 == cPFDEntry || USHRT_MAX == cPFDEntry, WMP_errUnsupportedFormat);
1823     Call(ParsePFD(pID, offPos, cPFDEntry));
1824 
1825     //================================
1826     Call(pWS->SetPos(pWS, pID->WMP.wmiDEMisc.uImageOffset));
1827 
1828 Cleanup:
1829     return err;
1830 }
1831 
1832 
1833 //================================================
PKImageDecode_Initialize_WMP(PKImageDecode * pID,struct WMPStream * pWS)1834 ERR PKImageDecode_Initialize_WMP(
1835     PKImageDecode* pID,
1836     struct WMPStream* pWS)
1837 {
1838     ERR err = WMP_errSuccess;
1839 
1840     CWMImageInfo* pII = NULL;
1841 
1842     //================================
1843     Call(PKImageDecode_Initialize(pID, pWS));
1844 
1845     //================================
1846     Call(ReadContainer(pID));
1847 
1848     //================================
1849     pID->WMP.wmiSCP.pWStream = pWS;
1850     pID->WMP.DecoderCurrMBRow = 0;
1851     pID->WMP.cLinesDecoded = 0;
1852     pID->WMP.cLinesCropped = 0;
1853     pID->WMP.fFirstNonZeroDecode = FALSE;
1854 
1855     FailIf(ICERR_OK != ImageStrDecGetInfo(&pID->WMP.wmiI, &pID->WMP.wmiSCP), WMP_errFail);
1856     assert(Y_ONLY <= pID->WMP.wmiSCP.cfColorFormat && pID->WMP.wmiSCP.cfColorFormat < CFT_MAX);
1857     assert(BD_SHORT == pID->WMP.wmiSCP.bdBitDepth || BD_LONG == pID->WMP.wmiSCP.bdBitDepth);
1858 
1859     // If HD Photo container provided an orientation, this should override bitstream orientation
1860     // If container did NOT provide an orientation, force O_NONE. This is to be consistent with
1861     // Vista behaviour, which is to ignore bitstream orientation (only looks at container).
1862     if (pID->WMP.fOrientationFromContainer)
1863     {
1864         pID->WMP.wmiI.oOrientation = pID->WMP.oOrientationFromContainer;
1865     }
1866     else
1867     {
1868         // Force to O_NONE to match Vista decode behaviour
1869         pID->WMP.wmiI.oOrientation = O_NONE;
1870     }
1871 
1872     pII = &pID->WMP.wmiI;
1873     pID->uWidth = (U32)pII->cWidth;
1874     pID->uHeight = (U32)pII->cHeight;
1875 
1876 Cleanup:
1877     return err;
1878 }
1879 
1880 
PKImageDecode_GetSize_WMP(PKImageDecode * pID,I32 * piWidth,I32 * piHeight)1881 ERR PKImageDecode_GetSize_WMP(
1882     PKImageDecode* pID,
1883     I32* piWidth,
1884     I32* piHeight)
1885 {
1886     if (pID->WMP.wmiI.oOrientation >= O_RCW)
1887     {
1888         *piWidth = (I32)pID->uHeight;
1889         *piHeight = (I32)pID->uWidth;
1890     }
1891     else
1892     {
1893         *piWidth = (I32)pID->uWidth;
1894         *piHeight = (I32)pID->uHeight;
1895     }
1896     return WMP_errSuccess;
1897 }
1898 
1899 
PKImageDecode_GetRawStream_WMP(PKImageDecode * pID,struct WMPStream ** ppWS)1900 ERR PKImageDecode_GetRawStream_WMP(
1901     PKImageDecode* pID,
1902     struct WMPStream** ppWS)
1903 {
1904     ERR err = WMP_errSuccess;
1905     struct WMPStream* pWS = pID->pStream;
1906 
1907     *ppWS = NULL;
1908     Call(pWS->SetPos(pWS, pID->WMP.wmiDEMisc.uImageOffset));
1909     *ppWS = pWS;
1910 
1911 Cleanup:
1912     return err;
1913 }
1914 
PKImageDecode_Copy_WMP(PKImageDecode * pID,const PKRect * pRect,U8 * pb,U32 cbStride)1915 ERR PKImageDecode_Copy_WMP(
1916     PKImageDecode* pID,
1917     const PKRect* pRect,
1918     U8* pb,
1919     U32 cbStride)
1920 {
1921     ERR err = WMP_errSuccess;
1922     U32 cThumbnailScale;
1923     U32 linesperMBRow;
1924     CWMImageBufferInfo wmiBI = { 0 };
1925 #ifdef REENTRANT_MODE
1926     U8 *pbLowMemAdj = NULL;
1927     U32 i, cMBRow;
1928     U32 cMBRowStart;
1929 #endif // REENTRANT_MODE
1930     struct WMPStream* pWS = pID->pStream;
1931     U8 tempAlphaMode = 0;
1932     wmiBI.pv = pb;
1933     wmiBI.cLine = pRect->Height;
1934     wmiBI.cbStride = cbStride;
1935 #ifdef REENTRANT_MODE
1936     // In REENTRANT_MODE, we allow rectangles with any top left corner (not just (0,0))
1937 #else
1938     FailIf(0 != pRect->X, WMP_errInvalidParameter);
1939     FailIf(0 != pRect->Y, WMP_errInvalidParameter);
1940 #endif // REENTRANT_MODE
1941 
1942     cThumbnailScale = 1;
1943 	if (pID->WMP.wmiI.cThumbnailWidth > 0)
1944 	{
1945 		while(cThumbnailScale * pID->WMP.wmiI.cThumbnailWidth < pID->uWidth)
1946 			cThumbnailScale <<= 1;
1947 	}
1948     // note the following implementation can't handle fractional linesperMBRow limiting
1949     // us to >= 1/256 thumbnail which is unfortunate, but all the PS plugin needs is 1/256
1950     // and I didn't care to get into floating point or a bunch of conditional tests or
1951     // other rewrite for a case not needed nor tested by PS plugin.  sorry.
1952     linesperMBRow = 16 / cThumbnailScale;
1953 
1954 #ifdef REENTRANT_MODE
1955     if (0 == pID->WMP.DecoderCurrMBRow)
1956     {
1957 #endif // REENTRANT_MODE
1958     // Set the fPaddedUserBuffer if the following conditions are met
1959     if (0 == ((size_t)pb % 128) &&    // Frame buffer is aligned to 128-byte boundary
1960         0 == (pRect->Height % 16) &&        // Horizontal resolution is multiple of 16
1961         0 == (pRect->Width % 16) &&        // Vertical resolution is multiple of 16
1962         0 == (cbStride % 128))              // Stride is a multiple of 128 bytes
1963     {
1964         pID->WMP.wmiI.fPaddedUserBuffer = TRUE;
1965         // Note that there are additional conditions in strdec_x86.c's strDecOpt
1966         // which could prevent optimization from being engaged
1967     }
1968 #ifdef REENTRANT_MODE
1969     }
1970 #endif // REENTRANT_MODE
1971     //if(pID->WMP.wmiSCP.uAlphaMode != 1)
1972     if((!pID->WMP.bHasAlpha) || (pID->WMP.wmiSCP.uAlphaMode != 1))
1973     {
1974         if(pID->WMP.bHasAlpha)//planar alpha
1975         {
1976             tempAlphaMode = pID->WMP.wmiSCP.uAlphaMode;
1977             pID->WMP.wmiSCP.uAlphaMode = 0;
1978         }
1979         pID->WMP.wmiSCP.fMeasurePerf = TRUE;
1980 #ifdef REENTRANT_MODE
1981         if (0 == pID->WMP.DecoderCurrMBRow)
1982         {
1983             Call(pID->WMP.wmiSCP.pWStream->GetPos(pID->WMP.wmiSCP.pWStream, &(pID->WMP.cMarker)));
1984             FailIf(ICERR_OK != ImageStrDecInit(&pID->WMP.wmiI, &pID->WMP.wmiSCP, &pID->WMP.ctxSC), WMP_errFail);
1985         }
1986         // Re-entrant mode incurs 1 MBR delay, so to get 0th MBR, we have to ask for 1st MBR
1987         cMBRow = ((U32) pID->WMP.cLinesCropped + pRect->Y + pRect->Height +
1988             (pRect->Y + pRect->Height >= (I32) pID->WMP.wmiI.cROIHeight ? linesperMBRow - 1 : 0)) / // round up if last MBR
1989             linesperMBRow + 1;
1990         cMBRowStart = ((U32) pID->WMP.cLinesCropped + pRect->Y) / linesperMBRow + 1;
1991         // if current request starts before current state, then rewind.
1992         if (cMBRowStart < pID->WMP.DecoderCurrMBRow)
1993         {
1994             pID->WMP.DecoderCurrMBRow = 0;
1995             pID->WMP.cLinesDecoded = 0;
1996             pID->WMP.cLinesCropped = 0;
1997             pID->WMP.fFirstNonZeroDecode = FALSE;
1998             FailIf(ICERR_OK != ImageStrDecTerm(pID->WMP.ctxSC), WMP_errFail);
1999             Call(pID->WMP.wmiSCP.pWStream->SetPos(pID->WMP.wmiSCP.pWStream, pID->WMP.cMarker));
2000             FailIf(ICERR_OK != ImageStrDecInit(&pID->WMP.wmiI, &pID->WMP.wmiSCP, &pID->WMP.ctxSC), WMP_errFail);
2001         }
2002 
2003         // In "Low Memory mode", we don't have full frame buffer. We therefore cannot rotate the image.
2004         // We can flip H, V and HV, but no rotations.
2005         FailIf(pID->WMP.wmiI.oOrientation >= O_RCW, WMP_errFail);
2006 
2007         // In low-memory mode, the full frame buffer is unavailable. This doesn't seem to
2008         // matter in O_NONE and O_FLIPH, but for O_FLIPV and O_FLIPVH, outputMBRow tries to write to
2009         // the bottom of full-frame buffer. Adjust the buffer pointer to compensate.
2010         if (O_FLIPV == pID->WMP.wmiI.oOrientation || O_FLIPVH == pID->WMP.wmiI.oOrientation)
2011         {
2012             I32 iActualY2 = pRect->Y + pRect->Height;
2013             pbLowMemAdj = pb - (pID->WMP.wmiI.cROIHeight - (iActualY2 - pID->WMP.cLinesCropped)) * cbStride;
2014         }
2015         else
2016         {
2017             pbLowMemAdj = pb - pRect->Y * cbStride;
2018         }
2019         wmiBI.pv = pbLowMemAdj;
2020 
2021         for (i = (U32)pID->WMP.DecoderCurrMBRow; i < cMBRow; i++)
2022         {
2023             size_t cLinesDecoded;
2024             wmiBI.uiFirstMBRow = i;
2025             wmiBI.uiLastMBRow = i;
2026             FailIf(ICERR_OK != ImageStrDecDecode(pID->WMP.ctxSC, &wmiBI, &cLinesDecoded), WMP_errFail);
2027             pID->WMP.cLinesDecoded = cLinesDecoded;
2028             if (FALSE == pID->WMP.fFirstNonZeroDecode && cLinesDecoded > 0)
2029             {
2030                 pID->WMP.cLinesCropped += (linesperMBRow - cLinesDecoded);
2031                 pID->WMP.fFirstNonZeroDecode = TRUE;
2032                 // update cMBRow if partial MB row cropped
2033                 cMBRow = ((U32) pID->WMP.cLinesCropped + pRect->Y + pRect->Height +
2034                     (pRect->Y + pRect->Height >= (I32) pID->WMP.wmiI.cROIHeight ? linesperMBRow - 1 : 0)) / // round up if last MBR
2035                     linesperMBRow + 1;
2036             }
2037 
2038             if (0 == cLinesDecoded && i > 0)
2039             {
2040                 pID->WMP.cLinesCropped += linesperMBRow;
2041                 // update cMBRow if whole MB row cropped
2042                 cMBRow++;
2043             }
2044         }
2045         wmiBI.pv = pbLowMemAdj;
2046 
2047         // If we're past the top of the image, then we're done, so terminate.
2048         if (linesperMBRow * (cMBRow - 1) >= (U32) pID->WMP.cLinesCropped + pID->WMP.wmiI.cROIHeight) {
2049             FailIf(ICERR_OK != ImageStrDecTerm(pID->WMP.ctxSC), WMP_errFail);
2050         }
2051         pID->WMP.DecoderCurrMBRow = cMBRow; // Set to next possible MBRow that is decodable
2052 
2053 #else
2054         FailIf(ICERR_OK != ImageStrDecInit(&pID->WMP.wmiI, &pID->WMP.wmiSCP, &pID->WMP.ctxSC), WMP_errFail);
2055         FailIf(ICERR_OK != ImageStrDecDecode(pID->WMP.ctxSC, &wmiBI), WMP_errFail);
2056         FailIf(ICERR_OK != ImageStrDecTerm(pID->WMP.ctxSC), WMP_errFail);
2057 #endif //REENTRANT_MODE
2058 
2059         if(pID->WMP.bHasAlpha)//planar alpha
2060         {
2061             pID->WMP.wmiSCP.uAlphaMode = tempAlphaMode;
2062         }
2063     }
2064 
2065 //    if(pID->WMP.bHasAlpha && pID->WMP.wmiSCP.uAlphaMode == 2)
2066 //    if(pID->WMP.bHasAlpha && pID->WMP.wmiSCP.uAlphaMode != 1)
2067     if(pID->WMP.bHasAlpha && pID->WMP.wmiSCP.uAlphaMode != 0)
2068     {
2069         pID->WMP.wmiI_Alpha = pID->WMP.wmiI;
2070         pID->WMP.wmiSCP_Alpha = pID->WMP.wmiSCP;
2071 
2072 //        assert(pID->WMP.wmiI_Alpha.cfColorFormat == CF_RGB); // only RGBA is supported for now!
2073         pID->WMP.wmiI_Alpha.cfColorFormat = Y_ONLY;
2074 
2075         switch (pID->WMP.wmiI.bdBitDepth)
2076         {
2077             case BD_8:
2078                 pID->WMP.wmiI_Alpha.cLeadingPadding += (pID->WMP.wmiI.cBitsPerUnit >> 3) - 1;
2079                 break;
2080 
2081             case BD_16:
2082             case BD_16S:
2083             case BD_16F:
2084                 pID->WMP.wmiI_Alpha.cLeadingPadding += (pID->WMP.wmiI.cBitsPerUnit >> 3) / sizeof(U16) - 1;
2085                 break;
2086 
2087             case BD_32:
2088             case BD_32S:
2089             case BD_32F:
2090                 pID->WMP.wmiI_Alpha.cLeadingPadding += (pID->WMP.wmiI.cBitsPerUnit >> 3) / sizeof(float) - 1;
2091                 break;
2092 
2093             case BD_5:
2094             case BD_10:
2095             case BD_565:
2096             default:
2097                 break;
2098         }
2099 
2100         pID->WMP.wmiSCP_Alpha.fMeasurePerf = TRUE;
2101         Call(pWS->SetPos(pWS, pID->WMP.wmiDEMisc.uAlphaOffset));
2102 #ifdef REENTRANT_MODE
2103         if (0 == pID->WMP.DecoderCurrAlphaMBRow) // add this to WMP struct!
2104         {
2105             FailIf(ICERR_OK != ImageStrDecInit(&pID->WMP.wmiI_Alpha, &pID->WMP.wmiSCP_Alpha, &pID->WMP.ctxSC_Alpha), WMP_errFail);
2106         }
2107 
2108         // Re-entrant mode incurs 1 MBR delay, so to get 0th MBR, we have to ask for 1st MBR
2109         cMBRow = ((U32) pID->WMP.cLinesCropped + pRect->Y + pRect->Height +
2110             (pRect->Y + pRect->Height >= (I32) pID->WMP.wmiI.cROIHeight ? linesperMBRow - 1 : 0)) / // round up if last MBR
2111             linesperMBRow + 1;
2112         cMBRowStart = ((U32) pID->WMP.cLinesCropped + pRect->Y) / linesperMBRow + 1;
2113         // if current request starts before current state, then rewind.
2114         if (cMBRowStart < pID->WMP.DecoderCurrAlphaMBRow)
2115         {
2116             pID->WMP.DecoderCurrAlphaMBRow = 0;
2117             FailIf(ICERR_OK != ImageStrDecTerm(pID->WMP.ctxSC_Alpha), WMP_errFail);
2118             FailIf(ICERR_OK != ImageStrDecInit(&pID->WMP.wmiI_Alpha, &pID->WMP.wmiSCP_Alpha, &pID->WMP.ctxSC_Alpha), WMP_errFail);
2119         }
2120 
2121         for (i = (U32)pID->WMP.DecoderCurrAlphaMBRow; i < cMBRow; i++)
2122         {
2123             size_t cLinesDecoded;
2124             wmiBI.uiFirstMBRow = i;
2125             wmiBI.uiLastMBRow = i;
2126             FailIf(ICERR_OK != ImageStrDecDecode(pID->WMP.ctxSC_Alpha, &wmiBI, &cLinesDecoded), WMP_errFail);
2127         }
2128 
2129         // If we're past the top of the image, then we're done, so terminate
2130         if (linesperMBRow * (cMBRow - 1) >= (U32) pID->WMP.cLinesCropped + pID->WMP.wmiI.cROIHeight) {
2131             FailIf(ICERR_OK != ImageStrDecTerm(pID->WMP.ctxSC_Alpha), WMP_errFail);
2132         }
2133         pID->WMP.DecoderCurrAlphaMBRow = cMBRow; // Set to next possible MBRow that is decodable
2134         wmiBI.pv = pb;
2135 #else
2136         FailIf(ICERR_OK != ImageStrDecInit(&pID->WMP.wmiI_Alpha, &pID->WMP.wmiSCP_Alpha, &pID->WMP.ctxSC_Alpha), WMP_errFail);
2137         FailIf(ICERR_OK != ImageStrDecDecode(pID->WMP.ctxSC_Alpha, &wmiBI), WMP_errFail);
2138         FailIf(ICERR_OK != ImageStrDecTerm(pID->WMP.ctxSC_Alpha), WMP_errFail);
2139 #endif //REENTRANT_MODE
2140     }
2141 
2142     pID->idxCurrentLine += pRect->Height;
2143 
2144 Cleanup:
2145     return err;
2146 }
2147 
2148 
PKImageDecode_GetMetadata_WMP(PKImageDecode * pID,U32 uOffset,U32 uByteCount,U8 * pbGot,U32 * pcbGot)2149 ERR PKImageDecode_GetMetadata_WMP(PKImageDecode *pID, U32 uOffset, U32 uByteCount, U8 *pbGot, U32 *pcbGot)
2150 {
2151     ERR err = WMP_errSuccess;
2152 
2153     if (pbGot && uOffset)
2154     {
2155         struct WMPStream* pWS = pID->pStream;
2156         size_t iCurrPos;
2157 
2158         FailIf(*pcbGot < uByteCount, WMP_errBufferOverflow);
2159         Call(pWS->GetPos(pWS, &iCurrPos));
2160         Call(pWS->SetPos(pWS, uOffset));
2161         Call(pWS->Read(pWS, pbGot, uByteCount));
2162         Call(pWS->SetPos(pWS, iCurrPos));
2163     }
2164 
2165 Cleanup:
2166     if (Failed(err))
2167         *pcbGot = 0;
2168     else
2169         *pcbGot = uByteCount;
2170 
2171     return err;
2172 }
2173 
2174 
2175 
PKImageDecode_GetColorContext_WMP(PKImageDecode * pID,U8 * pbColorContext,U32 * pcbColorContext)2176 ERR PKImageDecode_GetColorContext_WMP(PKImageDecode *pID, U8 *pbColorContext, U32 *pcbColorContext)
2177 {
2178     return PKImageDecode_GetMetadata_WMP(pID, pID->WMP.wmiDEMisc.uColorProfileOffset,
2179         pID->WMP.wmiDEMisc.uColorProfileByteCount, pbColorContext, pcbColorContext);
2180 }
2181 
2182 
2183 
PKImageDecode_GetDescriptiveMetadata_WMP(PKImageDecode * pID,DESCRIPTIVEMETADATA * pDescMetadata)2184 ERR PKImageDecode_GetDescriptiveMetadata_WMP(PKImageDecode *pID, DESCRIPTIVEMETADATA *pDescMetadata)
2185 {
2186     ERR err = WMP_errSuccess;
2187     *pDescMetadata = pID->WMP.sDescMetadata;
2188     return err;
2189 }
2190 
2191 
PKImageDecode_Release_WMP(PKImageDecode ** ppID)2192 ERR PKImageDecode_Release_WMP(PKImageDecode** ppID)
2193 {
2194     ERR             err = WMP_errSuccess;
2195     PKImageDecode  *pID;
2196 
2197     if (NULL == ppID)
2198         goto Cleanup;
2199 
2200     pID = *ppID;
2201 
2202     // Free descriptive metadata
2203     FreeDescMetadata(&pID->WMP.sDescMetadata.pvarImageDescription);
2204     FreeDescMetadata(&pID->WMP.sDescMetadata.pvarCameraMake);
2205     FreeDescMetadata(&pID->WMP.sDescMetadata.pvarCameraModel);
2206     FreeDescMetadata(&pID->WMP.sDescMetadata.pvarSoftware);
2207     FreeDescMetadata(&pID->WMP.sDescMetadata.pvarDateTime);
2208     FreeDescMetadata(&pID->WMP.sDescMetadata.pvarArtist);
2209     FreeDescMetadata(&pID->WMP.sDescMetadata.pvarCopyright);
2210     FreeDescMetadata(&pID->WMP.sDescMetadata.pvarRatingStars);
2211     FreeDescMetadata(&pID->WMP.sDescMetadata.pvarRatingValue);
2212     FreeDescMetadata(&pID->WMP.sDescMetadata.pvarCaption);
2213     FreeDescMetadata(&pID->WMP.sDescMetadata.pvarDocumentName);
2214     FreeDescMetadata(&pID->WMP.sDescMetadata.pvarPageName);
2215     FreeDescMetadata(&pID->WMP.sDescMetadata.pvarPageNumber);
2216     FreeDescMetadata(&pID->WMP.sDescMetadata.pvarHostComputer);
2217 
2218     // Release base class
2219     Call(PKImageDecode_Release(ppID));
2220 
2221 Cleanup:
2222     return err;
2223 }
2224 
2225 
2226 
PKImageDecode_Create_WMP(PKImageDecode ** ppID)2227 ERR PKImageDecode_Create_WMP(PKImageDecode** ppID)
2228 {
2229     ERR err = WMP_errSuccess;
2230     PKImageDecode* pID = NULL;
2231 
2232     Call(PKImageDecode_Create(ppID));
2233 
2234     pID = *ppID;
2235     pID->Initialize = PKImageDecode_Initialize_WMP;
2236     pID->GetSize = PKImageDecode_GetSize_WMP;
2237     pID->GetRawStream = PKImageDecode_GetRawStream_WMP;
2238     pID->Copy = PKImageDecode_Copy_WMP;
2239     pID->GetColorContext = PKImageDecode_GetColorContext_WMP;
2240     pID->GetDescriptiveMetadata = PKImageDecode_GetDescriptiveMetadata_WMP;
2241     pID->Release = PKImageDecode_Release_WMP;
2242 
2243 Cleanup:
2244     return err;
2245 }
2246 
2247