예제 #1
0
        internal static void LogNkitInfo(NkitInfo imageInfo, ILog log, string id, bool isDisc)
        {
            string pfx = string.Format("NKit {0} [{1}]", isDisc ? "Disc" : "Prtn", SourceFiles.CleanseFileName(id).PadRight(4));

            log?.LogDetail(string.Format("{0}: In [{1,2:#.0} MiB] ({2} bytes), Out [{3,2:#.0} MiB] (bytes {4})", pfx, imageInfo.BytesReadSize / (double)(1024 * 1024), imageInfo.BytesReadSize.ToString(), imageInfo.BytesWriteSize / (double)(1024 * 1024), imageInfo.BytesWriteSize.ToString()));
            if (imageInfo.BytesGcz != 0)
            {
                log?.LogDetail(string.Format("{0}: GCZ Out [{1,2:#.0} MiB] ({2} bytes)", pfx, imageInfo.BytesGcz / (double)(1024 * 1024), imageInfo.BytesGcz.ToString()));
            }

            if (imageInfo.BytesJunkFiles != 0)
            {
                log?.LogDetail(string.Format("{0}: Junk Files Removed [{1,2:#.0} MiB] ({2} bytes)", pfx, imageInfo.BytesJunkFiles / (double)(1024 * 1024), imageInfo.BytesJunkFiles.ToString()));
            }

            if (imageInfo.BytesHashesData != 0 || imageInfo.BytesHashesPreservation != 0)
            {
                log?.LogDetail(string.Format("{0}: Hashes In [{1,2:#.0} MiB] ({2} bytes), Preserved [{3,2:#.0} MiB] (bytes {4})", pfx, imageInfo.BytesHashesData / (double)(1024 * 1024), imageInfo.BytesHashesData.ToString(), imageInfo.BytesHashesPreservation / (double)(1024 * 1024), imageInfo.BytesHashesPreservation.ToString()));
            }

            if (imageInfo.BytesPreservationData != 0)
            {
                log?.LogDetail(string.Format("{0}: Preservation Data [{1,2:#.0} MiB] {2} bytes", pfx, imageInfo.BytesPreservationData / (double)(1024 * 1024), imageInfo.BytesPreservationData.ToString()));
            }

            if (imageInfo.BytesPreservationDiscPadding != 0)
            {
                log?.LogDetail(string.Format("{0}: Preservation Padding [{1,2:#.0} MiB] {2} bytes", pfx, imageInfo.BytesPreservationDiscPadding / (double)(1024 * 1024), imageInfo.BytesPreservationDiscPadding.ToString()));
            }

            if (imageInfo.FilesTotal != 0 || imageInfo.FilesAligned != 0)
            {
                log?.LogDetail(string.Format("{0}: {1} Total Files, {2} aligning boundary preserved", pfx, imageInfo.FilesTotal.ToString(), imageInfo.FilesAligned.ToString()));
            }
        }
