2003-08-22 23:53:27 +00:00
|
|
|
/* ILoaderStream Implementation
|
|
|
|
*
|
2004-01-20 00:21:40 +00:00
|
|
|
* Copyright (C) 2003-2004 Rok Mandeljc
|
2003-08-22 23:53:27 +00:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program 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 Library General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define NONAMELESSUNION
|
|
|
|
#define NONAMELESSSTRUCT
|
|
|
|
|
|
|
|
#include "dmloader_private.h"
|
|
|
|
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(dmloader);
|
2004-01-20 00:21:40 +00:00
|
|
|
WINE_DECLARE_DEBUG_CHANNEL(dmfileraw);
|
2003-08-22 23:53:27 +00:00
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
* Custom functions:
|
|
|
|
*/
|
2004-01-20 00:21:40 +00:00
|
|
|
HRESULT WINAPI ILoaderStream_Attach (LPSTREAM iface, LPCWSTR wzFile, IDirectMusicLoader *pLoader) {
|
|
|
|
ICOM_THIS_MULTI(ILoaderStream, StreamVtbl, iface);
|
2003-10-27 22:08:37 +00:00
|
|
|
TRACE("(%p, %s, %p)\n", This, debugstr_w(wzFile), pLoader);
|
2004-01-20 00:21:40 +00:00
|
|
|
ILoaderStream_Detach (iface);
|
2003-10-27 22:08:37 +00:00
|
|
|
This->hFile = CreateFileW (wzFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
2003-08-22 23:53:27 +00:00
|
|
|
if (This->hFile == INVALID_HANDLE_VALUE) {
|
2003-10-27 22:08:37 +00:00
|
|
|
TRACE(": failed\n");
|
2004-01-20 00:21:40 +00:00
|
|
|
return DMUS_E_LOADER_FAILEDOPEN;
|
2003-08-22 23:53:27 +00:00
|
|
|
}
|
2003-10-27 22:08:37 +00:00
|
|
|
/* create IDirectMusicGetLoader */
|
|
|
|
(LPDIRECTMUSICLOADER) This->pLoader = pLoader;
|
2003-08-22 23:53:27 +00:00
|
|
|
strncpyW (This->wzFileName, wzFile, MAX_PATH);
|
2003-10-27 22:08:37 +00:00
|
|
|
TRACE(": succeeded\n");
|
2003-08-22 23:53:27 +00:00
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
2004-01-20 00:21:40 +00:00
|
|
|
void WINAPI ILoaderStream_Detach (LPSTREAM iface) {
|
|
|
|
ICOM_THIS_MULTI(ILoaderStream, StreamVtbl, iface);
|
2003-08-22 23:53:27 +00:00
|
|
|
if (This->hFile != INVALID_HANDLE_VALUE) {
|
|
|
|
CloseHandle(This->hFile);
|
|
|
|
}
|
|
|
|
This->wzFileName[0] = (L'\0');
|
|
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
2004-01-20 00:21:40 +00:00
|
|
|
* ILoaderStream implementation
|
2003-08-22 23:53:27 +00:00
|
|
|
*/
|
2004-01-20 00:21:40 +00:00
|
|
|
/* ILoaderStream IUnknown part: */
|
|
|
|
HRESULT WINAPI ILoaderStream_IUnknown_QueryInterface (LPUNKNOWN iface, REFIID riid, void** ppobj) {
|
|
|
|
ICOM_THIS_MULTI(ILoaderStream, UnknownVtbl, iface);
|
2003-08-22 23:53:27 +00:00
|
|
|
|
2004-01-20 00:21:40 +00:00
|
|
|
TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppobj);
|
|
|
|
if (IsEqualIID (riid, &IID_IUnknown)) {
|
|
|
|
*ppobj = (LPVOID)&This->UnknownVtbl;
|
|
|
|
ILoaderStream_IUnknown_AddRef ((LPUNKNOWN)&This->UnknownVtbl);
|
|
|
|
return S_OK;
|
|
|
|
} else if (IsEqualIID (riid, &IID_IStream)) {
|
2003-08-22 23:53:27 +00:00
|
|
|
*ppobj = (LPVOID)&This->StreamVtbl;
|
2004-01-20 00:21:40 +00:00
|
|
|
ILoaderStream_IStream_AddRef ((LPSTREAM)&This->StreamVtbl);
|
2003-08-22 23:53:27 +00:00
|
|
|
return S_OK;
|
|
|
|
} else if (IsEqualIID (riid, &IID_IDirectMusicGetLoader)) {
|
|
|
|
*ppobj = (LPVOID)&This->GetLoaderVtbl;
|
2004-01-20 00:21:40 +00:00
|
|
|
ILoaderStream_IDirectMusicGetLoader_AddRef ((LPDIRECTMUSICGETLOADER)&This->GetLoaderVtbl);
|
2003-08-22 23:53:27 +00:00
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
WARN("(%p)->(%s,%p),not found\n", This, debugstr_guid(riid), ppobj);
|
|
|
|
return E_NOINTERFACE;
|
|
|
|
}
|
|
|
|
|
2004-01-20 00:21:40 +00:00
|
|
|
ULONG WINAPI ILoaderStream_IUnknown_AddRef (LPUNKNOWN iface) {
|
|
|
|
ICOM_THIS_MULTI(ILoaderStream, UnknownVtbl, iface);
|
2003-08-22 23:53:27 +00:00
|
|
|
TRACE("(%p) : AddRef from %ld\n", This, This->ref);
|
|
|
|
return ++(This->ref);
|
|
|
|
}
|
|
|
|
|
2004-01-20 00:21:40 +00:00
|
|
|
ULONG WINAPI ILoaderStream_IUnknown_Release (LPUNKNOWN iface) {
|
|
|
|
ICOM_THIS_MULTI(ILoaderStream, UnknownVtbl, iface);
|
2003-08-22 23:53:27 +00:00
|
|
|
ULONG ref = --This->ref;
|
|
|
|
TRACE("(%p) : ReleaseRef to %ld\n", This, This->ref);
|
|
|
|
if (ref == 0) {
|
|
|
|
HeapFree(GetProcessHeap(), 0, This);
|
|
|
|
}
|
|
|
|
return ref;
|
|
|
|
}
|
|
|
|
|
2004-01-20 00:21:40 +00:00
|
|
|
ICOM_VTABLE(IUnknown) LoaderStream_Unknown_Vtbl = {
|
|
|
|
ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
|
|
|
|
ILoaderStream_IUnknown_QueryInterface,
|
|
|
|
ILoaderStream_IUnknown_AddRef,
|
|
|
|
ILoaderStream_IUnknown_Release
|
|
|
|
};
|
|
|
|
|
|
|
|
/* ILoaderStream IStream part: */
|
|
|
|
HRESULT WINAPI ILoaderStream_IStream_QueryInterface (LPSTREAM iface, REFIID riid, void** ppobj) {
|
2003-08-22 23:53:27 +00:00
|
|
|
ICOM_THIS_MULTI(ILoaderStream, StreamVtbl, iface);
|
2004-01-20 00:21:40 +00:00
|
|
|
return ILoaderStream_IUnknown_QueryInterface ((LPUNKNOWN)&This->UnknownVtbl, riid, ppobj);
|
|
|
|
}
|
2003-08-22 23:53:27 +00:00
|
|
|
|
2004-01-20 00:21:40 +00:00
|
|
|
ULONG WINAPI ILoaderStream_IStream_AddRef (LPSTREAM iface) {
|
|
|
|
ICOM_THIS_MULTI(ILoaderStream, StreamVtbl, iface);
|
|
|
|
return ILoaderStream_IUnknown_AddRef ((LPUNKNOWN)&This->UnknownVtbl);
|
|
|
|
}
|
|
|
|
|
|
|
|
ULONG WINAPI ILoaderStream_IStream_Release (LPSTREAM iface) {
|
|
|
|
ICOM_THIS_MULTI(ILoaderStream, StreamVtbl, iface);
|
|
|
|
return ILoaderStream_IUnknown_Release ((LPUNKNOWN)&This->UnknownVtbl);
|
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT WINAPI ILoaderStream_IStream_Read (LPSTREAM iface, void* pv, ULONG cb, ULONG* pcbRead) {
|
|
|
|
ICOM_THIS_MULTI(ILoaderStream, StreamVtbl, iface);
|
|
|
|
ULONG cbRead;
|
|
|
|
TRACE_(dmfileraw)("(%p, %p, 0x%04lx, %p)\n", This, pv, cb, pcbRead);
|
2003-08-22 23:53:27 +00:00
|
|
|
if (This->hFile == INVALID_HANDLE_VALUE) return E_FAIL;
|
|
|
|
if (pcbRead == NULL) pcbRead = &cbRead;
|
|
|
|
if (!ReadFile (This->hFile, pv, cb, pcbRead, NULL) || *pcbRead != cb) return E_FAIL;
|
2004-01-20 00:21:40 +00:00
|
|
|
TRACE_(dmfileraw)(": data (size = 0x%04lx): '%s'\n", *pcbRead, debugstr_an(pv, *pcbRead));
|
2003-08-22 23:53:27 +00:00
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
2004-01-20 00:21:40 +00:00
|
|
|
HRESULT WINAPI ILoaderStream_IStream_Seek (LPSTREAM iface, LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition) {
|
2003-08-22 23:53:27 +00:00
|
|
|
ICOM_THIS_MULTI(ILoaderStream, StreamVtbl, iface);
|
|
|
|
LARGE_INTEGER liNewPos;
|
2004-01-20 00:21:40 +00:00
|
|
|
|
|
|
|
TRACE_(dmfileraw)("(%p, 0x%04llx, %s, %p)\n", This, dlibMove.QuadPart, resolve_STREAM_SEEK(dwOrigin), plibNewPosition);
|
2003-08-22 23:53:27 +00:00
|
|
|
|
|
|
|
if (This->hFile == INVALID_HANDLE_VALUE) return E_FAIL;
|
|
|
|
|
|
|
|
liNewPos.s.HighPart = dlibMove.s.HighPart;
|
|
|
|
liNewPos.s.LowPart = SetFilePointer (This->hFile, dlibMove.s.LowPart, &liNewPos.s.HighPart, dwOrigin);
|
|
|
|
|
2003-10-16 19:31:11 +00:00
|
|
|
if (liNewPos.s.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) return E_FAIL;
|
2003-08-22 23:53:27 +00:00
|
|
|
if (plibNewPosition) plibNewPosition->QuadPart = liNewPos.QuadPart;
|
|
|
|
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
2004-01-20 00:21:40 +00:00
|
|
|
HRESULT WINAPI ILoaderStream_IStream_Clone (LPSTREAM iface, IStream** ppstm) {
|
2003-08-22 23:53:27 +00:00
|
|
|
ICOM_THIS_MULTI(ILoaderStream, StreamVtbl, iface);
|
2004-01-20 00:21:40 +00:00
|
|
|
LPSTREAM pOther = NULL;
|
2003-08-22 23:53:27 +00:00
|
|
|
HRESULT result;
|
|
|
|
|
|
|
|
TRACE("(%p, %p)\n", iface, ppstm);
|
2004-01-20 00:21:40 +00:00
|
|
|
result = DMUSIC_CreateLoaderStream ((LPVOID*)&pOther);
|
2003-08-22 23:53:27 +00:00
|
|
|
if (FAILED(result)) return result;
|
|
|
|
if (This->hFile != INVALID_HANDLE_VALUE) {
|
|
|
|
ULARGE_INTEGER ullCurrentPosition;
|
|
|
|
result = ILoaderStream_Attach (pOther, This->wzFileName, (LPDIRECTMUSICLOADER)This->pLoader);
|
|
|
|
if (SUCCEEDED(result)) {
|
|
|
|
LARGE_INTEGER liZero;
|
|
|
|
liZero.QuadPart = 0;
|
|
|
|
result = ILoaderStream_IStream_Seek (iface, liZero, STREAM_SEEK_CUR, &ullCurrentPosition); /* get current position in current stream */
|
|
|
|
}
|
|
|
|
if (SUCCEEDED(result)) {
|
|
|
|
LARGE_INTEGER liNewPosition;
|
|
|
|
liNewPosition.QuadPart = ullCurrentPosition.QuadPart;
|
|
|
|
result = ILoaderStream_IStream_Seek ((LPSTREAM)pOther, liNewPosition, STREAM_SEEK_SET, &ullCurrentPosition);
|
|
|
|
}
|
|
|
|
if (FAILED(result)) {
|
|
|
|
TRACE(": failed\n");
|
|
|
|
ILoaderStream_IStream_Release ((LPSTREAM)pOther);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
TRACE(": succeeded\n");
|
|
|
|
*ppstm = (IStream*)pOther;
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
2004-01-20 00:21:40 +00:00
|
|
|
HRESULT WINAPI ILoaderStream_IStream_Write (LPSTREAM iface, const void* pv, ULONG cb, ULONG* pcbWritten) {
|
2003-09-22 19:37:33 +00:00
|
|
|
ERR(": should not be needed\n");
|
2003-08-22 23:53:27 +00:00
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
2004-01-20 00:21:40 +00:00
|
|
|
HRESULT WINAPI ILoaderStream_IStream_SetSize (LPSTREAM iface, ULARGE_INTEGER libNewSize) {
|
2003-09-22 19:37:33 +00:00
|
|
|
ERR(": should not be needed\n");
|
2003-08-22 23:53:27 +00:00
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
2004-01-20 00:21:40 +00:00
|
|
|
HRESULT WINAPI ILoaderStream_IStream_CopyTo (LPSTREAM iface, IStream* pstm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, ULARGE_INTEGER* pcbWritten) {
|
2003-09-22 19:37:33 +00:00
|
|
|
ERR(": should not be needed\n");
|
2003-08-22 23:53:27 +00:00
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
2004-01-20 00:21:40 +00:00
|
|
|
HRESULT WINAPI ILoaderStream_IStream_Commit (LPSTREAM iface, DWORD grfCommitFlags) {
|
2003-09-22 19:37:33 +00:00
|
|
|
ERR(": should not be needed\n");
|
2003-08-22 23:53:27 +00:00
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
2004-01-20 00:21:40 +00:00
|
|
|
HRESULT WINAPI ILoaderStream_IStream_Revert (LPSTREAM iface) {
|
2003-09-22 19:37:33 +00:00
|
|
|
ERR(": should not be needed\n");
|
2003-08-22 23:53:27 +00:00
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
2004-01-20 00:21:40 +00:00
|
|
|
HRESULT WINAPI ILoaderStream_IStream_LockRegion (LPSTREAM iface, ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) {
|
2003-09-22 19:37:33 +00:00
|
|
|
ERR(": should not be needed\n");
|
2003-08-22 23:53:27 +00:00
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
2004-01-20 00:21:40 +00:00
|
|
|
HRESULT WINAPI ILoaderStream_IStream_UnlockRegion (LPSTREAM iface, ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) {
|
2003-09-22 19:37:33 +00:00
|
|
|
ERR(": should not be needed\n");
|
2003-08-22 23:53:27 +00:00
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
2004-01-20 00:21:40 +00:00
|
|
|
HRESULT WINAPI ILoaderStream_IStream_Stat (LPSTREAM iface, STATSTG* pstatstg, DWORD grfStatFlag) {
|
2003-09-22 19:37:33 +00:00
|
|
|
ERR(": should not be needed\n");
|
2003-08-22 23:53:27 +00:00
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
2004-01-20 00:21:40 +00:00
|
|
|
ICOM_VTABLE(IStream) LoaderStream_Stream_Vtbl = {
|
2003-08-22 23:53:27 +00:00
|
|
|
ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
|
|
|
|
ILoaderStream_IStream_QueryInterface,
|
|
|
|
ILoaderStream_IStream_AddRef,
|
|
|
|
ILoaderStream_IStream_Release,
|
|
|
|
ILoaderStream_IStream_Read,
|
|
|
|
ILoaderStream_IStream_Write,
|
|
|
|
ILoaderStream_IStream_Seek,
|
|
|
|
ILoaderStream_IStream_SetSize,
|
|
|
|
ILoaderStream_IStream_CopyTo,
|
|
|
|
ILoaderStream_IStream_Commit,
|
|
|
|
ILoaderStream_IStream_Revert,
|
|
|
|
ILoaderStream_IStream_LockRegion,
|
|
|
|
ILoaderStream_IStream_UnlockRegion,
|
|
|
|
ILoaderStream_IStream_Stat,
|
|
|
|
ILoaderStream_IStream_Clone
|
|
|
|
};
|
|
|
|
|
|
|
|
/*****************************************************************************
|
2004-01-20 00:21:40 +00:00
|
|
|
* ILoaderStream IDirectMusicGetLoader part:
|
2003-08-22 23:53:27 +00:00
|
|
|
*/
|
2004-01-20 00:21:40 +00:00
|
|
|
HRESULT WINAPI ILoaderStream_IDirectMusicGetLoader_QueryInterface (LPDIRECTMUSICGETLOADER iface, REFIID riid, void** ppobj) {
|
2003-08-22 23:53:27 +00:00
|
|
|
ICOM_THIS_MULTI(ILoaderStream, GetLoaderVtbl, iface);
|
2004-01-20 00:21:40 +00:00
|
|
|
return ILoaderStream_IUnknown_QueryInterface ((LPUNKNOWN)&This->UnknownVtbl, riid, ppobj);
|
2003-08-22 23:53:27 +00:00
|
|
|
}
|
|
|
|
|
2004-01-20 00:21:40 +00:00
|
|
|
ULONG WINAPI ILoaderStream_IDirectMusicGetLoader_AddRef (LPDIRECTMUSICGETLOADER iface) {
|
2003-08-22 23:53:27 +00:00
|
|
|
ICOM_THIS_MULTI(ILoaderStream, GetLoaderVtbl, iface);
|
2004-01-20 00:21:40 +00:00
|
|
|
return ILoaderStream_IUnknown_AddRef ((LPUNKNOWN)&This->UnknownVtbl);
|
2003-08-22 23:53:27 +00:00
|
|
|
}
|
|
|
|
|
2004-01-20 00:21:40 +00:00
|
|
|
ULONG WINAPI ILoaderStream_IDirectMusicGetLoader_Release (LPDIRECTMUSICGETLOADER iface) {
|
2003-08-22 23:53:27 +00:00
|
|
|
ICOM_THIS_MULTI(ILoaderStream, GetLoaderVtbl, iface);
|
2004-01-20 00:21:40 +00:00
|
|
|
return ILoaderStream_IUnknown_Release ((LPUNKNOWN)&This->UnknownVtbl);
|
2003-08-22 23:53:27 +00:00
|
|
|
}
|
|
|
|
|
2004-01-20 00:21:40 +00:00
|
|
|
HRESULT WINAPI ILoaderStream_IDirectMusicGetLoader_GetLoader (LPDIRECTMUSICGETLOADER iface, IDirectMusicLoader **ppLoader) {
|
2003-08-22 23:53:27 +00:00
|
|
|
ICOM_THIS_MULTI(ILoaderStream, GetLoaderVtbl, iface);
|
|
|
|
|
|
|
|
TRACE("(%p, %p)\n", This, ppLoader);
|
|
|
|
*ppLoader = (LPDIRECTMUSICLOADER)This->pLoader;
|
2003-09-22 19:37:33 +00:00
|
|
|
IDirectMusicLoader8_AddRef ((LPDIRECTMUSICLOADER8)*ppLoader);
|
|
|
|
|
2003-08-22 23:53:27 +00:00
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
2004-01-20 00:21:40 +00:00
|
|
|
ICOM_VTABLE(IDirectMusicGetLoader) LoaderStream_GetLoader_Vtbl = {
|
2003-08-22 23:53:27 +00:00
|
|
|
ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
|
|
|
|
ILoaderStream_IDirectMusicGetLoader_QueryInterface,
|
|
|
|
ILoaderStream_IDirectMusicGetLoader_AddRef,
|
|
|
|
ILoaderStream_IDirectMusicGetLoader_Release,
|
|
|
|
ILoaderStream_IDirectMusicGetLoader_GetLoader
|
|
|
|
};
|
|
|
|
|
2004-01-20 00:21:40 +00:00
|
|
|
HRESULT WINAPI DMUSIC_CreateLoaderStream (LPVOID* ppobj) {
|
2003-08-22 23:53:27 +00:00
|
|
|
ILoaderStream *pStream;
|
|
|
|
|
2004-01-20 00:21:40 +00:00
|
|
|
TRACE("(%p)\n", ppobj);
|
2003-08-22 23:53:27 +00:00
|
|
|
pStream = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(ILoaderStream));
|
|
|
|
if (NULL == pStream) {
|
2004-01-20 00:21:40 +00:00
|
|
|
*ppobj = (LPVOID) NULL;
|
2003-08-22 23:53:27 +00:00
|
|
|
return E_OUTOFMEMORY;
|
|
|
|
}
|
2004-01-20 00:21:40 +00:00
|
|
|
pStream->UnknownVtbl = &LoaderStream_Unknown_Vtbl;
|
2003-08-22 23:53:27 +00:00
|
|
|
pStream->StreamVtbl = &LoaderStream_Stream_Vtbl;
|
|
|
|
pStream->GetLoaderVtbl = &LoaderStream_GetLoader_Vtbl;
|
2004-01-20 00:21:40 +00:00
|
|
|
pStream->ref = 0; /* will be inited with QueryInterface */
|
|
|
|
|
|
|
|
return ILoaderStream_IUnknown_QueryInterface ((LPUNKNOWN)&pStream->UnknownVtbl, &IID_IStream, ppobj);
|
2003-08-22 23:53:27 +00:00
|
|
|
}
|