/* ************************************************************ * * * '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 #include #include #include #include #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; }