public static void Main(string[] args)
        {
            bool   verbose          = false;
            string filterPattern    = null;
            bool   overwriteFiles   = false;
            bool   dontUseFullPaths = false;
            bool   showHelp         = false;

            var options = new OptionSet()
            {
                { "v|verbose", "be verbose (list files)", v => verbose = v != null },
                { "f|filter=", "only extract files using pattern", v => filterPattern = v },
                { "o|overwrite", "overwrite files if they already exist", v => overwriteFiles = v != null },
                { "nf|no-full-paths", "don't extract using full paths", v => dontUseFullPaths = v != null },
                { "h|help", "show this message and exit", v => showHelp = v != null },
            };

            List <string> extra;

            try
            {
                extra = 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 (extra.Count < 1 || extra.Count > 2 || showHelp == true)
            {
                Console.WriteLine("Usage: {0} [OPTIONS]+ input_sarc [output_directory]", GetExecutableName());
                Console.WriteLine("Unpack specified small archive.");
                Console.WriteLine();
                Console.WriteLine("Options:");
                options.WriteOptionDescriptions(Console.Out);
                return;
            }

            string inputPath     = extra[0];
            string outputPath    = extra.Count > 1 ? extra[1] : Path.ChangeExtension(inputPath, null) + "_unpack";
            string tmpOutputPath = extra.Count > 1 ? extra[1] : Path.ChangeExtension(inputPath, ".sarc");
            Regex  filter        = null;

            if (string.IsNullOrEmpty(filterPattern) == false)
            {
                filter = new Regex(filterPattern, RegexOptions.Compiled | RegexOptions.IgnoreCase);
            }

            using (var temp = File.OpenRead(inputPath))
                using (var cool = CreateCoolArchiveStream(temp))
                {
                    //if (cool != null)
                    //{
                    //    using (var output = File.Create(tmpOutputPath))
                    //    {
                    //        var res = cool.ReadBytes((uint)cool.Length);
                    //        output.WriteBytes(res);
                    //        cool.Position = 0;
                    //    }
                    //}
                    var input = cool ?? temp;

                    var smallArchive = new SmallArchiveFile();
                    smallArchive.Deserialize(input);

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

                    Directory.CreateDirectory(outputPath);

                    var xmlPath     = Path.Combine(outputPath, "@files.xml");
                    var xmlSettings = new XmlWriterSettings()
                    {
                        Indent = true,
                    };
                    using (var xml = XmlWriter.Create(xmlPath, xmlSettings))
                    {
                        xml.WriteStartDocument();
                        xml.WriteStartElement("files");

                        foreach (var entry in smallArchive.Entries)
                        {
                            current++;

                            if (string.IsNullOrEmpty(entry.Name) == true)
                            {
                                throw new InvalidOperationException();
                            }

                            var entryName = entry.Name;

                            //if (filter != null && filter.IsMatch(entryName) == false)
                            //{
                            //    continue;
                            //}

                            var entryPath = entryName;
                            if (entryPath[0] == '/' || entryPath[0] == '\\')
                            {
                                entryPath = entryPath.Substring(1);
                            }
                            entryPath = entryPath.Replace('/', Path.DirectorySeparatorChar);

                            if (dontUseFullPaths == true)
                            {
                                entryPath = Path.GetFileName(entryPath);
                            }

                            entryPath = Path.Combine(outputPath, entryPath);
                            //if (overwriteFiles == false && File.Exists(entryName) == true)
                            //{
                            //    continue;
                            //}

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

                            if (entry.Offset == 0)
                            {
                                xml.WriteStartElement("file");
                                xml.WriteStartAttribute("name");
                                xml.WriteValue(entryName);
                                xml.WriteEndAttribute();
                                xml.WriteStartAttribute("size");
                                xml.WriteValue(entry.Size);
                                xml.WriteEndAttribute();
                                xml.WriteEndElement();
                            }
                            else
                            {
                                xml.WriteStartElement("file");
                                xml.WriteStartAttribute("name");
                                xml.WriteValue(entryName);
                                xml.WriteEndAttribute();
                                xml.WriteValue(GetRelativePathForFile(xmlPath, entryPath));
                                xml.WriteEndElement();

                                var parentOutputPath = Path.GetDirectoryName(entryPath);
                                if (string.IsNullOrEmpty(parentOutputPath) == false)
                                {
                                    Directory.CreateDirectory(parentOutputPath);
                                }

                                using (var output = File.Create(entryPath))
                                {
                                    input.Seek(entry.Offset, SeekOrigin.Begin);
                                    output.WriteFromStream(input, entry.Size);
                                }
                            }
                        }
                        Console.WriteLine("exported {0} files", current);
                        xml.WriteEndElement();
                        xml.WriteEndDocument();
                    }
                }
        }
        public static void Main(string[] args)
        {
            const int alignment = 4;
            var       endian    = Endian.Little;
            bool      verbose   = false;
            bool      compress  = false;
            bool      showHelp  = false;

            var options = new OptionSet
            {
                {
                    "v|verbose", "be verbose (list files)", v => verbose = v != null
                },
                {
                    "l|little-endian", "write in little endian mode", v =>
                    {
                        if (v != null)
                        {
                            endian = Endian.Little;
                        }
                    }
                },
                {
                    "b|big-endian", "write in big endian mode", v =>
                    {
                        if (v != null)
                        {
                            endian = Endian.Big;
                        }
                    }
                },
                {
                    "c|compress", "compress small archive with zlib.", v => compress = v != null
                },
                {
                    "h|help", "show this message and exit", v => showHelp = v != null
                }
            };

            List <string> extra;

            try
            {
                extra = 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 (extra.Count < 1 || extra.Count > 2 || showHelp == true)
            {
                Console.WriteLine("Usage: {0} [OPTIONS]+ input_directory [output_sarc]", GetExecutableName());
                Console.WriteLine("Pack specified directory.");
                Console.WriteLine();
                Console.WriteLine("Options:");
                options.WriteOptionDescriptions(Console.Out);
                return;
            }

            string inputPath  = extra[0];
            string outputPath = extra.Count > 1 ? extra[1] : inputPath + ".sarc";

            using (var output = File.Create(outputPath))
            {
                Stream data = output;

                if (compress == true)
                {
                    data = new DeflaterOutputStream(output, new Deflater(Deflater.BEST_SPEED, false));
                }

                var paths = new List <string>();
                paths.AddRange(Directory.GetFiles(inputPath, "*", SearchOption.AllDirectories));
                paths.Sort(new NameComparer());

                int headerSize = 0;
                // ReSharper disable LoopCanBeConvertedToQuery
                foreach (string path in paths) // ReSharper restore LoopCanBeConvertedToQuery
                {
                    headerSize += 4 + (Path.GetFileName(path) ?? "").Length + 4 + 4;
                }
                headerSize = headerSize.Align(16);

                // TODO: rewrite this terrible, terrible code.
                var smallArchive = new SmallArchiveFile();
                int offset       = 16 + headerSize;
                foreach (string path in paths)
                {
                    smallArchive.Entries.Add(new SmallArchiveFile.Entry()
                    {
                        Name   = Path.GetFileName(path),
                        Offset = (uint)offset,
                        Size   = (uint)((new FileInfo(path)).Length),
                    });
                    offset += (int)((new FileInfo(path)).Length);
                    offset  = offset.Align(alignment);
                }

                smallArchive.Endian = endian;
                smallArchive.Serialize(data);

                var buffer = new byte[0x4000];
                foreach (string path in paths)
                {
                    if (verbose == true)
                    {
                        Console.WriteLine("Adding {0}...", Path.GetFileName(path));
                    }

                    int total = 0;
                    using (var input = File.OpenRead(path))
                    {
                        while (true)
                        {
                            int read = input.Read(buffer, 0, 0x4000);
                            if (read == 0)
                            {
                                break;
                            }
                            data.Write(buffer, 0, read);
                            total += read;
                        }
                    }

                    int dummySize = total.Align(alignment) - total;
                    if (dummySize > 0)
                    {
                        var dummyBlock = new byte[dummySize];
                        data.Write(dummyBlock, 0, dummySize);
                    }
                }

                var deflaterOutputStream = data as DeflaterOutputStream;
                if (deflaterOutputStream != null)
                {
                    (deflaterOutputStream).Finish();
                }

                data.Flush();
            }
        }
        public static void Main(string[] args)
        {
            var  endian   = Endian.Little;
            bool verbose  = false;
            bool compress = false;
            bool showHelp = false;

            var options = new OptionSet
            {
                { "v|verbose", "be verbose (list files)", v => verbose = v != null },
                { "l|little-endian", "write in little endian mode", v => SetOption(v, ref endian, Endian.Little) },
                { "b|big-endian", "write in big endian mode", v => SetOption(v, ref endian, Endian.Big) },
                { "c|compress", "compress small archive with zlib.", v => compress = v != null },
                { "h|help", "show this message and exit", v => showHelp = v != null }
            };

            List <string> extra;

            try
            {
                extra = 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 (extra.Count < 1 || extra.Count > 2 || showHelp == true)
            {
                Console.WriteLine("Usage: {0} [OPTIONS]+ input_directory [output_sarc]", GetExecutableName());
                Console.WriteLine("Pack specified directory.");
                Console.WriteLine();
                Console.WriteLine("Options:");
                options.WriteOptionDescriptions(Console.Out);
                return;
            }

            var    inputPath = Path.GetFullPath(extra[0]);
            string xmlPath;

            if (Directory.Exists(inputPath) == true)
            {
                xmlPath = Path.Combine(inputPath, "@files.xml");
            }
            else
            {
                xmlPath   = inputPath;
                inputPath = Path.GetDirectoryName(inputPath);
            }
            var outputPath = extra.Count > 1 ? extra[1] : inputPath + ".sarc";

            var pendingEntries = new List <PendingEntry>();

            using (var xml = File.OpenRead(xmlPath))
            {
                var doc = new XPathDocument(xml);
                var nav = doc.CreateNavigator();

                var rawFiles = nav.Select("/files/file");
                while (rawFiles.MoveNext() == true)
                {
                    var rawFile = rawFiles.Current;

                    if (rawFile.MoveToAttribute("name", "") == false)
                    {
                        throw new FormatException();
                    }
                    var entryName = rawFile.Value;
                    rawFile.MoveToParent();

                    if (rawFile.MoveToAttribute("size", "") == true)
                    {
                        uint entrySize;
                        if (uint.TryParse(rawFile.Value, out entrySize) == false)
                        {
                            throw new FormatException();
                        }

                        pendingEntries.Add(new PendingEntry()
                        {
                            Name = entryName,
                            Size = entrySize,
                        });
                        rawFile.MoveToParent();
                        continue;
                    }

                    string entryPath;
                    if (Path.IsPathRooted(rawFile.Value) == false)
                    {
                        entryPath = Path.Combine(inputPath, rawFile.Value);
                    }
                    else
                    {
                        entryPath = rawFile.Value;
                    }

                    pendingEntries.Add(new PendingEntry()
                    {
                        Name = entryName,
                        Path = entryPath,
                    });
                }
            }

            using (var output = File.Create(outputPath))
            {
                var headerSize = SmallArchiveFile.EstimateHeaderSize(pendingEntries.Select(pe => pe.Name));

                var smallArchive = new SmallArchiveFile();

                output.Position = headerSize;
                foreach (var pendingEntry in pendingEntries)
                {
                    if (pendingEntry.Size != null)
                    {
                        smallArchive.Entries.Add(new SmallArchiveFile.Entry(pendingEntry.Name,
                                                                            0,
                                                                            pendingEntry.Size.Value));
                        continue;
                    }

                    using (var input = File.OpenRead(pendingEntry.Path))
                    {
                        output.Position = output.Position.Align(4);
                        smallArchive.Entries.Add(new SmallArchiveFile.Entry(pendingEntry.Name,
                                                                            (uint)output.Position,
                                                                            (uint)input.Length));
                        output.WriteFromStream(input, input.Length);
                    }
                }

                output.Position     = 0;
                smallArchive.Endian = endian;
                smallArchive.Serialize(output);
            }
        }
Beispiel #4
0
        private void HandleStream(Stream file, string type)
        {
            file.Position = 0;
            if (type == "ADF")
            {
                // Got some AAF file
                bool inc = false;
                try
                {
                    var adf = new AdfFile();
                    try
                    {
                        adf.Deserialize(file);
                        ++ADFReadCount;
                    }
                    catch
                    {
                        inc = true;
                        ++ADFSkipCount;
                    }
                    ADFExtractStrings(adf);
                }
                catch
                {
                    if (!inc)
                    {
                        ++ADFSkipCount;
                    }
                }
            }
            else if (type == "RTPC")
            {
                // Got some RTPC file
                try
                {
                    var propertyContainerFile = new PropertyContainerFile();
                    propertyContainerFile.Deserialize(file);
                    RTPCExtractStrings(propertyContainerFile);
                    ++RTPCReadCount;
                }
                catch
                {
                    ++RTPCSkipCount;
                }
            }
            else if (type == "AAF")
            {
                // Got some AAF Archive
                using (var cool = CreateCoolArchiveStream(file))
                {
                    var input = cool ?? file;

                    var smallArchive = new SmallArchiveFile();
                    smallArchive.Deserialize(input);

                    foreach (var entry in smallArchive.Entries)
                    {
                        this.AddString(entry.Name);
                        if (entry.Offset == 0)
                        {
                            continue;
                        }

                        ++this.FileCount;
                        this.PrintProgress();

                        input.Position = entry.Offset;
                        string subtype = this.GetType(input);
                        if (string.IsNullOrEmpty(subtype))
                        {
                            continue;
                        }
                        using (var entryStream = entry.ReadToMemoryStream(input))
                        {
                            this.HandleStream(entryStream, subtype);
                        }
                    }

                    ++this.AAFExtractCount;
                }
            }
        }
        private void HandleStream(Stream file, string type)
        {
            // flush if the limit is reached
            if (this._EntryCount > 300000)
            {
                this.flush();
            }

            //file.Position = 0;
            if (type == "ADF")
            {
                // Got some AAF file
                bool inc = false;
                try
                {
                    var adf = new AdfFile();
                    try
                    {
                        adf.Deserialize(file);
                        ++ADFReadCount;
                    }
                    catch
                    {
                        inc = true;
                        ++ADFSkipCount;
                    }
                    ADFExtractStrings(adf);
                }
                catch
                {
                    if (!inc)
                    {
                        ++ADFSkipCount;
                    }
                }
            }
            else if (type == "RTPC")
            {
                // Got some RTPC file
                try
                {
                    var propertyContainerFile = new PropertyContainerFile();
                    propertyContainerFile.Deserialize(file);
                    RTPCExtractStrings(propertyContainerFile);
                    ++RTPCReadCount;
                }
                catch
                {
                    ++RTPCSkipCount;
                }
            }
            else if (type == "AAF")
            {
                // Got some AAF Archive
                using (var cool = CreateCoolArchiveStream(file))
                {
                    var input = cool ?? file;

                    var smallArchive = new SmallArchiveFile();
                    smallArchive.Deserialize(input);

                    this._CurrentFile.Add(null);

                    foreach (var entry in smallArchive.Entries)
                    {
                        this.AddString(entry.Name);
                        if (entry.Offset == 0)
                        {
                            continue;
                        }

                        ++this.FileCount;
                        this.PrintProgress();

                        input.Position = entry.Offset;
                        string subtype = this.GetType(input);
                        if (string.IsNullOrEmpty(subtype))
                        {
                            continue;
                        }
                        // insert the name
                        this._CurrentFile[this._CurrentFile.Count - 1] = entry.Name;
                        this.UpdateCurrentFile();
                        // process the file
                        using (var entryStream = entry.ReadToMemoryStream(input))
                        {
                            // I know that this copies a copy of a memory (that's a stupid thing)
                            // but without this the memories goes crazy and if I force GC Collect
                            // that's even worse. So a little copy doesn't look bad in front of
                            // the horrors produced when you don't have it.
                            // to see what it's like, replace entryStream with input.
                            this.HandleStream(entryStream, subtype);
                        }
                    }

                    this._CurrentFile.RemoveAt(this._CurrentFile.Count - 1);

                    ++this.AAFExtractCount;
                }
            }
        }
Beispiel #6
0
        public static void Main(string[] args)
        {
            bool verbose        = false;
            bool overwriteFiles = false;
            bool decompress     = false;
            bool listing        = false;
            bool showHelp       = false;

            var options = new OptionSet()
            {
                {
                    "v|verbose",
                    "be verbose (list files)",
                    v => verbose = v != null
                },
                {
                    "l|list",
                    "just list files (don't extract)",
                    v => listing = v != null
                },
                {
                    "o|overwrite",
                    "overwrite files if they already exist",
                    v => overwriteFiles = v != null
                },
                {
                    "d|decompress",
                    "decompress a zlib compressed small archive.",
                    v => decompress = v != null
                },
                {
                    "h|help",
                    "show this message and exit",
                    v => showHelp = v != null
                },
            };

            List <string> extra;

            try
            {
                extra = 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 (extra.Count < 1 || extra.Count > 2 || showHelp == true)
            {
                Console.WriteLine("Usage: {0} [OPTIONS]+ input_sarc [output_directory]", GetExecutableName());
                Console.WriteLine("Unpack specified small archive.");
                Console.WriteLine();
                Console.WriteLine("Options:");
                options.WriteOptionDescriptions(Console.Out);
                return;
            }

            string inputPath  = extra[0];
            string outputPath = extra.Count > 1
                                    ? extra[1]
                                    : Path.ChangeExtension(inputPath, null) + "_unpack";

            using (var input = File.OpenRead(inputPath))
            {
                if (input.ReadValueU8() == 0x78)
                {
                    if (verbose == true)
                    {
                        Console.WriteLine("Detected compressed SARC.");
                    }

                    decompress = true;
                }
                input.Seek(-1, SeekOrigin.Current);

                Stream data;
                if (decompress == false)
                {
                    data = input;
                }
                else
                {
                    var decompressed = new MemoryStream();

                    //var zlib = new ZlibStream(input, CompressionMode.Decompress);
                    var zlib = new InflaterInputStream(input);

                    var buffer = new byte[0x4000];
                    while (true)
                    {
                        int read = zlib.Read(buffer, 0, buffer.Length);
                        if (read < 0)
                        {
                            throw new InvalidOperationException("zlib error");
                        }

                        if (read == 0)
                        {
                            break;
                        }

                        decompressed.Write(buffer, 0, read);
                    }

                    zlib.Close();
                    input.Close();
                    decompressed.Position = 0;

                    data = decompressed;
                }

                if (listing == false)
                {
                    Directory.CreateDirectory(outputPath);
                }

                var smallArchive = new SmallArchiveFile();
                smallArchive.Deserialize(data);

                long counter    = 0;
                long skipped    = 0;
                long totalCount = smallArchive.Entries.Count;

                if (verbose == true)
                {
                    Console.WriteLine("{0} files in small archive.", totalCount);
                }

                foreach (var entry in smallArchive.Entries)
                {
                    counter++;

                    var entryName = Path.GetFileName(entry.Name);
                    if (entryName == null)
                    {
                        throw new InvalidOperationException();
                    }

                    var entryPath = Path.Combine(outputPath, entryName);

                    if (overwriteFiles == false && File.Exists(entryPath) == true)
                    {
                        if (verbose == true)
                        {
                            Console.WriteLine("{1:D4}/{2:D4} !! {0}", entry.Name, counter, totalCount);
                        }

                        skipped++;
                        continue;
                    }

                    if (verbose == true || listing == true)
                    {
                        Console.WriteLine("{1:D4}/{2:D4} => {0}", entry.Name, counter, totalCount);
                    }

                    if (listing == false)
                    {
                        using (var output = File.Create(entryPath))
                        {
                            data.Seek(entry.Offset, SeekOrigin.Begin);
                            output.WriteFromStream(data, entry.Size);
                        }
                    }
                }

                if (verbose == true && skipped > 0)
                {
                    Console.WriteLine("{0} files not overwritten.", skipped);
                }
            }
        }