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
24 #define NONAMELESSUNION
29 #include "propvarutil.h"
31 #include "wincodecs_private.h"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs
);
37 static const WCHAR
*map_shortname_to_schema(const GUID
*format
, const WCHAR
*name
);
40 IWICMetadataQueryReader IWICMetadataQueryReader_iface
;
42 IWICMetadataBlockReader
*block
;
46 static inline QueryReader
*impl_from_IWICMetadataQueryReader(IWICMetadataQueryReader
*iface
)
48 return CONTAINING_RECORD(iface
, QueryReader
, IWICMetadataQueryReader_iface
);
51 static HRESULT WINAPI
mqr_QueryInterface(IWICMetadataQueryReader
*iface
, REFIID riid
,
54 QueryReader
*This
= impl_from_IWICMetadataQueryReader(iface
);
56 TRACE("(%p,%s,%p)\n", This
, debugstr_guid(riid
), ppvObject
);
58 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
59 IsEqualGUID(riid
, &IID_IWICMetadataQueryReader
))
60 *ppvObject
= &This
->IWICMetadataQueryReader_iface
;
66 IUnknown_AddRef((IUnknown
*)*ppvObject
);
73 static ULONG WINAPI
mqr_AddRef(IWICMetadataQueryReader
*iface
)
75 QueryReader
*This
= impl_from_IWICMetadataQueryReader(iface
);
76 ULONG ref
= InterlockedIncrement(&This
->ref
);
77 TRACE("(%p) refcount=%u\n", This
, ref
);
81 static ULONG WINAPI
mqr_Release(IWICMetadataQueryReader
*iface
)
83 QueryReader
*This
= impl_from_IWICMetadataQueryReader(iface
);
84 ULONG ref
= InterlockedDecrement(&This
->ref
);
85 TRACE("(%p) refcount=%u\n", This
, ref
);
88 IWICMetadataBlockReader_Release(This
->block
);
89 HeapFree(GetProcessHeap(), 0, This
->root
);
90 HeapFree(GetProcessHeap(), 0, This
);
95 static HRESULT WINAPI
mqr_GetContainerFormat(IWICMetadataQueryReader
*iface
, GUID
*format
)
97 QueryReader
*This
= impl_from_IWICMetadataQueryReader(iface
);
99 TRACE("(%p,%p)\n", This
, format
);
101 return IWICMetadataBlockReader_GetContainerFormat(This
->block
, format
);
104 static HRESULT WINAPI
mqr_GetLocation(IWICMetadataQueryReader
*iface
, UINT len
, WCHAR
*location
, UINT
*ret_len
)
106 QueryReader
*This
= impl_from_IWICMetadataQueryReader(iface
);
110 TRACE("(%p,%u,%p,%p)\n", This
, len
, location
, ret_len
);
112 if (!ret_len
) return E_INVALIDARG
;
114 root
= This
->root
? This
->root
: L
"/";
115 actual_len
= lstrlenW(root
) + 1;
119 if (len
< actual_len
)
120 return WINCODEC_ERR_INSUFFICIENTBUFFER
;
122 memcpy(location
, root
, actual_len
* sizeof(WCHAR
));
125 *ret_len
= actual_len
;
143 { 4, {'c','h','a','r'}, VT_I1
},
144 { 5, {'u','c','h','a','r'}, VT_UI1
},
145 { 5, {'s','h','o','r','t'}, VT_I2
},
146 { 6, {'u','s','h','o','r','t'}, VT_UI2
},
147 { 4, {'l','o','n','g'}, VT_I4
},
148 { 5, {'u','l','o','n','g'}, VT_UI4
},
149 { 3, {'i','n','t'}, VT_I4
},
150 { 4, {'u','i','n','t'}, VT_UI4
},
151 { 8, {'l','o','n','g','l','o','n','g'}, VT_I8
},
152 { 9, {'u','l','o','n','g','l','o','n','g'}, VT_UI8
},
153 { 5, {'f','l','o','a','t'}, VT_R4
},
154 { 6, {'d','o','u','b','l','e'}, VT_R8
},
155 { 3, {'s','t','r'}, VT_LPSTR
},
156 { 4, {'w','s','t','r'}, VT_LPWSTR
},
157 { 4, {'g','u','i','d'}, VT_CLSID
},
158 { 4, {'b','o','o','l'}, VT_BOOL
}
161 static VARTYPE
map_type(struct string_t
*str
)
165 for (i
= 0; i
< ARRAY_SIZE(str2vt
); i
++)
167 if (str2vt
[i
].len
== str
->len
)
169 if (CompareStringW(LOCALE_SYSTEM_DEFAULT
, NORM_IGNORECASE
,
170 str
->str
, str
->len
, str2vt
[i
].str
, str2vt
[i
].len
) == CSTR_EQUAL
)
175 WARN("type %s is not recognized\n", wine_dbgstr_wn(str
->str
, str
->len
));
180 static HRESULT
get_token(struct string_t
*elem
, PROPVARIANT
*id
, PROPVARIANT
*schema
, int *idx
)
182 const WCHAR
*start
, *end
, *p
;
184 struct string_t next_elem
;
187 TRACE("%s, len %d\n", wine_dbgstr_wn(elem
->str
, elem
->len
), elem
->len
);
190 PropVariantInit(schema
);
192 if (!elem
->len
) return S_OK
;
200 if (start
[1] < '0' || start
[1] > '9') return DISP_E_TYPEMISMATCH
;
202 *idx
= wcstol(start
+ 1, &idx_end
, 10);
203 if (idx_end
> elem
->str
+ elem
->len
) return WINCODEC_ERR_INVALIDQUERYREQUEST
;
204 if (*idx_end
!= ']') return WINCODEC_ERR_INVALIDQUERYREQUEST
;
205 if (*idx
< 0) return WINCODEC_ERR_INVALIDQUERYREQUEST
;
209 next_elem
.len
= elem
->len
- (end
- start
);
210 hr
= get_token(&next_elem
, id
, schema
, idx
);
213 TRACE("get_token error %#x\n", hr
);
216 elem
->len
= (end
- start
) + next_elem
.len
;
218 TRACE("indexed %s [%d]\n", wine_dbgstr_wn(elem
->str
, elem
->len
), *idx
);
221 else if (*start
== '{')
224 PROPVARIANT next_token
;
226 end
= wmemchr(start
+ 1, '=', elem
->len
- 1);
227 if (!end
) return WINCODEC_ERR_INVALIDQUERYREQUEST
;
228 if (end
> elem
->str
+ elem
->len
) return WINCODEC_ERR_INVALIDQUERYREQUEST
;
230 next_elem
.str
= start
+ 1;
231 next_elem
.len
= end
- start
- 1;
232 vt
= map_type(&next_elem
);
233 TRACE("type %s => %d\n", wine_dbgstr_wn(next_elem
.str
, next_elem
.len
), vt
);
234 if (vt
== VT_ILLEGAL
) return WINCODEC_ERR_WRONGSTATE
;
236 next_token
.vt
= VT_BSTR
;
237 next_token
.bstrVal
= SysAllocStringLen(NULL
, elem
->len
- (end
- start
) + 1);
238 if (!next_token
.bstrVal
) return E_OUTOFMEMORY
;
240 bstr
= next_token
.bstrVal
;
243 while (*end
&& *end
!= '}' && end
- start
< elem
->len
)
245 if (*end
== '\\') end
++;
250 PropVariantClear(&next_token
);
251 return WINCODEC_ERR_INVALIDQUERYREQUEST
;
254 TRACE("schema/id %s\n", wine_dbgstr_w(next_token
.bstrVal
));
259 id
->puuid
= CoTaskMemAlloc(sizeof(GUID
));
262 PropVariantClear(&next_token
);
263 return E_OUTOFMEMORY
;
266 hr
= UuidFromStringW(next_token
.bstrVal
, id
->puuid
);
269 hr
= PropVariantChangeType(id
, &next_token
, 0, vt
);
270 PropVariantClear(&next_token
);
273 PropVariantClear(id
);
274 PropVariantClear(schema
);
281 PROPVARIANT next_id
, next_schema
;
284 next_elem
.str
= end
+ 1;
285 next_elem
.len
= elem
->len
- (end
- start
+ 1);
286 hr
= get_token(&next_elem
, &next_id
, &next_schema
, &next_idx
);
289 TRACE("get_token error %#x\n", hr
);
292 elem
->len
= (end
- start
+ 1) + next_elem
.len
;
294 TRACE("id %s [%d]\n", wine_dbgstr_wn(elem
->str
, elem
->len
), *idx
);
296 if (next_schema
.vt
!= VT_EMPTY
)
298 PropVariantClear(&next_id
);
299 PropVariantClear(&next_schema
);
300 return WINCODEC_ERR_WRONGSTATE
;
309 elem
->len
= end
- start
;
313 end
= wmemchr(start
, '/', elem
->len
);
314 if (!end
) end
= start
+ elem
->len
;
316 p
= wmemchr(start
, ':', end
- start
);
319 next_elem
.str
= p
+ 1;
320 next_elem
.len
= end
- p
- 1;
322 elem
->len
= p
- start
;
325 elem
->len
= end
- start
;
328 id
->bstrVal
= SysAllocStringLen(NULL
, elem
->len
+ 1);
329 if (!id
->bstrVal
) return E_OUTOFMEMORY
;
333 while (p
- elem
->str
< elem
->len
)
339 TRACE("%s [%d]\n", wine_dbgstr_variant((VARIANT
*)id
), *idx
);
343 PROPVARIANT next_id
, next_schema
;
346 hr
= get_token(&next_elem
, &next_id
, &next_schema
, &next_idx
);
349 TRACE("get_token error %#x\n", hr
);
350 PropVariantClear(id
);
351 PropVariantClear(schema
);
354 elem
->len
+= next_elem
.len
+ 1;
356 TRACE("id %s [%d]\n", wine_dbgstr_wn(elem
->str
, elem
->len
), *idx
);
358 if (next_schema
.vt
!= VT_EMPTY
)
360 PropVariantClear(&next_id
);
361 PropVariantClear(&next_schema
);
362 PropVariantClear(id
);
363 PropVariantClear(schema
);
364 return WINCODEC_ERR_WRONGSTATE
;
374 static HRESULT
find_reader_from_block(IWICMetadataBlockReader
*block_reader
, UINT index
,
375 GUID
*guid
, IWICMetadataReader
**reader
)
379 IWICMetadataReader
*new_reader
;
380 UINT count
, i
, matched_index
;
384 hr
= IWICMetadataBlockReader_GetCount(block_reader
, &count
);
385 if (hr
!= S_OK
) return hr
;
389 for (i
= 0; i
< count
; i
++)
391 hr
= IWICMetadataBlockReader_GetReaderByIndex(block_reader
, i
, &new_reader
);
392 if (hr
!= S_OK
) return hr
;
394 hr
= IWICMetadataReader_GetMetadataFormat(new_reader
, &format
);
397 if (IsEqualGUID(&format
, guid
))
399 if (matched_index
== index
)
401 *reader
= new_reader
;
409 IWICMetadataReader_Release(new_reader
);
410 if (hr
!= S_OK
) return hr
;
413 return WINCODEC_ERR_PROPERTYNOTFOUND
;
416 static HRESULT
get_next_reader(IWICMetadataReader
*reader
, UINT index
,
417 GUID
*guid
, IWICMetadataReader
**new_reader
)
420 PROPVARIANT schema
, id
, value
;
424 PropVariantInit(&schema
);
425 PropVariantInit(&id
);
426 PropVariantInit(&value
);
431 schema
.uiVal
= index
;
436 hr
= IWICMetadataReader_GetValue(reader
, &schema
, &id
, &value
);
437 if (hr
!= S_OK
) return hr
;
439 if (value
.vt
== VT_UNKNOWN
)
440 hr
= IUnknown_QueryInterface(value
.punkVal
, &IID_IWICMetadataReader
, (void **)new_reader
);
442 hr
= WINCODEC_ERR_UNEXPECTEDMETADATATYPE
;
444 PropVariantClear(&value
);
448 static HRESULT WINAPI
mqr_GetMetadataByName(IWICMetadataQueryReader
*iface
, LPCWSTR query
, PROPVARIANT
*value
)
450 QueryReader
*This
= impl_from_IWICMetadataQueryReader(iface
);
451 struct string_t elem
;
455 PROPVARIANT tk_id
, tk_schema
, new_value
;
457 IWICMetadataReader
*reader
;
460 TRACE("(%p,%s,%p)\n", This
, wine_dbgstr_w(query
), value
);
462 len
= lstrlenW(query
) + 1;
463 if (This
->root
) len
+= lstrlenW(This
->root
);
464 full_query
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
467 lstrcpyW(full_query
, This
->root
);
468 lstrcatW(full_query
, query
);
470 PropVariantInit(&tk_id
);
471 PropVariantInit(&tk_schema
);
472 PropVariantInit(&new_value
);
481 WARN("query should start with '/'\n");
482 hr
= WINCODEC_ERR_PROPERTYNOTSUPPORTED
;
490 elem
.len
= lstrlenW(p
);
491 hr
= get_token(&elem
, &tk_id
, &tk_schema
, &index
);
494 WARN("get_token error %#x\n", hr
);
497 TRACE("parsed %d characters: %s, index %d\n", elem
.len
, wine_dbgstr_wn(elem
.str
, elem
.len
), index
);
498 TRACE("id %s, schema %s\n", wine_dbgstr_variant((VARIANT
*)&tk_id
), wine_dbgstr_variant((VARIANT
*)&tk_schema
));
500 if (!elem
.len
) break;
502 if (tk_id
.vt
== VT_CLSID
|| (tk_id
.vt
== VT_BSTR
&& WICMapShortNameToGuid(tk_id
.bstrVal
, &guid
) == S_OK
))
506 if (tk_schema
.vt
!= VT_EMPTY
)
508 FIXME("unsupported schema vt %u\n", tk_schema
.vt
);
509 PropVariantClear(&tk_schema
);
512 if (tk_id
.vt
== VT_CLSID
) guid
= *tk_id
.puuid
;
516 IWICMetadataReader
*new_reader
;
518 hr
= get_next_reader(reader
, index
, &guid
, &new_reader
);
519 IWICMetadataReader_Release(reader
);
523 hr
= find_reader_from_block(This
->block
, index
, &guid
, &reader
);
525 if (hr
!= S_OK
) break;
527 root
= SysAllocStringLen(NULL
, elem
.str
+ elem
.len
- full_query
+ 2);
533 lstrcpynW(root
, full_query
, p
- full_query
+ elem
.len
+ 1);
535 PropVariantClear(&new_value
);
536 new_value
.vt
= VT_UNKNOWN
;
537 hr
= MetadataQueryReader_CreateInstance(This
->block
, root
, (IWICMetadataQueryReader
**)&new_value
.punkVal
);
539 if (hr
!= S_OK
) break;
543 PROPVARIANT schema
, id
;
547 hr
= WINCODEC_ERR_INVALIDQUERYREQUEST
;
551 if (tk_schema
.vt
== VT_BSTR
)
553 hr
= IWICMetadataReader_GetMetadataFormat(reader
, &guid
);
554 if (hr
!= S_OK
) break;
556 schema
.vt
= VT_LPWSTR
;
557 schema
.pwszVal
= (LPWSTR
)map_shortname_to_schema(&guid
, tk_schema
.bstrVal
);
559 schema
.pwszVal
= tk_schema
.bstrVal
;
564 if (tk_id
.vt
== VT_BSTR
)
567 id
.pwszVal
= tk_id
.bstrVal
;
572 PropVariantClear(&new_value
);
573 hr
= IWICMetadataReader_GetValue(reader
, &schema
, &id
, &new_value
);
574 if (hr
!= S_OK
) break;
579 PropVariantClear(&tk_id
);
580 PropVariantClear(&tk_schema
);
584 IWICMetadataReader_Release(reader
);
586 PropVariantClear(&tk_id
);
587 PropVariantClear(&tk_schema
);
589 if (hr
== S_OK
&& value
)
592 PropVariantClear(&new_value
);
594 HeapFree(GetProcessHeap(), 0, full_query
);
599 static HRESULT WINAPI
mqr_GetEnumerator(IWICMetadataQueryReader
*iface
,
600 IEnumString
**ppIEnumString
)
602 QueryReader
*This
= impl_from_IWICMetadataQueryReader(iface
);
603 FIXME("(%p,%p)\n", This
, ppIEnumString
);
607 static IWICMetadataQueryReaderVtbl mqr_vtbl
= {
611 mqr_GetContainerFormat
,
613 mqr_GetMetadataByName
,
617 HRESULT
MetadataQueryReader_CreateInstance(IWICMetadataBlockReader
*mbr
, const WCHAR
*root
, IWICMetadataQueryReader
**out
)
621 obj
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*obj
));
623 return E_OUTOFMEMORY
;
625 obj
->IWICMetadataQueryReader_iface
.lpVtbl
= &mqr_vtbl
;
628 IWICMetadataBlockReader_AddRef(mbr
);
631 obj
->root
= root
? heap_strdupW(root
) : NULL
;
633 *out
= &obj
->IWICMetadataQueryReader_iface
;
640 IWICMetadataQueryWriter IWICMetadataQueryWriter_iface
;
642 IWICMetadataBlockWriter
*block
;
647 static inline QueryWriter
*impl_from_IWICMetadataQueryWriter(IWICMetadataQueryWriter
*iface
)
649 return CONTAINING_RECORD(iface
, QueryWriter
, IWICMetadataQueryWriter_iface
);
652 static HRESULT WINAPI
mqw_QueryInterface(IWICMetadataQueryWriter
*iface
, REFIID riid
,
655 QueryWriter
*writer
= impl_from_IWICMetadataQueryWriter(iface
);
657 TRACE("writer %p, riid %s, object %p.\n", writer
, debugstr_guid(riid
), object
);
659 if (IsEqualGUID(riid
, &IID_IUnknown
)
660 || IsEqualGUID(riid
, &IID_IWICMetadataQueryWriter
)
661 || IsEqualGUID(riid
, &IID_IWICMetadataQueryReader
))
662 *object
= &writer
->IWICMetadataQueryWriter_iface
;
668 IUnknown_AddRef((IUnknown
*)*object
);
672 return E_NOINTERFACE
;
675 static ULONG WINAPI
mqw_AddRef(IWICMetadataQueryWriter
*iface
)
677 QueryWriter
*writer
= impl_from_IWICMetadataQueryWriter(iface
);
678 ULONG ref
= InterlockedIncrement(&writer
->ref
);
680 TRACE("writer %p, refcount=%u\n", writer
, ref
);
685 static ULONG WINAPI
mqw_Release(IWICMetadataQueryWriter
*iface
)
687 QueryWriter
*writer
= impl_from_IWICMetadataQueryWriter(iface
);
688 ULONG ref
= InterlockedDecrement(&writer
->ref
);
690 TRACE("writer %p, refcount=%u.\n", writer
, ref
);
694 IWICMetadataBlockWriter_Release(writer
->block
);
695 HeapFree(GetProcessHeap(), 0, writer
->root
);
696 HeapFree(GetProcessHeap(), 0, writer
);
701 static HRESULT WINAPI
mqw_GetContainerFormat(IWICMetadataQueryWriter
*iface
, GUID
*container_format
)
703 FIXME("iface %p, container_format %p stub.\n", iface
, container_format
);
708 static HRESULT WINAPI
mqw_GetEnumerator(IWICMetadataQueryWriter
*iface
, IEnumString
**enum_string
)
710 FIXME("iface %p, enum_string %p stub.\n", iface
, enum_string
);
715 static HRESULT WINAPI
mqw_GetLocation(IWICMetadataQueryWriter
*iface
, UINT max_length
, WCHAR
*namespace, UINT
*actual_length
)
717 FIXME("iface %p, max_length %u, namespace %s, actual_length %p stub.\n",
718 iface
, max_length
, debugstr_w(namespace), actual_length
);
723 static HRESULT WINAPI
mqw_GetMetadataByName(IWICMetadataQueryWriter
*iface
, LPCWSTR name
, PROPVARIANT
*value
)
725 FIXME("name %s, value %p stub.\n", debugstr_w(name
), value
);
730 static HRESULT WINAPI
mqw_SetMetadataByName(IWICMetadataQueryWriter
*iface
, LPCWSTR name
, const PROPVARIANT
*value
)
732 FIXME("iface %p, name %s, value %p stub.\n", iface
, debugstr_w(name
), value
);
737 static HRESULT WINAPI
mqw_RemoveMetadataByName(IWICMetadataQueryWriter
*iface
, LPCWSTR name
)
739 FIXME("iface %p, name %s stub.\n", iface
, debugstr_w(name
));
744 static const IWICMetadataQueryWriterVtbl mqw_vtbl
=
749 mqw_GetContainerFormat
,
751 mqw_GetMetadataByName
,
753 mqw_SetMetadataByName
,
754 mqw_RemoveMetadataByName
,
757 HRESULT
MetadataQueryWriter_CreateInstance(IWICMetadataBlockWriter
*mbw
, const WCHAR
*root
, IWICMetadataQueryWriter
**out
)
761 obj
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*obj
));
763 return E_OUTOFMEMORY
;
765 obj
->IWICMetadataQueryWriter_iface
.lpVtbl
= &mqw_vtbl
;
768 IWICMetadataBlockWriter_AddRef(mbw
);
771 obj
->root
= root
? heap_strdupW(root
) : NULL
;
773 *out
= &obj
->IWICMetadataQueryWriter_iface
;
784 { &GUID_ContainerFormatBmp
, L
"bmp" },
785 { &GUID_ContainerFormatPng
, L
"png" },
786 { &GUID_ContainerFormatIco
, L
"ico" },
787 { &GUID_ContainerFormatJpeg
, L
"jpg" },
788 { &GUID_ContainerFormatTiff
, L
"tiff" },
789 { &GUID_ContainerFormatGif
, L
"gif" },
790 { &GUID_ContainerFormatWmp
, L
"wmphoto" },
791 { &GUID_MetadataFormatUnknown
, L
"unknown" },
792 { &GUID_MetadataFormatIfd
, L
"ifd" },
793 { &GUID_MetadataFormatSubIfd
, L
"sub" },
794 { &GUID_MetadataFormatExif
, L
"exif" },
795 { &GUID_MetadataFormatGps
, L
"gps" },
796 { &GUID_MetadataFormatInterop
, L
"interop" },
797 { &GUID_MetadataFormatApp0
, L
"app0" },
798 { &GUID_MetadataFormatApp1
, L
"app1" },
799 { &GUID_MetadataFormatApp13
, L
"app13" },
800 { &GUID_MetadataFormatIPTC
, L
"iptc" },
801 { &GUID_MetadataFormatIRB
, L
"irb" },
802 { &GUID_MetadataFormat8BIMIPTC
, L
"8bimiptc" },
803 { &GUID_MetadataFormat8BIMResolutionInfo
, L
"8bimResInfo" },
804 { &GUID_MetadataFormat8BIMIPTCDigest
, L
"8bimiptcdigest" },
805 { &GUID_MetadataFormatXMP
, L
"xmp" },
806 { &GUID_MetadataFormatThumbnail
, L
"thumb" },
807 { &GUID_MetadataFormatChunktEXt
, L
"tEXt" },
808 { &GUID_MetadataFormatXMPStruct
, L
"xmpstruct" },
809 { &GUID_MetadataFormatXMPBag
, L
"xmpbag" },
810 { &GUID_MetadataFormatXMPSeq
, L
"xmpseq" },
811 { &GUID_MetadataFormatXMPAlt
, L
"xmpalt" },
812 { &GUID_MetadataFormatLSD
, L
"logscrdesc" },
813 { &GUID_MetadataFormatIMD
, L
"imgdesc" },
814 { &GUID_MetadataFormatGCE
, L
"grctlext" },
815 { &GUID_MetadataFormatAPE
, L
"appext" },
816 { &GUID_MetadataFormatJpegChrominance
, L
"chrominance" },
817 { &GUID_MetadataFormatJpegLuminance
, L
"luminance" },
818 { &GUID_MetadataFormatJpegComment
, L
"com" },
819 { &GUID_MetadataFormatGifComment
, L
"commentext" },
820 { &GUID_MetadataFormatChunkgAMA
, L
"gAMA" },
821 { &GUID_MetadataFormatChunkbKGD
, L
"bKGD" },
822 { &GUID_MetadataFormatChunkiTXt
, L
"iTXt" },
823 { &GUID_MetadataFormatChunkcHRM
, L
"cHRM" },
824 { &GUID_MetadataFormatChunkhIST
, L
"hIST" },
825 { &GUID_MetadataFormatChunkiCCP
, L
"iCCP" },
826 { &GUID_MetadataFormatChunksRGB
, L
"sRGB" },
827 { &GUID_MetadataFormatChunktIME
, L
"tIME" }
830 HRESULT WINAPI
WICMapGuidToShortName(REFGUID guid
, UINT len
, WCHAR
*name
, UINT
*ret_len
)
834 TRACE("%s,%u,%p,%p\n", wine_dbgstr_guid(guid
), len
, name
, ret_len
);
836 if (!guid
) return E_INVALIDARG
;
838 for (i
= 0; i
< ARRAY_SIZE(guid2name
); i
++)
840 if (IsEqualGUID(guid
, guid2name
[i
].guid
))
844 if (!len
) return E_INVALIDARG
;
846 len
= min(len
- 1, lstrlenW(guid2name
[i
].name
));
847 memcpy(name
, guid2name
[i
].name
, len
* sizeof(WCHAR
));
850 if (len
< lstrlenW(guid2name
[i
].name
))
851 return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER
);
853 if (ret_len
) *ret_len
= lstrlenW(guid2name
[i
].name
) + 1;
858 return WINCODEC_ERR_PROPERTYNOTFOUND
;
861 HRESULT WINAPI
WICMapShortNameToGuid(PCWSTR name
, GUID
*guid
)
865 TRACE("%s,%p\n", debugstr_w(name
), guid
);
867 if (!name
|| !guid
) return E_INVALIDARG
;
869 for (i
= 0; i
< ARRAY_SIZE(guid2name
); i
++)
871 if (!lstrcmpiW(name
, guid2name
[i
].name
))
873 *guid
= *guid2name
[i
].guid
;
878 return WINCODEC_ERR_PROPERTYNOTFOUND
;
887 { L
"rdf", L
"http://www.w3.org/1999/02/22-rdf-syntax-ns#" },
888 { L
"dc", L
"http://purl.org/dc/elements/1.1/" },
889 { L
"xmp", L
"http://ns.adobe.com/xap/1.0/" },
890 { L
"xmpidq", L
"http://ns.adobe.com/xmp/Identifier/qual/1.0/" },
891 { L
"xmpRights", L
"http://ns.adobe.com/xap/1.0/rights/" },
892 { L
"xmpMM", L
"http://ns.adobe.com/xap/1.0/mm/" },
893 { L
"xmpBJ", L
"http://ns.adobe.com/xap/1.0/bj/" },
894 { L
"xmpTPg", L
"http://ns.adobe.com/xap/1.0/t/pg/" },
895 { L
"pdf", L
"http://ns.adobe.com/pdf/1.3/" },
896 { L
"photoshop", L
"http://ns.adobe.com/photoshop/1.0/" },
897 { L
"tiff", L
"http://ns.adobe.com/tiff/1.0/" },
898 { L
"exif", L
"http://ns.adobe.com/exif/1.0/" },
899 { L
"stDim", L
"http://ns.adobe.com/xap/1.0/sType/Dimensions#" },
900 { L
"xapGImg", L
"http://ns.adobe.com/xap/1.0/g/img/" },
901 { L
"stEvt", L
"http://ns.adobe.com/xap/1.0/sType/ResourceEvent#" },
902 { L
"stRef", L
"http://ns.adobe.com/xap/1.0/sType/ResourceRef#" },
903 { L
"stVer", L
"http://ns.adobe.com/xap/1.0/sType/Version#" },
904 { L
"stJob", L
"http://ns.adobe.com/xap/1.0/sType/Job#" },
905 { L
"aux", L
"http://ns.adobe.com/exif/1.0/aux/" },
906 { L
"crs", L
"http://ns.adobe.com/camera-raw-settings/1.0/" },
907 { L
"xmpDM", L
"http://ns.adobe.com/xmp/1.0/DynamicMedia/" },
908 { L
"Iptc4xmpCore", L
"http://iptc.org/std/Iptc4xmpCore/1.0/xmlns/" },
909 { L
"MicrosoftPhoto", L
"http://ns.microsoft.com/photo/1.0/" },
910 { L
"MP", L
"http://ns.microsoft.com/photo/1.2/" },
911 { L
"MPRI", L
"http://ns.microsoft.com/photo/1.2/t/RegionInfo#" },
912 { L
"MPReg", L
"http://ns.microsoft.com/photo/1.2/t/Region#" }
915 static const WCHAR
*map_shortname_to_schema(const GUID
*format
, const WCHAR
*name
)
919 /* It appears that the only metadata formats
920 * that support schemas are xmp and xmpstruct.
922 if (!IsEqualGUID(format
, &GUID_MetadataFormatXMP
) &&
923 !IsEqualGUID(format
, &GUID_MetadataFormatXMPStruct
))
926 for (i
= 0; i
< ARRAY_SIZE(name2schema
); i
++)
928 if (!wcscmp(name2schema
[i
].name
, name
))
929 return name2schema
[i
].schema
;
935 HRESULT WINAPI
WICMapSchemaToName(REFGUID format
, LPWSTR schema
, UINT len
, WCHAR
*name
, UINT
*ret_len
)
939 TRACE("%s,%s,%u,%p,%p\n", wine_dbgstr_guid(format
), debugstr_w(schema
), len
, name
, ret_len
);
941 if (!format
|| !schema
|| !ret_len
)
944 /* It appears that the only metadata formats
945 * that support schemas are xmp and xmpstruct.
947 if (!IsEqualGUID(format
, &GUID_MetadataFormatXMP
) &&
948 !IsEqualGUID(format
, &GUID_MetadataFormatXMPStruct
))
949 return WINCODEC_ERR_PROPERTYNOTFOUND
;
951 for (i
= 0; i
< ARRAY_SIZE(name2schema
); i
++)
953 if (!wcscmp(name2schema
[i
].schema
, schema
))
957 if (!len
) return E_INVALIDARG
;
959 len
= min(len
- 1, lstrlenW(name2schema
[i
].name
));
960 memcpy(name
, name2schema
[i
].name
, len
* sizeof(WCHAR
));
963 if (len
< lstrlenW(name2schema
[i
].name
))
964 return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER
);
967 *ret_len
= lstrlenW(name2schema
[i
].name
) + 1;
972 return WINCODEC_ERR_PROPERTYNOTFOUND
;