; Binary AHK Array RC2 ; (w) by DerRaphael ; ; Released under the Terms of European Public License (EUPL 1.0) ; see http://ec.europa.eu/idabc/en/document/7330 ; for translations in your language. A_Put(ByRef Array, ByRef Data, Index=-1, dSize=-1){ If !(A_Array(Array)) ; No Array ? Do an ArrayInit to get a proper Structure A_Init(Array) if ((Index=-1) || (A_Count(Array)+1=Index)) { Gosub, GetArrayStats nSize := aSize+dSize+8 ; calculate new size VarSetCapacity(tmpArray, nSize, 32) ; create tmpArray for our new data A_ArrayMM(&tmpArray, &Array, aSize) ; Copy entire array to TMP NumPut(nSize, tmpArray, 12) ; Update size of array in total NumPut(tSize+8, tmpArray, 16) ; Update tableLenght NumPut(oSize+dSize, tmpArray, 20) ; Update length of new ArrayStructure NumPut(ElmCount+1, tmpArray, 24) ; Update elementcount A_ArrayMM( &tmpArray + tSize + 8 ; Shift ArrayData for 8 bytes , &Array + tSize, oSize ) A_ArrayMM(&tmpArray+aSize+8,&Data,dSize) ; copy data to tmpArray Offset := 28 ; move offsets for array contents Loop, % ElmCount+1 NumPut( NumGet(tmpArray ,(Offset+(A_index-1)*8))+8 ; get last known value and ,tmpArray,(Offset+(A_index-1)*8)) ; increment it by 8 NumPut(aSize+8, tmpArray, tSize) ; Set offsetpointer to new data NumPut(dSize, tmpArray, tSize+4) ; Set size of new element VarSetCapacity(Array,nSize,32) ; Resize the array A_ArrayMM(&Array, &tmpArray, nSize) ; copy tmpArray back to array Return ElmCount+1 } else if ((A_Count(Array)>=Index) && (Index!=0)) { Gosub, GetArrayStats ElmPtr := NumGet(Array,28+(Index-1)*8) ElmSize := NumGet(Array,32+(Index-1)*8) if ((dSize>ElmSize) || (dSizenSize) ? nSize : aSize)) ; with a correct calculated length NumPut(nSize, tmpArray, 12) ; Update size of array in total NumPut(oSize+ptrDiff, tmpArray, 20) ; Update length of new ArrayStructure NumPut(dSize, tmpArray, Offset-4) ; Set size of new element Loop,% ElmCount-Index ; loop remaining elements NumPut( NumGet(tmpArray ,(Offset+(A_index-1)*8))+ptrDiff ; get last known value and ,tmpArray,(Offset+(A_index-1)*8)) ; add the difference Offset := NumGet(tmpArray,Offset-8) A_ArrayMM(&tmpArray+Offset, &Data, dSize) ; Copy new data into tmpArray A_ArrayMM(&tmpArray+Offset+dSize ; remaining ArrayData to new offset , &Array+Offset+ElmSize, aSize-(OffSet+ElmSize)) VarSetCapacity(Array,nSize,32) ; Resize the array A_ArrayMM(&Array, &tmpArray, nSize) ; copy tmpArray back to array } else if (dSize=ElmSize) { ; No need to fix tableoffsets A_ArrayMM(&Array+ElmPtr,&Data,dSize) ; speeeed! } else { ; THIS SHOULD NEVER HAPPEN ErrorLevel := "Internal Binary Array Structure Error / Invalid Binary Array Object" return -1 } Return ElmCount } else { ErrorLevel := "Binary Array Index Mismatch" Return -1 } GetArrayStats: ElmCount := A_Count(Array) ; update ElementCount aSize := A_Size(Array) ; current ByteSize of entire Array oSize := A_Length(Array) ; current ByteSize of contained data in Array tSize := NumGet(Array,16) ; table size If (dSize<=-1) ; No size given - assume it's a string and fix it! RegExReplace(Data,".","",dSize) return } A_Get(ByRef Array, Index) { If !(A_Array(Array)) { ErrorLevel := "No valid binary Array" return -1 } else if ((Index>A_Count(Array)) || (Index<=0)) { ErrorLevel := "Binary Array Index mismatch - no such Index" return -1 } else { Offset := 28+(Index-1)*8 ; Get starting offset in table ElmPtr := NumGet(Array,Offset) ElmSize := NumGet(Array,Offset+4) VarSetCapacity(ArrayElement,ElmSize,32) ; Initialise the returnbuffer A_ArrayMM(&ArrayElement,&Array+ElmPtr,ElmSize) ; Copy the binary data ErrorLevel := ElmSize Return ArrayElement } } ; Returns a joined string of given Array and glue parameter ; Length is returned as ErrorLevel A_Implode(ByRef Array, glue=" ") { If !(A_Array(Array)) { ErrorLevel := "No valid binary Array" return -1 } else { lGlue := glue glueLength := StrLen(lGlue) aSize := A_Length(Array) ; current DataSize of array elmCount := A_Count(Array) ; get ElementCount of Array ErrorLevel := (elmCount-1)*glueLength + aSize ; count new Size of returnString Offset := 0 ; set Offset for A_ArrayMM Loop VarSetCapacity(String,ErrorLevel,32) ; Allocate space for new return Loop,% elmCount { elmLength := NumGet(Array,32+(A_Index-1)*8) ; current element's length elmPos := NumGet(Array,28+(A_Index-1)*8) ; current element's position in Array A_ArrayMM(&String+Offset, &Array+elmPos, elmLength) ; Move it to ReturnData Offset += elmLength ; calculate Offset if (A_Index!=elmCount) A_ArrayMM(&String+Offset, &lGlue, glueLength) ; Move Glue to ReturnData Offset += glueLength ; calculate Offset again } return String } } ; Returns an array of strings, each of which is a substring of string formed ; by splitting it on boundaries formed by the string delimiter. ; unlike Stringsplit, multiple chars are allowed in dString A_Explode(ByRef Array, dString, sString, Limit=0, trimChars="", trimCharsIsRegEx=False, dStringIsRegEx=False) { if !(A_Array(Array)) A_Init(Array) oIF := A_FormatInteger ; Store current Integerformat SetFormat,Integer,H If !(trimCharsIsRegEx) { ; Build RegExNeedle for trimming if non given Loop,Parse,TrimChars ; parse each char and build hexescaped needle escTrimChars .= "|^\" SubStr(asc(A_LoopField),2) "|\" SubStr(asc(A_LoopField),2) "$" trimChars := "(" SubStr(escTrimChars,2) ")" } gLen := StrLen(dString) ; get length of delimiterString sLen := StrLen(sString) ; get length of string ; since this is not a byref parameter, ; binary values need to be assigned direct in call such as ; A_Explode(Array,"\x0",FileGetContent("myfile.dat"),"",0,1) If !(dStringIsRegEx) { ; Build RegExNeedle for matching if non given Loop,Parse,dString ; parse each char and build hexescaped needle escdString .= "|\" SubStr(asc(A_LoopField),2) dString := "(" SubStr(escdString,2) ")" } SetFormat,Integer,% oIF Loop, if (nPos := RegExMatch(sString,dString)) { sLen -= nPos ; calculate new length data := RegExReplace(sString,"(.{" sLen+gLen "}$)") ; generate data to store in Array _tmp := RegExReplace(data,".","",dLen) ; fix length for data sString := RegExReplace(sString,"(^.{" nPos "})") ; generate new sourceString _tmp := RegExReplace(sString,".","",sLen) ; fix length for binary Arrays A_Put(Array,Data,-1,dLen) ; store to Array } else { A_Put(Array,sString,-1,sLen) Break } return A_Count(Array) } ; Deletes ItemIndex of given Array A_Del(ByRef Array, Item=-1){ If !(A_Array(Array)) { ErrorLevel := "No valid binary Array" return -1 } else if ((Item+0<=0) || (Item>A_Count(Array))) { ErrorLevel := "No valid Index" return -1 } else { aSize := A_Size(Array) ; current DataSize of Array VarSetCapacity(tmpArray, aSize, 32) A_ArrayMM(&tmpArray, &Array, aSize) ; copy Array VarSetCapacity(Array,0) ; delete Old Array Loop,% A_Count(tmpArray) { elmData := A_Get(tmpArray,A_Index) if (A_Index!=Item) A_Put(Array,elmData,-1,ErrorLevel) } data := A_Get(tmpArray,Item) ; Get return data size := ErrorLevel ; store size for reuse VarSetCapacity(out,0) ; prepare element VarSetCapacity(out,size,32) A_ArrayMM(&out, &data, size) ; copy data to return var ErrorLevel := size ; update ErrorLevel Return out } } ; Returns the element off the end of array and removes it ; Length is returned as ErrorLevel A_Pop(ByRef Array){ If !(A_Array(Array)) { ErrorLevel := "No valid binary Array" return -1 } else { Item := A_Count(Array) data := A_Del(Array,Item) ; Get return data size := ErrorLevel ; store size for reuse VarSetCapacity(out,0) ; prepare element VarSetCapacity(out,size,32) A_ArrayMM(&out, &data, size) ; copy data to return var ErrorLevel := size ; update ErrorLevel Return out } } ; Shift an element off the beginning of array and returns it ; Length is returned as ErrorLevel A_Shift(ByRef Array){ If !(A_Array(Array)) { ErrorLevel := "No valid binary Array" return -1 } else { Item := 1 data := A_Del(Array,Item) ; Get return data size := ErrorLevel ; store size for reuse VarSetCapacity(out,0) ; prepare element VarSetCapacity(out,size,32) A_ArrayMM(&out, &data, size) ; copy data to return var ErrorLevel := size ; update ErrorLevel Return out } } ; Swaps element IdxA with element IdxB in given Array A_Swap(ByRef Array, IdxA, IdxB) { If !(A_Array(Array)) { ErrorLevel := "No valid binary Array" return -1 } else { elmA := A_Get(Array,IdxA), sizeA := ErrorLevel elmB := A_Get(Array,IdxB), sizeB := ErrorLevel A_Put(Array,elmB,idxA,sizeB) A_Put(Array,elmA,idxB,sizeA) return true } } ; sArray's given intersection Elements are appended to Array, which ; will be created at runtime if neccessary A_Slice(ByRef Array, ByRef sArray, Start, End) { If !(A_Array(sArray)) { ErrorLevel := "No valid source Array" return -1 } else if ((cnt := A_Count(sArray)) && (Start>0) && (cnt0) && (cnt End)? End : Start endIndex := (start==startIndex) ? End : Start Loop, % endIndex - StartIndex + 1 { elm := A_Get(sArray, StartIndex-1+A_Index), size := ErrorLevel cnt := A_Put(Array, elm, -1, size) } ErrorLevel := cnt } } ; Appends entire sArray to Array A_Merge(Byref Array, ByRef sArray) { If (!(A_Array(sArray)) || (A_Count(sArray)<1)) { ErrorLevel := "No valid source Array" return -1 } else { If !(A_Array(Array)) A_Init(Array) A_Slice(Array,sArray,1,A_Count(sArray)) } } ; Returns TRUE if Array, FALSE otherwise - Thx, Lexikos A_Array(byRef Array) { Return Array="Array()" && VarSetCapacity(Array)>=28 && NumGet(Array,8)=0x1001 } ; Returns current element count of given array or -1 if no valid binary array A_Count(byRef Array) { If !(A_Array(Array)) { ErrorLevel := "No valid binary Array" return -1 } else { ErrorLevel := 0 Return NumGet(Array,24,"uInt") } } ; for internal use only - initialises bytestructure of array A_Init(byRef Array) { ; ATM 28 Bytes is minimum for AHK binary array structure ArraySize := 28 VarSetCapacity(Array,ArraySize,32) Array = Array() NumPut(0x1001, Array, 8) ; Array version NumPut(ArraySize, Array, 12) ; ArraySize in bytes NumPut(0x1c, Array, 16) ; TableLength in bytes NumPut(0x0, Array, 20) ; ArrayLength in bytes NumPut(0x0, Array, 24) ; Element count Return True } ; for internal use only - returns ArrayStructuresize A_Size(ByRef Array){ If !(A_Array(Array)) { ErrorLevel := "No valid binary Array" return -1 } else { ErrorLevel := 0 Return NumGet(Array,12,"uInt") } } ; for internal use only - returns DataLength of Array A_Length(ByRef Array){ If !(A_Array(Array)) { ErrorLevel := "No valid binary Array" return -1 } else { ErrorLevel := 0 Return NumGet(Array,20,"uInt") } } A_Dump(ByRef Array) { If !(A_Array(Array)) { ErrorLevel := "No valid binary Array" return -1 } else { out := "Array(" A_Count(Array) ")`n{`n" A_Implode(Array,"`n`t=>`t") "`n}`n" Loop,parse,out,`n if ((A_Index>=3) && (A_Count(Array)+2>=A_Index)) out .= " [" A_Index-2 "]" ((A_index-2=1) ? "`t=>`t" : "") A_LoopField "`n" else out := ((A_Index=1) ? A_LoopField : out A_LoopField) "`n" Return out } } ; for internal use only - SyntaxSugar for RtlMoveMemory A_ArrayMM(Target, Source, Length) { DllCall("RtlMoveMemory","uInt",Target,"uInt",Source,"uInt",Length) } ; for debugging purposes only A___ArrayBin(ByRef Array,offset,length){ SetFormat,Integer,h n := 0 Loop,% length { c := NumGet(Array,offset+A_Index-1,"uchar") o .= SubStr("0" SubStr(c,3),-1) " " ((n=16) ? "`t" chars "`n" : "" ) chars := ((n=16) ? "" : chars (RegExMatch(chr(c),"[^\x0-\x1f\x7f-\xa0]") ? chr(c) : ".")) n:= ((n=16) ? 0 : n+1) } SetFormat,Integer,D if (n) && (n!=16) { VarSetCapacity(spc,(16-n)*3,32) r := spc "`t" chars } return o r } ; for debugging purposes only - to dump an array use A_Dump(Array) A___ArrayInsideView(Array) { A_ArrayMM(&(as1:="-------"), &Array, 7) as2 := ((x:=NumGet(Array, 7,"uchar"))=0) ? "\0" : x av := NumGet(Array, 8) ; Array version as := NumGet(Array, 12) ; ArraySize in bytes (Structure) tl := NumGet(Array, 16) ; TableLength in bytes al := NumGet(Array, 20) ; ArrayLength in bytes (Data) ec := NumGet(Array, 24) ; Element count offset := 28 Loop,% (tl-offset) // 8 { elms .= "&" offset+((A_index-1)*8) " ptr elm " a_index . "`t->`t" (o:=NumGet(Array,offset+((A_index-1)*8))) "`n" . "&" offset+((A_index-1)*8)+4 " len elm " a_index . "`t->`t" (l:=NumGet(Array,offset+4+((A_index-1)*8))) "`n" data .= "&" o ": " A___ArrayBin(Array,o,l) "`n" } out= (LTrim aSignature &0 %as1% Terminator &7 %as2% arrayVersion &8 %av% tArraySize &12 %as% tableLength &16 %tl% arrayLength &20 %al% elementCount &24 %ec% %elms% %data% ) return out } /* a_array - by derRaphael - exmaple internal table layout &0 (str) Array() &7 (uchar) \0 &8 (uint) AHK Array Version Major/Minor ::atm dec 4097 or 0x1001:: &12 (uint) ArraySize in bytes &16 (uint) TableLength ::subject to change:: will stay reserved &20 (uint) ArrayLength &24 (uint) ElementsCount &28 (uint) Elm1Offset ::In this case &36:: &32 (uint) elm1Length &36 rawdata */