Esempio n. 1
0
        private void WriteTable(Stream output, CpkTable table, long tableOffset, string offsetName, string sizeName)
        {
            var tocTableSize = table.CalculateSize();
            var tocOffset    = CpkSupport.Align(tableOffset, _align);

            table.Write(output, tocOffset, _align);
            WriteAlignment(output, 0x10);

            _header.Rows[0].Set(offsetName, tocOffset);
            _header.Rows[0].Set(sizeName, (long)tocTableSize);
        }
Esempio n. 2
0
        private void WriteEtocTable(Stream output, long tableOffset)
        {
            var tocTableSize = _etocTable.CalculateSize();
            var tocOffset    = CpkSupport.Align(tableOffset, _align);

            _etocTable.Write(output, tocOffset);
            WriteAlignment(output, 0x10);

            _header.Rows[0].Set("EtocOffset", tocOffset);
            _header.Rows[0].Set("EtocSize", (long)tocTableSize);
        }
Esempio n. 3
0
        private void WriteTocTable(Stream output, IList <IArchiveFileInfo> files, long tableOffset, long fileOffset)
        {
            // Update file information
            foreach (var file in files.Cast <CpkArchiveFileInfo>())
            {
                file.Row.Set("DirName", file.FilePath.ToRelative().GetDirectory().FullName);
                file.Row.Set("FileName", file.FilePath.GetName());
                file.Row.Set("ExtractSize", (int)file.FileSize);
            }

            var tocTableSize = _tocTable.CalculateSize();
            var tocOffset    = CpkSupport.Align(tableOffset, _align);

            fileOffset = CpkSupport.Align(fileOffset, _align);
            var filePosition = fileOffset;

            // Write files and update remaining file information
            foreach (var file in files.Cast <CpkArchiveFileInfo>().OrderBy(x => x.Row.Get <int>("ID")))
            {
                // Update offset
                file.Row.Set("FileOffset", filePosition - tocOffset);

                // Write file
                output.Position = filePosition;
                var writtenSize = file.SaveFileData(output);

                while (output.Position % _align > 0)
                {
                    output.WriteByte(0);
                }

                filePosition = output.Position;

                // Update compressed size
                // HINT: This code allows for the scenario that the table size was calculated to have a const value for FileSize, instead of a row value,
                // since it works on previous data. Setting FileSize before calculating the table size however, would require
                // caching all compressed files either in memory or in a temporary file.
                // Since it is very unlikely that every compressed file has either the same size or every file is not compressed,
                // we only update the FileSize here. This gains memory efficiency over a very unlikely case of wrong table size.
                file.Row.Set("FileSize", (int)writtenSize);
            }

            // Write table
            _tocTable.Write(output, tocOffset, _align);

            // Update header
            _header.Rows[0].Set("TocOffset", (long)tocOffset);
            _header.Rows[0].Set("ContentOffset", fileOffset);
            _header.Rows[0].Set("TocSize", (long)tocTableSize);
            _header.Rows[0].Set("ContentSize", filePosition - fileOffset);
        }
Esempio n. 4
0
        public void Save(Stream output, IList <IArchiveFileInfo> files)
        {
            var  headerTableSize = _header.CalculateSize();
            long tableOffset     = headerTableSize;

            var fileOffset = tableOffset +
                             CpkSupport.Align(_tocTable?.CalculateSize() ?? 0, _align) +
                             CpkSupport.Align(_etocTable?.CalculateSize() ?? 0, _align) +
                             CpkSupport.Align(_itocTable?.CalculateSize() ?? 0, _align) +
                             CpkSupport.Align(_gtocTable?.CalculateSize() ?? 0, _align);

            // Write files and toc table
            if (_tocTable != null)
            {
                WriteTocTable(output, files, tableOffset, fileOffset);
                tableOffset = CpkSupport.Align(tableOffset, _align) + _tocTable.CalculateSize();
            }

            if (_itocTable != null)
            {
                WriteItocTable(output, files, tableOffset, fileOffset);
                tableOffset = CpkSupport.Align(tableOffset, _align) + _itocTable.CalculateSize();
            }

            if (_etocTable != null)
            {
                WriteEtocTable(output, tableOffset);
                tableOffset = CpkSupport.Align(tableOffset, _align) + _etocTable.CalculateSize();
            }

            if (_gtocTable != null)
            {
                WriteGtocTable(output, tableOffset);
                tableOffset = CpkSupport.Align(tableOffset, _align) + _gtocTable.CalculateSize();
            }

            // Write header
            _header.Write(output, 0, _align);
        }
Esempio n. 5
0
        private void WriteItocFileTable(Stream output, IList <IArchiveFileInfo> files, long tableOffset, long fileOffset)
        {
            // Update file information
            foreach (var file in files.Cast <CpkArchiveFileInfo>())
            {
                file.Row.Set("ExtractSize", (int)file.FileSize);
            }

            var tocTableSize = _itocTable.CalculateSize();
            var tocOffset    = CpkSupport.Align(tableOffset, _align);
            var filePosition = fileOffset;

            // Write files and update remaining file information
            foreach (var file in files.Cast <CpkArchiveFileInfo>().OrderBy(x => int.Parse(x.FilePath.GetNameWithoutExtension())))
            {
                // Write file
                output.Position = filePosition;
                var writtenSize = file.SaveFileData(output);

                while (output.Position % _align > 0)
                {
                    output.WriteByte(0);
                }

                filePosition = output.Position;

                // Update compressed size
                // HINT: This code allows for the scenario that the table size was calculated to have a const value for FileSize,
                // since it works on previous data. Setting FileSize before calculating the table size however, would require
                // caching all compressed files either in memory or in a temporary file.
                // Since it is very unlikely that every compressed file has either the same size or every file is not compressed,
                // we only update the FileSize here. This gains memory efficiency over a very unlikely case of wrong table size.
                file.Row.Set("FileSize", (int)writtenSize);

                // Rearrange row into correct data table
                if (writtenSize <= 0xFFFF && _dataHTable.Rows.Contains(file.Row))
                {
                    _dataHTable.Rows.Remove(file.Row);
                    _dataLTable.Rows.Add(file.Row);
                }
                else if (writtenSize >= 0x10000 && _dataLTable.Rows.Contains(file.Row))
                {
                    _dataLTable.Rows.Remove(file.Row);
                    _dataHTable.Rows.Add(file.Row);
                }
            }

            // Store written data tables
            var dataLStream = new MemoryStream();

            _dataLTable.Write(dataLStream, 0, _align, false);
            WriteAlignment(dataLStream, 0x10);

            var dataHStream = new MemoryStream();

            _dataHTable.Write(dataHStream, 0, _align, false);
            WriteAlignment(dataHStream, 0x10);

            // Update and write table
            _itocTable.Rows[0].Set("DataL", dataLStream.ToArray());
            _itocTable.Rows[0].Set("DataH", dataHStream.ToArray());
            _itocTable.Rows[0].Set("FilesL", _dataLTable.Rows.Count);
            _itocTable.Rows[0].Set("FilesH", _dataHTable.Rows.Count);

            _itocTable.Write(output, tocOffset, _align);

            // Update header
            _header.Rows[0].Set("ItocOffset", (long)tocOffset);
            _header.Rows[0].Set("ContentOffset", fileOffset);
            _header.Rows[0].Set("ItocSize", (long)tocTableSize);
            _header.Rows[0].Set("ContentSize", filePosition - fileOffset);
        }