msi: Return ERROR_MORE_DATA if the size is too small.
[wine] / dlls / mshtml / loadopts.c
1 /*
2  * Copyright 2006 Jacek Caban for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include "config.h"
20
21 #include <stdarg.h>
22 #include <stdio.h>
23
24 #define COBJMACROS
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "ole2.h"
30 #include "optary.h"
31
32 #include "wine/debug.h"
33
34 #include "mshtml_private.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
37
38 typedef struct load_opt {
39     DWORD option;
40     PVOID buffer;
41     DWORD size;
42
43     struct load_opt *next;
44 } load_opt;
45
46 typedef struct {
47     const IHtmlLoadOptionsVtbl *lpHtmlLoadOptionsVtbl;
48
49     LONG ref;
50
51     load_opt *opts;
52 } HTMLLoadOptions;
53
54 #define LOADOPTS(x)  ((IHtmlLoadOptions*) &(x)->lpHtmlLoadOptionsVtbl)
55
56 #define LOADOPTS_THIS(iface) DEFINE_THIS(HTMLLoadOptions, HtmlLoadOptions, iface)
57
58 static HRESULT WINAPI HtmlLoadOptions_QueryInterface(IHtmlLoadOptions *iface,
59         REFIID riid, void **ppv)
60 {
61     HTMLLoadOptions *This = LOADOPTS_THIS(iface);
62
63     *ppv = NULL;
64
65     if(IsEqualGUID(&IID_IUnknown, riid)) {
66         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
67         *ppv = LOADOPTS(This);
68     }else if(IsEqualGUID(&IID_IOptionArray, riid)) {
69         TRACE("(%p)->(IID_IOptionArray %p)\n", This, ppv);
70         *ppv = LOADOPTS(This);
71     }else if(IsEqualGUID(&IID_IHtmlLoadOptions, riid)) {
72         TRACE("(%p)->(IID_IHtmlLoadOptions %p)\n", This, ppv);
73         *ppv = LOADOPTS(This);
74     }
75
76     if(*ppv) {
77         IHtmlLoadOptions_AddRef(LOADOPTS(This));
78         return S_OK;
79     }
80
81     WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
82     return E_NOINTERFACE;
83 }
84
85 static ULONG WINAPI HtmlLoadOptions_AddRef(IHtmlLoadOptions *iface)
86 {
87     HTMLLoadOptions *This = LOADOPTS_THIS(iface);
88     LONG ref = InterlockedIncrement(&This->ref);
89
90     TRACE("(%p) ref=%d\n", This, ref);
91
92     return ref;
93 }
94
95 static ULONG WINAPI HtmlLoadOptions_Release(IHtmlLoadOptions *iface)
96 {
97     HTMLLoadOptions *This = LOADOPTS_THIS(iface);
98     LONG ref = InterlockedDecrement(&This->ref);
99
100     TRACE("(%p) ref=%d\n", This, ref);
101
102     if(!ref) {
103         load_opt *iter = This->opts, *last;
104
105         while(iter) {
106             last = iter;
107             iter = iter->next;
108
109             heap_free(last->buffer);
110             heap_free(last);
111         }
112
113         heap_free(This);
114     }
115
116     return ref;
117 }
118
119 static HRESULT WINAPI HtmlLoadOptions_QueryOption(IHtmlLoadOptions *iface, DWORD dwOption,
120         LPVOID pBuffer, ULONG *pcbBuf)
121 {
122     HTMLLoadOptions *This = LOADOPTS_THIS(iface);
123     load_opt *iter;
124
125     TRACE("(%p)->(%d %p %p)\n", This, dwOption, pBuffer, pcbBuf);
126
127     for(iter = This->opts; iter; iter = iter->next) {
128         if(iter->option == dwOption)
129             break;
130     }
131
132     if(!iter) {
133         *pcbBuf = 0;
134         return S_OK;
135     }
136
137     if(*pcbBuf < iter->size) {
138         *pcbBuf = iter->size;
139         return E_FAIL;
140     }
141
142     memcpy(pBuffer, iter->buffer, iter->size);
143     *pcbBuf = iter->size;
144
145     return S_OK;
146 }
147
148 static HRESULT WINAPI HtmlLoadOptions_SetOption(IHtmlLoadOptions *iface, DWORD dwOption,
149         LPVOID pBuffer, ULONG cbBuf)
150 {
151     HTMLLoadOptions *This = LOADOPTS_THIS(iface);
152     load_opt *iter = NULL;
153
154     TRACE("(%p)->(%d %p %d)\n", This, dwOption, pBuffer, cbBuf);
155
156     for(iter = This->opts; iter; iter = iter->next) {
157         if(iter->option == dwOption)
158             break;
159     }
160
161     if(!iter) {
162         iter = heap_alloc(sizeof(load_opt));
163         iter->next = This->opts;
164         This->opts = iter;
165
166         iter->option = dwOption;
167     }else {
168         heap_free(iter->buffer);
169     }
170
171     if(!cbBuf) {
172         iter->buffer = NULL;
173         iter->size = 0;
174
175         return S_OK;
176     }
177
178     iter->size = cbBuf;
179     iter->buffer = heap_alloc(cbBuf);
180     memcpy(iter->buffer, pBuffer, iter->size);
181
182     return S_OK;
183 }
184
185 #undef LOADOPTS_THIS
186
187 static const IHtmlLoadOptionsVtbl HtmlLoadOptionsVtbl = {
188     HtmlLoadOptions_QueryInterface,
189     HtmlLoadOptions_AddRef,
190     HtmlLoadOptions_Release,
191     HtmlLoadOptions_QueryOption,
192     HtmlLoadOptions_SetOption
193 };
194
195 HRESULT HTMLLoadOptions_Create(IUnknown *pUnkOuter, REFIID riid, void** ppv)
196 {
197     HTMLLoadOptions *ret;
198     HRESULT hres;
199
200     TRACE("(%p %s %p)\n", pUnkOuter, debugstr_guid(riid), ppv);
201
202     ret = heap_alloc(sizeof(HTMLLoadOptions));
203
204     ret->lpHtmlLoadOptionsVtbl = &HtmlLoadOptionsVtbl;
205     ret->ref = 1;
206     ret->opts = NULL;
207
208     hres = IHtmlLoadOptions_QueryInterface(LOADOPTS(ret), riid, ppv);
209     IHtmlLoadOptions_Release(LOADOPTS(ret));
210
211     return hres;
212 }