include: Be consistent in naming regarding MSF's block.
[wine.git] / dlls / windowscodecs / metadataquery.c
blob75da054cd38205cc941b1542a424dc5f148e4e81
1 /*
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 <stdarg.h>
21 #include <wchar.h>
23 #define COBJMACROS
24 #define NONAMELESSUNION
26 #include "windef.h"
27 #include "winbase.h"
28 #include "objbase.h"
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);
39 typedef struct {
40 IWICMetadataQueryReader IWICMetadataQueryReader_iface;
41 LONG ref;
42 IWICMetadataBlockReader *block;
43 WCHAR *root;
44 } QueryReader;
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,
52 void **ppvObject)
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;
61 else
62 *ppvObject = NULL;
64 if (*ppvObject)
66 IUnknown_AddRef((IUnknown*)*ppvObject);
67 return S_OK;
70 return E_NOINTERFACE;
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=%lu\n", This, ref);
78 return 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=%lu\n", This, ref);
86 if (!ref)
88 IWICMetadataBlockReader_Release(This->block);
89 free(This->root);
90 free(This);
92 return ref;
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);
107 const WCHAR *root;
108 UINT actual_len;
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;
117 if (location)
119 if (len < actual_len)
120 return WINCODEC_ERR_INSUFFICIENTBUFFER;
122 memcpy(location, root, actual_len * sizeof(WCHAR));
125 *ret_len = actual_len;
127 return S_OK;
130 struct string_t
132 const WCHAR *str;
133 int len;
136 static const struct
138 int len;
139 WCHAR str[10];
140 VARTYPE vt;
141 } str2vt[] =
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)
163 UINT i;
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)
171 return str2vt[i].vt;
175 WARN("type %s is not recognized\n", wine_dbgstr_wn(str->str, str->len));
177 return VT_ILLEGAL;
180 static HRESULT get_token(struct string_t *elem, PROPVARIANT *id, PROPVARIANT *schema, int *idx)
182 const WCHAR *start, *end, *p;
183 WCHAR *bstr;
184 struct string_t next_elem;
185 HRESULT hr;
187 TRACE("%s, len %d\n", wine_dbgstr_wn(elem->str, elem->len), elem->len);
189 PropVariantInit(id);
190 PropVariantInit(schema);
192 if (!elem->len) return S_OK;
194 start = elem->str;
196 if (*start == '[')
198 WCHAR *idx_end;
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;
206 end = idx_end + 1;
208 next_elem.str = end;
209 next_elem.len = elem->len - (end - start);
210 hr = get_token(&next_elem, id, schema, idx);
211 if (hr != S_OK)
213 TRACE("get_token error %#lx\n", hr);
214 return hr;
216 elem->len = (end - start) + next_elem.len;
218 TRACE("indexed %s [%d]\n", wine_dbgstr_wn(elem->str, elem->len), *idx);
219 return S_OK;
221 else if (*start == '{')
223 VARTYPE vt;
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;
242 end++;
243 while (*end && *end != '}' && end - start < elem->len)
245 if (*end == '\\') end++;
246 *bstr++ = *end++;
248 if (*end != '}')
250 PropVariantClear(&next_token);
251 return WINCODEC_ERR_INVALIDQUERYREQUEST;
253 *bstr = 0;
254 TRACE("schema/id %s\n", wine_dbgstr_w(next_token.bstrVal));
256 if (vt == VT_CLSID)
258 id->vt = VT_CLSID;
259 id->puuid = CoTaskMemAlloc(sizeof(GUID));
260 if (!id->puuid)
262 PropVariantClear(&next_token);
263 return E_OUTOFMEMORY;
266 hr = UuidFromStringW(next_token.bstrVal, id->puuid);
268 else
269 hr = PropVariantChangeType(id, &next_token, 0, vt);
270 PropVariantClear(&next_token);
271 if (hr != S_OK)
273 PropVariantClear(id);
274 PropVariantClear(schema);
275 return hr;
278 end++;
279 if (*end == ':')
281 PROPVARIANT next_id, next_schema;
282 int next_idx = 0;
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);
287 if (hr != S_OK)
289 TRACE("get_token error %#lx\n", hr);
290 return 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;
303 *schema = *id;
304 *id = next_id;
306 return S_OK;
309 elem->len = end - start;
310 return S_OK;
313 end = wmemchr(start, '/', elem->len);
314 if (!end) end = start + elem->len;
316 p = wmemchr(start, ':', end - start);
317 if (p)
319 next_elem.str = p + 1;
320 next_elem.len = end - p - 1;
322 elem->len = p - start;
324 else
325 elem->len = end - start;
327 id->vt = VT_BSTR;
328 id->bstrVal = SysAllocStringLen(NULL, elem->len + 1);
329 if (!id->bstrVal) return E_OUTOFMEMORY;
331 bstr = id->bstrVal;
332 p = elem->str;
333 while (p - elem->str < elem->len)
335 if (*p == '\\') p++;
336 *bstr++ = *p++;
338 *bstr = 0;
339 TRACE("%s [%d]\n", wine_dbgstr_variant((VARIANT *)id), *idx);
341 if (*p == ':')
343 PROPVARIANT next_id, next_schema;
344 int next_idx = 0;
346 hr = get_token(&next_elem, &next_id, &next_schema, &next_idx);
347 if (hr != S_OK)
349 TRACE("get_token error %#lx\n", hr);
350 PropVariantClear(id);
351 PropVariantClear(schema);
352 return hr;
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;
367 *schema = *id;
368 *id = next_id;
371 return S_OK;
374 static HRESULT find_reader_from_block(IWICMetadataBlockReader *block_reader, UINT index,
375 GUID *guid, IWICMetadataReader **reader)
377 HRESULT hr;
378 GUID format;
379 IWICMetadataReader *new_reader;
380 UINT count, i, matched_index;
382 *reader = NULL;
384 hr = IWICMetadataBlockReader_GetCount(block_reader, &count);
385 if (hr != S_OK) return hr;
387 matched_index = 0;
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);
395 if (hr == S_OK)
397 if (IsEqualGUID(&format, guid))
399 if (matched_index == index)
401 *reader = new_reader;
402 return S_OK;
405 matched_index++;
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)
419 HRESULT hr;
420 PROPVARIANT schema, id, value;
422 *new_reader = NULL;
424 PropVariantInit(&schema);
425 PropVariantInit(&id);
426 PropVariantInit(&value);
428 if (index)
430 schema.vt = VT_UI2;
431 schema.uiVal = index;
434 id.vt = VT_CLSID;
435 id.puuid = guid;
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);
441 else
442 hr = WINCODEC_ERR_UNEXPECTEDMETADATATYPE;
444 PropVariantClear(&value);
445 return hr;
448 static HRESULT WINAPI mqr_GetMetadataByName(IWICMetadataQueryReader *iface, LPCWSTR query, PROPVARIANT *value)
450 QueryReader *This = impl_from_IWICMetadataQueryReader(iface);
451 struct string_t elem;
452 WCHAR *full_query;
453 const WCHAR *p;
454 int index, len;
455 PROPVARIANT tk_id, tk_schema, new_value;
456 GUID guid;
457 IWICMetadataReader *reader;
458 HRESULT hr = S_OK;
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 = malloc(len * sizeof(WCHAR));
465 full_query[0] = 0;
466 if (This->root)
467 lstrcpyW(full_query, This->root);
468 lstrcatW(full_query, query);
470 PropVariantInit(&tk_id);
471 PropVariantInit(&tk_schema);
472 PropVariantInit(&new_value);
474 reader = NULL;
475 p = full_query;
477 while (*p)
479 if (*p != '/')
481 WARN("query should start with '/'\n");
482 hr = WINCODEC_ERR_PROPERTYNOTSUPPORTED;
483 break;
486 p++;
488 index = 0;
489 elem.str = p;
490 elem.len = lstrlenW(p);
491 hr = get_token(&elem, &tk_id, &tk_schema, &index);
492 if (hr != S_OK)
494 WARN("get_token error %#lx\n", hr);
495 break;
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))
504 WCHAR *root;
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;
514 if (reader)
516 IWICMetadataReader *new_reader;
518 hr = get_next_reader(reader, index, &guid, &new_reader);
519 IWICMetadataReader_Release(reader);
520 reader = new_reader;
522 else
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);
528 if (!root)
530 hr = E_OUTOFMEMORY;
531 break;
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);
538 SysFreeString(root);
539 if (hr != S_OK) break;
541 else
543 PROPVARIANT schema, id;
545 if (!reader)
547 hr = WINCODEC_ERR_INVALIDQUERYREQUEST;
548 break;
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);
558 if (!schema.pwszVal)
559 schema.pwszVal = tk_schema.bstrVal;
561 else
562 schema = tk_schema;
564 if (tk_id.vt == VT_BSTR)
566 id.vt = VT_LPWSTR;
567 id.pwszVal = tk_id.bstrVal;
569 else
570 id = tk_id;
572 PropVariantClear(&new_value);
573 hr = IWICMetadataReader_GetValue(reader, &schema, &id, &new_value);
574 if (hr != S_OK) break;
577 p += elem.len;
579 PropVariantClear(&tk_id);
580 PropVariantClear(&tk_schema);
583 if (reader)
584 IWICMetadataReader_Release(reader);
586 PropVariantClear(&tk_id);
587 PropVariantClear(&tk_schema);
589 if (hr == S_OK && value)
590 *value = new_value;
591 else
592 PropVariantClear(&new_value);
594 free(full_query);
596 return hr;
599 struct string_enumerator
601 IEnumString IEnumString_iface;
602 LONG ref;
605 static struct string_enumerator *impl_from_IEnumString(IEnumString *iface)
607 return CONTAINING_RECORD(iface, struct string_enumerator, IEnumString_iface);
610 static HRESULT WINAPI string_enumerator_QueryInterface(IEnumString *iface, REFIID riid, void **ppv)
612 struct string_enumerator *this = impl_from_IEnumString(iface);
614 TRACE("iface %p, riid %s, ppv %p.\n", iface, debugstr_guid(riid), ppv);
616 if (IsEqualGUID(riid, &IID_IEnumString) || IsEqualGUID(riid, &IID_IUnknown))
617 *ppv = &this->IEnumString_iface;
618 else
620 WARN("Unknown riid %s.\n", debugstr_guid(riid));
621 *ppv = NULL;
622 return E_NOINTERFACE;
625 IUnknown_AddRef(&this->IEnumString_iface);
626 return S_OK;
629 static ULONG WINAPI string_enumerator_AddRef(IEnumString *iface)
631 struct string_enumerator *this = impl_from_IEnumString(iface);
632 ULONG ref = InterlockedIncrement(&this->ref);
634 TRACE("iface %p, ref %lu.\n", iface, ref);
636 return ref;
639 static ULONG WINAPI string_enumerator_Release(IEnumString *iface)
641 struct string_enumerator *this = impl_from_IEnumString(iface);
642 ULONG ref = InterlockedDecrement(&this->ref);
644 TRACE("iface %p, ref %lu.\n", iface, ref);
646 if (!ref)
647 free(this);
649 return ref;
652 static HRESULT WINAPI string_enumerator_Next(IEnumString *iface, ULONG count, LPOLESTR *strings, ULONG *ret)
654 FIXME("iface %p, count %lu, strings %p, ret %p stub.\n", iface, count, strings, ret);
656 if (!strings || !ret)
657 return E_INVALIDARG;
659 *ret = 0;
660 return count ? S_FALSE : S_OK;
663 static HRESULT WINAPI string_enumerator_Reset(IEnumString *iface)
665 TRACE("iface %p.\n", iface);
667 return S_OK;
670 static HRESULT WINAPI string_enumerator_Skip(IEnumString *iface, ULONG count)
672 FIXME("iface %p, count %lu stub.\n", iface, count);
674 return count ? S_FALSE : S_OK;
677 static HRESULT WINAPI string_enumerator_Clone(IEnumString *iface, IEnumString **out)
679 FIXME("iface %p, out %p stub.\n", iface, out);
681 *out = NULL;
682 return E_NOTIMPL;
685 static const IEnumStringVtbl string_enumerator_vtbl =
687 string_enumerator_QueryInterface,
688 string_enumerator_AddRef,
689 string_enumerator_Release,
690 string_enumerator_Next,
691 string_enumerator_Skip,
692 string_enumerator_Reset,
693 string_enumerator_Clone
696 static HRESULT string_enumerator_create(IEnumString **enum_string)
698 struct string_enumerator *object;
700 if (!(object = calloc(1, sizeof(*object))))
701 return E_OUTOFMEMORY;
703 object->IEnumString_iface.lpVtbl = &string_enumerator_vtbl;
704 object->ref = 1;
706 *enum_string = &object->IEnumString_iface;
708 return S_OK;
711 static HRESULT WINAPI mqr_GetEnumerator(IWICMetadataQueryReader *iface,
712 IEnumString **enum_string)
714 TRACE("iface %p, enum_string %p.\n", iface, enum_string);
716 return string_enumerator_create(enum_string);
719 static IWICMetadataQueryReaderVtbl mqr_vtbl = {
720 mqr_QueryInterface,
721 mqr_AddRef,
722 mqr_Release,
723 mqr_GetContainerFormat,
724 mqr_GetLocation,
725 mqr_GetMetadataByName,
726 mqr_GetEnumerator
729 HRESULT MetadataQueryReader_CreateInstance(IWICMetadataBlockReader *mbr, const WCHAR *root, IWICMetadataQueryReader **out)
731 QueryReader *obj;
733 obj = calloc(1, sizeof(*obj));
734 if (!obj)
735 return E_OUTOFMEMORY;
737 obj->IWICMetadataQueryReader_iface.lpVtbl = &mqr_vtbl;
738 obj->ref = 1;
740 IWICMetadataBlockReader_AddRef(mbr);
741 obj->block = mbr;
743 obj->root = wcsdup(root);
745 *out = &obj->IWICMetadataQueryReader_iface;
747 return S_OK;
750 typedef struct
752 IWICMetadataQueryWriter IWICMetadataQueryWriter_iface;
753 LONG ref;
754 IWICMetadataBlockWriter *block;
755 WCHAR *root;
757 QueryWriter;
759 static inline QueryWriter *impl_from_IWICMetadataQueryWriter(IWICMetadataQueryWriter *iface)
761 return CONTAINING_RECORD(iface, QueryWriter, IWICMetadataQueryWriter_iface);
764 static HRESULT WINAPI mqw_QueryInterface(IWICMetadataQueryWriter *iface, REFIID riid,
765 void **object)
767 QueryWriter *writer = impl_from_IWICMetadataQueryWriter(iface);
769 TRACE("writer %p, riid %s, object %p.\n", writer, debugstr_guid(riid), object);
771 if (IsEqualGUID(riid, &IID_IUnknown)
772 || IsEqualGUID(riid, &IID_IWICMetadataQueryWriter)
773 || IsEqualGUID(riid, &IID_IWICMetadataQueryReader))
774 *object = &writer->IWICMetadataQueryWriter_iface;
775 else
776 *object = NULL;
778 if (*object)
780 IUnknown_AddRef((IUnknown *)*object);
781 return S_OK;
784 return E_NOINTERFACE;
787 static ULONG WINAPI mqw_AddRef(IWICMetadataQueryWriter *iface)
789 QueryWriter *writer = impl_from_IWICMetadataQueryWriter(iface);
790 ULONG ref = InterlockedIncrement(&writer->ref);
792 TRACE("writer %p, refcount=%lu\n", writer, ref);
794 return ref;
797 static ULONG WINAPI mqw_Release(IWICMetadataQueryWriter *iface)
799 QueryWriter *writer = impl_from_IWICMetadataQueryWriter(iface);
800 ULONG ref = InterlockedDecrement(&writer->ref);
802 TRACE("writer %p, refcount=%lu.\n", writer, ref);
804 if (!ref)
806 IWICMetadataBlockWriter_Release(writer->block);
807 free(writer->root);
808 free(writer);
810 return ref;
813 static HRESULT WINAPI mqw_GetContainerFormat(IWICMetadataQueryWriter *iface, GUID *container_format)
815 FIXME("iface %p, container_format %p stub.\n", iface, container_format);
817 return E_NOTIMPL;
820 static HRESULT WINAPI mqw_GetEnumerator(IWICMetadataQueryWriter *iface, IEnumString **enum_string)
822 TRACE("iface %p, enum_string %p.\n", iface, enum_string);
824 return string_enumerator_create(enum_string);
827 static HRESULT WINAPI mqw_GetLocation(IWICMetadataQueryWriter *iface, UINT max_length, WCHAR *namespace, UINT *actual_length)
829 FIXME("iface %p, max_length %u, namespace %s, actual_length %p stub.\n",
830 iface, max_length, debugstr_w(namespace), actual_length);
832 return E_NOTIMPL;
835 static HRESULT WINAPI mqw_GetMetadataByName(IWICMetadataQueryWriter *iface, LPCWSTR name, PROPVARIANT *value)
837 FIXME("name %s, value %p stub.\n", debugstr_w(name), value);
839 return E_NOTIMPL;
842 static HRESULT WINAPI mqw_SetMetadataByName(IWICMetadataQueryWriter *iface, LPCWSTR name, const PROPVARIANT *value)
844 FIXME("iface %p, name %s, value %p stub.\n", iface, debugstr_w(name), value);
846 return E_NOTIMPL;
849 static HRESULT WINAPI mqw_RemoveMetadataByName(IWICMetadataQueryWriter *iface, LPCWSTR name)
851 FIXME("iface %p, name %s stub.\n", iface, debugstr_w(name));
853 return E_NOTIMPL;
856 static const IWICMetadataQueryWriterVtbl mqw_vtbl =
858 mqw_QueryInterface,
859 mqw_AddRef,
860 mqw_Release,
861 mqw_GetContainerFormat,
862 mqw_GetLocation,
863 mqw_GetMetadataByName,
864 mqw_GetEnumerator,
865 mqw_SetMetadataByName,
866 mqw_RemoveMetadataByName,
869 HRESULT MetadataQueryWriter_CreateInstance(IWICMetadataBlockWriter *mbw, const WCHAR *root, IWICMetadataQueryWriter **out)
871 QueryWriter *obj;
873 obj = calloc(1, sizeof(*obj));
874 if (!obj)
875 return E_OUTOFMEMORY;
877 obj->IWICMetadataQueryWriter_iface.lpVtbl = &mqw_vtbl;
878 obj->ref = 1;
880 IWICMetadataBlockWriter_AddRef(mbw);
881 obj->block = mbw;
883 obj->root = wcsdup(root);
885 *out = &obj->IWICMetadataQueryWriter_iface;
887 return S_OK;
890 static const struct
892 const GUID *guid;
893 const WCHAR *name;
894 } guid2name[] =
896 { &GUID_ContainerFormatBmp, L"bmp" },
897 { &GUID_ContainerFormatPng, L"png" },
898 { &GUID_ContainerFormatIco, L"ico" },
899 { &GUID_ContainerFormatJpeg, L"jpg" },
900 { &GUID_ContainerFormatTiff, L"tiff" },
901 { &GUID_ContainerFormatGif, L"gif" },
902 { &GUID_ContainerFormatWmp, L"wmphoto" },
903 { &GUID_MetadataFormatUnknown, L"unknown" },
904 { &GUID_MetadataFormatIfd, L"ifd" },
905 { &GUID_MetadataFormatSubIfd, L"sub" },
906 { &GUID_MetadataFormatExif, L"exif" },
907 { &GUID_MetadataFormatGps, L"gps" },
908 { &GUID_MetadataFormatInterop, L"interop" },
909 { &GUID_MetadataFormatApp0, L"app0" },
910 { &GUID_MetadataFormatApp1, L"app1" },
911 { &GUID_MetadataFormatApp13, L"app13" },
912 { &GUID_MetadataFormatIPTC, L"iptc" },
913 { &GUID_MetadataFormatIRB, L"irb" },
914 { &GUID_MetadataFormat8BIMIPTC, L"8bimiptc" },
915 { &GUID_MetadataFormat8BIMResolutionInfo, L"8bimResInfo" },
916 { &GUID_MetadataFormat8BIMIPTCDigest, L"8bimiptcdigest" },
917 { &GUID_MetadataFormatXMP, L"xmp" },
918 { &GUID_MetadataFormatThumbnail, L"thumb" },
919 { &GUID_MetadataFormatChunktEXt, L"tEXt" },
920 { &GUID_MetadataFormatXMPStruct, L"xmpstruct" },
921 { &GUID_MetadataFormatXMPBag, L"xmpbag" },
922 { &GUID_MetadataFormatXMPSeq, L"xmpseq" },
923 { &GUID_MetadataFormatXMPAlt, L"xmpalt" },
924 { &GUID_MetadataFormatLSD, L"logscrdesc" },
925 { &GUID_MetadataFormatIMD, L"imgdesc" },
926 { &GUID_MetadataFormatGCE, L"grctlext" },
927 { &GUID_MetadataFormatAPE, L"appext" },
928 { &GUID_MetadataFormatJpegChrominance, L"chrominance" },
929 { &GUID_MetadataFormatJpegLuminance, L"luminance" },
930 { &GUID_MetadataFormatJpegComment, L"com" },
931 { &GUID_MetadataFormatGifComment, L"commentext" },
932 { &GUID_MetadataFormatChunkgAMA, L"gAMA" },
933 { &GUID_MetadataFormatChunkbKGD, L"bKGD" },
934 { &GUID_MetadataFormatChunkiTXt, L"iTXt" },
935 { &GUID_MetadataFormatChunkcHRM, L"cHRM" },
936 { &GUID_MetadataFormatChunkhIST, L"hIST" },
937 { &GUID_MetadataFormatChunkiCCP, L"iCCP" },
938 { &GUID_MetadataFormatChunksRGB, L"sRGB" },
939 { &GUID_MetadataFormatChunktIME, L"tIME" }
942 HRESULT WINAPI WICMapGuidToShortName(REFGUID guid, UINT len, WCHAR *name, UINT *ret_len)
944 UINT i;
946 TRACE("%s,%u,%p,%p\n", wine_dbgstr_guid(guid), len, name, ret_len);
948 if (!guid) return E_INVALIDARG;
950 for (i = 0; i < ARRAY_SIZE(guid2name); i++)
952 if (IsEqualGUID(guid, guid2name[i].guid))
954 if (name)
956 if (!len) return E_INVALIDARG;
958 len = min(len - 1, lstrlenW(guid2name[i].name));
959 memcpy(name, guid2name[i].name, len * sizeof(WCHAR));
960 name[len] = 0;
962 if (len < lstrlenW(guid2name[i].name))
963 return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
965 if (ret_len) *ret_len = lstrlenW(guid2name[i].name) + 1;
966 return S_OK;
970 return WINCODEC_ERR_PROPERTYNOTFOUND;
973 HRESULT WINAPI WICMapShortNameToGuid(PCWSTR name, GUID *guid)
975 UINT i;
977 TRACE("%s,%p\n", debugstr_w(name), guid);
979 if (!name || !guid) return E_INVALIDARG;
981 for (i = 0; i < ARRAY_SIZE(guid2name); i++)
983 if (!lstrcmpiW(name, guid2name[i].name))
985 *guid = *guid2name[i].guid;
986 return S_OK;
990 return WINCODEC_ERR_PROPERTYNOTFOUND;
993 static const struct
995 const WCHAR *name;
996 const WCHAR *schema;
997 } name2schema[] =
999 { L"rdf", L"http://www.w3.org/1999/02/22-rdf-syntax-ns#" },
1000 { L"dc", L"http://purl.org/dc/elements/1.1/" },
1001 { L"xmp", L"http://ns.adobe.com/xap/1.0/" },
1002 { L"xmpidq", L"http://ns.adobe.com/xmp/Identifier/qual/1.0/" },
1003 { L"xmpRights", L"http://ns.adobe.com/xap/1.0/rights/" },
1004 { L"xmpMM", L"http://ns.adobe.com/xap/1.0/mm/" },
1005 { L"xmpBJ", L"http://ns.adobe.com/xap/1.0/bj/" },
1006 { L"xmpTPg", L"http://ns.adobe.com/xap/1.0/t/pg/" },
1007 { L"pdf", L"http://ns.adobe.com/pdf/1.3/" },
1008 { L"photoshop", L"http://ns.adobe.com/photoshop/1.0/" },
1009 { L"tiff", L"http://ns.adobe.com/tiff/1.0/" },
1010 { L"exif", L"http://ns.adobe.com/exif/1.0/" },
1011 { L"stDim", L"http://ns.adobe.com/xap/1.0/sType/Dimensions#" },
1012 { L"xapGImg", L"http://ns.adobe.com/xap/1.0/g/img/" },
1013 { L"stEvt", L"http://ns.adobe.com/xap/1.0/sType/ResourceEvent#" },
1014 { L"stRef", L"http://ns.adobe.com/xap/1.0/sType/ResourceRef#" },
1015 { L"stVer", L"http://ns.adobe.com/xap/1.0/sType/Version#" },
1016 { L"stJob", L"http://ns.adobe.com/xap/1.0/sType/Job#" },
1017 { L"aux", L"http://ns.adobe.com/exif/1.0/aux/" },
1018 { L"crs", L"http://ns.adobe.com/camera-raw-settings/1.0/" },
1019 { L"xmpDM", L"http://ns.adobe.com/xmp/1.0/DynamicMedia/" },
1020 { L"Iptc4xmpCore", L"http://iptc.org/std/Iptc4xmpCore/1.0/xmlns/" },
1021 { L"MicrosoftPhoto", L"http://ns.microsoft.com/photo/1.0/" },
1022 { L"MP", L"http://ns.microsoft.com/photo/1.2/" },
1023 { L"MPRI", L"http://ns.microsoft.com/photo/1.2/t/RegionInfo#" },
1024 { L"MPReg", L"http://ns.microsoft.com/photo/1.2/t/Region#" }
1027 static const WCHAR *map_shortname_to_schema(const GUID *format, const WCHAR *name)
1029 UINT i;
1031 /* It appears that the only metadata formats
1032 * that support schemas are xmp and xmpstruct.
1034 if (!IsEqualGUID(format, &GUID_MetadataFormatXMP) &&
1035 !IsEqualGUID(format, &GUID_MetadataFormatXMPStruct))
1036 return NULL;
1038 for (i = 0; i < ARRAY_SIZE(name2schema); i++)
1040 if (!wcscmp(name2schema[i].name, name))
1041 return name2schema[i].schema;
1044 return NULL;
1047 HRESULT WINAPI WICMapSchemaToName(REFGUID format, LPWSTR schema, UINT len, WCHAR *name, UINT *ret_len)
1049 UINT i;
1051 TRACE("%s,%s,%u,%p,%p\n", wine_dbgstr_guid(format), debugstr_w(schema), len, name, ret_len);
1053 if (!format || !schema || !ret_len)
1054 return E_INVALIDARG;
1056 /* It appears that the only metadata formats
1057 * that support schemas are xmp and xmpstruct.
1059 if (!IsEqualGUID(format, &GUID_MetadataFormatXMP) &&
1060 !IsEqualGUID(format, &GUID_MetadataFormatXMPStruct))
1061 return WINCODEC_ERR_PROPERTYNOTFOUND;
1063 for (i = 0; i < ARRAY_SIZE(name2schema); i++)
1065 if (!wcscmp(name2schema[i].schema, schema))
1067 if (name)
1069 if (!len) return E_INVALIDARG;
1071 len = min(len - 1, lstrlenW(name2schema[i].name));
1072 memcpy(name, name2schema[i].name, len * sizeof(WCHAR));
1073 name[len] = 0;
1075 if (len < lstrlenW(name2schema[i].name))
1076 return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
1079 *ret_len = lstrlenW(name2schema[i].name) + 1;
1080 return S_OK;
1084 return WINCODEC_ERR_PROPERTYNOTFOUND;