Esempio n. 1
0
        public void ReadIndexFile()
        {
            files = new ConcurrentDictionary <byte[], FileEntry>(new ByteArrayComparer());

            indexFile = new IndexFile
            {
                Signature = indexFileReader.ReadFourCC(),
                Version   = indexFileReader.ReadUInt32(),
            };

            indexFileReader.Skip(512);

            indexFile.FileSize = indexFileReader.ReadUInt32();

            indexFileReader.Skip(12);

            indexFile.FileSystemInfo = indexFileReader.ReadUInt32();

            // Set to XDIA start.
            indexFileReader.BaseStream.Position = 0x240;

            indexFile.AIDX = new ArchiveIndex
            {
                Signature = indexFileReader.ReadFourCC(),
                Version   = indexFileReader.ReadUInt32(),
                GameBuild = indexFileReader.ReadUInt32()
            };

            indexFileReader.BaseStream.Position = indexFile.FileSystemInfo - 8;

            var aidxEntryCount = indexFileReader.ReadInt32() / 16;

            indexFileReader.Skip(4 + 16);

            indexFile.AIDX.Entries = new List <ArchiveIndexEntry>(aidxEntryCount - 1);

            folders = new Dictionary <uint, Tuple <SortedDictionary <uint, FolderEntry>, SortedDictionary <uint, FileEntry> > >();

            for (var i = 0; i < aidxEntryCount - 1; i++)
            {
                var entryOffset     = indexFileReader.ReadInt64();
                var entrySize       = indexFileReader.ReadInt64();
                var nextEntryOffset = indexFileReader.BaseStream.Position;

                // Skip AIDX start.
                if (entryOffset <= 0x240 || entrySize == 0 || entryOffset == (aidxEntryCount * 16))
                {
                    continue;
                }

                indexFileReader.BaseStream.Position = entryOffset;

                var aidxEntry = new ArchiveIndexEntry
                {
                    FolderEntryCount = indexFileReader.ReadUInt32(),
                    FileEntryCount   = indexFileReader.ReadUInt32()
                };

                aidxEntry.Folders = new Dictionary <uint, FolderEntry>((int)aidxEntry.FolderEntryCount);
                aidxEntry.Files   = new List <FileEntry>((int)aidxEntry.FileEntryCount);

                var lastStringLength = 0;
                var folderStringEnd  = 0L;

                var fList = new SortedDictionary <uint, FolderEntry>();

                for (var j = 0; j < aidxEntry.FolderEntryCount; j++)
                {
                    var folderEntry = new FolderEntry();

                    folderEntry.LowestLevel = indexFileReader.ReadUInt32();
                    folderEntry.Level       = indexFileReader.ReadUInt32();

                    var position = indexFileReader.BaseStream.Position;

                    indexFileReader.BaseStream.Position = entryOffset + 8 + ((aidxEntry.FolderEntryCount * 8) + (aidxEntry.FileEntryCount * 56) + lastStringLength);

                    folderEntry.Name = indexFileReader.ReadCString();

                    lastStringLength += folderEntry.Name.Length + 1;
                    folderStringEnd   = indexFileReader.BaseStream.Position;

                    indexFileReader.BaseStream.Position = position;

                    fList.Add(folderEntry.Level, folderEntry);

                    aidxEntry.Folders.Add(folderEntry.Level, folderEntry);
                }

                var fList2 = new SortedDictionary <uint, FileEntry>();

                for (var j = 0; j < aidxEntry.FileEntryCount; j++)
                {
                    var fileEntry = new FileEntry();

                    fileEntry.Index  = indexFileReader.ReadUInt32();
                    fileEntry.Option = (Constants.FileOptions)indexFileReader.ReadUInt32();

                    indexFileReader.ReadUInt32();
                    indexFileReader.ReadUInt32();

                    fileEntry.UncompressedSize = indexFileReader.ReadUInt32();

                    indexFileReader.ReadUInt32();

                    fileEntry.CompressedSize = indexFileReader.ReadUInt32();

                    indexFileReader.ReadUInt32();

                    fileEntry.Sha1 = indexFileReader.ReadBytes(20);
                    indexFileReader.ReadUInt32();

                    var position = indexFileReader.BaseStream.Position;

                    indexFileReader.BaseStream.Position = entryOffset + 8 + ((aidxEntry.FolderEntryCount * 8) + (aidxEntry.FileEntryCount * 56) + lastStringLength);

                    fileEntry.Name = indexFileReader.ReadCString();

                    lastStringLength += fileEntry.Name.Length + 1;

                    indexFileReader.BaseStream.Position = position;

                    files.TryAdd(fileEntry.Sha1, fileEntry);

                    fList2.Add(fileEntry.Index, fileEntry);
                }

                if (fList.Count > 0 || fList2.Count > 0)
                {
                    folders.Add((uint)i, Tuple.Create(fList, fList2));
                }

                indexFileReader.BaseStream.Position = nextEntryOffset;
            }
        }
