Пример #1
0
        private PatchRecord GetLargestContiguousRegion(PatchRecord p, byte[] modified)
        {
            if (p.offset < 0 || p.length < 0 || p.offset + p.length > modified.Length)
            {
                return(new PatchRecord());
            }
            PatchRecord highest = new PatchRecord()
            {
                isRLE = true
            };
            PatchRecord current = new PatchRecord()
            {
                isRLE = true
            };
            int curr = p.offset;

            while (curr < p.offset + p.length)
            {
                current.offset = curr;
                current.length = 1;
                while (modified[curr + 1] == modified[curr])
                {
                    current.length++;
                    curr++;
                }
                if (current.length > highest.length)
                {
                    highest = current;
                }
                curr++;
            }
            return(highest);
        }
Пример #2
0
        private List <PatchRecord> CombineRecords(List <PatchRecord> inRecords)
        {
            var ret = new List <PatchRecord>();

            if (inRecords.Count == 0)
            {
                return(ret);
            }
            PatchRecord cache = inRecords[0];

            for (int i = 1; i < inRecords.Count; i++)
            {
                // If the non-changed region inbetween two records is greater than 5, then a combined
                // patch with the length of that region plus the length of the two records saves
                // space in the final patch.
                int diff = inRecords[i].offset - (cache.offset + cache.length);
                if (diff > 5)
                {
                    int newLen = inRecords[i].length + cache.length + diff;
                    cache = new PatchRecord(inRecords[i].offset, newLen);
                }
                else
                {
                    ret.Add(cache);
                    cache = inRecords[i];
                }
            }
            return(ret);
        }
Пример #3
0
        private List <PatchRecord> ConstrainRecords(List <PatchRecord> inRecords)
        {
            var ret = new List <PatchRecord>();

            if (inRecords.Count == 0)
            {
                return(ret);
            }
            for (int i = 0; i < inRecords.Count; i++)
            {
                PatchRecord current = inRecords[i];
                while (current.length > 0xFFFF)
                {
                    PatchRecord split = new PatchRecord();
                    split.isRLE     = current.isRLE;
                    split.offset    = current.offset;
                    split.length    = 0xFFFF;
                    current.offset += 0xFFFF;
                    current.length -= 0xFFFF;
                    ret.Add(split);
                    if (current.isRLE)
                    {
                        current.isRLE = current.length >= 3;
                    }
                }
                ret.Add(current);
            }
            return(ret);
        }
Пример #4
0
        public ErrorMessage GenerateIPS(byte[] source, byte[] modified, bool optimize = false)
        {
            if (source.Length != modified.Length)
            {
                return(ErrorMessage.IPS_FileSizeMismatch);
            }
            else if (source.Length > 0xFFFFFF)
            {
                return(ErrorMessage.IPS_FileSizeTooLarge);
            }
            ClearStream();
            WriteChar('P');
            WriteChar('A');
            WriteChar('T');
            WriteChar('C');
            WriteChar('H');
            var patches = new List <PatchRecord>();
            int curPos  = 0;

            while (curPos < source.Length)
            {
                while (curPos < source.Length && source[curPos] == modified[curPos])
                {
                    curPos++;
                }
                if (curPos == source.Length)
                {
                    break;
                }
                PatchRecord p = new PatchRecord(curPos, 1);
                while (curPos < source.Length && source[curPos] != modified[curPos])
                {
                    curPos++;
                    p.length++;
                }
                patches.Add(p);
            }
            patches = ConstrainRecords(SplitRecords(CombineRecords(patches), modified));
            foreach (PatchRecord p in patches)
            {
                if (!WritePatchRecord(p, modified))
                {
                    return(ErrorMessage.IPS_UnknownError);
                }
            }
            WriteChar('E');
            WriteChar('O');
            WriteChar('F');
            return(ErrorMessage.General_NoError);
        }
Пример #5
0
 public ErrorMessage GenerateIPS(byte[] source, byte[] modified, bool optimize = false)
 {
     if (source.Length != modified.Length)
     {
         return ErrorMessage.IPS_FileSizeMismatch;
     }
     else if (source.Length > 0xFFFFFF)
     {
         return ErrorMessage.IPS_FileSizeTooLarge;
     }
     ClearStream();
     WriteChar('P');
     WriteChar('A');
     WriteChar('T');
     WriteChar('C');
     WriteChar('H');
     var patches = new List<PatchRecord>();
     int curPos = 0;
     while (curPos < source.Length)
     {
         while (curPos < source.Length && source[curPos] == modified[curPos])
         {
             curPos++;
         }
         if (curPos == source.Length)
         {
             break;
         }
         PatchRecord p = new PatchRecord(curPos, 1);
         while (curPos < source.Length && source[curPos] != modified[curPos])
         {
             curPos++;
             p.length++;
         }
         patches.Add(p);
     }
     patches = ConstrainRecords(SplitRecords(CombineRecords(patches), modified));
     foreach (PatchRecord p in patches)
     {
         if (!WritePatchRecord(p, modified))
         {
             return ErrorMessage.IPS_UnknownError;
         }
     }
     WriteChar('E');
     WriteChar('O');
     WriteChar('F');
     return ErrorMessage.General_NoError;
 }
