|
|
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include "stampinf.h"
DRIVER_VER_DATA dvdata; BOOLEAN HaveDate = FALSE; BOOLEAN HaveVersion = FALSE;
int _cdecl main (int argc, char **argv) {
char *StampInfEnv; //
// Zero out our main data structure
//
ZeroMemory (&dvdata, sizeof (DRIVER_VER_DATA));
//
// Process and validate the arguments
//
lstrcpy (dvdata.SectionName, "Version");
if (StampInfEnv = getenv("STAMPINF_DATE")) { if (ValidateDate (StampInfEnv)) { lstrcpy (dvdata.DateString, StampInfEnv); HaveDate = TRUE; } else printf ("Date error\n"); }
if (StampInfEnv = getenv("STAMPINF_VERSION")) { lstrcpyn (dvdata.VersionString, StampInfEnv, 20); HaveVersion = TRUE; }
if (!GetArgs (argc, argv)) { DisplayHelp (); return 1; }
//
// Write the DriverVer key to the inf
//
if (!StampInf ()) { printf ("Error writing to inf!\n"); return 1; }
return 0; }
BOOLEAN GetArgs (int argc, char **argv) { int args; char *arg; ARGTYPE argtype = ArgSwitch;
//
// Loop through the arguments, the filename is required
// but version and date are optional.
//
for (args = 1; args < argc; args++) {
arg = argv[args];
//
// switch based on the type of argument
// we are expecting.
//
switch (argtype) { case ArgSwitch:
//
// better be a switch prefix
//
if (*arg != '-') return FALSE; else arg++;
switch (toupper(*arg)) {
case 'F': argtype = ArgFileName; break;
case 'D': argtype = ArgDate; break;
case 'V': argtype = ArgVersion; break;
case 'S': argtype = ArgSection; break;
default: printf ("Invalid argument %s\n", arg); } break;
case ArgFileName:
//
// See if the provided filename includes any
// path separators. If it doesn't prepend .\ // because the WritePrivateProfile api
// defaults to the Windows dir unless
// you specify a path.
//
if (strchr (arg, '\\') == NULL) { lstrcpy (dvdata.InfName, ".\\"); }
//
// concatenate the actual file name
//
lstrcat (dvdata.InfName, arg); argtype = ArgSwitch; break;
case ArgDate:
//
// If the user specified a date, do some basic validation.
//
if (ValidateDate (arg)) { lstrcpy (dvdata.DateString, arg); HaveDate = TRUE; } else printf ("Date error\n"); argtype = ArgSwitch;
break;
case ArgVersion:
//
// If the user specified a version override, use it.
//
lstrcpyn (dvdata.VersionString, arg, 20); argtype = ArgSwitch; HaveVersion = TRUE; break;
case ArgSection:
lstrcpyn (dvdata.SectionName, arg, 64); argtype = ArgSwitch; break; } }
if (!HaveDate) {
//
// Get the date in xx/yy/zzzz format.
//
GetDateFormat (LOCALE_SYSTEM_DEFAULT, 0, NULL, "MM'/'dd'/'yyyy", dvdata.DateString, 11); }
if (!HaveVersion) {
//
// If the user didn't provide a version override, then open and read
// ntverp.h and figure out what the version stamp should be.
//
if (!ProcessNtVerP (dvdata.VersionString)) { return FALSE; } }
//
// Must have a name.
//
return (dvdata.InfName[0] != '\0'); }
BOOLEAN ValidateDate (char *datestring) { ULONG Month, Day, Year;
if (lstrlen (datestring) != 10) return FALSE;
Month = atoi(&datestring[0]);
if (Month < 1 || Month > 12) return FALSE;
Day = atoi (&datestring[3]);
if (Day < 1 || Day > 31) return FALSE;
Year = atoi (&datestring[6]);
if (Year < 1980 || Year > 2099) return FALSE;
return TRUE; }
ULONG GetLengthOfLine (WCHAR *Pos, WCHAR *LastChar) { ULONG Length=0;
if (Pos == NULL) return 0;
while ( (Pos < LastChar) && (*Pos != 0x00D) ) { Pos++; Length++; }
if (Pos < LastChar) Length+=2;
return Length; }
WCHAR *GetNextLine (WCHAR *CurPos, WCHAR *LastChar) { LastChar--;
for (;CurPos < LastChar;CurPos++) { if ( (CurPos[0] == 0x00D) && (CurPos[1] == 0x00A) ) break; }
return ( (&(CurPos[2]) <= LastChar) ? &(CurPos[2]) : NULL ); }
BOOLEAN DoesLineMatch (WCHAR *Target, WCHAR *Sample, WCHAR *LastChar) { USHORT LineLength = 0; WCHAR *Pos = Sample; WCHAR *buffer; BOOLEAN result; ULONG TargetLength;
if (Pos == NULL) return FALSE;
while ( (Pos <= LastChar) && (*Pos != 0x00D) ) { LineLength++; Pos++; }
TargetLength = lstrlenW (Target);
if (TargetLength > LineLength) { return FALSE; }
return (BOOLEAN)(!memcmp (Target, Sample, TargetLength)); }
USHORT FindEntry (WCHAR *FileStart, WCHAR *FileEnd, WCHAR *SectionNameW, WCHAR **Entry) { WCHAR *FilePos=FileStart; WCHAR FixedSectionNameW[64+2]; BOOLEAN FoundMatch = FALSE; ULONG iter = 0;
wsprintfW (FixedSectionNameW, L"[%s]", SectionNameW);
for (FilePos = FileStart; FilePos; FilePos = GetNextLine (FilePos, FileEnd)) {
if (DoesLineMatch (FixedSectionNameW, FilePos, FileEnd)) { FoundMatch = TRUE; break; } }
if (FoundMatch) {
FoundMatch = FALSE;
while ( ((FilePos = GetNextLine (FilePos, FileEnd)) != NULL) && (*FilePos != L'[') ) {
if (DoesLineMatch (L"DriverVer", FilePos, FileEnd)) { FoundMatch = TRUE; break; } } if (FoundMatch) { *Entry = FilePos; return FOUND_ENTRY; } if (FilePos) { *Entry = FilePos; return FOUND_SECTION; } }
*Entry = NULL; return FOUND_NOTHING; }
UINT UniWPPS (char *SectionName, char *Stamp, char *InfName) { WCHAR SectionNameW [64]; WCHAR *NextLinePtr; WCHAR NewEntryW [64]; WCHAR StampW [32]; WCHAR InfNameW [MAX_PATH]; HANDLE hFile, hMapping; WCHAR *MappedBuffer; ULONG filesize; WCHAR *LastChar; WCHAR *Entry = NULL; ULONG result; ULONG StampLength; ULONG numwritten; ULONG deleted;
MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, SectionName, (int)-1, SectionNameW, 64);
MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, Stamp, (int)-1, StampW, 32);
MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, InfName, (int)-1, InfNameW, MAX_PATH);
StampLength = lstrlenW (StampW);
hFile = CreateFile (InfName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if (hFile == INVALID_HANDLE_VALUE) { printf ("Create file failed!\n"); return 0; }
filesize = GetFileSize (hFile, NULL);
hMapping = CreateFileMapping (hFile, NULL, PAGE_READWRITE, 0, filesize+128, NULL);
if (!hMapping) { printf ("Map file failed!\n"); CloseHandle (hFile); return 0; }
MappedBuffer = MapViewOfFile (hMapping, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (!MappedBuffer) { printf ("MapView Failed!\n"); CloseHandle (hMapping); CloseHandle (hFile); return 0; }
LastChar = (WCHAR *)((ULONG_PTR)MappedBuffer+filesize-sizeof(WCHAR));
result = FindEntry (MappedBuffer, LastChar, SectionNameW, &Entry);
wsprintfW (NewEntryW, L"DriverVer=%s\r\n",StampW); StampLength = lstrlenW (NewEntryW);
switch (result) {
case FOUND_SECTION:
MoveMemory ((WCHAR *)((ULONG_PTR)Entry+(StampLength*sizeof(WCHAR))), Entry, (ULONG_PTR)LastChar-(ULONG_PTR)Entry+sizeof(WCHAR)); CopyMemory (Entry, NewEntryW, StampLength*sizeof(WCHAR)); UnmapViewOfFile (MappedBuffer); CloseHandle (hMapping); SetFilePointer (hFile, filesize+StampLength*sizeof(WCHAR), NULL, FILE_BEGIN); SetEndOfFile (hFile); break;
case FOUND_ENTRY:
deleted = GetLengthOfLine (Entry, LastChar); deleted *=sizeof(WCHAR); NextLinePtr = GetNextLine (Entry, LastChar); MoveMemory ((WCHAR *)((ULONG_PTR)Entry+(StampLength*sizeof(WCHAR))), NextLinePtr, (ULONG_PTR)LastChar-(ULONG_PTR)NextLinePtr+sizeof(WCHAR)); CopyMemory (Entry, NewEntryW, StampLength*sizeof(WCHAR)); UnmapViewOfFile (MappedBuffer); CloseHandle (hMapping); SetFilePointer (hFile, filesize+StampLength*sizeof(WCHAR)-deleted, NULL, FILE_BEGIN); SetEndOfFile (hFile); break;
case FOUND_NOTHING:
UnmapViewOfFile (MappedBuffer); CloseHandle (hMapping); SetFilePointer (hFile, filesize, NULL, FILE_BEGIN); SetEndOfFile (hFile); break; }
CloseHandle (hFile); return 1; }
BOOLEAN IsInfUnicode (VOID) { HANDLE hFile, hMapping; char *MappedBuffer; ULONG filesize; BOOLEAN unicode = FALSE;
hFile = CreateFile (dvdata.InfName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if (hFile == INVALID_HANDLE_VALUE) { printf ("Create file failed!\n"); return FALSE; }
hMapping = CreateFileMapping (hFile, NULL, PAGE_READONLY, 0, 0, NULL);
if (!hMapping) { printf ("Map file failed!\n"); CloseHandle (hFile); return FALSE; }
MappedBuffer = MapViewOfFile (hMapping, FILE_MAP_READ, 0, 0, 0);
if (!MappedBuffer) { printf ("MapView Failed!\n"); CloseHandle (hMapping); CloseHandle (hFile); return FALSE; }
filesize = GetFileSize (hFile, NULL);
if (filesize < sizeof (WCHAR)) return 0;
if ( *((WCHAR *)MappedBuffer) == 0xFEFF ) { unicode = TRUE; } if ( IsTextUnicode (MappedBuffer, filesize, NULL) ) { unicode = TRUE; }
UnmapViewOfFile (MappedBuffer); CloseHandle (hMapping); CloseHandle (hFile);
return unicode; }
BOOLEAN StampInf (VOID) {
char DateVerStamp[32];
wsprintf (DateVerStamp, "%s,%s",dvdata.DateString,dvdata.VersionString);
printf ("Stamping %s [%s] section with DriverVer=%s\n",dvdata.InfName, dvdata.SectionName, DateVerStamp);
//
// Let WritePrivateProfile do all of our work!
//
if (IsInfUnicode()) {
printf ("Unicode Inf Detected\n");
if (UniWPPS (dvdata.SectionName, DateVerStamp, dvdata.InfName) == 0) { printf ("Error\n"); return FALSE; }
} else {
if (WritePrivateProfileString (dvdata.SectionName, "DriverVer", DateVerStamp, dvdata.InfName) == 0) { printf ("Error\n"); return FALSE; } }
return TRUE;
}
VOID DisplayHelp (VOID) { printf ("\tUSAGE:\n"); printf ("\tstampinf -f filename [-s section] [-d xx/yy/zzzz] [-v w.x.y.z]\n"); }
DWORD NextInterestingCharacter (DWORD CurFilePos, DWORD Size, char *MappedBuffer) { char thischar; DWORD NewPos;
//
// Find the next character that is not whitespace, EOL, or within a comment block.
// Return the offset into the buffer for that character, or Size if there is no
// such character.
//
while (CurFilePos < Size) {
thischar = MappedBuffer[CurFilePos];
if ( (thischar == 0x0A) || (thischar == 0x0D) || (thischar == ' ') ) { CurFilePos++; continue; }
if (CurFilePos == Size-1) break; if ( (thischar == '/') && (MappedBuffer[CurFilePos+1] == '*') ) {
//
// Skip past the comment char's and search for the end of the comment block
//
NewPos = CurFilePos+2; while (NewPos < (Size-1)) {
if ( (MappedBuffer[NewPos] == '*') && (MappedBuffer[NewPos+1] == '/') ) {
CurFilePos = NewPos+1; break; } NewPos++; } } else if ( (thischar == '/') && (MappedBuffer[CurFilePos+1] == '/') ) {
// Search for newline or EOF
CurFilePos += 2; while (CurFilePos < (Size-1)) { if ( (MappedBuffer[CurFilePos] == 0x0A) || (MappedBuffer[CurFilePos] == 0x0D)) { break; } CurFilePos++; } } else { break; } CurFilePos++; }
return CurFilePos; }
DWORD FindLengthOfInterestingCharacters (DWORD CurFilePos, DWORD Size, char *MappedBuffer) { DWORD Pos = CurFilePos; char thischar;
//
// Find the length of a string. Return the length.
//
while (Pos < Size) {
thischar = MappedBuffer[Pos];
if ( (thischar == 0x0A) || (thischar == 0x0D) || (thischar == ' ') || (thischar == '/') ) { return (Pos-CurFilePos); }
Pos++;
} printf ("How did we get here?\n"); return 0; }
BOOLEAN ProcessNtVerP (char *VersionString) { HANDLE hFile, hMapping; char *MappedBuffer, *location; DWORD pos; DWORD qfelen,buildlen,majorverlen,minorverlen; char qfe[5]={'0','0','0','0',0}; char build[5]={'0','0','0','0',0}; char majorversion[5]={'0','0','0','0',0}; char minorversion[5]={'0','0','0','0',0}; DWORD filesize; char *p; TCHAR ntroot[MAX_PATH];
if ( GetEnvironmentVariable ("_NTDRIVE", ntroot, 3) == 0 ) { printf ("Unable to evaluate _NTDRIVE!\n"); return FALSE; }
if ( GetEnvironmentVariable ("_NTROOT", &(ntroot[2]), MAX_PATH-2) == 0 ) { printf ("Unable to evaluate _NTROOT!\n"); return FALSE; }
lstrcat (ntroot, "\\public\\sdk\\inc\\ntverp.h");
printf ("Using version information from %s\n",ntroot);
//
// Create a memory mapped image of ntverp.h
//
hFile = CreateFile (ntroot, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if (hFile == INVALID_HANDLE_VALUE) { printf ("Create file failed!\n"); return FALSE; }
filesize = GetFileSize (hFile, NULL); hMapping = CreateFileMapping (hFile, NULL, PAGE_READONLY, 0, 0, NULL);
if (!hMapping) { printf ("Map file failed!\n"); CloseHandle (hFile); return FALSE; }
MappedBuffer = MapViewOfFile (hMapping, FILE_MAP_READ, 0, 0, 0);
if (!MappedBuffer) { printf ("MapView Failed!\n"); CloseHandle (hMapping); CloseHandle (hFile); return FALSE; }
//
// The version is made up of a.b.c.d where a.b is the Product Version.
// c is the Build and d is the QFE level. (e.g. 5.0.1922.1)
//
location = strstr (MappedBuffer, "#define VER_PRODUCTMAJORVERSION "); pos = NextInterestingCharacter ((DWORD)(location-MappedBuffer+32), filesize, MappedBuffer); majorverlen = FindLengthOfInterestingCharacters (pos, filesize, MappedBuffer); lstrcpyn (majorversion, &(MappedBuffer[pos]), majorverlen+1);
location = strstr (MappedBuffer, "#define VER_PRODUCTMINORVERSION "); pos = NextInterestingCharacter ((DWORD)(location-MappedBuffer+32), filesize, MappedBuffer); minorverlen = FindLengthOfInterestingCharacters (pos, filesize, MappedBuffer); lstrcpyn (minorversion, &(MappedBuffer[pos]), minorverlen+1);
location = strstr (MappedBuffer, "#define VER_PRODUCTBUILD "); pos = NextInterestingCharacter ((DWORD)(location-MappedBuffer+25), filesize, MappedBuffer); buildlen = FindLengthOfInterestingCharacters (pos, filesize, MappedBuffer); lstrcpyn (build, &(MappedBuffer[pos]), buildlen+1);
location = strstr (MappedBuffer, "#define VER_PRODUCTBUILD_QFE "); pos = NextInterestingCharacter ((DWORD)(location-MappedBuffer+29), filesize, MappedBuffer); qfelen = FindLengthOfInterestingCharacters (pos, filesize, MappedBuffer); lstrcpyn (qfe, &(MappedBuffer[pos]), qfelen+1);
wsprintf (VersionString, "%s.%s.%s.%s",majorversion, minorversion, build, qfe);
UnmapViewOfFile (MappedBuffer); CloseHandle (hMapping); CloseHandle (hFile);
return TRUE; }
|