Simple package file format and unpackager
by Nick \"ShotgunNinja\" Iannone · in Torque Game Engine · 07/31/2007 (4:23 pm) · 3 replies
LPF is a file format for a simple package file that I have come up with. It's short for Liberator Package File, which is based on the name of my game development group, Liberator Studios Ltd. I came up with the idea for a package file while writing my in-game download script, which can only send one file at a time. With a package file, I could send a self-extracting group of files all in one fell swoop, and by keeping it in ASCII instead of binary, I could allow the user to easily write or construct one either in-game or in a text editor.
In LPF, individual files are separated by declaration lines. These are either stand alone, or are followed by their value (in the next line of the file). For example:
In LPF, individual files are separated by declaration lines. These are either stand alone, or are followed by their value (in the next line of the file). For example:
About the author
Nick \"ShotgunNinja\" Iannone
And here is the decompiler code:
function UnpackPackFile(%pakfile) { %this = new FileObject(); if (%this.openForRead(%pakfile)) { Echo("Pakfile opened: " @ %pakfile @ "/nCreating Write Buffer..."); %writer = new FileObject(); while (!%this.IsEOF()) { %line = %this.readLine(); switch$(%line) { case ":: Drive ::": if (!%this.IsEOF()) { %drive = %this.readLine(); %writer.drive = ExpandEscape(%drive); Echo("Drive: " @ %writer.drive); } else { Warn("File ended prematurely! Canceling..."); return false; } case ":: Directory ::": if (!%this.IsEOF()) { %dir = %this.readLine(); %writer.dir = ExpandEscape(%dir); Echo("Directory: " @ %writer.dir); } else { Warn("File ended prematurely! Canceling..."); return false; } case ":: File ::": if (!%this.IsEOF()) { %file = %this.readLine(); %writer.file = ExpandEscape(%file); Echo("Extracting file: " @ %writer.file); if (!ExtractFile(%this, %writer, %pakfile)) { Warn("File extraction error! Canceling..."); return false; } } else { Warn("File ended prematurely. Canceling..."); return false; } case ":: Program Root Drive ::": %writer.drive = CollapseEscape(".//"); Echo("Resetting drive to program's root directory..."); case ":: Mod Path Drive ::": %writer.drive = CollapseEscape("~//"); Echo("Resetting drive to current mod path..."); case ":: End Package ::": Echo("Package complete."); %writer.isDone = true; default: %writer.blankLines++; } if (%writer.isDone) break; } Echo("Empty lines: " @ %writer.blankLines); Echo("Deleting Write Buffer..."); %writer.delete(); } else { Warn("Invalid pakfile. Canceling..."); return false; } %this.delete(); Echo("File unpacking complete."); return true; } function ExtractFile(%this, %writer, %pakfile) { %drive = CollapseEscape(%writer.drive); %dir = CollapseEscape(%writer.dir); %file = CollapseEscape(%writer.file); if (!IsWriteableFileName(%drive @ %dir @ %file)) { Warn("ERROR: Invalid output file name."); return false; } else %name = %drive @ %dir @ %file; %argline = %this.readLine(); if (%argline $= ":: Options ::" && (!%this.IsEOF())) { %val = %this.readLine(); switch$(%val) { case "1": %writer.close(); Echo("Append:"); %open = %writer.openForAppend(%name); case "2": %writer.close(); Echo("Delete and Overwrite:"); if (!DeleteFile(%name)) Echo("File delete unsuccessful."); else Echo("File delete successful!"); %open = %writer.openForWrite(%name); default: %writer.close(); Echo("Overwrite:"); %open = %writer.openForWrite(%name); } if (%open && (!%this.IsEOF())) { %argline = %this.readLine(); if (%argline $= ":: Begin ::") { while (%line !$= ":: End ::") { %line = %this.readLine(); if (%line !$= ":: End ::") %writer.writeLine(%line); } Echo("File output successful."); return true; } } else { Warn("File output interrupted! Canceling..."); return false; } } else { Warn("No output mode selected! Canceling..."); return false; } } function DeleteFile(%name) { %read = new FileObject(); %write = new FileObject(); if (IsFile(%name) or (!IsWriteableFileName(%name))) return false; if (%read.openForRead(%name)) { if (%write.openForWrite(%name)) { while (!%read.IsEOF()) { %read.readLine(); %write.writeLine(""); } return true; } return false; } return false; }