mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
897 lines
20 KiB
897 lines
20 KiB
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
infgen.c
|
|
|
|
Abstract:
|
|
|
|
Routines to generate an inf file that can later be used
|
|
instead of sysdiff /apply, to apply a sysdiff package
|
|
|
|
Author:
|
|
|
|
Ted Miller (tedm) 12-Apr-1996
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
|
|
typedef enum {
|
|
AddQuotesNone,
|
|
AddQuotesNormal,
|
|
AddQuotesOpenNoClose,
|
|
AddQuotesNoOpenOrClose,
|
|
} AddQuotesOp;
|
|
|
|
|
|
DWORD
|
|
pInfCmdlinesTxt(
|
|
IN PINFFILEGEN Context
|
|
);
|
|
|
|
|
|
DWORD
|
|
FlushGenInfLineBuf(
|
|
IN OUT PINFFILEGEN Context,
|
|
IN HANDLE File
|
|
)
|
|
{
|
|
CHAR TransBuf[INFLINEBUFLEN*2];
|
|
DWORD rc;
|
|
PVOID Buffer;
|
|
DWORD Size;
|
|
BOOL b;
|
|
|
|
if(UnicodeTextFiles) {
|
|
|
|
Buffer = Context->LineBuf;
|
|
Size = Context->LineBufUsed * sizeof(WCHAR);
|
|
|
|
} else {
|
|
|
|
Buffer = TransBuf;
|
|
|
|
Size = WideCharToMultiByte(
|
|
CP_ACP,
|
|
0,
|
|
Context->LineBuf,
|
|
Context->LineBufUsed,
|
|
TransBuf,
|
|
sizeof(TransBuf),
|
|
NULL,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
if(WriteFile(File,Buffer,Size,&rc,NULL)) {
|
|
rc = NO_ERROR;
|
|
Context->LineBufUsed = 0;
|
|
} else {
|
|
rc = GetLastError();
|
|
}
|
|
|
|
return(rc);
|
|
}
|
|
|
|
|
|
DWORD
|
|
__inline
|
|
GenInfWriteChar(
|
|
IN OUT PINFFILEGEN Context,
|
|
IN HANDLE File,
|
|
IN WCHAR Char
|
|
)
|
|
{
|
|
DWORD rc;
|
|
PVOID Buffer;
|
|
|
|
Context->LineBuf[Context->LineBufUsed++] = Char;
|
|
|
|
rc = (Context->LineBufUsed == INFLINEBUFLEN)
|
|
? FlushGenInfLineBuf(Context,File)
|
|
: NO_ERROR;
|
|
|
|
return(rc);
|
|
}
|
|
|
|
|
|
DWORD
|
|
GenInfWriteString(
|
|
IN OUT PINFFILEGEN Context,
|
|
IN HANDLE File,
|
|
IN PCWSTR String,
|
|
IN AddQuotesOp AddQuotes
|
|
)
|
|
{
|
|
DWORD rc;
|
|
WCHAR CONST *p;
|
|
|
|
if((AddQuotes == AddQuotesNormal) || (AddQuotes == AddQuotesOpenNoClose)) {
|
|
rc = GenInfWriteChar(Context,File,L'\"');
|
|
if(rc != NO_ERROR) {
|
|
return(rc);
|
|
}
|
|
}
|
|
|
|
for(p=String; *p; p++) {
|
|
rc = GenInfWriteChar(Context,File,*p);
|
|
if(rc != NO_ERROR) {
|
|
return(rc);
|
|
}
|
|
|
|
if((*p == L'\"') && (AddQuotes != AddQuotesNone)) {
|
|
rc = GenInfWriteChar(Context,File,L'\"');
|
|
if(rc != NO_ERROR) {
|
|
return(rc);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(AddQuotes == AddQuotesNormal) {
|
|
rc = GenInfWriteChar(Context,File,L'\"');
|
|
if(rc != NO_ERROR) {
|
|
return(rc);
|
|
}
|
|
}
|
|
|
|
return(NO_ERROR);
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
CreateAndOpenTempFile(
|
|
IN PCWSTR Path,
|
|
IN PCWSTR HeaderLine, OPTIONAL
|
|
OUT HANDLE *Handle,
|
|
OUT PWSTR Filename
|
|
)
|
|
{
|
|
HANDLE h;
|
|
DWORD rc;
|
|
|
|
//
|
|
// Note that this creates the file.
|
|
//
|
|
if(!GetTempFileName(Path,L"$IF",0,Filename)) {
|
|
rc = GetLastError();
|
|
goto c0;
|
|
}
|
|
|
|
h = CreateFile(
|
|
Filename,
|
|
GENERIC_WRITE,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
CREATE_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL
|
|
);
|
|
|
|
if(h == INVALID_HANDLE_VALUE) {
|
|
rc = GetLastError();
|
|
goto c1;
|
|
}
|
|
|
|
if(HeaderLine) {
|
|
rc = WriteText(h,MSG_INF_SINGLELINE,HeaderLine);
|
|
if(rc != NO_ERROR) {
|
|
goto c2;
|
|
}
|
|
}
|
|
|
|
*Handle = h;
|
|
return(NO_ERROR);
|
|
|
|
c2:
|
|
CloseHandle(h);
|
|
c1:
|
|
DeleteFile(Filename);
|
|
c0:
|
|
return(rc);
|
|
}
|
|
|
|
|
|
DWORD
|
|
InfStart(
|
|
IN PCWSTR InfName,
|
|
IN PCWSTR Directory,
|
|
OUT PINFFILEGEN *Context
|
|
)
|
|
{
|
|
WCHAR InfFileName[MAX_PATH];
|
|
DWORD d;
|
|
DWORD rc;
|
|
PINFFILEGEN context;
|
|
UCHAR UnicodeMark[2];
|
|
PWSTR p;
|
|
|
|
//
|
|
// Allocate some context.
|
|
//
|
|
context = _MyMalloc(sizeof(INFFILEGEN));
|
|
if(!context) {
|
|
rc = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto c0;
|
|
}
|
|
ZeroMemory(context,sizeof(INFFILEGEN));
|
|
|
|
//
|
|
// We'll create a unique inf name in the given directory
|
|
// to use as the output inf. The directory itself will
|
|
// become the oem file root.
|
|
//
|
|
if(!GetFullPathName(Directory,MAX_PATH,context->OemRoot,&p)) {
|
|
rc = GetLastError();
|
|
goto c1;
|
|
}
|
|
lstrcpy(context->OutputFileName,context->OemRoot);
|
|
ConcatenatePaths(context->OutputFileName,WINNT_OEM_DIR,MAX_PATH,NULL);
|
|
ConcatenatePaths(context->OutputFileName,InfName,MAX_PATH,NULL);
|
|
|
|
//
|
|
// Try to make sure the target dir exists.
|
|
//
|
|
pSetupMakeSurePathExists(context->OutputFileName);
|
|
|
|
//
|
|
// Form a temp filename for the registry add section
|
|
// and open the file.
|
|
//
|
|
rc = CreateAndOpenTempFile(
|
|
Directory,
|
|
L"[AddReg]",
|
|
&context->AddRegFile,
|
|
context->AddRegFileName
|
|
);
|
|
|
|
if(rc != NO_ERROR) {
|
|
goto c1;
|
|
}
|
|
|
|
//
|
|
// Form a temp filename for the registry delete section
|
|
// and open the file
|
|
//
|
|
rc = CreateAndOpenTempFile(
|
|
Directory,
|
|
L"[DelReg]",
|
|
&context->DelRegFile,
|
|
context->DelRegFileName
|
|
);
|
|
|
|
if(rc != NO_ERROR) {
|
|
goto c2;
|
|
}
|
|
|
|
//
|
|
// Form a temp filename for the inifiles section
|
|
// and open the file
|
|
//
|
|
rc = CreateAndOpenTempFile(
|
|
Directory,
|
|
L"[UpdateInis]",
|
|
&context->InifilesFile,
|
|
context->InifilesFileName
|
|
);
|
|
|
|
if(rc != NO_ERROR) {
|
|
goto c3;
|
|
}
|
|
|
|
//
|
|
// Create the output file.
|
|
//
|
|
context->OutputFile = CreateFile(
|
|
context->OutputFileName,
|
|
GENERIC_WRITE,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
CREATE_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL
|
|
);
|
|
|
|
if(context->OutputFile == INVALID_HANDLE_VALUE) {
|
|
rc = GetLastError();
|
|
goto c4;
|
|
}
|
|
|
|
//
|
|
// Write Unicode marker byte if needed.
|
|
//
|
|
if(UnicodeTextFiles) {
|
|
rc = WriteUnicodeMark(context->OutputFile);
|
|
if(rc != NO_ERROR) {
|
|
goto c5;
|
|
}
|
|
}
|
|
|
|
*Context = context;
|
|
return(NO_ERROR);
|
|
|
|
c5:
|
|
CloseHandle(context->OutputFile);
|
|
DeleteFile(context->OutputFileName);
|
|
c4:
|
|
CloseHandle(context->InifilesFile);
|
|
DeleteFile(context->InifilesFileName);
|
|
c3:
|
|
CloseHandle(context->DelRegFile);
|
|
DeleteFile(context->DelRegFileName);
|
|
c2:
|
|
CloseHandle(context->AddRegFile);
|
|
DeleteFile(context->AddRegFileName);
|
|
c1:
|
|
_MyFree(context);
|
|
c0:
|
|
return(rc);
|
|
}
|
|
|
|
|
|
DWORD
|
|
InfEnd(
|
|
IN OUT PINFFILEGEN *Context
|
|
)
|
|
{
|
|
PINFFILEGEN context;
|
|
DWORD rc;
|
|
HANDLE h;
|
|
DWORD Size;
|
|
|
|
context = *Context;
|
|
*Context = NULL;
|
|
|
|
CloseHandle(context->AddRegFile);
|
|
CloseHandle(context->DelRegFile);
|
|
CloseHandle(context->InifilesFile);
|
|
|
|
h = context->OutputFile;
|
|
|
|
//
|
|
// Write out header for inf file.
|
|
//
|
|
rc = WriteText(h,MSG_INF_HEADER);
|
|
if(rc != NO_ERROR) {
|
|
goto c1;
|
|
}
|
|
|
|
//
|
|
// Append temp files.
|
|
//
|
|
rc = AppendFile(h,context->AddRegFileName,FALSE,&Size);
|
|
if(rc != NO_ERROR) {
|
|
goto c1;
|
|
}
|
|
|
|
rc = AppendFile(h,context->DelRegFileName,FALSE,&Size);
|
|
if(rc != NO_ERROR) {
|
|
goto c1;
|
|
}
|
|
|
|
rc = AppendFile(h,context->InifilesFileName,FALSE,&Size);
|
|
if(rc != NO_ERROR) {
|
|
goto c1;
|
|
}
|
|
|
|
rc = pInfCmdlinesTxt(context);
|
|
|
|
c1:
|
|
CloseHandle(h);
|
|
if(rc != NO_ERROR) {
|
|
DeleteFile(context->OutputFileName);
|
|
}
|
|
//
|
|
// Delete temp files before returning.
|
|
//
|
|
DeleteFile(context->AddRegFileName);
|
|
DeleteFile(context->DelRegFileName);
|
|
DeleteFile(context->InifilesFileName);
|
|
_MyFree(context);
|
|
return(rc);
|
|
}
|
|
|
|
|
|
DWORD
|
|
pInfCmdlinesTxt(
|
|
IN PINFFILEGEN Context
|
|
)
|
|
{
|
|
WCHAR Filename[MAX_PATH];
|
|
PWCHAR p;
|
|
WCHAR Command[2*MAX_PATH];
|
|
PWCHAR Buffer;
|
|
DWORD BufferSize;
|
|
DWORD d;
|
|
DWORD Needed;
|
|
PCWSTR SectionName = L"Commands";
|
|
|
|
//
|
|
// Outputfilename should be a full path.
|
|
//
|
|
lstrcpy(Filename,Context->OutputFileName);
|
|
p = wcsrchr(Filename,L'\\');
|
|
MYASSERT(p);
|
|
if(p) {
|
|
p++;
|
|
} else {
|
|
return(ERROR_INVALID_NAME);
|
|
}
|
|
|
|
wsprintf(Command,L"\"rundll32 setupapi,InstallHinfSection DefaultInstall 128 .\\%s\"",p);
|
|
|
|
lstrcpy(p,L"CMDLINES.TXT");
|
|
|
|
Buffer = MyMalloc(1024);
|
|
if(!Buffer) {
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
BufferSize = 1024;
|
|
|
|
while((d = GetPrivateProfileSection(SectionName,Buffer,BufferSize,Filename)) == (BufferSize-2)) {
|
|
if(p = MyRealloc(Buffer,BufferSize+1024)) {
|
|
Buffer = p;
|
|
BufferSize += 1024;
|
|
} else {
|
|
MyFree(Buffer);
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
}
|
|
|
|
//
|
|
// The number of characters we need is the number of chars returned by
|
|
// GetPrivateProfileSection, plus the number of chars in the command string,
|
|
// plus one for the command string terminating nul, plus one for the final
|
|
// terminating nul.
|
|
//
|
|
Needed = d + lstrlen(Command) + 2;
|
|
if(Needed > BufferSize) {
|
|
if(p = MyRealloc(Buffer,Needed)) {
|
|
Buffer = p;
|
|
} else {
|
|
MyFree(Buffer);
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
}
|
|
|
|
lstrcpy(Buffer+d,Command);
|
|
*(Buffer+d+lstrlen(Command)+1) = 0;
|
|
|
|
//
|
|
// Delete section first.
|
|
//
|
|
WritePrivateProfileString(SectionName,NULL,NULL,Filename);
|
|
|
|
d = WritePrivateProfileSection(SectionName,Buffer,Filename) ? NO_ERROR : GetLastError();
|
|
MyFree(Buffer);
|
|
return(d);
|
|
}
|
|
|
|
|
|
DWORD
|
|
pInfRegLineCommon(
|
|
IN OUT PINFFILEGEN Context,
|
|
IN HANDLE OutputFile,
|
|
IN HKEY Key,
|
|
IN PCWSTR Subkey,
|
|
IN PCWSTR Value OPTIONAL
|
|
)
|
|
{
|
|
PCWSTR RootSpec;
|
|
PCWSTR SubkeySpec;
|
|
DWORD rc;
|
|
|
|
if(Subkey[0] == L'\\') {
|
|
Subkey++;
|
|
}
|
|
|
|
//
|
|
// Figure out the root key spec.
|
|
//
|
|
switch((DWORD)Key) {
|
|
|
|
case (DWORD)HKEY_LOCAL_MACHINE:
|
|
|
|
//
|
|
// Check for HKEY_CLASSES_ROOT
|
|
//
|
|
if(_wcsnicmp(Subkey,L"SOFTWARE\\Classes",16)) {
|
|
RootSpec = L"HKLM";
|
|
SubkeySpec = Subkey;
|
|
} else {
|
|
RootSpec = L"HKCR";
|
|
SubkeySpec = Subkey+16;
|
|
if(*SubkeySpec == L'\\') {
|
|
SubkeySpec++;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case (DWORD)HKEY_CURRENT_USER:
|
|
|
|
RootSpec = L"HKCU";
|
|
SubkeySpec = Subkey;
|
|
break;
|
|
|
|
case (DWORD)HKEY_CLASSES_ROOT:
|
|
|
|
RootSpec = L"HKCR";
|
|
SubkeySpec = Subkey;
|
|
break;
|
|
|
|
default:
|
|
//
|
|
// Value we can't express via inf.
|
|
// Use HKEY_ROOT but also write out a comment incidating
|
|
// that there's a problem
|
|
//
|
|
RootSpec = L"HKR";
|
|
SubkeySpec = Subkey;
|
|
|
|
Context->SawBogusOp = TRUE;
|
|
rc = FlushGenInfLineBuf(Context,OutputFile);
|
|
if(rc != NO_ERROR) {
|
|
return(rc);
|
|
}
|
|
rc = WriteText(OutputFile,MSG_INF_BAD_REGSPEC_1);
|
|
if(rc != NO_ERROR) {
|
|
return(rc);
|
|
}
|
|
break;
|
|
}
|
|
|
|
rc = GenInfWriteString(Context,OutputFile,RootSpec,AddQuotesNone);
|
|
if(rc == NO_ERROR) {
|
|
rc = GenInfWriteChar(Context,OutputFile,L',');
|
|
if(rc == NO_ERROR) {
|
|
rc = GenInfWriteString(Context,OutputFile,SubkeySpec,AddQuotesNormal);
|
|
if((rc == NO_ERROR) && Value) {
|
|
rc = GenInfWriteChar(Context,OutputFile,L',');
|
|
if(rc == NO_ERROR) {
|
|
rc = GenInfWriteString(Context,OutputFile,Value,AddQuotesNormal);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return(rc);
|
|
}
|
|
|
|
|
|
DWORD
|
|
InfRecordAddReg(
|
|
IN OUT PINFFILEGEN Context,
|
|
IN HKEY Key,
|
|
IN PCWSTR Subkey,
|
|
IN PCWSTR Value, OPTIONAL
|
|
IN DWORD DataType,
|
|
IN PVOID Data,
|
|
IN DWORD DataLength
|
|
)
|
|
{
|
|
DWORD rc;
|
|
DWORD Flags;
|
|
PWSTR p;
|
|
DWORD d;
|
|
int LineLen;
|
|
WCHAR NumStr[24];
|
|
|
|
//
|
|
// Figure out flags based on data type.
|
|
// The flags dword is built as two halves depending on whether
|
|
// data is string or binary in nature.
|
|
//
|
|
// We do this before we write out the actual line
|
|
// since that routine might also write a warning if a bogus root key
|
|
// is specified.
|
|
//
|
|
switch(DataType) {
|
|
|
|
case REG_SZ:
|
|
Flags = FLG_ADDREG_TYPE_SZ;
|
|
break;
|
|
|
|
case REG_EXPAND_SZ:
|
|
Flags = FLG_ADDREG_TYPE_EXPAND_SZ;
|
|
break;
|
|
|
|
case REG_MULTI_SZ:
|
|
Flags = FLG_ADDREG_TYPE_MULTI_SZ;
|
|
break;
|
|
|
|
case REG_DWORD:
|
|
Flags = FLG_ADDREG_TYPE_DWORD;
|
|
break;
|
|
|
|
//case REG_NONE:
|
|
// Flags = FLG_ADDREG_TYPE_NONE;
|
|
// break;
|
|
|
|
default:
|
|
//
|
|
// Arbitrary binary data. Better hope the data type doesn't overflow
|
|
// 16 bits.
|
|
//
|
|
if(DataType > 0xffff) {
|
|
Context->SawBogusOp = TRUE;
|
|
rc = FlushGenInfLineBuf(Context,Context->AddRegFile);
|
|
if(rc != NO_ERROR) {
|
|
return(rc);
|
|
}
|
|
rc = WriteText(Context->AddRegFile,MSG_INF_BAD_REGSPEC_2);
|
|
if(rc != NO_ERROR) {
|
|
return(rc);
|
|
}
|
|
DataType = REG_BINARY;
|
|
}
|
|
Flags = FLG_ADDREG_BINVALUETYPE | (DataType << 16);
|
|
break;
|
|
}
|
|
|
|
rc = pInfRegLineCommon(Context,Context->AddRegFile,Key,Subkey,Value);
|
|
if(rc != NO_ERROR) {
|
|
return(rc);
|
|
}
|
|
|
|
wsprintf(NumStr,L",%u",Flags);
|
|
rc = GenInfWriteString(Context,Context->AddRegFile,NumStr,AddQuotesNone);
|
|
if(rc != NO_ERROR) {
|
|
return(rc);
|
|
}
|
|
|
|
//
|
|
// Now we need to write out the data itself.
|
|
// How we do this is dependent on the data type.
|
|
//
|
|
switch(DataType) {
|
|
|
|
case REG_SZ:
|
|
case REG_EXPAND_SZ:
|
|
//
|
|
// Single string. Ignore data length.
|
|
//
|
|
rc = GenInfWriteChar(Context,Context->AddRegFile,L',');
|
|
if(rc == NO_ERROR) {
|
|
rc = GenInfWriteString(Context,Context->AddRegFile,Data,AddQuotesNormal);
|
|
}
|
|
break;
|
|
|
|
case REG_DWORD:
|
|
//
|
|
// Write out as a dword.
|
|
//
|
|
wsprintf(NumStr,L",%u",*(DWORD UNALIGNED *)Data);
|
|
rc = GenInfWriteString(Context,Context->AddRegFile,NumStr,AddQuotesNone);
|
|
break;
|
|
|
|
case REG_MULTI_SZ:
|
|
//
|
|
// Write out each string.
|
|
//
|
|
for(p=Data; (rc==NO_ERROR) && *p; p+=lstrlen(p)+1) {
|
|
rc = GenInfWriteChar(Context,Context->AddRegFile,L',');
|
|
if(rc == NO_ERROR) {
|
|
rc = GenInfWriteString(Context,Context->AddRegFile,p,AddQuotesNormal);
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
//
|
|
// Treat as binary. If we have any data at all start a new line.
|
|
//
|
|
if(DataLength) {
|
|
rc = GenInfWriteString(Context,Context->AddRegFile,L",\\\r\n ",AddQuotesNone);
|
|
}
|
|
|
|
LineLen = 0;
|
|
for(d=0; (rc==NO_ERROR) && (d<DataLength); d++) {
|
|
|
|
if(LineLen == 25) {
|
|
rc = GenInfWriteString(Context,Context->AddRegFile,L",\\\r\n ",AddQuotesNone);
|
|
LineLen = 0;
|
|
}
|
|
|
|
if(rc == NO_ERROR) {
|
|
if(LineLen) {
|
|
rc = GenInfWriteChar(Context,Context->AddRegFile,L',');
|
|
}
|
|
if(rc == NO_ERROR) {
|
|
wsprintf(NumStr,L"%02x",((PBYTE)Data)[d]);
|
|
rc = GenInfWriteString(Context,Context->AddRegFile,NumStr,AddQuotesNone);
|
|
LineLen++;
|
|
}
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
if(rc == NO_ERROR) {
|
|
rc = GenInfWriteString(Context,Context->AddRegFile,L"\r\n",AddQuotesNone);
|
|
if(rc == NO_ERROR) {
|
|
rc = FlushGenInfLineBuf(Context,Context->AddRegFile);
|
|
}
|
|
}
|
|
|
|
return(rc);
|
|
}
|
|
|
|
|
|
DWORD
|
|
InfRecordDelReg(
|
|
IN OUT PINFFILEGEN Context,
|
|
IN HKEY Key,
|
|
IN PCWSTR Subkey,
|
|
IN PCWSTR Value OPTIONAL
|
|
)
|
|
{
|
|
DWORD rc;
|
|
|
|
rc = pInfRegLineCommon(Context,Context->DelRegFile,Key,Subkey,Value);
|
|
if(rc == NO_ERROR) {
|
|
rc = GenInfWriteString(Context,Context->DelRegFile,L"\r\n",AddQuotesNone);
|
|
if(rc == NO_ERROR) {
|
|
rc = FlushGenInfLineBuf(Context,Context->DelRegFile);
|
|
}
|
|
}
|
|
|
|
return(rc);
|
|
}
|
|
|
|
|
|
DWORD
|
|
InfRecordIniFileChange(
|
|
IN OUT PINFFILEGEN Context,
|
|
IN PCWSTR Filename,
|
|
IN PCWSTR Section,
|
|
IN PCWSTR OldKey, OPTIONAL
|
|
IN PCWSTR New, OPTIONAL
|
|
IN PCWSTR NewKey, OPTIONAL
|
|
IN PCWSTR NewValue OPTIONAL
|
|
)
|
|
{
|
|
DWORD rc;
|
|
|
|
//
|
|
// If none of OldKey, NewKey, or NewSection are specified,
|
|
// then the section is being deleted. This is not specifyable
|
|
// in the inf so just output a warning.
|
|
//
|
|
if(!OldKey && !New && !NewKey && !NewValue) {
|
|
|
|
rc = FlushGenInfLineBuf(Context,Context->InifilesFile);
|
|
if(rc != NO_ERROR) {
|
|
return(rc);
|
|
}
|
|
rc = WriteText(Context->InifilesFile,MSG_INF_DELINISECT,Filename,Section);
|
|
Context->SawBogusOp = TRUE;
|
|
|
|
return(rc);
|
|
}
|
|
|
|
//
|
|
// Write the filename and section.
|
|
//
|
|
rc = GenInfWriteString(Context,Context->InifilesFile,Filename,AddQuotesNormal);
|
|
if(rc != NO_ERROR) {
|
|
return(rc);
|
|
}
|
|
rc = GenInfWriteChar(Context,Context->InifilesFile,L',');
|
|
if(rc != NO_ERROR) {
|
|
return(rc);
|
|
}
|
|
rc = GenInfWriteString(Context,Context->InifilesFile,Section,AddQuotesNormal);
|
|
if(rc != NO_ERROR) {
|
|
return(rc);
|
|
}
|
|
rc = GenInfWriteChar(Context,Context->InifilesFile,L',');
|
|
if(rc != NO_ERROR) {
|
|
return(rc);
|
|
}
|
|
|
|
//
|
|
// If OldKey is specified but neither NewKey or NewValue are,
|
|
// then this key is being deleted.
|
|
//
|
|
if(OldKey) {
|
|
MYASSERT(!NewKey && !NewValue);
|
|
if(!NewKey && !NewValue) {
|
|
|
|
//
|
|
// Now write oldkey=
|
|
//
|
|
rc = GenInfWriteString(Context,Context->InifilesFile,OldKey,AddQuotesOpenNoClose);
|
|
if(rc != NO_ERROR) {
|
|
return(rc);
|
|
}
|
|
rc = GenInfWriteChar(Context,Context->InifilesFile,L'=');
|
|
if(rc != NO_ERROR) {
|
|
return(rc);
|
|
}
|
|
|
|
rc = GenInfWriteString(Context,Context->InifilesFile,L"\"\r\n",AddQuotesNone);
|
|
if(rc == NO_ERROR) {
|
|
rc = FlushGenInfLineBuf(Context,Context->InifilesFile);
|
|
}
|
|
return(rc);
|
|
}
|
|
}
|
|
|
|
//
|
|
// If OldKey is not specified, then this is an addition or change
|
|
// of some sort. Note that one of NewKey or NewValue is specified
|
|
// or we wouldn't be here.
|
|
//
|
|
if(!OldKey) {
|
|
//
|
|
// There has to be at least a new value.
|
|
//
|
|
MYASSERT(New || NewValue);
|
|
if(New || NewValue) {
|
|
|
|
if(New) {
|
|
|
|
rc = GenInfWriteString(Context,Context->InifilesFile,New,AddQuotesNormal);
|
|
|
|
} else {
|
|
|
|
rc = GenInfWriteString(Context,Context->InifilesFile,L",\"",AddQuotesNone);
|
|
if(rc != NO_ERROR) {
|
|
return(rc);
|
|
}
|
|
|
|
if(NewKey) {
|
|
//
|
|
// Write key=
|
|
//
|
|
rc = GenInfWriteString(Context,Context->InifilesFile,NewKey,AddQuotesNoOpenOrClose);
|
|
if(rc != NO_ERROR) {
|
|
return(rc);
|
|
}
|
|
rc = GenInfWriteChar(Context,Context->InifilesFile,L'=');
|
|
if(rc != NO_ERROR) {
|
|
return(rc);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Write value
|
|
//
|
|
rc = GenInfWriteString(Context,Context->InifilesFile,NewValue,AddQuotesNoOpenOrClose);
|
|
if(rc != NO_ERROR) {
|
|
return(rc);
|
|
}
|
|
|
|
rc = GenInfWriteChar(Context,Context->InifilesFile,L'\"');
|
|
}
|
|
|
|
if(rc != NO_ERROR) {
|
|
return(rc);
|
|
}
|
|
|
|
//
|
|
// Terminate line
|
|
//
|
|
rc = GenInfWriteString(Context,Context->InifilesFile,L"\r\n",AddQuotesNone);
|
|
if(rc == NO_ERROR) {
|
|
rc = FlushGenInfLineBuf(Context,Context->InifilesFile);
|
|
}
|
|
return(rc);
|
|
}
|
|
}
|
|
|
|
//
|
|
// We shouldn't get here.
|
|
//
|
|
MYASSERT(FALSE);
|
|
return(ERROR_INVALID_DATA);
|
|
}
|