Ejemplo n.º 1
0
 internal BaseSection(NStream stream, long discOffset, byte[] data, long size)
 {
     this.Stream     = stream;
     this.DiscOffset = discOffset;
     this.Data       = data;
     this.Size       = size;
 }
Ejemplo n.º 2
0
        internal long WriteRecoveryPartitionData(Stream crcStream, bool unscrub, WiiPartitionSection ps, int channelNo, out string tempFileName, out string fileName, out NStream output)
        {
            if (ps.Header.Type == PartitionType.Update)
            {
                fileName = string.Format("{0}_{1}_", BitConverter.ToString(ps.Header.ContentSha1).Replace("-", ""), ps.Header.IsKorean ? "K" : "N");
            }
            else
            {
                fileName = string.Format("{0}_{1}_{2}_{3}_", this.NStream.Id8, channelNo.ToString().PadLeft(2, '0'), SourceFiles.CleanseFileName(ps.Header.Id).PadRight(4), ps.Header.IsKorean ? "K" : "N");
            }
            tempFileName = Path.Combine(Settings.OtherRecoveryFilesPath, fileName + "TEMP");

            Directory.CreateDirectory(Settings.OtherRecoveryFilesPath);
            output = new NStream(File.Create(tempFileName));
            output.Write(ps.Header.Data, 0, (int)ps.Header.Size);
            crcStream.Write(ps.Header.Data, 0, (int)ps.Header.Size);
            long read = ps.Header.Size;

            foreach (WiiPartitionGroupSection pg in ps.Sections)
            {
                if (unscrub)
                {
                    pg.Unscrub(null);
                }
                output.Write(pg.Encrypted, 0, (int)pg.Size);
                crcStream.Write(pg.Encrypted, 0, (int)pg.Size);
                read = ps.Size;
            }
            return(read);
        }
Ejemplo n.º 3
0
 private void ensurePosition(NStream stream, long discOffset)
 {
     if (stream.Position != discOffset)
     {
         stream.Seek(discOffset, SeekOrigin.Begin); //stream will seek forward
     }
 }
Ejemplo n.º 4
0
        private bool applyFixes(WiiPartitionHeaderSection partHdr, NStream inStream)
        {
            bool changed = false;

            try
            {
                if (inStream.Id == "010E" && partHdr.Id == "RELS")
                {
                    _hdr.Data[0] = (byte)'4';
                    _log?.LogDetail("Disc ID swapped from 010E to 410E");
                    changed = true;
                }

                //if (inStream.Id.StartsWith("RSB") && partHdr.Id.StartsWith("HA8")) //Super Smash Brothers Brawl
                if (inStream.Id.StartsWith("RSB") && partHdr.Type != PartitionType.Update && partHdr.Type != PartitionType.Data) //Super Smash Brothers Brawl
                {
                    WiiPartitionInfo part = _hdr.Partitions.FirstOrDefault(a => a.DiscOffset == partHdr.DiscOffset);
                    if (part != null && part.Table == 0)
                    {
                        part.Table = 1; //WBM swaps this for some reason
                        //_log?.LogDetail("Fixed SSBB partition table - channel location moved");
                        _log?.LogDetail(string.Format("Fixed SSBB partition table - channel {0} moved to table 1 from 0", partHdr.Id));
                        changed = true;
                    }
                }
            }
            catch (Exception ex)
            {
                throw new HandledException(ex, "RestoreReaderWii.applyFixes");
            }
            return(changed);
        }
Ejemplo n.º 5
0
 internal BaseSection(NStream stream, long discOffset, byte[] data, long size)
 {
     Stream     = stream;
     DiscOffset = discOffset;
     Data       = data;
     Size       = size;
 }
Ejemplo n.º 6
0
        internal NDisc(ILog log, NStream nStream, string sourceFileName)
        {
            NStream        = nStream;
            SourceFileName = sourceFileName;

            _settings = new Settings(NStream.IsGameCube ? DiscType.GameCube : DiscType.Wii);

            this.Log = log;
        }
Ejemplo n.º 7
0
        public static FileSystem Parse(Stream fstData, long fstOffset, long length, string id, bool isGc)
        {
            MemorySection ms = MemorySection.Read(fstData, length);
            FstFile       ff = new FstFile(null)
            {
                Name = "fst.bin", DataOffset = fstOffset, Offset = NStream.DataToOffset(fstOffset, !isGc), IsNonFstFile = true, Length = (int)fstData.Length
            };

            return(Parse(ms, ff, id, isGc));
        }
Ejemplo n.º 8
0
        public NDisc(Converter cvt, string sourceFileName)
        {
            SourceFileName = sourceFileName;
            NStream        = cvt.NStream;
            NStream.Initialize(true);

            _settings = new Settings(NStream.IsGameCube ? DiscType.GameCube : DiscType.Wii);

            Log = cvt;
        }
Ejemplo n.º 9
0
 internal void CloseStream()
 {
     try
     {
         if (NStream != null)
         {
             NStream.Close();
         }
     }
     catch { }
 }
Ejemplo n.º 10
0
 public Converter(SourceFile sourceFile, bool cacheLogsWhileProcessing)
 {
     _inProgress = false;
     _cacheLogsWhileProcessing = cacheLogsWhileProcessing;
     _logCache          = null;
     _logCacheLock      = new Object();
     _sourceFile        = sourceFile;
     _nstream           = sourceFile.OpenNStream();
     _detailLinesOutput = 0;
     _settings          = new Settings(_nstream.IsGameCube ? DiscType.GameCube : DiscType.Wii);
 }
Ejemplo n.º 11
0
        public NDisc(ILog log, Stream stream)
        {
            NStream = (stream is NStream) ? (NStream)stream : new NStream(stream);
            if (!(stream is NStream))
            {
                NStream.Initialize(true);
            }

            _settings = new Settings(NStream.IsGameCube ? DiscType.GameCube : DiscType.Wii);

            Log = log;
        }
Ejemplo n.º 12
0
 internal WiiFillerSectionItem(NStream stream, long discOffset, byte[] data, long size, bool useBuff, JunkStream junk) : base(stream, discOffset, data, size)
 {
     _useBuff = useBuff;
     _junk    = junk;
     if (_junk != null)
     {
         _junk.Position = discOffset;
         _junkData      = new byte[this.Data.Length];
         _junk.Read(_junkData, 0, (int)base.Size);
         Array.Clear(_junkData, 0, 28);
         base.Data = _useBuff ? data : _junkData;
     }
 }
Ejemplo n.º 13
0
 internal WiiFillerSection(NStream stream, bool updatePartition, long discOffset, long size, long updateSkip, string overrideJunkId, bool generateUpdateFiller, bool generateOtherFiller, bool forceFillerJunk)
 {
     _stream               = stream;
     _buff                 = new byte[0x40000]; //junkstream block size
     _junkId               = overrideJunkId ?? stream.Id;
     this.DiscOffset       = discOffset;
     this.Size             = size;
     _srcSize              = size - updateSkip;
     _generateUpdateFiller = generateUpdateFiller || size > _srcSize;
     _generateOtherFiller  = generateOtherFiller;
     _forceFillerJunk      = forceFillerJunk;
     _updatePartiton       = updatePartition;
 }
Ejemplo n.º 14
0
        public Converter(SourceFile sourceFile, bool cacheLogsWhileProcessing)
        {
            _inProgress = false;
            _cacheLogsWhileProcessing = cacheLogsWhileProcessing;
            _logCache          = null;
            _logCacheLock      = new object();
            _sourceFile        = sourceFile;
            _nstream           = sourceFile.OpenNStream();
            _detailLinesOutput = 0;
            _settings          = new Settings(_nstream.IsGameCube ? DiscType.GameCube : DiscType.Wii);

            //IConfigurationRoot configuration = new ConfigurationBuilder()
            //    .SetBasePath(Directory.GetCurrentDirectory())
            //    .AddJsonFile("appsettings.json").Build();
        }
Ejemplo n.º 15
0
        internal WiiPartitionSection(NStream stream, WiiDiscHeaderSection header, NStream readPartitionStream, long discOffset)
        {
            _stream     = readPartitionStream;
            _discHdr    = header;
            _partialFst = 0;
            _seek       = -1;

            //calc the header
            byte[] partHdrTmp = new byte[0x400];             //read enough to get all the details we need
            _stream.Read(partHdrTmp, 0, partHdrTmp.Length);  //need to read this to get header length
            byte[] partHdrLen = new byte[4];
            Array.Copy(partHdrTmp, 0x2b8, partHdrLen, 0, 4); //location of partion header length
            long hdrLen = bigEndian(BitConverter.ToUInt32(partHdrLen, 0)) * 4;

            byte[] partHdr = new byte[hdrLen];
            Array.Copy(partHdrTmp, partHdr, partHdrTmp.Length);
            _stream.Read(partHdr, partHdrTmp.Length, partHdr.Length - partHdrTmp.Length);

            Header = new WiiPartitionHeaderSection(_discHdr, readPartitionStream, discOffset, partHdr, partHdr.Length);
            if (Header.IsRvtH)
            {
                throw new Exception("RVT-H image detected - this image type is not currently supported.");
            }

            byte[] data = new byte[GroupSize];

            //this is an awful work around that blocks are scrubbed but the wiistream can't unscrub them because the partition ID is unknown
            Dictionary <int, int> IsoDecUnscub = new Dictionary <int, int>(); //must cache this because of a dependency

            int dataLen = (int)Math.Min(data.Length, Header.PartitionSize);

            _stream.Read(data, 0, dataLen, (a, b) => IsoDecUnscub.Add(a, b)); //defer the decryption because we don't have the partition id etc

            WiiPartitionGroupSection ps = new WiiPartitionGroupSection(stream, _discHdr, Header, data, Header.DiscOffset + Header.Data.Length, dataLen, true);

            Header.Initialise(ps);

            //defered unscrubbing
            foreach (KeyValuePair <int, int> x in IsoDecUnscub)
            {
                _stream.JunkStream.Position = _stream.OffsetToData(x.Key);
                _stream.JunkStream.Read(ps.Decrypted, x.Key, x.Value);
            }
            _firstSection = ps;
        }
