コード例 #1
0
ファイル: Version.cs プロジェクト: RichardBradley/MMEd
        ///========================================================================
        /// Method : GetLevel
        ///
        /// <summary>
        ///     Get the level represented by this Version
        /// </summary>
        /// <param name="xiPreviousVersion">
        ///   The previous version, which must already have had GetLevel called.
        /// </param>
        /// <returns></returns>
        ///========================================================================
        internal Level GetLevel(Version xiPreviousVersion)
        {
            //=======================================================================
            // Apply the diffs if necessary
            //=======================================================================
            if (SerialisedLevel == null)
            {
                if (xiPreviousVersion == null)
                {
                    throw new Exception("Cannot access a differentially-serialised level if the previous version is not available");
                }
                else if (xiPreviousVersion.SerialisedLevel == null)
                {
                    throw new Exception("Cannot access a differentially-serialised level if the previous version has not already been accessed");
                }

                SerialisedLevel = DiffBlock.ApplyPatch(xiPreviousVersion.SerialisedLevel, DifferentialLevel);
            }

            //=======================================================================
            // Deserialise the level
            //=======================================================================
            using (MemoryStream lLevelStream = new MemoryStream())
            {
                lLevelStream.Write(SerialisedLevel, 0, SerialisedLevel.Length);
                lLevelStream.Seek(0, SeekOrigin.Begin);
                return(new Level(lLevelStream));
            }
        }
コード例 #2
0
        private static void AssertDifferenceFound(DiffResult result, params DiffBlock[] expectedDiffBlocks)
        {
            Assert.AreEqual(DiffStatus.DifferencesFound, result.Status);
            Assert.AreEqual(expectedDiffBlocks.Length, result.DiffBlocks.Count);

            for (int i = 0; i < expectedDiffBlocks.Length; i++)
            {
                DiffBlock expected        = expectedDiffBlocks[i];
                DiffBlock resultDiffBlock = result.DiffBlocks.ElementAt(i);
                Assert.AreEqual(expected.Offset, resultDiffBlock.Offset);
                Assert.AreEqual(expected.Lenght, resultDiffBlock.Lenght);
            }
        }
コード例 #3
0
        public void AnalyseMethodShouldReturnOneDifferenceFoundWhenDifferencesAreInTheBeginningInRightBlock()
        {
            // Arrange
            var leftBlock  = new byte[] { 1, 2, 3, 4, 5 };
            var rightBlock = new byte[] { 0, 0, 0, 4, 5 };

            var expectedDiffBlock = new DiffBlock(0, 3);
            // Act
            var result = _diffAnalyser.Analyse(leftBlock, rightBlock);

            // Assert
            AssertDifferenceFound(result, expectedDiffBlock);
        }
コード例 #4
0
        public static void AppendDiffBlock(this DiffFile diffFile, int blockPosition, int offset,
                                           DiffBlockType type)
        {
            var diffBlock = diffFile.Blocks.LastOrDefault();

            if (diffBlock != null && diffBlock.Type == type &&
                diffBlock.EndPosition + 1 == blockPosition)
            {
                diffBlock.EndPosition++;
                return;
            }

            diffBlock = new DiffBlock(offset, blockPosition, blockPosition, type);
            diffFile.Blocks.Add(diffBlock);
        }
