public static void Main(string[] args) { bool showHelp = false; bool overwriteFiles = false; bool verbose = false; var options = new OptionSet() { { "o|overwrite", "overwrite existing files", v => overwriteFiles = v != null }, { "v|verbose", "be verbose", v => verbose = v != null }, { "h|help", "show this message and exit", v => showHelp = v != null }, }; List <string> extras; try { extras = options.Parse(args); } catch (OptionException e) { Console.Write("{0}: ", GetExecutableName()); Console.WriteLine(e.Message); Console.WriteLine("Try `{0} --help' for more information.", GetExecutableName()); return; } if (extras.Count < 1 || extras.Count > 2 || showHelp == true) { Console.WriteLine("Usage: {0} [OPTIONS]+ input_dir [output_rcf]", GetExecutableName()); Console.WriteLine(); Console.WriteLine("Options:"); options.WriteOptionDescriptions(Console.Out); return; } var inputPaths = new List <string>(); inputPaths.Add(Path.GetFullPath(extras[0])); var outputPath = extras.Count > 1 ? extras[1] : Path.ChangeExtension(extras[0], ".rcf"); var paths = new SortedDictionary <string, string>(); if (verbose == true) { Console.WriteLine("Finding files..."); } foreach (var relPath in inputPaths) { string inputPath = Path.GetFullPath(relPath); if (inputPath.EndsWith(Path.DirectorySeparatorChar.ToString(CultureInfo.InvariantCulture)) == true) { inputPath = inputPath.Substring(0, inputPath.Length - 1); } foreach (string path in Directory.GetFiles(inputPath, "*", SearchOption.AllDirectories)) { string fullPath = Path.GetFullPath(path); string partPath = fullPath.Substring(inputPath.Length + 1).ToLowerInvariant(); if (paths.ContainsKey(partPath) == true) { Console.WriteLine("Ignoring {0} duplicate.", partPath); continue; } paths[partPath] = fullPath; } } using (var output = File.Create(outputPath)) { var cement = new CementFile(); cement.Endian = Endian.Little; cement.Entries.Clear(); cement.Metadatas.Clear(); foreach (var kv in paths) { var entry = new Cement.Entry(); entry.NameHash = kv.Key.HashFileName(0); entry.Offset = 0; entry.Size = 0; var metadata = new Cement.Metadata(); metadata.TypeHash = 0; metadata.Alignment = 2048; metadata.Name = kv.Key; cement.Entries.Add(entry); cement.Metadatas.Add(metadata); } var preestimatedHeaderSize = cement.EstimateHeaderSize(); output.Seek(preestimatedHeaderSize, SeekOrigin.Begin); cement.Entries.Clear(); cement.Metadatas.Clear(); const uint fileAlignment = 2048; if (verbose == true) { Console.WriteLine("Writing files to archive..."); } foreach (var kvp in paths) { if (verbose == true) { Console.WriteLine(kvp.Key); } using (var input = File.OpenRead(kvp.Value)) { var entry = new Cement.Entry(); entry.NameHash = kvp.Key.HashFileName(0); entry.Offset = (uint)output.Position; entry.Size = (uint)input.Length; /*var extension = Path.GetExtension(kvp.Key); * if (extension != null && * extension.StartsWith(".") == true) * { * extension = extension.Substring(1); * }*/ var metadata = new Cement.Metadata(); metadata.TypeHash = 0;//extension == null ? 0 : extension.HashFileName(0); metadata.Alignment = fileAlignment; metadata.Name = kvp.Key; cement.Entries.Add(entry); cement.Metadatas.Add(metadata); output.WriteFromStream(input, entry.Size); output.Seek(output.Position.Align(fileAlignment), SeekOrigin.Begin); } } var estimatedHeaderSize = cement.EstimateHeaderSize(); if (preestimatedHeaderSize != estimatedHeaderSize) { throw new InvalidOperationException(); } if (verbose == true) { Console.WriteLine("Writing header..."); } output.Seek(0, SeekOrigin.Begin); cement.Serialize(output); if (output.Position != estimatedHeaderSize) { throw new InvalidOperationException(); } } }
public void Deserialize(Stream input) { var magic = input.ReadString(24, true, Encoding.ASCII); if (magic != "ATG CORE CEMENT LIBRARY") { throw new FormatException("not a cement file"); } input.ReadBytes(8); // padding var majorVersion = input.ReadValueU8(); var minorVersion = input.ReadValueU8(); var endian = input.ReadValueB8() == false ? Endian.Little : Endian.Big; var unknown1 = input.ReadValueU8(); if (majorVersion != 2 || minorVersion != 1 || unknown1 != 1) { throw new FormatException("bad cement version"); } var indexOffset = input.ReadValueU32(endian); var indexSize = input.ReadValueU32(endian); var metadataOffset = input.ReadValueU32(endian); var metadataSize = input.ReadValueU32(endian); var unknown2 = input.ReadValueU32(endian); var entryCount = input.ReadValueU32(endian); if (unknown2 != 0) { throw new FormatException(); } this.MajorVersion = majorVersion; this.MinorVersion = minorVersion; input.Seek(indexOffset, SeekOrigin.Begin); using (var temp = input.ReadToMemoryStream(indexSize)) { this.Entries.Clear(); for (int i = 0; i < entryCount; i++) { var entry = new Cement.Entry(); entry.Deserialize(temp, endian); this.Entries.Add(entry); } if (temp.Position != temp.Length) { throw new FormatException(); } } input.Seek(metadataOffset, SeekOrigin.Begin); using (var temp = input.ReadToMemoryStream(metadataSize)) { var namesAlignment = temp.ReadValueU32(Endian.Little); var namesUnknown = temp.ReadValueU32(Endian.Little); this.Metadatas.Clear(); for (int i = 0; i < entryCount; i++) { var metadata = new Cement.Metadata(); metadata.Deserialize(temp, endian); this.Metadatas.Add(metadata); } } this.Endian = endian; }