Ejemplo n.º 16
0
        internal WiiPartitionGroupSection(NStream stream, WiiDiscHeaderSection hdr, WiiPartitionHeaderSection partHdr, byte[] data, long discOffset, long size, bool encrypted) : base(stream, discOffset, new byte[(0x400 * 32) * 64], size)
        {
            _isIsoDec  = hdr.IsIsoDecPartition(partHdr.DiscOffset);
            _partHdr   = partHdr;
            _h3Table   = _partHdr.H3Table;
            _idx       = 0;
            _maxLength = base.Data.Length; //0x8000 per block * 64 = 0x200000

            _data = new WiiPartitionGroupEncryptionState((int)WiiPartitionSection.GroupSize, this.Key, _h3Table);

            this.IsEncrypted = encrypted || !data.Equals(0x26c, new byte[20], 0, 20);
            this.Junk        = new byte[WiiPartitionSection.GroupSize];

            _unscrubValid = new bool[64];
            _data.Populate(data, (int)size, this.IsEncrypted && !_isIsoDec, _isIsoDec, _idx);

            initialise();
        }
Ejemplo n.º 17
0
        private string getPassesLine(NStream nstream, List <Processor> passes)
        {
            StringBuilder sb = new StringBuilder();

            sb.Append(string.Format("{0} Pass{1}: ", passes.Count.ToString(), passes.Count == 1 ? "" : "es"));

            sb.AppendFormat("[{0}]", nstream.ExtensionString());

            for (int i = 0; i < passes.Count; i++)
            {
                sb.Append(" >> [");
                if (passes.Count > 1)
                {
                    sb.AppendFormat("{0}:", (i + 1).ToString());
                }
                sb.Append(passes[i].Title);
                sb.Append("]");
            }

            return(sb.ToString());
        }
Ejemplo n.º 18
0
        private static uint recurseFst(MemorySection ms, FstFolder folder, long names, uint i, string id, bool isGc)
        {
            uint   j;
            uint   hdr  = ms.ReadUInt32B((int)(12 * i));
            long   name = names + hdr & 0x00ffffffL;
            int    type = (int)(hdr >> 24);
            string nm   = ms.ReadStringToNull((int)name, Encoding.GetEncoding("shift-jis"));
            uint   size = ms.ReadUInt32B((int)(12 * i + 8));

            if (type == 1)
            {
                FstFolder f = i == 0 ? folder : new FstFolder(folder)
                {
                    Name = nm
                };
                if (i != 0)
                {
                    folder.Folders.Add(f);
                }

                for (j = i + 1; j < size;)
                {
                    j = recurseFst(ms, f, names, j, id, isGc);
                }

                return(size);
            }
            else
            {
                int  pos  = (int)(12 * i + 4);
                long doff = ms.ReadUInt32B(pos) * (isGc ? 1L : 4L); //offset in data
                size = ms.ReadUInt32B((int)(12 * i + 8));
                long off = NStream.DataToOffset(doff, !isGc);       //offset in raw partition
                folder.Files.Add(new FstFile(folder)
                {
                    DataOffset = doff, Offset = off, Length = size, Name = nm, PartitionId = id, OffsetInFstFile = pos
                });
                return(i + 1);
            }
        }
Ejemplo n.º 19
0
        public NStream OpenNStream(bool readAsDisc)
        {
            if (!File.Exists(this.FilePath))
            {
                throw new HandledException("SourceFile.Open - '{0}' does not exist.", (this.FilePath) ?? "");
            }

            Stream fs = null;

            if (!this.IsArchive)
            {
                try
                {
                    fs = this.OpenStream();
                    NStream nStream = new NStream(new StreamForward(fs, null));
                    nStream.Initialize(readAsDisc);
                    return(nStream);
                }
                catch (Exception ex)
                {
                    throw new HandledException(ex, "SourceFile.OpenNStream '{0}'", this.FilePath ?? "");
                }
            }
            else
            {
                string   arcType = "";
                IArchive archive;
                if (!this.IsSplit)
                {
                    try
                    {
                        arcType = ((this.AllFiles.Length == 0) ? "" : "multipart ") + "archive";
                        archive = ArchiveFactory.Open(this.FilePath); //handles multipart archives
                    }
                    catch (Exception ex)
                    {
                        throw new HandledException(ex, "SourceFile.OpenNStream ({0}) '{1}'", arcType, this.FilePath ?? "");
                    }
                }
                else
                {
                    try
                    {
                        arcType = "split archive";
                        fs      = this.OpenStream();
                        archive = ArchiveFactory.Open(fs); //handles multipart archives
                    }
                    catch (Exception ex)
                    {
                        throw new HandledException(ex, "SourceFile.OpenNStream ({0}) '{1}'", arcType, this.FilePath ?? "");
                    }
                }

                IArchiveEntry ent;
                string        key = "";
                try
                {
                    //zip uses / path separator rar uses \
                    int pathLen = string.IsNullOrEmpty(this.Path) ? 0 : this.Path.Length + 1;
                    ent = archive.Entries.FirstOrDefault(e => e.Key.Length == pathLen + this.Name.Length && e.Key.StartsWith(this.Path) && e.Key.EndsWith(this.Name));
                    if (ent == null)
                    {
                        throw new Exception("Open archive file entry failure");
                    }
                    key = ent.Key;
                }
                catch (Exception ex)
                {
                    throw new HandledException(ex, "SourceFile.OpenNStream ({0}) '{1}' failed to open entry '{2}'", arcType, this.FilePath ?? "", this.Name ?? "");
                }

                try
                {
                    if (ent != null)
                    {
                        NStream nStream = new NStream(new StreamForward((long)ent.Size, ent.OpenEntryStream(), archive));
                        nStream.Initialize(true);
                        return(nStream);
                    }
                }
                catch (Exception ex)
                {
                    throw new HandledException(ex, "SourceFile.OpenNStream ({0}) '{1}' failed to stream entry '{2}'", arcType, this.FilePath ?? "", key ?? "");
                }

                return(null);
            }
        }
Ejemplo n.º 20
0
        public bool Unscrub(List <JunkRedumpPatch> junkPatches)
        {
            bool changed = false;
            //bool performCheck = true; //start on the assumption last was valid as it would be hassle to work out
            List <FstFile> nulls = new List <FstFile>();

            bool good = _data.IsValid(false);                                                    //forces decrypt and hash cache build and test - does not test data in blocks matchs H0 table

            Parallel.For(0, _data.UsedBlocks, bi => _unscrubValid[bi] = _data.BlockIsValid(bi)); //test data matches H0 table

            for (int bi = 0; bi < _data.UsedBlocks; bi++)
            {
                if (!_unscrubValid[bi])
                {
                    if (_junk == null)
                    {
                        _junk = new JunkStream(_partHdr.Id, _partHdr.DiscNo, _partHdr.PartitionDataSize);
                    }

                    _junk.Position = NStream.OffsetToData(this.Offset + _data.BlockDataOffset(bi), true);
                    _junk.Read(_data.Decrypted, _data.BlockDataOffset(bi), 0x7c00);
                    _data.MarkBlockUnscrubbedAndDirty(bi);
                    changed = true;
                }
            }

            if (junkPatches != null && junkPatches.Count != 0)
            {
                foreach (JunkRedumpPatch jp in junkPatches)
                {
                    if (jp.Offset >= this.DiscOffset && jp.Offset < this.DiscOffset + this.Size)
                    {
                        Array.Copy(jp.Data, 0, _data.Decrypted, jp.Offset - this.DiscOffset, jp.Data.Length);
                        _data.MarkBlockDirty((int)((jp.Offset - this.DiscOffset) / 0x8000));  //560de532
                    }
                }
            }

            if (changed)
            {
                good = _data.IsValid(true); //true as changes were made
                if (!good)
                {
                    bool zerod = false;
                    List <Tuple <long, int, FstFile> > h3Nulls = new List <Tuple <long, int, FstFile> >(_partHdr.ScrubManager.H3Nulls);

                    if (h3Nulls.Count != 0)
                    {
                        int dataLen = (int)NStream.HashedLenToData(this.Decrypted.Length);
                        foreach (Tuple <long, int, FstFile> n in h3Nulls)
                        {
                            if (n.Item1 >= this.DataOffset && n.Item1 < this.DataOffset + dataLen)
                            {
                                int idx = (int)((n.Item1 - this.DataOffset) / 0x7c00);
                                _data.MarkBlockDirty(idx);
                                int pos = (int)NStream.DataToOffset(n.Item1 - this.DataOffset, true);
                                Array.Clear(_data.Decrypted, pos, n.Item2);
                                zerod = true;
                            }
                        }
                    }
                    if (zerod)
                    {
                        good = _data.IsValid(true);
                    }
                    if (!good)
                    {
                        this.H3Errors++;
                    }
                }
            }

            return(changed);
        }
