static void Main(string[] args)
        {
            Options options = null;

            try
            {
                options = CommandLine.Parse <Options>();
            }
            catch (CommandLineException exception)
            {
                Console.WriteLine(exception.ArgumentHelp.Message);
                Console.WriteLine();
                Console.WriteLine(exception.ArgumentHelp.GetHelpText(Console.BufferWidth));

#if DEBUG
                Console.ReadLine();
#endif
                return;
            }

            using (Stream stream = File.OpenRead(options.Source))
            {
                var packfile = Packfile.FromStream(stream, Path.GetExtension(options.Source) == ".str2_pc");

                string folderName = (options.Output != null) ? options.Output : "extracted-" + Path.GetFileName(options.Source);

                Console.WriteLine("Extracting {0} to {1}.", options.Source, folderName);

                Directory.CreateDirectory(folderName);

                int currentFile = 0;
                foreach (IPackfileEntry entry in packfile.Files)
                {
                    currentFile++;

                    Console.Write("[{0}/{1}] Extracting {2}... ", currentFile, packfile.Files.Count, entry.Name);
                    using (Stream outputStream = File.Create(Path.Combine(folderName, entry.Name)))
                    {
                        using (Stream inputStream = entry.GetStream())
                        {
                            inputStream.CopyTo(outputStream);
                        }
                        outputStream.Flush();
                    }
                    Console.WriteLine("done.");
                }

#if DEBUG
                Console.ReadLine();
#endif
            }
        }
        private void DoExtract(object o)
        {
            DisableButton();
            ExtractOptions options = (ExtractOptions)o;

            SetProgressBarSettings(0, 100, 1, ProgressBarStyle.Marquee);
            SetText("Opening packfile...");

            using (Stream stream = File.OpenRead(options.Source))
            {
                var packfile = Packfile.FromStream(stream, Path.GetExtension(options.Source) == ".str2_pc");

                string filename  = Path.GetFileName(options.Source);
                string outputDir = Path.Combine(options.Destination, filename);
                if (File.Exists(outputDir))
                {
                    outputDir = Path.Combine(options.Destination, "extracted-" + filename);
                }
                Directory.CreateDirectory(outputDir);

                SetProgressBarSettings(0, packfile.Files.Count, 1, ProgressBarStyle.Continuous);
                SetText("Extracting {0}...", filename);

                foreach (IPackfileEntry entry in packfile.Files)
                {
                    using (Stream outputStream = File.Create(Path.Combine(outputDir, entry.Name)))
                    {
                        using (Stream inputStream = entry.GetStream())
                        {
                            inputStream.CopyTo(outputStream);
                        }
                        outputStream.Flush();
                    }

                    Step();
                }
            }

            SetText("Finished!");
            EnableButton();
        }
Exemple #3
0
        static void Main(string[] args)
        {
            Options options = null;

            try
            {
                options = CommandLine.Parse <Options>();
            }
            catch (CommandLineException exception)
            {
                Console.WriteLine(exception.ArgumentHelp.Message);
                Console.WriteLine();
                Console.WriteLine(exception.ArgumentHelp.GetHelpText(Console.BufferWidth));

                Console.ReadLine();
                return;
            }

            if (options.Source == null)
            {
                string srtt   = ThomasJepp.SaintsRow.Utility.GetGamePath(GameSteamID.SaintsRowTheThird);
                string sriv   = ThomasJepp.SaintsRow.Utility.GetGamePath(GameSteamID.SaintsRowIV);
                string srgooh = ThomasJepp.SaintsRow.Utility.GetGamePath(GameSteamID.SaintsRowGatOutOfHell);

                int gameCount = 0, srttNum = 0, srivNum = 0, srgoohNum = 0;
                Console.WriteLine("Detected the following games:");
                if (srtt != null)
                {
                    gameCount++;
                    srttNum = gameCount;
                    Console.WriteLine("{0}. Saints Row The Third: {1}", gameCount, srtt);
                }
                if (sriv != null)
                {
                    gameCount++;
                    srivNum = gameCount;
                    Console.WriteLine("{0}. Saints Row IV: {1}", gameCount, sriv);
                }
                if (srgooh != null)
                {
                    gameCount++;
                    srgoohNum = gameCount;
                    Console.WriteLine("{0}. Saints Row Gat Out Of Hell: {1}", gameCount, srgooh);
                }

                if (gameCount == 0)
                {
                    Console.WriteLine("Couldn't find any installed games?");

                    Console.WriteLine();
                    Console.WriteLine("Press enter to exit.");
                    Console.ReadLine();
                    return;
                }

                Console.WriteLine();
                while (true)
                {
                    Console.Write("Which game do you want to update? (enter the number) ");
                    ConsoleKeyInfo input = Console.ReadKey();
                    Console.WriteLine();
                    Console.WriteLine();
                    if (input.Key == ConsoleKey.D1 || input.Key == ConsoleKey.NumPad1)
                    {
                        if (srttNum == 1)
                        {
                            options.Source = srtt;
                            Console.WriteLine("Updating Saints Row: The Third files.");
                        }
                        else if (srivNum == 1)
                        {
                            options.Source = sriv;
                            Console.WriteLine("Updating Saints Row IV files.");
                        }
                        else if (srgoohNum == 1)
                        {
                            options.Source = srgooh;
                            Console.WriteLine("Updating Saints Row: Gat Out Of Hell files.");
                        }
                    }
                    else if (input.Key == ConsoleKey.D2 || input.Key == ConsoleKey.NumPad2)
                    {
                        if (srttNum == 2)
                        {
                            options.Source = srtt;
                            Console.WriteLine("Updating Saints Row: The Third files.");
                        }
                        else if (srivNum == 2)
                        {
                            options.Source = sriv;
                            Console.WriteLine("Updating Saints Row IV files.");
                        }
                        else if (srgoohNum == 2)
                        {
                            options.Source = srgooh;
                            Console.WriteLine("Updating Saints Row: Gat Out Of Hell files.");
                        }
                    }
                    else if (input.Key == ConsoleKey.D3 || input.Key == ConsoleKey.NumPad3)
                    {
                        if (srttNum == 3)
                        {
                            options.Source = srtt;
                            Console.WriteLine("Updating Saints Row: The Third files.");
                        }
                        else if (srivNum == 3)
                        {
                            options.Source = sriv;
                            Console.WriteLine("Updating Saints Row IV files.");
                        }
                        else if (srgoohNum == 3)
                        {
                            options.Source = srgooh;
                            Console.WriteLine("Updating Saints Row: Gat Out Of Hell files.");
                        }
                    }

                    if (options.Source != null)
                    {
                        break;
                    }
                }
            }


            if (options.Source == null)
            {
                Console.WriteLine("Couldn't find a Saints Row folder?");

                Console.WriteLine();
                Console.WriteLine("Press enter to exit.");
                Console.ReadLine();
                return;
            }

            string str2Dir = options.Source;

            //if (Directory.Exists(Path.Combine(options.Source, "mods")))
            //str2Dir = Path.Combine(options.Source, "mods");

            string[] str2Paths = Directory.GetFiles(str2Dir, "*.str2_pc");

            List <string> str2Files = new List <string>();

            foreach (string str2Path in str2Paths)
            {
                str2Files.Add(Path.GetFileName(str2Path));
            }

            if (str2Files.Count == 0)
            {
                Console.WriteLine("No str2_pc files found - no update needed.");

                Console.WriteLine();
                Console.WriteLine("Press enter to exit.");
                Console.ReadLine();
                return;
            }

            string packfileCache = Path.Combine(options.Source, "packfiles", "pc", "cache");

            Dictionary <string, IAssetAssemblerFile> asmsToSave = new Dictionary <string, IAssetAssemblerFile>();

            string[] packfiles = Directory.GetFiles(packfileCache, "*.vpp_pc");
            int      vppCount  = 0;

            foreach (string packfilePath in packfiles)
            {
                vppCount++;
                Console.WriteLine("[{0}/{1}] Checking {2}...", vppCount, packfiles.Length, Path.GetFileName(packfilePath));

                using (Stream stream = File.OpenRead(packfilePath))
                {
                    using (IPackfile packfile = Packfile.FromStream(stream, false))
                    {
                        foreach (var packedFile in packfile.Files)
                        {
                            if (Path.GetExtension(packedFile.Name) != ".asm_pc")
                            {
                                continue;
                            }

                            using (Stream asmStream = packedFile.GetStream())
                            {
                                IAssetAssemblerFile asm = AssetAssemblerFile.FromStream(asmStream);

                                foreach (var container in asm.Containers)
                                {
                                    string containerName = Path.ChangeExtension(container.Name, ".str2_pc");
                                    if (str2Files.Contains(containerName))
                                    {
                                        if (!asmsToSave.ContainsKey(packedFile.Name))
                                        {
                                            asmsToSave.Add(packedFile.Name, asm);
                                        }

                                        Console.Write(" - Updating {0} - {1}...", packedFile.Name, containerName);
                                        using (Stream str2Stream = File.OpenRead(Path.Combine(str2Dir, containerName)))
                                        {
                                            using (IPackfile str2 = Packfile.FromStream(str2Stream, true))
                                            {
                                                str2.Update(container);
                                            }
                                        }
                                        Console.WriteLine(" done.");
                                    }
                                }
                            }
                        }
                    }
                }
            }

            Console.WriteLine();

            Console.WriteLine("Writing updated asm_pc files...");
            int count = 0;

            foreach (var asmPair in asmsToSave)
            {
                count++;
                Console.Write("[{0}/{1}] Saving {2}...", count, asmsToSave.Count, asmPair.Key);
                string outPath = Path.Combine(str2Dir, asmPair.Key);

                using (Stream outStream = File.Create(outPath))
                {
                    asmPair.Value.Save(outStream);
                }
                Console.WriteLine(" done.");
            }

            Console.WriteLine("Done.");

            Console.WriteLine();
            Console.WriteLine("Press enter to exit.");
            Console.ReadLine();
        }
        static bool ClonePackfile(IGameInstance sriv, string packfileName, string clothSimFilename, string outputFolder, IAssetAssemblerFile newAsm, string oldName, string newName, string newStr2Filename)
        {
            using (Stream oldStream = sriv.OpenPackfileFile(packfileName))
            {
                if (oldStream == null)
                {
                    return(false);
                }

                IContainer oldContainer = FindContainer(sriv, packfileName);
                if (oldContainer == null)
                {
                    return(false);
                }

                oldContainer.Name = Path.GetFileNameWithoutExtension(newStr2Filename);

                using (IPackfile oldPackfile = Packfile.FromStream(oldStream, true))
                {
                    using (IPackfile newPackfile = Packfile.FromVersion(0x0A, true))
                    {
                        newPackfile.IsCompressed = true;
                        newPackfile.IsCondensed  = true;

                        Stream pegStream = null;

                        var pegEntry = FindPackfileEntry(oldPackfile, ".cpeg_pc");
                        if (pegEntry != null)
                        {
                            pegStream = ProcessPeg(pegEntry, newName);
                        }


                        foreach (var file in oldPackfile.Files)
                        {
                            string     extension = Path.GetExtension(file.Name);
                            IPrimitive primitive = FindPrimitive(oldContainer, file.Name);

                            switch (extension)
                            {
                            case ".ccmesh_pc":
                            {
                                Stream newCcmeshStream = ProcessCCMesh(file, oldName, newName);
                                string newMeshName     = newName + extension;
                                newPackfile.AddFile(newCcmeshStream, newMeshName);
                                primitive.Name = newMeshName;
                                break;
                            }

                            case ".cpeg_pc":
                            {
                                string newPegName = newName + extension;

                                newPackfile.AddFile(pegStream, newPegName);
                                primitive.Name = newPegName;
                                break;
                            }

                            case ".cmorph_pc":
                            {
                                string morphSuffix = Path.GetFileNameWithoutExtension(file.Name).Split('_').Last();

                                string newFilename = newName + "_" + morphSuffix + extension;

                                Stream fStream = file.GetStream();
                                // copy the morph to the output folder (fixes some odd issues with the morph not applying when loaded from save)
                                using (Stream s = File.Create(Path.Combine(outputFolder, newFilename)))
                                {
                                    fStream.CopyTo(s);
                                }

                                fStream.Seek(0, SeekOrigin.Begin);

                                newPackfile.AddFile(fStream, newFilename);
                                primitive.Name = newFilename;
                                break;
                            }

                            case ".sim_pc":
                            {
                                string newFilename = newName + extension;
                                Stream newStream   = ProcessClothSim(file, newName);
                                newPackfile.AddFile(newStream, newFilename);
                                primitive.Name = newFilename;
                                break;
                            }

                            case ".gcmesh_pc":
                            case ".gpeg_pc":
                            case ".rig_pc":
                            {
                                string newFilename = newName + extension;
                                newPackfile.AddFile(file.GetStream(), newFilename);
                                if (primitive != null)
                                {
                                    primitive.Name = newFilename;
                                }
                                break;
                            }

                            default:
                                throw new Exception(String.Format("Unrecognised extension: {0}", extension));
                            }
                        }

                        newAsm.Containers.Add(oldContainer);

                        using (Stream s = File.Create(newStr2Filename))
                        {
                            newPackfile.Save(s);
                        }

                        newPackfile.Update(oldContainer);
                    }
                }
            }

            return(true);
        }
        static void Main(string[] args)
        {
            if (args.Length < 3)
            {
                Console.WriteLine("Usage:");
                Console.WriteLine("EditPackfile <source> <destination> <new file 1> <new file 2>...");
                return;
            }

            string sourcePath      = args[0];
            string destinationPath = args[1];

            List <string> newFiles = new List <string>();

            for (int i = 2; i < args.Length; i++)
            {
                newFiles.Add(args[i]);
            }

            string sourceExtension = Path.GetExtension(sourcePath);
            bool   sourceIsStr2    = sourceExtension.ToLowerInvariant() == ".str2_pc";

            Dictionary <string, NewFileEntry> filenameToPathMap = new Dictionary <string, NewFileEntry>(StringComparer.OrdinalIgnoreCase);

            foreach (string newFile in newFiles)
            {
                filenameToPathMap.Add(Path.GetFileName(newFile), new NewFileEntry(newFile));
            }

            using (Stream sourceStream = File.OpenRead(sourcePath))
            {
                using (IPackfile source = Packfile.FromStream(sourceStream, sourceIsStr2))
                {
                    using (IPackfile destination = Packfile.FromVersion(source.Version, sourceIsStr2))
                    {
                        destination.IsCompressed = source.IsCompressed;
                        destination.IsCondensed  = source.IsCondensed;

                        foreach (IPackfileEntry entry in source.Files)
                        {
                            string filename = entry.Name;
                            if (filenameToPathMap.ContainsKey(filename))
                            {
                                NewFileEntry newFilePath = filenameToPathMap[filename];
                                destination.AddFile(File.OpenRead(newFilePath.Path), entry.Name);
                                newFilePath.Inserted = true;
                                Console.WriteLine("Replaced {0}.", filename);
                            }
                            else
                            {
                                destination.AddFile(entry.GetStream(), entry.Name);
                            }
                        }

                        foreach (var pair in filenameToPathMap)
                        {
                            NewFileEntry nfe = pair.Value;
                            if (!nfe.Inserted)
                            {
                                string filename = Path.GetFileName(nfe.Path);
                                destination.AddFile(File.OpenRead(nfe.Path), filename);
                                Console.WriteLine("Inserted {0}.", filename);
                            }
                        }

                        using (Stream destinationStream = File.Create(destinationPath))
                        {
                            destination.Save(destinationStream);
                        }
                    }
                }
            }

#if DEBUG
            Console.ReadLine();
#endif
        }
        static void Main(string[] args)
        {
            Options options = null;

            try
            {
                options = CommandLine.Parse <Options>();
            }
            catch (CommandLineException exception)
            {
                Console.WriteLine(exception.ArgumentHelp.Message);
                Console.WriteLine();
                Console.WriteLine(exception.ArgumentHelp.GetHelpText(Console.BufferWidth));

#if DEBUG
                Console.ReadLine();
#endif
                return;
            }

            Directory.CreateDirectory(options.Output);

            string[] files = Directory.GetFiles(options.Source);

            Dictionary <string, IPackfile> packfiles = new Dictionary <string, IPackfile>();

            int totalFiles = 0;

            Console.Write("Looking for packfiles... ");

            foreach (string file in files)
            {
                if (Path.GetExtension(file) == ".vpp_pc")
                {
                    var packfile = Packfile.FromStream(File.OpenRead(file), false);
                    totalFiles += packfile.Files.Count;
                    packfiles.Add(Path.GetFileName(file), packfile);
                }
            }

            Console.WriteLine("found {0} packfiles, containing {1} files.", packfiles.Count, totalFiles);

            int currentFile = 0;

            foreach (var packfilePair in packfiles)
            {
                Console.WriteLine("{0} Compressed: {1} Condensed: {2}", packfilePair.Key, packfilePair.Value.IsCompressed, packfilePair.Value.IsCondensed);
                Directory.CreateDirectory(Path.Combine(options.Output, packfilePair.Key));
                foreach (var file in packfilePair.Value.Files)
                {
                    currentFile++;
                    if (Path.GetExtension(file.Name) == ".str2_pc")
                    {
                        string strOutputFolder = Path.Combine(options.Output, packfilePair.Key, file.Name);
                        Directory.CreateDirectory(strOutputFolder);
                        Console.WriteLine("[{0}/{1}] Extracting {2}: packfile {3} to {4}:", currentFile, totalFiles, packfilePair.Key, file.Name, strOutputFolder);
                        using (Stream strStream = file.GetStream())
                        {
                            using (var strPackfile = Packfile.FromStream(strStream, true))
                            {
                                int strCurrentFile = 0;

                                foreach (var strFile in strPackfile.Files)
                                {
                                    strCurrentFile++;

                                    Console.Write("[{0}/{1}] [{2}/{3}] Extracting {4}\\{5}: {6}", currentFile, totalFiles, strCurrentFile, strPackfile.Files.Count, packfilePair.Key, file.Name, strFile.Name);
                                    using (Stream outputStream = File.Create(Path.Combine(strOutputFolder, strFile.Name)))
                                    {
                                        using (Stream inputStream = strFile.GetStream())
                                        {
                                            inputStream.CopyTo(outputStream);
                                        }
                                        outputStream.Flush();
                                    }
                                    Console.WriteLine("done.");
                                }
                            }
                        }
                    }
                    else
                    {
                        Console.Write("[{0}/{1}] Extracting {2}: {3}... ", currentFile, totalFiles, packfilePair.Key, file.Name);
                        using (Stream outputStream = File.Create(Path.Combine(options.Output, packfilePair.Key, file.Name)))
                        {
                            using (Stream inputStream = file.GetStream())
                            {
                                inputStream.CopyTo(outputStream);
                            }
                            outputStream.Flush();
                        }
                        Console.WriteLine("done.");
                    }
                }
            }

#if DEBUG
            Console.ReadLine();
#endif
        }
        static void Main(string[] args)
        {
            Options options = null;

            try
            {
                options = CommandLine.Parse <Options>();
            }
            catch (CommandLineException exception)
            {
                Console.WriteLine(exception.ArgumentHelp.Message);
                Console.WriteLine();
                Console.WriteLine(exception.ArgumentHelp.GetHelpText(Console.BufferWidth));

#if DEBUG
                Console.ReadLine();
#endif
                return;
            }


            switch (options.Action)
            {
            case "toxml":
            {
                using (Stream stream = File.OpenRead(options.Source))
                {
                    IAssetAssemblerFile file = AssetAssemblerFile.FromStream(stream);

                    if (options.Output == null || options.Output == "")
                    {
                        options.Output = Path.ChangeExtension(options.Source, "xml");
                    }

                    XmlWriterSettings settings = new XmlWriterSettings();
                    settings.Indent       = true;
                    settings.IndentChars  = "\t";
                    settings.NewLineChars = "\r\n";

                    using (XmlWriter xml = XmlWriter.Create(options.Output, settings))
                    {
                        xml.WriteStartDocument();
                        xml.WriteStartElement("AssetAssembler");
                        xml.WriteAttributeString("Version", file.Version.ToString());

                        xml.WriteStartElement("AllocatorTypes");
                        foreach (var pair in file.AllocatorTypes)
                        {
                            xml.WriteStartElement("AllocatorType");
                            xml.WriteAttributeString("ID", pair.Key.ToString());
                            xml.WriteAttributeString("Name", pair.Value);
                            xml.WriteEndElement();
                        }
                        xml.WriteEndElement();         // AllocatorTypes

                        xml.WriteStartElement("ContainerTypes");
                        foreach (var pair in file.ContainerTypes)
                        {
                            xml.WriteStartElement("ContainerType");
                            xml.WriteAttributeString("ID", pair.Key.ToString());
                            xml.WriteAttributeString("Name", pair.Value);
                            xml.WriteEndElement();
                        }
                        xml.WriteEndElement();         // ContainerTypes

                        xml.WriteStartElement("PrimitiveTypes");
                        foreach (var pair in file.PrimitiveTypes)
                        {
                            xml.WriteStartElement("PrimitiveType");
                            xml.WriteAttributeString("ID", pair.Key.ToString());
                            xml.WriteAttributeString("Name", pair.Value);
                            xml.WriteEndElement();
                        }
                        xml.WriteEndElement();         // PrimitiveTypes

                        xml.WriteStartElement("Containers");
                        foreach (var container in file.Containers)
                        {
                            xml.WriteStartElement("Container");
                            xml.WriteAttributeString("Name", container.Name);
                            xml.WriteAttributeString("Type", file.ContainerTypes[container.ContainerType]);
                            xml.WriteAttributeString("Flags", container.Flags.ToString());
                            xml.WriteAttributeString("PackfileBaseOffset", container.PackfileBaseOffset.ToString());
                            xml.WriteAttributeString("CompressionType", container.CompressionType.ToString());
                            xml.WriteAttributeString("StubContainerParentName", container.StubContainerParentName);
                            xml.WriteAttributeString("TotalCompressedPackfileReadSize", container.TotalCompressedPackfileReadSize.ToString());

                            if (container.AuxData.Length > 0)
                            {
                                xml.WriteStartElement("AuxData");
                                xml.WriteString(Convert.ToBase64String(container.AuxData, Base64FormattingOptions.None));
                                xml.WriteEndElement();         // AuxData
                            }

                            for (int i = 0; i < container.PrimitiveCount; i++)
                            {
                                var primitive = container.Primitives[i];
                                //var sizes = container.PrimitiveSizes[i];

                                xml.WriteStartElement("Primitive");

                                xml.WriteAttributeString("Name", primitive.Name);
                                xml.WriteAttributeString("Type", file.PrimitiveTypes[primitive.Type]);
                                xml.WriteAttributeString("Allocator", file.AllocatorTypes.ContainsKey(primitive.Allocator) ? file.AllocatorTypes[primitive.Allocator] : primitive.Allocator.ToString());
                                xml.WriteAttributeString("Flags", primitive.Flags.ToString());
                                xml.WriteAttributeString("ExtensionIndex", primitive.ExtensionIndex.ToString());
                                xml.WriteAttributeString("CPUSize", primitive.CPUSize.ToString());
                                xml.WriteAttributeString("GPUSize", primitive.GPUSize.ToString());
                                xml.WriteAttributeString("AllocationGroup", primitive.AllocationGroup.ToString());

                                //xml.WriteAttributeString("WriteTimeCPUSize", sizes.CPUSize.ToString());
                                //xml.WriteAttributeString("WriteTimeGPUSize", sizes.GPUSize.ToString());

                                xml.WriteEndElement();         // Primitive
                            }

                            xml.WriteEndElement();         // Container
                        }

                        xml.WriteEndElement();         // Containers

                        xml.WriteEndElement();         // AssetAssembler
                        xml.WriteEndDocument();
                    }
                }
                break;
            }

            case "toasm":
            {
                using (Stream stream = File.OpenRead(options.Source))
                {
                    XDocument xml     = XDocument.Load(stream);
                    var       asmNode = xml.Element("AssetAssembler");
                    uint      version = uint.Parse(asmNode.Attribute("Version").Value);

                    IAssetAssemblerFile file = AssetAssemblerFile.Create(version);

                    if (options.Output == null || options.Output == "")
                    {
                        options.Output = Path.ChangeExtension(options.Source, "asm_pc");
                    }

                    Dictionary <string, byte> allocatorTypesLookup = new Dictionary <string, byte>();
                    Dictionary <string, byte> containerTypesLookup = new Dictionary <string, byte>();
                    Dictionary <string, byte> primitiveTypesLookup = new Dictionary <string, byte>();

                    foreach (var node in xml.Descendants("AllocatorType"))
                    {
                        byte   id   = byte.Parse(node.Attribute("ID").Value);
                        string name = node.Attribute("Name").Value;
                        allocatorTypesLookup.Add(name, id);
                        file.AllocatorTypes.Add(id, name);
                    }

                    foreach (var node in xml.Descendants("ContainerType"))
                    {
                        byte   id   = byte.Parse(node.Attribute("ID").Value);
                        string name = node.Attribute("Name").Value;
                        containerTypesLookup.Add(name, id);
                        file.ContainerTypes.Add(id, name);
                    }

                    foreach (var node in xml.Descendants("PrimitiveType"))
                    {
                        byte   id   = byte.Parse(node.Attribute("ID").Value);
                        string name = node.Attribute("Name").Value;
                        primitiveTypesLookup.Add(name, id);
                        file.PrimitiveTypes.Add(id, name);
                    }

                    foreach (var cNode in xml.Descendants("Container"))
                    {
                        IContainer container = file.CreateContainer();
                        container.Name                            = cNode.Attribute("Name").Value;
                        container.ContainerType                   = containerTypesLookup[cNode.Attribute("Type").Value];
                        container.Flags                           = (ContainerFlags)ushort.Parse(cNode.Attribute("Flags").Value);
                        container.PackfileBaseOffset              = uint.Parse(cNode.Attribute("PackfileBaseOffset").Value);
                        container.CompressionType                 = byte.Parse(cNode.Attribute("CompressionType").Value);
                        container.StubContainerParentName         = cNode.Attribute("StubContainerParentName").Value;
                        container.TotalCompressedPackfileReadSize = int.Parse(cNode.Attribute("TotalCompressedPackfileReadSize").Value);
                        var auxData = cNode.Element("AuxData");
                        if (auxData != null)
                        {
                            container.AuxData = Convert.FromBase64String(auxData.Value);
                        }
                        else
                        {
                            container.AuxData = new byte[0];
                        }

                        foreach (var pNode in cNode.Descendants("Primitive"))
                        {
                            IPrimitive p = container.CreatePrimitive();
                            p.Name = pNode.Attribute("Name").Value;
                            p.Type = primitiveTypesLookup[pNode.Attribute("Type").Value];
                            byte allocatorType = 0;
                            if (byte.TryParse(pNode.Attribute("Allocator").Value, out allocatorType))
                            {
                                p.Allocator = allocatorType;
                            }
                            else
                            {
                                p.Allocator = allocatorTypesLookup[pNode.Attribute("Allocator").Value];
                            }
                            p.Flags           = byte.Parse(pNode.Attribute("Flags").Value);
                            p.ExtensionIndex  = byte.Parse(pNode.Attribute("ExtensionIndex").Value);
                            p.CPUSize         = uint.Parse(pNode.Attribute("CPUSize").Value);
                            p.GPUSize         = uint.Parse(pNode.Attribute("GPUSize").Value);
                            p.AllocationGroup = byte.Parse(pNode.Attribute("AllocationGroup").Value);
                            container.Primitives.Add(p);
                        }

                        container.PrimitiveCount = (short)container.Primitives.Count;
                        file.Containers.Add(container);
                    }

                    using (Stream outputStream = File.Create(options.Output))
                    {
                        file.Save(outputStream);
                    }
                }
                break;
            }

            case "update":
            {
                IAssetAssemblerFile file = null;
                using (Stream stream = File.OpenRead(options.Source))
                {
                    file = AssetAssemblerFile.FromStream(stream);

                    string folder = Path.GetDirectoryName(options.Source);

                    foreach (var container in file.Containers)
                    {
                        string str2File = Path.ChangeExtension(container.Name, ".str2_pc");
                        string filename = Path.Combine(folder, str2File);
                        if (File.Exists(filename))
                        {
                            Console.Write("Found {0}, updating... ", str2File);
                            using (Stream str2Stream = File.OpenRead(filename))
                            {
                                IPackfile packfile = Packfile.FromStream(str2Stream, true);
                                packfile.Update(container);
                            }
                            Console.WriteLine("done.");
                        }
                        else
                        {
                            Console.WriteLine("Could not find {0}.", str2File);
                        }
                    }
                }

                using (Stream stream = File.Create(options.Source))
                {
                    file.Save(stream);
                }
                break;
            }

            default:
            {
                Console.WriteLine("Unrecogised action!");
                break;
            }
            }

#if DEBUG
            Console.ReadLine();
#endif
        }