コード例 #5
0
ファイル: Version.cs プロジェクト: RichardBradley/MMEd
            ///======================================================================
            /// Static Method : ApplyPatch
            ///
            /// <summary>
            ///     Apply the supplied DiffBlocks to the source array to undo the
            ///   operation of GetDifferences().
            /// </summary>
            /// <param name="xiA"></param>
            /// <param name="xiDiffs"></param>
            /// <returns></returns>
            ///======================================================================
            public static byte[] ApplyPatch(byte[] xiA, DiffBlock[] xiDiffs)
            {
                //=====================================================================
                // Calculate the length of the final byte array
                //=====================================================================
                int lNewLength = xiA.Length;

                if (xiDiffs.Length > 0)
                {
                    DiffBlock lFinalDiff = xiDiffs[xiDiffs.Length - 1];

                    if (lFinalDiff.mData.Length == 0)
                    {
                        lNewLength = lFinalDiff.mOffset;
                    }
                    else if (lFinalDiff.mOffset + lFinalDiff.mData.Length > xiA.Length)
                    {
                        lNewLength = lFinalDiff.mOffset + lFinalDiff.mData.Length;
                    }
                }

                byte[] lRet = new byte[lNewLength];

                //=====================================================================
                // Fill in the data
                //=====================================================================
                int lOffset = 0;

                foreach (DiffBlock lDiff in xiDiffs)
                {
                    int lCopyLength = lDiff.mOffset - lOffset;
                    Array.Copy(xiA, lOffset, lRet, lOffset, lCopyLength);
                    lOffset += lCopyLength;

                    Array.Copy(lDiff.mData, 0, lRet, lOffset, lDiff.mData.Length);
                    lOffset += lDiff.mData.Length;
                }

                if (lRet.Length != lOffset)
                {
                    Array.Copy(xiA, lOffset, lRet, lOffset, lRet.Length - lOffset);
                }

                return(lRet);
            }
コード例 #6
0
        public void ApplyDiffInfo(DiffFile diffFile)
        {
            StringBuilder diffCodeBuilder = new StringBuilder();
            int           currentLine     = 0;
            int           diffLineOffset  = 0;

            for (int i = 0; i < diffFile.Blocks.Count; i++)
            {
                DiffBlock block = diffFile.Blocks[i];

                for (; currentLine < block.StartPosition - block.Offset; currentLine++)
                {
                    string line = diffFile.Lines[currentLine];
                    diffCodeBuilder.Append(line).Append(this.NewLine);
                }
                if (block.Type == DiffBlockType.Imaginary)
                {
                    int addedLines = block.EndPosition - block.StartPosition + 1;
                    for (int j = addedLines, k = 0; j > 0; j--, k++)
                    {
                        diffCodeBuilder.Append(this.NewLine);
                    }

                    diffLineOffset += addedLines;
                    originalLineNumberToRelativeDiffLineOffsetMap.Add(new DiffLineInfo(currentLine, diffLineOffset));
                }
                if (block.Type != DiffBlockType.Unchanged)
                {
                    for (int k = block.StartPosition; k <= block.EndPosition; k++)
                    {
                        lineToClasificationTypeMap.Add(k, ConvertDiffBlockTypeToClassificationType(block.Type));
                    }
                }
            }
            for (; currentLine < diffFile.Lines.Count; currentLine++)
            {
                diffCodeBuilder.Append(diffFile.Lines[currentLine]).Append(this.NewLine);
            }
            this.totalLineCount     = currentLine + diffLineOffset;
            this.sourceCode         = diffCodeBuilder.ToString();
            this.BackgroundRenderer = new DiffBackgroundRenderer(lineToClasificationTypeMap);
        }
コード例 #7
0
ファイル: Version.cs プロジェクト: RichardBradley/MMEd
        ///========================================================================
        /// Method : Deserialise
        ///
        /// <summary>
        ///     Diesierliase this Version from binary format.
        /// </summary>
        /// <param name="xiInStream"></param>
        ///========================================================================
        public override void Deserialise(Stream xiInStream)
        {
            BinaryReader lInput = new BinaryReader(xiInStream);

            //=======================================================================
            // Check the magic number
            //=======================================================================
            int lMagicNumber = lInput.ReadInt32();

            if (lMagicNumber != MAGIC_NUMBER)
            {
                throw new DeserialisationException(string.Format(
                                                       "Version has the wrong magic number! Expected {0}, found {1}", MAGIC_NUMBER, lMagicNumber));
            }

            //=======================================================================
            // Work out whether we've got differences or a whole level, and
            // read in accordingly.
            //=======================================================================
            bool lDifferential = lInput.ReadBoolean();
            int  lLength       = lInput.ReadInt32();

            if (lDifferential)
            {
                DifferentialLevel = new DiffBlock[lLength];

                for (int ii = 0; ii < DifferentialLevel.Length; ii++)
                {
                    DifferentialLevel[ii] = new DiffBlock(lInput);
                }
            }
            else
            {
                SerialisedLevel = lInput.ReadBytes(lLength);
            }

            //=======================================================================
            // Read the creation date and change list
            //=======================================================================
            CreationDate = DateTime.FromBinary(lInput.ReadInt64());
            Changes      = StreamUtils.ReadASCIINullTermString(xiInStream);
        }
