Example #1
0
        public static long CalculateRomFsSize(IList <IArchiveFileInfo> files, UPath rootDirectory)
        {
            var rootNode = RomFsDirectoryNode.Parse(files, rootDirectory);

            long totalSize = BlockSize_;

            // Calculate meta size
            totalSize += GetHashTableEntryCount(rootNode.DirectoryCount) * 4;
            totalSize += GetHashTableEntryCount(files.Count) * 4;
            totalSize += rootNode.SizeInBytes;
            totalSize += files.Sum(x => MetaData.FileEntry.Size + ((Encoding.Unicode.GetByteCount(x.FilePath.GetName()) + 3) & ~3));

            // Calculate file size
            totalSize  = (totalSize + 0xF) & ~0xF;
            totalSize += files.Sum(x => (x.FileSize + 0xF) & ~0xF);
            totalSize  = (totalSize + BlockSize_ - 1) & ~(BlockSize_ - 1);

            // Calculate hash level sizes
            var levelSize = totalSize - BlockSize_;

            for (var i = 0; i < 2; i++)
            {
                var currentLevelSize = levelSize / BlockSize_ * 0x20;
                currentLevelSize = (currentLevelSize + BlockSize_ - 1) & ~(BlockSize_ - 1);

                totalSize += currentLevelSize;

                levelSize = currentLevelSize;
            }

            return(totalSize);
        }
Example #2
0
        public static RomFsDirectoryNode Parse(IList <IArchiveFileInfo> files, UPath rootDirectory)
        {
            var root = new RomFsDirectoryNode
            {
                Name        = "/",
                Directories = new List <RomFsDirectoryNode>(),
                Files       = new List <IArchiveFileInfo>()
            };

            var directories = files.Select(x => x.FilePath.GetSubDirectory(rootDirectory.ToAbsolute()).GetDirectory()).Distinct().OrderBy(x => x).ToArray();

            foreach (var directory in directories)
            {
                var currentNode = root;
                foreach (var part in directory.Split())
                {
                    var newNode = currentNode.Directories.FirstOrDefault(x => x.Name == part);
                    if (newNode != null)
                    {
                        currentNode = newNode;
                        continue;
                    }

                    newNode = new RomFsDirectoryNode
                    {
                        _parent = currentNode,

                        Name        = part,
                        Directories = new List <RomFsDirectoryNode>(),
                        Files       = new List <IArchiveFileInfo>()
                    };
                    currentNode.Directories.Add(newNode);

                    currentNode = newNode;
                }

                foreach (var file in files.Where(x => x.FilePath.GetDirectory().ToRelative() == rootDirectory / directory.ToRelative()))
                {
                    currentNode.Files.Add(file);
                }
            }

            return(root);
        }
Example #3
0
        public static (long, long) Build(Stream input, IList <IArchiveFileInfo> files, UPath rootDirectory)
        {
            // Parse files into file tree
            var rootNode = RomFsDirectoryNode.Parse(files, rootDirectory);

            // Create MetaData Tree
            var metaData = new MetaData
            {
                DirMetaOffset = rootNode.Directories.Count <= 0 ? UnusedEntry_ : 0x18
            };

            metaData.Dirs.Add(new MetaData.DirEntry
            {
                MetaOffset          = 0,
                ParentOffset        = 0,
                NextSiblingOffset   = UnusedEntry_,
                FirstChildOffset    = rootNode.Directories.Count <= 0 ? UnusedEntry_ : 0x18,
                FirstFileOffset     = 0,
                NextDirInSameBucket = UnusedEntry_,
                Hash = CalculatePathHash(0, Encoding.Unicode.GetBytes(string.Empty)),
                Name = string.Empty
            });

            PopulateMetaData(metaData, rootNode, metaData.Dirs[0]);

            // Creating directory hash buckets
            metaData.DirHashTable = Enumerable.Repeat(0xFFFFFFFF, GetHashTableEntryCount(metaData.Dirs.Count)).ToArray();
            PopulateDirHashTable(metaData.Dirs, metaData.DirHashTable);

            // Creating file hash buckets
            metaData.FileHashTable = Enumerable.Repeat(0xFFFFFFFF, GetHashTableEntryCount(metaData.Files.Count)).ToArray();
            PopulateFileHashTable(metaData.Files, metaData.FileHashTable);

            // Write RomFs
            var romFsSizes = WriteRomFs(input, metaData);

            return(romFsSizes);
        }
Example #4
0
        /// <summary>
        /// Populates the meta data tree.
        /// </summary>
        /// <param name="metaData">The meta data to populate.</param>
        /// <param name="dir">The directory to populate the meta data with.</param>
        /// <param name="parentDir">The parent directory meta data.</param>
        private static void PopulateMetaData(MetaData metaData, RomFsDirectoryNode dir, MetaData.DirEntry parentDir)
        {
            // Adding files
            var files = dir.Files;

            for (var i = 0; i < files.Count; i++)
            {
                var newFileEntry = new MetaData.FileEntry
                {
                    MetaOffset = metaData.FileMetaOffset,
                    Hash       = CalculatePathHash((uint)parentDir.MetaOffset, Encoding.Unicode.GetBytes(files[i].FilePath.GetName())),

                    FileData = files[i].GetFileData().Result,

                    ParentDirOffset = parentDir.MetaOffset,
                    DataOffset      = metaData.FileOffset,
                    DataSize        = files[i].FileSize,
                    Name            = files[i].FilePath.GetName()
                };
                metaData.FileOffset = (metaData.FileOffset + files[i].FileSize + 0xF) & ~0xF;

                metaData.FileMetaOffset += MetaData.FileEntry.Size + files[i].FilePath.GetName().Length * 2;
                if (metaData.FileMetaOffset % 4 != 0)
                {
                    metaData.FileMetaOffset += 2;
                }

                newFileEntry.NextSiblingOffset = i + 1 == files.Count ? UnusedEntry_ : metaData.FileMetaOffset;

                metaData.Files.Add(newFileEntry);
            }

            // Adding sub directories
            var dirs           = dir.Directories;
            var metaDirIndices = new List <int>();

            for (var i = 0; i < dirs.Count; i++)
            {
                var newDirEntry = new MetaData.DirEntry
                {
                    //Parent = parentDir,

                    MetaOffset = metaData.DirMetaOffset,
                    Hash       = CalculatePathHash((uint)parentDir.MetaOffset, Encoding.Unicode.GetBytes(dirs[i].Name)),

                    ParentOffset = parentDir.MetaOffset,

                    Name = dirs[i].Name
                };

                metaData.DirMetaOffset += MetaData.DirEntry.Size + dirs[i].Name.Length * 2;
                if (metaData.DirMetaOffset % 4 != 0)
                {
                    metaData.DirMetaOffset += 2;
                }

                newDirEntry.NextSiblingOffset = i + 1 < dirs.Count ? metaData.DirMetaOffset : UnusedEntry_;

                metaData.Dirs.Add(newDirEntry);
                metaDirIndices.Add(metaData.Dirs.Count - 1);
            }

            // Adding children of sub directories
            for (var i = 0; i < dirs.Count; i++)
            {
                metaData.Dirs[metaDirIndices[i]].FirstChildOffset = dirs[i].Directories.Count > 0 ? metaData.DirMetaOffset : UnusedEntry_;
                metaData.Dirs[metaDirIndices[i]].FirstFileOffset  = dirs[i].Files.Count > 0 ? metaData.FileMetaOffset : UnusedEntry_;

                PopulateMetaData(metaData, dirs[i], metaData.Dirs[metaDirIndices[i]]);
            }
        }