|
|
//+---------------------------------------------------------------------------
//
// File: rwinf.cpp
//
// Contents: Implementation for the Windows NT 3.51 inf Read/Write module
//
// Classes:
//
// History: 13-Mar-95 alessanm created
//
//----------------------------------------------------------------------------
#include "stdafx.h"
#include <afxdllx.h>
#include "inf.h"
#include "..\common\helper.h"
#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__; #endif
/////////////////////////////////////////////////////////////////////////////
// General Declarations
#define RWTAG "INF"
#define INF_TYPE 11
#define MAX_INF_TEXT_LINE 55
#define Pad4(x) ((((x+3)>>2)<<2)-x)
typedef struct tagUpdResList { WORD * pTypeId; BYTE * pTypeName; WORD * pResId; BYTE * pResName; DWORD * pLang; DWORD * pSize; struct tagUpdResList* pNext; } UPDATEDRESLIST, *PUPDATEDRESLIST;
class CLoadedFile : public CObject { public: CLoadedFile(LPCSTR lpfilename);
CInfFile m_infFile; CString m_strFileName; };
CLoadedFile::CLoadedFile(LPCSTR lpfilename) { TRY { m_infFile.Open(lpfilename, CFile::modeRead | CFile::shareDenyNone); } CATCH(CFileException, pfe) { AfxThrowFileException(pfe->m_cause, pfe->m_lOsError); } END_CATCH
m_strFileName = lpfilename; }
/////////////////////////////////////////////////////////////////////////////
// Function Declarations
LONG WriteResInfo( BYTE** lplpBuffer, LONG* plBufSize, WORD wTypeId, LPCSTR lpszTypeId, BYTE bMaxTypeLen, WORD wNameId, LPCSTR lpszNameId, BYTE bMaxNameLen, DWORD dwLang, DWORD dwSize, DWORD dwFileOffset );
CInfFile * LoadFile(LPCSTR lpfilename);
PUPDATEDRESLIST CreateUpdateResList(BYTE * lpBuffer, UINT uiBufSize); PUPDATEDRESLIST FindId(LPCSTR pstrId, PUPDATEDRESLIST pList);
/////////////////////////////////////////////////////////////////////////////
// Public C interface implementation
CObArray g_LoadedFile;
//[registration]
extern "C" BOOL FAR PASCAL RWGetTypeString(LPSTR lpszTypeName) { strcpy( lpszTypeName, RWTAG ); return FALSE; }
extern "C" BOOL FAR PASCAL RWValidateFileType(LPCSTR lpszFilename) { TRACE("RWINF.DLL: RWValidateFileType()\n");
// Check file exstension and try to open it
if(strstr(lpszFilename, ".INF")!=NULL || strstr(lpszFilename, ".inf")!=NULL) return TRUE;
return FALSE; }
extern "C" DllExport UINT APIENTRY RWReadTypeInfo( LPCSTR lpszFilename, LPVOID lpBuffer, UINT* puiSize ) { TRACE("RWINF.DLL: RWReadTypeInfo()\n"); UINT uiError = ERROR_NO_ERROR;
if (!RWValidateFileType(lpszFilename)) return ERROR_RW_INVALID_FILE; //
// Open the file
//
CInfFile * pinfFile; TRY { pinfFile = LoadFile(lpszFilename); } CATCH(CFileException, pfe) { return pfe->m_cause + IODLL_LAST_ERROR; } END_CATCH
//
// Read the data and fill the iodll buffer
//
// Get to the beginning of the localization section
//
if(!pinfFile->SeekToLocalize()) return ERROR_RW_NO_RESOURCES;
CString strSection; CString strLine; CString strTag; CInfLine infLine;
BYTE ** pBuf = (BYTE**)&lpBuffer; LONG lBufSize = 0;
while(pinfFile->ReadTextSection(strSection)) { while(pinfFile->ReadSectionString(infLine)) { strTag = strSection + '.' + infLine.GetTag(); lBufSize += WriteResInfo( pBuf, (LONG*)puiSize, INF_TYPE, "", 0, 0, strTag, 255, 0l, infLine.GetTextLength()+1, pinfFile->GetLastFilePos() ); } }
*puiSize = lBufSize;
return uiError; }
extern "C" DllExport DWORD APIENTRY RWGetImage( LPCSTR lpszFilename, DWORD dwImageOffset, LPVOID lpBuffer, DWORD dwSize ) { UINT uiError = ERROR_NO_ERROR;
//
// Open the file
//
CInfFile * pinfFile; TRY { pinfFile = LoadFile(lpszFilename);
} CATCH(CFileException, pfe) { return pfe->m_cause + IODLL_LAST_ERROR; } END_CATCH
//
// Seek to the string to retrieve and read it
//
CInfLine infLine;
pinfFile->Seek( dwImageOffset, SEEK_SET ); pinfFile->ReadSectionString(infLine);
//
// Fill the buffer with the string
//
if(infLine.GetTextLength()+1<=(LONG)dwSize) { memcpy(lpBuffer, infLine.GetText(), infLine.GetTextLength()+1); uiError = infLine.GetTextLength()+1; } else uiError = 0;
return (DWORD)uiError; }
extern "C" DllExport UINT APIENTRY RWParseImage( LPCSTR lpszType, LPVOID lpImageBuf, DWORD dwImageSize, LPVOID lpBuffer, DWORD dwSize ) { UINT uiSizeOfDataStruct = strlen((LPCSTR)lpImageBuf)+sizeof(RESITEM);
if(uiSizeOfDataStruct<=dwSize) { //
// We have to fill the RESITEM Struct
//
LPRESITEM pResItem = (LPRESITEM)lpBuffer; memset(pResItem, '\0', uiSizeOfDataStruct);
pResItem->dwSize = uiSizeOfDataStruct; pResItem->lpszCaption = (LPSTR)memcpy( ((BYTE*)pResItem)+sizeof(RESITEM), lpImageBuf, dwImageSize); // Caption
}
return uiSizeOfDataStruct; }
extern"C" DllExport UINT APIENTRY RWWriteFile( LPCSTR lpszSrcFilename, LPCSTR lpszTgtFilename, HANDLE hResFileModule, LPVOID lpBuffer, UINT uiSize, HINSTANCE hDllInst, LPCSTR lpszSymbolPath ) { UINT uiError = ERROR_NO_ERROR;
// Get the handle to the IODLL
hDllInst = LoadLibrary("iodll.dll"); if (!hDllInst) return ERROR_DLL_LOAD;
DWORD (FAR PASCAL * lpfnGetImage)(HANDLE, LPCSTR, LPCSTR, DWORD, LPVOID, DWORD); // Get the pointer to the function to extract the resources image
lpfnGetImage = (DWORD (FAR PASCAL *)(HANDLE, LPCSTR, LPCSTR, DWORD, LPVOID, DWORD)) GetProcAddress( hDllInst, "RSGetResImage" ); if (lpfnGetImage==NULL) { FreeLibrary(hDllInst); return ERROR_DLL_LOAD; }
//
// Get the handle to the source file
//
CInfFile * psrcinfFile; TRY { psrcinfFile = LoadFile(lpszSrcFilename);
} CATCH(CFileException, pfe) { return pfe->m_cause + IODLL_LAST_ERROR; } END_CATCH
//
// Create the target file
//
CFile tgtFile; CFileException fe; if(!tgtFile.Open(lpszTgtFilename, CFile::modeCreate | CFile::modeReadWrite | CFile::shareDenyNone, &fe)) { return fe.m_cause + IODLL_LAST_ERROR; }
//
// Copy the part of the file that is not localizable
//
LONG lLocalize = psrcinfFile->SeekToLocalize(); const BYTE * pStart = psrcinfFile->GetBuffer();
if(lLocalize==-1) { // the file has no localizable info in it just copy it
lLocalize = psrcinfFile->SeekToEnd(); }
TRY { tgtFile.Write(pStart, lLocalize); } CATCH(CFileException, pfe) { return pfe->m_cause + IODLL_LAST_ERROR; } END_CATCH
//
// Create the list of updated resources
//
PUPDATEDRESLIST pResList = CreateUpdateResList((BYTE*)lpBuffer, uiSize);
//
// What we have now is a part that is mized. Part of it has localizable
// information and part has none.
// We will read each section and decide if is a localizable section or not.
// If it is we will update it otherwise just copy it
//
CString strSection, str; CString strLang = psrcinfFile->GetLanguage(); LONG lEndPos, lStartPos; CInfLine infLine;
while(psrcinfFile->ReadSection(strSection)) { TRY { tgtFile.Write(strSection, strSection.GetLength()); tgtFile.Write("\r\n", 2); } CATCH(CFileException, pfe) { return pfe->m_cause + IODLL_LAST_ERROR; } END_CATCH
if(strSection.Find(strLang)==-1) { //
// This is not a localizable section
//
lStartPos = psrcinfFile->Seek(0, SEEK_CUR);
//
// Read the next section untill we find a localizable section
//
while(psrcinfFile->ReadSection(strSection)) { if(strSection.Find(strLang)!=-1) break; }
//
// Where are we now?
//
lEndPos = psrcinfFile->Seek(0, SEEK_CUR) - strSection.GetLength()-2;
//
// Make sure we are not at the end of the file
//
if(lEndPos<=lStartPos) { // we have no more section so copy all is left
lEndPos = psrcinfFile->Seek(0, SEEK_END) - 1; }
//
// copy the full block
//
pStart = psrcinfFile->GetBuffer(lStartPos); TRY { tgtFile.Write(pStart, lEndPos-lStartPos); } CATCH(CFileException, pfe) { return pfe->m_cause + IODLL_LAST_ERROR; } END_CATCH
psrcinfFile->Seek(lEndPos, SEEK_SET); } else { //
// This is a localizable section
// Read all the strings and see if they have been updated
//
CString strId; PUPDATEDRESLIST pListItem; BYTE * pByte;
lEndPos = psrcinfFile->Seek(0, SEEK_CUR);
while(psrcinfFile->ReadSectionString(str)) { str += "\r\n";
infLine = str;
//
// Check if we need to update this string
//
strId = strSection + "." + infLine.GetTag();
if(pListItem = FindId(strId, pResList)) { // allocate the buffer to hold the resource data
pByte = new BYTE[*pListItem->pSize]; if(!pByte){ uiError = ERROR_NEW_FAILED; goto exit; }
// get the data from the iodll
LPSTR lpType = NULL; LPSTR lpRes = NULL; if (*pListItem->pTypeId) { lpType = (LPSTR)((WORD)*pListItem->pTypeId); } else { lpType = (LPSTR)pListItem->pTypeName; } if (*pListItem->pResId) { lpRes = (LPSTR)((WORD)*pListItem->pResId); } else { lpRes = (LPSTR)pListItem->pResName; }
DWORD dwImageBufSize = (*lpfnGetImage)( hResFileModule, lpType, lpRes, *pListItem->pLang, pByte, *pListItem->pSize );
if(dwImageBufSize!=*pListItem->pSize) { // something is wrong...
delete []pByte; } else {
infLine.ChangeText((LPCSTR)pByte);
//
// Now we have the updated image...
//
//
// Check how long is the Data and split it in to lines
//
if(infLine.GetTextLength()>MAX_INF_TEXT_LINE) { //
// First write the tag
//
str = infLine.GetData(); int iSpaceLen = str.Find('=')+1; int iTagLen = 0;
TRY { tgtFile.Write(str, iSpaceLen); } CATCH(CFileException, pfe) { return pfe->m_cause + IODLL_LAST_ERROR; } END_CATCH
//
// Now write the rest
//
int iExtra, iMaxStr; CString strLine; CString strSpace( ' ', iSpaceLen+1 ); BOOL bFirstLine = TRUE;
strSpace += '\"'; str = infLine.GetText(); str.TrimLeft();
while(str.GetLength()>MAX_INF_TEXT_LINE) { iMaxStr = str.GetLength();
strLine = str.Left(MAX_INF_TEXT_LINE);
//
// Check if we are in the middle of a word
//
iExtra = 0; while((iMaxStr>MAX_INF_TEXT_LINE+iExtra) && str.GetAt(MAX_INF_TEXT_LINE+iExtra)!=' ') { strLine += str.GetAt(MAX_INF_TEXT_LINE+iExtra++); }
//
// Make sure the spaces are the last thing
//
while((iMaxStr>MAX_INF_TEXT_LINE+iExtra) && str.GetAt(MAX_INF_TEXT_LINE+iExtra)==' ') { strLine += str.GetAt(MAX_INF_TEXT_LINE+iExtra++); }
str = str.Mid(MAX_INF_TEXT_LINE+iExtra); if(str.IsEmpty()) { //
// This string is all done write it as is, we can't break it
//
strLine += "\r\n"; } else strLine += "\"+\r\n";
if(bFirstLine) { strLine = " " + strLine; bFirstLine = FALSE;
} else { strLine = strSpace + strLine; }
TRY { tgtFile.Write(strLine, strLine.GetLength()); } CATCH(CFileException, pfe) { return pfe->m_cause + IODLL_LAST_ERROR; } END_CATCH
//str = str.Mid(MAX_INF_TEXT_LINE+iExtra);
}
if(bFirstLine) { strLine = " " + str; } else { if(!str.IsEmpty()) strLine = strSpace + str; else strLine = ""; }
if(!strLine.IsEmpty()) { TRY { tgtFile.Write(strLine, strLine.GetLength()); tgtFile.Write("\r\n", 2); } CATCH(CFileException, pfe) { return pfe->m_cause + IODLL_LAST_ERROR; } END_CATCH } } else { TRY { tgtFile.Write(infLine.GetData(), infLine.GetDataLength()); tgtFile.Write("\r\n", 2); } CATCH(CFileException, pfe) { return pfe->m_cause + IODLL_LAST_ERROR; } END_CATCH }
delete []pByte; } } else { TRY { tgtFile.Write(infLine.GetData(), infLine.GetDataLength()); } CATCH(CFileException, pfe) { return pfe->m_cause + IODLL_LAST_ERROR; } END_CATCH }
lEndPos = psrcinfFile->Seek(0, SEEK_CUR); } } }
exit: tgtFile.Close();
if(pResList) delete []pResList;
return uiError; }
extern "C" DllExport UINT APIENTRY RWUpdateImage( LPCSTR lpszType, LPVOID lpNewBuf, DWORD dwNewSize, LPVOID lpOldImage, DWORD dwOldImageSize, LPVOID lpNewImage, DWORD* pdwNewImageSize ) { UINT uiError = ERROR_NO_ERROR;
//
// Get the new string
//
LPCSTR lpNewStr = (LPCSTR)(((LPRESITEM)lpNewBuf)->lpszCaption);
//
// Copy the string in the new image buffer
//
int iLen = strlen(lpNewStr)+1; if(iLen<=(LONG)*pdwNewImageSize) { memcpy(lpNewImage, lpNewStr, iLen); }
*pdwNewImageSize = iLen;
return uiError; }
///////////////////////////////////////////////////////////////////////////
// Functions implementation
//=============================================================================
// WriteResInfo
//
// Fill the buffer to pass back to the iodll
//=============================================================================
LONG WriteResInfo( BYTE** lplpBuffer, LONG* plBufSize, WORD wTypeId, LPCSTR lpszTypeId, BYTE bMaxTypeLen, WORD wNameId, LPCSTR lpszNameId, BYTE bMaxNameLen, DWORD dwLang, DWORD dwSize, DWORD dwFileOffset ) { LONG lSize = 0; lSize = PutWord( lplpBuffer, wTypeId, plBufSize ); lSize += PutStringA( lplpBuffer, (LPSTR)lpszTypeId, plBufSize ); // Note: PutStringA should get LPCSTR and not LPSTR
lSize += Allign( lplpBuffer, plBufSize, lSize);
lSize += PutWord( lplpBuffer, wNameId, plBufSize ); lSize += PutStringA( lplpBuffer, (LPSTR)lpszNameId, plBufSize ); lSize += Allign( lplpBuffer, plBufSize, lSize);
lSize += PutDWord( lplpBuffer, dwLang, plBufSize ); lSize += PutDWord( lplpBuffer, dwSize, plBufSize ); lSize += PutDWord( lplpBuffer, dwFileOffset, plBufSize );
return (LONG)lSize; }
CInfFile * LoadFile(LPCSTR lpfilename) { // Check if we have loaded the file before
int c = (int)g_LoadedFile.GetSize(); CLoadedFile * pLoaded; while(c) { pLoaded = (CLoadedFile*)g_LoadedFile.GetAt(--c); if(pLoaded->m_strFileName==lpfilename) return &pLoaded->m_infFile; }
// The file need to be added to the list
pLoaded = new CLoadedFile(lpfilename);
g_LoadedFile.Add((CObject*)pLoaded);
return &pLoaded->m_infFile; }
PUPDATEDRESLIST CreateUpdateResList(BYTE * lpBuffer, UINT uiBufSize) { //
// Walk the buffer and count how many resources we have
//
int iResCount = 0; int iBufSize = uiBufSize; int iResSize = 0; BYTE * pBuf = lpBuffer; while(iBufSize>0) { iResSize = 2; iResSize += strlen((LPSTR)(pBuf+iResSize))+1; iResSize += Pad4(iResSize);
iResSize += 2; iResSize += strlen((LPSTR)(pBuf+iResSize))+1; iResSize += Pad4(iResSize);
iResSize += 4*2;
if(iResSize<=iBufSize) { iBufSize -= iResSize; pBuf = pBuf + iResSize; iResCount++; } }
//
// Allocate the buffer that will hold the list
//
if(!iResCount) return NULL;
pBuf = lpBuffer; iBufSize = uiBufSize;
PUPDATEDRESLIST pListHead = new UPDATEDRESLIST[iResCount];
if(pListHead==NULL) AfxThrowMemoryException();
memset(pListHead, 0, sizeof(UPDATEDRESLIST)*iResCount);
PUPDATEDRESLIST pList = pListHead; BYTE bPad = 0; WORD wSize = 0; while(iBufSize>0) { pList->pTypeId = (WORD*)pBuf; pList->pTypeName = (BYTE*)pList->pTypeId+sizeof(WORD); // check the allignement
bPad = strlen((LPSTR)pList->pTypeName)+1+sizeof(WORD); bPad += Pad4(bPad); wSize = bPad; pList->pResId = (WORD*)((BYTE*)pBuf+bPad); pList->pResName = (BYTE*)pList->pResId+sizeof(WORD); bPad = strlen((LPSTR)pList->pResName)+1+sizeof(WORD); bPad += Pad4(bPad); wSize += bPad; pList->pLang = (DWORD*)((BYTE*)pList->pResId+bPad); pList->pSize = (DWORD*)((BYTE*)pList->pLang+sizeof(DWORD)); pList->pNext = (PUPDATEDRESLIST)pList+1; wSize += sizeof(DWORD)*2; pBuf = pBuf+wSize; iBufSize -= wSize; if(!iBufSize) pList->pNext = NULL; else pList++; }
return pListHead; }
PUPDATEDRESLIST FindId(LPCSTR pstrId, PUPDATEDRESLIST pList) { //
// Note that this function assumes that the type is always right
// since it is a inf file this is a fair assumption.
// It could be optimized.
//
if(!pList) return NULL;
PUPDATEDRESLIST pLast = pList; while(pList) { if(!strcmp((LPSTR)pList->pResName, pstrId)) { return pList; } pList = pList->pNext; }
return NULL; }
////////////////////////////////////////////////////////////////////////////
// DLL Specific code implementation
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
// Library init
static AFX_EXTENSION_MODULE rwinfDLL = { NULL, NULL };
extern "C" int APIENTRY DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) { if (dwReason == DLL_PROCESS_ATTACH) { TRACE0("RWINF.DLL Initializing!\n");
AfxInitExtensionModule(rwinfDLL, hInstance);
new CDynLinkLibrary(rwinfDLL);
} else if (dwReason == DLL_PROCESS_DETACH) { TRACE0("RWINF.DLL Terminating!\n");
// free all the loaded files
int c = (int)g_LoadedFile.GetSize(); CLoadedFile * pLoaded; while(c) { pLoaded = (CLoadedFile*)g_LoadedFile.GetAt(--c); delete pLoaded; } } return 1; }
|