Ejemplo n.º 21
0
        private long writeDestGap(long nullsPos, Stream dest, long pos, long size, bool firstOrLastFile, List <JunkRedumpPatch> patches, long junkStart, NStream nstream) //gap 0 == 28 null, 1 == junk, -1 == auto detect
        {
            long nulls = 0;

            long maxNulls = Math.Max(0, nullsPos - pos); //0x1cL

            //maxNulls = 0x1c;
            if (size < maxNulls) //need to test this commented if
            {
                nulls = size;
            }
            else
            {
                nulls = maxNulls;
                if (size >= 0x40000 && !firstOrLastFile)
                {
                    nulls = 0;
                    if (pos % 0x4L != 0)
                    {
                        nulls += 0x4L - pos % 0x4L; //pad to 4 byte boundary
                    }
                }
            }

            if (junkStart != 0 && junkStart > pos)
            {
                nulls = Math.Min(junkStart - pos, size);
                if (junkStart < pos + size)
                {
                    junkStart = 0; //revert to normal
                }
            }

            if (patches != null)
            {
                patches.RemoveAll(a => a.Offset < pos);
            }

            long copied = 0;

            if (nulls != 0 && (patches.Count == 0 || patches[0].Offset != pos)) //if there are strange bytes in the padding then the full padding must be replaced (no cases as yet, never used)
            {
                ByteStream.Zeros.Copy(dest, nulls);
                pos   += nulls;
                copied = nulls;
            }

            int c = 0;

            while (patches.Count != 0 && patches[0].Offset >= pos && patches[0].Offset < (pos - copied) + size)
            {
                if (patches.Count != 0 && patches[0].Offset > pos)
                {
                    nstream.JunkStream.Position = pos;
                    c = (int)(patches[0].Offset - pos);
                    nstream.JunkStream.Copy(dest, c);
                    copied += c;
                    pos    += c;
                }
                c = (int)Math.Min(size - copied, patches[0].Data.Length);
                dest.Write(patches[0].Data, 0, c);
                _log?.LogDetail(string.Format("Junk patched at 0x{0} - {1} byte{2}", patches[0].Offset.ToString("X8"), patches[0].Data.Length.ToString(), patches[0].Data.Length == 1 ? "" : "s"));
                patches.RemoveAt(0);
                copied += c;
                pos    += c;
                nulls   = copied;
            }

            if (copied < size)
            {
                nstream.JunkStream.Position = pos;
                nstream.JunkStream.Copy(dest, size - nulls);
            }

            return(size);
        }
Ejemplo n.º 22
0
        private long writeFile(ref long nullsPos, Stream dest, long dstPos, ref bool firstFile, Stream srcStream, FstFile lastFile, FstFile file, List <JunkRedumpPatch> patches, NStream nstream, long junkStart, bool isJunkFile)
        {
            //Debug.WriteLine(string.Format(@"{0} : {1} : {2} : {3}/{4}", file.DataOffset.ToString("X8"), (file.DataOffset + file.Length).ToString("X8"), /*(nextFile.DataOffset - lastEnd).ToString("X8"),*/ file.Length.ToString("X8"), file.Path, file.Name));

            //file found
            long gap = writeDestGap(nullsPos, dest, dstPos, file.DataOffset - dstPos, firstFile, patches, junkStart, nstream);

            firstFile = false;

            bool missing = false;

            if (file.Length == 0)
            {
                //    missing = true;
            }
            else if (isJunkFile)
            {
                missing = true;
                MemorySection ms = MemorySection.Read(srcStream, 8);

                long    size = ms.ReadUInt32B(0);
                GapType gt   = (GapType)(size & 0b11);
                size &= 0xFFFFFFFC;

                //set nullsPos value if zerobyte file without junk
                if (gt == GapType.JunkFile)
                {
                    nullsPos = Math.Min(nullsPos - (dstPos + gap), 0); //reset the nulls
                    long nulls       = (size & 0xFC) >> 2;
                    long junkFileLen = ms.ReadUInt32B(4);
                    if (junkFileLen != file.Length)
                    {
                        throw new HandledException(string.Format("NKit Junk file restoration length mismatch {0}: {1}", file.DataOffset.ToString("X8"), file.Name));
                    }

                    ByteStream.Zeros.Copy(dest, nulls);
                    nstream.JunkStream.Position = (dstPos + gap) + nulls;
                    nstream.JunkStream.Copy(dest, junkFileLen - nulls);
                    _log?.LogDetail(string.Format("Generated file content with Junk {0}: {1}", file.DataOffset.ToString("X8"), file.Name));
                }
                else
                {
                    throw new HandledException(string.Format("NKit Junk file restoration bytes invalid {0}: {1}", file.DataOffset.ToString("X8"), file.Name));
                }
            }
            else
            {
                byte[] f = new byte[Math.Min(0x30, file.Length)];
                srcStream.Read(f, 0, f.Length);                                     //then read while junk is created

                if (lastFile.DataOffset == file.DataOffset && lastFile.Length == 0) //null file overlapped this file so set nullsPos to have a gap (XGIII) needs fst sorting by offset then size
                {
                    nullsPos = dstPos + 0x1CL;                                      //will already be aligned
                }

                int nulls = (int)(nullsPos - (dstPos + gap));
                nstream.JunkStream.Position = file.DataOffset; //async junk gen
                int countNulls = 0;
                for (int i = 0; i < f.Length && f[i] == 0; i++)
                {
                    countNulls++;
                }

                if (f.Length > nulls && countNulls < f.Length) //don't test all nulls
                {
                    missing = nstream.JunkStream.Compare(f, 0, f.Length, Math.Max(0, nulls)) == f.Length;
                }

                if (missing)
                {
                    _log?.LogDetail(string.Format("File content is Junk {0}: {1}", file.DataOffset.ToString("X8"), file.Name));
                }

                dest.Write(f, 0, f.Length);
                srcStream.Copy(dest, file.Length - f.Length); //copy file
            }

            if (!missing) //reset the gap when no junk
            {
                nullsPos = dstPos + gap + file.Length + 0x1c;
                if (nullsPos % 4 != 0)
                {
                    nullsPos += 4 - (nullsPos % 4);
                }
            }


            return(gap + file.Length);
        }