コード例 #8
0
        /// <summary>
        /// Adapt the result into a set of misspelling operations.
        /// </summary>
        /// <param name="result">result</param>
        /// <returns>zero or more misspelling operations</returns>
        /// <exception cref="ArgumentNullException">null result</exception>
        public IList <MspOperation> Adapt(DiffResult result)
        {
            if (result == null)
            {
                throw new ArgumentNullException(nameof(result));
            }

            // create the A and B strings, assuming that in char diffing each piece
            // is a single char.
            string a = string.Concat(result.PiecesOld);
            string b = string.Concat(result.PiecesNew);

            List <MspOperation> operations = new List <MspOperation>();
            int i = 0;

            while (i < result.DiffBlocks.Count)
            {
                DiffBlock block = result.DiffBlocks[i];

                // REPLACE: a-del.count > 0 && b-ins.count > 0
                if (block.DeleteCountA > 0 && block.InsertCountB > 0)
                {
                    operations.Add(new MspOperation
                    {
                        Operator = MspOperator.Replace,
                        RangeA   = new TextRange(block.DeleteStartA, block.DeleteCountA),
                        RangeB   = new TextRange(block.InsertStartB, block.InsertCountB),
                        ValueA   = a.Substring(block.DeleteStartA, block.DeleteCountA),
                        ValueB   = b.Substring(block.InsertStartB, block.InsertCountB)
                    });
                    i++;
                    continue;
                } // rep

                // DELETE: a-del.count > 0 && b-ins.count = 0
                if (block.DeleteCountA > 0 && block.InsertCountB == 0)
                {
                    // MOVE corner case: delete+insert
                    DiffBlock next = i + 1 < result.DiffBlocks.Count ?
                                     result.DiffBlocks[i + 1] : null;
                    if (next?.DeleteCountA == 0 &&
                        next.InsertCountB > 0 &&
                        b.Substring(block.InsertStartB, block.InsertCountB)
                        == a.Substring(next.DeleteStartA, next.DeleteCountA))
                    {
                        operations.Add(new MspOperation
                        {
                            Operator = MspOperator.Move,
                            RangeA   = new TextRange(
                                block.DeleteStartA, block.DeleteCountA),
                            RangeB = new TextRange(
                                next.InsertStartB, next.InsertCountB),
                            ValueA = a.Substring(
                                block.DeleteStartA, block.DeleteCountA),
                            ValueB = null
                        });
                        i += 2;
                        continue;
                    } // mov

                    operations.Add(new MspOperation
                    {
                        Operator = MspOperator.Delete,
                        RangeA   = new TextRange(
                            block.DeleteStartA, block.DeleteCountA),
                        RangeB = new TextRange(
                            block.InsertStartB, block.InsertCountB),
                        ValueA = a.Substring(
                            block.DeleteStartA, block.DeleteCountA),
                        ValueB = null
                    });
                    i++;
                    continue;
                } // del

                // INSERT: a-del.count = 0 && b-ins.count > 0
                if (block.DeleteCountA == 0 && block.InsertCountB > 0)
                {
                    // SWAP corner case: insert+delete
                    DiffBlock next = i + 1 < result.DiffBlocks.Count ?
                                     result.DiffBlocks[i + 1] : null;
                    string inserted;

                    if (next?.DeleteCountA > 0 &&
                        next.InsertCountB == 0 &&
                        Math.Abs(block.DeleteStartA - next.DeleteStartA) == 1 &&
                        (inserted = b.Substring(
                             block.InsertStartB, block.InsertCountB))
                        == a.Substring(next.DeleteStartA, next.DeleteCountA))
                    {
                        operations.Add(new MspOperation
                        {
                            Operator = MspOperator.Swap,
                            RangeA   = new TextRange(
                                block.DeleteStartA, inserted.Length),
                            RangeB = new TextRange(
                                next.DeleteStartA, block.InsertCountB),
                            ValueA = a.Substring(
                                block.DeleteStartA, inserted.Length),
                            ValueB = inserted
                        });
                        i += 2;
                        continue;
                    } // swap

                    operations.Add(new MspOperation
                    {
                        Operator = MspOperator.Insert,
                        RangeA   = new TextRange(
                            block.DeleteStartA, block.DeleteCountA),
                        RangeB = new TextRange(
                            block.InsertStartB, block.InsertCountB),
                        ValueA = null,
                        ValueB = b.Substring(
                            block.InsertStartB, block.InsertCountB)
                    });
                    i++;
                    continue;
                } // ins

                i++;
            }

            return(operations);
        }