Пример #6
0
        protected IPatch Patch(MethodBase method, string prefix = null, string postfix = null, string transpiler = null)
        {
            IPatch patch;

         #if ZyBatch
            try {
         #endif
            lock (_ILock) if (Patcher == null)
                {
                    Patcher = HarmonyInstance.Create(GetType().Namespace);
                }
            patch = new PatchRecord(Patcher, method, ToHarmony(prefix), ToHarmony(postfix), ToHarmony(transpiler)).Patch();
         #if ZyBatch
        }
        catch (Exception ex) { RollbackPatch(ex); throw; }
        lock (Trans) if (TransId != null)
            {
                Trans.Add(patch);
            }
         #endif
            return(patch);
        }
Пример #7
0
 private bool WritePatchRecord(PatchRecord p, byte[] modified)
 {
     if (p.offset < 0 || p.length <= 0 || p.offset + p.length > modified.Length || p.length > 0xFFFF)
     {
         return(false);
     }
     if (p.isRLE)
     {
         Write24(p.offset);
         Write16(0);
         Write16(p.length);
         Write8(modified[p.offset]);
     }
     else
     {
         Write24(p.offset);
         Write16(p.length);
         for (int i = 0; i < p.length; i++)
         {
             Write8(modified[p.offset + i]);
         }
     }
     return(true);
 }
Пример #8
0
        private List <PatchRecord> SplitRecords(List <PatchRecord> inRecords, byte[] modified)
        {
            var ret = new List <PatchRecord>();

            if (inRecords.Count == 0)
            {
                return(ret);
            }
            var cache = new Stack <PatchRecord>();

            for (int i = 1; i < inRecords.Count; i++)
            {
                cache.Push(inRecords[i]);
                while (cache.Count > 0)
                {
                    PatchRecord start = cache.Pop();
                    if (start.isRLE)
                    {
                        ret.Add(start);
                    }
                    else
                    {
                        PatchRecord split = GetLargestContiguousRegion(start, modified);
                        if (split.offset == start.offset)
                        {
                            // Case A: the size of the RLE region is equivalent to the
                            // entire region. Split if the length of the run is > 3.
                            if (split.length == start.length)
                            {
                                if (split.length > 3)
                                {
                                    ret.Add(split);
                                }
                                else
                                {
                                    ret.Add(start);
                                }
                            }
                            // Case B: the RLE region is at the beginning, and less than
                            // the size of the entire region. Split if the length of the
                            // run is > 8.
                            else
                            {
                                if (split.length > 8)
                                {
                                    start.offset += split.length;
                                    cache.Push(start);
                                    ret.Add(split);
                                }
                                else
                                {
                                    ret.Add(start);
                                }
                            }
                        }
                        // Case C: the RLE region is at the end, and less than the size
                        // of the region. Split if the length of the run is > 8.
                        else if (split.offset + split.length == start.offset + start.length)
                        {
                            if (split.length > 8)
                            {
                                start.length += split.length;
                                cache.Push(split);
                                cache.Push(start);
                            }
                            else
                            {
                                ret.Add(start);
                            }
                        }
                        // Case D: the RLE region is in the middle of the whole region.
                        // Split into 3 if the length of the run is > 13.
                        else
                        {
                            if (split.length > 13)
                            {
                                PatchRecord end = new PatchRecord();
                                end.offset    = split.offset + split.length;
                                end.length    = start.length - split.length;
                                start.length -= split.length + end.length;
                                cache.Push(end);
                                cache.Push(split);
                                cache.Push(start);
                            }
                            else
                            {
                                ret.Add(start);
                            }
                        }
                    }
                }
            }
            return(ret);
        }
Пример #9
0
 private List<PatchRecord> CombineRecords(List<PatchRecord> inRecords)
 {
     var ret = new List<PatchRecord>();
     if (inRecords.Count == 0)
     {
         return ret;
     }
     PatchRecord cache = inRecords[0];
     for (int i = 1; i < inRecords.Count; i++)
     {
         // If the non-changed region inbetween two records is greater than 5, then a combined
         // patch with the length of that region plus the length of the two records saves
         // space in the final patch.
         int diff = inRecords[i].offset - (cache.offset + cache.length);
         if (diff > 5)
         {
             int newLen = inRecords[i].length + cache.length + diff;
             cache = new PatchRecord(inRecords[i].offset, newLen);
         }
         else
         {
             ret.Add(cache);
             cache = inRecords[i];
         }
     }
     return ret;
 }
