regstream.c 10.3 KB
Newer Older
1
/*
2
 * SHLWAPI Registry Stream functions
3 4
 *
 * Copyright 1999 Juergen Schmied
5
 * Copyright 2002 Jon Griffiths
6 7 8 9 10 11 12 13 14 15 16 17 18
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20
 */
21

22
#include <stdarg.h>
23 24
#include <string.h>

25 26
#define COBJMACROS

27
#include "winerror.h"
28
#include "windef.h"
29
#include "winbase.h"
30
#include "objbase.h"
31
#include "winreg.h"
32
#include "shlwapi.h"
33

34
#include "wine/debug.h"
35

36
WINE_DEFAULT_DEBUG_CHANNEL(shell);
37

38
typedef struct
39
{
40
	IStream IStream_iface;
Mike McCormack's avatar
Mike McCormack committed
41
	LONG   ref;
42 43 44
	LPBYTE pbBuffer;
	DWORD  dwLength;
	DWORD  dwPos;
45
	DWORD  dwMode;
46 47
} ISHRegStream;

48 49 50 51 52
static inline ISHRegStream *impl_from_IStream(IStream *iface)
{
	return CONTAINING_RECORD(iface, ISHRegStream, IStream_iface);
}

53 54 55 56 57
/**************************************************************************
*  IStream_fnQueryInterface
*/
static HRESULT WINAPI IStream_fnQueryInterface(IStream *iface, REFIID riid, LPVOID *ppvObj)
{
58
	ISHRegStream *This = impl_from_IStream(iface);
59

60
	TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj);
61 62 63

	*ppvObj = NULL;

64 65
       if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IStream))
         *ppvObj = &This->IStream_iface;
66 67

	if(*ppvObj)
68 69
	{
	  IStream_AddRef((IStream*)*ppvObj);
70
	  TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
71 72
	  return S_OK;
	}
73
	TRACE("-- Interface: E_NOINTERFACE\n");
74 75 76 77 78 79 80 81
	return E_NOINTERFACE;
}

/**************************************************************************
*  IStream_fnAddRef
*/
static ULONG WINAPI IStream_fnAddRef(IStream *iface)
{
82
	ISHRegStream *This = impl_from_IStream(iface);
83 84
	ULONG refCount = InterlockedIncrement(&This->ref);
	
85
	TRACE("(%p)->(ref before=%u)\n",This, refCount - 1);
86

87
	return refCount;
88 89 90 91 92 93 94
}

/**************************************************************************
*  IStream_fnRelease
*/
static ULONG WINAPI IStream_fnRelease(IStream *iface)
{
95
	ISHRegStream *This = impl_from_IStream(iface);
96
	ULONG refCount = InterlockedDecrement(&This->ref);
97

98
	TRACE("(%p)->(ref before=%u)\n",This, refCount + 1);
99

100
	if (!refCount)
101
	{
102
	  HeapFree(GetProcessHeap(),0,This->pbBuffer);
103 104 105
	  HeapFree(GetProcessHeap(),0,This);
	  return 0;
	}
106 107

	return refCount;
108 109
}

110 111 112
/**************************************************************************
 * IStream_fnRead
 */
113
static HRESULT WINAPI IStream_fnRead (IStream * iface, void* pv, ULONG cb, ULONG* pcbRead)
114
{
115
	ISHRegStream *This = impl_from_IStream(iface);
116
	DWORD dwBytesToRead;
117

118
	TRACE("(%p)->(%p,0x%08x,%p)\n",This, pv, cb, pcbRead);
119

120 121 122 123
	if (This->dwPos >= This->dwLength)
	  dwBytesToRead = 0;
        else
	  dwBytesToRead = This->dwLength - This->dwPos;
124

125 126 127 128 129 130
	dwBytesToRead = (cb > dwBytesToRead) ? dwBytesToRead : cb;
	if (dwBytesToRead != 0) /* not at end of buffer and we want to read something */
	{
	  memmove(pv, This->pbBuffer + This->dwPos, dwBytesToRead);
	  This->dwPos += dwBytesToRead; /* adjust pointer */
	}
131 132 133 134 135 136

	if (pcbRead)
	  *pcbRead = dwBytesToRead;

	return S_OK;
}
137 138 139 140

/**************************************************************************
 * IStream_fnWrite
 */