コード例 #9
0
ファイル: Version.cs プロジェクト: RichardBradley/MMEd
            ///======================================================================
            /// Static Method : ApplyPatch
            /// 
            /// <summary>
            /// 	Apply the supplied DiffBlocks to the source array to undo the 
            ///   operation of GetDifferences().
            /// </summary>
            /// <param name="xiA"></param>
            /// <param name="xiDiffs"></param>
            /// <returns></returns>
            ///======================================================================
            public static byte[] ApplyPatch(byte[] xiA, DiffBlock[] xiDiffs)
            {
                //=====================================================================
                // Calculate the length of the final byte array
                //=====================================================================
                int lNewLength = xiA.Length;

                if (xiDiffs.Length > 0)
                {
                  DiffBlock lFinalDiff = xiDiffs[xiDiffs.Length - 1];

                  if (lFinalDiff.mData.Length == 0)
                  {
                lNewLength = lFinalDiff.mOffset;
                  }
                  else if (lFinalDiff.mOffset + lFinalDiff.mData.Length > xiA.Length)
                  {
                lNewLength = lFinalDiff.mOffset + lFinalDiff.mData.Length;
                  }
                }

                byte[] lRet = new byte[lNewLength];

                //=====================================================================
                // Fill in the data
                //=====================================================================
                int lOffset = 0;

                foreach (DiffBlock lDiff in xiDiffs)
                {
                  int lCopyLength = lDiff.mOffset - lOffset;
                  Array.Copy(xiA, lOffset, lRet, lOffset, lCopyLength);
                  lOffset += lCopyLength;

                  Array.Copy(lDiff.mData, 0, lRet, lOffset, lDiff.mData.Length);
                  lOffset += lDiff.mData.Length;
                }

                if (lRet.Length != lOffset)
                {
                  Array.Copy(xiA, lOffset, lRet, lOffset, lRet.Length - lOffset);
                }

                return lRet;
            }
