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
20 #include "wincodecs_private.h"
22 #include <propvarutil.h>
24 static const WCHAR
*map_shortname_to_schema(const GUID
*format
, const WCHAR
*name
);
27 IWICMetadataQueryReader IWICMetadataQueryReader_iface
;
29 IWICMetadataBlockReader
*block
;
33 static inline QueryReader
*impl_from_IWICMetadataQueryReader(IWICMetadataQueryReader
*iface
)
35 return CONTAINING_RECORD(iface
, QueryReader
, IWICMetadataQueryReader_iface
);
38 static HRESULT WINAPI
mqr_QueryInterface(IWICMetadataQueryReader
*iface
, REFIID riid
,
41 QueryReader
*This
= impl_from_IWICMetadataQueryReader(iface
);
43 TRACE("(%p,%s,%p)\n", This
, debugstr_guid(riid
), ppvObject
);
45 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
46 IsEqualGUID(riid
, &IID_IWICMetadataQueryReader
))
47 *ppvObject
= &This
->IWICMetadataQueryReader_iface
;
53 IUnknown_AddRef((IUnknown
*)*ppvObject
);
60 static ULONG WINAPI
mqr_AddRef(IWICMetadataQueryReader
*iface
)
62 QueryReader
*This
= impl_from_IWICMetadataQueryReader(iface
);
63 ULONG ref
= InterlockedIncrement(&This
->ref
);
64 TRACE("(%p) refcount=%u\n", This
, ref
);
68 static ULONG WINAPI
mqr_Release(IWICMetadataQueryReader
*iface
)
70 QueryReader
*This
= impl_from_IWICMetadataQueryReader(iface
);
71 ULONG ref
= InterlockedDecrement(&This
->ref
);
72 TRACE("(%p) refcount=%u\n", This
, ref
);
75 IWICMetadataBlockReader_Release(This
->block
);
76 HeapFree(GetProcessHeap(), 0, This
->root
);
77 HeapFree(GetProcessHeap(), 0, This
);
82 static HRESULT WINAPI
mqr_GetContainerFormat(IWICMetadataQueryReader
*iface
, GUID
*format
)
84 QueryReader
*This
= impl_from_IWICMetadataQueryReader(iface
);
86 TRACE("(%p,%p)\n", This
, format
);
88 return IWICMetadataBlockReader_GetContainerFormat(This
->block
, format
);
91 static HRESULT WINAPI
mqr_GetLocation(IWICMetadataQueryReader
*iface
, UINT len
, WCHAR
*location
, UINT
*ret_len
)
93 static const WCHAR rootW
[] = { '/',0 };
94 QueryReader
*This
= impl_from_IWICMetadataQueryReader(iface
);
98 TRACE("(%p,%u,%p,%p)\n", This
, len
, location
, ret_len
);
100 if (!ret_len
) return E_INVALIDARG
;
102 root
= This
->root
? This
->root
: rootW
;
103 actual_len
= lstrlenW(root
) + 1;
107 if (len
< actual_len
)
108 return WINCODEC_ERR_INSUFFICIENTBUFFER
;
110 memcpy(location
, root
, actual_len
* sizeof(WCHAR
));
113 *ret_len
= actual_len
;
131 { 4, {'c','h','a','r'}, VT_I1
},
132 { 5, {'u','c','h','a','r'}, VT_UI1
},
133 { 5, {'s','h','o','r','t'}, VT_I2
},
134 { 6, {'u','s','h','o','r','t'}, VT_UI2
},
135 { 4, {'l','o','n','g'}, VT_I4
},
136 { 5, {'u','l','o','n','g'}, VT_UI4
},
137 { 3, {'i','n','t'}, VT_I4
},
138 { 4, {'u','i','n','t'}, VT_UI4
},
139 { 8, {'l','o','n','g','l','o','n','g'}, VT_I8
},
140 { 9, {'u','l','o','n','g','l','o','n','g'}, VT_UI8
},
141 { 5, {'f','l','o','a','t'}, VT_R4
},
142 { 6, {'d','o','u','b','l','e'}, VT_R8
},
143 { 3, {'s','t','r'}, VT_LPSTR
},
144 { 4, {'w','s','t','r'}, VT_LPWSTR
},
145 { 4, {'g','u','i','d'}, VT_CLSID
},
146 { 4, {'b','o','o','l'}, VT_BOOL
}
149 static VARTYPE
map_type(struct string_t
*str
)
153 for (i
= 0; i
< sizeof(str2vt
)/sizeof(str2vt
[0]); i
++)
155 if (str2vt
[i
].len
== str
->len
)
157 if (CompareStringW(LOCALE_SYSTEM_DEFAULT
, NORM_IGNORECASE
,
158 str
->str
, str
->len
, str2vt
[i
].str
, str2vt
[i
].len
) == CSTR_EQUAL
)
163 WARN("type %s is not recognized\n", wine_dbgstr_wn(str
->str
, str
->len
));
168 static HRESULT
get_token(struct string_t
*elem
, PROPVARIANT
*id
, PROPVARIANT
*schema
, int *idx
)
170 const WCHAR
*start
, *end
, *p
;
172 struct string_t next_elem
;
175 TRACE("%s, len %d\n", wine_dbgstr_wn(elem
->str
, elem
->len
), elem
->len
);
178 PropVariantInit(schema
);
180 if (!elem
->len
) return S_OK
;
188 if (start
[1] < '0' || start
[1] > '9') return DISP_E_TYPEMISMATCH
;
190 *idx
= strtolW(start
+ 1, &idx_end
, 10);
191 if (idx_end
> elem
->str
+ elem
->len
) return WINCODEC_ERR_INVALIDQUERYREQUEST
;
192 if (*idx_end
!= ']') return WINCODEC_ERR_INVALIDQUERYREQUEST
;
193 if (*idx
< 0) return WINCODEC_ERR_INVALIDQUERYREQUEST
;
197 next_elem
.len
= elem
->len
- (end
- start
);
198 hr
= get_token(&next_elem
, id
, schema
, idx
);
201 TRACE("get_token error %#x\n", hr
);
204 elem
->len
= (end
- start
) + next_elem
.len
;
206 TRACE("indexed %s [%d]\n", wine_dbgstr_wn(elem
->str
, elem
->len
), *idx
);
209 else if (*start
== '{')
212 PROPVARIANT next_token
;
214 end
= memchrW(start
+ 1, '=', elem
->len
- 1);
215 if (!end
) return WINCODEC_ERR_INVALIDQUERYREQUEST
;
216 if (end
> elem
->str
+ elem
->len
) return WINCODEC_ERR_INVALIDQUERYREQUEST
;
218 next_elem
.str
= start
+ 1;
219 next_elem
.len
= end
- start
- 1;
220 vt
= map_type(&next_elem
);
221 TRACE("type %s => %d\n", wine_dbgstr_wn(next_elem
.str
, next_elem
.len
), vt
);
222 if (vt
== VT_ILLEGAL
) return WINCODEC_ERR_WRONGSTATE
;
224 next_token
.vt
= VT_BSTR
;
225 next_token
.u
.bstrVal
= SysAllocStringLen(NULL
, elem
->len
- (end
- start
) + 1);
226 if (!next_token
.u
.bstrVal
) return E_OUTOFMEMORY
;
228 bstr
= next_token
.u
.bstrVal
;
232 while (*end
&& *end
!= '}' && end
- start
< elem
->len
)
234 if (*end
== '\\') end
++;
239 PropVariantClear(&next_token
);
240 return WINCODEC_ERR_INVALIDQUERYREQUEST
;
243 TRACE("schema/id %s\n", wine_dbgstr_w(next_token
.u
.bstrVal
));
248 id
->u
.puuid
= CoTaskMemAlloc(sizeof(GUID
));
251 PropVariantClear(&next_token
);
252 return E_OUTOFMEMORY
;
255 hr
= UuidFromStringW(next_token
.u
.bstrVal
, id
->u
.puuid
);
258 hr
= PropVariantChangeType(id
, &next_token
, 0, vt
);
259 PropVariantClear(&next_token
);
262 PropVariantClear(id
);
263 PropVariantClear(schema
);
270 PROPVARIANT next_id
, next_schema
;
273 next_elem
.str
= end
+ 1;
274 next_elem
.len
= elem
->len
- (end
- start
+ 1);
275 hr
= get_token(&next_elem
, &next_id
, &next_schema
, &next_idx
);
278 TRACE("get_token error %#x\n", hr
);
281 elem
->len
= (end
- start
+ 1) + next_elem
.len
;
283 TRACE("id %s [%d]\n", wine_dbgstr_wn(elem
->str
, elem
->len
), *idx
);
285 if (next_schema
.vt
!= VT_EMPTY
)
287 PropVariantClear(&next_id
);
288 PropVariantClear(&next_schema
);
289 return WINCODEC_ERR_WRONGSTATE
;
298 elem
->len
= end
- start
;
302 end
= memchrW(start
, '/', elem
->len
);
303 if (!end
) end
= start
+ elem
->len
;
305 p
= memchrW(start
, ':', end
- start
);
308 next_elem
.str
= p
+ 1;
309 next_elem
.len
= end
- p
- 1;
311 elem
->len
= p
- start
;
314 elem
->len
= end
- start
;
317 id
->u
.bstrVal
= SysAllocStringLen(NULL
, elem
->len
+ 1);
318 if (!id
->u
.bstrVal
) return E_OUTOFMEMORY
;
320 bstr
= id
->u
.bstrVal
;
322 while (p
- elem
->str
< elem
->len
)
328 TRACE("%s [%d]\n", wine_dbgstr_variant((VARIANT
*)id
), *idx
);
332 PROPVARIANT next_id
, next_schema
;
335 hr
= get_token(&next_elem
, &next_id
, &next_schema
, &next_idx
);
338 TRACE("get_token error %#x\n", hr
);
339 PropVariantClear(id
);
340 PropVariantClear(schema
);
343 elem
->len
+= next_elem
.len
+ 1;
345 TRACE("id %s [%d]\n", wine_dbgstr_wn(elem
->str
, elem
->len
), *idx
);
347 if (next_schema
.vt
!= VT_EMPTY
)
349 PropVariantClear(&next_id
);
350 PropVariantClear(&next_schema
);
351 PropVariantClear(id
);
352 PropVariantClear(schema
);
353 return WINCODEC_ERR_WRONGSTATE
;
363 static HRESULT
find_reader_from_block(IWICMetadataBlockReader
*block_reader
, UINT index
,
364 GUID
*guid
, IWICMetadataReader
**reader
)
368 IWICMetadataReader
*new_reader
;
369 UINT count
, i
, matched_index
;
373 hr
= IWICMetadataBlockReader_GetCount(block_reader
, &count
);
374 if (hr
!= S_OK
) return hr
;
378 for (i
= 0; i
< count
; i
++)
380 hr
= IWICMetadataBlockReader_GetReaderByIndex(block_reader
, i
, &new_reader
);
381 if (hr
!= S_OK
) return hr
;
383 hr
= IWICMetadataReader_GetMetadataFormat(new_reader
, &format
);
386 if (IsEqualGUID(&format
, guid
))
388 if (matched_index
== index
)
390 *reader
= new_reader
;
398 IWICMetadataReader_Release(new_reader
);
399 if (hr
!= S_OK
) return hr
;
402 return WINCODEC_ERR_PROPERTYNOTFOUND
;
405 static HRESULT
get_next_reader(IWICMetadataReader
*reader
, UINT index
,
406 GUID
*guid
, IWICMetadataReader
**new_reader
)
409 PROPVARIANT schema
, id
, value
;
413 PropVariantInit(&schema
);
414 PropVariantInit(&id
);
415 PropVariantInit(&value
);
420 schema
.u
.uiVal
= index
;
425 hr
= IWICMetadataReader_GetValue(reader
, &schema
, &id
, &value
);
426 if (hr
!= S_OK
) return hr
;
428 if (value
.vt
== VT_UNKNOWN
)
429 hr
= IUnknown_QueryInterface(value
.u
.punkVal
, &IID_IWICMetadataReader
, (void **)new_reader
);
431 hr
= WINCODEC_ERR_UNEXPECTEDMETADATATYPE
;
433 PropVariantClear(&value
);
437 static HRESULT WINAPI
mqr_GetMetadataByName(IWICMetadataQueryReader
*iface
, LPCWSTR query
, PROPVARIANT
*value
)
439 QueryReader
*This
= impl_from_IWICMetadataQueryReader(iface
);
440 struct string_t elem
;
444 PROPVARIANT tk_id
, tk_schema
, new_value
;
446 IWICMetadataReader
*reader
;
449 TRACE("(%p,%s,%p)\n", This
, wine_dbgstr_w(query
), value
);
451 len
= lstrlenW(query
) + 1;
452 if (This
->root
) len
+= lstrlenW(This
->root
);
453 full_query
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
456 lstrcpyW(full_query
, This
->root
);
457 lstrcatW(full_query
, query
);
459 PropVariantInit(&tk_id
);
460 PropVariantInit(&tk_schema
);
461 PropVariantInit(&new_value
);
470 WARN("query should start with '/'\n");
471 hr
= WINCODEC_ERR_PROPERTYNOTSUPPORTED
;
479 elem
.len
= lstrlenW(p
);
480 hr
= get_token(&elem
, &tk_id
, &tk_schema
, &index
);
483 WARN("get_token error %#x\n", hr
);
486 TRACE("parsed %d characters: %s, index %d\n", elem
.len
, wine_dbgstr_wn(elem
.str
, elem
.len
), index
);
487 TRACE("id %s, schema %s\n", wine_dbgstr_variant((VARIANT
*)&tk_id
), wine_dbgstr_variant((VARIANT
*)&tk_schema
));
489 if (!elem
.len
) break;
491 if (tk_id
.vt
== VT_CLSID
|| (tk_id
.vt
== VT_BSTR
&& WICMapShortNameToGuid(tk_id
.u
.bstrVal
, &guid
) == S_OK
))
495 if (tk_schema
.vt
!= VT_EMPTY
)
497 FIXME("unsupported schema vt %u\n", tk_schema
.vt
);
498 PropVariantClear(&tk_schema
);
501 if (tk_id
.vt
== VT_CLSID
) guid
= *tk_id
.u
.puuid
;
505 IWICMetadataReader
*new_reader
;
507 hr
= get_next_reader(reader
, index
, &guid
, &new_reader
);
508 IWICMetadataReader_Release(reader
);
512 hr
= find_reader_from_block(This
->block
, index
, &guid
, &reader
);
514 if (hr
!= S_OK
) break;
516 root
= SysAllocStringLen(NULL
, elem
.str
+ elem
.len
- full_query
+ 2);
522 lstrcpynW(root
, full_query
, p
- full_query
+ elem
.len
+ 1);
524 PropVariantClear(&new_value
);
525 new_value
.vt
= VT_UNKNOWN
;
526 hr
= MetadataQueryReader_CreateInstance(This
->block
, root
, (IWICMetadataQueryReader
**)&new_value
.u
.punkVal
);
528 if (hr
!= S_OK
) break;
532 PROPVARIANT schema
, id
;
536 hr
= WINCODEC_ERR_INVALIDQUERYREQUEST
;
540 if (tk_schema
.vt
== VT_BSTR
)
542 hr
= IWICMetadataReader_GetMetadataFormat(reader
, &guid
);
543 if (hr
!= S_OK
) break;
545 schema
.vt
= VT_LPWSTR
;
546 schema
.u
.pwszVal
= (LPWSTR
)map_shortname_to_schema(&guid
, tk_schema
.u
.bstrVal
);
547 if (!schema
.u
.pwszVal
)
548 schema
.u
.pwszVal
= tk_schema
.u
.bstrVal
;
553 if (tk_id
.vt
== VT_BSTR
)
556 id
.u
.pwszVal
= tk_id
.u
.bstrVal
;
561 PropVariantClear(&new_value
);
562 hr
= IWICMetadataReader_GetValue(reader
, &schema
, &id
, &new_value
);
563 if (hr
!= S_OK
) break;
568 PropVariantClear(&tk_id
);
569 PropVariantClear(&tk_schema
);
573 IWICMetadataReader_Release(reader
);
575 PropVariantClear(&tk_id
);
576 PropVariantClear(&tk_schema
);
581 PropVariantClear(&new_value
);
583 HeapFree(GetProcessHeap(), 0, full_query
);
588 static HRESULT WINAPI
mqr_GetEnumerator(IWICMetadataQueryReader
*iface
,
589 IEnumString
**ppIEnumString
)
591 QueryReader
*This
= impl_from_IWICMetadataQueryReader(iface
);
592 FIXME("(%p,%p)\n", This
, ppIEnumString
);
596 static IWICMetadataQueryReaderVtbl mqr_vtbl
= {
600 mqr_GetContainerFormat
,
602 mqr_GetMetadataByName
,
606 HRESULT
MetadataQueryReader_CreateInstance(IWICMetadataBlockReader
*mbr
, const WCHAR
*root
, IWICMetadataQueryReader
**out
)
610 obj
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*obj
));
612 return E_OUTOFMEMORY
;
614 obj
->IWICMetadataQueryReader_iface
.lpVtbl
= &mqr_vtbl
;
617 IWICMetadataBlockReader_AddRef(mbr
);
620 obj
->root
= root
? heap_strdupW(root
) : NULL
;
622 *out
= &obj
->IWICMetadataQueryReader_iface
;
627 static const WCHAR bmpW
[] = { 'b','m','p',0 };
628 static const WCHAR pngW
[] = { 'p','n','g',0 };
629 static const WCHAR icoW
[] = { 'i','c','o',0 };
630 static const WCHAR jpgW
[] = { 'j','p','g',0 };
631 static const WCHAR tiffW
[] = { 't','i','f','f',0 };
632 static const WCHAR gifW
[] = { 'g','i','f',0 };
633 static const WCHAR wmphotoW
[] = { 'w','m','p','h','o','t','o',0 };
634 static const WCHAR unknownW
[] = { 'u','n','k','n','o','w','n',0 };
635 static const WCHAR ifdW
[] = { 'i','f','d',0 };
636 static const WCHAR subW
[] = { 's','u','b',0 };
637 static const WCHAR exifW
[] = { 'e','x','i','f',0 };
638 static const WCHAR gpsW
[] = { 'g','p','s',0 };
639 static const WCHAR interopW
[] = { 'i','n','t','e','r','o','p',0 };
640 static const WCHAR app0W
[] = { 'a','p','p','0',0 };
641 static const WCHAR app1W
[] = { 'a','p','p','1',0 };
642 static const WCHAR app13W
[] = { 'a','p','p','1','3',0 };
643 static const WCHAR iptcW
[] = { 'i','p','t','c',0 };
644 static const WCHAR irbW
[] = { 'i','r','b',0 };
645 static const WCHAR _8bimiptcW
[] = { '8','b','i','m','i','p','t','c',0 };
646 static const WCHAR _8bimResInfoW
[] = { '8','b','i','m','R','e','s','I','n','f','o',0 };
647 static const WCHAR _8bimiptcdigestW
[] = { '8','b','i','m','i','p','t','c','d','i','g','e','s','t',0 };
648 static const WCHAR xmpW
[] = { 'x','m','p',0 };
649 static const WCHAR thumbW
[] = { 't','h','u','m','b',0 };
650 static const WCHAR tEXtW
[] = { 't','E','X','t',0 };
651 static const WCHAR xmpstructW
[] = { 'x','m','p','s','t','r','u','c','t',0 };
652 static const WCHAR xmpbagW
[] = { 'x','m','p','b','a','g',0 };
653 static const WCHAR xmpseqW
[] = { 'x','m','p','s','e','q',0 };
654 static const WCHAR xmpaltW
[] = { 'x','m','p','a','l','t',0 };
655 static const WCHAR logscrdescW
[] = { 'l','o','g','s','c','r','d','e','s','c',0 };
656 static const WCHAR imgdescW
[] = { 'i','m','g','d','e','s','c',0 };
657 static const WCHAR grctlextW
[] = { 'g','r','c','t','l','e','x','t',0 };
658 static const WCHAR appextW
[] = { 'a','p','p','e','x','t',0 };
659 static const WCHAR chrominanceW
[] = { 'c','h','r','o','m','i','n','a','n','c','e',0 };
660 static const WCHAR luminanceW
[] = { 'l','u','m','i','n','a','n','c','e',0 };
661 static const WCHAR comW
[] = { 'c','o','m',0 };
662 static const WCHAR commentextW
[] = { 'c','o','m','m','e','n','t','e','x','t',0 };
663 static const WCHAR gAMAW
[] = { 'g','A','M','A',0 };
664 static const WCHAR bKGDW
[] = { 'b','K','G','D',0 };
665 static const WCHAR iTXtW
[] = { 'i','T','X','t',0 };
666 static const WCHAR cHRMW
[] = { 'c','H','R','M',0 };
667 static const WCHAR hISTW
[] = { 'h','I','S','T',0 };
668 static const WCHAR iCCPW
[] = { 'i','C','C','P',0 };
669 static const WCHAR sRGBW
[] = { 's','R','G','B',0 };
670 static const WCHAR tIMEW
[] = { 't','I','M','E',0 };
678 { &GUID_ContainerFormatBmp
, bmpW
},
679 { &GUID_ContainerFormatPng
, pngW
},
680 { &GUID_ContainerFormatIco
, icoW
},
681 { &GUID_ContainerFormatJpeg
, jpgW
},
682 { &GUID_ContainerFormatTiff
, tiffW
},
683 { &GUID_ContainerFormatGif
, gifW
},
684 { &GUID_ContainerFormatWmp
, wmphotoW
},
685 { &GUID_MetadataFormatUnknown
, unknownW
},
686 { &GUID_MetadataFormatIfd
, ifdW
},
687 { &GUID_MetadataFormatSubIfd
, subW
},
688 { &GUID_MetadataFormatExif
, exifW
},
689 { &GUID_MetadataFormatGps
, gpsW
},
690 { &GUID_MetadataFormatInterop
, interopW
},
691 { &GUID_MetadataFormatApp0
, app0W
},
692 { &GUID_MetadataFormatApp1
, app1W
},
693 { &GUID_MetadataFormatApp13
, app13W
},
694 { &GUID_MetadataFormatIPTC
, iptcW
},
695 { &GUID_MetadataFormatIRB
, irbW
},
696 { &GUID_MetadataFormat8BIMIPTC
, _8bimiptcW
},
697 { &GUID_MetadataFormat8BIMResolutionInfo
, _8bimResInfoW
},
698 { &GUID_MetadataFormat8BIMIPTCDigest
, _8bimiptcdigestW
},
699 { &GUID_MetadataFormatXMP
, xmpW
},
700 { &GUID_MetadataFormatThumbnail
, thumbW
},
701 { &GUID_MetadataFormatChunktEXt
, tEXtW
},
702 { &GUID_MetadataFormatXMPStruct
, xmpstructW
},
703 { &GUID_MetadataFormatXMPBag
, xmpbagW
},
704 { &GUID_MetadataFormatXMPSeq
, xmpseqW
},
705 { &GUID_MetadataFormatXMPAlt
, xmpaltW
},
706 { &GUID_MetadataFormatLSD
, logscrdescW
},
707 { &GUID_MetadataFormatIMD
, imgdescW
},
708 { &GUID_MetadataFormatGCE
, grctlextW
},
709 { &GUID_MetadataFormatAPE
, appextW
},
710 { &GUID_MetadataFormatJpegChrominance
, chrominanceW
},
711 { &GUID_MetadataFormatJpegLuminance
, luminanceW
},
712 { &GUID_MetadataFormatJpegComment
, comW
},
713 { &GUID_MetadataFormatGifComment
, commentextW
},
714 { &GUID_MetadataFormatChunkgAMA
, gAMAW
},
715 { &GUID_MetadataFormatChunkbKGD
, bKGDW
},
716 { &GUID_MetadataFormatChunkiTXt
, iTXtW
},
717 { &GUID_MetadataFormatChunkcHRM
, cHRMW
},
718 { &GUID_MetadataFormatChunkhIST
, hISTW
},
719 { &GUID_MetadataFormatChunkiCCP
, iCCPW
},
720 { &GUID_MetadataFormatChunksRGB
, sRGBW
},
721 { &GUID_MetadataFormatChunktIME
, tIMEW
}
724 HRESULT WINAPI
WICMapGuidToShortName(REFGUID guid
, UINT len
, WCHAR
*name
, UINT
*ret_len
)
728 TRACE("%s,%u,%p,%p\n", wine_dbgstr_guid(guid
), len
, name
, ret_len
);
730 if (!guid
) return E_INVALIDARG
;
732 for (i
= 0; i
< sizeof(guid2name
)/sizeof(guid2name
[0]); i
++)
734 if (IsEqualGUID(guid
, guid2name
[i
].guid
))
738 if (!len
) return E_INVALIDARG
;
740 len
= min(len
- 1, lstrlenW(guid2name
[i
].name
));
741 memcpy(name
, guid2name
[i
].name
, len
* sizeof(WCHAR
));
744 if (len
< lstrlenW(guid2name
[i
].name
))
745 return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER
);
747 if (ret_len
) *ret_len
= lstrlenW(guid2name
[i
].name
) + 1;
752 return WINCODEC_ERR_PROPERTYNOTFOUND
;
755 HRESULT WINAPI
WICMapShortNameToGuid(PCWSTR name
, GUID
*guid
)
759 TRACE("%s,%p\n", debugstr_w(name
), guid
);
761 if (!name
|| !guid
) return E_INVALIDARG
;
763 for (i
= 0; i
< sizeof(guid2name
)/sizeof(guid2name
[0]); i
++)
765 if (!lstrcmpiW(name
, guid2name
[i
].name
))
767 *guid
= *guid2name
[i
].guid
;
772 return WINCODEC_ERR_PROPERTYNOTFOUND
;
775 static const WCHAR rdf
[] = { 'r','d','f',0 };
776 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 };
777 static const WCHAR dc
[] = { 'd','c',0 };
778 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 };
779 static const WCHAR xmp
[] = { 'x','m','p',0 };
780 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 };
781 static const WCHAR xmpidq
[] = { 'x','m','p','i','d','q',0 };
782 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 };
783 static const WCHAR xmpRights
[] = { 'x','m','p','R','i','g','h','t','s',0 };
784 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 };
785 static const WCHAR xmpMM
[] = { 'x','m','p','M','M',0 };
786 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 };
787 static const WCHAR xmpBJ
[] = { 'x','m','p','B','J',0 };
788 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 };
789 static const WCHAR xmpTPg
[] = { 'x','m','p','T','P','g',0 };
790 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 };
791 static const WCHAR pdf
[] = { 'p','d','f',0 };
792 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 };
793 static const WCHAR photoshop
[] = { 'p','h','o','t','o','s','h','o','p',0 };
794 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 };
795 static const WCHAR tiff
[] = { 't','i','f','f',0 };
796 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 };
797 static const WCHAR exif
[] = { 'e','x','i','f',0 };
798 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 };
799 static const WCHAR stDim
[] = { 's','t','D','i','m',0 };
800 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 };
801 static const WCHAR xapGImg
[] = { 'x','a','p','G','I','m','g',0 };
802 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 };
803 static const WCHAR stEvt
[] = { 's','t','E','v','t',0 };
804 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 };
805 static const WCHAR stRef
[] = { 's','t','R','e','f',0 };
806 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 };
807 static const WCHAR stVer
[] = { 's','t','V','e','r',0 };
808 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 };
809 static const WCHAR stJob
[] = { 's','t','J','o','b',0 };
810 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 };
811 static const WCHAR aux
[] = { 'a','u','x',0 };
812 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 };
813 static const WCHAR crs
[] = { 'c','r','s',0 };
814 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 };
815 static const WCHAR xmpDM
[] = { 'x','m','p','D','M',0 };
816 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 };
817 static const WCHAR Iptc4xmpCore
[] = { 'I','p','t','c','4','x','m','p','C','o','r','e',0 };
818 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 };
819 static const WCHAR MicrosoftPhoto
[] = { 'M','i','c','r','o','s','o','f','t','P','h','o','t','o',0 };
820 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 };
821 static const WCHAR MP
[] = { 'M','P',0 };
822 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 };
823 static const WCHAR MPRI
[] = { 'M','P','R','I',0 };
824 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 };
825 static const WCHAR MPReg
[] = { 'M','P','R','e','g',0 };
826 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 };
837 { xmpidq
, xmpidq_scheme
},
838 { xmpRights
, xmpRights_scheme
},
839 { xmpMM
, xmpMM_scheme
},
840 { xmpBJ
, xmpBJ_scheme
},
841 { xmpTPg
, xmpTPg_scheme
},
843 { photoshop
, photoshop_scheme
},
844 { tiff
, tiff_scheme
},
845 { exif
, exif_scheme
},
846 { stDim
, stDim_scheme
},
847 { xapGImg
, xapGImg_scheme
},
848 { stEvt
, stEvt_scheme
},
849 { stRef
, stRef_scheme
},
850 { stVer
, stVer_scheme
},
851 { stJob
, stJob_scheme
},
854 { xmpDM
, xmpDM_scheme
},
855 { Iptc4xmpCore
, Iptc4xmpCore_scheme
},
856 { MicrosoftPhoto
, MicrosoftPhoto_scheme
},
858 { MPRI
, MPRI_scheme
},
859 { MPReg
, MPReg_scheme
}
862 static const WCHAR
*map_shortname_to_schema(const GUID
*format
, const WCHAR
*name
)
866 /* It appears that the only metadata formats
867 * that support schemas are xmp and xmpstruct.
869 if (!IsEqualGUID(format
, &GUID_MetadataFormatXMP
) &&
870 !IsEqualGUID(format
, &GUID_MetadataFormatXMPStruct
))
873 for (i
= 0; i
< sizeof(name2schema
)/sizeof(name2schema
[0]); i
++)
875 if (!lstrcmpW(name2schema
[i
].name
, name
))
876 return name2schema
[i
].schema
;
882 HRESULT WINAPI
WICMapSchemaToName(REFGUID format
, LPWSTR schema
, UINT len
, WCHAR
*name
, UINT
*ret_len
)
886 TRACE("%s,%s,%u,%p,%p\n", wine_dbgstr_guid(format
), debugstr_w(schema
), len
, name
, ret_len
);
888 if (!format
|| !schema
|| !ret_len
)
891 /* It appears that the only metadata formats
892 * that support schemas are xmp and xmpstruct.
894 if (!IsEqualGUID(format
, &GUID_MetadataFormatXMP
) &&
895 !IsEqualGUID(format
, &GUID_MetadataFormatXMPStruct
))
896 return WINCODEC_ERR_PROPERTYNOTFOUND
;
898 for (i
= 0; i
< sizeof(name2schema
)/sizeof(name2schema
[0]); i
++)
900 if (!lstrcmpW(name2schema
[i
].schema
, schema
))
904 if (!len
) return E_INVALIDARG
;
906 len
= min(len
- 1, lstrlenW(name2schema
[i
].name
));
907 memcpy(name
, name2schema
[i
].name
, len
* sizeof(WCHAR
));
910 if (len
< lstrlenW(name2schema
[i
].name
))
911 return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER
);
914 if (ret_len
) *ret_len
= lstrlenW(name2schema
[i
].name
) + 1;
919 return WINCODEC_ERR_PROPERTYNOTFOUND
;