usp10: Move the application of pair values to a helper function.
[wine] / dlls / itss / moniker.c
1 /*
2  *    ITSS Moniker implementation
3  *
4  * Copyright 2004 Mike McCormack
5  *
6  *  Implementation of the infamous mk:@MSITStore moniker
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22
23 #include "config.h"
24
25 #include <stdarg.h>
26 #include <stdio.h>
27
28 #define COBJMACROS
29
30 #include "windef.h"
31 #include "winbase.h"
32 #include "winuser.h"
33 #include "ole2.h"
34
35 #include "wine/itss.h"
36 #include "wine/unicode.h"
37 #include "wine/debug.h"
38
39 #include "itsstor.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(itss);
42
43 /*****************************************************************************/
44
45 typedef struct {
46     IMoniker IMoniker_iface;
47     LONG ref;
48     LPWSTR szHtml;
49     WCHAR szFile[1];
50 } ITS_IMonikerImpl;
51
52 static inline ITS_IMonikerImpl *impl_from_IMoniker(IMoniker *iface)
53 {
54     return CONTAINING_RECORD(iface, ITS_IMonikerImpl, IMoniker_iface);
55 }
56
57 /*** IUnknown methods ***/
58 static HRESULT WINAPI ITS_IMonikerImpl_QueryInterface(
59     IMoniker* iface,
60     REFIID riid,
61     void** ppvObject)
62 {
63     ITS_IMonikerImpl *This = impl_from_IMoniker(iface);
64
65     if (IsEqualGUID(riid, &IID_IUnknown)
66         || IsEqualGUID(riid, &IID_IParseDisplayName))
67     {
68         IMoniker_AddRef(iface);
69         *ppvObject = iface;
70         return S_OK;
71     }
72
73     WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
74     return E_NOINTERFACE;
75 }
76
77 static ULONG WINAPI ITS_IMonikerImpl_AddRef(
78     IMoniker* iface)
79 {
80     ITS_IMonikerImpl *This = impl_from_IMoniker(iface);
81     TRACE("%p\n", This);
82     return InterlockedIncrement(&This->ref);
83 }
84
85 static ULONG WINAPI ITS_IMonikerImpl_Release(
86     IMoniker* iface)
87 {
88     ITS_IMonikerImpl *This = impl_from_IMoniker(iface);
89     ULONG ref = InterlockedDecrement(&This->ref);
90
91     if (ref == 0) {
92         HeapFree(GetProcessHeap(), 0, This);
93         ITSS_UnlockModule();
94     }
95
96     return ref;
97 }
98
99 /*** IPersist methods ***/
100 static HRESULT WINAPI ITS_IMonikerImpl_GetClassID(
101     IMoniker* iface,
102     CLSID* pClassID)
103 {
104     ITS_IMonikerImpl *This = impl_from_IMoniker(iface);
105
106     TRACE("%p %p\n", This, pClassID);
107     *pClassID = CLSID_ITStorage;
108     return S_OK;
109 }
110
111 /*** IPersistStream methods ***/
112 static HRESULT WINAPI ITS_IMonikerImpl_IsDirty(
113     IMoniker* iface)
114 {
115     FIXME("\n");
116     return E_NOTIMPL;
117 }
118
119 static HRESULT WINAPI ITS_IMonikerImpl_Load(
120     IMoniker* iface,
121     IStream* pStm)
122 {
123     FIXME("\n");
124     return E_NOTIMPL;
125 }
126
127 static HRESULT WINAPI ITS_IMonikerImpl_Save(
128     IMoniker* iface,
129     IStream* pStm,
130     BOOL fClearDirty)
131 {
132     FIXME("\n");
133     return E_NOTIMPL;
134 }
135
136 static HRESULT WINAPI ITS_IMonikerImpl_GetSizeMax(
137     IMoniker* iface,
138     ULARGE_INTEGER* pcbSize)
139 {
140     FIXME("\n");
141     return E_NOTIMPL;
142 }
143
144 /*** IMoniker methods ***/
145 static HRESULT WINAPI ITS_IMonikerImpl_BindToObject(
146     IMoniker* iface,
147     IBindCtx* pbc,
148     IMoniker* pmkToLeft,
149     REFIID riidResult,
150     void** ppvResult)
151 {
152     FIXME("\n");
153     return E_NOTIMPL;
154 }
155
156 static HRESULT WINAPI ITS_IMonikerImpl_BindToStorage(
157     IMoniker* iface,
158     IBindCtx* pbc,
159     IMoniker* pmkToLeft,
160     REFIID riid,
161     void** ppvObj)
162 {
163     ITS_IMonikerImpl *This = impl_from_IMoniker(iface);
164     DWORD grfMode = STGM_SIMPLE | STGM_READ | STGM_SHARE_EXCLUSIVE;
165     HRESULT r;
166     IStorage *stg = NULL;
167
168     TRACE("%p %p %p %s %p\n", This,
169            pbc, pmkToLeft, debugstr_guid(riid), ppvObj);
170
171     r = ITSS_StgOpenStorage( This->szFile, NULL, grfMode, 0, 0, &stg );
172     if( r == S_OK )
173     {
174         TRACE("Opened storage %s\n", debugstr_w( This->szFile ) );
175         if (IsEqualGUID(riid, &IID_IStream))
176             r = IStorage_OpenStream( stg, This->szHtml,
177                        NULL, grfMode, 0, (IStream**)ppvObj );
178         else if (IsEqualGUID(riid, &IID_IStorage))
179             r = IStorage_OpenStorage( stg, This->szHtml,
180                        NULL, grfMode, NULL, 0, (IStorage**)ppvObj );
181         else
182             r = STG_E_ACCESSDENIED;
183         IStorage_Release( stg );
184     }
185
186     return r;
187 }
188
189 static HRESULT WINAPI ITS_IMonikerImpl_Reduce(
190     IMoniker* iface,
191     IBindCtx* pbc,
192     DWORD dwReduceHowFar,
193     IMoniker** ppmkToLeft,
194     IMoniker** ppmkReduced)
195 {
196     FIXME("\n");
197     return E_NOTIMPL;
198 }
199
200 static HRESULT WINAPI ITS_IMonikerImpl_ComposeWith(
201     IMoniker* iface,
202     IMoniker* pmkRight,
203     BOOL fOnlyIfNotGeneric,
204     IMoniker** ppmkComposite)
205 {
206     FIXME("\n");
207     return E_NOTIMPL;
208 }
209
210 static HRESULT WINAPI ITS_IMonikerImpl_Enum(
211     IMoniker* iface,
212     BOOL fForward,
213     IEnumMoniker** ppenumMoniker)
214 {
215     FIXME("\n");
216     return E_NOTIMPL;
217 }
218
219 static HRESULT WINAPI ITS_IMonikerImpl_IsEqual(
220     IMoniker* iface,
221     IMoniker* pmkOtherMoniker)
222 {
223     FIXME("\n");
224     return E_NOTIMPL;
225 }
226
227 static HRESULT WINAPI ITS_IMonikerImpl_Hash(
228     IMoniker* iface,
229     DWORD* pdwHash)
230 {
231     FIXME("\n");
232     return E_NOTIMPL;
233 }
234
235 static HRESULT WINAPI ITS_IMonikerImpl_IsRunning(
236     IMoniker* iface,
237     IBindCtx* pbc,
238     IMoniker* pmkToLeft,
239     IMoniker* pmkNewlyRunning)
240 {
241     FIXME("\n");
242     return E_NOTIMPL;
243 }
244
245 static HRESULT WINAPI ITS_IMonikerImpl_GetTimeOfLastChange(
246     IMoniker* iface,
247     IBindCtx* pbc,
248     IMoniker* pmkToLeft,
249     FILETIME* pFileTime)
250 {
251     FIXME("\n");
252     return E_NOTIMPL;
253 }
254
255 static HRESULT WINAPI ITS_IMonikerImpl_Inverse(
256     IMoniker* iface,
257     IMoniker** ppmk)
258 {
259     FIXME("\n");
260     return E_NOTIMPL;
261 }
262
263 static HRESULT WINAPI ITS_IMonikerImpl_CommonPrefixWith(
264     IMoniker* iface,
265     IMoniker* pmkOther,
266     IMoniker** ppmkPrefix)
267 {
268     FIXME("\n");
269     return E_NOTIMPL;
270 }
271
272 static HRESULT WINAPI ITS_IMonikerImpl_RelativePathTo(
273     IMoniker* iface,
274     IMoniker* pmkOther,
275     IMoniker** ppmkRelPath)
276 {
277     FIXME("\n");
278     return E_NOTIMPL;
279 }
280
281 static HRESULT WINAPI ITS_IMonikerImpl_GetDisplayName(
282     IMoniker* iface,
283     IBindCtx* pbc,
284     IMoniker* pmkToLeft,
285     LPOLESTR* ppszDisplayName)
286 {
287     ITS_IMonikerImpl *This = impl_from_IMoniker(iface);
288     static const WCHAR szFormat[] = {
289         'm','s','-','i','t','s',':','%','s',':',':','%','s',0 };
290     DWORD len = sizeof szFormat / sizeof(WCHAR);
291     LPWSTR str;
292
293     TRACE("%p %p %p %p\n", iface, pbc, pmkToLeft, ppszDisplayName);
294
295     len = strlenW( This->szFile ) + strlenW( This->szHtml );
296     str = CoTaskMemAlloc( len*sizeof(WCHAR) );
297     sprintfW( str, szFormat, This->szFile, This->szHtml );
298
299     *ppszDisplayName = str;
300     
301     return S_OK;
302 }
303
304 static HRESULT WINAPI ITS_IMonikerImpl_ParseDisplayName(
305     IMoniker* iface,
306     IBindCtx* pbc,
307     IMoniker* pmkToLeft,
308     LPOLESTR pszDisplayName,
309     ULONG* pchEaten,
310     IMoniker** ppmkOut)
311 {
312     FIXME("\n");
313     return E_NOTIMPL;
314 }
315
316 static HRESULT WINAPI ITS_IMonikerImpl_IsSystemMoniker(
317     IMoniker* iface,
318     DWORD* pdwMksys)
319 {
320     FIXME("\n");
321     return E_NOTIMPL;
322 }
323
324 static const IMonikerVtbl ITS_IMonikerImpl_Vtbl =
325 {
326     ITS_IMonikerImpl_QueryInterface,
327     ITS_IMonikerImpl_AddRef,
328     ITS_IMonikerImpl_Release,
329     ITS_IMonikerImpl_GetClassID,
330     ITS_IMonikerImpl_IsDirty,
331     ITS_IMonikerImpl_Load,
332     ITS_IMonikerImpl_Save,
333     ITS_IMonikerImpl_GetSizeMax,
334     ITS_IMonikerImpl_BindToObject,
335     ITS_IMonikerImpl_BindToStorage,
336     ITS_IMonikerImpl_Reduce,
337     ITS_IMonikerImpl_ComposeWith,
338     ITS_IMonikerImpl_Enum,
339     ITS_IMonikerImpl_IsEqual,
340     ITS_IMonikerImpl_Hash,
341     ITS_IMonikerImpl_IsRunning,
342     ITS_IMonikerImpl_GetTimeOfLastChange,
343     ITS_IMonikerImpl_Inverse,
344     ITS_IMonikerImpl_CommonPrefixWith,
345     ITS_IMonikerImpl_RelativePathTo,
346     ITS_IMonikerImpl_GetDisplayName,
347     ITS_IMonikerImpl_ParseDisplayName,
348     ITS_IMonikerImpl_IsSystemMoniker
349 };
350
351 static HRESULT ITS_IMoniker_create( IMoniker **ppObj, LPCWSTR name, DWORD n )
352 {
353     ITS_IMonikerImpl *itsmon;
354     DWORD sz;
355
356     /* szFile[1] has space for one character already */
357     sz = FIELD_OFFSET( ITS_IMonikerImpl, szFile[strlenW( name ) + 1] );
358
359     itsmon = HeapAlloc( GetProcessHeap(), 0, sz );
360     itsmon->IMoniker_iface.lpVtbl = &ITS_IMonikerImpl_Vtbl;
361     itsmon->ref = 1;
362     strcpyW( itsmon->szFile, name );
363     itsmon->szHtml = &itsmon->szFile[n];
364
365     while( *itsmon->szHtml == ':' )
366         *itsmon->szHtml++ = 0;
367
368     TRACE("-> %p %s %s\n", itsmon,
369           debugstr_w(itsmon->szFile), debugstr_w(itsmon->szHtml) );
370     *ppObj = &itsmon->IMoniker_iface;
371
372     ITSS_LockModule();
373     return S_OK;
374 }
375
376 /*****************************************************************************/
377
378 typedef struct {
379     IParseDisplayName IParseDisplayName_iface;
380     LONG ref;
381 } ITS_IParseDisplayNameImpl;
382
383 static inline ITS_IParseDisplayNameImpl *impl_from_IParseDisplayName(IParseDisplayName *iface)
384 {
385     return CONTAINING_RECORD(iface, ITS_IParseDisplayNameImpl, IParseDisplayName_iface);
386 }
387
388 static HRESULT WINAPI ITS_IParseDisplayNameImpl_QueryInterface(
389     IParseDisplayName* iface,
390     REFIID riid,
391     void** ppvObject)
392 {
393     ITS_IParseDisplayNameImpl *This = impl_from_IParseDisplayName(iface);
394
395     if (IsEqualGUID(riid, &IID_IUnknown)
396         || IsEqualGUID(riid, &IID_IParseDisplayName))
397     {
398         IParseDisplayName_AddRef(iface);
399         *ppvObject = iface;
400         return S_OK;
401     }
402
403     WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
404     return E_NOINTERFACE;
405 }
406
407 static ULONG WINAPI ITS_IParseDisplayNameImpl_AddRef(
408     IParseDisplayName* iface)
409 {
410     ITS_IParseDisplayNameImpl *This = impl_from_IParseDisplayName(iface);
411     TRACE("%p\n", This);
412     return InterlockedIncrement(&This->ref);
413 }
414
415 static ULONG WINAPI ITS_IParseDisplayNameImpl_Release(
416     IParseDisplayName* iface)
417 {
418     ITS_IParseDisplayNameImpl *This = impl_from_IParseDisplayName(iface);
419     ULONG ref = InterlockedDecrement(&This->ref);
420
421     if (ref == 0) {
422         HeapFree(GetProcessHeap(), 0, This);
423         ITSS_UnlockModule();
424     }
425
426     return ref;
427 }
428
429 static HRESULT WINAPI ITS_IParseDisplayNameImpl_ParseDisplayName(
430     IParseDisplayName *iface,
431     IBindCtx * pbc,
432     LPOLESTR pszDisplayName, 
433     ULONG * pchEaten,
434     IMoniker ** ppmkOut)
435 {
436     static const WCHAR szPrefix[] = { 
437         '@','M','S','I','T','S','t','o','r','e',':',0 };
438     const DWORD prefix_len = (sizeof szPrefix/sizeof szPrefix[0])-1;
439     DWORD n;
440
441     ITS_IParseDisplayNameImpl *This = impl_from_IParseDisplayName(iface);
442
443     TRACE("%p %s %p %p\n", This,
444           debugstr_w( pszDisplayName ), pchEaten, ppmkOut );
445
446     if( strncmpiW( pszDisplayName, szPrefix, prefix_len ) )
447         return MK_E_SYNTAX;
448
449     /* search backwards for a double colon */
450     for( n = strlenW( pszDisplayName ) - 3; prefix_len <= n; n-- )
451         if( ( pszDisplayName[n] == ':' ) && ( pszDisplayName[n+1] == ':' ) )
452             break;
453
454     if( n < prefix_len )
455         return MK_E_SYNTAX;
456
457     if( !pszDisplayName[n+2] )
458         return MK_E_SYNTAX;
459
460     *pchEaten = strlenW( pszDisplayName ) - n - 3;
461
462     return ITS_IMoniker_create( ppmkOut,
463               &pszDisplayName[prefix_len], n-prefix_len );
464 }
465
466 static const IParseDisplayNameVtbl ITS_IParseDisplayNameImpl_Vtbl =
467 {
468     ITS_IParseDisplayNameImpl_QueryInterface,
469     ITS_IParseDisplayNameImpl_AddRef,
470     ITS_IParseDisplayNameImpl_Release,
471     ITS_IParseDisplayNameImpl_ParseDisplayName
472 };
473  
474 HRESULT ITS_IParseDisplayName_create(IUnknown *pUnkOuter, LPVOID *ppObj)
475 {
476     ITS_IParseDisplayNameImpl *its;
477
478     if( pUnkOuter )
479         return CLASS_E_NOAGGREGATION;
480
481     its = HeapAlloc( GetProcessHeap(), 0, sizeof(ITS_IParseDisplayNameImpl) );
482     its->IParseDisplayName_iface.lpVtbl = &ITS_IParseDisplayNameImpl_Vtbl;
483     its->ref = 1;
484
485     TRACE("-> %p\n", its);
486     *ppObj = its;
487
488     ITSS_LockModule();
489     return S_OK;
490 }