Ejemplo n.º 23
0
        public void Read(Context ctx, NStream inStream, Stream outStream, Coordinator pc)
        {
            string resultMsg = "";

            if (!Settings.ConfigFileFound)
            {
                _log?.Log("!! No config file found - This is required to restore and validate images");
            }

            NCrc          crc        = new NCrc();
            Settings      settings   = ctx.Settings;
            List <string> addedFiles = new List <string>();

            DatData      data = ctx.Dats;
            RecoveryData rec  = ctx.Recovery;

            List <JunkRedumpPatch> patches = rec.JunkPatches;
            MemorySection          hdr     = null;

            try
            {
                long junkStart = settings.JunkStartOffsets.FirstOrDefault(a => a.Id8 == inStream.Id8)?.Offset ?? 0;

                string forceJunkId = settings.JunkIdSubstitutions.FirstOrDefault(a => a.Id8 == inStream.Id8)?.JunkId;
                if (forceJunkId != null)
                {
                    _log?.LogDetail(string.Format("Using ID {0} for junk not image ID {1}", forceJunkId, inStream.Id));
                    //result.ImageInfo.JunkId = forceJunkId;
                    inStream.ChangeJunk(forceJunkId);
                }
                if (junkStart != 0)
                {
                    _log?.LogDetail(string.Format("Junk forced to start at 0x{0}", junkStart.ToString("X8")));
                }

                hdr = inStream.DiscHeader;

                FstFileItem goodFst = rec.GcBinFiles.Where(a => a is FstFileItem).Cast <FstFileItem>().FirstOrDefault(a => a.Id8 == inStream.Id8 && !(inStream.Id8 == "GNHE5d0000" && a.Length == 116));

                if (goodFst != null)
                {
                    _log?.LogDetail(string.Format("Recovery:   {0}", goodFst.Filename));
                }

                if (goodFst == null && rec.GcNewBinFiles != null)
                {
                    goodFst = rec.GcNewBinFiles.Where(a => a is FstFileItem).Cast <FstFileItem>().FirstOrDefault(a => a.Id8 == inStream.Id8);
                }

                if (goodFst != null)
                {
                    goodFst.Populate();
                }

                ApploaderFileItem goodAldr = goodFst == null ? null : (ApploaderFileItem)rec.GcBinFiles.FirstOrDefault(a => a.Crc == goodFst.AppLoadCrc);
                if (goodAldr == null && rec.GcNewBinFiles != null)
                {
                    goodAldr = goodFst == null ? null : (ApploaderFileItem)rec.GcNewBinFiles.FirstOrDefault(a => a.Crc == goodFst.AppLoadCrc);
                }

                //is it an action replay (custom hacks)
                if ((hdr.ReadUInt32B(0x420) == 0 && inStream.Id8 == "GNHE5d0000") || inStream.Id8 == "DTLX010000" || inStream.Id8 == "102E010007")
                {
                    if (inStream.Id8 == "102E010007")
                    {
                        resultMsg = "Aging Disc detected - Skipping recover";
                    }
                    else
                    {
                        resultMsg = "Datel Action Replay detected - Skipping recover";
                    }

                    try
                    {
                        using (CryptoStream target = new CryptoStream(outStream, crc, CryptoStreamMode.Write))
                        {
                            target.Write(hdr.Data, 0, (int)hdr.Size);
                            pc.ReaderCheckPoint1PreWrite(forceJunkId, 0); //size that we will output from this read
                            inStream.Copy(target, pc.OutputSize - hdr.Size);
                        }
                        _log?.LogDetail(resultMsg);
                    }
                    catch (Exception ex)
                    {
                        throw new HandledException(ex, resultMsg);
                    }
                    crc.Snapshot("files");
                }
                else
                {
                    //############################################################################
                    //# READ DISC START

                    //########### Header (boot.bin)  0 (read by base stream already)
                    long srcPos = hdr.Size;

                    _log?.LogDetail(string.Format("Header Read: {0} - {1}", friendly(inStream.Id), friendly(inStream.Title)));

                    //########### Header Info (bi2.bin)  0x440
                    MemorySection bi2bin = MemorySection.Read(inStream, 0x2000);
                    srcPos += bi2bin.Size;

                    //########### APPLOADER (appldr.bin)  0x2440 - Action Reply can have 0 as the main.dol
                    MemorySection appldr = MemorySection.Read(inStream, Math.Min(hdr.ReadUInt32B(0x420) == 0 ? uint.MaxValue : hdr.ReadUInt32B(0x420), hdr.ReadUInt32B(0x424)) - srcPos);
                    srcPos += appldr.Size;

                    //########### APP (main.dol)
                    MemorySection maindol;
                    if (hdr.ReadUInt32B(0x420) < hdr.ReadUInt32B(0x424))
                    {
                        maindol = MemorySection.Read(inStream, hdr.ReadUInt32B(0x424) - srcPos);
                    }
                    else
                    {
                        maindol = new MemorySection(new byte[0]);
                    }

                    srcPos += maindol.Size;

                    //########### FST (fst.bin)
                    MemorySection srcFst = MemorySection.Read(inStream, hdr.ReadUInt32B(0x428));
                    srcPos += hdr.ReadUInt32B(0x428);

                    //############################################################################
                    //# CORRECT ISSUES

                    List <FstFile> srcFiles = FileSystem.Parse(srcFst, null, inStream.Id, true)?.Files?.OrderBy(a => a.Offset)?.ThenBy(a => a.Length)?.ToList();
                    if (srcFiles == null)
                    {
                        throw new HandledException(string.Format("FST Corrupt or misaligned, could not be parsed at position 0x{0}", hdr.ReadUInt32B(0x424).ToString("X8")));
                    }

                    uint crcTmp = Crc.Compute(appldr.Data, 0, Math.Min((int)appldr.Size, 0x20 + (int)(appldr.ReadUInt32B(0x14) + appldr.ReadUInt32B(0x18))));
                    //adjust appldr
                    if (goodAldr != null && crcTmp != goodAldr.Crc)
                    {
                        _log?.LogDetail(string.Format("Replacing appldr.bin crc {0} with Recovery appldr.bin {1}", crcTmp.ToString("X8"), goodAldr.Crc.ToString("X8")));
                        addedFiles.Add(goodAldr.Filename);
                        appldr = new MemorySection(File.ReadAllBytes(goodAldr.Filename));
                    }

                    //adjust main.dol
                    if (goodFst != null)
                    {
                        if (goodFst.MainDolOffset != hdr.ReadUInt32B(0x420))
                        {
                            //main.dol is before fst in image and after in goodfst
                            if (hdr.ReadUInt32B(0x420) < hdr.ReadUInt32B(0x424) && goodFst.MainDolOffset > goodFst.FstOffset)
                            {
                                _log?.LogDetail(string.Format("Skipping main.dol at 0x{0} using 0x{1}", hdr.ReadUInt32B(0x420).ToString("X8"), goodFst.MainDolOffset.ToString("X8")));
                                maindol = new MemorySection(new byte[0]);
                            }
                            else
                            {
                                _log?.LogDetail(string.Format("Moving main.dol address 0x{0} to 0x{1}", hdr.ReadUInt32B(0x420).ToString("X8"), goodFst.MainDolOffset.ToString("X8")));
                            }

                            hdr.WriteUInt32B(0x420, (uint)goodFst.MainDolOffset);
                        }

                        if (goodFst.Region != (Region)bi2bin.ReadUInt32B(0x18))
                        {
                            _log?.LogDetail(string.Format("Region Changed to {0} from {1}", goodFst.Region.ToString(), ((Region)bi2bin.ReadUInt32B(0x18)).ToString()));
                            bi2bin.WriteUInt32B(0x18, (uint)goodFst.Region);
                        }
                        if (goodFst.MaxFst != hdr.ReadUInt32B(0x42C))
                        {
                            _log?.LogDetail(string.Format("Max Fst Size changed to {0} from {1}", goodFst.MaxFst.ToString("X8"), hdr.ReadUInt32B(0x42C).ToString("X8")));
                            hdr.WriteUInt32B(0x42C, (uint)goodFst.MaxFst);
                        }
                        string newTitle = Encoding.ASCII.GetString(goodFst.Title);
                        if (newTitle != hdr.ReadString(0x20, 0x60 - 0x20))
                        {
                            _log?.LogDetail(string.Format("Title changed to '{0}' from '{1}'", newTitle.TrimEnd('\0'), hdr.ReadString(0x20, 0x60 - 0x20).TrimEnd('\0')));
                            hdr.Write(0x20, goodFst.Title);
                        }
                    }

                    MemorySection  fst      = srcFst;
                    List <FstFile> fstFiles = srcFiles;
                    crcTmp = Crc.Compute(srcFst.Data);
                    if (goodFst != null && crcTmp != goodFst.Crc)
                    {
                        _log?.LogDetail(string.Format("Replacing fst.bin crc {0} with Recovery fst {1}", crcTmp.ToString("X8"), goodFst.Crc.ToString("X8")));
                        addedFiles.Add(goodFst.Filename);
                        fst      = new MemorySection(goodFst.FstData);
                        fstFiles = FileSystem.Parse(fst, null, inStream.Id, true).Files.OrderBy(a => a.Offset).ThenBy(a => a.Length).ToList();
                    }
                    //adjust fst.bin
                    if (goodFst != null && (goodFst.FstOffset != hdr.ReadUInt32B(0x424) || goodFst.FstData.Length != hdr.ReadUInt32B(0x428)))
                    {
                        _log?.LogDetail(string.Format("Moving / Resizing fst.bin address 0x{0} (Length {1}) to 0x{2} (Length {3})", hdr.ReadUInt32B(0x424).ToString("X8"), hdr.ReadUInt32B(0x428).ToString(), goodFst.FstOffset.ToString("X8"), goodFst.FstData.Length.ToString()));
                        hdr.WriteUInt32B(0x424, (uint)goodFst.FstOffset);
                        hdr.WriteUInt32B(0x428, (uint)goodFst.FstData.Length);
                    }


                    int c;
                    int failCount     = 0;
                    int filesMoved    = 0;
                    int nkitJunkFiles = 0;
                    foreach (FstFile f in srcFiles)
                    {
                        FstFile[] fnd = fstFiles.Where(a => a.Name == f.Name && a.Path == f.Path).ToArray();
                        if (fnd.Length == 0)
                        {
                            failCount++;
                            _log?.LogDetail(string.Format("FST Error: No File Found - {0}/{1} (Length {2})", f.Path, f.Name, f.Length.ToString()));
                        }
                        else if (inStream.IsNkit && (c = fnd.Count(a => a.Length != 0 && f.Length == 0)) == 1)
                        {
                            nkitJunkFiles++;
                        }
                        else if ((c = fnd.Count(a => a.Length == f.Length)) != 1)
                        {
                            failCount++;
                            _log?.LogDetail(string.Format("FST Error: File Size bad - {0}/{1} (Length {2}){3}", f.Path, f.Name, f.Length.ToString(), c <= 1 ? "" : string.Format(" {0} files found", c.ToString())));
                        }
                        else if (f.DataOffset != fnd[0].DataOffset)
                        {
                            filesMoved++;
                        }

                        if (failCount >= 10)
                        {
                            break;
                        }
                    }
                    if (failCount != 0)
                    {
                        if (failCount >= 10)
                        {
                            throw new HandledException(string.Format("{0} or more FST errors found", failCount.ToString()));
                        }
                    }
                    if (filesMoved != 0)
                    {
                        _log?.LogDetail(string.Format("{0} file{1} of {2} will be repositioned when rebuilding this image", filesMoved.ToString(), filesMoved == 1 ? "" : "s", fstFiles.Count.ToString()));
                    }

                    if (nkitJunkFiles != 0)
                    {
                        _log?.LogDetail(string.Format("{0} file{1} of {2} will be generated from junk when rebuilding this image", nkitJunkFiles.ToString(), nkitJunkFiles == 1 ? "" : "s", fstFiles.Count.ToString()));
                    }

                    if (goodFst != null)
                    {
                        //is the data output so far correct
                        if (!bruteForceValidHeader(ctx, goodFst, hdr, bi2bin, appldr, maindol, fst, pc))
                        {
                            throw new HandledException(string.Format("Post FST Crc Failed 0x{0}", goodFst.PostFstCrc.ToString("X8")));
                        }
                    }

                    //############################################################################
                    //# WRITE DISC START
                    CryptoStream target = new CryptoStream(outStream, crc, CryptoStreamMode.Write);

                    target.Write(hdr.Data, 0, (int)hdr.Size);
                    pc.ReaderCheckPoint1PreWrite(forceJunkId, 0); //size that we will output from this read

                    long dstPos = hdr.Data.Length;
                    crc.Snapshot("boot.bin");

                    target.Write(bi2bin.Data, 0, (int)bi2bin.Size);
                    dstPos += bi2bin.Size;
                    crc.Snapshot("bi2.bin");

                    target.Write(appldr.Data, 0, (int)appldr.Size);
                    dstPos += appldr.Size;
                    ByteStream.Zeros.Copy(target, Math.Min(hdr.ReadUInt32B(0x420), hdr.ReadUInt32B(0x424)) - dstPos);
                    dstPos += Math.Min(hdr.ReadUInt32B(0x420), hdr.ReadUInt32B(0x424)) - dstPos;
                    crc.Snapshot("appldr.bin");

                    target.Write(maindol.Data, 0, (int)maindol.Size);
                    dstPos += maindol.Size;

                    if (goodFst != null)
                    {
                        long padding = goodFst.FstOffset - dstPos;
                        ByteStream.Zeros.Copy(target, padding);
                        dstPos += padding;
                    }
                    crc.Snapshot("main.dol");


                    target.Write(fst.Data, 0, fst.Data.Length);
                    dstPos += fst.Size;

                    bool firstFile = true;

                    Dictionary <FstFile, byte[]> cache = new Dictionary <FstFile, byte[]>();
                    crc.Snapshot("fst.bin");

                    //############################################################################
                    //# WRITE THE FILESYSTEM

                    int     fidx     = -1;
                    FstFile lastFile = new FstFile(null)
                    {
                        DataOffset = hdr.ReadUInt32B(0x424), Offset = hdr.ReadUInt32B(0x424), Length = fst.Size
                    };
                    FstFile nextFile  = fstFiles[++fidx];
                    FstFile cacheFile = null;

                    long nullsPos = dstPos + 0x1c;
                    if (nullsPos % 4 != 0)
                    {
                        nullsPos += 4 - (nullsPos % 4);
                    }

                    //########### FILES
                    foreach (FstFile f in srcFiles)                                                                                                                                                             //read the files and write them out as goodFiles (possible order difference)
                    {
                        while ((cacheFile = cache.Keys.FirstOrDefault(a => (a.Length == nextFile.Length || (inStream.IsNkit && a.Length == 0)) && a.Name == nextFile.Name && a.Path == nextFile.Path)) != null) //write cache
                        {
                            bool isJunk = inStream.IsNkit && cacheFile.Length == 0 && cacheFile.Name == nextFile.Name && cacheFile.Path == nextFile.Path;
                            using (MemoryStream cacheStream = new MemoryStream(cache[cacheFile]))
                            {
                                dstPos += writeFile(ref nullsPos, target, dstPos, ref firstFile, cacheStream, lastFile, nextFile, patches, inStream, junkStart, isJunk);
                            }

                            cache.Remove(cacheFile);
                            lastFile = nextFile;
                            nextFile = fidx + 1 < fstFiles.Count ? fstFiles[++fidx] : null;
                        }

                        if (f.DataOffset - srcPos > 0) //skip src junk
                        {
                            inStream.Copy(ByteStream.Zeros, f.DataOffset - srcPos);
                            srcPos += f.DataOffset - srcPos;
                        }
                        if (nextFile != null && (f.Length != nextFile.Length || f.Name != nextFile.Name || f.Path != nextFile.Path)) //cache file (nkit junk files are cached)
                        {
                            bool isNkitJunk = inStream.IsNkit && f.Length == 0 && nextFile.Length != 0 && f.Name == nextFile.Name && f.Path == nextFile.Path;

                            byte[] cacheItem = new byte[isNkitJunk ? 8 : f.Length];
                            inStream.Read(cacheItem, 0, cacheItem.Length); //read the nkit junk data - details (real length and null counts)
                            cache.Add(f, cacheItem);
                            srcPos += cacheItem.Length;
                        }
                        else //copy file
                        {
                            dstPos  += writeFile(ref nullsPos, target, dstPos, ref firstFile, inStream, lastFile, nextFile, patches, inStream, junkStart, false);
                            lastFile = nextFile;
                            nextFile = fidx + 1 < fstFiles.Count ? fstFiles[++fidx] : null;
                            srcPos  += f.Length;
                        }
                    }

                    while (nextFile != null && fidx < fstFiles.Count && (cacheFile = cache.Keys.FirstOrDefault(a => a.Length == nextFile.Length && a.Name == nextFile.Name && a.Path == nextFile.Path)) != null)
                    {
                        using (MemoryStream cacheStream = new MemoryStream(cache[cacheFile]))
                        {
                            dstPos += writeFile(ref nullsPos, target, dstPos, ref firstFile, cacheStream, lastFile, nextFile, patches, inStream, junkStart, false);
                        }

                        cache.Remove(cacheFile);
                        lastFile = nextFile;
                        nextFile = fidx + 1 < fstFiles.Count ? fstFiles[++fidx] : null;
                    }

                    writeDestGap(nullsPos, target, dstPos, pc.OutputSize - dstPos, true, patches, junkStart, inStream);

                    crc.Snapshot("files");
                }

                resultMsg = "MatchFail";
                uint finalCrc = crc.FullCrc(true);
                if (ctx.Dats.RedumpData.FirstOrDefault(a => a.Crc == finalCrc) != null)
                {
                    resultMsg = "Match Redump";
                }

                if (ctx.Dats.CustomData.FirstOrDefault(a => a.Crc == finalCrc) != null)
                {
                    resultMsg = "Match Custom";
                }

                pc.ReaderCheckPoint2Complete(crc, false, finalCrc, finalCrc, VerifyIsWrite, hdr.Data, resultMsg);
                pc.ReaderCheckPoint3Complete();
            }
            catch (Exception ex)
            {
                throw pc.SetReaderException(ex, "RestoreReaderGc.Read - Read and repair"); //don't let the writer lock
            }
        }