141
static HRESULT WINAPI IStream_fnWrite (IStream * iface, const void* pv, ULONG cb, ULONG* pcbWritten)
142
{
143
	ISHRegStream *This = impl_from_IStream(iface);
144
	DWORD newLen = This->dwPos + cb;
145

146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
	TRACE("(%p, %p, %d, %p)\n",This, pv, cb, pcbWritten);

	if (newLen < This->dwPos) /* overflow */
	  return STG_E_INSUFFICIENTMEMORY;

	if (newLen > This->dwLength)
	{
	  LPBYTE newBuf = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->pbBuffer, newLen);
	  if (!newBuf)
	    return STG_E_INSUFFICIENTMEMORY;

	  This->dwLength = newLen;
	  This->pbBuffer = newBuf;
	}
	memmove(This->pbBuffer + This->dwPos, pv, cb);
	This->dwPos += cb; /* adjust pointer */
162

163
	if (pcbWritten)
164
	  *pcbWritten = cb;
165

166
	return S_OK;
167
}
168 169 170 171

/**************************************************************************
 *  IStream_fnSeek
 */
172
static HRESULT WINAPI IStream_fnSeek (IStream * iface, LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition)
173
{
174
	ISHRegStream *This = impl_from_IStream(iface);
175 176 177 178 179 180 181 182 183 184 185 186
	LARGE_INTEGER tmp;
	TRACE("(%p, %s, %d %p)\n", This,
              wine_dbgstr_longlong(dlibMove.QuadPart), dwOrigin, plibNewPosition);

	if (dwOrigin == STREAM_SEEK_SET)
	  tmp = dlibMove;
        else if (dwOrigin == STREAM_SEEK_CUR)
	  tmp.QuadPart = This->dwPos + dlibMove.QuadPart;
	else if (dwOrigin == STREAM_SEEK_END)
	  tmp.QuadPart = This->dwLength + dlibMove.QuadPart;
        else
	  return STG_E_INVALIDPARAMETER;
187

188 189 190 191
	if (tmp.QuadPart < 0)
	  return STG_E_INVALIDFUNCTION;

	/* we cut off the high part here */
192
	This->dwPos = tmp.u.LowPart;
193

194
	if (plibNewPosition)
195 196
	  plibNewPosition->QuadPart = This->dwPos;
	return S_OK;
197
}
198 199 200 201

/**************************************************************************
 * IStream_fnSetSize
 */
202
static HRESULT WINAPI IStream_fnSetSize (IStream * iface, ULARGE_INTEGER libNewSize)
203
{
204
	ISHRegStream *This = impl_from_IStream(iface);
205 206 207 208
	DWORD newLen;
	LPBYTE newBuf;

	TRACE("(%p, %s)\n", This, wine_dbgstr_longlong(libNewSize.QuadPart));
209

210
	/* we cut off the high part here */
211
	newLen = libNewSize.u.LowPart;
212 213 214 215 216 217 218 219
	newBuf = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->pbBuffer, newLen);
	if (!newBuf)
	  return STG_E_INSUFFICIENTMEMORY;

	This->pbBuffer = newBuf;
	This->dwLength = newLen;

	return S_OK;
220
}
221 222 223 224

/**************************************************************************
 * IStream_fnCopyTo
 */
225
static HRESULT WINAPI IStream_fnCopyTo (IStream * iface, IStream* pstm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, ULARGE_INTEGER* pcbWritten)
226
{
227
	ISHRegStream *This = impl_from_IStream(iface);
228

229
	TRACE("(%p)\n",This);
230 231 232 233
	if (pcbRead)
	  pcbRead->QuadPart = 0;
	if (pcbWritten)
	  pcbWritten->QuadPart = 0;
234 235

	/* TODO implement */
236 237
	return E_NOTIMPL;
}
238 239 240 241

/**************************************************************************
 * IStream_fnCommit
 */
242
static HRESULT WINAPI IStream_fnCommit (IStream * iface, DWORD grfCommitFlags)
243
{
244
	ISHRegStream *This = impl_from_IStream(iface);
245

246
	TRACE("(%p)\n",This);
247

248
	/* commit not supported by this stream */
249 250
	return E_NOTIMPL;
}
251 252 253 254

/**************************************************************************
 * IStream_fnRevert
 */
255
static HRESULT WINAPI IStream_fnRevert (IStream * iface)
256
{
257
	ISHRegStream *This = impl_from_IStream(iface);
258

259
	TRACE("(%p)\n",This);
260

261
	/* revert not supported by this stream */
262 263 264
	return E_NOTIMPL;
}

265 266 267 268
/**************************************************************************
 * IStream_fnLockUnlockRegion
 */
