windows-nt/Source/XPSP1/NT/base/ntsetup/opktools/lfn/textfile.c
2020-09-26 16:20:57 +08:00

488 lines
10 KiB
C

#include "lfn.h"
#pragma hdrstop
PMYTEXTFILE
ReadRenameFile(
IN PCWSTR DriveRootPath
);
BOOLEAN
FindSections(
IN PMYTEXTFILE TextFile
);
BOOLEAN
GetLine(
IN PWCHAR StartOfLine,
OUT PWSTR LineBuffer,
IN ULONG BufferSizeChars,
OUT PWCHAR *StartOfNextLine
);
int
__cdecl
ComparePaths(
const void *p1,
const void *p2
);
PMYTEXTFILE
LoadRenameFile(
IN PCWSTR DriveRootPath
)
{
PMYTEXTFILE TextFile;
BOOLEAN b;
//
// Read in the file.
//
if(TextFile = ReadRenameFile(DriveRootPath)) {
if(b = FindSections(TextFile)) {
return(TextFile);
}
UnloadRenameFile(&TextFile);
}
return(FALSE);
}
VOID
UnloadRenameFile(
IN OUT PMYTEXTFILE *TextFile
)
{
PMYTEXTFILE textFile;
ULONG u;
textFile = *TextFile;
*TextFile = NULL;
if(textFile->Sections) {
for(u=0; u<textFile->SectionCount; u++) {
FREE(textFile->Sections[u].Name);
}
FREE(textFile->Sections);
}
FREE(textFile);
}
PMYTEXTFILE
ReadRenameFile(
IN PCWSTR DriveRootPath
)
{
NTSTATUS Status;
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING UnicodeString;
IO_STATUS_BLOCK IoStatusBlock;
WCHAR FullPath[NTMAXPATH] = {0};
HANDLE Handle;
FILE_STANDARD_INFORMATION FileInfo;
PVOID Buffer;
PWCHAR UnicodeBuffer;
ULONG u;
PMYTEXTFILE p = NULL;
ULONG CharCount;
wcsncpy(FullPath,DriveRootPath,sizeof(FullPath)/sizeof(FullPath[0]) - 1);
ConcatenatePaths(FullPath,WINNT_OEM_LFNLIST_W,NTMAXPATH);
//
// Open the file.
//
INIT_OBJA(&ObjectAttributes,&UnicodeString,FullPath);
Status = NtCreateFile(
&Handle,
FILE_READ_DATA | FILE_READ_ATTRIBUTES | SYNCHRONIZE,
&ObjectAttributes,
&IoStatusBlock,
NULL,
0,
FILE_SHARE_READ,
FILE_OPEN,
FILE_SYNCHRONOUS_IO_ALERT | FILE_NON_DIRECTORY_FILE,
NULL,
0
);
if(!NT_SUCCESS(Status)) {
KdPrint(("LFN: Unable to open %ws (%x)\n",FullPath,Status));
goto c0;
}
//
// Determine the size of the file.
//
Status = NtQueryInformationFile(
Handle,
&IoStatusBlock,
&FileInfo,
sizeof(FileInfo),
FileStandardInformation
);
if(!NT_SUCCESS(Status)) {
KdPrint(("LFN: Unable to determine size of %ws (%x)\n",FullPath,Status));
goto c1;
}
//
// Allocate a chunk of memory and read the file in.
//
Buffer = MALLOC(FileInfo.EndOfFile.LowPart);
if(!Buffer) {
KdPrint(("LFN: malloc failed\n"));
goto c1;
}
Status = NtReadFile(
Handle,
NULL,
NULL,
NULL,
&IoStatusBlock,
Buffer,
FileInfo.EndOfFile.LowPart,
NULL,
NULL
);
if(!NT_SUCCESS(Status)) {
KdPrint((
"LFN: Unable to read %u bytes from file %ws (%x)\n",
FileInfo.EndOfFile.LowPart,
FullPath,
Status
));
goto c2;
}
//
// Allocate a buffer for unicode conversion.
// Leave room for a terminating NUL.
//
UnicodeBuffer = MALLOC((FileInfo.EndOfFile.LowPart+1)*sizeof(WCHAR));
if(!UnicodeBuffer) {
KdPrint(("LFN: malloc failed\n"));
goto c2;
}
//
// Convert to unicode.
//
Status = RtlOemToUnicodeN(
UnicodeBuffer,
FileInfo.EndOfFile.LowPart*sizeof(WCHAR),
&CharCount,
Buffer,
FileInfo.EndOfFile.LowPart
);
if(!NT_SUCCESS(Status)) {
KdPrint(("LFN: Unable to convert file data to unicode (%x)\n",Status));
goto c3;
}
CharCount /= sizeof(WCHAR);
//
// Nul-terminate the buffer and change instances of CR and control-z
// to spaces. Also make sure there are no 0 chars in the buffer.
//
for(u=0; u<CharCount; u++) {
if((UnicodeBuffer[u] == 26) || (UnicodeBuffer[u] == L'\r') || !UnicodeBuffer[u]) {
UnicodeBuffer[u] = L' ';
}
}
//
// Allocate a text file structure.
//
p = MALLOC(sizeof(MYTEXTFILE));
if(!p) {
KdPrint(("LFN: malloc failed\n"));
goto c3;
}
RtlZeroMemory(p,sizeof(MYTEXTFILE));
p->Text = UnicodeBuffer;
UnicodeBuffer[CharCount] = 0;
c3:
if(!NT_SUCCESS(Status)) {
FREE(UnicodeBuffer);
}
c2:
FREE(Buffer);
c1:
NtClose(Handle);
c0:
return(NT_SUCCESS(Status) ? p : NULL);
}
BOOLEAN
FindSections(
IN PMYTEXTFILE TextFile
)
{
PWCHAR p,n;
WCHAR Line[2*NTMAXPATH];
PWCHAR e;
PVOID NewArray;
PWCHAR s;
PWSTR SectionName;
for(p=TextFile->Text; GetLine(p,Line,sizeof(Line)/sizeof(WCHAR),&n); p=n) {
//
// If this is a section save it away in a table of section names.
//
if(Line[0] == L'[') {
s = Line+1;
while((*s == L' ') || (*s == L'\t')) {
s++;
}
if(*s == L'\\') {
s++;
}
//
// Find the end, which is either the ] or a nul.
// Strip off trailing spaces.
//
if(e = wcschr(s,L']')) {
*e = 0;
} else {
e = wcschr(s,0);
}
while((*(e-1) == L' ') || (*(e-1) == L'\t')) {
e--;
*e = 0;
}
if(SectionName = MALLOC((wcslen(s)+1)*sizeof(WCHAR))) {
wcscpy(SectionName,s);
if(TextFile->SectionCount == TextFile->SectionArraySize) {
if(TextFile->SectionCount) {
NewArray = REALLOC(TextFile->Sections,(TextFile->SectionCount+10)*sizeof(MYSECTION));
} else {
NewArray = MALLOC(10*sizeof(MYSECTION));
}
if(NewArray) {
TextFile->Sections = NewArray;
TextFile->SectionArraySize += 10;
} else {
FREE(SectionName);
KdPrint(("LFN: malloc failed\n"));
return(FALSE);
}
}
TextFile->Sections[TextFile->SectionCount].Name = SectionName;
TextFile->Sections[TextFile->SectionCount].Data = n;
TextFile->SectionCount++;
} else {
KdPrint(("LFN: malloc failed\n"));
return(FALSE);
}
}
}
//
// Now sort the sections by name.
//
qsort(TextFile->Sections,TextFile->SectionCount,sizeof(MYSECTION),ComparePaths);
return(TRUE);
}
BOOLEAN
GetLineInSection(
IN PWCHAR StartOfLine,
OUT PWSTR LineBuffer,
IN ULONG BufferSizeChars,
OUT PWCHAR *StartOfNextLine
)
{
//
// Get the line and check if we've reached the end of the section.
//
if(!GetLine(StartOfLine,LineBuffer,BufferSizeChars,StartOfNextLine)
|| (LineBuffer[0] == L'[')) {
return(FALSE);
}
return(TRUE);
}
BOOLEAN
GetLine(
IN PWCHAR StartOfLine,
OUT PWSTR LineBuffer,
IN ULONG BufferSizeChars,
OUT PWCHAR *StartOfNextLine
)
{
PWCHAR LineEnd;
SIZE_T Count;
while(1) {
//
// Skip space chars.
//
while(*StartOfLine && ((*StartOfLine == L' ') || (*StartOfLine == L'\t'))) {
StartOfLine++;
}
if(*StartOfLine == 0) {
//
// Nothing left.
//
return(FALSE);
}
//
// Find the end of the line, which is either the newline or nul.
//
if(LineEnd = wcschr(StartOfLine,L'\n')) {
*StartOfNextLine = LineEnd+1;
} else {
LineEnd = wcschr(StartOfLine,0);
*StartOfNextLine = LineEnd;
}
//
// Ignore this line if it's a comment or empty.
// Otherwise return it.
//
if((*StartOfLine != L';') && (*StartOfLine != L' ')) {
Count = LineEnd - StartOfLine;
if(Count >= BufferSizeChars) {
Count = BufferSizeChars-1;
}
RtlCopyMemory(LineBuffer,StartOfLine,Count*sizeof(WCHAR));
LineBuffer[Count] = 0;
return(TRUE);
}
StartOfLine = *StartOfNextLine;
}
}
int
__cdecl
ComparePaths(
const void *p1,
const void *p2
)
{
unsigned u1,u2;
PWCHAR s1,s2;
//
// Count \'s in each. The one with fewer is 'greater'.
//
s1 = ((PMYSECTION)p1)->Name;
s2 = ((PMYSECTION)p2)->Name;
u1 = 0;
u2 = 0;
while(*s1) {
if(*s1 == L'\\') {
u1++;
}
s1++;
}
while(*s2) {
if(*s2 == L'\\') {
u2++;
}
s2++;
}
if(u1 == u2) {
return(0);
}
return((u1 < u2) ? 1 : -1);
}
BOOLEAN
ParseLine(
IN OUT PWSTR Line,
OUT PWSTR *LHS,
OUT PWSTR *RHS
)
{
PWCHAR p,q;
//
// We rely on the routines abive to have stripped out
// leading spaces.
//
*LHS = Line;
//
// Find the equals. The LHS isn't allowed to be quoted.
// Strip trailing space off the LHS.
//
p = wcschr(Line,L'=');
if(!p || (p == Line)) {
return(FALSE);
}
q = p+1;
*p-- = 0;
while((*p == L' ') || (*p == L'\t')) {
*p-- = 0;
}
while(*q && ((*q == L' ') || (*q == L'\t'))) {
q++;
}
if(*q == 0) {
return(FALSE);
}
if(*q == L'\"') {
q++;
}
*RHS = q;
p = q + wcslen(q);
p--;
while((*p == L' ') || (*p == L'\t')) {
*p-- = 0;
}
if(*p == L'\"') {
*p = 0;
}
return(TRUE);
}