Esempio n. 2
0
        public static void ExtractTmod(string file, string folder, bool createOverrideFolders, bool createYaml, Action <double> updateProgress)
        {
            var   buffer         = new byte[1048576];
            var   properties     = new Dictionary <string, string>();
            var   archiveEntries = new List <ArchiveIndexEntry>();
            ulong headerSize     = 0;

            using (var stream = File.OpenRead(file))
            {
                using (var reader = new MyBinaryReader(stream))
                {
                    headerSize = ReadProperties(properties, stream, reader);

                    // Read archive index entries (remainder of header)
                    while ((ulong)stream.Position < headerSize)
                    {
                        var entry = new ArchiveIndexEntry();
                        entry.file         = reader.ReadString();
                        entry.archiveIndex = reader.Read7BitEncodedInt();
                        entry.byteOffset   = reader.Read7BitEncodedInt();
                        entry.size         = reader.Read7BitEncodedInt();
                        entry.hash         = reader.Read7BitEncodedInt();

                        archiveEntries.Add(entry);
                    }

                    int    offset = 0, byteRead = 0;
                    double count = 0;
                    if (stream.Position != (long)headerSize)
                    {
                        stream.Position = (long)headerSize;
                    }

                    using (InflaterInputStream decompressionStream = new InflaterInputStream(stream))
                    {
                        foreach (var entry in archiveEntries.OrderBy(e => e.byteOffset))
                        {
                            updateProgress(count / archiveEntries.Count * 100d);
                            log.InfoFormat("Extracting {0}", entry.file);
                            string extractPath = Path.Combine(folder, entry.file.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar));
                            if (createOverrideFolders)
                            {
                                extractPath = Path.Combine(Path.GetDirectoryName(extractPath), TroveMod.OverrideFolder, Path.GetFileName(extractPath));
                            }
                            SettingsDataProvider.ResolveFolder(Path.GetDirectoryName(extractPath));

                            // Advance data position to the next entry offset if needed
                            while (offset < entry.byteOffset && byteRead != -1)
                            {
                                byteRead = decompressionStream.ReadByte();
                                offset++;
                            }
                            offset += SaveBytes(extractPath, stream, decompressionStream, Convert.ToInt64(headerSize) + Convert.ToInt64(entry.byteOffset), entry.size, buffer);
                        }
                    }
                }
            }

            try
            {
                if (createYaml)
                {
                    string title    = properties.ContainsKey(TitleValue) ? properties[TitleValue] : Path.GetFileNameWithoutExtension(file);
                    string yamlPath = Path.Combine(folder, SettingsDataProvider.GetSafeFilename(title) + ".yaml");
                    log.InfoFormat("Generating YAML file: {0}", yamlPath);

                    ModDetails details = new ModDetails()
                    {
                        Author      = properties[AuthorValue],
                        Title       = properties[TitleValue],
                        Notes       = properties[NotesValue],
                        PreviewPath = properties[PreviewPathValue],
                        Files       = archiveEntries.Select(e => e.file).ToList()
                    };
                    if (properties.ContainsKey(TagsValue))
                    {
                        string tags = properties[TagsValue];
                        if (!string.IsNullOrWhiteSpace(tags))
                        {
                            details.Tags = tags.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList();
                        }
                    }
                    details.SaveYamlFile(yamlPath);
                }
            }
            catch (Exception ex) { log.Error("Error generating YAML file", ex); }

            log.InfoFormat("Completed extracting files from {0}", file);
        }