- Base FileMonikerImpl_Save() on XP.

- Correct handling of Unicode strings & multibyte locales.
- More error checking.
- Change ERR to WARN.
- Match Windows quick & dirty estimate for GetSizeMax().
This commit is contained in:
Richard Cohen 2005-06-02 19:42:48 +00:00 committed by Alexandre Julliard
parent 07b19112e5
commit 54f041ad32
1 changed files with 164 additions and 117 deletions

View File

@ -185,118 +185,152 @@ static HRESULT WINAPI
FileMonikerImpl_Load(IMoniker* iface, IStream* pStm) FileMonikerImpl_Load(IMoniker* iface, IStream* pStm)
{ {
HRESULT res; HRESULT res;
CHAR* filePathA; CHAR* filePathA = NULL;
WCHAR* filePathW; WCHAR* filePathW = NULL;
ULONG bread; ULONG bread;
WORD wbuffer; WORD wbuffer;
DWORD dwbuffer,length,i,doubleLenHex,doubleLenDec; DWORD dwbuffer, bytesA, bytesW, len;
int i;
FileMonikerImpl *This = (FileMonikerImpl *)iface; FileMonikerImpl *This = (FileMonikerImpl *)iface;
TRACE("(%p,%p)\n",iface,pStm); TRACE("(%p,%p)\n",iface,pStm);
/* first WORD is non significative */ /* first WORD must be 0 */
res=IStream_Read(pStm,&wbuffer,sizeof(WORD),&bread); res=IStream_Read(pStm,&wbuffer,sizeof(WORD),&bread);
if (bread!=sizeof(WORD) || wbuffer!=0) if (bread!=sizeof(WORD) || wbuffer!=0)
{ {
ERR("Couldn't read 0 word\n"); WARN("Couldn't read 0 word\n");
return E_FAIL; goto fail;
} }
/* read filePath string length (plus one) */ /* read filePath string length (plus one) */
res=IStream_Read(pStm,&length,sizeof(DWORD),&bread); res=IStream_Read(pStm,&bytesA,sizeof(DWORD),&bread);
if (bread != sizeof(DWORD)) if (bread != sizeof(DWORD))
{ {
ERR("Couldn't read file string length\n"); WARN("Couldn't read file string length\n");
return E_FAIL; goto fail;
} }
/* read filePath string */ /* read filePath string */
filePathA=HeapAlloc(GetProcessHeap(),0,length); filePathA=HeapAlloc(GetProcessHeap(),0,bytesA);
res=IStream_Read(pStm,filePathA,length,&bread); if (!filePathA)
HeapFree(GetProcessHeap(),0,filePathA);
if (bread != length)
{ {
ERR("Couldn't read file path string\n"); res = E_OUTOFMEMORY;
return E_FAIL; goto fail;
}
res=IStream_Read(pStm,filePathA,bytesA,&bread);
if (bread != bytesA)
{
WARN("Couldn't read file path string\n");
goto fail;
} }
/* read the first constant */ /* read the first constant */
IStream_Read(pStm,&dwbuffer,sizeof(DWORD),&bread); IStream_Read(pStm,&dwbuffer,sizeof(DWORD),&bread);
if (bread != sizeof(DWORD) || dwbuffer != 0xDEADFFFF) if (bread != sizeof(DWORD) || dwbuffer != 0xDEADFFFF)
{ {
ERR("Couldn't read 0xDEADFFFF constant\n"); WARN("Couldn't read 0xDEADFFFF constant\n");
return E_FAIL; goto fail;
} }
length--; for(i=0;i<5;i++)
for(i=0;i<10;i++){
res=IStream_Read(pStm,&wbuffer,sizeof(WORD),&bread);
if (bread!=sizeof(WORD) || wbuffer!=0)
{ {
ERR("Couldn't read 0 padding\n"); res=IStream_Read(pStm,&dwbuffer,sizeof(DWORD),&bread);
return E_FAIL; if (bread!=sizeof(DWORD) || dwbuffer!=0)
{
WARN("Couldn't read 0 padding\n");
goto fail;
} }
} }
if (length>8) res=IStream_Read(pStm,&dwbuffer,sizeof(DWORD),&bread);
length=0; if (bread!=sizeof(DWORD))
goto fail;
doubleLenHex=doubleLenDec=2*length; if (!dwbuffer) /* No W-string */
if (length > 5) {
doubleLenDec+=6; bytesA--;
len=MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, filePathA, bytesA, NULL, 0);
if (!len)
goto fail;
filePathW=HeapAlloc(GetProcessHeap(),0,(len+1)*sizeof(WCHAR));
if (!filePathW)
{
res = E_OUTOFMEMORY;
goto fail;
}
MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, filePathA, -1, filePathW, len+1);
goto succeed;
}
if (dwbuffer < 6)
goto fail;
bytesW=dwbuffer - 6;
res=IStream_Read(pStm,&dwbuffer,sizeof(DWORD),&bread); res=IStream_Read(pStm,&dwbuffer,sizeof(DWORD),&bread);
if (bread!=sizeof(DWORD) || dwbuffer!=doubleLenDec) if (bread!=sizeof(DWORD) || dwbuffer!=bytesW)
return E_FAIL; goto fail;
if (length==0)
return res;
res=IStream_Read(pStm,&dwbuffer,sizeof(DWORD),&bread);
if (bread!=sizeof(DWORD) || dwbuffer!=doubleLenHex)
return E_FAIL;
res=IStream_Read(pStm,&wbuffer,sizeof(WORD),&bread); res=IStream_Read(pStm,&wbuffer,sizeof(WORD),&bread);
if (bread!=sizeof(WORD) || wbuffer!=0x3) if (bread!=sizeof(WORD) || wbuffer!=0x3)
return E_FAIL; goto fail;
filePathW=HeapAlloc(GetProcessHeap(),0,(length+1)*sizeof(WCHAR)); len=bytesW/sizeof(WCHAR);
filePathW[length]=0; filePathW=HeapAlloc(GetProcessHeap(),0,(len+1)*sizeof(WCHAR));
res=IStream_Read(pStm,filePathW,doubleLenHex,&bread); if(!filePathW)
if (bread!=doubleLenHex) { {
HeapFree(GetProcessHeap(), 0, filePathW); res = E_OUTOFMEMORY;
return E_FAIL; goto fail;
} }
res=IStream_Read(pStm,filePathW,bytesW,&bread);
if (bread!=bytesW)
goto fail;
filePathW[len]=0;
succeed:
HeapFree(GetProcessHeap(),0,filePathA);
HeapFree(GetProcessHeap(),0,This->filePathName); HeapFree(GetProcessHeap(),0,This->filePathName);
This->filePathName=filePathW; This->filePathName=filePathW;
return S_OK;
fail:
HeapFree(GetProcessHeap(), 0, filePathA);
HeapFree(GetProcessHeap(), 0, filePathW);
if (SUCCEEDED(res))
res = E_FAIL;
return res; return res;
} }
/****************************************************************************** /******************************************************************************
* FileMoniker_Save * FileMoniker_Save
* *
* This function saves data of this object. In the beginning I thougth * This function saves data of this object. In the beginning I thought
* that I have just to write the filePath string on Stream. But, when I * that I have just to write the filePath string on Stream. But, when I
* tested this function whith windows programs samples, I noticed that it * tested this function with windows programs samples, I noticed that it
* was not the case. So I analysed data written by this function on * was not the case. This implementation is based on XP SP2. Other versions
* Windows and what this did function exactly ! But I have no idea about * of Windows have minor variations.
* its logic ! *
* I guessed data which must be written on stream is: * Data which must be written on stream is:
* 1) WORD constant:zero * 1) WORD constant:zero
* 2) length of the path string ("\0" included) * 2) length of the path string ("\0" included)
* 3) path string type A * 3) path string type A
* 4) DWORD constant : 0xDEADFFFF * 4) DWORD constant : 0xDEADFFFF
* 5) ten WORD constant: zero * 5) five DWORD constant: zero
* 6) DWORD: double-length of the the path string type W ("\0" not * 6) If we're only writing the multibyte version,
* write a zero DWORD and finish.
*
* 7) DWORD: double-length of the the path string type W ("\0" not
* included) * included)
* 7) WORD constant: 0x3 * 8) WORD constant: 0x3
* 8) filePath unicode string. * 9) filePath unicode string.
* if the length(filePath) > 8 or length(filePath) == 8 stop at step 5) *
*/ */
static HRESULT WINAPI static HRESULT WINAPI
FileMonikerImpl_Save(IMoniker* iface, IStream* pStm, BOOL fClearDirty) FileMonikerImpl_Save(IMoniker* iface, IStream* pStm, BOOL fClearDirty)
@ -306,63 +340,91 @@ FileMonikerImpl_Save(IMoniker* iface, IStream* pStm, BOOL fClearDirty)
HRESULT res; HRESULT res;
LPOLESTR filePathW=This->filePathName; LPOLESTR filePathW=This->filePathName;
CHAR* filePathA; CHAR* filePathA;
DWORD len; DWORD bytesA, bytesW, len;
DWORD constant1 = 0xDEADFFFF; /* these constants are detected after analysing the data structure written by */ static const DWORD DEADFFFF = 0xDEADFFFF; /* Constants */
WORD constant2 = 0x3; /* FileMoniker_Save function in a windows program system */ static const DWORD ZERO = 0;
static const WORD THREE = 0x3;
WORD zero=0; int i;
DWORD doubleLenHex; BOOL bUsedDefault, bWriteWide;
DWORD doubleLenDec;
int i=0;
TRACE("(%p,%p,%d)\n",iface,pStm,fClearDirty); TRACE("(%p,%p,%d)\n",iface,pStm,fClearDirty);
if (pStm==NULL) if (pStm==NULL)
return E_POINTER; return E_POINTER;
/* write a DWORD set to 0 : constant */ /* write a 0 WORD */
res=IStream_Write(pStm,&zero,sizeof(WORD),NULL); res=IStream_Write(pStm,&ZERO,sizeof(WORD),NULL);
if (!SUCCEEDED(res)) return res;
/* write length of filePath string ( "\0" included )*/ /* write length of filePath string ( 0 included )*/
len = WideCharToMultiByte( CP_ACP, 0, filePathW, -1, NULL, 0, NULL, NULL ); bytesA = WideCharToMultiByte( CP_ACP, 0, filePathW, -1, NULL, 0, NULL, NULL );
res=IStream_Write(pStm,&len,sizeof(DWORD),NULL); res=IStream_Write(pStm,&bytesA,sizeof(DWORD),NULL);
if (!SUCCEEDED(res)) return res;
/* write filePath string type A */ /* write A string (with '\0') */
filePathA=HeapAlloc(GetProcessHeap(),0,len); filePathA=HeapAlloc(GetProcessHeap(),0,bytesA);
WideCharToMultiByte( CP_ACP, 0, filePathW, -1, filePathA, len, NULL, NULL ); if (!filePathA)
res=IStream_Write(pStm,filePathA,len,NULL); return E_OUTOFMEMORY;
WideCharToMultiByte( CP_ACP, 0, filePathW, -1, filePathA, bytesA, NULL, &bUsedDefault);
res=IStream_Write(pStm,filePathA,bytesA,NULL);
HeapFree(GetProcessHeap(),0,filePathA); HeapFree(GetProcessHeap(),0,filePathA);
if (!SUCCEEDED(res)) return res;
/* write a DWORD set to 0xDEADFFFF: constant */ /* write a DWORD 0xDEADFFFF */
res=IStream_Write(pStm,&constant1,sizeof(DWORD),NULL); res=IStream_Write(pStm,&DEADFFFF,sizeof(DWORD),NULL);
if (!SUCCEEDED(res)) return res;
len--; /* write 5 zero DWORDs */
/* write 10 times a DWORD set to 0 : constants */ for(i=0;i<5;i++)
for(i=0;i<10;i++) {
res=IStream_Write(pStm,&zero,sizeof(WORD),NULL); res=IStream_Write(pStm,&ZERO,sizeof(DWORD),NULL);
if (!SUCCEEDED(res)) return res;
}
if (len>8) /* Write the wide version if:
len=0; * + couldn't convert to CP_ACP,
* or + it's a directory,
* or + there's a character > 0xFF
*/
len = lstrlenW(filePathW);
bWriteWide = (bUsedDefault || (len > 0 && filePathW[len-1]=='\\' ));
if (!bWriteWide)
{
WCHAR* pch;
for(pch=filePathW;*pch;++pch)
{
if (*pch > 0xFF)
{
bWriteWide = TRUE;
break;
}
}
}
doubleLenHex=doubleLenDec=2*len; if (!bWriteWide)
if (len > 5) {
doubleLenDec+=6; res=IStream_Write(pStm,&ZERO,sizeof(DWORD),NULL);
/* write double-length of the path string ( "\0" included )*/
res=IStream_Write(pStm,&doubleLenDec,sizeof(DWORD),NULL);
if (len==0)
return res; return res;
}
/* write double-length (hexa representation) of the path string ( "\0" included ) */ /* write bytes needed for the filepathW (without 0) + 6 */
res=IStream_Write(pStm,&doubleLenHex,sizeof(DWORD),NULL); bytesW = len*sizeof(WCHAR) + 6;
res=IStream_Write(pStm,&bytesW,sizeof(DWORD),NULL);
if (!SUCCEEDED(res)) return res;
/* write a WORD set to 0x3: constant */ /* try again, without the extra 6 */
res=IStream_Write(pStm,&constant2,sizeof(WORD),NULL); bytesW -= 6;
res=IStream_Write(pStm,&bytesW,sizeof(DWORD),NULL);
if (!SUCCEEDED(res)) return res;
/* write path unicode string */ /* write a WORD 3 */
res=IStream_Write(pStm,filePathW,doubleLenHex,NULL); res=IStream_Write(pStm,&THREE,sizeof(WORD),NULL);
if (!SUCCEEDED(res)) return res;
/* write W string (no 0) */
res=IStream_Write(pStm,filePathW,bytesW,NULL);
return res; return res;
} }
@ -374,31 +436,16 @@ static HRESULT WINAPI
FileMonikerImpl_GetSizeMax(IMoniker* iface, ULARGE_INTEGER* pcbSize) FileMonikerImpl_GetSizeMax(IMoniker* iface, ULARGE_INTEGER* pcbSize)
{ {
FileMonikerImpl *This = (FileMonikerImpl *)iface; FileMonikerImpl *This = (FileMonikerImpl *)iface;
DWORD len=lstrlenW(This->filePathName);
DWORD sizeMAx;
TRACE("(%p,%p)\n",iface,pcbSize); TRACE("(%p,%p)\n",iface,pcbSize);
if (!pcbSize) if (!pcbSize)
return E_POINTER; return E_POINTER;
/* for more details see FileMonikerImpl_Save coments */ /* We could calculate exactly (see ...::Save()) but instead
* we'll make a quick over-estimate, like Windows (NT4, XP) does.
sizeMAx = sizeof(WORD) + /* first WORD is 0 */ */
sizeof(DWORD)+ /* length of filePath including "\0" in the end of the string */ pcbSize->u.LowPart = 0x38 + 4 * lstrlenW(This->filePathName);
(len+1)+ /* filePath string */
sizeof(DWORD)+ /* constant : 0xDEADFFFF */
10*sizeof(WORD)+ /* 10 zero WORD */
sizeof(DWORD); /* size of the unicode filePath: "\0" not included */
if (len==0 || len > 8)
return S_OK;
sizeMAx += sizeof(DWORD)+ /* size of the unicode filePath: "\0" not included */
sizeof(WORD)+ /* constant : 0x3 */
len*sizeof(WCHAR); /* unicde filePath string */
pcbSize->u.LowPart=sizeMAx;
pcbSize->u.HighPart = 0; pcbSize->u.HighPart = 0;
return S_OK; return S_OK;