Ejemplo n.º 1
0
        public CriAfs2Archive(FileStream fs, long offset)
        {
            ushort previousCueId = ushort.MaxValue;

            if (IsCriAfs2Archive(fs, offset))
            {
                this.SourceFile = fs.Name;
                long afs2FileSize = fs.Length;

                this.MagicBytes = ParseFile.ParseSimpleOffset(fs, offset, SIGNATURE.Length);
                this.Version    = ParseFile.ParseSimpleOffset(fs, offset + 4, 4);
                this.FileCount  = ParseFile.ReadUintLE(fs, offset + 8);

                // setup offset field size
                int  offsetFieldSize = this.Version[1]; // known values: 2 and 4.  4 is most common.  I've only seen 2 in 'se_enemy_gurdon_galaga_bee.acb' from Sonic Lost World.
                uint offsetMask      = 0;

                for (int j = 0; j < offsetFieldSize; j++)
                {
                    offsetMask |= (uint)((byte)0xFF << (j * 8));
                }

                if (this.FileCount > ushort.MaxValue)
                {
                    throw new FormatException(String.Format("ERROR, file count exceeds max value for ushort.  Please report this at official feedback forums (see 'Other' menu item).", fs.Name));
                }

                this.ByteAlignment = ParseFile.ReadUintLE(fs, offset + 0xC);
                this.Files         = new Dictionary <ushort, CriAfs2File>((int)this.FileCount);

                CriAfs2File dummy;

                for (ushort i = 0; i < this.FileCount; i++)
                {
                    dummy = new CriAfs2File();

                    dummy.CueId         = ParseFile.ReadUshortLE(fs, offset + (0x10 + (2 * i)));
                    dummy.FileOffsetRaw = ParseFile.ReadUintLE(fs, offset + (0x10 + (this.FileCount * 2) + (offsetFieldSize * i)));

                    // mask off unneeded info
                    dummy.FileOffsetRaw &= offsetMask;

                    // add offset
                    dummy.FileOffsetRaw += offset;  // for AFS2 files inside of other files (ACB, etc.)

                    // set file offset to byte alignment
                    if ((dummy.FileOffsetRaw % this.ByteAlignment) != 0)
                    {
                        dummy.FileOffsetByteAligned = MathUtil.RoundUpToByteAlignment(dummy.FileOffsetRaw, this.ByteAlignment);
                    }
                    else
                    {
                        dummy.FileOffsetByteAligned = dummy.FileOffsetRaw;
                    }

                    //---------------
                    // set file size
                    //---------------
                    // last file will use final offset entry
                    if (i == this.FileCount - 1)
                    {
                        dummy.FileLength = (ParseFile.ReadUintLE(fs, offset + (0x10 + (this.FileCount * 2) + ((offsetFieldSize) * i)) + offsetFieldSize) + offset) - dummy.FileOffsetByteAligned;
                    }

                    // else set length for previous cue id
                    if (previousCueId != ushort.MaxValue)
                    {
                        this.Files[previousCueId].FileLength = dummy.FileOffsetRaw - this.Files[previousCueId].FileOffsetByteAligned;
                    }

                    this.Files.Add(dummy.CueId, dummy);
                    previousCueId = dummy.CueId;
                } // for (uint i = 0; i < this.FileCount; i++)
            }
            else
            {
                throw new FormatException(String.Format("AFS2 magic bytes not found at offset: 0x{0}.", offset.ToString("X8")));
            }
        }