Ejemplo n.º 24
0
        public void Read(Context ctx, NStream inStream, Stream outStream, Coordinator pc)
        {
            NCrc crc = new NCrc();

            try
            {
                CryptoStream target    = new CryptoStream(outStream, crc, CryptoStreamMode.Write);
                uint         outputCrc = 0;

                if (inStream.IsNkit || inStream.IsGameCube || !EncryptWiiPartitions)
                {
                    pc.ReaderCheckPoint1PreWrite(null, 0); //size that we will output from this read
                    if (inStream.HeaderRead)
                    {
                        target.Write(inStream.DiscHeader.Data, 0, (int)inStream.DiscHeader.Size); //write the header
                        inStream.Copy(target, inStream.Length - inStream.DiscHeader.Size);
                    }
                    else
                    {
                        inStream.Copy(target, inStream.Length);
                    }
                }
                else
                {
                    WiiDiscHeaderSection hdr = null;
                    using (NDisc disc = new NDisc(_log, inStream))
                    {
                        foreach (IWiiDiscSection s in disc.EnumerateSections(inStream.Length)) //ctx.ImageLength
                        {
                            if (s is WiiDiscHeaderSection)
                            {
                                hdr = (WiiDiscHeaderSection)s;
                                target.Write(hdr.Data, 0, hdr.Data.Length); //write the header
                                pc.ReaderCheckPoint1PreWrite(null, 0);      //size that we will output from this read //ctx.ImageLength
                            }
                            else if (s is WiiPartitionSection)
                            {
                                WiiPartitionSection ps = (WiiPartitionSection)s;
                                //bool lengthChanged = inStream.CheckLength(ps.DiscOffset, ps.Header.PartitionSize);

                                target.Write(ps.Header.Data, 0, (int)ps.Header.Size);
                                foreach (WiiPartitionGroupSection pg in ps.Sections)
                                {
                                    target.Write(pg.Encrypted, 0, (int)pg.Size);
                                }
                            }
                            else if (s is WiiFillerSection)
                            {
                                WiiFillerSection fs = (WiiFillerSection)s;
                                if (fs.Size != 0)
                                {
                                    foreach (WiiFillerSectionItem item in ((WiiFillerSection)s).Sections)
                                    {
                                        target.Write(item.Data, 0, (int)item.Size);
                                    }
                                }
                            }
                        }
                    }
                }
                crc.Snapshot("iso");

                if (inStream.IsNkit)
                {
                    outputCrc = inStream.DiscHeader.ReadUInt32B(0x208); //assume source nkit crc is correct
                }
                else
                {
                    outputCrc = crc.FullCrc(true);
                }

                pc.ReaderCheckPoint2Complete(crc, false, outputCrc, outputCrc, this.VerifyIsWrite, null, null);
                pc.ReaderCheckPoint3Complete();
            }
            catch (Exception ex)
            {
                throw pc.SetReaderException(ex, "IsoReader.Read - Read Image"); //don't let the writer lock
            }
        }
Ejemplo n.º 25
0
        public ExtractResult ExtractRecoveryFilesGc()
        {
            MemorySection hdr = NStream.DiscHeader;
            MemorySection bi2bin;
            List <ExtractRecoveryResult> result = new List <ExtractRecoveryResult>();
            NCrc          crc       = new NCrc();
            uint          appLdrCrc = 0;
            MemorySection fst       = null;
            uint          fstCrc    = 0;
            string        fn;
            string        tmpFullName;

            Log?.Log(string.Format("Processing: {0}", SourceFileName));
            int storeType;

            using (CryptoStream bw = new CryptoStream(ByteStream.Zeros, crc, CryptoStreamMode.Write))
            {
                bw.Write(hdr.Data, 0, (int)hdr.Size);

                bi2bin = MemorySection.Read(NStream, 0x2000);
                bw.Write(bi2bin.Data, 0, (int)bi2bin.Size);

                MemorySection aplHdr = MemorySection.Read(NStream, 0x20);
                byte[]        appLdr = new byte[0x20 + aplHdr.ReadUInt32B(0x14) + aplHdr.ReadUInt32B(0x18)];
                Array.Copy(aplHdr.Data, appLdr, (int)aplHdr.Size);
                NStream.Read(appLdr, (int)aplHdr.Size, appLdr.Length - (int)aplHdr.Size);
                appLdrCrc = Crc.Compute(appLdr);

                fn = string.Format("appldr[{0}][{1}].bin", aplHdr.ReadString(0, 10).Replace("/", ""), appLdrCrc.ToString("X8"));
                Log?.Log(string.Format("    1 of 2 - Extracting appldr.bin Recovery File: {0}", fn));
                tmpFullName = Path.Combine(Settings.OtherRecoveryFilesPath, fn + "_TEMP") + appLdrCrc.ToString("X8");
                if (File.Exists(tmpFullName))
                {
                    File.Delete(tmpFullName);
                }
                File.WriteAllBytes(tmpFullName, appLdr);
                if ((storeType = storeRecoveryFile(this.Settings.RedumpAppldrCrcs.Contains(appLdrCrc), tmpFullName, fn, Settings.RecoveryFilesPath, Settings.OtherRecoveryFilesPath, false)) != 0)
                {
                    result.Add(new ExtractRecoveryResult()
                    {
                        FileName = fn, Extracted = true, Type = PartitionType.Other, IsNew = storeType == 2, IsGameCube = true
                    });
                }

                bw.Write(appLdr, 0, appLdr.Length); //add to fullcrc

                NStream.Copy(bw, hdr.ReadUInt32B(0x424) - (0x2440 + appLdr.Length));
                byte[] fstData = new byte[(int)((4 * 4) + (0x60 - 0x20) + hdr.ReadUInt32B(0x428))];
                fst = new MemorySection(fstData);                                                    //info:  dolAddr, fstAddr, maxfst, region, title, fst
                NStream.Read(fstData, (4 * 4) + (0x60 - 0x20), (int)hdr.ReadUInt32B(0x428));
                fst.WriteUInt32B(0x00, hdr.ReadUInt32B(0x420));                                      //dol
                fst.WriteUInt32B(0x04, hdr.ReadUInt32B(0x424));                                      //fstAddr
                fst.WriteUInt32B(0x08, hdr.ReadUInt32B(0x42C));                                      //maxfst
                fst.WriteUInt32B(0x0c, bi2bin.ReadUInt32B(0x18));                                    //region
                fst.Write(0x10, hdr.Read(0x20, 0x60 - 0x20));                                        //title
                fstCrc = Crc.Compute(fstData, (4 * 4) + (0x60 - 0x20), (int)hdr.ReadUInt32B(0x428)); //fst

                bw.Write(fstData, (4 * 4) + (0x60 - 0x20), (int)hdr.ReadUInt32B(0x428));
                crc.Snapshot("crc");
            }

            //fst checksums are postfst
            fn = string.Format("fst[{0}][{1}][{2}][{3}].bin", NStream.Id8, appLdrCrc.ToString("X8"), fstCrc.ToString("X8"), crc.FullCrc().ToString("X8"));
            Log?.Log(string.Format("    2 of 2 - Extracting fst.bin Recovery File: {0}", fn));
            tmpFullName = Path.Combine(Settings.OtherRecoveryFilesPath, fn + "_TEMP") + crc.FullCrc().ToString("X8");
            if (File.Exists(tmpFullName))
            {
                File.Delete(tmpFullName);
            }
            File.WriteAllBytes(tmpFullName, fst.Data);
            if ((storeType = storeRecoveryFile(this.Settings.RedumpFstCrcs.Contains(crc.FullCrc()), tmpFullName, fn, Settings.RecoveryFilesPath, Settings.OtherRecoveryFilesPath, false)) != 0)
            {
                result.Add(new ExtractRecoveryResult()
                {
                    FileName = fn, Extracted = true, Type = PartitionType.Other, IsNew = storeType == 2, IsGameCube = true
                });
            }

            return(createExtractResult((Region)bi2bin.Read8(0x18), result.ToArray()));
        }
