windows-nt/Source/XPSP1/NT/sdktools/packer/packer.c
2020-09-26 16:20:57 +08:00

484 lines
13 KiB
C

/* ************************************************************ *
*
* 'Packer.C
*
* Packer.C is a tool that packages the structure and data within
* a given directory into two C header files. Currently this tool
* is specific for the WorkGroup PostOffice. If there is some
* interest in making this tool more general, I would be happy
* to make it so, time permitting.
*
* ************************************************************ */
#include <windows.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#pragma pack(1)
/* ************************************************************ *
*
* Constants and definitions
*
* ************************************************************ */
#define rgbMaxBuffer 16 * 1024
#define crgMaxFile 256
#define cchMaxFile 64
#define szCR "\n"
typedef int FO;
#define FO_Open 101
#define FO_Write 102
#define FO_Close 103
/* ************************************************************ *
*
* Function prototypes
*
* ************************************************************ */
int EcTravelDir(char *);
int EcFileInfo(FO, char *);
int EcFileData(FO, char *);
/* ************************************************************ *
*
* Global variables
*
* ************************************************************ */
// Store file info
char rgszFile[crgMaxFile][cchMaxFile];
int rgFileState[crgMaxFile];
// Store file data
unsigned char rgbBuffer[rgbMaxBuffer];
/* ************************************************************ *
*
* void 'Main
*
* In: int cArg Count of arguments
* In: char *rgszArg[] Argument string array
*
* Main returns void.
*
* Main checks if the command-line arguments are valid.
* If so, it calls EcTravelDir to pack the given directory.
*
* Main causes no side-effects.
*
* Main indicates any error with a message to stdout.
*
* ************************************************************ */
void
__cdecl
main(
int cArg,
char *rgszArg[]
)
{
int ec = 0;
// Check count of command-line arguments
if (cArg != 2) {
printf("USAGE: packer [directory]\n");
exit(EXIT_FAILURE);
}
if (EcTravelDir(rgszArg[1]) != 0)
exit(EXIT_FAILURE);
exit(EXIT_SUCCESS);
}
/* ************************************************************ *
*
* int 'EcTravelDir
*
* In: char *szTravelDir Directory to pack
*
* EcTravelDir returns a standard exit code.
*
* EcTravelDir packages the directory structure and all files
* within the given directory into two C header files. The
* directory tree is travelled in a current node, "low" branch,
* "high" branch pattern. This means the files and sub-directories
* of the current directory are enumerated and saved, then the
* sub-directories are traversed from the lowest to the highest
* as they appear in the directory list. Directory structure
* info is handled by EcFileInfo while file data is handled by
* EcFileData.
*
* EcTravelDir causes a disk side-effect.
*
* EcTravelDir indicates any error via the exit code.
*
* ************************************************************ */
int
EcTravelDir(
char *szTravelDir
)
{
int ec = 0;
int iFile = 0;
int iFileParent;
char szFile[cchMaxFile] = "";
char szDir[cchMaxFile] = "";
char szDrive[_MAX_DRIVE] = "";
char szPath[_MAX_DIR] = "";
char szFileName[_MAX_FNAME] = "";
char szFileExt[_MAX_EXT] = "";
int ixType;
long lcbxFile;
char szxFile[cchMaxFile];
unsigned short us;
HANDLE hdir;
WIN32_FIND_DATA findbuf;
_splitpath(szTravelDir, szDrive, szPath, szFileName, szFileExt);
_makepath(szDir, "", szPath, szFileName, szFileExt);
if (szDir[strlen(szDir)-1] != '\\')
strcat(szDir, "\\");
// *** Open header files ***
ec = EcFileInfo(FO_Open, "_fileinf.h");
if (ec != 0)
goto RET;
ec = EcFileData(FO_Open, "_filedat.h");
if (ec != 0)
goto RET;
// *** Traverse directory tree ***
// Initial directory
strcpy(rgszFile[0], "");
rgFileState[0] = '\0';
while (1) {
if (rgFileState[iFile] == 0) {
// Keep track of parent directory
rgFileState[iFile] = 1;
iFileParent = iFile;
// Prepare szFile and hdir
strcpy(szFile, szDrive);
strcat(szFile, szDir);
strcat(szFile, rgszFile[iFile]);
strcat(szFile, "*.*");
// Skip . entry
hdir = FindFirstFile(szFile, &findbuf);
if (hdir == INVALID_HANDLE_VALUE) {
ec = 1;
goto CLOSE;
}
// Skip .. entry
//FindNextFile(hdir, &findbuf);
// *** Enumerate current directory ***
while (1) {
if(!FindNextFile(hdir, &findbuf) &&
GetLastError() == ERROR_NO_MORE_FILES)
break;
//
// Skip over any file that begins with '.'.
//
if (findbuf.cFileName[0] == '.')
continue;
//
// Skip over hidden and system files.
//
if (findbuf.dwFileAttributes & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM))
continue;
// *** Set file info data ***
if (findbuf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
iFile += 1;
strcpy(rgszFile[iFile], rgszFile[iFileParent]);
strcat(rgszFile[iFile], findbuf.cFileName);
strcat(rgszFile[iFile], "\\");
rgFileState[iFile] = 0;
ixType = 0;
lcbxFile = 0;
strcpy(szxFile, rgszFile[iFile]);
} else {
ixType = 1;
lcbxFile = findbuf.nFileSizeLow;
strcpy(szxFile, rgszFile[iFileParent]);
strcat(szxFile, findbuf.cFileName);
}
// *** Write file info ***
sprintf(szFile, "%d, %4ld, \"%s\"," szCR,
ixType, lcbxFile, szxFile);
ec = EcFileInfo(FO_Write, szFile);
if (ec != 0)
goto CLOSE;
if (lcbxFile == 0)
continue;
// *** Write file data ***
strcpy(szFile, szDrive);
strcat(szFile, szDir);
strcat(szFile, szxFile);
ec = EcFileData(FO_Write, szFile);
if (ec != 0)
goto CLOSE;
}
} else {
iFile -= 1;
}
if (iFile == 0)
break;
}
CLOSE:
EcFileInfo(FO_Close, "");
EcFileData(FO_Close, "");
RET:
if (ec != 0) {
printf("ERROR: Disk error %d\n", ec);
remove("_fileinf.h");
remove("_filedat.h");
}
return ec;
}
/* ************************************************************ *
*
* int 'EcFileInfo
*
* In: FO foType File operation
* In: char *szFileInfo File name or data string
*
* EcFileInfo returns a standard exit code.
*
* EcFileInfo opens, writes, and closes the directory structure
* header file. The info is saved in an array of type HDR.
* The array is rghdrFile and the constant chdrFile counts the
* number of elements in the array.
*
* EcFileInfo causes a disk side-effect.
*
* EcFileInfo indicates any error via the exit code.
*
* ************************************************************ */
int
EcFileInfo(
FO foType,
char *szFileInfo
)
{
int ec = 0, dos;
char szT[cchMaxFile] = "";
int iszT;
static FILE *hfFileInfo;
static int chdrFileInfo;
unsigned iszFileInfo;
switch (foType) {
case FO_Open:
// Open szFileInfo file
hfFileInfo = fopen(szFileInfo, "wt");
if (hfFileInfo == NULL) {
printf("ERROR: Can't open %s\n", szFileInfo);
exit(EXIT_FAILURE);
}
// Open rghdrFile declaration and set chdFileInfo to 0
fprintf(hfFileInfo, szCR);
fprintf(hfFileInfo, "static CSRG(HDR) rghdrFile[] =" szCR);
fprintf(hfFileInfo, "{" szCR);
chdrFileInfo = 0;
break;
case FO_Write:
// Double every backlash in szFileInfo
for (iszFileInfo = 0, iszT = 0; iszFileInfo < strlen(szFileInfo);
iszFileInfo += 1)
{
szT[iszT++] = szFileInfo[iszFileInfo];
if (szFileInfo[iszFileInfo] == '\\') szT[iszT++] = '\\';
}
szT[iszT] = '\0';
// Write file info
fwrite(szT, sizeof(char), iszT, hfFileInfo);
chdrFileInfo += 1;
break;
case FO_Close:
// Close rghdrFile definition and set chdrFile
fprintf(hfFileInfo, szCR);
fprintf(hfFileInfo, "// END" szCR);
fprintf(hfFileInfo, szCR);
fprintf(hfFileInfo, "0, 0, \"\"" szCR);
fprintf(hfFileInfo, szCR);
fprintf(hfFileInfo, "}; // rghdrFile" szCR);
fprintf(hfFileInfo, szCR);
fprintf(hfFileInfo, "#define chdrFile %d" szCR, chdrFileInfo);
fprintf(hfFileInfo, szCR);
// Close szFileInfo
dos = fclose(hfFileInfo);
assert(dos == 0);
break;
default:
printf("ERROR: Unknown EcFileInfo foType %d\n", foType);
break;
}
return ec;
}
/* ************************************************************ *
*
* int 'EcFileData
*
* In: FO foType File operation
* In: char *szFileData File name or data string
*
* EcFileData returns a standard exit code.
*
* EcFileData opens, writes, and closes the file data header
* file. The file data is saved in an array of char (bytes).
* The array is named rgbFile and the constant cbFile counts
* the number of elements in the array.
*
* EcFileData causes a disk side-effect.
*
* EcFileData indicates any error via the exit code.
*
* ************************************************************ */
int
EcFileData(
FO foType,
char *szFileData
)
{
int ec = 0, dos;
int fContinue;
static FILE *hfFileData;
static int cbFileData;
FILE *hfSourceFile;
long lcbRead;
long ibBuffer, ibOffset, cbOffset;
switch (foType) {
case FO_Open:
// Open szFileData file
hfFileData = fopen(szFileData, "wt");
if (hfFileData == NULL) {
printf("ERROR: Can't open %s\n", szFileData);
exit(EXIT_FAILURE);
}
// Write rgbFile declaration and set cbFiledata to 0
fprintf(hfFileData, szCR);
fprintf(hfFileData, "static CSRG(unsigned char) rgbFile[] =" szCR);
fprintf(hfFileData, "{" szCR);
cbFileData = 0;
break;
case FO_Write:
// Open source file
hfSourceFile = fopen(szFileData, "rb");
if (!hfSourceFile) {
break;
}
fprintf(hfFileData, szCR);
fprintf(hfFileData, "// %s" szCR, szFileData);
fprintf(hfFileData, szCR);
// Write file data
fContinue = 1;
while (fContinue == 1) {
// Read source file
lcbRead = fread(rgbBuffer, sizeof(char),
rgbMaxBuffer, hfSourceFile);
assert(ferror(hfSourceFile) == 0);
if (feof(hfSourceFile) != 0) fContinue = 0;
// Write target file
for (ibBuffer = 0; ibBuffer < lcbRead; ibBuffer += 16) {
cbOffset = min((long) 16, lcbRead-ibBuffer);
for (ibOffset = 0; ibOffset < cbOffset; ibOffset += 1) {
fprintf(hfFileData, "%3u, ",
rgbBuffer[ibBuffer+ibOffset]);
cbFileData += 1;
}
fprintf(hfFileData, szCR);
}
}
// Close source file
dos = fclose(hfSourceFile);
assert(dos == 0);
break;
case FO_Close:
// Close rgbFile definition and set cbFile
fprintf(hfFileData, szCR);
fprintf(hfFileData, "// END" szCR);
fprintf(hfFileData, szCR);
fprintf(hfFileData, "000" szCR);
fprintf(hfFileData, szCR);
fprintf(hfFileData, "}; // rgbFile" szCR);
fprintf(hfFileData, szCR);
fprintf(hfFileData, "#define cbFile %d" szCR, cbFileData);
fprintf(hfFileData, szCR);
// Close szFileData
dos = fclose(hfFileData);
assert(dos == 0);
break;
default:
printf("ERROR: Unknown EcFileData foType %d\n", foType);
break;
}
return ec;
}