static HRESULT WINAPI IStream_fnLockUnlockRegion (IStream * iface, ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
269
{
270
	ISHRegStream *This = impl_from_IStream(iface);
271

272
	TRACE("(%p)\n",This);
273

274
	/* lock/unlock not supported by this stream */
275 276
	return E_NOTIMPL;
}
277 278 279 280

/*************************************************************************
 * IStream_fnStat
 */
281
static HRESULT WINAPI IStream_fnStat (IStream * iface, STATSTG* pstatstg, DWORD grfStatFlag)
282
{
283
	ISHRegStream *This = impl_from_IStream(iface);
284

285 286 287 288 289 290 291 292 293 294 295
	TRACE("(%p, %p, %d)\n",This,pstatstg,grfStatFlag);

	pstatstg->pwcsName = NULL;
	pstatstg->type = STGTY_STREAM;
	pstatstg->cbSize.QuadPart = This->dwLength;
	pstatstg->mtime.dwHighDateTime = 0;
	pstatstg->mtime.dwLowDateTime = 0;
	pstatstg->ctime.dwHighDateTime = 0;
	pstatstg->ctime.dwLowDateTime = 0;
	pstatstg->atime.dwHighDateTime = 0;
	pstatstg->atime.dwLowDateTime = 0;
296
	pstatstg->grfMode = This->dwMode;
297 298 299 300
	pstatstg->grfLocksSupported = 0;
	pstatstg->clsid = CLSID_NULL;
	pstatstg->grfStateBits = 0;
	pstatstg->reserved = 0;
301

302
	return S_OK;
303
}
304 305 306 307

/*************************************************************************
 * IStream_fnClone
 */
308
static HRESULT WINAPI IStream_fnClone (IStream * iface, IStream** ppstm)
309
{
310
	ISHRegStream *This = impl_from_IStream(iface);
311

312
	TRACE("(%p)\n",This);
313 314 315
	*ppstm = NULL;

	/* clone not supported by this stream */
316 317 318
	return E_NOTIMPL;
}

319
static const IStreamVtbl rstvt =
320
{
321 322 323 324 325 326 327 328 329 330
	IStream_fnQueryInterface,
	IStream_fnAddRef,
	IStream_fnRelease,
	IStream_fnRead,
	IStream_fnWrite,
	IStream_fnSeek,
	IStream_fnSetSize,
	IStream_fnCopyTo,
	IStream_fnCommit,
	IStream_fnRevert,
331 332
	IStream_fnLockUnlockRegion,
	IStream_fnLockUnlockRegion,
333 334
	IStream_fnStat,
	IStream_fnClone
335 336 337 338 339 340 341
};

/**************************************************************************
 * IStream_Create
 *
 * Internal helper: Create and initialise a new registry stream object.
 */
342
static ISHRegStream *IStream_Create(HKEY hKey, LPBYTE pbBuffer, DWORD dwLength)
343 344 345
{
 ISHRegStream* regStream;

346
 regStream = HeapAlloc(GetProcessHeap(), 0, sizeof(ISHRegStream));
347 348 349

 if (regStream)
 {
350
   regStream->IStream_iface.lpVtbl = &rstvt;
351 352 353 354
   regStream->ref = 1;
   regStream->pbBuffer = pbBuffer;
   regStream->dwLength = dwLength;
   regStream->dwPos = 0;
355
   regStream->dwMode = STGM_READWRITE;
356 357
 }
 TRACE ("Returning %p\n", regStream);
358
 return regStream;
359 360
}

361 362 363
/*************************************************************************
 * SHCreateStreamWrapper   [SHLWAPI.@]
 *
Jon Griffiths's avatar
Jon Griffiths committed
364
 * Create an IStream object on a block of memory.
365 366
 *
 * PARAMS
Jon Griffiths's avatar
Jon Griffiths committed
367
 * lpbData    [I] Memory block to create the IStream object on
368 369
 * dwDataLen  [I] Length of data block
 * dwReserved [I] Reserved, Must be 0.
Jon Griffiths's avatar
Jon Griffiths committed
370
 * lppStream  [O] Destination for IStream object
371 372
 *
 * RETURNS
Jon Griffiths's avatar
Jon Griffiths committed
373
 * Success: S_OK. lppStream contains the new IStream object.
374 375 376 377 378 379 380 381 382
 * Failure: E_INVALIDARG, if any parameters are invalid,
 *          E_OUTOFMEMORY if memory allocation fails.
 *
 * NOTES
 *  The stream assumes ownership of the memory passed to it.
 */
HRESULT WINAPI SHCreateStreamWrapper(LPBYTE lpbData, DWORD dwDataLen,
                                     DWORD dwReserved, IStream **lppStream)
{
383
  ISHRegStream *strm;
384 385 386 387 388 389 390

  if (lppStream)
    *lppStream = NULL;

  if(dwReserved || !lppStream)
    return E_INVALIDARG;

391
  strm = IStream_Create(NULL, lpbData, dwDataLen);
392

393
  if(!strm)
394 395
    return E_OUTOFMEMORY;

396 397
  IStream_QueryInterface(&strm->IStream_iface, &IID_IStream, (void**)lppStream);
  IStream_Release(&strm->IStream_iface);
398 399
  return S_OK;
}