/// <summary>Adds one or more files to the list of files to be packed</summary> /// <param name="packagePath">Path to the package that assets are read from</param> /// <param name="packageFiles">Enumerable list with the paths of the files to add</param> public static void Build(string packagePath, IEnumerable <PackageFile> packageFiles) { List <PackageFileHeader> packageFileHeaders = setupPackageFileHeaders(packageFiles); using ( FileStream package = new FileStream( packagePath, FileMode.Create, FileAccess.Write, FileShare.None ) ) { BinaryWriter packageWriter = new BinaryWriter(package); packageWriter.Write(packageFileHeaders.Count); // Write the preliminary headers to the package (we don't know some informations, // like the compressed file sizes, yet). The headers will be written a second // time after the data offsets and compressed file sizes have been filled in. foreach (PackageFileHeader packageFileHeader in packageFileHeaders) { packageFileHeader.Write(packageWriter); } // Compress all files and write them into the package, filling the missing fields // in the package file headers in the process. int index = 0; foreach (PackageFile packageFile in packageFiles) { using ( FileStream asset = new FileStream( packageFile.Path, FileMode.Open, FileAccess.Read, FileShare.Read ) ) { PackageFileHeader header = packageFileHeaders[index]; header.DataOffset = package.Position; header.CompressedLength = compress(package, asset); packageFileHeaders[index] = header; } ++index; } // Second run writing the package file headers, this time we know all the // informations. This relies on the headers not changing in size, so any // strings contained in the headers must not be modified. package.Position = 4; foreach (PackageFileHeader packageFileHeader in packageFileHeaders) { packageFileHeader.Write(packageWriter); } } }
public void Build() { List<PackageFileHeader> packageFileHeaders = new List<PackageFileHeader>(packageFiles.Count); using (FileStream package = new FileStream(packagePath, FileMode.Create, FileAccess.ReadWrite, FileShare.None)) { // Create a binary writer using ASCII in little-endian format BinaryWriter writer = new BinaryWriter(package); // The Package Header Section writer.Write(PACKAGE_ID, 0, 4); // The Package ID writer.Write((int)0); // File Count writer.Write((long)0); // Offset to Package File Headers writer.Write((int)0); // CRC // Compress and write the file data foreach (PackageFile packageFile in packageFiles) { using (FileStream file = new FileStream(packageFile.Path, FileMode.Open, FileAccess.Read, FileShare.Read)) { FileInfo fileInfo = new FileInfo(packageFile.Path); string relativePath = packageFile.Path.Substring(packageFile.Path.LastIndexOf("..\\Data\\")); switch (fileInfo.Extension) { case ".pak": // Check the file for the package file header ID byte[] packageID = new byte[4]; file.Read(packageID, 0, 4); file.Position = 0; for (int i = 0; i < packageID.Length; ++i) { if (packageID[i] != PACKAGE_ID[i]) goto default; } // Skip packaged files break; case ".xml": PackageFileHeader packageFileHeader = new PackageFileHeader(relativePath, package.Position, fileInfo.Length, true); // Encrypt the file MemoryStream encryptedFile = Encrypt(file, "mtT_;oV4)0Gw", "89ZB!]ekT(0d", "SHA1", 2, "3BgLd7#q{@@ZoR1E", KeySize.AES128); // The size of the encrypted file can increase due to padding packageFileHeader.UncompressedSize = encryptedFile.Length; // Compress and write to package //packageFileHeader.CompressedSize = Compress(package, encryptedFile); package.Write(encryptedFile.ToArray(), 0, (int)encryptedFile.Length); encryptedFile.Close(); packageFileHeaders.Add(packageFileHeader); break; default: packageFileHeader = new PackageFileHeader(relativePath, package.Position, fileInfo.Length); // Compress and write to package //packageFileHeader.CompressedSize = Compress(package, file); byte[] buffer = new byte[file.Length]; file.Read(buffer, 0, (int)file.Length); package.Write(buffer, 0, (int)file.Length); packageFileHeaders.Add(packageFileHeader); break; } } } // Save the position of the first file header for the File Header section long offsetToHeaders = package.Position; // Write Headers foreach (PackageFileHeader header in packageFileHeaders) { header.Write(writer); } writer.Flush(); // Write the position of the first file header package.Position = PACKAGE_HEADER_FILE_COUNT_POSITION; writer.Write(packageFileHeaders.Count); writer.Write(offsetToHeaders); package.Flush(); } }