예제 #2
0
파일: NkitWriterWii.cs 프로젝트: skudi/NKit
        public void Write(Context ctx, Stream inStream, Stream outStream, Coordinator pc)
        {
            try
            {
                WiiDiscHeaderSection      hdr   = null;
                WiiPartitionHeaderSection pHdr  = null;
                string        lastPartitionId   = null;
                PartitionType lastPartitionType = PartitionType.Other;
                NCrc          crc                 = new NCrc();
                Crc           updateCrc           = new Crc();
                bool          updateRemoved       = false;
                string        updateTmpFileName   = null;
                string        updateFileName      = null;
                bool          extractingUpdate    = false;
                CryptoStream  updateCrcStream     = null;
                NStream       updateTarget        = null;
                CryptoStream  target              = null;
                MemorySection removedUpdateFiller = null;
                int           preservedHashCount  = 0;

                NkitInfo nkitDiscInfo     = new NkitInfo();
                long     fstFileAlignment = -1;

                WiiPartitionSection lastPart = null;

                long dstPos = 0;

                long   imageSize = pc.OutputSize;                 //for Wii: pHdr.PartitionDataLength
                string ignoreJunkId;
                pc.WriterCheckPoint1WriteReady(out ignoreJunkId); //wait until read has written the header and set the length

                NDisc disc = new NDisc(_log, inStream);

                foreach (IWiiDiscSection s in disc.EnumerateSections(imageSize)) //no fixing, image should be good //ctx.ImageLength
                {
                    if (s is WiiDiscHeaderSection)
                    {
                        hdr = (WiiDiscHeaderSection)s;
                        hdr.Write8(0x60, 1);
                        hdr.Write8(0x61, 1);

                        fstFileAlignment = ctx?.Settings?.PreserveFstFileAlignment?.FirstOrDefault(a => a.Item1 == hdr.Id8)?.Item2 ?? -1;

                        target = new CryptoStream(outStream, crc, CryptoStreamMode.Write);
                        target.Write(hdr.Data, 0, hdr.Data.Length); //write the header
                        nkitDiscInfo.BytesData += hdr.Size;
                        dstPos += hdr.Size;

                        crc.Snapshot("Disc Header");
                    }
                    else if (s is WiiPartitionSection)
                    {
                        WiiPartitionSection ps     = (WiiPartitionSection)s;
                        WiiHashStore        hashes = new WiiHashStore(ps.PartitionDataLength);
                        ScrubManager        scrub  = ps.Header.ScrubManager;

                        NkitInfo nkitPartInfo = new NkitInfo();

                        if (ps.Header.Type == PartitionType.Update && ctx.Settings.NkitUpdatePartitionRemoval && hdr.Partitions.Count() > 1) //only remove update if there's more partitions
                        {
                            updateRemoved    = true;
                            extractingUpdate = true;

                            pHdr             = ps.Header;
                            extractingUpdate = true;
                            updateCrcStream  = new CryptoStream(ByteStream.Zeros, updateCrc, CryptoStreamMode.Write);
                            crc.Initialize();
                            nkitPartInfo.BytesData += disc.WriteRecoveryPartitionData(updateCrcStream, false, ps, 0, out updateTmpFileName, out updateFileName, out updateTarget);
                            _log?.LogDetail(string.Format("Extracted and Removed {0} Recovery Partition: [{1}]", ps.Header.Type.ToString(), SourceFiles.CleanseFileName(ps.Header.Id).PadRight(4)));
                            removedUpdateFiller = new MemorySection(new byte[0x8000]);
                            removedUpdateFiller.Write(0, hdr.Read(0x40000, 0x100)); //backup the original partition table in case it's non standard in some way
                        }
                        else
                        {
                            target.Write(ps.Header.Data, 0, (int)ps.Header.Size);
                            nkitDiscInfo.BytesData += ps.Header.Size;

                            crc.Snapshot(ps.Id + " Hdr");
                            crc.Crcs.Last().PatchData = ps.Header.Data;
                            dstPos          += ps.Header.Size;
                            ps.NewDiscOffset = dstPos;

                            //long written = 0;
                            using (StreamCircularBuffer decrypted = new StreamCircularBuffer(ps.PartitionDataLength, null, null, output =>
                            {
                                //read decrypted partition
                                foreach (WiiPartitionGroupSection pg in ps.Sections)
                                {
                                    nkitPartInfo.BytesHashesData += (pg.Size / 0x8000 * 0x400); //size of input hashes

                                    if (pg.PreserveHashes())
                                    {
                                        nkitPartInfo.BytesHashesPreservation += hashes.Preserve(pg.Offset, pg.Decrypted, pg.Size);
                                        if (++preservedHashCount >= 1500) //too many will bomb the patch caching when converting back. Something is wrong
                                        {
                                            throw pc.SetWriterException(new HandledException("Over 1500 hashes preserved, aborting as image is corrupt or poorly scrubbed."));
                                        }
                                    }
#if !DECRYPT
                                    for (int i = 0; i < pg.Size / 0x8000; i++)
                                    {
                                        output.Write(pg.Decrypted, (i * 0x8000) + 0x400, 0x7c00);
                                    }
#else
                                    output.Write(pg.Decrypted, 0, (int)pg.Size);
#endif
                                }
                            }))
                            {
                                long len = partitionWrite(decrypted, crc, target, ps, ctx, pc, nkitPartInfo, scrub, hashes, fstFileAlignment);
                                ps.NewPartitionDataLength = len;
                                dstPos  += len;
                                lastPart = ps;
                            }
                        }
                        NkitFormat.LogNkitInfo(nkitPartInfo, _log, ps.Id, false);

                        lastPartitionId   = ps.Id;
                        lastPartitionType = ps.Header.Type;
                    }
                    else if (s is WiiFillerSection)
                    {
                        WiiFillerSection fs    = (WiiFillerSection)s;
                        ScrubManager     scrub = new ScrubManager(null);
                        JunkStream       junk  = new JunkStream(lastPartitionType != PartitionType.Data ? hdr.ReadString(0, 4) : lastPartitionId, hdr.Read8(6), lastPartitionType == PartitionType.Update ? 0 : imageSize);

                        if (lastPartitionType == PartitionType.Update && updateRemoved)
                        {
                            //preserve the original partition table and update filename
                            target.Write(removedUpdateFiller.Data, 0, (int)removedUpdateFiller.Size); //remove update partition by adding a 32k placeholder. Avoid having a non update partition at 0x50000
                            nkitDiscInfo.BytesPreservationDiscPadding += removedUpdateFiller.Size;
                            nkitDiscInfo.BytesGaps += fs.Size;
                            dstPos += removedUpdateFiller.Size;

                            crc.Snapshot(string.Format("{0}Replacement Filler", string.IsNullOrEmpty(lastPartitionId) ? "" : (" " + SourceFiles.CleanseFileName(lastPartitionId).PadRight(4))));
                            if (extractingUpdate)
                            {
                                int storeType;
                                if ((storeType = disc.WriteRecoveryPartitionFiller(updateCrcStream, junk, fs.DiscOffset, true, true, fs, updateTarget, updateTmpFileName, ref updateFileName, updateCrc, true)) != 0)
                                {
                                    _log.LogDetail(string.Format("{0}Update recovery partition stored: {1}", storeType == 2 ? "Other " : "", updateFileName));
                                }
                                extractingUpdate = false;
                            }
                        }
                        else
                        {
                            if (fs.Size != 0)
                            {
                                using (StreamCircularBuffer filler = new StreamCircularBuffer(fs.Size, null, null, output =>
                                {
                                    foreach (WiiFillerSectionItem item in ((WiiFillerSection)s).Sections)
                                    {
                                        output.Write(item.Data, 0, (int)item.Size);
                                    }
                                }))
                                {
                                    Gap  gap    = new Gap(fs.Size, false);
                                    long srcPos = fs.DiscOffset;
                                    long gapLen = gap.Encode(filler, ref srcPos, lastPartitionType == PartitionType.Update ? fs.Size : 0x1cL, fs.Size, junk, scrub, target, _log);
                                    nkitDiscInfo.BytesPreservationData += gapLen;
                                    nkitDiscInfo.BytesGaps             += fs.Size;
                                    dstPos += gapLen;
                                    if (lastPart != null)
                                    {
                                        lastPart.NewPartitionDataLength += gapLen;
                                    }
                                }
                            }
                            //pad partition to 32k
                            int gapLen2 = (int)(dstPos % 0x8000 == 0 ? 0 : 0x8000 - (dstPos % 0x8000));
                            ByteStream.Zeros.Copy(target, gapLen2);
                            nkitDiscInfo.BytesPreservationDiscPadding += gapLen2;
                            dstPos += gapLen2;
                            if (lastPart != null)
                            {
                                lastPart.NewPartitionDataLength += gapLen2;
                            }

                            if (lastPart != null)
                            {
                                lastPart.Header.WriteUInt32B(0x2bc, (uint)(lastPart.NewPartitionDataLength / 4)); //updates the array in the crc data
                                hdr.Partitions.First(a => a.DiscOffset == lastPart.DiscOffset).DiscOffset = (lastPart.NewDiscOffset - 0x20000);
                            }
                            crc.Snapshot(string.Format("{0}{1}Files+Filler", lastPartitionId ?? "", string.IsNullOrEmpty(lastPartitionId) ? "" : " "));
                        }
                    }
                }

                NkitFormat.LogNkitInfo(nkitDiscInfo, _log, hdr.Id, true);

                foreach (CrcItem ci in crc.Crcs.Where(a => a.PatchData != null))
                {
                    ci.PatchCrc = Crc.Compute(ci.PatchData);
                }

                NCrc readerCrcs;
                uint validationCrc;
                pc.WriterCheckPoint2Complete(out readerCrcs, out validationCrc, hdr.Data, dstPos); //wait until reader has completed and get crc patches.

                if (updateRemoved && crc.Crcs.Length > 2)                                          //freeloader wii only has update partition
                {
                    hdr.RemoveUpdatePartition(crc.Crcs[2].Offset);
                }

                hdr.UpdateOffsets();
                hdr.WriteString(0x200, 8, "NKIT v01"); //header and version
                hdr.Write8(0x60, 1);
                hdr.Write8(0x61, 1);
                hdr.WriteUInt32B(0x208, readerCrcs.FullCrc(true)); //original crc
                hdr.WriteUInt32B(0x210, (uint)(imageSize / 4L));   //ctx.ImageLength
                hdr.WriteUInt32B(0x218, updateCrc.Value);          //Update crc - Only if removed
                crc.Crcs[0].PatchCrc  = Crc.Compute(hdr.Data);
                crc.Crcs[0].PatchData = hdr.Data;
                hdr.WriteUInt32B(0x20C, CrcForce.Calculate(crc.FullCrc(true), dstPos, readerCrcs.FullCrc(true), 0x20C, 0)); //magic to force crc
                crc.Crcs[0].PatchCrc = Crc.Compute(hdr.Data);                                                               //update with magic applied

                pc.WriterCheckPoint3ApplyPatches(crc, false, crc.FullCrc(true), crc.FullCrc(true), this.VerifyIsWrite, "NKit Written");
            }
            catch (Exception ex)
            {
                throw pc.SetWriterException(ex, "NkitWriterWii.Write - Convert");
            }
        }
