// Constructor internal EditScript( EditScript next) { _nextEditScript = next; }
// Constructor internal EditScriptMatch( int startSourceIndex, int startTargetIndex, int length, EditScript next ) : base ( next ) { Debug.Assert( length > 0 ); Debug.Assert( startSourceIndex > 0 ); Debug.Assert( startTargetIndex > 0 ); _firstSourceIndex = startSourceIndex; _firstTargetIndex = startTargetIndex; _length = length; }
// Constructor internal EditScriptOpened(EditScript next) : base(next) { }
// Constructor internal EditScriptReference( EditScript editScriptReference, EditScript next ) : base( next ) { Debug.Assert( editScriptReference != null ); Debug.Assert( next != null ); _editScriptReference = editScriptReference; }
private void OnMatch( DiffgramParentOperation parent, bool bNeedPosition ) { EditScriptMatch matchOp = _editScript as EditScriptMatch; Debug.Assert( _curSourceIndex == matchOp._firstSourceIndex + matchOp._length - 1 ); Debug.Assert( _curTargetIndex == matchOp._firstTargetIndex + matchOp._length - 1 ); // cache int endTargetIndex = matchOp._firstTargetIndex + matchOp._length - 1; int endSourceIndex = matchOp._firstSourceIndex + matchOp._length - 1; XmlDiffNode targetRoot = _targetNodes[ endTargetIndex ]; XmlDiffNode sourceRoot = _sourceNodes[ endSourceIndex ]; // a subtree or leaf node matches if ( matchOp._firstTargetIndex <= targetRoot.Left && matchOp._firstSourceIndex <= sourceRoot.Left ) { if ( _bBuildingAddTree ) { Debug.Assert( !bNeedPosition ); ulong opid = GenerateOperationID( XmlDiffDescriptorType.Move ); // output <add match=" "> to diffgram and "remove" to substitute script parent.InsertAtBeginning( new DiffgramCopy( sourceRoot, true, opid ) ); // add 'remove' operation to postponed operations PostponedRemoveSubtrees( sourceRoot, opid, //AddToPosponedOperations( new DiffgramRemoveSubtrees( sourceRoot, opid ), sourceRoot.Left, endSourceIndex ); } else { // matched element -> check attributes if they really match (hash values of attributes matches) if ( sourceRoot.NodeType == XmlDiffNodeType.Element ) { DiffgramPosition diffPos = _cachedDiffgramPosition; diffPos._sourceNode = sourceRoot; GenerateChangeDiffgramForAttributes( diffPos, (XmlDiffElement)sourceRoot, (XmlDiffElement)targetRoot ); if ( diffPos._firstChildOp != null || bNeedPosition ) { parent.InsertAtBeginning( diffPos ); _cachedDiffgramPosition = new DiffgramPosition( null ); bNeedPosition = false; } } // otherwise output <node> - only if we need the position (<=> preceding operation was 'add') else { if ( bNeedPosition ) { parent.InsertAtBeginning( new DiffgramPosition( sourceRoot ) ); bNeedPosition = false; } // xml declaration, DTD else if ( !_bChildOrderSignificant && (int)sourceRoot.NodeType < 0 ) { DiffgramOperation op = parent._firstChildOp; if ( op is DiffgramAddNode || op is DiffgramAddSubtrees || op is DiffgramCopy ) { parent.InsertAtBeginning( new DiffgramPosition( sourceRoot ) ); } } } } // adjust current position _curSourceIndex = sourceRoot.Left - 1; _curTargetIndex = targetRoot.Left - 1; // adjust boundaries in the edit script or move to next edit script operation matchOp._length -= endTargetIndex - targetRoot.Left + 1; if ( matchOp._length <= 0 ) _editScript = _editScript._nextEditScript; } // single but non-leaf node matches (-> recursively generate the diffgram subtree) else { // adjust current position _curSourceIndex--; _curTargetIndex--; // adjust boundaries in the edit script or move to next edit script operation matchOp._length--; if ( matchOp._length <= 0 ) _editScript = _editScript._nextEditScript; DiffgramParentOperation diffgramNode; if ( _bBuildingAddTree ) { Debug.Assert( !bNeedPosition ); ulong opid = GenerateOperationID( XmlDiffDescriptorType.Move ); bool bCopySubtree = sourceRoot.NodeType != XmlDiffNodeType.Element; // output <add match=".." subtree="no"> diffgramNode = new DiffgramCopy( sourceRoot, bCopySubtree, opid ); // add 'remove' operation to postponed operations PostponedRemoveNode( sourceRoot, bCopySubtree, opid, endSourceIndex, endSourceIndex ); // recursively generate the diffgram subtree GenerateDiffgramAdd( diffgramNode, sourceRoot.Left, targetRoot.Left ); // insert to diffgram tree parent.InsertAtBeginning( diffgramNode ); } else { // output <node> diffgramNode = new DiffgramPosition( sourceRoot ); // recursively generate the diffgram subtree GenerateDiffgramMatch( diffgramNode, sourceRoot.Left, targetRoot.Left ); // insert to diffgram tree if ( diffgramNode._firstChildOp != null ) parent.InsertAtBeginning( diffgramNode ); } } }
private void OnRemove( DiffgramParentOperation parent ) { EditScriptRemove remOp = _editScript as EditScriptRemove; Debug.Assert( remOp._endSourceIndex == _curSourceIndex ); XmlDiffNode sourceRoot = _sourceNodes[ remOp._endSourceIndex ]; // remove subtree or leaf node and no descendant node matches (=has been moved somewhere else) if ( remOp._startSourceIndex <= sourceRoot.Left ) { bool bShrankNode = sourceRoot is XmlDiffShrankNode; if ( sourceRoot._bSomeDescendantMatches && !bShrankNode ) { DiffgramOperation newDiffOp = GenerateDiffgramRemoveWhenDescendantMatches( (XmlDiffParentNode)sourceRoot ); if ( _bBuildingAddTree ) { PostponedOperation( newDiffOp, sourceRoot.Left, remOp._endSourceIndex ); } else { parent.InsertAtBeginning( newDiffOp ); } } else { ulong opid = 0; // shrank node -> output as 'move' operation if ( bShrankNode ) { XmlDiffShrankNode shrankNode = (XmlDiffShrankNode) sourceRoot; if ( shrankNode.MoveOperationId == 0 ) shrankNode.MoveOperationId = GenerateOperationID( XmlDiffDescriptorType.Move ); opid = shrankNode.MoveOperationId; Debug.Assert( sourceRoot == _sourceNodes[ sourceRoot.Left ] ); } // insert 'remove' operation if ( _bBuildingAddTree ) { PostponedRemoveSubtrees( sourceRoot, opid, //AddToPosponedOperations( new DiffgramRemoveSubtrees( sourceRoot, opid ), sourceRoot.Left, remOp._endSourceIndex ); } else { if ( opid != 0 || !parent.MergeRemoveSubtreeAtBeginning( sourceRoot ) ) { parent.InsertAtBeginning( new DiffgramRemoveSubtrees( sourceRoot, opid, !_xmlDiff.IgnoreChildOrder ) ); } } } // adjust current position _curSourceIndex = sourceRoot.Left - 1; // adjust boundaries in the edit script or move to next edit script operation remOp._endSourceIndex = sourceRoot.Left - 1; if ( remOp._startSourceIndex > remOp._endSourceIndex ) _editScript = _editScript._nextEditScript; } // remove single but non-leaf node or some descendant matches (=has been moved somewhere else) // -> recursively process diffgram subtree else { Debug.Assert( !( sourceRoot is XmlDiffShrankNode) ); // adjust current position _curSourceIndex--; // adjust boundaries in the edit script or move to next edit script operation remOp._endSourceIndex--; if ( remOp._startSourceIndex > remOp._endSourceIndex ) _editScript = _editScript._nextEditScript; bool bRemoveSubtree = sourceRoot.NodeType != XmlDiffNodeType.Element; if ( _bBuildingAddTree ) { // add 'remove' to postponed operations PostponedRemoveNode( sourceRoot, bRemoveSubtree, 0, //AddToPosponedOperations( new DiffgramRemoveNode( sourceRoot, bRemoveSubtree, 0 ), remOp._endSourceIndex + 1, remOp._endSourceIndex + 1 ); // recursively parse subtree GenerateDiffgramAdd( parent, sourceRoot.Left, _targetNodes[ _curTargetIndex ].Left ); } else { // 'remove' operation DiffgramRemoveNode remNode = new DiffgramRemoveNode( sourceRoot, bRemoveSubtree, 0 ); // parse subtree GenerateDiffgramMatch( remNode, sourceRoot.Left, _targetNodes[ _curTargetIndex ].Left ); parent.InsertAtBeginning( remNode ); } } }
// Constructor internal EditScriptChange( int sourceIndex, int targetIndex, XmlDiffOperation changeOp, EditScript next ) : base( next ) { Debug.Assert( sourceIndex > 0 ); Debug.Assert( targetIndex > 0 ); Debug.Assert( XmlDiff.IsChangeOperation( changeOp) ); _sourceIndex = sourceIndex; _targetIndex = targetIndex; _changeOp = changeOp; }
// produces <change> element in diffgram private void OnChange( DiffgramParentOperation parent ) { EditScriptChange chOp = _editScript as EditScriptChange; Debug.Assert( chOp._targetIndex == _curTargetIndex ); Debug.Assert( chOp._sourceIndex == _curSourceIndex ); XmlDiffNode sourceRoot = _sourceNodes[ chOp._sourceIndex ]; XmlDiffNode targetRoot = _targetNodes[ chOp._targetIndex ]; Debug.Assert( !( sourceRoot is XmlDiffShrankNode) ); Debug.Assert( !( targetRoot is XmlDiffShrankNode) ); // adjust current position _curSourceIndex--; _curTargetIndex--; // move to next edit script operation _editScript = _editScript._nextEditScript; DiffgramOperation diffgramNode = null; if ( _bBuildingAddTree ) { // <add> changed node to the new location if ( targetRoot.NodeType == XmlDiffNodeType.Element ) diffgramNode = new DiffgramAddNode( targetRoot, 0 ); else diffgramNode = new DiffgramAddSubtrees( targetRoot, 0, !_xmlDiff.IgnoreChildOrder ); // <remove> old node from old location -> add to postponed operations bool bSubtree = sourceRoot.NodeType != XmlDiffNodeType.Element; PostponedRemoveNode( sourceRoot, bSubtree, 0, //AddToPosponedOperations( new DiffgramRemoveNode( sourceRoot, bSubtree, 0 ), chOp._sourceIndex, chOp._sourceIndex ); // recursively process children if ( sourceRoot.Left < chOp._sourceIndex || targetRoot.Left < chOp._targetIndex ) { Debug.Assert( targetRoot.NodeType == XmlDiffNodeType.Element ); GenerateDiffgramAdd( (DiffgramParentOperation)diffgramNode, sourceRoot.Left, targetRoot.Left ); } // add attributes, if element if ( targetRoot.NodeType == XmlDiffNodeType.Element ) GenerateAddDiffgramForAttributes( (DiffgramParentOperation)diffgramNode, (XmlDiffElement)targetRoot ); } else { ulong opid = 0; // change of namespace or prefix -> get the appropriate operation id if ( !_xmlDiff.IgnoreNamespaces && sourceRoot.NodeType == XmlDiffNodeType.Element ) { XmlDiffElement sourceEl = (XmlDiffElement)sourceRoot; XmlDiffElement targetEl = (XmlDiffElement)targetRoot; if ( sourceEl.LocalName == targetEl.LocalName ) { opid = GetNamespaceChangeOpid( sourceEl.NamespaceURI, sourceEl.Prefix, targetEl.NamespaceURI, targetEl.Prefix ); } } if ( sourceRoot.NodeType == XmlDiffNodeType.Element ) { if ( XmlDiff.IsChangeOperationOnAttributesOnly( chOp._changeOp ) ) diffgramNode = new DiffgramPosition( sourceRoot ); else { Debug.Assert( (int)chOp._changeOp == (int)XmlDiffOperation.ChangeElementName || ( (int)chOp._changeOp >= (int)XmlDiffOperation.ChangeElementNameAndAttr1 && (int)chOp._changeOp <= (int)XmlDiffOperation.ChangeElementNameAndAttr2 ) ); diffgramNode = new DiffgramChangeNode( sourceRoot, targetRoot, XmlDiffOperation.ChangeElementName, opid ); } // recursively process children if ( sourceRoot.Left < chOp._sourceIndex || targetRoot.Left < chOp._targetIndex ) { GenerateDiffgramMatch( (DiffgramParentOperation) diffgramNode, sourceRoot.Left, targetRoot.Left ); } GenerateChangeDiffgramForAttributes( (DiffgramParentOperation)diffgramNode, (XmlDiffElement)sourceRoot, (XmlDiffElement)targetRoot ); } else { // '<change>' diffgramNode = new DiffgramChangeNode( sourceRoot, targetRoot, chOp._changeOp, opid ); Debug.Assert( !sourceRoot.HasChildNodes ); } } parent.InsertAtBeginning( diffgramNode ); }
// Constructor internal EditScriptAdd( int startTargetIndex, int endTargetIndex, EditScript next ) : base ( next ) { Debug.Assert( endTargetIndex - startTargetIndex >= 0 ); Debug.Assert( startTargetIndex > 0 ); Debug.Assert( endTargetIndex > 0 ); _startTargetIndex = startTargetIndex; _endTargetIndex = endTargetIndex; }
// Constructor internal EditScriptRemove( int startSourceIndex, int endSourceIndex, EditScript next ) : base ( next ) { Debug.Assert( endSourceIndex - startSourceIndex >= 0 ); Debug.Assert( startSourceIndex > 0 ); Debug.Assert( endSourceIndex > 0 ); _startSourceIndex = startSourceIndex; _endSourceIndex = endSourceIndex; }
// Constructor internal EditScriptRemoveOpened(int startSourceIndex, EditScript next) : base(next) { Debug.Assert(startSourceIndex > 0); _startSourceIndex = startSourceIndex; }
// Constructor internal EditScript(EditScript next) { _nextEditScript = next; }
// Constructor internal EditScriptAddOpened(int startTargetIndex, EditScript next) : base(next) { Debug.Assert(startTargetIndex > 0); _startTargetIndex = startTargetIndex; }
private void GenerateDiffgramPostponed( DiffgramParentOperation parent, ref EditScript editScript, int sourceBorderIndex, int targetBorderIndex ) { while ( _curSourceIndex >= sourceBorderIndex && editScript != null ) { EditScriptPostponed esp = editScript as EditScriptPostponed; if ( esp == null ) { GenerateDiffgramMatch( parent, sourceBorderIndex, targetBorderIndex ); return; } Debug.Assert( esp._endSourceIndex == _curSourceIndex ); int sourceStartIndex = esp._startSourceIndex; int sourceLeft = _sourceNodes[ esp._endSourceIndex ].Left; DiffgramOperation diffOp = esp._diffOperation; // adjust current source index _curSourceIndex = esp._startSourceIndex - 1; // move to next edit script editScript = esp._nextEditScript; // not a subtree or leaf node operation -> process child operations if ( sourceStartIndex > sourceLeft ) { GenerateDiffgramPostponed( (DiffgramParentOperation) diffOp, ref editScript, sourceLeft, targetBorderIndex ); } // insert operation parent.InsertAtBeginning( diffOp ); } }
// Constructor internal EditScriptOpened( EditScript next ) : base ( next ) {}
// returns true if a positioning <node> element is needed in diffgram private bool OnAdd( DiffgramParentOperation parent, int sourceBorderIndex, int targetBorderIndex ) { EditScriptAdd addOp = _editScript as EditScriptAdd; Debug.Assert( addOp._endTargetIndex == _curTargetIndex ); XmlDiffNode targetRoot = _targetNodes[ addOp._endTargetIndex ]; // add subtree or leaf node and no descendant node matches (= has been moved from somewhere else) if ( addOp._startTargetIndex <= targetRoot.Left && !targetRoot._bSomeDescendantMatches ) { switch ( targetRoot.NodeType ) { case XmlDiffNodeType.ShrankNode: XmlDiffShrankNode shrankNode = (XmlDiffShrankNode)targetRoot; if ( shrankNode.MoveOperationId == 0 ) shrankNode.MoveOperationId = GenerateOperationID( XmlDiffDescriptorType.Move ); parent.InsertAtBeginning( new DiffgramCopy( shrankNode.MatchingShrankNode, true, shrankNode.MoveOperationId ) ); break; case XmlDiffNodeType.XmlDeclaration: case XmlDiffNodeType.DocumentType: case XmlDiffNodeType.EntityReference: parent.InsertAtBeginning( new DiffgramAddNode( targetRoot, 0 ) ); break; default: if ( !parent.MergeAddSubtreeAtBeginning( targetRoot ) ) { parent.InsertAtBeginning( new DiffgramAddSubtrees( targetRoot, 0, !_xmlDiff.IgnoreChildOrder ) ); } break; } // adjust current position _curTargetIndex = targetRoot.Left - 1; // adjust boundaries in the edit script or move to next edit script operation addOp._endTargetIndex = targetRoot.Left - 1; if ( addOp._startTargetIndex > addOp._endTargetIndex ) _editScript = _editScript._nextEditScript; } // add single but non-leaf node, or some descendant matches (= has been moved from somewhere else ) // -> recursively process diffgram subtree else { Debug.Assert( !( targetRoot is XmlDiffShrankNode) ); DiffgramAddNode addNode = new DiffgramAddNode( targetRoot, 0 ); // adjust current position _curTargetIndex--; // adjust boundaries in the edit script or move to next edit script operation addOp._endTargetIndex--; if ( addOp._startTargetIndex > addOp._endTargetIndex ) _editScript = _editScript._nextEditScript; if ( _bBuildingAddTree ) { GenerateDiffgramAdd( addNode, sourceBorderIndex, targetRoot.Left ); } else { // switch to 'building add-tree' mode _postponedEditScript.Reset(); _bBuildingAddTree = true; // generate new tree GenerateDiffgramAdd( addNode, sourceBorderIndex, targetRoot.Left ); _bBuildingAddTree = false; // attach postponed edit script to _editScript for futher processing if ( _postponedEditScript._firstES != null ) { Debug.Assert( _postponedEditScript._lastES != null ); Debug.Assert( _postponedEditScript._startSourceIndex != 0 ); Debug.Assert( _postponedEditScript._endSourceIndex != 0 ); _curSourceIndex = _postponedEditScript._endSourceIndex; _postponedEditScript._lastES._nextEditScript = _editScript; _editScript = _postponedEditScript._firstES; } } // add attributes if ( targetRoot.NodeType == XmlDiffNodeType.Element ) GenerateAddDiffgramForAttributes( addNode, (XmlDiffElement)targetRoot ); parent.InsertAtBeginning( addNode ); } // return true if positioning <node> element is needed in diffgram if ( _bChildOrderSignificant ) { return !_bBuildingAddTree; } else { return false; } }
// Constructor internal EditScriptMatchOpened( int startSourceIndex, int startTargetIndex, EditScript next ) : base ( next ) { Debug.Assert( startSourceIndex > 0 ); Debug.Assert( startTargetIndex > 0 ); _startSourceIndex = startSourceIndex; _startTargetIndex = startTargetIndex; }
void OnEditScriptPostponed( DiffgramParentOperation parent, int targetBorderIndex ) { EditScriptPostponed esp = (EditScriptPostponed)_editScript; Debug.Assert( _curSourceIndex == esp._endSourceIndex ); DiffgramOperation diffOp = esp._diffOperation; int sourceStartIndex = esp._startSourceIndex; int sourceLeft = _sourceNodes[ esp._endSourceIndex ].Left; // adjust current source index _curSourceIndex = esp._startSourceIndex - 1; // move to next edit script _editScript = esp._nextEditScript; // not a subtree or leaf node operation -> process child operations if ( sourceStartIndex > sourceLeft ) { GenerateDiffgramPostponed( (DiffgramParentOperation)diffOp, ref _editScript, sourceLeft, targetBorderIndex ); } parent.InsertAtBeginning( diffOp ); }
// Constructor internal EditScriptAddOpened( int startTargetIndex, EditScript next ) : base ( next ) { Debug.Assert( startTargetIndex > 0 ); _startTargetIndex = startTargetIndex; }
// Methods internal Diffgram GenerateFromEditScript( EditScript editScript ) { Debug.Assert( editScript != null ); Debug.Assert( _xmlDiff._sourceNodes != null ); Debug.Assert( _xmlDiff._targetNodes != null ); _sourceNodes = _xmlDiff._sourceNodes; _targetNodes = _xmlDiff._targetNodes; Diffgram diffgram = new Diffgram( _xmlDiff ); // root nodes always match; remove them from the edit script EditScriptMatch esm = editScript as EditScriptMatch; if ( editScript.Operation == EditScriptOperation.Match && ( esm._firstSourceIndex + esm._length == _sourceNodes.Length && esm._firstTargetIndex + esm._length == _targetNodes.Length ) ) { esm._length--; if ( esm._length == 0 ) editScript = esm._nextEditScript; } else Debug.Assert( false, "The root nodes does not match!" ); // init globals _curSourceIndex = _sourceNodes.Length - 2; _curTargetIndex = _targetNodes.Length - 2; _editScript = editScript; // generate diffgram GenerateDiffgramMatch( diffgram, 1, 1 ); // add descriptors AppendDescriptors( diffgram ); return diffgram; }
// Constructor internal EditScriptRemoveOpened( int startSourceIndex, EditScript next ) : base ( next ) { Debug.Assert( startSourceIndex > 0 ); _startSourceIndex = startSourceIndex; }
// Static methods // This method expands 'reference edit script' items and removes the last item // (which is the static instance of EmptyEditScript). private static EditScript NormalizeScript( EditScript es ) { EditScript returnES = es; EditScript curES = es; EditScript prevES = null; while ( curES != EmptyEditScript ) { Debug.Assert( curES != null ); if ( curES.Operation != EditScriptOperation.EditScriptReference ) { prevES = curES; curES = curES._nextEditScript; } else { EditScriptReference refES = curES as EditScriptReference; EditScript lastES = refES._editScriptReference; Debug.Assert( lastES != EmptyEditScript && lastES != null ); while ( lastES.Next != EmptyEditScript ) { lastES = lastES._nextEditScript; Debug.Assert( lastES != null ); } lastES._nextEditScript = curES._nextEditScript; curES = refES._editScriptReference; if ( prevES == null ) returnES = curES; else prevES._nextEditScript = curES; } } if ( prevES != null ) prevES._nextEditScript = null; else returnES = null; return returnES; }
// Constructor internal EditScriptChange(int sourceIndex, int targetIndex, XmlDiffOperation changeOp, EditScript next) : base(next) { Debug.Assert(sourceIndex > 0); Debug.Assert(targetIndex > 0); Debug.Assert(XmlDiff.IsChangeOperation(changeOp)); _sourceIndex = sourceIndex; _targetIndex = targetIndex; _changeOp = changeOp; }