Пример #10
0
 private bool WritePatchRecord(PatchRecord p, byte[] modified)
 {
     if (p.offset < 0 || p.length <= 0 || p.offset + p.length > modified.Length || p.length > 0xFFFF)
     {
         return false;
     }
     if (p.isRLE)
     {
         Write24(p.offset);
         Write16(0);
         Write16(p.length);
         Write8(modified[p.offset]);
     }
     else
     {
         Write24(p.offset);
         Write16(p.length);
         for (int i = 0; i < p.length; i++)
         {
             Write8(modified[p.offset + i]);
         }
     }
     return true;
 }
Пример #11
0
 private List<PatchRecord> SplitRecords(List<PatchRecord> inRecords, byte[] modified)
 {
     var ret = new List<PatchRecord>();
     if (inRecords.Count == 0)
     {
         return ret;
     }
     var cache = new Stack<PatchRecord>();
     for (int i = 1; i < inRecords.Count; i++)
     {
         cache.Push(inRecords[i]);
         while (cache.Count > 0)
         {
             PatchRecord start = cache.Pop();
             if (start.isRLE)
             {
                 ret.Add(start);
             }
             else
             {
                 PatchRecord split = GetLargestContiguousRegion(start, modified);
                 if (split.offset == start.offset)
                 {
                     // Case A: the size of the RLE region is equivalent to the
                     // entire region. Split if the length of the run is > 3.
                     if (split.length == start.length)
                     {
                         if (split.length > 3)
                         {
                             ret.Add(split);
                         }
                         else
                         {
                             ret.Add(start);
                         }
                     }
                     // Case B: the RLE region is at the beginning, and less than
                     // the size of the entire region. Split if the length of the
                     // run is > 8.
                     else
                     {
                         if (split.length > 8)
                         {
                             start.offset += split.length;
                             cache.Push(start);
                             ret.Add(split);
                         }
                         else
                         {
                             ret.Add(start);
                         }
                     }
                 }
                 // Case C: the RLE region is at the end, and less than the size
                 // of the region. Split if the length of the run is > 8.
                 else if (split.offset + split.length == start.offset + start.length)
                 {
                     if (split.length > 8)
                     {
                         start.length += split.length;
                         cache.Push(split);
                         cache.Push(start);
                     }
                     else
                     {
                         ret.Add(start);
                     }
                 }
                 // Case D: the RLE region is in the middle of the whole region.
                 // Split into 3 if the length of the run is > 13.
                 else
                 {
                     if (split.length > 13)
                     {
                         PatchRecord end = new PatchRecord();
                         end.offset = split.offset + split.length;
                         end.length = start.length - split.length;
                         start.length -= split.length + end.length;
                         cache.Push(end);
                         cache.Push(split);
                         cache.Push(start);
                     }
                     else
                     {
                         ret.Add(start);
                     }
                 }
             }
         }
     }
     return ret;
 }
Пример #12
0
 private PatchRecord GetLargestContiguousRegion(PatchRecord p, byte[] modified)
 {
     if (p.offset < 0 || p.length < 0 || p.offset + p.length > modified.Length)
     {
         return new PatchRecord();
     }
     PatchRecord highest = new PatchRecord() { isRLE = true };
     PatchRecord current = new PatchRecord() { isRLE = true };
     int curr = p.offset;
     while (curr < p.offset + p.length)
     {
         current.offset = curr;
         current.length = 1;
         while (modified[curr + 1] == modified[curr])
         {
             current.length++;
             curr++;
         }
         if (current.length > highest.length)
         {
             highest = current;
         }
         curr++;
     }
     return highest;
 }
Пример #13
0
 private List<PatchRecord> ConstrainRecords(List<PatchRecord> inRecords)
 {
     var ret = new List<PatchRecord>();
     if (inRecords.Count == 0)
     {
         return ret;
     }
     for (int i = 0; i < inRecords.Count; i++)
     {
         PatchRecord current = inRecords[i];
         while (current.length > 0xFFFF)
         {
             PatchRecord split = new PatchRecord();
             split.isRLE = current.isRLE;
             split.offset = current.offset;
             split.length = 0xFFFF;
             current.offset += 0xFFFF;
             current.length -= 0xFFFF;
             ret.Add(split);
             if (current.isRLE)
             {
                 current.isRLE = current.length >= 3;
             }
         }
         ret.Add(current);
     }
     return ret;
 }