Ejemplo n.º 26
0
        /// <summary>
        /// Extracts files from partitions, this is not random access. The iso is read in it's entirety
        /// </summary>
        public ExtractResult ExtractRecoveryFilesWii()
        {
            List <ExtractRecoveryResult> result    = new List <ExtractRecoveryResult>();
            List <WiiPartitionInfo>      toExtract = new List <WiiPartitionInfo>();
            WiiDiscHeaderSection         hdr       = null;
            WiiPartitionHeaderSection    pHdr      = null;
            NStream       target            = null;
            bool          extracting        = false;
            int           channel           = 1;
            string        lastPartitionId   = null;
            PartitionType lastPartitionType = PartitionType.Other;

            string fileName    = null;
            string tmpFileName = null;
            int    extracted   = 0;
            Crc    crc         = new Crc();
            Stream crcStream   = null;
            long   imageSize   = this.NStream.RecoverySize; //for Wii: pHdr.PartitionDataLength


            bool isIso = false; //force to always scrub //Path.GetExtension(_name).ToLower() == ".iso";

            foreach (IWiiDiscSection s in this.EnumerateSectionsFix(false, true, false))
            {
                if (s is WiiDiscHeaderSection)
                {
                    hdr = (WiiDiscHeaderSection)s;

                    Log?.Log(string.Format("Processing: {0}", SourceFileName));

                    toExtract = hdr.Partitions.Where(a => a.Type != PartitionType.Data && a.Type != PartitionType.GameData).ToList();
                    if (toExtract.Count() == 0)
                    {
                        Log?.Log(string.Format("    Skipped: No Recovery Partitions to extract - {0}", SourceFileName));
                        break;
                    }
                }
                else if (s is WiiPartitionSection)
                {
                    WiiPartitionSection ps = (WiiPartitionSection)s;

                    if (!toExtract.Any(a => a.DiscOffset == ps.DiscOffset))
                    {
                        Log?.Log(string.Format("    Skipping {0} Partition: [{1}]...", ps.Header.Type.ToString(), SourceFiles.CleanseFileName(ps.Header.Id).PadRight(4)));
                        continue;
                    }
                    extracting = true;

                    pHdr       = ps.Header;
                    extracting = true;
                    Log?.Log(string.Format("    {0} of {1} - Extracting {2} Recovery Partition: [{3}]", (extracted + 1).ToString(), toExtract.Count().ToString(), ps.Header.Type.ToString(), SourceFiles.CleanseFileName(ps.Header.Id).PadRight(4)));

                    crcStream = new CryptoStream(ByteStream.Zeros, crc, CryptoStreamMode.Write);
                    crc.Initialize();

                    WriteRecoveryPartitionData(crcStream, isIso, ps, channel, out tmpFileName, out fileName, out target);
                    lastPartitionId   = ps.Id;
                    lastPartitionType = ps.Header.Type;
                }
                else if (s is WiiFillerSection)
                {
                    JunkStream       junk = new JunkStream(lastPartitionType != PartitionType.Data ? hdr.ReadString(0, 4) : lastPartitionId, hdr.Read8(6), lastPartitionType == PartitionType.Update ? 0 : imageSize);
                    WiiFillerSection fs   = (WiiFillerSection)s;
                    if (extracting)
                    {
                        int storeType;
                        if ((storeType = WriteRecoveryPartitionFiller(crcStream, junk, fs.DiscOffset, pHdr.Type == PartitionType.Update, false, fs, target, tmpFileName, ref fileName, crc, false)) != 0)
                        {
                            result.Add(new ExtractRecoveryResult()
                            {
                                FileName = fileName, Extracted = true, Type = PartitionType.Other, IsNew = storeType == 2, IsGameCube = false
                            });
                        }

                        if (pHdr.Type != PartitionType.Update)
                        {
                            channel++;
                        }
                        extracted++;
                        extracting = false;
                        bool complete = (extracted == toExtract.Count());
                        if (complete)
                        {
                            break;
                        }
                    }
                }
            }
            return(createExtractResult((Region)hdr.ReadUInt32B(0x4e000), result.ToArray()));
        }
Ejemplo n.º 27
0
        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");
            }
        }