예제 #3
0
파일: NkitWriterWii.cs 프로젝트: skudi/NKit
        private long partitionWrite(Stream inStream, NCrc crc, Stream target, WiiPartitionSection pHdr, Context ctx, Coordinator pc, NkitInfo imageInfo, ScrubManager scrub, WiiHashStore hashes, long fstFileAlignment)
        {
#if DEHASH
            return(pHdr.NewPartitionDataLength = inStream.Copy(target, pHdr.PartitionDataLength, null));
#elif DECRYPT
            inStream.Copy(target, pHdr.PartitionLength, null);
            return(pHdr.NewPartitionDataLength = pHdr.PartitionDataLength);
#endif
            MemorySection hdr = MemorySection.Read(inStream, 0x440);

            //ProgressResult result = ctx.Result;
            long   mlt          = 4L;                       //GC 1L
            long   logicalSize  = pHdr.PartitionDataLength; //GC: ctx.ImageLength;
            long   physicalSize = pHdr.PartitionDataLength; //GC: result.ImageInfo.IsoSize;
            string junkId       = hdr.ReadString(0, 4);
            //bool write = true;

            List <string> addedFiles = new List <string>();

            long srcPos;
            long dstPos = 0;

            JunkStream js = new JunkStream(junkId, hdr.Read8(6), logicalSize);

            try
            {
                if (junkId == "\0\0\0\0")
                {
                    srcPos = hdr.Size;
                    imageInfo.BytesData = srcPos;
                    _log?.LogDetail("Null Partition ID, preserving partition as raw");
                    ConvertFile cf = new ConvertFile(logicalSize - hdr.Size, true) //Size isn't important for writing //result.ImageInfo.IsoSize
                    {
                        FstFile = new FstFile(null)
                        {
                            DataOffset = hdr.Size, Offset = hdr.Size, Length = 0
                        },
                    };
                    long nullsPos = 0;
                    target.Write(hdr.Data, 0, (int)hdr.Size); //0x400
                    target.Write(pHdr.Header.Data, 0x2bc, 4); //copy the original partition length
                    dstPos += 0x440 + 4 + NkitFormat.ProcessGap(ref nullsPos, cf, ref srcPos, inStream, js, true, scrub, target, _log);
                }
                else
                {
                    hdr.WriteString(0x200, 8, "NKIT v01");
                    hdr.WriteUInt32B(0x210, (uint)(pHdr.PartitionLength / mlt));

                    MemorySection   fst;
                    List <JunkDiff> junkDiffs   = new List <JunkDiff>();
                    long            mainDolAddr = hdr.ReadUInt32B(0x420) * mlt;

                    //############################################################################
                    //# READ DISC START
                    target.Write(hdr.Data, 0, (int)hdr.Size);

                    inStream.Copy(target, (hdr.ReadUInt32B(0x424) * mlt) - hdr.Size);

                    //read fst with 4 byte boundary
                    fst = MemorySection.Read(inStream, (hdr.ReadUInt32B(0x428) * mlt) + (((hdr.ReadUInt32B(0x428) * mlt) % 4 == 0 ? 0 : 4 - ((hdr.ReadUInt32B(0x428) * mlt) % 4))));
                    crc.Snapshot(junkId + " PrtHdr");
                    target.Write(fst.Data, 0, (int)fst.Size);
                    crc.Snapshot(junkId + " Fst");
                    target.Write(hashes.FlagsToByteArray(), 0, (int)hashes.FlagsLength);
                    crc.Snapshot(junkId + " HashFlags");

                    srcPos = (hdr.ReadUInt32B(0x424) * mlt) + fst.Size;

                    long nullsPos = srcPos + 0x1c;
                    dstPos = srcPos + hashes.FlagsLength;

                    //create as late as possible in case id is swaped  - Dairantou Smash Brothers DX (Japan) (Taikenban), Star Wars - Rogue Squadron II (Japan) (Jitsuen-you Sample)

                    string             error;
                    List <ConvertFile> conFiles = NkitFormat.GetConvertFstFiles(inStream, physicalSize, hdr, fst, false, fstFileAlignment, out error);

                    imageInfo.BytesData = srcPos;

                    if (conFiles == null)
                    {
                        if (error != null)
                        {
                            _log?.LogDetail(error);
                        }
                        ConvertFile cf = new ConvertFile(pHdr.PartitionDataLength - srcPos, true) //Size isn't important for writing //result.ImageInfo.IsoSize
                        {
                            FstFile = new FstFile(null)
                            {
                                DataOffset = hdr.ReadUInt32B(0x424), Offset = hdr.ReadUInt32B(0x424), Length = (int)fst.Size
                            },
                        };
                        dstPos += NkitFormat.ProcessGap(ref nullsPos, cf, ref srcPos, inStream, js, true, scrub, target, _log);
                    }
                    else
                    {
                        //############################################################################
                        //# WRITE THE FILESYSTEM
                        List <ConvertFile> missing;
                        NkitFormat.NkitWriteFileSystem(ctx, imageInfo, mlt, inStream, ref srcPos, ref dstPos, hdr, fst, ref mainDolAddr, target, nullsPos, js, conFiles, out missing, scrub, pHdr.PartitionDataLength, _log);
                        dstPos += hashes.HashesToStream(target);

                        if (missing.Count != 0)
                        {
                            _log?.LogDetail(string.Format("{0} Junk File{1} Removed (Files listed in the FST, but not in the image)", missing.Count.ToString(), missing.Count == 1 ? "" : "s"));
                            foreach (ConvertFile cf in missing)
                            {
                                _log?.LogDebug(string.Format("File content is Junk {0}: {1} - Size: {2}", cf.FstFile.DataOffset.ToString("X8"), cf.FstFile.Name, cf.FstFile.Length));
                            }
                        }
                        crc.Crcs[crc.Crcs.Length - 1].PatchData = hashes.FlagsToByteArray();
                        crc.Crcs[crc.Crcs.Length - 1].PatchCrc  = Crc.Compute(crc.Crcs[crc.Crcs.Length - 2].PatchData);
                        crc.Crcs[crc.Crcs.Length - 2].PatchData = fst.Data;
                        crc.Crcs[crc.Crcs.Length - 2].PatchCrc  = Crc.Compute(fst.Data);
                    }
                }
            }
            catch (Exception ex)
            {
                throw new HandledException(ex, "NkitWriterGc.Write - Convert");
            }
            return(dstPos);
        }
