Esempio n. 1
0
        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();
                }
            }
        }
Esempio n. 2
0
        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;
        }