2 * Copyright 2016 Andrew Eikum for CodeWeavers
3 * Copyright 2017 Dmitry Timoshkov
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #define NONAMELESSUNION
30 #include "propvarutil.h"
32 #include "wincodecs_private.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs
);
38 static const WCHAR
*map_shortname_to_schema(const GUID
*format
, const WCHAR
*name
);
41 IWICMetadataQueryReader IWICMetadataQueryReader_iface
;
43 IWICMetadataBlockReader
*block
;
47 static inline QueryReader
*impl_from_IWICMetadataQueryReader(IWICMetadataQueryReader
*iface
)
49 return CONTAINING_RECORD(iface
, QueryReader
, IWICMetadataQueryReader_iface
);
52 static HRESULT WINAPI
mqr_QueryInterface(IWICMetadataQueryReader
*iface
, REFIID riid
,
55 QueryReader
*This
= impl_from_IWICMetadataQueryReader(iface
);
57 TRACE("(%p,%s,%p)\n", This
, debugstr_guid(riid
), ppvObject
);
59 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
60 IsEqualGUID(riid
, &IID_IWICMetadataQueryReader
))
61 *ppvObject
= &This
->IWICMetadataQueryReader_iface
;
67 IUnknown_AddRef((IUnknown
*)*ppvObject
);
74 static ULONG WINAPI
mqr_AddRef(IWICMetadataQueryReader
*iface
)
76 QueryReader
*This
= impl_from_IWICMetadataQueryReader(iface
);
77 ULONG ref
= InterlockedIncrement(&This
->ref
);
78 TRACE("(%p) refcount=%u\n", This
, ref
);
82 static ULONG WINAPI
mqr_Release(IWICMetadataQueryReader
*iface
)
84 QueryReader
*This
= impl_from_IWICMetadataQueryReader(iface
);
85 ULONG ref
= InterlockedDecrement(&This
->ref
);
86 TRACE("(%p) refcount=%u\n", This
, ref
);
89 IWICMetadataBlockReader_Release(This
->block
);
90 HeapFree(GetProcessHeap(), 0, This
->root
);
91 HeapFree(GetProcessHeap(), 0, This
);
96 static HRESULT WINAPI
mqr_GetContainerFormat(IWICMetadataQueryReader
*iface
, GUID
*format
)
98 QueryReader
*This
= impl_from_IWICMetadataQueryReader(iface
);
100 TRACE("(%p,%p)\n", This
, format
);
102 return IWICMetadataBlockReader_GetContainerFormat(This
->block
, format
);
105 static HRESULT WINAPI
mqr_GetLocation(IWICMetadataQueryReader
*iface
, UINT len
, WCHAR
*location
, UINT
*ret_len
)
107 static const WCHAR rootW
[] = { '/',0 };
108 QueryReader
*This
= impl_from_IWICMetadataQueryReader(iface
);
112 TRACE("(%p,%u,%p,%p)\n", This
, len
, location
, ret_len
);
114 if (!ret_len
) return E_INVALIDARG
;
116 root
= This
->root
? This
->root
: rootW
;
117 actual_len
= lstrlenW(root
) + 1;
121 if (len
< actual_len
)
122 return WINCODEC_ERR_INSUFFICIENTBUFFER
;
124 memcpy(location
, root
, actual_len
* sizeof(WCHAR
));
127 *ret_len
= actual_len
;
145 { 4, {'c','h','a','r'}, VT_I1
},
146 { 5, {'u','c','h','a','r'}, VT_UI1
},
147 { 5, {'s','h','o','r','t'}, VT_I2
},
148 { 6, {'u','s','h','o','r','t'}, VT_UI2
},
149 { 4, {'l','o','n','g'}, VT_I4
},
150 { 5, {'u','l','o','n','g'}, VT_UI4
},
151 { 3, {'i','n','t'}, VT_I4
},
152 { 4, {'u','i','n','t'}, VT_UI4
},
153 { 8, {'l','o','n','g','l','o','n','g'}, VT_I8
},
154 { 9, {'u','l','o','n','g','l','o','n','g'}, VT_UI8
},
155 { 5, {'f','l','o','a','t'}, VT_R4
},
156 { 6, {'d','o','u','b','l','e'}, VT_R8
},
157 { 3, {'s','t','r'}, VT_LPSTR
},
158 { 4, {'w','s','t','r'}, VT_LPWSTR
},
159 { 4, {'g','u','i','d'}, VT_CLSID
},
160 { 4, {'b','o','o','l'}, VT_BOOL
}
163 static VARTYPE
map_type(struct string_t
*str
)
167 for (i
= 0; i
< ARRAY_SIZE(str2vt
); i
++)
169 if (str2vt
[i
].len
== str
->len
)
171 if (CompareStringW(LOCALE_SYSTEM_DEFAULT
, NORM_IGNORECASE
,
172 str
->str
, str
->len
, str2vt
[i
].str
, str2vt
[i
].len
) == CSTR_EQUAL
)
177 WARN("type %s is not recognized\n", wine_dbgstr_wn(str
->str
, str
->len
));
182 static HRESULT
get_token(struct string_t
*elem
, PROPVARIANT
*id
, PROPVARIANT
*schema
, int *idx
)
184 const WCHAR
*start
, *end
, *p
;
186 struct string_t next_elem
;
189 TRACE("%s, len %d\n", wine_dbgstr_wn(elem
->str
, elem
->len
), elem
->len
);
192 PropVariantInit(schema
);
194 if (!elem
->len
) return S_OK
;
202 if (start
[1] < '0' || start
[1] > '9') return DISP_E_TYPEMISMATCH
;
204 *idx
= strtolW(start
+ 1, &idx_end
, 10);
205 if (idx_end
> elem
->str
+ elem
->len
) return WINCODEC_ERR_INVALIDQUERYREQUEST
;
206 if (*idx_end
!= ']') return WINCODEC_ERR_INVALIDQUERYREQUEST
;
207 if (*idx
< 0) return WINCODEC_ERR_INVALIDQUERYREQUEST
;
211 next_elem
.len
= elem
->len
- (end
- start
);
212 hr
= get_token(&next_elem
, id
, schema
, idx
);
215 TRACE("get_token error %#x\n", hr
);
218 elem
->len
= (end
- start
) + next_elem
.len
;
220 TRACE("indexed %s [%d]\n", wine_dbgstr_wn(elem
->str
, elem
->len
), *idx
);
223 else if (*start
== '{')
226 PROPVARIANT next_token
;
228 end
= memchrW(start
+ 1, '=', elem
->len
- 1);
229 if (!end
) return WINCODEC_ERR_INVALIDQUERYREQUEST
;
230 if (end
> elem
->str
+ elem
->len
) return WINCODEC_ERR_INVALIDQUERYREQUEST
;
232 next_elem
.str
= start
+ 1;
233 next_elem
.len
= end
- start
- 1;
234 vt
= map_type(&next_elem
);
235 TRACE("type %s => %d\n", wine_dbgstr_wn(next_elem
.str
, next_elem
.len
), vt
);
236 if (vt
== VT_ILLEGAL
) return WINCODEC_ERR_WRONGSTATE
;
238 next_token
.vt
= VT_BSTR
;
239 next_token
.u
.bstrVal
= SysAllocStringLen(NULL
, elem
->len
- (end
- start
) + 1);
240 if (!next_token
.u
.bstrVal
) return E_OUTOFMEMORY
;
242 bstr
= next_token
.u
.bstrVal
;
245 while (*end
&& *end
!= '}' && end
- start
< elem
->len
)
247 if (*end
== '\\') end
++;
252 PropVariantClear(&next_token
);
253 return WINCODEC_ERR_INVALIDQUERYREQUEST
;
256 TRACE("schema/id %s\n", wine_dbgstr_w(next_token
.u
.bstrVal
));
261 id
->u
.puuid
= CoTaskMemAlloc(sizeof(GUID
));
264 PropVariantClear(&next_token
);
265 return E_OUTOFMEMORY
;
268 hr
= UuidFromStringW(next_token
.u
.bstrVal
, id
->u
.puuid
);
271 hr
= PropVariantChangeType(id
, &next_token
, 0, vt
);
272 PropVariantClear(&next_token
);
275 PropVariantClear(id
);
276 PropVariantClear(schema
);
283 PROPVARIANT next_id
, next_schema
;
286 next_elem
.str
= end
+ 1;
287 next_elem
.len
= elem
->len
- (end
- start
+ 1);
288 hr
= get_token(&next_elem
, &next_id
, &next_schema
, &next_idx
);
291 TRACE("get_token error %#x\n", hr
);
294 elem
->len
= (end
- start
+ 1) + next_elem
.len
;
296 TRACE("id %s [%d]\n", wine_dbgstr_wn(elem
->str
, elem
->len
), *idx
);
298 if (next_schema
.vt
!= VT_EMPTY
)
300 PropVariantClear(&next_id
);
301 PropVariantClear(&next_schema
);
302 return WINCODEC_ERR_WRONGSTATE
;
311 elem
->len
= end
- start
;
315 end
= memchrW(start
, '/', elem
->len
);
316 if (!end
) end
= start
+ elem
->len
;
318 p
= memchrW(start
, ':', end
- start
);
321 next_elem
.str
= p
+ 1;
322 next_elem
.len
= end
- p
- 1;
324 elem
->len
= p
- start
;
327 elem
->len
= end
- start
;
330 id
->u
.bstrVal
= SysAllocStringLen(NULL
, elem
->len
+ 1);
331 if (!id
->u
.bstrVal
) return E_OUTOFMEMORY
;
333 bstr
= id
->u
.bstrVal
;
335 while (p
- elem
->str
< elem
->len
)
341 TRACE("%s [%d]\n", wine_dbgstr_variant((VARIANT
*)id
), *idx
);
345 PROPVARIANT next_id
, next_schema
;
348 hr
= get_token(&next_elem
, &next_id
, &next_schema
, &next_idx
);
351 TRACE("get_token error %#x\n", hr
);
352 PropVariantClear(id
);
353 PropVariantClear(schema
);
356 elem
->len
+= next_elem
.len
+ 1;
358 TRACE("id %s [%d]\n", wine_dbgstr_wn(elem
->str
, elem
->len
), *idx
);
360 if (next_schema
.vt
!= VT_EMPTY
)
362 PropVariantClear(&next_id
);
363 PropVariantClear(&next_schema
);
364 PropVariantClear(id
);
365 PropVariantClear(schema
);
366 return WINCODEC_ERR_WRONGSTATE
;
376 static HRESULT
find_reader_from_block(IWICMetadataBlockReader
*block_reader
, UINT index
,
377 GUID
*guid
, IWICMetadataReader
**reader
)
381 IWICMetadataReader
*new_reader
;
382 UINT count
, i
, matched_index
;
386 hr
= IWICMetadataBlockReader_GetCount(block_reader
, &count
);
387 if (hr
!= S_OK
) return hr
;
391 for (i
= 0; i
< count
; i
++)
393 hr
= IWICMetadataBlockReader_GetReaderByIndex(block_reader
, i
, &new_reader
);
394 if (hr
!= S_OK
) return hr
;
396 hr
= IWICMetadataReader_GetMetadataFormat(new_reader
, &format
);
399 if (IsEqualGUID(&format
, guid
))
401 if (matched_index
== index
)
403 *reader
= new_reader
;
411 IWICMetadataReader_Release(new_reader
);
412 if (hr
!= S_OK
) return hr
;
415 return WINCODEC_ERR_PROPERTYNOTFOUND
;
418 static HRESULT
get_next_reader(IWICMetadataReader
*reader
, UINT index
,
419 GUID
*guid
, IWICMetadataReader
**new_reader
)
422 PROPVARIANT schema
, id
, value
;
426 PropVariantInit(&schema
);
427 PropVariantInit(&id
);
428 PropVariantInit(&value
);
433 schema
.u
.uiVal
= index
;
438 hr
= IWICMetadataReader_GetValue(reader
, &schema
, &id
, &value
);
439 if (hr
!= S_OK
) return hr
;
441 if (value
.vt
== VT_UNKNOWN
)
442 hr
= IUnknown_QueryInterface(value
.u
.punkVal
, &IID_IWICMetadataReader
, (void **)new_reader
);
444 hr
= WINCODEC_ERR_UNEXPECTEDMETADATATYPE
;
446 PropVariantClear(&value
);
450 static HRESULT WINAPI
mqr_GetMetadataByName(IWICMetadataQueryReader
*iface
, LPCWSTR query
, PROPVARIANT
*value
)
452 QueryReader
*This
= impl_from_IWICMetadataQueryReader(iface
);
453 struct string_t elem
;
457 PROPVARIANT tk_id
, tk_schema
, new_value
;
459 IWICMetadataReader
*reader
;
462 TRACE("(%p,%s,%p)\n", This
, wine_dbgstr_w(query
), value
);
464 len
= lstrlenW(query
) + 1;
465 if (This
->root
) len
+= lstrlenW(This
->root
);
466 full_query
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
469 lstrcpyW(full_query
, This
->root
);
470 lstrcatW(full_query
, query
);
472 PropVariantInit(&tk_id
);
473 PropVariantInit(&tk_schema
);
474 PropVariantInit(&new_value
);
483 WARN("query should start with '/'\n");
484 hr
= WINCODEC_ERR_PROPERTYNOTSUPPORTED
;
492 elem
.len
= lstrlenW(p
);
493 hr
= get_token(&elem
, &tk_id
, &tk_schema
, &index
);
496 WARN("get_token error %#x\n", hr
);
499 TRACE("parsed %d characters: %s, index %d\n", elem
.len
, wine_dbgstr_wn(elem
.str
, elem
.len
), index
);
500 TRACE("id %s, schema %s\n", wine_dbgstr_variant((VARIANT
*)&tk_id
), wine_dbgstr_variant((VARIANT
*)&tk_schema
));
502 if (!elem
.len
) break;
504 if (tk_id
.vt
== VT_CLSID
|| (tk_id
.vt
== VT_BSTR
&& WICMapShortNameToGuid(tk_id
.u
.bstrVal
, &guid
) == S_OK
))
508 if (tk_schema
.vt
!= VT_EMPTY
)
510 FIXME("unsupported schema vt %u\n", tk_schema
.vt
);
511 PropVariantClear(&tk_schema
);
514 if (tk_id
.vt
== VT_CLSID
) guid
= *tk_id
.u
.puuid
;
518 IWICMetadataReader
*new_reader
;
520 hr
= get_next_reader(reader
, index
, &guid
, &new_reader
);
521 IWICMetadataReader_Release(reader
);
525 hr
= find_reader_from_block(This
->block
, index
, &guid
, &reader
);
527 if (hr
!= S_OK
) break;
529 root
= SysAllocStringLen(NULL
, elem
.str
+ elem
.len
- full_query
+ 2);
535 lstrcpynW(root
, full_query
, p
- full_query
+ elem
.len
+ 1);
537 PropVariantClear(&new_value
);
538 new_value
.vt
= VT_UNKNOWN
;
539 hr
= MetadataQueryReader_CreateInstance(This
->block
, root
, (IWICMetadataQueryReader
**)&new_value
.u
.punkVal
);
541 if (hr
!= S_OK
) break;
545 PROPVARIANT schema
, id
;
549 hr
= WINCODEC_ERR_INVALIDQUERYREQUEST
;
553 if (tk_schema
.vt
== VT_BSTR
)
555 hr
= IWICMetadataReader_GetMetadataFormat(reader
, &guid
);
556 if (hr
!= S_OK
) break;
558 schema
.vt
= VT_LPWSTR
;
559 schema
.u
.pwszVal
= (LPWSTR
)map_shortname_to_schema(&guid
, tk_schema
.u
.bstrVal
);
560 if (!schema
.u
.pwszVal
)
561 schema
.u
.pwszVal
= tk_schema
.u
.bstrVal
;
566 if (tk_id
.vt
== VT_BSTR
)
569 id
.u
.pwszVal
= tk_id
.u
.bstrVal
;
574 PropVariantClear(&new_value
);
575 hr
= IWICMetadataReader_GetValue(reader
, &schema
, &id
, &new_value
);
576 if (hr
!= S_OK
) break;
581 PropVariantClear(&tk_id
);
582 PropVariantClear(&tk_schema
);
586 IWICMetadataReader_Release(reader
);
588 PropVariantClear(&tk_id
);
589 PropVariantClear(&tk_schema
);
591 if (hr
== S_OK
&& value
)
594 PropVariantClear(&new_value
);
596 HeapFree(GetProcessHeap(), 0, full_query
);
601 static HRESULT WINAPI
mqr_GetEnumerator(IWICMetadataQueryReader
*iface
,
602 IEnumString
**ppIEnumString
)
604 QueryReader
*This
= impl_from_IWICMetadataQueryReader(iface
);
605 FIXME("(%p,%p)\n", This
, ppIEnumString
);
609 static IWICMetadataQueryReaderVtbl mqr_vtbl
= {
613 mqr_GetContainerFormat
,
615 mqr_GetMetadataByName
,
619 HRESULT
MetadataQueryReader_CreateInstance(IWICMetadataBlockReader
*mbr
, const WCHAR
*root
, IWICMetadataQueryReader
**out
)
623 obj
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*obj
));
625 return E_OUTOFMEMORY
;
627 obj
->IWICMetadataQueryReader_iface
.lpVtbl
= &mqr_vtbl
;
630 IWICMetadataBlockReader_AddRef(mbr
);
633 obj
->root
= root
? heap_strdupW(root
) : NULL
;
635 *out
= &obj
->IWICMetadataQueryReader_iface
;
640 static const WCHAR bmpW
[] = { 'b','m','p',0 };
641 static const WCHAR pngW
[] = { 'p','n','g',0 };
642 static const WCHAR icoW
[] = { 'i','c','o',0 };
643 static const WCHAR jpgW
[] = { 'j','p','g',0 };
644 static const WCHAR tiffW
[] = { 't','i','f','f',0 };
645 static const WCHAR gifW
[] = { 'g','i','f',0 };
646 static const WCHAR wmphotoW
[] = { 'w','m','p','h','o','t','o',0 };
647 static const WCHAR unknownW
[] = { 'u','n','k','n','o','w','n',0 };
648 static const WCHAR ifdW
[] = { 'i','f','d',0 };
649 static const WCHAR subW
[] = { 's','u','b',0 };
650 static const WCHAR exifW
[] = { 'e','x','i','f',0 };
651 static const WCHAR gpsW
[] = { 'g','p','s',0 };
652 static const WCHAR interopW
[] = { 'i','n','t','e','r','o','p',0 };
653 static const WCHAR app0W
[] = { 'a','p','p','0',0 };
654 static const WCHAR app1W
[] = { 'a','p','p','1',0 };
655 static const WCHAR app13W
[] = { 'a','p','p','1','3',0 };
656 static const WCHAR iptcW
[] = { 'i','p','t','c',0 };
657 static const WCHAR irbW
[] = { 'i','r','b',0 };
658 static const WCHAR _8bimiptcW
[] = { '8','b','i','m','i','p','t','c',0 };
659 static const WCHAR _8bimResInfoW
[] = { '8','b','i','m','R','e','s','I','n','f','o',0 };
660 static const WCHAR _8bimiptcdigestW
[] = { '8','b','i','m','i','p','t','c','d','i','g','e','s','t',0 };
661 static const WCHAR xmpW
[] = { 'x','m','p',0 };
662 static const WCHAR thumbW
[] = { 't','h','u','m','b',0 };
663 static const WCHAR tEXtW
[] = { 't','E','X','t',0 };
664 static const WCHAR xmpstructW
[] = { 'x','m','p','s','t','r','u','c','t',0 };
665 static const WCHAR xmpbagW
[] = { 'x','m','p','b','a','g',0 };
666 static const WCHAR xmpseqW
[] = { 'x','m','p','s','e','q',0 };
667 static const WCHAR xmpaltW
[] = { 'x','m','p','a','l','t',0 };
668 static const WCHAR logscrdescW
[] = { 'l','o','g','s','c','r','d','e','s','c',0 };
669 static const WCHAR imgdescW
[] = { 'i','m','g','d','e','s','c',0 };
670 static const WCHAR grctlextW
[] = { 'g','r','c','t','l','e','x','t',0 };
671 static const WCHAR appextW
[] = { 'a','p','p','e','x','t',0 };
672 static const WCHAR chrominanceW
[] = { 'c','h','r','o','m','i','n','a','n','c','e',0 };
673 static const WCHAR luminanceW
[] = { 'l','u','m','i','n','a','n','c','e',0 };
674 static const WCHAR comW
[] = { 'c','o','m',0 };
675 static const WCHAR commentextW
[] = { 'c','o','m','m','e','n','t','e','x','t',0 };
676 static const WCHAR gAMAW
[] = { 'g','A','M','A',0 };
677 static const WCHAR bKGDW
[] = { 'b','K','G','D',0 };
678 static const WCHAR iTXtW
[] = { 'i','T','X','t',0 };
679 static const WCHAR cHRMW
[] = { 'c','H','R','M',0 };
680 static const WCHAR hISTW
[] = { 'h','I','S','T',0 };
681 static const WCHAR iCCPW
[] = { 'i','C','C','P',0 };
682 static const WCHAR sRGBW
[] = { 's','R','G','B',0 };
683 static const WCHAR tIMEW
[] = { 't','I','M','E',0 };
691 { &GUID_ContainerFormatBmp
, bmpW
},
692 { &GUID_ContainerFormatPng
, pngW
},
693 { &GUID_ContainerFormatIco
, icoW
},
694 { &GUID_ContainerFormatJpeg
, jpgW
},
695 { &GUID_ContainerFormatTiff
, tiffW
},
696 { &GUID_ContainerFormatGif
, gifW
},
697 { &GUID_ContainerFormatWmp
, wmphotoW
},
698 { &GUID_MetadataFormatUnknown
, unknownW
},
699 { &GUID_MetadataFormatIfd
, ifdW
},
700 { &GUID_MetadataFormatSubIfd
, subW
},
701 { &GUID_MetadataFormatExif
, exifW
},
702 { &GUID_MetadataFormatGps
, gpsW
},
703 { &GUID_MetadataFormatInterop
, interopW
},
704 { &GUID_MetadataFormatApp0
, app0W
},
705 { &GUID_MetadataFormatApp1
, app1W
},
706 { &GUID_MetadataFormatApp13
, app13W
},
707 { &GUID_MetadataFormatIPTC
, iptcW
},
708 { &GUID_MetadataFormatIRB
, irbW
},
709 { &GUID_MetadataFormat8BIMIPTC
, _8bimiptcW
},
710 { &GUID_MetadataFormat8BIMResolutionInfo
, _8bimResInfoW
},
711 { &GUID_MetadataFormat8BIMIPTCDigest
, _8bimiptcdigestW
},
712 { &GUID_MetadataFormatXMP
, xmpW
},
713 { &GUID_MetadataFormatThumbnail
, thumbW
},
714 { &GUID_MetadataFormatChunktEXt
, tEXtW
},
715 { &GUID_MetadataFormatXMPStruct
, xmpstructW
},
716 { &GUID_MetadataFormatXMPBag
, xmpbagW
},
717 { &GUID_MetadataFormatXMPSeq
, xmpseqW
},
718 { &GUID_MetadataFormatXMPAlt
, xmpaltW
},
719 { &GUID_MetadataFormatLSD
, logscrdescW
},
720 { &GUID_MetadataFormatIMD
, imgdescW
},
721 { &GUID_MetadataFormatGCE
, grctlextW
},
722 { &GUID_MetadataFormatAPE
, appextW
},
723 { &GUID_MetadataFormatJpegChrominance
, chrominanceW
},
724 { &GUID_MetadataFormatJpegLuminance
, luminanceW
},
725 { &GUID_MetadataFormatJpegComment
, comW
},
726 { &GUID_MetadataFormatGifComment
, commentextW
},
727 { &GUID_MetadataFormatChunkgAMA
, gAMAW
},
728 { &GUID_MetadataFormatChunkbKGD
, bKGDW
},
729 { &GUID_MetadataFormatChunkiTXt
, iTXtW
},
730 { &GUID_MetadataFormatChunkcHRM
, cHRMW
},
731 { &GUID_MetadataFormatChunkhIST
, hISTW
},
732 { &GUID_MetadataFormatChunkiCCP
, iCCPW
},
733 { &GUID_MetadataFormatChunksRGB
, sRGBW
},
734 { &GUID_MetadataFormatChunktIME
, tIMEW
}
737 HRESULT WINAPI
WICMapGuidToShortName(REFGUID guid
, UINT len
, WCHAR
*name
, UINT
*ret_len
)
741 TRACE("%s,%u,%p,%p\n", wine_dbgstr_guid(guid
), len
, name
, ret_len
);
743 if (!guid
) return E_INVALIDARG
;
745 for (i
= 0; i
< ARRAY_SIZE(guid2name
); i
++)
747 if (IsEqualGUID(guid
, guid2name
[i
].guid
))
751 if (!len
) return E_INVALIDARG
;
753 len
= min(len
- 1, lstrlenW(guid2name
[i
].name
));
754 memcpy(name
, guid2name
[i
].name
, len
* sizeof(WCHAR
));
757 if (len
< lstrlenW(guid2name
[i
].name
))
758 return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER
);
760 if (ret_len
) *ret_len
= lstrlenW(guid2name
[i
].name
) + 1;
765 return WINCODEC_ERR_PROPERTYNOTFOUND
;
768 HRESULT WINAPI
WICMapShortNameToGuid(PCWSTR name
, GUID
*guid
)
772 TRACE("%s,%p\n", debugstr_w(name
), guid
);
774 if (!name
|| !guid
) return E_INVALIDARG
;
776 for (i
= 0; i
< ARRAY_SIZE(guid2name
); i
++)
778 if (!lstrcmpiW(name
, guid2name
[i
].name
))
780 *guid
= *guid2name
[i
].guid
;
785 return WINCODEC_ERR_PROPERTYNOTFOUND
;
788 static const WCHAR rdf
[] = { 'r','d','f',0 };
789 static const WCHAR rdf_scheme
[] = { 'h','t','t','p',':','/','/','w','w','w','.','w','3','.','o','r','g','/','1','9','9','9','/','0','2','/','2','2','-','r','d','f','-','s','y','n','t','a','x','-','n','s','#',0 };
790 static const WCHAR dc
[] = { 'd','c',0 };
791 static const WCHAR dc_scheme
[] = { 'h','t','t','p',':','/','/','p','u','r','l','.','o','r','g','/','d','c','/','e','l','e','m','e','n','t','s','/','1','.','1','/',0 };
792 static const WCHAR xmp
[] = { 'x','m','p',0 };
793 static const WCHAR xmp_scheme
[] = { 'h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','x','a','p','/','1','.','0','/',0 };
794 static const WCHAR xmpidq
[] = { 'x','m','p','i','d','q',0 };
795 static const WCHAR xmpidq_scheme
[] = { 'h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','x','m','p','/','I','d','e','n','t','i','f','i','e','r','/','q','u','a','l','/','1','.','0','/',0 };
796 static const WCHAR xmpRights
[] = { 'x','m','p','R','i','g','h','t','s',0 };
797 static const WCHAR xmpRights_scheme
[] = { 'h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','x','a','p','/','1','.','0','/','r','i','g','h','t','s','/',0 };
798 static const WCHAR xmpMM
[] = { 'x','m','p','M','M',0 };
799 static const WCHAR xmpMM_scheme
[] = { 'h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','x','a','p','/','1','.','0','/','m','m','/',0 };
800 static const WCHAR xmpBJ
[] = { 'x','m','p','B','J',0 };
801 static const WCHAR xmpBJ_scheme
[] = { 'h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','x','a','p','/','1','.','0','/','b','j','/',0 };
802 static const WCHAR xmpTPg
[] = { 'x','m','p','T','P','g',0 };
803 static const WCHAR xmpTPg_scheme
[] = { 'h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','x','a','p','/','1','.','0','/','t','/','p','g','/',0 };
804 static const WCHAR pdf
[] = { 'p','d','f',0 };
805 static const WCHAR pdf_scheme
[] = { 'h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','p','d','f','/','1','.','3','/',0 };
806 static const WCHAR photoshop
[] = { 'p','h','o','t','o','s','h','o','p',0 };
807 static const WCHAR photoshop_scheme
[] = { 'h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','p','h','o','t','o','s','h','o','p','/','1','.','0','/',0 };
808 static const WCHAR tiff
[] = { 't','i','f','f',0 };
809 static const WCHAR tiff_scheme
[] = { 'h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','t','i','f','f','/','1','.','0','/',0 };
810 static const WCHAR exif
[] = { 'e','x','i','f',0 };
811 static const WCHAR exif_scheme
[] = { 'h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','e','x','i','f','/','1','.','0','/',0 };
812 static const WCHAR stDim
[] = { 's','t','D','i','m',0 };
813 static const WCHAR stDim_scheme
[] = { 'h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','x','a','p','/','1','.','0','/','s','T','y','p','e','/','D','i','m','e','n','s','i','o','n','s','#',0 };
814 static const WCHAR xapGImg
[] = { 'x','a','p','G','I','m','g',0 };
815 static const WCHAR xapGImg_scheme
[] = { 'h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','x','a','p','/','1','.','0','/','g','/','i','m','g','/',0 };
816 static const WCHAR stEvt
[] = { 's','t','E','v','t',0 };
817 static const WCHAR stEvt_scheme
[] = { 'h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','x','a','p','/','1','.','0','/','s','T','y','p','e','/','R','e','s','o','u','r','c','e','E','v','e','n','t','#',0 };
818 static const WCHAR stRef
[] = { 's','t','R','e','f',0 };
819 static const WCHAR stRef_scheme
[] = { 'h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','x','a','p','/','1','.','0','/','s','T','y','p','e','/','R','e','s','o','u','r','c','e','R','e','f','#',0 };
820 static const WCHAR stVer
[] = { 's','t','V','e','r',0 };
821 static const WCHAR stVer_scheme
[] = { 'h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','x','a','p','/','1','.','0','/','s','T','y','p','e','/','V','e','r','s','i','o','n','#',0 };
822 static const WCHAR stJob
[] = { 's','t','J','o','b',0 };
823 static const WCHAR stJob_scheme
[] = { 'h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','x','a','p','/','1','.','0','/','s','T','y','p','e','/','J','o','b','#',0 };
824 static const WCHAR aux
[] = { 'a','u','x',0 };
825 static const WCHAR aux_scheme
[] = { 'h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','e','x','i','f','/','1','.','0','/','a','u','x','/',0 };
826 static const WCHAR crs
[] = { 'c','r','s',0 };
827 static const WCHAR crs_scheme
[] = { 'h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','c','a','m','e','r','a','-','r','a','w','-','s','e','t','t','i','n','g','s','/','1','.','0','/',0 };
828 static const WCHAR xmpDM
[] = { 'x','m','p','D','M',0 };
829 static const WCHAR xmpDM_scheme
[] = { 'h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','x','m','p','/','1','.','0','/','D','y','n','a','m','i','c','M','e','d','i','a','/',0 };
830 static const WCHAR Iptc4xmpCore
[] = { 'I','p','t','c','4','x','m','p','C','o','r','e',0 };
831 static const WCHAR Iptc4xmpCore_scheme
[] = { 'h','t','t','p',':','/','/','i','p','t','c','.','o','r','g','/','s','t','d','/','I','p','t','c','4','x','m','p','C','o','r','e','/','1','.','0','/','x','m','l','n','s','/',0 };
832 static const WCHAR MicrosoftPhoto
[] = { 'M','i','c','r','o','s','o','f','t','P','h','o','t','o',0 };
833 static const WCHAR MicrosoftPhoto_scheme
[] = { 'h','t','t','p',':','/','/','n','s','.','m','i','c','r','o','s','o','f','t','.','c','o','m','/','p','h','o','t','o','/','1','.','0','/',0 };
834 static const WCHAR MP
[] = { 'M','P',0 };
835 static const WCHAR MP_scheme
[] = { 'h','t','t','p',':','/','/','n','s','.','m','i','c','r','o','s','o','f','t','.','c','o','m','/','p','h','o','t','o','/','1','.','2','/',0 };
836 static const WCHAR MPRI
[] = { 'M','P','R','I',0 };
837 static const WCHAR MPRI_scheme
[] = { 'h','t','t','p',':','/','/','n','s','.','m','i','c','r','o','s','o','f','t','.','c','o','m','/','p','h','o','t','o','/','1','.','2','/','t','/','R','e','g','i','o','n','I','n','f','o','#',0 };
838 static const WCHAR MPReg
[] = { 'M','P','R','e','g',0 };
839 static const WCHAR MPReg_scheme
[] = { 'h','t','t','p',':','/','/','n','s','.','m','i','c','r','o','s','o','f','t','.','c','o','m','/','p','h','o','t','o','/','1','.','2','/','t','/','R','e','g','i','o','n','#',0 };
850 { xmpidq
, xmpidq_scheme
},
851 { xmpRights
, xmpRights_scheme
},
852 { xmpMM
, xmpMM_scheme
},
853 { xmpBJ
, xmpBJ_scheme
},
854 { xmpTPg
, xmpTPg_scheme
},
856 { photoshop
, photoshop_scheme
},
857 { tiff
, tiff_scheme
},
858 { exif
, exif_scheme
},
859 { stDim
, stDim_scheme
},
860 { xapGImg
, xapGImg_scheme
},
861 { stEvt
, stEvt_scheme
},
862 { stRef
, stRef_scheme
},
863 { stVer
, stVer_scheme
},
864 { stJob
, stJob_scheme
},
867 { xmpDM
, xmpDM_scheme
},
868 { Iptc4xmpCore
, Iptc4xmpCore_scheme
},
869 { MicrosoftPhoto
, MicrosoftPhoto_scheme
},
871 { MPRI
, MPRI_scheme
},
872 { MPReg
, MPReg_scheme
}
875 static const WCHAR
*map_shortname_to_schema(const GUID
*format
, const WCHAR
*name
)
879 /* It appears that the only metadata formats
880 * that support schemas are xmp and xmpstruct.
882 if (!IsEqualGUID(format
, &GUID_MetadataFormatXMP
) &&
883 !IsEqualGUID(format
, &GUID_MetadataFormatXMPStruct
))
886 for (i
= 0; i
< ARRAY_SIZE(name2schema
); i
++)
888 if (!lstrcmpW(name2schema
[i
].name
, name
))
889 return name2schema
[i
].schema
;
895 HRESULT WINAPI
WICMapSchemaToName(REFGUID format
, LPWSTR schema
, UINT len
, WCHAR
*name
, UINT
*ret_len
)
899 TRACE("%s,%s,%u,%p,%p\n", wine_dbgstr_guid(format
), debugstr_w(schema
), len
, name
, ret_len
);
901 if (!format
|| !schema
|| !ret_len
)
904 /* It appears that the only metadata formats
905 * that support schemas are xmp and xmpstruct.
907 if (!IsEqualGUID(format
, &GUID_MetadataFormatXMP
) &&
908 !IsEqualGUID(format
, &GUID_MetadataFormatXMPStruct
))
909 return WINCODEC_ERR_PROPERTYNOTFOUND
;
911 for (i
= 0; i
< ARRAY_SIZE(name2schema
); i
++)
913 if (!lstrcmpW(name2schema
[i
].schema
, schema
))
917 if (!len
) return E_INVALIDARG
;
919 len
= min(len
- 1, lstrlenW(name2schema
[i
].name
));
920 memcpy(name
, name2schema
[i
].name
, len
* sizeof(WCHAR
));
923 if (len
< lstrlenW(name2schema
[i
].name
))
924 return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER
);
927 *ret_len
= lstrlenW(name2schema
[i
].name
) + 1;
932 return WINCODEC_ERR_PROPERTYNOTFOUND
;