예제 #4
0
        public void Write(Context ctx, Stream inStream, Stream outStream, Coordinator pc)
        {
            try
            {
                long mlt       = 1L;                               //for Wii: 4L
                long imageSize = pc.OutputSize;                    //for Wii: pHdr.PartitionDataLength
                pc.WriterCheckPoint1WriteReady(out string junkId); //wait until read has written the header and set the length

                List <string> addedFiles = new List <string>();

                NCrc crc = new NCrc();
                long srcPos;
                long dstPos = 0;

                MemorySection hdr = MemorySection.Read(inStream, 0x440);
                string        id8 = string.Concat(hdr.ReadString(0, 6), hdr.Data[6].ToString("X2"), hdr.Data[7].ToString("X2"));

                if (junkId == null)
                {
                    junkId = ctx.Settings.JunkIdSubstitutions.FirstOrDefault(a => a.Id8 == id8)?.JunkId;
                    if (junkId != null)
                    {
                        _log?.LogDetail(string.Format("Using ID {0} for junk not image ID {1}", junkId, id8.Substring(0, 4)));
                    }
                }

                if (junkId == null)
                {
                    junkId = hdr.ReadString(0, 4);
                }

                MemorySection   fst;
                List <JunkDiff> junkDiffs   = new List <JunkDiff>();
                long            mainDolAddr = hdr.ReadUInt32B(0x420) * mlt;

                long fstFileAlignment = ctx?.Settings?.PreserveFstFileAlignment?.FirstOrDefault(a => a.Item1 == id8)?.Item2 ?? -1;

                CryptoStream target = new CryptoStream(outStream, crc, CryptoStreamMode.Write);

                //############################################################################
                //# READ DISC START
                target.Write(hdr.Data, 0, (int)hdr.Size);
                crc.Snapshot("hdr.bin");

                inStream.Copy(target, (hdr.ReadUInt32B(0x424) * mlt) - hdr.Size);
                crc.Snapshot("bi2.bin, appldr.bin, main.dol");

                //read fst with 4 byte boundary
                fst = MemorySection.Read(inStream, (hdr.ReadUInt32B(0x428) * mlt) + (((hdr.ReadUInt32B(0x428) * mlt) % 4 == 0 ? 0 : 4 - ((hdr.ReadUInt32B(0x428) * mlt) % 4))));
                target.Write(fst.Data, 0, (int)fst.Size);
                crc.Snapshot("fst.bin");

                srcPos = (hdr.ReadUInt32B(0x424) * mlt) + fst.Size;

                long nullsPos = srcPos + 0x1c;
                dstPos = srcPos;

                //create as late as possible in case id is swaped  - Dairantou Smash Brothers DX (Japan) (Taikenban), Star Wars - Rogue Squadron II (Japan) (Jitsuen-you Sample)
                JunkStream         js       = new JunkStream(junkId, hdr.Read8(6), NStream.FullSizeGameCube);
                List <ConvertFile> conFiles = NkitFormat.GetConvertFstFiles(inStream, imageSize, hdr, fst, true, fstFileAlignment, out string error); //Size isn't important for writing //result.ImageInfo.IsoSize

                NkitInfo nkitInfo = new NkitInfo
                {
                    BytesData                    = srcPos,
                    BytesGaps                    = 0,
                    BytesJunkFiles               = 0,
                    BytesPreservationData        = 0,
                    BytesPreservationDiscPadding = 0
                };

                ScrubManager scrub = new ScrubManager();
                if (conFiles == null)
                {
                    if (error != null)
                    {
                        _log?.LogDetail(error);
                    }

                    ConvertFile cf = new ConvertFile(imageSize - srcPos, true) //Size isn't important for writing //result.ImageInfo.IsoSize
                    {
                        FstFile = new FstFile(null)
                        {
                            DataOffset = hdr.ReadUInt32B(0x424), Offset = hdr.ReadUInt32B(0x424), Length = (int)fst.Size
                        },
                    };
                    NkitFormat.ProcessGap(ref nullsPos, cf, ref srcPos, inStream, js, true, scrub, target, _log);
                }
                else
                {
                    //############################################################################
                    //# WRITE THE FILESYSTEM
                    NkitFormat.NkitWriteFileSystem(ctx, nkitInfo, mlt, inStream, ref srcPos, ref dstPos, hdr, fst, ref mainDolAddr, target, nullsPos, js, conFiles, out List <ConvertFile> missing, scrub, imageSize, _log);
                    if (missing.Count != 0)
                    {
                        _log?.LogDetail(string.Format("{0} Junk File{1} Removed (Files listed in the FST, but not in the image)", missing.Count.ToString(), missing.Count == 1 ? "" : "s"));
                        foreach (ConvertFile cf in missing)
                        {
                            _log?.LogDebug(string.Format("File content is Junk {0}: {1} - Size: {2}", cf.FstFile.DataOffset.ToString("X8"), cf.FstFile.Name, cf.FstFile.Length));
                        }
                    }
                }

                if (dstPos % 0x800 != 0)
                {
                    long l = 0x800 - (dstPos % 0x800);
                    ByteStream.Zeros.Copy(target, l);
                    dstPos += l;
                    nkitInfo.BytesPreservationDiscPadding += l;
                }
                crc.Snapshot("files");

                NkitFormat.LogNkitInfo(nkitInfo, _log, hdr.ReadString(0, 4), true);

                pc.WriterCheckPoint2Complete(out NCrc readerCrcs, out uint validationCrc, hdr.Data, dstPos); //wait until reader has completed and get crc patches.

                hdr.WriteUInt32B(0x420, (uint)mainDolAddr);

                hdr.WriteString(0x200, 8, "NKIT v01");             //header and version
                hdr.WriteUInt32B(0x208, readerCrcs.FullCrc(true)); //original crc
                hdr.WriteUInt32B(0x210, (uint)imageSize);          //result.ImageInfo.IsoSize);
                hdr.WriteString(0x214, 4, hdr.ReadString(0, 4) != junkId ? junkId : "\0\0\0\0");

                crc.Crcs[0].PatchCrc  = Crc.Compute(hdr.Data);
                crc.Crcs[0].PatchData = hdr.Data;
                crc.Crcs[2].PatchCrc  = Crc.Compute(fst.Data);
                crc.Crcs[2].PatchData = fst.Data;

                hdr.WriteUInt32B(0x20C, CrcForce.Calculate(crc.FullCrc(true), dstPos, readerCrcs.FullCrc(true), 0x20C, 0)); //magic to force crc
                crc.Crcs[0].PatchCrc = Crc.Compute(hdr.Data);

                pc.WriterCheckPoint3ApplyPatches(crc, false, crc.FullCrc(true), crc.FullCrc(true), VerifyIsWrite, "NKit Written");
            }
            catch (Exception ex)
            {
                throw pc.SetWriterException(ex, "NkitWriterGc.Write - Convert");
            }
        }
