- 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:
parent
07b19112e5
commit
54f041ad32
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue