Example #1
0
        /// <summary>
        /// Create a new ArcContainer from the given .arc file.
        /// </summary>
        /// <param name="inputStream">Stream containing the .arc file.</param>
        public ArcContainer(Stream inputStream)
        {
            EndianBinaryReader inputBinaryStream = new EndianBinaryReader(EndianBitConverter.Big, inputStream);

            if (inputBinaryStream.ReadUInt32() != ArcMagic)
            {
                throw new InvalidArcFileException("Invalid magic number.");
            }
            int rootNodeOffset          = inputBinaryStream.ReadInt32();
            int nodesAndStringTableSize = inputBinaryStream.ReadInt32();
            int dataOffset = inputBinaryStream.ReadInt32();

            // Hackily get all the nodes and the offset of the string table
            inputStream.Position = rootNodeOffset;

            U8Node rootNode = U8Node.Read(inputBinaryStream);

            U8Node[] nodes = new U8Node[rootNode.Size];
            nodes[0] = rootNode;
            for (int i = 1; i < rootNode.Size; i++)
            {
                nodes[i] = U8Node.Read(inputBinaryStream);
            }

            long stringTableBase = inputStream.Position;

            int nodeIdx = 0;

            Root = (ArcFileSystemDirectory)ParseNode(inputBinaryStream, stringTableBase, nodes, ref nodeIdx);
        }
Example #2
0
        /// <summary>
        /// Generates a ArcFileSystemEntry from a U8Node.
        /// </summary>
        /// <param name="inputBinaryStream">The input stream containing the ARC container.</param>
        /// <param name="stringTableBase">Offset in the ARC of the string table.</param>
        /// <param name="nodes">Array of all U8Nodes in the ARC.</param>
        /// <param name="nodeIdx">
        /// The index of the node to parse.
        /// This will be updated to the index of the next node in the directory.
        /// </param>
        /// <returns>The ArcFileSystemEntry corresponding to the U8Node.</returns>
        private ArcFileSystemEntry ParseNode(EndianBinaryReader inputBinaryStream, long stringTableBase,
                                             U8Node[] nodes, ref int nodeIdx)
        {
            U8Node currentNode = nodes[nodeIdx++];

            inputBinaryStream.BaseStream.Position = stringTableBase + currentNode.NameOffset;
            string name = inputBinaryStream.ReadAsciiString();

            if (currentNode.Type == U8Node.TYPE_FILE)
            {
                inputBinaryStream.BaseStream.Position = currentNode.DataOffset;
                byte[] data = inputBinaryStream.ReadBytesOrThrow(currentNode.Size);
                return(new ArcFileSystemFile(name, data));
            }
            else if (currentNode.Type == U8Node.TYPE_DIRECTORY)
            {
                ArcFileSystemDirectory dir = new ArcFileSystemDirectory(name);

                /* n.Size contains the index of the end entry in the directory.
                * Since parseNode() updates nodeIdx to the next entry in the directory,
                * we should entries until we reach the end of the directory. */
                while (nodeIdx != currentNode.Size)
                {
                    dir.Entries.Add(ParseNode(inputBinaryStream, stringTableBase, nodes, ref nodeIdx));
                }

                return(dir);
            }
            else
            {
                throw new InvalidArcFileException("Invalid node Type in ARC container.");
            }
        }
Example #3
0
        private void GenerateNodes(ArcFileSystemEntry currentEntry, List <U8Node> nodes, List <ArcFileSystemEntry> entries,
                                   ref int currentNodeId, int parentNodeId, ref int currentStringTableOffset, ref int currentDataOffset)
        {
            // Add the node and the entry to the enumeration
            U8Node node = new U8Node();

            nodes.Add(node);
            entries.Add(currentEntry);

            int thisNodeId = currentNodeId;

            currentNodeId++;

            // Reserve space for the name in the string table
            node.NameOffset           = currentStringTableOffset;
            currentStringTableOffset += currentEntry.Name.Length + 1;

            if (currentEntry is ArcFileSystemDirectory)
            {
                ArcFileSystemDirectory currentDirectory = (ArcFileSystemDirectory)currentEntry;

                foreach (ArcFileSystemEntry subEntry in currentDirectory.Entries)
                {
                    GenerateNodes(subEntry, nodes, entries, ref currentNodeId, thisNodeId, ref currentStringTableOffset, ref currentDataOffset);
                }

                node.Type       = U8Node.TYPE_DIRECTORY;
                node.DataOffset = parentNodeId;
                node.Size       = currentNodeId;
            }
            else if (currentEntry is ArcFileSystemFile)
            {
                ArcFileSystemFile currentFile = (ArcFileSystemFile)currentEntry;

                node.Type       = U8Node.TYPE_FILE;
                node.DataOffset = currentDataOffset;
                node.Size       = currentFile.Data.Length;

                currentDataOffset = PaddingUtils.Align(currentDataOffset + currentFile.Data.Length, 0x20);
            }
        }
Example #4
0
 /// <summary>
 /// Create a new ArcContainer from the contents of the given directory.
 /// </summary>
 /// <param name="inputDir">The path of the directory from which the files should be added.</param>
 public ArcContainer(string inputDir)
 {
     Root = new ArcFileSystemDirectory("", inputDir);
 }
Example #5
0
 /// <summary>
 /// Create a new empty ArcContainer.
 /// </summary>
 public ArcContainer()
 {
     Root = new ArcFileSystemDirectory("");
 }