Exemple #1
0
        public override void Read(IffFile iff, Stream stream)
        {
            using (var io = IoBuffer.FromStream(stream, ByteOrder.LITTLE_ENDIAN))
            {
                Version   = io.ReadUInt16();
                SourceIff = io.ReadVariableLengthPascalString();
                if (Version > 1)
                {
                    Comment = io.ReadVariableLengthPascalString();
                }
                Entries = new PIFFEntry[io.ReadUInt16()];
                for (int i = 0; i < Entries.Length; i++)
                {
                    var e = new PIFFEntry();
                    e.Type    = io.ReadCString(4);
                    e.ChunkID = io.ReadUInt16();
                    if (Version > 1)
                    {
                        e.Comment = io.ReadVariableLengthPascalString();
                    }
                    e.EntryType = (PIFFEntryType)io.ReadByte();

                    if (e.EntryType == PIFFEntryType.Patch)
                    {
                        e.ChunkLabel = io.ReadVariableLengthPascalString();
                        e.ChunkFlags = io.ReadUInt16();
                        if (Version > 0)
                        {
                            e.NewChunkID = io.ReadUInt16();
                        }
                        else
                        {
                            e.NewChunkID = e.ChunkID;
                        }
                        e.NewDataSize = io.ReadUInt32();

                        var size = io.ReadUInt32();
                        e.Patches = new PIFFPatch[size];
                        uint lastOff = 0;

                        for (int j = 0; j < e.Patches.Length; j++)
                        {
                            var p = new PIFFPatch();

                            p.Offset = lastOff + io.ReadVarLen();
                            lastOff  = p.Offset;
                            p.Size   = io.ReadVarLen();
                            p.Mode   = (PIFFPatchMode)io.ReadByte();

                            if (p.Mode == PIFFPatchMode.Add)
                            {
                                p.Data = io.ReadBytes(p.Size);
                            }
                            e.Patches[j] = p;
                        }
                    }
                    Entries[i] = e;
                }
            }
        }
Exemple #2
0
        public override void Read(IffFile iff, Stream stream)
        {
            using (var io = IoBuffer.FromStream(stream, ByteOrder.LITTLE_ENDIAN))
            {
                Version = io.ReadUInt16();
                SourceIff = io.ReadVariableLengthPascalString();
                Entries = new PIFFEntry[io.ReadUInt16()];
                for (int i=0; i<Entries.Length; i++)
                {
                    var e = new PIFFEntry();
                    e.Type = io.ReadCString(4);
                    e.ChunkID = io.ReadUInt16();
                    e.Delete = io.ReadByte()>0;

                    if (!e.Delete)
                    {
                        e.ChunkLabel = io.ReadVariableLengthPascalString();
                        e.ChunkFlags = io.ReadUInt16();
                        if (Version > 0) e.NewChunkID = io.ReadUInt16();
                        else e.NewChunkID = e.ChunkID;
                        e.NewDataSize = io.ReadUInt32();

                        var size = io.ReadUInt32();
                        e.Patches = new PIFFPatch[size];
                        uint lastOff = 0;

                        for (int j=0; j<e.Patches.Length; j++)
                        {
                            var p = new PIFFPatch();

                            p.Offset = lastOff + io.ReadVarLen();
                            lastOff = p.Offset;
                            p.Size = io.ReadVarLen();
                            p.Mode = (PIFFPatchMode)io.ReadByte();

                            if (p.Mode == PIFFPatchMode.Add) p.Data = io.ReadBytes(p.Size);
                            e.Patches[j] = p;
                        }
                    }
                    Entries[i] = e;
                }
            }
        }
