static void Unpack(PackerSettings settings) { Console.WriteLine("-- Unpack Files in " + settings.target + " --"); FileStream stream = new FileStream(settings.target, FileMode.Open); BinaryReader r = new BinaryReader(stream); DiskArchiveHeader header = new DiskArchiveHeader(); header.Read(r); if (header.HasValidMagicValue() == false) { Console.WriteLine("Error: " + settings.target + " is not a P.A.C.K file"); return; } Console.WriteLine("Files: " + header.numFiles); Console.WriteLine("Manifest position: " + header.fileListOffset); string outputDir = "output\\" + Path.GetFileNameWithoutExtension(settings.target); Console.WriteLine("Writing contents to " + outputDir); Directory.CreateDirectory(outputDir); r.BaseStream.Seek(header.fileListOffset, SeekOrigin.Begin); for (int i = 0; i < header.numFiles; ++i) { DiskArchiveFile file = new DiskArchiveFile(); uint manifestReadPosition = file.Read(r); r.BaseStream.Seek(file.offset, SeekOrigin.Begin); byte[] bytes = r.ReadBytes((int)file.numBytes); // remember seek back to manifest position r.BaseStream.Seek(manifestReadPosition, SeekOrigin.Begin); string fileName = outputDir + file.fileName.Trim('\0'); Console.WriteLine("Writing " + fileName + ": Size: " + bytes.Length); // Make sure directory exists Directory.CreateDirectory(Path.GetDirectoryName(fileName)); File.WriteAllBytes(fileName, bytes); } }
static void ListContents(PackerSettings settings) { Console.WriteLine("-- List Files in " + settings.target + " --"); FileStream stream = new FileStream(settings.target, FileMode.Open); BinaryReader r = new BinaryReader(stream); DiskArchiveHeader header = new DiskArchiveHeader(); header.Read(r); if (header.HasValidMagicValue() == false) { Console.WriteLine("Error: " + settings.target + " is not a P.A.C.K file"); return; } Console.WriteLine("Files: " + header.numFiles); Console.WriteLine("Manifest position: " + header.fileListOffset); r.BaseStream.Seek(header.fileListOffset, SeekOrigin.Begin); for (int i = 0; i < header.numFiles; ++i) { DiskArchiveFile file = new DiskArchiveFile(); file.Read(r); Console.WriteLine(file.fileName + ": Size: " + file.numBytes + " offset: " + file.offset + " type: " + file.info[0]); } }
static void Pack(PackerSettings settings) { string outputFile = settings.target + ".dat"; List <string> list = new List <string>(100); GetRecursiveFileList(settings.target, list); if (list.Count == 0) { throw new Exception("No files found in directory '" + settings.target + "'"); } int memSizeOfFileList = DiskArchiveFile.SIZE_IN_BYTES * list.Count; Console.WriteLine("Size of file table: " + memSizeOfFileList + " bytes, or 64 * " + list.Count + " files"); ////////////////////////////////////////////////////////////////////// // Build manifest // headers are stored in memory until write is finished, then appended to the end. ////////////////////////////////////////////////////////////////////// List <DiskArchiveFile> fileHeaders = new List <DiskArchiveFile>(list.Count); foreach (string path in list) { int properStart = path.IndexOf('\\'); string output; if (properStart >= 0) { output = path.Remove(0, properStart); } else { output = path; } // validate filename if (output.Length > MAX_ARCHIVE_FILE_NAME_SIZE) { throw new Exception("File path " + output + " is too long. Must be 51 chars or lower"); } foreach (char c in output) { if (c > 255) { throw new Exception("File path " + output + " contains non-ascii characters"); } } DiskArchiveFile file = new DiskArchiveFile(); file.SetFileName(path); file.numBytes = (uint)GetFileSize(path); file.offset = 0; fileHeaders.Add(file); } ////////////////////////////////////////////////////////////////////// // Write files ////////////////////////////////////////////////////////////////////// // open streams FileStream stream = new FileStream(outputFile, FileMode.Create); BinaryWriter writer = new BinaryWriter(stream); DiskArchiveHeader header = new DiskArchiveHeader(); header.numFiles = (uint)fileHeaders.Count; writer.Seek(DiskArchiveHeader.SIZE_IN_BYTES, SeekOrigin.Begin); Console.WriteLine("Writing files:"); // Build the actual file, updating the manifest foreach (DiskArchiveFile file in fileHeaders) { Console.WriteLine("Writing " + file.fullFilePath + " at " + writer.BaseStream.Position); file.offset = (uint)writer.BaseStream.Position; file.numBytes = (uint)GetFileSize(file.fullFilePath); writer.Write(File.ReadAllBytes(file.fullFilePath)); } Console.WriteLine("Writing manifest:"); // Note the position of the file table in the header header.fileListOffset = (uint)writer.BaseStream.Position; // Write the manifest table foreach (DiskArchiveFile file in fileHeaders) { file.Write(writer); } // Write header now that manifest is completed writer.Seek(0, SeekOrigin.Begin); header.Write(writer); // cleanup writer.Close(); stream.Close(); long outputSize = GetFileSize(outputFile); string sizeStr; if (outputSize >= (1024 * 1024)) { sizeStr = (outputSize / (1024 * 1024)).ToString() + " MB (" + outputSize + " bytes)"; } else if (outputSize > 1024) { sizeStr = (outputSize / 1024).ToString() + " KB (" + outputSize + " bytes)"; } else { sizeStr = outputSize.ToString() + " B"; } Console.Write("Wrote \"" + outputFile + "\": " + sizeStr); }