#include #include #include #include #include #include "debug.h" #include "virtualBuffer.h" #include "storage.h" using namespace std; map _cache_XMLBufferTextByOffsets; map _cache_XMLContextAtBufferOffset; bool _VBufStorage_nodeIdentifier_struct::operator<(const _VBufStorage_nodeIdentifier_struct &other) const { int docHandleCmp=this->docHandle-other.docHandle; if(docHandleCmp==0) { return (this->ID-other.ID)<0; } return docHandleCmp<0; } void _sendXMLOpenTagForNodeToStream(wostringstream* XMLStream,VBufStorage_tagNode_t* node) { int childCount=0; if(node!=NULL) { } for(VBufStorage_node_t* tempNode=node->firstChild;tempNode!=NULL;tempNode=tempNode->next) { if(tempNode->dataType==VBUFINTERNAL_NODETYPE_TAG) { childCount+=1; } } int indexInParent=-1; for(VBufStorage_node_t* tempNode=node;tempNode!=NULL;tempNode=tempNode->previous) { if(tempNode->dataType==VBUFINTERNAL_NODETYPE_TAG) { indexInParent+=1; } } int parentChildCount=indexInParent+1; for(VBufStorage_node_t* tempNode=node;tempNode!=NULL;tempNode=tempNode->next) { if(tempNode->dataType==VBUFINTERNAL_NODETYPE_TAG) { parentChildCount+=1; } } (*XMLStream)<identifier.docHandle<identifier.ID<numAttribs;i++) { (*XMLStream)<attribs[i].name<attribs[i].value<"; } #define _XMLCloseTagForNode L"" #define _debug_nodeInfo(msg, node) {\ if(node==NULL) {\ debug_info(L"%s, node: NULL",msg);\ } else if(node->dataType==VBUFINTERNAL_NODETYPE_BUFFER) {\ debug_info(L"%s, buffer: address %p, offsets %d and %d, buffer text at address %p, ID map at address %p, ID map size %d",msg,node,node->startOffset,node->endOffset,((VBufStorage_bufferNode_t*)node)->bufferText,((VBufStorage_bufferNode_t*)node)->nodesByIdentifier,((VBufStorage_bufferNode_t*)node)->nodesByIdentifier->size());\ } else if(node->dataType==VBUFINTERNAL_NODETYPE_TAG) {\ debug_info(L"%s, tag node: address %p, offsets %d and %d, docHandle %d, ID %d, numAttributes %d, isBlock %d",msg,node,node->startOffset,node->endOffset,node->identifier.docHandle,node->identifier.ID,((VBufStorage_tagNode_t*)node)->numAttribs,((VBufStorage_tagNode_t*)node)->isBlock);\ } else if(node->dataType==VBUFINTERNAL_NODETYPE_TEXT) {\ debug_info(L"%s, text node: address %p, offsets %d and %d, docHandle %d, ID %d",msg,node,node->startOffset,node->endOffset,node->identifier.docHandle,node->identifier.ID);\ }\ } VBufStorage_textNode_t* _createTextNode(int docHandle, int ID) { VBufStorage_textNode_t* node; debug_funcEntered(); debug_info(L"docHandle %d, ID %d",docHandle,ID); node=(VBufStorage_textNode_t*)malloc(sizeof(VBufStorage_textNode_t)); if(node==NULL) { debug_warn(L"Error allocating node memory"); debug_funcReturn(); return (VBufStorage_textNode_t*)-1; } debug_info(L"Allocated node memory at %p",node); node->dataType=VBUFINTERNAL_NODETYPE_TEXT; node->identifier.docHandle=docHandle; node->identifier.ID=ID; node->buffer=NULL; node->parent=node->previous=node->next=node->firstChild=node->lastChild=NULL; node->startOffset=node->endOffset=0; debug_funcReturn(); return node; } int _freeTextNode(VBufStorage_textNode_t* node) { debug_funcEntered(); _debug_nodeInfo(L"freeing node",node); free(node); debug_funcReturn(); return 0; } VBufStorage_tagNode_t* _createTagNode(int docHandle, int ID, VBuf_attribute_t* attribs, int numAttribs, int isBlock) { VBufStorage_tagNode_t* node; debug_funcEntered(); debug_info(L"docHandle %d, ID %d, numAttribs %d",docHandle,ID,numAttribs); node=(VBufStorage_tagNode_t*)malloc(sizeof(VBufStorage_tagNode_t)); if(node==NULL) { debug_warn(L"Error allocating node memory"); debug_funcReturn(); return (VBufStorage_tagNode_t*)-1; } debug_info(L"Allocated node memory at %p",node); node->dataType=VBUFINTERNAL_NODETYPE_TAG; node->identifier.docHandle=docHandle; node->identifier.ID=ID; if(numAttribs>0) { node->attribs=(VBuf_attribute_t*)malloc(sizeof(VBuf_attribute_t)*numAttribs); for(int i=0;iattribs[i].name=_wcsdup(attribs[i].name); node->attribs[i].value=_wcsdup(attribs[i].value); } } node->numAttribs=numAttribs; node->isBlock=isBlock; node->buffer=NULL; node->parent=node->previous=node->next=node->firstChild=node->lastChild=NULL; node->startOffset=node->endOffset=0; debug_funcReturn(); return node; } int _freeTagNode(VBufStorage_tagNode_t* node) { debug_funcEntered(); _debug_nodeInfo(L"freeing node",node); for(int i=0;inumAttribs;i++) { free(node->attribs[i].name); free(node->attribs[i].value); } free(node->attribs); free(node); debug_funcReturn(); return 0; } int _freeBuffer(VBufStorage_bufferNode_t* buf) { debug_funcEntered(); _debug_nodeInfo(L"freeing node",buf); debug_info(L"Deleting ID-to-node map at address %p, contained %d items",buf->nodesByIdentifier,buf->nodesByIdentifier->size()); delete buf->nodesByIdentifier; debug_info(L"Deleting buffer text at address %p",buf->bufferText); delete buf->bufferText; debug_info(L"Freeing buffer memory"); free(buf); debug_funcReturn(); return 0; } //Merges this text node with the next node if it is also a text node, creating one larger text node. int _mergeTextNodeWithNext(VBufStorage_textNode_t* node) { VBufStorage_node_t* nextNode; debug_funcEntered(); if((node==NULL)||(node->dataType!=VBUFINTERNAL_NODETYPE_TEXT)) { debug_warn(L"invalid node"); debug_funcReturn(); return VBUF_ERROR_INVALIDDATA; } nextNode=node->next; _debug_nodeInfo(L"first",node); _debug_nodeInfo(L"second",node); if((nextNode==NULL)||(nextNode->dataType!=VBUFINTERNAL_NODETYPE_TEXT)) { debug_warn(L"Next node is not a text node"); debug_funcReturn(); return VBUF_ERROR_INVALIDDATA; } node->identifier=(node->identifier.ID==0)?nextNode->identifier:node->identifier; node->next=nextNode->next; if(node->next!=NULL) { node->next->previous=node; } node->endOffset=nextNode->endOffset; _freeTextNode((VBufStorage_textNode_t*)nextNode); _debug_nodeInfo(L"merged",node); debug_funcReturn(); return 0; } //Incriments the start and end offsets of the given node and its descendants by given offset int _traverseAndCorrectNodeOffsets(VBufStorage_node_t* node, int offset) { int res; VBufStorage_node_t* child; debug_funcEntered(); debug_info(L"Tweek by offset %d",offset); if(node==NULL) { debug_warn(L"invalid node"); debug_funcReturn(); return VBUF_ERROR_INVALIDDATA; } _debug_nodeInfo(L"starting",node); node->startOffset+=offset; node->endOffset+=offset; debug_info(L"changed to %d, %d",node->startOffset,node->endOffset); for(child=node->firstChild;child!=NULL;child=child->next) { if((res=_traverseAndCorrectNodeOffsets(child,offset))<0) { debug_warn(L"error in traversal"); debug_funcReturn(); return res; } } debug_funcReturn(); return 0; } #define _RESIZEAFFECTEDNODES_ADD 0 #define _RESIZEAFFECTEDNODES_REMOVE 1 //Caches ID-to-node mappings for given node and descendants, in to givennodesByIdentifier map int _cacheIdentifiersForNodeAndDescendants(VBufStorage_node_t* node, std::map<_VBufStorage_nodeIdentifier_struct,VBufStorage_node_t*>* identifierMap) { debug_funcEntered(); if(node->identifier.ID!=0) { (*identifierMap)[node->identifier]=node; } for(VBufStorage_node_t* tempNode=node->firstChild;tempNode!=NULL;tempNode=tempNode->next) { _cacheIdentifiersForNodeAndDescendants(tempNode,identifierMap); } debug_funcReturn(); return 0; } //For given node and its descendants, increase start and end offsets by given amount int _fixOffsetsForNodeAndDescendants(VBufStorage_node_t* node, int offset) { debug_funcEntered(); node->startOffset+=offset; node->endOffset+=offset; for(VBufStorage_node_t* tempNode=node->firstChild;tempNode!=NULL;tempNode=tempNode->next) { _fixOffsetsForNodeAndDescendants(tempNode,offset); } debug_funcReturn(); return 0; } //Using the length of this node, widens/shrinks the offsets of all ancestors, //and incriments/decriments the start/end offsets of any nodes and descendants, after each ancestor on the same level. int _resizeAffectedNodes(VBufStorage_node_t* node, int mode) { VBufStorage_node_t* ancestor=NULL; VBufStorage_node_t* next; int nodeLength; int selOffset; int res; debug_funcEntered(); _debug_nodeInfo(L"using node",node); nodeLength=node->endOffset-node->startOffset; debug_info(L"Node is of length %d",nodeLength); if(mode==_RESIZEAFFECTEDNODES_REMOVE) { nodeLength=0-nodeLength; debug_info(L"Removal mode"); } else { debug_info(L"Adding mode"); } if(nodeLength!=0) { selOffset=node->buffer->selectionStart; if((mode==_RESIZEAFFECTEDNODES_REMOVE)&&(selOffset>node->startOffset)&&(selOffsetendOffset)) { debug_info(L"Selection start was with in this node, at %d. moving selection to %d",selOffset,node->startOffset); node->buffer->selectionStart=node->startOffset; } else if(selOffset>=node->endOffset) { node->buffer->selectionStart+=nodeLength; debug_info(L"Selection start was after this node, at %d. moving it by %d to %d",selOffset,nodeLength,node->buffer->selectionStart); } selOffset=node->buffer->selectionEnd; if((mode==_RESIZEAFFECTEDNODES_REMOVE)&&(selOffset>node->startOffset)&&(selOffsetendOffset)) { debug_info(L"Selection end was with in this node, at %d. moving selection to %d",selOffset,node->startOffset); node->buffer->selectionEnd=node->startOffset; } else if(selOffset>=node->endOffset) { node->buffer->selectionEnd+=nodeLength; debug_info(L"Selection end was after this node, at %d. moving it by %d to %d",selOffset,nodeLength,node->buffer->selectionEnd); } } for(ancestor=node;ancestor!=NULL;ancestor=ancestor->parent) { _debug_nodeInfo(L"ancestor node",ancestor); if(ancestor!=node) { debug_info(L"Changing ancestor endOffset by %d, to %d",nodeLength,ancestor->endOffset+nodeLength); ancestor->endOffset+=nodeLength; } for(next=ancestor->next;next!=NULL;next=next->next) { _debug_nodeInfo(L"next node",next); if((res=_traverseAndCorrectNodeOffsets(next,nodeLength))<0) { debug_warn(L"error in traversal"); debug_funcReturn(); return res; } } } debug_funcReturn(); return 0; } //Links node in to a tree of nodes with given previous and parent. //Start and end offsets are calculated from previous and parent, and any given text //Any given text is also inserted in to the text buffer at node's calculated startOffset int _insertNode(VBufStorage_node_t* parent, VBufStorage_node_t* previous, VBufStorage_node_t* node, wchar_t* text) { int nodeLength; int newStartOffset; int res; debug_funcEntered(); debug_info(L"Inserting node with address %p",node); _debug_nodeInfo(L"parent",parent); _debug_nodeInfo(L"previous",previous); nodeLength=(text!=NULL)?wcslen(text):0; debug_info(L"Node length %d, text %s",nodeLength,text); if(previous!=NULL) { debug_info(L"Using previous"); node->buffer=previous->buffer; newStartOffset=previous->endOffset; node->previous=previous; node->next=previous->next; previous->next=node; } else { debug_info(L"using parent"); node->buffer=parent->buffer; newStartOffset=parent->startOffset; node->next=parent->firstChild; } if(node->next==NULL) { parent->lastChild=node; } if(node->previous==NULL) { parent->firstChild=node; } node->parent=parent; node->endOffset=node->startOffset+nodeLength; _fixOffsetsForNodeAndDescendants(node,newStartOffset-(node->startOffset)); debug_info(L"Offsets set to %d, %d",node->startOffset,node->endOffset); if(nodeLength>0) { debug_info(L"Adding text \"%s\"",text); node->buffer->bufferText->insert(node->startOffset,text); if((res=_resizeAffectedNodes(node,_RESIZEAFFECTEDNODES_ADD))<0) { debug_warn(L"Error resizing affected nodes"); debug_funcReturn(); return res; } } _cacheIdentifiersForNodeAndDescendants(node,node->buffer->nodesByIdentifier); _debug_nodeInfo(L"inserted",node); debug_funcReturn(); return 0; } //Returns the child of the given node, which surrounds the given offset. //If the node has no children but it does surround the given offset, return 0 //Meaning that this is the deepest node for this offset //This function only deals with tag nodes, a text node is never returned VBufStorage_node_t* _fallTowardsNodeAtOffset(VBufStorage_node_t* node, int offset) { VBufStorage_node_t* tempNode=NULL; debug_funcEntered(); if(node==NULL) { debug_warn(L"invalid node"); debug_funcReturn(); return (VBufStorage_node_t*)VBUF_ERROR_INVALIDDATA; } debug_info(L"Searching for offset %d",offset); _debug_nodeInfo(L"using node",node); if((node->firstChild==NULL)&&(offset>=node->startOffset)&&(offsetendOffset)) { debug_info(L"already reached offset"); debug_funcReturn(); return 0; } for(tempNode=node->firstChild;tempNode!=NULL;tempNode=tempNode->next) { if((offset>=tempNode->startOffset)&&(offsetendOffset)) { _debug_nodeInfo(L"closest childnode",tempNode); debug_funcReturn(); return tempNode; } } debug_warn(L"no child node range for offset %d",offset); debug_funcReturn(); return (VBufStorage_node_t*)VBUF_ERROR_INVALIDOFFSET; } //Returns the deepest tag node that surrounds the given offset VBufStorage_node_t* _getNodeAtOffset(VBufStorage_bufferNode_t* buf, int offset) { VBufStorage_node_t* oldNode=NULL; VBufStorage_node_t* tempNode=NULL; debug_funcEntered(); if(buf==NULL) { debug_warn(L"invalid buf"); debug_funcReturn(); return (VBufStorage_node_t*)VBUF_ERROR_INVALIDDATA; } tempNode=(VBufStorage_node_t*)buf; do { oldNode=tempNode; tempNode=_fallTowardsNodeAtOffset(tempNode,offset); } while(tempNode>0); if((int)tempNode<0) { debug_warn(L"error in falling towards offset"); debug_funcReturn(); return tempNode; } _debug_nodeInfo(L"node at offset",oldNode); debug_funcReturn(); return oldNode; } void _generateXMLFromSubtreeWithOffsetLimits(VBufStorage_node_t* node, int startOffset, int endOffset, int isInitial, wostringstream* XMLStream) { int textLength, startIndex, endIndex; VBufStorage_node_t* curNode; VBufStorage_node_t* nextNode; VBufStorage_node_t* childNode; debug_funcEntered(); curNode=node; do { if((curNode->endOffset-curNode->startOffset)>0) { if((curNode->dataType==VBUFINTERNAL_NODETYPE_TAG)&&((curNode!=node)||!isInitial)) { debug_info(L"adding xml open tag for node %d",((VBufStorage_tagNode_t*)curNode)->identifier.ID); _sendXMLOpenTagForNodeToStream(XMLStream,((VBufStorage_tagNode_t*)curNode)); } if(curNode->dataType==VBUFINTERNAL_NODETYPE_TEXT) { startIndex=max(curNode->startOffset,startOffset); endIndex=min(curNode->endOffset,endOffset); debug_info(L"Adding text starting at %d, to %d",startIndex,endIndex); wchar_t c; for(int i=startIndex;ibuffer->bufferText))[i]; switch(c) { case L'"': *(XMLStream)<': *(XMLStream)<firstChild!=NULL) { debug_info(L"recursing to first child"); _generateXMLFromSubtreeWithOffsetLimits(curNode->firstChild,startOffset,endOffset,0,XMLStream); } if(curNode->dataType==VBUFINTERNAL_NODETYPE_TAG) { debug_info(L"Adding close tag for node %d",((VBufStorage_tagNode_t*)curNode)->identifier.ID); *(XMLStream)<<_XMLCloseTagForNode; } } nextNode=curNode->next; if((nextNode==NULL)||(nextNode->startOffset>=endOffset)) { debug_info(L"no next, or next is too far away"); break; } curNode=nextNode; } while(curNode); debug_funcReturn(); } int _doesTagNodeMatchProperties(VBufStorage_tagNode_t* node, VBuf_multyValueAttribute_t* attribs, int numAttribs) { int matched, subMatched; debug_funcEntered(); _debug_nodeInfo(L"checking node",node); for(int i=0;inumAttribs;j++) { debug_info(L"j=%d",j); if(wcscmp(attribs[i].name,node->attribs[j].name)==0) { subMatched=0; for(int k=0;kattribs[j].value)==0)) { subMatched=1; break; } } if(!subMatched) { debug_info(L"attrib %s found, but value different",attribs[i].name); debug_funcReturn(); return 0; } matched=1; } } if(!matched) { for(int j=0;jfirstChild!=NULL) { debug_info(L"moved to first child"); node=node->firstChild; } else if(node->next!=NULL) { debug_info(L"moved to next"); node=node->next; } else if(node->parent!=NULL) { while(node->parent&&!node->next) { node=node->parent; } if(node->next) { node=node->next; } else { debug_warn(L"can't move"); debug_funcReturn(); return (VBufStorage_node_t*)VBUF_ERROR_NOTFOUND; } } else { debug_warn(L"can't move"); debug_funcReturn(); return (VBufStorage_node_t*)VBUF_ERROR_NOTFOUND; } } else if(direction==VBUF_FINDDIRECTION_PREVIOUS) { debug_info(L"direction: previous"); if(node->lastChild!=NULL) { debug_info(L"moved to last child"); node=node->lastChild; } else if(node->previous!=NULL) { debug_info(L"moved to previous"); node=node->previous; } else if(node->parent!=NULL) { while(node->parent&&!node->previous) { node=node->parent; } if(node->previous) { node=node->previous; } else { debug_warn(L"can't move"); debug_funcReturn(); return (VBufStorage_node_t*)VBUF_ERROR_NOTFOUND; } } else { debug_warn(L"can't move"); debug_funcReturn(); return (VBufStorage_node_t*)VBUF_ERROR_NOTFOUND; } } else { debug_warn(L"unknown direction: %d",direction); debug_funcReturn(); return (VBufStorage_node_t*)VBUF_ERROR_BADPARAMETER; } tagNode=(VBufStorage_tagNode_t*)node; if((tagNode->dataType==VBUFINTERNAL_NODETYPE_TAG)&&_doesTagNodeMatchProperties(tagNode,attribs,numAttribs)) { debug_info(L"Found match"); debug_funcReturn(); return node; } debug_info(L"no match, traversing"); tempNode=_findNodeByProperties(node, direction, attribs, numAttribs); if((int)tempNode<=0) { debug_warn(L"error in finding node"); } debug_info(L"returning %p",tempNode); debug_funcReturn(); return tempNode; } int _removeNode(VBufStorage_node_t* node, int removeText) { VBufStorage_node_t* tempNode; int textLength; int bufTextLength; int res; debug_funcEntered(); _debug_nodeInfo(L"Removing node",node); for(tempNode=node->firstChild;tempNode!=NULL;tempNode=tempNode->next) { if((res=_removeNode(tempNode,0))<0) { debug_warn(L"Error removing a node"); debug_funcReturn(); return res; } } if(node->next!=NULL) { debug_info(L"setting next's previous to previous, next %p",node->next); node->next->previous=node->previous; } if(node->previous!=NULL) { debug_info(L"setting previous's next to next"); node->previous->next=node->next; } if((node->parent!=NULL)&&(node->parent->firstChild==node)) { debug_info(L"setting parent's first child to next"); node->parent->firstChild=node->next; } if((node->parent!=NULL)&&(node->parent->lastChild==node)) { debug_info(L"Setting parent's last child to previous"); node->parent->lastChild=node->previous; } if((node->buffer!=node)&&removeText) { textLength=node->endOffset-node->startOffset; if(textLength>0) { debug_info(L"removing text of length %d, starting at %d",textLength,node->startOffset); node->buffer->bufferText->erase(node->startOffset,textLength); if((res=_resizeAffectedNodes(node,_RESIZEAFFECTEDNODES_REMOVE))<0) { debug_warn(L"Error resizing affected nodes, code %d",res); debug_funcReturn(); return res; } } } if((node->previous!=NULL)&&(node->previous->dataType==VBUFINTERNAL_NODETYPE_TEXT)&&(node->previous->next!=NULL)&&(node->previous->next->dataType==VBUFINTERNAL_NODETYPE_TEXT)&&(node->previous->identifier.ID==0)&&(node->previous->next->identifier.ID==0)&&(node->previous->identifier.docHandle==node->previous->next->identifier.docHandle)) { _mergeTextNodeWithNext((VBufStorage_textNode_t*)(node->previous)); } if(node->dataType==VBUFINTERNAL_NODETYPE_BUFFER) { _freeBuffer((VBufStorage_bufferNode_t*)node); } else if(node->dataType==VBUFINTERNAL_NODETYPE_TAG) { if(node->identifier.ID!=0) { node->buffer->nodesByIdentifier->erase(node->identifier); } _freeTagNode((VBufStorage_tagNode_t*)node); } else if(node->dataType==VBUFINTERNAL_NODETYPE_TEXT) { if(node->identifier.ID!=0) { node->buffer->nodesByIdentifier->erase(node->identifier); } _freeTextNode((VBufStorage_textNode_t*)node); } debug_funcReturn(); return 0; } VBufStorage_bufferNode_t* VBufStorage_createBuffer() { debug_funcEntered(); VBufStorage_bufferNode_t* buf=(VBufStorage_bufferNode_t*)malloc(sizeof(VBufStorage_bufferNode_t)); if(buf==NULL) { debug_warn(L"could not allocate memory"); debug_funcReturn(); return (VBufStorage_bufferNode_t*)VBUF_ERROR_MEMALLOC; } debug_info(L"buffer address %p",buf); buf->dataType=VBUFINTERNAL_NODETYPE_BUFFER; buf->buffer=buf; buf->firstChild=buf->lastChild=buf->previous=buf->next=buf->parent=NULL; buf->nodesByIdentifier=new map<_VBufStorage_nodeIdentifier_struct,VBufStorage_node_t*>; buf->bufferText=new wstring(); buf->startOffset=buf->endOffset=buf->selectionStart=buf->selectionEnd=0; debug_funcReturn(); return buf; } int VBufStorage_destroyBuffer(VBufStorage_bufferNode_t* buf) { int res; debug_funcEntered(); if(buf==NULL) { debug_warn(L"invalid buffer"); debug_funcReturn(); return VBUF_ERROR_INVALIDDATA; } if((res=VBufStorage_clearBuffer(buf))<0) { debug_warn(L"error with clear"); debug_funcReturn(); return res; } delete buf->nodesByIdentifier; delete buf->bufferText; debug_funcReturn(); return VBUF_ERROR_OK; } int VBufStorage_mergeBuffer(VBufStorage_node_t* parent, VBufStorage_node_t* previous, VBufStorage_bufferNode_t* node) { int res; VBufStorage_node_t* tempNode; debug_funcEntered(); if((node==NULL)||(node->dataType!=VBUFINTERNAL_NODETYPE_BUFFER)) { debug_warn(L"invalid node, or node is not a buffer"); debug_funcReturn(); return VBUF_ERROR_INVALIDDATA; } if(node->firstChild==NULL) { debug_warn(L"Buffer is empty"); debug_funcReturn(); return VBUF_ERROR_INVALIDDATA; } if((res=_insertNode(parent,previous,(VBufStorage_node_t*)node,(wchar_t*)(node->bufferText->c_str())))<0) { debug_warn(L"Error inserting node, code %d",res); debug_funcReturn(); return res; } node->firstChild->previous=node->previous; if(node->firstChild->previous!=NULL) { node->firstChild->previous->next=node->firstChild; } node->lastChild->next=node->next; if(node->lastChild->next!=NULL) { node->lastChild->next->previous=node->lastChild; } for(tempNode=node->firstChild;tempNode!=NULL;tempNode=tempNode->next) { tempNode->parent=node->parent; } if(node->parent->firstChild==node) { node->parent->firstChild=node->firstChild; } if(node->parent->lastChild==node) { node->parent->lastChild=node->lastChild; } node->firstChild=node->lastChild=node->previous=node->next=node->parent=NULL; if((res=_freeBuffer(node))<0) { debug_warn(L"Error destroying buffer, code %d",res); debug_funcReturn(); return res; } debug_funcReturn(); return 0; } int VBufStorage_splitTextNodeAtOffset(VBufStorage_textNode_t* node, int offset) { VBufStorage_textNode_t* nextNode; debug_funcEntered() if((node==NULL)||(node->dataType!=VBUFINTERNAL_NODETYPE_TEXT)) { debug_warn(L"invalid node"); debug_funcReturn(); return VBUF_ERROR_INVALIDDATA; } if((offset<0)||(offset>=(node->endOffset-node->startOffset))) { debug_warn(L"Invalid offset, %d",offset); debug_funcReturn(); return -1; } if((nextNode=_createTextNode(0,0))<=0) { debug_warn(L"Error creating text node"); debug_funcReturn(); return (int)nextNode; } nextNode->buffer=node->buffer; nextNode->identifier.docHandle=node->identifier.docHandle; nextNode->parent=node->parent; nextNode->previous=node; nextNode->next=node->next; node->next=nextNode; nextNode->endOffset=node->endOffset; node->endOffset=nextNode->startOffset=offset; debug_funcReturn(); return 0; } int VBufStorage_clearBuffer(VBufStorage_bufferNode_t* buf) { VBufStorage_node_t* tempNode; int res; debug_funcEntered(); if(buf==NULL) { debug_warn(L"invalid buffer"); debug_funcReturn(); return VBUF_ERROR_INVALIDDATA; } if(buf->firstChild!=NULL) { for(tempNode=buf->firstChild;tempNode!=NULL;tempNode=tempNode->next) { if((res=_removeNode(tempNode,0))<0) { debug_warn(L"error in remove"); debug_funcReturn(); return res; } } } buf->endOffset=buf->startOffset; buf->bufferText->clear(); debug_funcReturn(); return VBUF_ERROR_OK; } VBufStorage_node_t* VBufStorage_getBufferNodeWithIdentifier(VBufStorage_bufferNode_t* buf, int docHandle, int ID) { VBufStorage_node_t* node; VBufStorage_nodeIdentifier_t identifier; debug_funcEntered(); if(buf==NULL) { debug_warn(L"invalid buffer"); debug_funcReturn(); return (VBufStorage_node_t*)VBUF_ERROR_INVALIDDATA; } debug_info(L"Requesting node with docHandle %d and ID %d, from buffer at address %p",docHandle,ID,buf); identifier.docHandle=docHandle; identifier.ID=ID; if(buf->nodesByIdentifier->count(identifier)<=0) { debug_warn(L"ID does not exist"); debug_funcReturn(); return (VBufStorage_node_t*)VBUF_ERROR_INVALIDID; } node=(*buf->nodesByIdentifier)[identifier]; _debug_nodeInfo(L"found node",node); debug_funcReturn(); return node; } VBufStorage_tagNode_t* VBufStorage_addTagNodeToBuffer(VBufStorage_node_t* parent, VBufStorage_node_t* previous, int docHandle, int ID, VBuf_attribute_t* attribs, int numAttribs, int isBlock) { VBufStorage_tagNode_t* node; int res; debug_funcEntered(); if((node=_createTagNode(docHandle,ID,attribs,numAttribs,isBlock))<=0) { debug_warn(L"Error creating node"); debug_funcReturn(); return node; } if((res=_insertNode(parent,previous,node,NULL))<0) { debug_warn(L"Error inserting node"); debug_funcReturn(); return (VBufStorage_tagNode_t*)res; } debug_funcReturn(); return node; } VBufStorage_textNode_t* VBufStorage_addTextNodeToBuffer(VBufStorage_node_t* parent, VBufStorage_node_t* previous, int docHandle, int ID, wchar_t* text) { VBufStorage_textNode_t* node; int res; debug_funcEntered(); if((node=_createTextNode(docHandle,ID))<=0) { debug_warn(L"Error creating node"); debug_funcReturn(); return node; } if((res=_insertNode(parent,previous,node,text))<0) { debug_warn(L"Error inserting node"); debug_funcReturn(); return (VBufStorage_textNode_t*)res; } debug_funcReturn(); return node; } int VBufStorage_removeNodeFromBuffer(VBufStorage_node_t* node) { int res; debug_funcEntered(); res=_removeNode(node,1); debug_funcReturn(); return res; } int VBufStorage_removeDescendantsFromBufferNode(VBufStorage_node_t* node) { int textLength; VBufStorage_node_t* tempNode; int res; debug_funcEntered(); for(tempNode=node->firstChild;tempNode!=NULL;tempNode=tempNode->next) { if((res=_removeNode(tempNode,0))<0) { debug_warn(L"error in removing child node"); debug_funcReturn(); return res; } } textLength=node->endOffset-node->startOffset; if(textLength>0) { _resizeAffectedNodes(node,_RESIZEAFFECTEDNODES_REMOVE); node->buffer->bufferText->erase(node->startOffset,textLength); node->endOffset=node->startOffset; } debug_funcReturn(); return 0; } int VBufStorage_getFieldIdentifierFromBufferOffset(VBufStorage_bufferNode_t* buf, int offset, int* foundDocHandle, int* foundID) { VBufStorage_node_t* node; VBufStorage_node_t* tempNode; debug_funcEntered(); if(buf==NULL) { debug_warn(L"invalid buffer"); debug_funcReturn(); return VBUF_ERROR_INVALIDDATA; } if(offset>=buf->endOffset) { debug_warn(L"offset %d is too large for buffer length of %d",offset,buf->bufferText->length()); debug_funcReturn(); return VBUF_ERROR_INVALIDOFFSET; } if(buf->firstChild==NULL) { debug_warn(L"buffer has no nodes"); debug_funcReturn(); return VBUF_ERROR_EMPTYBUFFER; } for(tempNode=_fallTowardsNodeAtOffset((VBufStorage_node_t*)buf,offset);tempNode>0;tempNode=_fallTowardsNodeAtOffset(tempNode,offset)) { node=tempNode; } if((int)tempNode<0) { debug_warn(L"error in finding node"); debug_funcReturn(); return (int)tempNode; } for(tempNode=node,node=NULL;(tempNode!=NULL)&&!(tempNode->dataType==VBUFINTERNAL_NODETYPE_TAG);tempNode=tempNode->parent) { node=tempNode; } if((node==NULL)||(node->parent==NULL)) { debug_warn(L"no ID at offset %d, returning -1 (buffer)",offset); debug_funcReturn(); return -1; } *foundDocHandle=((VBufStorage_tagNode_t*)node->parent)->identifier.docHandle; *foundID=((VBufStorage_tagNode_t*)node->parent)->identifier.ID; debug_funcReturn(); return 0; } int VBufStorage_getBufferOffsetsFromFieldIdentifier(VBufStorage_bufferNode_t* buf, int docHandle, int ID, int* startOffset, int* endOffset) { VBufStorage_node_t* node; VBufStorage_nodeIdentifier_t identifier; debug_funcEntered(); if(buf==NULL) { debug_warn(L"invalid buffer"); debug_funcReturn(); return VBUF_ERROR_INVALIDDATA; } identifier.docHandle=docHandle; identifier.ID=ID; if(buf->nodesByIdentifier->count(identifier)==0) { debug_warn(L"invalid ID: %d",ID); debug_funcReturn(); return VBUF_ERROR_INVALIDID; } node=(*buf->nodesByIdentifier)[identifier]; *startOffset=node->startOffset; *endOffset=node->endOffset; debug_funcReturn(); return VBUF_ERROR_OK; } int VBufStorage_findBufferFieldIdentifierByProperties(VBufStorage_bufferNode_t* buf, int direction, int startOffset, VBuf_multyValueAttribute_t* attribs, int numAttribs, int* foundDocHandle, int* foundID) { VBufStorage_node_t* tempNode; VBufStorage_node_t* node; debug_funcEntered(); if(buf==NULL) { debug_warn(L"invalid buffer"); debug_funcReturn(); return VBUF_ERROR_INVALIDDATA; } if(startOffset>=0) { node=_getNodeAtOffset(buf,startOffset); } else if(startOffset==-1) { node=buf; } else { debug_warn(L"Bad startOffset %d",startOffset); debug_funcReturn(); return VBUF_ERROR_BADPARAMETER; } if(node<=0) { debug_warn(L"Error fetching start node, code %d",node); debug_funcReturn(); return (int)node; } tempNode=_findNodeByProperties(node,direction,attribs,numAttribs); if((int)tempNode<0) { debug_warn(L"error in finding node"); debug_funcReturn(); return (int)tempNode; } else if(tempNode==NULL) { debug_warn(L"Could not find match"); debug_funcReturn(); *foundDocHandle=0; *foundID=0; } else { *foundDocHandle=tempNode->identifier.docHandle; *foundID=tempNode->identifier.ID; } debug_funcReturn(); return 0; } int VBufStorage_getBufferTextLength(VBufStorage_bufferNode_t* buf) { debug_funcEntered(); if(buf==NULL) { debug_warn(L"invalid buffer"); debug_funcReturn(); return VBUF_ERROR_INVALIDDATA; } debug_funcReturn(); return buf->bufferText->length(); } int VBufStorage_getBufferFieldCount(VBufStorage_bufferNode_t* buf) { debug_funcEntered(); if(buf==NULL) { debug_warn(L"invalid buffer"); debug_funcReturn(); return VBUF_ERROR_INVALIDDATA; } debug_funcReturn(); return buf->nodesByIdentifier->size(); } int VBufStorage_findBufferText(VBufStorage_bufferNode_t* buf, wchar_t* text, int startOffset, int direction, int flags) { int res; debug_funcEntered(); if(buf==NULL) { debug_warn(L"invalid buffer"); debug_funcReturn(); return VBUF_ERROR_INVALIDDATA; } if(text==NULL) { debug_warn(L"NULL text string"); debug_funcReturn(); return VBUF_ERROR_BADPARAMETER; } debug_info(L"Finding text \"%s\", starting at offset %d",text,startOffset); if(direction==VBUF_FINDDIRECTION_NEXT) { res=buf->bufferText->find(text,startOffset-buf->startOffset); } else if(direction==VBUF_FINDDIRECTION_PREVIOUS) { res=buf->bufferText->rfind(text,startOffset-buf->startOffset); } else { debug_warn(L"invalid direction %d",direction); debug_funcReturn(); return VBUF_ERROR_BADPARAMETER; } if((res<0)||(res>=buf->bufferText->length())) { debug_warn(L"text not found"); res=VBUF_ERROR_NOTFOUND; } debug_funcReturn(); debug_info(L"full text: \"%s\"",buf->bufferText->c_str()); return res+buf->startOffset; } int VBufStorage_getBufferTextByOffsets(VBufStorage_bufferNode_t* buf, int startOffset, int endOffset, wchar_t* text) { int textLength; debug_funcEntered(); if(buf==NULL) { debug_warn(L"invalid buffer"); debug_funcReturn(); return VBUF_ERROR_INVALIDDATA; } if(text==NULL) { debug_warn(L"invalid memory for text"); debug_funcReturn(); return VBUF_ERROR_BADPARAMETER; } if(endOffset>buf->endOffset) { debug_warn(L"Offsets out of range of buffer text length"); debug_funcReturn(); return VBUF_ERROR_INVALIDOFFSET; } textLength=endOffset-startOffset; textLength=buf->bufferText->copy(text,textLength,startOffset-buf->startOffset); text[textLength]=L'\0'; debug_funcReturn(); return textLength; } int VBufStorage_getXMLContextAtBufferOffset(VBufStorage_bufferNode_t* buf, int offset, wchar_t* text) { int textLength; VBufStorage_node_t* curNode=NULL; VBufStorage_node_t* tempNode=NULL; long long key=((long long)buf)*((long long)offset); wostringstream* XMLStream; debug_funcEntered(); if(buf==NULL) { debug_warn(L"invalid buffer"); debug_funcReturn(); return VBUF_ERROR_INVALIDDATA; } if(text!=NULL) { debug_info(L"received valid memory at %p to place cached text",text); if(_cache_XMLContextAtBufferOffset.count(key)==0) { debug_warn(L"no XML cached"); debug_funcReturn(); return VBUF_ERROR_UNKNOWN; } XMLStream=_cache_XMLContextAtBufferOffset[key]; textLength=XMLStream->str().length(); XMLStream->str().copy(text,textLength); _cache_XMLContextAtBufferOffset.erase(key); delete XMLStream; debug_funcReturn(); return wcslen(text); } if(_cache_XMLContextAtBufferOffset.count(key)>0) { debug_warn(L"already cached XML for these offsets"); debug_funcReturn(); return VBUF_ERROR_UNKNOWN; } if((offset<0)||(offset>=buf->endOffset)) { debug_warn(L"invalid offset"); debug_funcReturn(); return VBUF_ERROR_INVALIDOFFSET; } XMLStream=new wostringstream(); curNode=_fallTowardsNodeAtOffset((VBufStorage_node_t*)buf,offset); if(curNode<=0) { debug_warn(L"error falling towards offset"); debug_funcReturn(); return (int)curNode; } do { if(curNode->dataType==VBUFINTERNAL_NODETYPE_TAG) { _sendXMLOpenTagForNodeToStream(XMLStream,((VBufStorage_tagNode_t*)curNode)); curNode=_fallTowardsNodeAtOffset(curNode,offset); } else { curNode=NULL; } } while(curNode>0); _cache_XMLContextAtBufferOffset[key]=XMLStream; debug_funcReturn(); return XMLStream->str().length(); } int VBufStorage_getXMLBufferTextByOffsets(VBufStorage_bufferNode_t* buf, int startOffset, int endOffset, wchar_t* text) { int curStartOffset, curEndOffset, textLength; int isInitial=1; VBufStorage_node_t* curNode=NULL; VBufStorage_node_t* parentNode=NULL; VBufStorage_node_t* parentNextNode=NULL; VBufStorage_node_t* tempNode=NULL; long long key=((long long)buf)*((long long)startOffset)*((long long)endOffset); wostringstream* XMLStream; debug_funcEntered(); if(buf==NULL) { debug_warn(L"invalid buffer"); debug_funcReturn(); return VBUF_ERROR_INVALIDDATA; } if(text!=NULL) { debug_info(L"received valid memory at %p to place cached text",text); if(_cache_XMLBufferTextByOffsets.count(key)==0) { debug_warn(L"no XML cached"); debug_funcReturn(); return VBUF_ERROR_UNKNOWN; } XMLStream=_cache_XMLBufferTextByOffsets[key]; textLength=XMLStream->str().length(); XMLStream->str().copy(text,textLength); _cache_XMLBufferTextByOffsets.erase(key); delete XMLStream; debug_funcReturn(); return wcslen(text); } if(_cache_XMLBufferTextByOffsets.count(key)>0) { debug_warn(L"already cached XML for these offsets"); debug_funcReturn(); return VBUF_ERROR_UNKNOWN; } if((startOffset>=endOffset)||(startOffset<0)||((endOffset-startOffset)>buf->bufferText->length())) { debug_warn(L"invalid offsets"); debug_funcReturn(); return VBUF_ERROR_INVALIDOFFSET; } XMLStream=new wostringstream(); curNode=_getNodeAtOffset(buf,startOffset); if(curNode<=0) { debug_warn(L"error finding node for offset"); debug_funcReturn(); return (int)curNode; } isInitial=1; do { _generateXMLFromSubtreeWithOffsetLimits(curNode,startOffset,endOffset,isInitial,XMLStream); isInitial=0; int closeTagCount=0; for(curNode=curNode->parent;curNode!=NULL&&curNode->next==NULL;curNode=curNode->parent) { if(curNode->dataType==VBUFINTERNAL_NODETYPE_TAG) { closeTagCount+=1; } } if(curNode) { if(curNode->dataType==VBUFINTERNAL_NODETYPE_TAG) { closeTagCount+=1; } curNode=curNode->next; } if((curNode==NULL)||(curNode->startOffset>=endOffset)) { break; } for(int i=0;istr().length(); } int VBufStorage_getBufferLineOffsets(VBufStorage_bufferNode_t* buf, int offset, int maxLineLength, int useScreenLayout, int* startOffset, int* endOffset) { int hardStart, hardEnd; set possibleBreaks; debug_funcEntered(); if(buf==NULL) { debug_warn(L"invalid buffer"); debug_funcReturn(); return VBUF_ERROR_INVALIDDATA; } if(offset>=buf->endOffset) { debug_warn(L"invalid offsets"); debug_funcReturn(); return VBUF_ERROR_INVALIDOFFSET; } debug_info(L"using offset %d",offset); hardStart=0; hardEnd=buf->bufferText->length(); debug_info(L"buffer limits: start %d, end %d",hardStart,hardEnd); VBufStorage_node_t* tempNode; //Search parents tempNode=_getNodeAtOffset(buf,offset); while(tempNode->parent) { tempNode=tempNode->parent; if(tempNode->dataType==VBUFINTERNAL_NODETYPE_TAG) { if(!useScreenLayout||((VBufStorage_tagNode_t*)tempNode)->isBlock) { if(tempNode->startOffset>hardStart) { hardStart=tempNode->startOffset; } if(tempNode->endOffsetendOffset; } } else { possibleBreaks.insert(tempNode->startOffset); possibleBreaks.insert(tempNode->endOffset); } } } debug_info(L"Limits after checking parents: start %d, end %d",hardStart,hardEnd); //Search forward tempNode=_getNodeAtOffset(buf,offset); while((tempNode>0)&&(tempNode->startOffsetdataType==VBUFINTERNAL_NODETYPE_TAG) { if(!useScreenLayout||((VBufStorage_tagNode_t*)tempNode)->isBlock) { if(tempNode->startOffset>offset) { hardEnd=tempNode->startOffset; break; } else if((tempNode->endOffset>offset)&&(tempNode->endOffsetendOffset; break; } } else { possibleBreaks.insert(tempNode->startOffset); possibleBreaks.insert(tempNode->endOffset); } } if(tempNode->firstChild) { tempNode=tempNode->firstChild; } else if(tempNode->next) { tempNode=tempNode->next; } else if(tempNode->parent) { while(tempNode->parent&&!tempNode->next) { tempNode=tempNode->parent; } if(tempNode->next) { tempNode=tempNode->next; } else { tempNode=NULL; } } else { tempNode=NULL; } } tempNode=_getNodeAtOffset(buf,offset); //Search back while((tempNode>0)&&(tempNode->endOffset>hardStart)) { if(tempNode->dataType==VBUFINTERNAL_NODETYPE_TAG) { if(!useScreenLayout||((VBufStorage_tagNode_t*)tempNode)->isBlock) { if(tempNode->endOffset<=offset) { hardStart=tempNode->endOffset; break; } else if((tempNode->startOffset<=offset)&&(tempNode->startOffset>hardStart)) { hardStart=tempNode->startOffset; break; } } else { possibleBreaks.insert(tempNode->startOffset); possibleBreaks.insert(tempNode->endOffset); } } if(tempNode->lastChild) { tempNode=tempNode->lastChild; } else if(tempNode->previous) { tempNode=tempNode->previous; } else if(tempNode->parent) { while(tempNode->parent&&!tempNode->previous) { tempNode=tempNode->parent; } if(tempNode->previous) { tempNode=tempNode->previous; } else { tempNode=NULL; } } else { tempNode=NULL; } } debug_info(L"limits after searching forward and back for tags: start %d, end %d",hardStart,hardEnd); //Search text for line feeds and also possible word breaks char c; int lastWasSpace=0; for(int i=hardStart;ibufferText))[i]; if(c==L'\n') { if(i0) { set realBreaks; realBreaks.insert(hardStart); realBreaks.insert(hardEnd); for(int i=hardStart,lineCharCounter=0;i0) { set::iterator possible=possibleBreaks.upper_bound(i); if((possible!=possibleBreaks.begin())&&(*(--possible)>(i-maxLineLength))) { i=*possible; } } realBreaks.insert(i); lineCharCounter=0; } } set::iterator real=realBreaks.upper_bound(offset); hardEnd=*real; hardStart=*(--real); debug_info(L"limits after fixing for maxLineLength %: start %d, end %d\n",maxLineLength,hardStart,hardEnd); } debug_info(L"Line offsets are %d and %d\n",hardStart,hardEnd); *startOffset=hardStart; *endOffset=hardEnd; debug_funcReturn(); return VBUF_ERROR_OK; } int VBufStorage_getBufferSelectionOffsets(VBufStorage_bufferNode_t* buf, int* startOffset, int* endOffset) { debug_funcEntered(); if(buf==NULL) { debug_warn(L"invalid buffer"); debug_funcReturn(); return VBUF_ERROR_INVALIDDATA; } *startOffset=buf->selectionStart; *endOffset=buf->selectionEnd; debug_funcReturn(); return 0; } int VBufStorage_setBufferSelectionOffsets(VBufStorage_bufferNode_t* buf, int startOffset, int endOffset) { int bufTextLength; debug_funcEntered(); if(buf==NULL) { debug_warn(L"invalid buffer"); debug_funcReturn(); return VBUF_ERROR_INVALIDDATA; } bufTextLength=buf->bufferText->length(); if((startOffset>=bufTextLength)||(endOffset>bufTextLength)) { debug_warn(L"offsets greater than buffer text length"); debug_funcReturn(); return VBUF_ERROR_INVALIDDATA; } buf->selectionStart=startOffset; buf->selectionEnd=endOffset; debug_funcReturn(); return 0; }