예제 #5
0
        internal static void NkitWriteFileSystem(Context ctx, NkitInfo imageInfo, long mlt, Stream inStream, ref long srcPos, ref long dstPos, MemorySection hdr, MemorySection fst, ref long mainDolAddr, Stream target, long nullsPos, JunkStream js, List <ConvertFile> conFiles, out List <ConvertFile> missingFiles, ScrubManager scrub, long imageSize, ILog log)
        {
            FstFile ff;
            //########### FILES
            bool        firstFile = true;
            ConvertFile lastf     = conFiles.Last();
            ConvertFile prevf     = null;

            missingFiles = new List <ConvertFile>();

            foreach (ConvertFile f in conFiles) //read the files and write them out as goodFiles (possible order difference
            {
                ff = f.FstFile;

                if (!firstFile)
                {
                    if (srcPos == mainDolAddr && mainDolAddr == (hdr.ReadUInt32B(0x420) * mlt))
                    {
                        mainDolAddr = dstPos; //main/default.dol is moving
                    }

                    //Debug.WriteLine(string.Format(@"{5} : {0} : {1} : {2} : {3}/{4}", ff.DataOffset.ToString("X8"), (ff.DataOffset + ff.Length).ToString("X8"), /*(nextFile.DataOffset - lastEnd).ToString("X8"),*/ ff.Length.ToString("X8"), ff.Path, ff.Name, ff.OffsetInFstFile.ToString("X8")));

                    //srcPos aligned at 32k and the length is 32k (audio file) ensure new dest is also aligned
                    if (f.Alignment == 0 || (f.Alignment != -1 && dstPos % f.Alignment != 0)) //XGIII audio in race, Zelda collection games for TGC
                    {
                        long pad;
                        if (f.Alignment == 0) //no shrinking
                        {
                            pad = Math.Max(0, ff.DataOffset - dstPos);
                        }
                        else //align
                        {
                            pad = (int)(dstPos % f.Alignment == 0 ? 0 : f.Alignment - (dstPos % f.Alignment));
                        }

                        imageInfo.FilesAligned += 1;
                        ByteStream.Zeros.Copy(target, pad);
                        imageInfo.BytesPreservationDiscPadding += pad;
                        dstPos += pad;
                    }

                    fst.WriteUInt32B(ff.OffsetInFstFile, (uint)(dstPos / mlt));

                    //replace copy with junk test - adjust fst length to %4
                    long l = srcPos;

                    imageInfo.FilesTotal += 1;
                    long written = NkitFormat.CopyFile(ref nullsPos, f, prevf?.FstFile, target, ref srcPos, dstPos, inStream, js, imageSize, out bool missing);
                    if (missing)
                    {
                        missingFiles.Add(f);
                    }

                    dstPos += written;
                    imageInfo.BytesData += srcPos - l; //read

                    if (f.Gap.JunkFile != 0)           //encode the gap and write - pad to %4
                    {
                        imageInfo.BytesJunkFiles += f.Gap.JunkFile + (f.Gap.JunkFile % 4 == 0 ? 0 : (4 - (f.Gap.JunkFile % 4)));
                        fst.WriteUInt32B(ff.OffsetInFstFile + 4, 0); //modify size to be remainder of 4
                    }
                }

                if (f.GapLength != 0 || f.Gap.JunkFile != 0)
                {
                    long l = NkitFormat.ProcessGap(ref nullsPos, f, ref srcPos, inStream, js, firstFile || f == lastf, scrub, target, log);

                    imageInfo.BytesGaps             += f.GapLength;
                    imageInfo.BytesPreservationData += l;
                    dstPos += l;
                }

                firstFile = false;
                prevf     = f;
            }
        }