static void LoadXp3Enc(string filePath) { if (string.IsNullOrEmpty(filePath)) { return; } if (File.Exists(filePath)) { Xp3Enc.Load(filePath); } }
static void CreateArchive(CommandLineOptions options, LinkedList <TFileSource> sourceFiles, string outpuFile) { // Load encryption module LoadXp3Enc(options.Xp3EncPath); using (FileStream arcStream = File.Create(outpuFile)) using (BinaryWriter arcWriter = new BinaryWriter(arcStream)) { // Write header arcWriter.WriteBytes(new byte[] { 0x58, 0x50, 0x33, 0x0D, 0x0A, 0x20, 0x0A, 0x1A }); arcWriter.WriteBytes(new byte[] { 0x8B, 0x67, 0x01 }); arcWriter.WriteInt64(8 + 3 + 8 + 4); arcWriter.WriteUInt32(1); arcWriter.WriteByte(0x80); arcWriter.WriteInt64(0); long indexOffsetPos = arcStream.Position; arcWriter.WriteInt64(0); LinkedList <TFileInfo> files = new LinkedList <TFileInfo>(); long fileDataStart = arcStream.Position; // Add protection warning file arcWriter.WriteBytes(ProtectionWarningPng); { TFileSegment segm = new TFileSegment(); segm.Offset = fileDataStart + 0x30; segm.Size = 0x9D; // ProtectionWarningPng.Length; segm.StoreSize = 0x9D; // ProtectionWarningPng.Length; segm.Flags = 0; TFileInfo info = new TFileInfo(); info.Name = "$$$ This is a protected archive. $$$ 著作者はこのアーカイブが正規の利用方法以外の方法で展開されることを望んでいません。 $$$ This is a protected archive. $$$ 著作者はこのアーカイブが正規の利用方法以外の方法で展開されることを望んでいません。 $$$ This is a protected archive. $$$ 著作者はこのアーカイブが正規の利用方法以外の方法で展開されることを望んでいません。 $$$ Warning! Extracting this archive may infringe on author's rights. 警告 このアーカイブを展開することにより、あなたは著作者の権利を侵害するおそれがあります。.txt"; info.NameMd5 = Util.StringMd5(info.Name.ToLower()); info.Size = segm.Size; info.StoreSize = segm.StoreSize; info.Adler32 = Util.Adler32(ProtectionWarningPng); info.Flags = 0; info.Segments.Add(segm); files.AddLast(info); } // Store file foreach (var item in sourceFiles) { byte[] data = File.ReadAllBytes(item.LocalPath); TFileSegment segm = new TFileSegment(); segm.Offset = arcStream.Position; segm.Size = data.Length; segm.StoreSize = data.Length; segm.Flags = 0; TFileInfo info = new TFileInfo(); info.Name = item.Path.Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); info.NameMd5 = Util.StringMd5(info.Name.ToLower()); info.Timestamp = new DateTimeOffset(new FileInfo(item.LocalPath).LastWriteTime).ToUnixTimeMilliseconds(); info.Size = segm.Size; info.StoreSize = segm.StoreSize; info.Adler32 = Util.Adler32(data); // This algorithm maybe wrong. info.Flags = (1u << 31); // protected info.Segments.Add(segm); files.AddLast(info); Console.WriteLine("Storing file: {0}", info.Name); // Encrypt file data if (Xp3Enc.Loaded) { Xp3Enc.Encrypt(info.Adler32, 0, data); } else if (options.XorKey != null) { XorEncrypt(data, (byte)options.XorKey); } // Store to archive arcWriter.WriteBytes(data); } // Build index Console.WriteLine("Building index..."); MemoryStream indexStream = new MemoryStream(); BinaryWriter indexWriter = new BinaryWriter(indexStream); foreach (var item in files) { new ChunkWriter(indexWriter, "hnfn").Write(hnfnWriter => { hnfnWriter.WriteUInt32(item.Adler32); hnfnWriter.WriteUnicodeString(item.Name); }); } foreach (var item in files) { new ChunkWriter(indexWriter, "File").Write(fileWriter => { if (item.Timestamp != 0) { new ChunkWriter(indexWriter, "time").Write(timeWriter => { timeWriter.WriteInt64(item.Timestamp); }); } new ChunkWriter(indexWriter, "adlr").Write(adlrWriter => { adlrWriter.WriteUInt32(item.Adler32); }); new ChunkWriter(indexWriter, "segm").Write(segmWriter => { foreach (var segm in item.Segments) { segmWriter.WriteUInt32(segm.Flags); segmWriter.WriteInt64(segm.Offset); segmWriter.WriteInt64(segm.Size); segmWriter.WriteInt64(segm.StoreSize); } }); new ChunkWriter(indexWriter, "info").Write(infoWriter => { infoWriter.WriteUInt32(item.Flags); infoWriter.WriteInt64(item.Size); infoWriter.WriteInt64(item.StoreSize); infoWriter.WriteUnicodeString(item.NameMd5); }); }); } // Compress index byte[] indexData = indexStream.ToArray(); byte[] compressedIndexData = Util.Deflate(indexData); // Write index long indexOffset = arcStream.Position; arcWriter.WriteByte(1); // compressed arcWriter.WriteInt64(compressedIndexData.Length); arcWriter.WriteInt64(indexData.Length); arcWriter.WriteBytes(compressedIndexData); arcStream.Position = indexOffsetPos; arcWriter.WriteInt64(indexOffset); // Done arcWriter.Flush(); arcWriter.Close(); Console.WriteLine("Done."); } }