LOCAL lcFileText, lcBegDelimiter, lcEndDelimiter, loDrawingXML, lnSecs, lnCount lcFileText = FILETOSTR('drawing1.xml') lcBegDelimiter = "<xdr:twoCellAnchor>" lcEndDelimiter = "</xdr:twoCellAnchor>" *-* Create instance of FastString class loFastString = CREATEOBJECT("FastStringClass") *-* Add the string to be parsed to FastString class loDrawingXML = loFastString.AddStringToHeap(lcFileText) *-* Get a selected segment lnSecs = SECONDS() lcTwoCellAnchor = loFastString.StrExtract(loDrawingXML, lcBegDelimiter, lcEndDelimiter, 2000) ? "Selected Segment Extract: " + TRANSFORM(SECONDS() - lnSecs) _CLIPTEXT = lcTwoCellAnchor *-* Get all segments lnCount = 0 lnSecs = SECONDS() lcAbsoluteAnchor = loFastString.GetFirstSegment(loDrawingXML, lcBegDelimiter, lcEndDelimiter) DO WHILE !EMPTY(lcAbsoluteAnchor) lnCount = lnCount + 1 lcAbsoluteAnchor = loFastString.GetNextSegment(loDrawingXML) ENDDO ? "All Segments Extract: " + TRANSFORM(SECONDS() - lnSecs) ? "Segment Count: " + TRANSFORM(lnCount) *-* Release Fast string text from memory loDrawingXML = loFastString.ReleaseStringFromHeap(loDrawingXML) *-****************************************************************************************************** *-* Fast String class using SYS(2600) *-* *-* Idea for class by Rick Hodgin on Universal Thread (Thread Id 01674989) *-* Class Written by Gregory Green *-* Based on suggestion by Christof Wollenhaupt *-****************************************************************************************************** DEFINE CLASS FastStringClass AS Custom NAME = "FastStringClass" PROCEDURE LoadDLLs DECLARE INTEGER HeapAlloc IN Win32Api AS apiHeapAlloc INTEGER, INTEGER, INTEGER DECLARE INTEGER HeapFree IN Win32APi AS apiHeapFree INTEGER, INTEGER, INTEGER DECLARE LONG GetProcessHeap IN Win32API AS apiGetProcessHeap ENDPROC PROCEDURE Init this.LoadDLLs() ENDPROC PROCEDURE AddStringToHeap LPARAMETERS tcString LOCAL loString loString = CREATEOBJECT("Empty") ADDPROPERTY(loString, "Length", 0) ADDPROPERTY(loString, "BaseAdr", 0) ADDPROPERTY(loString, "LastAdr", 0) ADDPROPERTY(loString, "BegDelimiter", "") ADDPROPERTY(loString, "EndDelimiter", "") loString.Length = LEN(tcString) loString.BaseAdr = apiHeapAlloc(apiGetProcessHeap(), 0, loString.Length) SYS(2600, loString.BaseAdr, loString.Length, tcString) RETURN loString ENDPROC PROCEDURE GetFirstSegment LPARAMETERS toString, tcBegDelimiter, tcEndDelimiter LOCAL lnBeg, lcVal, lnEnd, lnBegLen, lnEndLen toString.BegDelimiter = tcBegDelimiter toString.EndDelimiter = tcEndDelimiter lnBegLen = LEN(toString.BegDelimiter) lnEndLen = LEN(toString.EndDelimiter) lnBeg = 1 DO WHILE lnBeg < toString.Length lcVal = SYS(2600, toString.BaseAdr-1 + lnBeg, lnBegLen) IF lcVal == toString.BegDelimiter FOR lnEnd=lnBeg+lnBegLen TO toString.Length lcVal = SYS(2600, toString.BaseAdr-1 + lnEnd, lnEndLen) IF lcVal == toString.EndDelimiter toString.LastAdr = lnEnd + lnEndLen RETURN SYS(2600, toString.BaseAdr-1 + lnBeg, lnEnd - lnBeg + lnBegLen + 1) ENDIF ENDFOR lnBeg = toString.Length ENDIF lnBeg = lnBeg + 1 ENDDO toString.LastAdr = toString.Length RETURN "" ENDPROC PROCEDURE GetNextSegment LPARAMETERS toString LOCAL lnBeg, lcVal, lnEnd, lnBegLen, lnEndLen lnBegLen = LEN(toString.BegDelimiter) lnEndLen = LEN(toString.EndDelimiter) lnBeg = toString.LastAdr DO WHILE lnBeg < toString.Length lcVal = SYS(2600, toString.BaseAdr-1 + lnBeg, lnBegLen) IF lcVal == toString.BegDelimiter FOR lnEnd=lnBeg+lnBegLen TO toString.Length lcVal = SYS(2600, toString.BaseAdr-1 + lnEnd, lnEndLen) IF lcVal == toString.EndDelimiter toString.LastAdr = lnEnd + lnEndLen RETURN SYS(2600, toString.BaseAdr-1 + lnBeg, lnEnd - lnBeg + lnBegLen + 1) ENDIF ENDFOR lnBeg = toString.Length ENDIF lnBeg = lnBeg + 1 ENDDO toString.LastAdr = toString.Length RETURN "" ENDPROC PROCEDURE ATC LPARAMETERS tcFindText, toString, tnOccurrence LOCAL lnBeg, lcVal, lnLen IF PCOUNT() = 2 tnOccurrence = 1 ENDIF tcFindText = UPPER(tcFindText) lnLen = LEN(tcFindText) lnOccurrence = 0 lnBeg = 1 DO WHILE lnBeg < toString.Length lcVal = UPPER(SYS(2600, toString.BaseAdr-1 + lnBeg, lnLen)) IF lcVal == tcFindText lnOccurrence = lnOccurrence + 1 IF lnOccurrence = tnOccurrence RETURN lnBeg ENDIF ENDIF lnBeg = lnBeg + 1 ENDDO RETURN 0 ENDPROC PROCEDURE AT LPARAMETERS tcFindText, toString, tnOccurrence LOCAL lnBeg, lcVal, lnLen IF PCOUNT() = 2 tnOccurrence = 1 ENDIF lnLen = LEN(tcFindText) lnOccurrence = 0 lnBeg = 1 DO WHILE lnBeg < toString.Length lcVal = SYS(2600, toString.BaseAdr-1 + lnBeg, lnLen) IF lcVal == tcFindText lnOccurrence = lnOccurrence + 1 IF lnOccurrence = tnOccurrence RETURN lnBeg ENDIF ENDIF lnBeg = lnBeg + 1 ENDDO RETURN 0 ENDPROC PROCEDURE StrExtract LPARAMETERS toString, tcBegDelimiter, tcEndDelimiter, tnOccurrence LOCAL lnBeg, lcVal, lnEnd, lnBegLen, lnEndLen lnBegLen = LEN(tcBegDelimiter) lnEndLen = LEN(tcEndDelimiter) lnOccurrence = 0 lnBeg = 1 DO WHILE lnBeg < toString.Length lcVal = SYS(2600, toString.BaseAdr-1 + lnBeg, lnBegLen) IF lcVal == tcBegDelimiter FOR lnEnd=lnBeg+lnBegLen TO toString.Length lcVal = SYS(2600, toString.BaseAdr-1 + lnEnd, lnEndLen) IF lcVal == tcEndDelimiter lnOccurrence = lnOccurrence + 1 IF lnOccurrence = tnOccurrence RETURN SYS(2600, toString.BaseAdr-1 + lnBeg, lnEnd - lnBeg + lnBegLen + 1) ENDIF lnBeg = lnEnd - 1 EXIT ENDIF ENDFOR ENDIF lnBeg = lnBeg + 1 ENDDO RETURN "" ENDPROC PROCEDURE ReleaseStringFromHeap LPARAMETERS toString apiHeapFree(apiGetProcessHeap(), 0, toString.BaseAdr) RETURN .NULL. ENDPROC ENDDEFINE