Esempio n. 1
0
        private static void Main(string[] args)
        {
            Endian endian   = Endian.Little;
            bool   showHelp = false;
            bool   verbose  = false;

            var options = new OptionSet()
            {
                { "v|verbose", "be verbose", v => verbose = v != null },
                { "l|little-endian", "little-endian mode (default)", v => GetOptionValue(ref endian, v, Endian.Little) },
                { "b|big-endian", "big-endian mode", v => GetOptionValue(ref endian, v, Endian.Big) },
                { "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 || showHelp == true)
            {
                Console.WriteLine("Usage: {0} [OPTIONS]+ output_par input_directory+", GetExecutableName());
                Console.WriteLine();
                Console.WriteLine("Pack files from input directories into a PARC file.");
                Console.WriteLine();
                Console.WriteLine("Options:");
                options.WriteOptionDescriptions(Console.Out);
                return;
            }

            var    inputPaths = new List <string>();
            string outputPath;

            if (extras.Count == 1)
            {
                inputPaths.Add(extras[0]);
                outputPath = extras[0] + ".par";
            }
            else
            {
                outputPath = extras[0];
                inputPaths.AddRange(extras.Skip(1));
            }

            var pendingEntries = new SortedDictionary <string, KeyValuePair <string, string> >();

            if (verbose == true)
            {
                Console.WriteLine("Finding files...");
            }

            foreach (var relativePath in inputPaths)
            {
                string inputPath = Path.GetFullPath(relativePath);

                if (inputPath.EndsWith(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar) == 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)
                                      .Replace(Path.DirectorySeparatorChar, '\\')
                                      .Replace(Path.AltDirectorySeparatorChar, '\\');

                    var partKey = partPath.ToLowerInvariant();

                    KeyValuePair <string, string> previousPair;
                    if (pendingEntries.TryGetValue(partKey, out previousPair) == true)
                    {
                        if (verbose == true)
                        {
                            Console.WriteLine("Ignoring duplicate of {0}:", previousPair.Key);
                            Console.WriteLine("  Previously added from: {0}", previousPair.Value);
                        }
                        else
                        {
                            Console.WriteLine("Ignoring duplicate of {0}!", previousPair.Key);
                        }
                        continue;
                    }

                    pendingEntries[partKey] = new KeyValuePair <string, string>(partPath, fullPath);
                }
            }

            const int alignment = 2048;

            var archive = new ArchiveFile()
            {
                Endian = endian,
            };

            using (var output = File.Create(outputPath))
            {
                var headerSize = ArchiveFile.EstimateHeaderSize(pendingEntries.Keys);

                output.Position = headerSize;

                long current = 0;
                long total   = pendingEntries.Count;
                var  padding = total.ToString(CultureInfo.InvariantCulture).Length;

                foreach (var kv in pendingEntries.Values)
                {
                    var partPath = kv.Key;
                    var fullPath = kv.Value;

                    current++;

                    if (verbose == true)
                    {
                        Console.WriteLine(
                            "[{0}/{1}] {2}",
                            current.ToString(CultureInfo.InvariantCulture).PadLeft(padding),
                            total,
                            partPath);
                    }

                    using (var input = File.OpenRead(fullPath))
                    {
                        var dataSize = (uint)input.Length;

                        output.Position = output.Position.Align(alignment);

                        if (output.Position > 0xfFFFFFFFFL)
                        {
                            throw new InvalidOperationException("unsupported data offset");
                        }

                        ArchiveFile.FileEntry fileEntry;
                        fileEntry.Path                 = partPath;
                        fileEntry.IsCompressed         = false;
                        fileEntry.DataUncompressedSize = dataSize;
                        fileEntry.DataCompressedSize   = dataSize;
                        fileEntry.DataOffset           = output.Position;
                        archive.Entries.Add(fileEntry);

                        if (dataSize > 0)
                        {
                            output.WriteFromStream(input, dataSize);
                        }
                    }
                }

                output.SetLength(output.Position.Align(alignment)); // pad file ending

                output.Position = 0;
                archive.Serialize(output);

                if (output.Position != headerSize)
                {
                    throw new InvalidOperationException("header estimation mismatch");
                }
            }
        }