Ejemplo n.º 28
0
        public virtual OutputResults Process(Context ctx, NStream input, Stream output)
        {
            OutputResults results = new OutputResults()
            {
                Conversion = ctx.ConversionName, VerifyOutputResult = VerifyResult.Unverified, ValidateReadResult = VerifyResult.Unverified
            };

            try
            {
                StreamCircularBuffer fs = null;

                _timer = new Timer
                {
                    Interval = 250
                };
                _timer.Elapsed += (s, e) =>
                {
                    if (_timerRunning)
                    {
                        return; //keep processing
                    }

                    try
                    {
                        _timerRunning = true;
                        _log.ProcessingProgress(((IProgress)fs)?.Value ?? 0);
                    }
                    catch { }
                    finally
                    {
                        _timerRunning = false;
                    }
                };
                _timer.Enabled = true;

                long size;
                switch (_sizeMode)
                {
                case ProcessorSizeMode.Source:
                    size = input.SourceSize;
                    break;

                case ProcessorSizeMode.Stream:
                    size = input.Length;
                    break;

                case ProcessorSizeMode.Image:
                    size = input.ImageSize;
                    break;

                case ProcessorSizeMode.Recover:
                default:
                    size = input.RecoverySize;
                    break;
                }

                Coordinator pc = new Coordinator(ctx.ValidationCrc, Reader, Writer, size);

                pc.Started += (s, e) =>
                {
                    _timer.Enabled      = true;
                    results.AliasJunkId = e.AliasJunkId;
                };
                pc.Completed += (s, e) =>
                {
                    _timer.Enabled = false;
                    if (Writer is HashWriter)
                    {
                        results.OutputMd5  = e.Md5;
                        results.OutputSha1 = e.Sha1;
                    }
                    else
                    {
                        MemorySection hdr = new MemorySection(e.Header ?? input.DiscHeader.Data);
                        results.OutputTitle       = hdr.ReadStringToNull(0x20, 0x60);
                        results.OutputDiscNo      = hdr.Read8(6);
                        results.OutputDiscVersion = hdr.Read8(7);
                        results.OutputId8         = string.Concat(hdr.ReadString(0, 6), results.OutputDiscNo.ToString("X2"), results.OutputDiscVersion.ToString("X2"));
                        results.ProcessorMessage  = e.ResultMessage;
                        results.OutputCrc         = e.PatchedCrc;
                        results.IsRecoverable     = e.IsRecoverable;
                        if (e.ValidationCrc != 0)
                        {
                            results.ValidationCrc      = e.ValidationCrc;
                            results.ValidateReadResult = e.ValidationCrc == e.PatchedCrc ? VerifyResult.VerifySuccess : VerifyResult.VerifyFailed;
                        }

                        if (!(Writer is VerifyWriter))
                        {
                            results.OutputSize = e.OutputSize; //never store the verify size
                        }
                        else
                        {
                            results.VerifyCrc = e.VerifyCrc;
                            if (e.VerifyIsWrite) //e.ValidationCrc can be set from a previous process run
                            {
                                results.VerifyOutputResult = results.ValidationCrc == results.VerifyCrc ? VerifyResult.VerifySuccess : VerifyResult.VerifyFailed;
                            }
                        }
                    }

                    bool l9 = pc.Patches.Crcs.Any(a => a.Offset > 0xFFFFFFFFL || a.Length > 0xFFFFFFFFL);
                    if (pc.ReaderCrcs != null)
                    {
                        foreach (CrcItem c in pc.ReaderCrcs.Crcs)
                        {
                            _log.LogDebug(string.Format("R-CRC {0}  Before:{1}  After:{2}  L:{3} {4}", c.Offset.ToString(l9 ? "X9" : "X8"), c.Value.ToString("X8"), c.PatchCrc == 0 ? "        " : c.PatchCrc.ToString("X8"), c.Length.ToString(l9 ? "X9" : "X8"), SourceFiles.CleanseFileName(c.Name)));
                        }

                        _log.LogDebug(string.Format("ReadCRC {0}Before:{1} After:{2}", l9 ? " " : "", pc.ReaderCrcs.FullCrc(false).ToString("X8"), pc.ReaderCrcs.FullCrc(true).ToString("X8")));
                    }
                    if (pc.WriterCrcs != null)
                    {
                        foreach (CrcItem c in pc.WriterCrcs.Crcs)
                        {
                            _log.LogDebug(string.Format("W-CRC {0}  Before:{1}  After:{2}  L:{3} {4}", c.Offset.ToString(l9 ? "X9" : "X8"), c.Value.ToString("X8"), c.PatchCrc == 0 ? "        " : c.PatchCrc.ToString("X8"), c.Length.ToString(l9 ? "X9" : "X8"), SourceFiles.CleanseFileName(c.Name)));
                        }

                        _log.LogDebug(string.Format("WriteCRC {0}Before:{1} After:{2}", l9 ? " " : "", pc.WriterCrcs.FullCrc(false).ToString("X8"), pc.WriterCrcs.FullCrc(true).ToString("X8")));
                    }
                    _log.ProcessingComplete(results.OutputSize, results.ProcessorMessage, true);
                };

                try
                {
                    _log.ProcessingStart(input.SourceSize, Title);

                    using (fs = new StreamCircularBuffer(size, input, null, s => Reader.Read(ctx, input, s, pc))) //read in stream and write to circular buffer
                    {
                        Writer.Write(ctx, fs, output, pc);
                    }
                }
                catch
                {
                    if (pc.Exception != null)
                    {
                        throw pc.Exception;
                    }

                    if (fs.WriterException != null)
                    {
                        throw fs.WriterException;
                    }

                    throw; //writer exception
                }

                foreach (CrcItem crc in pc.Patches.Crcs.Where(a => a.PatchData != null || a.PatchFile != null))
                {
                    output.Seek(crc.Offset, SeekOrigin.Begin);
                    if (crc.PatchFile == null)
                    {
                        output.Write(crc.PatchData, 0, (int)Math.Min(crc.Length, crc.PatchData.Length)); //PatchData might be larger
                    }
                    else
                    {
                        using (FileStream pf = File.OpenRead(crc.PatchFile))
                        {
                            pf.Copy(output, pf.Length);
                            ByteStream.Zeros.Copy(output, crc.Length - pf.Length);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                if (_timer != null)
                {
                    _timer.Enabled = false;
                }

                try
                {
                    _log.ProcessingComplete(results.OutputSize, results.ProcessorMessage, false); // force any log lines to be output - handy for diagnosis
                }
                catch { }
                throw new HandledException(ex, "Failed processing {0} -> {1}", Reader?.GetType()?.Name ?? "<null>", Writer?.GetType()?.Name ?? "<null>");
            }
            finally
            {
                if (_timer != null)
                {
                    _timer.Enabled = false;
                    _timer         = null;
                }
            }

            return(results);
        }
Ejemplo n.º 29
0
        internal int WriteRecoveryPartitionFiller(Stream crcStream, JunkStream junk, long pos, bool isUpdate, bool isNkit, WiiFillerSection fs, NStream target, string tmpFileName, ref string fileName, Crc crc, bool logAsDetail)
        {
            long nullBlocks = 0; //check for random junk - only on a handful of launch releases (Rampage, Ant Bully, Grim Adventures, Happy Feet etc)

            junk.Position = pos;
            long leadingNullsPos = pos;

            foreach (WiiFillerSectionItem fi in fs.Sections)
            {
                crcStream.Write(fi.Data, 0, (int)fi.Size);

                for (int i = 0; i < fi.Size; i += 0x8000)
                {
                    int  len   = (int)Math.Min(0x8000L, fi.Size - (long)i);
                    bool match = junk.Compare(fi.Data, i, len, junk.Position == leadingNullsPos ? 0x1c : 0) == len;

                    if (match)
                    {
                        nullBlocks++;
                    }
                    else
                    {
                        if (nullBlocks != 0)
                        {
                            if (pos == leadingNullsPos)
                            {
                                ByteStream.Zeros.Copy(target, 0x1cL);
                                junk.Position = pos + 0x1cL;
                                junk.Copy(target, (nullBlocks * 0x8000L) - 0x1cL);
                            }
                            else
                            {
                                junk.Position = pos;
                                junk.Copy(target, nullBlocks * 0x8000L);
                            }
                            pos += nullBlocks * 0x8000L;
                        }
                        nullBlocks = 0;
                        target.Write(fi.Data, i, len);
                    }
                }
            }
            target.Close();
            crcStream.Close();

            string fName = (fileName += crc.Value.ToString("X8"));
            bool   redump;

            if (isUpdate)
            {
                redump = this.Settings.RedumpUpdateCrcs.Contains(crc.Value);
            }
            else
            {
                redump = this.Settings.RedumpChannels.FirstOrDefault(a => fName.StartsWith(a.Item1)) != null;
            }
            if (isNkit)
            {
                Directory.CreateDirectory(Settings.NkitRecoveryFilesPath);
            }

            return(storeRecoveryFile(redump, tmpFileName, fileName, Settings.RecoveryFilesPath, isNkit ? Settings.NkitRecoveryFilesPath : Settings.OtherRecoveryFilesPath, logAsDetail));
            //rename the file, delete if dupe
        }
Ejemplo n.º 30
0
        private OutputResults process(string conversion, SourceFile sourceFile, bool renameWithMasks, bool toNkit, NkitFormatType nkitFormat, bool isRecovery, bool fullVerify, bool calcHashes, bool testMode, Func <NStream, IEnumerable <Processor> > passes)
        {
            OutputResults results = null;
            NStream       nstream = _nstream;
            string        lastTmp = null;
            string        tmp     = null;

            this.ConvertionName = conversion;

            try
            {
                SourceFile sf         = null;
                long       sourceSize = nstream.SourceSize;

                _context = new Context();
                _context.Initialise(this.ConvertionName, sourceFile, _settings, true, isRecovery, nstream.IsGameCube, nstream.Id8, this);

                List <Processor> processors = passes(nstream).Where(a => a != null).ToList();
                if (nkitFormat == NkitFormatType.Gcz)
                {
                    processors.Add(new Processor(new IsoReader(), new GczWriter(), "To GCZ", this, false, true, ProcessorSizeMode.Stream));
                }
                if (calcHashes)
                {
                    processors.Add(new Processor(new IsoReader(), new HashWriter(), "Calc Hashes", this, false, true, ProcessorSizeMode.Stream));
                }
                if (fullVerify)
                {
                    if (!toNkit)
                    {
                        processors.Add(new Processor(new IsoReader(), new VerifyWriter(), "Full Verify", this, false, true, ProcessorSizeMode.Stream));
                    }
                    else
                    {
                        processors.Add(new Processor(nstream.IsGameCube ? new NkitReaderGc() : (IReader) new NkitReaderWii(), new VerifyWriter(), "NKit Verify", this, true, true, ProcessorSizeMode.Image));
                    }
                    processors.Last().Writer.RequireVerifyCrc = true;
                    processors.Last().Writer.VerifyIsWrite = true; //read verify
                }
                _totalPasses = processors.Count();

                if (processors.Count == 0)
                {
                    return(null);
                }

                DateTime dt = DateTime.Now;
                _completedPasses = 0;

                Log("PROCESSING" + (testMode ? " [TEST MODE]" : ((_context.Settings.DeleteSource ? " [DELETE SOURCE]" : ""))));
                Log("-------------------------------------------------------------------------------");
                if (_forcedWiiFullNkitRebuild)
                {
                    LogBlank();
                    Log(string.Format("Nkit Reencode forced: NkitUpdatePartitionRemoval is {0} and source image has {1} Update Partition", _context.Settings.NkitUpdatePartitionRemoval.ToString(), nstream.IsNkitUpdateRemoved ? "no" : "an"));
                    LogBlank();
                }
                Log(string.Format("{0} [{1}]  {2}  [MiB:{3,2:#.0}]", friendly(nstream.Title), friendly(nstream.Id), nstream.IsGameCube ? "GameCube" : "Wii", (sourceSize / (double)(1024 * 1024))));
                LogBlank();
                string passesText = getPassesLine(nstream, processors);
                Log(passesText);

                int i = 1;
                foreach (Processor pro in processors.Where(pro => pro != null))
                {
                    LogDebug(string.Format("Pass {0}: {1}", (i++).ToString(), pro.ToString()));
                }
                LogBlank();

                foreach (Processor pro in processors)
                {
                    //sort out temp file and open input as nstream each time
                    //raise progress and output messages from processors

                    if (sf != null)
                    {
                        nstream = sf.OpenNStream(!(pro.Writer is HashWriter)); //if hashWriter then read as raw file
                        sf      = null;
                    }

                    tmp = null;
                    FileStream tmpFs = null;

                    try
                    {
                        if (pro.HasWriteStream)
                        {
                            tmp = Path.Combine(_context.Settings.TempPath, Path.GetFileName(Path.GetTempFileName()));
                            if (!Directory.Exists(_context.Settings.TempPath))
                            {
                                Directory.CreateDirectory(_context.Settings.TempPath);
                            }
                            tmpFs = File.Create(tmp, 0x400 * 0x400 * 4, FileOptions.SequentialScan);
                        }

                        _logCache = new List <Tuple <string, LogMessageType> >();
                        OutputResults nr = pro.Process(_context, nstream, tmpFs ?? Stream.Null);
                        _logCache = null;

                        if (results == null)
                        {
                            results                  = nr;
                            results.DiscType         = nstream.IsGameCube ? DiscType.GameCube : DiscType.Wii;
                            results.InputFileName    = sourceFile.AllFiles.Length != 0 ? sourceFile.AllFiles[0] : sourceFile.FilePath;
                            results.InputDiscNo      = nstream.DiscNo;
                            results.InputDiscVersion = nstream.Version;
                            results.InputTitle       = nstream.Title;
                            results.InputId8         = nstream.Id8;
                            results.InputSize        = sourceSize;
                            results.FullSize         = nstream.ImageSize;
                            results.Passes           = passesText;
                            if (pro.IsVerify)
                            {
                                results.OutputSize = results.InputSize;
                            }
                        }
                        else if (pro.Writer is HashWriter) //hash writer gives no meaningful info back other than md5 and sha1 (the crc is forced when nkit, so ignore)
                        {
                            results.OutputMd5  = nr.OutputMd5;
                            results.OutputSha1 = nr.OutputSha1;
                        }
                        else
                        {
                            if (nr.AliasJunkId != null)
                            {
                                results.AliasJunkId = nr.AliasJunkId;
                            }
                            if (nr.OutputTitle != null)
                            {
                                results.OutputDiscNo      = nr.OutputDiscNo;
                                results.OutputDiscVersion = nr.OutputDiscVersion;
                                results.OutputTitle       = nr.OutputTitle;
                            }
                            results.OutputId8         = nr.OutputId8;
                            results.OutputCrc         = nr.OutputCrc;
                            results.OutputPrePatchCrc = nr.OutputPrePatchCrc;
                            results.FullSize          = nstream.ImageSize;
                            if (tmp != null)
                            {
                                results.OutputSize = nr.OutputSize;
                            }

                            if (nr.ValidationCrc != 0 && results.VerifyCrc != 0)
                            {
                                results.VerifyCrc = 0; //blank verify if a new ValidationCrc is set - verification happened when both != 0
                            }
                            if (nr.VerifyCrc != 0)
                            {
                                results.VerifyCrc = nr.VerifyCrc;
                            }
                            if (nr.ValidationCrc != 0)
                            {
                                results.ValidationCrc = nr.ValidationCrc;
                            }
                            if (nr.ValidateReadResult != VerifyResult.Unverified)
                            {
                                results.ValidateReadResult = nr.ValidateReadResult;
                            }
                            if (nr.VerifyOutputResult != VerifyResult.Unverified)
                            {
                                if (results.ValidateReadResult == VerifyResult.Unverified && nstream.IsNkit)
                                {
                                    results.ValidateReadResult = nr.VerifyOutputResult;
                                }
                                results.VerifyOutputResult = nr.VerifyOutputResult;
                            }
                            if (nr.IsRecoverable)
                            {
                                results.IsRecoverable = nr.IsRecoverable;
                            }
                        }
                    }
                    finally
                    {
                        if (tmpFs != null)
                        {
                            tmpFs.Dispose();
                        }

                        nstream.Close();
                    }

                    if (lastTmp != null && tmp != null)
                    {
                        File.Delete(lastTmp);
                    }

                    //handle failures well
                    if (results.ValidateReadResult == VerifyResult.VerifyFailed || results.VerifyOutputResult == VerifyResult.VerifyFailed)
                    {
                        lastTmp = tmp; //keep post loop happy
                        break;
                    }

                    if (_completedPasses != _totalPasses) //last item
                    {
                        sf = SourceFiles.OpenFile(tmp ?? lastTmp);
                    }

                    if (tmp != null)
                    {
                        lastTmp = tmp;
                    }
                }

                TimeSpan ts = DateTime.Now - dt;
                results.ProcessingTime = ts;

                //FAIL
                if (results.ValidateReadResult == VerifyResult.VerifyFailed || results.VerifyOutputResult == VerifyResult.VerifyFailed)
                {
                    LogBlank();
                    Log(string.Format("Verification Failed Crc:{0} - Failed Test Crc:{1}", results.OutputCrc.ToString("X8"), results.ValidationCrc.ToString("X8")));

                    if (lastTmp != null) //only null when verify only
                    {
                        Log("Deleting Output" + (Settings.OutputLevel != 3 ? "" : " (Skipped as OutputLevel is 3:Debug)"));
                        results.OutputFileName = null;
                        if (Settings.OutputLevel != 3)
                        {
                            File.Delete(lastTmp);
                        }

                        LogBlank();
                    }
                }
                else //SUCCESS
                {
                    LogBlank();
                    Log(string.Format("Completed ~ {0}m {1}s  [MiB:{2:#.0}]", ((int)ts.TotalMinutes).ToString(), ts.Seconds.ToString(), (results.OutputSize / (double)(1024 * 1024))));
                    LogBlank();
                    Log("RESULTS");
                    Log("-------------------------------------------------------------------------------");

                    uint   finalCrc = results.ValidationCrc != 0 ? results.ValidationCrc : results.OutputCrc;
                    string mask     = _context.Settings.MatchFailRenameToMask;
                    results.OutputFileExt = "." + SourceFiles.ExtensionString(false, false, toNkit, nkitFormat == NkitFormatType.Gcz).ToLower();
                    results.RedumpInfo    = _context.Dats.GetRedumpEntry(_context.Settings, _context.Dats, finalCrc);
                    if (results.RedumpInfo.MatchType == MatchType.Redump || results.RedumpInfo.MatchType == MatchType.Custom)
                    {
                        Log(string.Format("{0} [{1} Name]", results.RedumpInfo.MatchName, results.RedumpInfo.MatchType.ToString()));
                        if (results.IsRecoverable)
                        {
                            Log(string.Format("Missing Recovery data is required to correctly restore this image!", results.RedumpInfo.MatchName, results.RedumpInfo.MatchType.ToString()));
                        }
                        mask = results.RedumpInfo.MatchType == MatchType.Custom ? _context.Settings.CustomMatchRenameToMask : _context.Settings.RedumpMatchRenameToMask;
                    }
                    else
                    {
                        Log(string.Format("CRC {0} not in Redump or Custom Dat", finalCrc.ToString("X8")));
                    }
                    LogBlank();


                    outputResults(results);


                    if (lastTmp != null) //only null when verify only
                    {
                        if (testMode)
                        {
                            Log("TestMode: Deleting Output");
                            results.OutputFileName = null;
                            if (File.Exists(lastTmp))
                            {
                                File.Delete(lastTmp);
                            }
                        }
                        else if (isRecovery && _context.Settings.RecoveryMatchFailDelete && results.RedumpInfo.MatchType == MatchType.MatchFail)
                        {
                            Log("Failed to Recover to Dat Entry: Deleting Output");
                            results.OutputFileName = null;
                            File.Delete(lastTmp);
                        }
                        else
                        {
                            if (renameWithMasks)
                            {
                                results.OutputFileName = _context.Dats.GetFilename(results, mask);
                                Log("Renaming Output Using Masks");
                            }
                            else
                            {
                                results.OutputFileName = SourceFiles.GetUniqueName(sourceFile.CreateOutputFilename(results.OutputFileExt));
                                Log("Renaming Output Based on Source File" + (sourceFile.AllFiles.Count() > 1 ? "s" : ""));
                            }
                            LogBlank();

                            string path = Path.GetDirectoryName(results.OutputFileName);
                            if (!Directory.Exists(path))
                            {
                                Directory.CreateDirectory(path);
                            }

                            File.Move(lastTmp, results.OutputFileName);

                            Log(string.Format("Output: {0}", Path.GetDirectoryName(results.OutputFileName)));
                            Log(string.Format("    {0}", Path.GetFileName(results.OutputFileName)));

                            //double check test mode just to be sure
                            if (_context.Settings.DeleteSource && !testMode && results.VerifyOutputResult == VerifyResult.VerifySuccess)
                            {
                                LogBlank();
                                Log("Deleting Source:");
                                foreach (string s in sourceFile.AllFiles.Length == 0 ? new string[] { sourceFile.FilePath } : sourceFile.AllFiles)
                                {
                                    Log(string.Format("    {0}", s));
                                    File.Delete(s);
                                }
                            }
                        }
                        LogBlank();
                    }
                }
            }
            catch (Exception ex)
            {
                try
                {
                    if (lastTmp == null)
                    {
                        lastTmp = tmp;
                    }
                    if (lastTmp != null)
                    {
                        LogBlank();
                        Log("Deleting Output" + (Settings.OutputLevel != 3 ? "" : " (Skipped as OutputLevel is 3:Debug)"));
                        if (results != null)
                        {
                            results.OutputFileName = null;
                        }
                        if (Settings.OutputLevel != 3)
                        {
                            File.Delete(lastTmp);
                        }
                    }
                }
                catch { }

                if (_context.Settings.EnableSummaryLog)
                {
                    if (results == null)
                    {
                        results                  = new OutputResults();
                        results.Conversion       = this.ConvertionName;
                        results.DiscType         = (nstream?.IsGameCube ?? true) ? DiscType.GameCube : DiscType.Wii;
                        results.InputFileName    = (sourceFile?.AllFiles?.Length ?? 0) == 0 ? (sourceFile?.FilePath ?? "") : (sourceFile?.AllFiles.FirstOrDefault() ?? "");
                        results.InputDiscNo      = nstream?.DiscNo ?? 0;
                        results.InputDiscVersion = nstream?.Version ?? 0;
                        results.InputTitle       = nstream?.Title ?? "";
                        results.InputId8         = nstream?.Id8 ?? "";
                        results.InputSize        = sourceFile?.Length ?? 0;
                    }
                    results.VerifyOutputResult = VerifyResult.Error;
                    HandledException hex = ex as HandledException;
                    if (hex == null)
                    {
                        hex = new HandledException(ex, "Unhandled Exception");
                    }
                    results.ErrorMessage = hex.FriendlyErrorMessage;
                }
                throw;
            }
            finally
            {
                if (_context.Settings.EnableSummaryLog)
                {
                    summaryLog(_context.Settings, results);
                    Log("Summary Log Written" + (results.VerifyOutputResult != VerifyResult.Error ? "" : " as Errored!"));
                    LogBlank();
                }
            }

            return(results);
        }