Ejemplo n.º 2
0
        public CriCpkDirectory GetDirectoryForItoc(FileStream fs, CriUtfTable cpkUtf, string BaseDirectoryName, long volumeBaseOffset)
        {
            ulong             currentOffset = 0;
            CriUtfTocFileInfo fileInfo      = new CriUtfTocFileInfo();
            CriAfs2File       afs2File      = new CriAfs2File();

            // get content offset and align
            ulong  contentOffset = (ulong)CriUtfTable.GetUtfFieldForRow(cpkUtf, 0, "ContentOffset");
            ushort align         = (ushort)CriUtfTable.GetUtfFieldForRow(cpkUtf, 0, "Align");

            // build direcory path
            CriCpkDirectory baseDirectory = new CriCpkDirectory(this.SourceFileName, BaseDirectoryName, String.Empty);
            CriCpkFile      tempFile;

            // read file groups
            uint   filesH    = 0;
            uint   filesL    = 0;
            object filesHObj = CriUtfTable.GetUtfFieldForRow(this.ItocUtf, 0, "FilesH"); //count of files in DataH
            object filesLObj = CriUtfTable.GetUtfFieldForRow(this.ItocUtf, 0, "FilesL"); // count of files in DataL

            if (filesHObj != null)
            {
                filesH = (uint)filesHObj;
            }

            if (filesHObj != null)
            {
                filesL = (uint)filesLObj;
            }

            if ((filesH > 0) || (filesL > 0))
            {
                Dictionary <string, CriUtfTocFileInfo> fileList = new Dictionary <string, CriUtfTocFileInfo>();

                if (filesH > 0)
                {
                    // read DataH group
                    CriUtfTable dataH = new CriUtfTable();
                    dataH.Initialize(fs, (long)CriUtfTable.GetOffsetForUtfFieldForRow(this.ItocUtf, 0, "DataH"));

                    for (int i = 0; i < dataH.Rows.GetLength(0); i++)
                    {
                        fileInfo = GetUtfItocFileInfo(dataH, i);
                        fileList.Add(fileInfo.FileName, fileInfo);
                    }
                }

                if (filesL > 0)
                {
                    // read DataL group
                    CriUtfTable dataL = new CriUtfTable();
                    dataL.Initialize(fs, (long)CriUtfTable.GetOffsetForUtfFieldForRow(this.ItocUtf, 0, "DataL"));

                    for (int i = 0; i < dataL.Rows.GetLength(0); i++)
                    {
                        fileInfo = GetUtfItocFileInfo(dataL, i);
                        fileList.Add(fileInfo.FileName, fileInfo);
                    }
                }

                // initialize current offset
                currentOffset = contentOffset;

                // populate offsets for files
                var keys = fileList.Keys.ToList();
                keys.Sort();

                foreach (string key in keys)
                {
                    // afs2 file for ACB extraction
                    afs2File               = new CriAfs2File();
                    afs2File.CueId         = Convert.ToUInt16(fileList[key].FileName); // ??? @TODO maybe key is enough?  need to check.
                    afs2File.FileOffsetRaw = volumeBaseOffset + (long)currentOffset;

                    // align offset
                    if (currentOffset % align != 0)
                    {
                        currentOffset = MathUtil.RoundUpToByteAlignment(currentOffset, align);
                    }

                    // update file info
                    fileList[key].FileOffset = (ulong)volumeBaseOffset + currentOffset;
                    fileList[key].FileName  += ".bin";

                    // afs2 file for ACB extraction
                    afs2File.FileOffsetByteAligned = (long)fileList[key].FileOffset;
                    afs2File.FileLength            = fileList[key].FileSize;

                    // increment current offset
                    currentOffset += fileList[key].FileSize;

                    // create file and add to base directory
                    tempFile = new CriCpkFile(BaseDirectoryName, this.SourceFileName, fileList[key].FileName,
                                              (long)fileList[key].FileOffset, this.VolumeBaseOffset, (long)fileList[key].FileOffset,
                                              fileList[key].FileSize, fileList[key].ExtractSize);

                    baseDirectory.FileArray.Add(tempFile);

                    // add afs2 file to ItocFiles for ACB extraction
                    this.ItocFiles.Add(afs2File.CueId, afs2File);
                } // foreach (string key in keys)
            }     // if ((filesH > 0) || (filesL > 0))


            return(baseDirectory);
        }