Exemple #3
0
        public static PIFFEntry MakeChunkDiff(IffChunk chk)
        {
            var e = new PIFFEntry { Type = chk.ChunkType, ChunkID = chk.OriginalID, NewChunkID = chk.ChunkID };
            if (chk == null)
            {
                e.Delete = true;
                return e;
            }

            byte[] newData = null;
            using (var stream = new MemoryStream())
            {
                if (!chk.Write(chk.ChunkParent, stream))
                {
                    return null; //use original
                }
                newData = stream.ToArray();
            }

            e.ChunkLabel = (chk.OriginalLabel==chk.ChunkLabel)?"":chk.ChunkLabel;
            e.ChunkFlags = chk.ChunkFlags;
            e.NewDataSize = (uint)newData.Length;

            //encode difference as sequence of changes
            var oldData = chk.OriginalData;
            var patches = new List<PIFFPatch>();

            int i;
            for (i=0; i<newData.Length; i += 1000)
            {
                if (i >= oldData.Length)
                {
                    //no more comparisons, just add the remainder
                    var remain = new byte[newData.Length-i];
                    Array.Copy(newData, i, remain, 0, remain.Length);
                    patches.Add(new PIFFPatch
                    {
                        Mode = PIFFPatchMode.Add,
                        Data = remain,
                        Offset = (uint)i,
                        Size = (uint)remain.Length
                    });
                    break;
                }

                //dynamic programming matrix.
                int m = Math.Min(1000, Math.Max(0, newData.Length - i))+1;
                int n = Math.Min(1000, Math.Max(0, oldData.Length - i))+1;
                ushort[,] comp = new ushort[m, n];
                for (int x=1; x<m; x++)
                {
                    for (int y=1; y<n; y++)
                    {
                        if (newData[i+x-1] == oldData[i + y -1]) comp[x, y] = (ushort)(comp[x - 1, y - 1] + 1);
                        else comp[x, y] = Math.Max(comp[x, y - 1], comp[x - 1, y]);
                    }
                }

                var changes = new Stack<byte>();
                //backtrack through compare
                {
                    int x = m-1, y = n-1;
                    while (true)
                    {
                        if (x>0 && y>0 && newData[i + x -1] == oldData[i + y -1])
                        {
                            x--; y--; changes.Push(0); //no change
                        } else if (y>0 && (x==0 || comp[x,y-1] >= comp[x-1,y]))
                        {
                            y--; changes.Push(2); //remove
                        } else if (x>0 && (y==0 || comp[x,y-1] < comp[x-1,y]))
                        {
                            x--; changes.Push(1); //add
                        } else
                        {
                            break;
                        }
                    }
                }

                byte lastC = 0;
                PIFFPatch curr = null;
                List<byte> addArray = null;
                int ptr = 0;
                foreach (var c in changes)
                {
                    if (c != lastC && curr != null)
                    {
                        if (lastC == 1) curr.Data = addArray.ToArray();
                        patches.Add(curr);
                        curr = null;
                    }
                    if (c == 0) ptr++;
                    else if (c == 1)
                    {
                        if (lastC != 1)
                        {
                            curr = new PIFFPatch { Mode = PIFFPatchMode.Add, Offset = (uint)(i + ptr), Size = 1 };
                            addArray = new List<byte>();
                            addArray.Add(newData[i + ptr]);
                        }
                        else
                        {
                            curr.Size++;
                            addArray.Add(newData[i + ptr]);
                        }
                        ptr++;
                    }
                    else
                    {
                        if (lastC != 2)
                            curr = new PIFFPatch { Mode = PIFFPatchMode.Remove, Offset = (uint)(i + ptr), Size = 1 };
                        else
                            curr.Size++;
                    }
                    lastC = c;
                }

                if (curr != null)
                {
                    if (lastC == 1) curr.Data = addArray.ToArray();
                    patches.Add(curr);
                }

                if (m < n)
                {
                    //remainder on src to be removed
                    patches.Add(new PIFFPatch { Mode = PIFFPatchMode.Remove, Offset = (uint)(i+ptr), Size = (uint)(n-m) });
                }
                /*else if (m != n)
                {
                    //remainder on dest to be added
                    var remain = new byte[m-n];
                    Array.Copy(newData, i+ptr, remain, 0, remain.Length);
                    patches.Add(new PIFFPatch
                    {
                        Mode = PIFFPatchMode.Add,
                        Data = remain,
                        Offset = (uint)(i+ ptr),
                        Size = (uint)remain.Length
                    });
                }*/
            }

            if (oldData.Length > i)
            {
                //ran out of new data, but old is still going. Remove the remainder.
                patches.Add(new PIFFPatch
                {
                    Mode = PIFFPatchMode.Remove,
                    Offset = (uint)newData.Length,
                    Size = (uint)(oldData.Length - i)
                });
            }

            e.Patches = patches.ToArray();

            return e;
        }