コード例 #10
0
ファイル: Version.cs プロジェクト: RichardBradley/MMEd
        ///========================================================================
        /// Method : Deserialise
        /// 
        /// <summary>
        /// 	Diesierliase this Version from binary format.
        /// </summary>
        /// <param name="xiInStream"></param>
        ///========================================================================
        public override void Deserialise(Stream xiInStream)
        {
            BinaryReader lInput = new BinaryReader(xiInStream);

              //=======================================================================
              // Check the magic number
              //=======================================================================
              int lMagicNumber = lInput.ReadInt32();

              if (lMagicNumber != MAGIC_NUMBER)
              {
            throw new DeserialisationException(string.Format(
              "Version has the wrong magic number! Expected {0}, found {1}", MAGIC_NUMBER, lMagicNumber));
              }

              //=======================================================================
              // Work out whether we've got differences or a whole level, and
              // read in accordingly.
              //=======================================================================
              bool lDifferential = lInput.ReadBoolean();
              int lLength = lInput.ReadInt32();

              if (lDifferential)
              {
            DifferentialLevel = new DiffBlock[lLength];

            for (int ii = 0; ii < DifferentialLevel.Length; ii++)
            {
              DifferentialLevel[ii] = new DiffBlock(lInput);
            }
              }
              else
              {
            SerialisedLevel = lInput.ReadBytes(lLength);
              }

              //=======================================================================
              // Read the creation date and change list
              //=======================================================================
              CreationDate = DateTime.FromBinary(lInput.ReadInt64());
              Changes = StreamUtils.ReadASCIINullTermString(xiInStream);
        }
コード例 #11
0
ファイル: Version.cs プロジェクト: RichardBradley/MMEd
        ///========================================================================
        /// Constructor : Version
        ///
        /// <summary>
        ///     Create a new version
        /// </summary>
        /// <param name="xiLevel"></param>
        /// <param name="xiPreviousVersion"></param>
        /// <param name="xiStoreAsDiff"></param>
        /// <param name="xiExpectedSize"></param>
        ///========================================================================
        internal Version(Level xiLevel, Version xiPreviousVersion, bool xiStoreAsDiff, long xiExpectedSize)
        {
            CreationDate = DateTime.Now;

            //=======================================================================
            // Serialise the level
            //=======================================================================
            while (true)
            {
                using (MemoryStream lLevelStream = new MemoryStream())
                {
                    xiLevel.Serialise(lLevelStream);
                    lLevelStream.Seek(0, SeekOrigin.Begin);
                    SerialisedLevel = new byte[lLevelStream.Length];
                    lLevelStream.Read(SerialisedLevel, 0, SerialisedLevel.Length);
                }

                if (xiExpectedSize > 0 && SerialisedLevel.Length != xiExpectedSize)
                {
                    long lSizeAdjustment = SerialisedLevel.Length - xiExpectedSize;

                    if (lSizeAdjustment > 0 && xiLevel.SHET.TrailingZeroByteCount < lSizeAdjustment)
                    {
                        MessageBox.Show(string.Format(@"WARNING: The level is too large to fit in the expected size of file. Please remove some content from the level. Your level can be saved, but attempts to play the course will fail.

Expected size: {0} bytes
Actual size: {1} bytes
Spare space: {2} bytes
Space required: {3} bytes",
                                                      xiExpectedSize,
                                                      SerialisedLevel.Length,
                                                      xiLevel.SHET.TrailingZeroByteCount,
                                                      lSizeAdjustment - xiLevel.SHET.TrailingZeroByteCount), "MMEd", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                    }
                    else if (MessageBox.Show("WARNING: The level is not of the expected size for this course. Do you want to adjust the file size to match? This can be done without corrupting the level.", "MMEd", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
                    {
                        xiLevel.SHET.TrailingZeroByteCount -= (int)lSizeAdjustment;
                        continue;
                    }
                }

                break;
            }

            //=======================================================================
            // Calculate differences, and store as a diff if appropriate
            //=======================================================================
            if (xiPreviousVersion != null)
            {
                Changes = string.Join("\r\n", xiLevel.GetDifferences(xiPreviousVersion.GetLevel(null)).ToArray());
            }
            else
            {
                Changes = "";
            }

            if (xiStoreAsDiff)
            {
                DifferentialLevel = DiffBlock.GetDifferences(xiPreviousVersion.SerialisedLevel, SerialisedLevel);
            }
        }