Easy To Read Pak Writer (Code)
- Code:
// Pak file structure
// 1. Header (12 bytes. "PACK" followed by offset to directory info and the length of that directory info)
// 2. File bytes one after another
// 3. Directory (56 chars for name, offset from start of file, length of data)
typedef struct
{
char name[56];
int filepos, filelen;
} packfile_t;
typedef struct
{
char id[4];
int dirofs;
int dirlen;
} packheader_t;
int File_Length_ByHandle (FILE* fileToCheck)
{
int lengthOfFile;
fseek (fileToCheck, 0, SEEK_END); // Go to end
lengthOfFile = ftell(fileToCheck); // Read position, that is file length
fseek (fileToCheck, 0, SEEK_SET); // Set to start
return lengthOfFile;
}
int File_Append_BinaryFile (FILE* writeHandle, const char* fileToRead)
{
int bytesWritten = 0;
FILE* readHandle = fopen (fileToRead, "rb");
if (readHandle)
{
char buf[4096];
int bufsize = sizeof(buf);
int fileReadLength = File_Length_ByHandle (readHandle);
int remaining = fileReadLength;
printf ("Appending %i bytes from %s\n", fileReadLength, fileToRead);
//CreatePath (dest);
while (remaining)
{
int bytesThisPass = remaining < bufsize ? remaining : bufsize;
fread (buf, bytesThisPass, 1, readHandle); // Read 4096 bytes in (or less if near EOF)
fwrite (buf, bytesThisPass, 1, writeHandle); // Write 4096 bytes out
remaining -= bytesThisPass;
bytesWritten += bytesThisPass;
}
fclose (readHandle);
}
return bytesWritten;
}
int File_GetCursor (FILE* fileHandle)
{
int position = ftell (fileHandle);
return position;
}
void File_SetCursor_ToStart (FILE* fileHandle)
{
fseek (fileHandle, 0, SEEK_SET);
}
int PakFile_Create_From_List (char* outputPakName, text1024_t* listOfFiles, int numFiles)
{
int i;
packheader_t pakHeader;
packfile_t pakDirectory[4096];
int pakHeaderSize = sizeof(pakHeader);
int dataBytesWritten = 0, fileSize, markSpot;
FILE* pakHandle = fopen (outputPakName, "wb");
if (!pakHandle)
{
printf ("Error opening file for write '%s'\n", outputPakName);
return 0;
}
memset (&pakHeader, 0, sizeof(pakHeader));
memset (pakDirectory, 0, sizeof(pakDirectory));
// Write the header with invalid data. Don't worry we will be updating this later.
fwrite (&pakHeader, pakHeaderSize, 1, pakHandle);
// Write the files
for (i = 0; i < numFiles ; i ++)
{
char* curFile = listOfFiles[i].text;
markSpot = File_GetCursor (pakHandle); // LittleLong for Endian correctness
dataBytesWritten += (fileSize = File_Append_BinaryFile (pakHandle, curFile) ); // Get file size, increment dataBytes
pakDirectory[i].filepos = LittleLong (markSpot);
pakDirectory[i].filelen = LittleLong (fileSize);
StringLCopy (pakDirectory[i].name, String_SkipPath(curFile));
}
{
// Store the offset then write the directory. Data at pakDirectory with entry size of entry 0 times filecount
int direntSize = sizeof(pakDirectory[0]);
int directoryStart = File_GetCursor (pakHandle);
int directoryByteLength = direntSize * numFiles;
fwrite (pakDirectory, directoryByteLength, 1, pakHandle);
// Construct final header
pakHeader.id[0] = 'P';
pakHeader.id[1] = 'A';
pakHeader.id[2] = 'C';
pakHeader.id[3] = 'K';
pakHeader.dirofs = LittleLong (directoryStart);
pakHeader.dirlen = LittleLong (directoryByteLength);
// Go back to the beginning and rewrite the header
File_SetCursor_ToStart (pakHandle);
fwrite (&pakHeader, pakHeaderSize, 1, pakHandle);
}
// close the file
fclose (pakHandle);
return 1;
}
"Comparing files pak_x.pak and pakscape_pak_x.pak
FC: no differences encountered"
Entire little utility source (just 1 file):
http://quake-1.com/docs/utils/pakMake.c.txt
