Über die String-Dekompression

  • Ich habe mir eine Funktion geschrieben um binär eingebundene Dateien zu komprimieren. Die binären Strings enthalten meist Unmengen von langen homogenen Zeichenketten, die werden dann komprimiert. Die Geschwindigkeit des Komprimierens ist annehmbar. Die Methode schrumpft die Strings auf ca 70% ihrer alten Größe.

    Allerdings ist das Dekomprimieren saulangsam. Obwohl die Funktion auf das Wesentliche reduziert ist, braucht es bis zu 4 Minuten um eine 100KB Datei zu "entpacken". Wie kann ich das Entpacken beschleunigen? Ich möchte nicht auf eine ZIP Kompression oder irgendeine UDF umsteigen, das ist dann widersinnig, da das Skript nur größer würde als vorher. Hier mal ein Testskript:

    Spoiler anzeigen
    [autoit]

    ;$sTest = "67B666666B76000000000000000000056B66666666B650000000000000000056B666666666676500000000000000006676666666666766000000000000000566666666666666665000000000000006666666666666666660000000000000566666666666666666650000000000005666666666666667666500000000000056677676767676767665000000000000566B777777777777B665000000000000566B7B777777777BB665000000000000066BBB7B7B7BB7BBD650000000000000056BDBBBBBBBBBBD76500000000000000056BDDDBDBDBDDD660000000000000000366BEDDDDDDEB655000000000000000005567BDEEDB76550000000000000000000055666666550000000000000000000000005555550000000000000FFFFFFFFFFFE7FFFFFF81FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFE007FFFFE007FFFFE007FFFFC003FFFFC003FFFFC003FFFFC003FFFF8001FFFF0000FFFF0000FFFE00007FFE00007FFC00003FFC00003FFC00003FFC00003FFC00003FFE00007FFE00007FFF0000FFFF0000FFFF8001FFFFE007FFFFF81FFF00000000F26A0451000000000000010000000000800300009053040030010000B0040000000000002800000020000000400000000100010000000000000100000000000000000000000000000000000000000000FFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC1FFFFFC3C7FFFC3FC1FF83FFC07FBFFFC1FFBFFFC7FFBFFFDFFFBFFFDFFFBFFFDFFFBFFFDFFFBFFFDFFFBFFFDFFFBFFFDFFFBFFFDFFFBFFC1FFFBFC3DFFFBC3C1FFF83C3FFFFBC3FFFFF83FFFFFFBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC1FFFFFC007FFFC0001FF8000007F800001FF800007FF80001FFF80001FFF80001FFF80001FFF80001FFF80001FFF80001FFF80001FFF80001FFF80001FFF80001FFF8003FFFF803FFFFF83FFFFFFBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000F26A0451000000000000010000000000D8040000E8540400E8020000B0040000000000002800000020000000400000000100040000000000800200000000000000000000000000000000000000000000"
    $sTest = '67B[6:6]B76[0:19]56B[6:8]B65[0:17]56B[6:10]765[0:16]667[6:10]766[0:15]5[6:16]5[0:14][6:18][0:13]5[6:18]5[0:12]5[6:14]76665[0:12]56677676767676767665[0:12]566B[7:12]B665[0:12]566B7B[7:9]BB665[0:13]66BBB7B7B7BB7BBD65[0:14]56BD[B:10]D765[0:15]56BDDDBDBDBDDD66[0:16]366BE[D:6]EB655[0:17]5567BDEEDB7655[0:20]55[6:6]55[0:24][5:6][0:13][F:11]E7[F:6]81[F:6]00[F:6]00[F:6]00[F:6]00[F:6]00[F:5]E007FFFFE007FFFFE007FFFFC003FFFFC003FFFFC003FFFFC003FFFF8001FFFF0000FFFF0000FFFE00007FFE00007FFC00003FFC00003FFC00003FFC00003FFC00003FFE00007FFE00007FFF0000FFFF0000FFFF8001FFFFE007[F:5]81FFF[0:8]F26A0451[0:13]1[0:10]800300009053040030010000B004[0:12]28[0:6]2[0:7]4[0:8]10001[0:13]1[0:44][F:6]00[F:44]C1[F:5]C3C7FFFC3FC1FF83FFC07FBFFFC1FFBFFFC7FFBFFFDFFFBFFFDFFFBFFFDFFFBFFFDFFFBFFFDFFFBFFFDFFFBFFFDFFFBFFFDFFFBFFC1FFFBFC3DFFFBC3C1FFF83C3FFFFBC3[F:5]83[F:6]B[F:98]C1[F:5]C007FFFC0001FF8[0:5]7F800001FF800007FF80001FFF80001FFF80001FFF80001FFF80001FFF80001FFF80001FFF80001FFF80001FFF80001FFF80001FFF8003FFFF803[F:5]83[F:6]B[F:54][0:8]F26A0451[0:13]1[0:10]D8040000E8540400E8020000B004[0:12]28[0:6]2[0:7]4[0:8]10004[0:10]8002[0:44]'

    [/autoit] [autoit][/autoit] [autoit]

    ;Compress_Binary($sTest)
    Decompress($sTest)

    [/autoit] [autoit][/autoit] [autoit]

    ; #FUNCTION# ====================================================================================================================
    ; Name ..........: Compress_Binary
    ; Description ...: Rudimentary binary compression
    ; Syntax ........: Compress_Binary($sString)
    ; Parameters ....: $sString - Binary String
    ; Return values .: Compressed String
    ; Author ........: minx
    ; ===============================================================================================================================
    Func Compress_Binary($sString)
    $OldLength = StringLen($sString)
    Local $aChr[16] = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"]
    $SumLength = 0
    For $i = 0 To 15; Finden der maximalen Länge um zusätzliche Schleifen zu vermeiden
    $MaxSize = 0
    Do
    $MaxSize += 1
    $State = StringInStr($sString, _($aChr[$i],$MaxSize))
    Until $State = 0
    If $MaxSize > $SumLength Then $SumLength = $MaxSize
    Next
    For $i = 0 To 15; Ersetzen der homogenen Strings. Von Groß nach Klein.
    For $j = $SumLength To 5 Step -1
    If StringInStr($sString, _($aChr[$i],$j)) Then
    $sString = StringReplace($sString, _($aChr[$i],$j), "[" & $aChr[$i] & ":" & $j & "]" )
    EndIf
    Next
    Next
    $Perc = Round((StringLen($sString) / $OldLength)*100)
    ;$sString = "'"&$sString&"'"
    ConsoleWrite("!> Compression: " & $Perc & "%" & @CRLF )
    Return $sString
    EndFunc

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func Decompress($a)
    Local $b="(\.|\||\*|\?|\+|\(|\)|\{|\}|\[|\]|\^|\$|\\)",$c=StringRegExp($a,"(?s)(?i)"&StringRegExpReplace("[",$b,"\\$1")&"(.*?)"&StringRegExpReplace("]",$b,"\\$1"),3)
    For $i=0 To UBound($c)-1
    $a=StringReplace($a,"["&$c[$i]&"]",_(StringLeft($c[$i],1),StringReplace($c[$i],StringLeft($c[$i],2),"")))
    Next
    Return $a
    EndFunc

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func _($a,$b)
    Local $c
    For $i = 1 To $b
    $c &= $a
    Next
    Return $c
    EndFunc

    [/autoit]

    Einmal editiert, zuletzt von minx (10. Februar 2013 um 13:35)

  • Ich möchte nicht auf eine ZIP Kompression oder irgendeine UDF umsteigen, das ist dann widersinnig, da das Skript nur größer würde als vorher.


    Öhm würd ich nicht behaupten. Seit Windows XP kann man durchaus auch die Boardmittel von Windows verwenden um Zip-Dateien zu entpacken. Somit ist es nicht zwingend notwendig externe Tools wie 7zip zu includen.


    Siehe hier: https://autoit.de/index.php?page=Thread&postID=150287

    Eine Zip-Kompression ist vermutlich auch deutlich effizienter was die Kompression anbelangt als deine selbst gebastelte Variante, könntest ja mal testen. ;)

    Einmal editiert, zuletzt von misterspeed (9. Februar 2013 um 20:13)

  • Hallo minx,

    mit diesen Funktionen habe ich positive Erfahrungen:

    Spoiler anzeigen
    [autoit]

    ; #FUNCTION# ;===============================================================================
    ;http://www.autoitscript.com/forum/index.ph…ndpost&p=627588
    ; Name...........: _LZNTCompress
    ; Description ...: Compresses input data.
    ; Syntax.........: _LZNTCompress ($vInput [, $iCompressionFormatAndEngine])
    ; Parameters ....: $vInput - Data to compress.
    ; $iCompressionFormatAndEngine - Compression format and engine type. Default is 2 (standard compression). Can be:
    ; |2 - COMPRESSION_FORMAT_LZNT1 | COMPRESSION_ENGINE_STANDARD
    ; |258 - COMPRESSION_FORMAT_LZNT1 | COMPRESSION_ENGINE_MAXIMUM
    ; Return values .: Success - Returns compressed binary data.
    ; - Sets @error to 0
    ; Failure - Returns empty string and sets @error:
    ; |1 - Error determining workspace buffer size.
    ; |2 - Error compressing.
    ; Author ........: trancexx
    ; Related .......: _LZNTDecompress
    ; Link ..........; http://msdn.microsoft.com/en-us/library/bb981783.aspx
    ;
    ;==========================================================================================
    Func _LZNTCompress($vInput, $iCompressionFormatAndEngine = 2)

    [/autoit] [autoit][/autoit] [autoit]

    If Not ($iCompressionFormatAndEngine = 258) Then
    $iCompressionFormatAndEngine = 2
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    Local $bBinary = Binary($vInput)

    [/autoit] [autoit][/autoit] [autoit]

    Local $tInput = DllStructCreate("byte[" & BinaryLen($bBinary) & "]")
    DllStructSetData($tInput, 1, $bBinary)

    [/autoit] [autoit][/autoit] [autoit]

    Local $a_Call = DllCall("ntdll.dll", "int", "RtlGetCompressionWorkSpaceSize", _
    "ushort", $iCompressionFormatAndEngine, _
    "dword*", 0, _
    "dword*", 0)

    [/autoit] [autoit][/autoit] [autoit]

    If @error Or $a_Call[0] Then
    Return SetError(1, 0, "") ; error determining workspace buffer size
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    Local $tWorkSpace = DllStructCreate("byte[" & $a_Call[2] & "]") ; workspace is needed for compression

    [/autoit] [autoit][/autoit] [autoit]

    Local $tBuffer = DllStructCreate("byte[" & 16 * DllStructGetSize($tInput) & "]") ; initially oversizing buffer

    [/autoit] [autoit][/autoit] [autoit]

    Local $a_Call = DllCall("ntdll.dll", "int", "RtlCompressBuffer", _
    "ushort", $iCompressionFormatAndEngine, _
    "ptr", DllStructGetPtr($tInput), _
    "dword", DllStructGetSize($tInput), _
    "ptr", DllStructGetPtr($tBuffer), _
    "dword", DllStructGetSize($tBuffer), _
    "dword", 4096, _
    "dword*", 0, _
    "ptr", DllStructGetPtr($tWorkSpace))

    [/autoit] [autoit][/autoit] [autoit]

    If @error Or $a_Call[0] Then
    Return SetError(2, 0, "") ; error compressing
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    Local $tOutput = DllStructCreate("byte[" & $a_Call[7] & "]", DllStructGetPtr($tBuffer))

    [/autoit] [autoit][/autoit] [autoit]

    Return SetError(0, 0, DllStructGetData($tOutput, 1))

    [/autoit] [autoit][/autoit] [autoit]

    EndFunc ;==>_LZNTCompress

    [/autoit] [autoit][/autoit] [autoit]

    ; #FUNCTION# ;===============================================================================
    ;
    ; Name...........: _LZNTDecompress
    ; Description ...: Decompresses input data.
    ; Syntax.........: _LZNTDecompress ($bBinary)
    ; Parameters ....: $vInput - Binary data to decompress.
    ; Return values .: Success - Returns decompressed binary data.
    ; - Sets @error to 0
    ; Failure - Returns empty string and sets @error:
    ; |1 - Error decompressing.
    ; Author ........: trancexx
    ; Related .......: _LZNTCompress
    ; Link ..........; http://msdn.microsoft.com/en-us/library/bb981784.aspx
    ;
    ;==========================================================================================
    Func _LZNTDecompress($bBinary)

    [/autoit] [autoit][/autoit] [autoit]

    $bBinary = Binary($bBinary)

    [/autoit] [autoit][/autoit] [autoit]

    Local $tInput = DllStructCreate("byte[" & BinaryLen($bBinary) & "]")
    DllStructSetData($tInput, 1, $bBinary)

    [/autoit] [autoit][/autoit] [autoit]

    Local $tBuffer = DllStructCreate("byte[" & 16 * DllStructGetSize($tInput) & "]") ; initially oversizing buffer

    [/autoit] [autoit][/autoit] [autoit]

    Local $a_Call = DllCall("ntdll.dll", "int", "RtlDecompressBuffer", _
    "ushort", 2, _
    "ptr", DllStructGetPtr($tBuffer), _
    "dword", DllStructGetSize($tBuffer), _
    "ptr", DllStructGetPtr($tInput), _
    "dword", DllStructGetSize($tInput), _
    "dword*", 0)

    [/autoit] [autoit][/autoit] [autoit]

    If @error Or $a_Call[0] Then
    Return SetError(1, 0, "") ; error decompressing
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    Local $tOutput = DllStructCreate("byte[" & $a_Call[6] & "]", DllStructGetPtr($tBuffer))

    [/autoit] [autoit][/autoit] [autoit]

    Return SetError(0, 0, DllStructGetData($tOutput, 1))

    [/autoit] [autoit][/autoit] [autoit]

    EndFunc ;==>_LZNTDecompress

    [/autoit]

    mfg autoBert

  • oder sehr simpel so^^

    Spoiler anzeigen
    [autoit]

    $stest = StringTrimLeft(StringToBinary(FileRead(@AutoItExe)), 2) ;0x entfernen
    ;~ $sTest = "67B666666B76000000000000000000056B66666666B650000000000000000056B666666666676500000000000000006676666666666766000000000000000566666666666666665000000000000006666666666666666660000000000000566666666666666666650000000000005666666666666667666500000000000056677676767676767665000000000000566B777777777777B665000000000000566B7B777777777BB665000000000000066BBB7B7B7BB7BBD650000000000000056BDBBBBBBBBBBD76500000000000000056BDDDBDBDBDDD660000000000000000366BEDDDDDDEB655000000000000000005567BDEEDB76550000000000000000000055666666550000000000000000000000005555550000000000000FFFFFFFFFFFE7FFFFFF81FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFE007FFFFE007FFFFE007FFFFC003FFFFC003FFFFC003FFFFC003FFFF8001FFFF0000FFFF0000FFFE00007FFE00007FFC00003FFC00003FFC00003FFC00003FFC00003FFE00007FFE00007FFF0000FFFF0000FFFF8001FFFFE007FFFFF81FFF00000000F26A0451000000000000010000000000800300009053040030010000B0040000000000002800000020000000400000000100010000000000000100000000000000000000000000000000000000000000FFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC1FFFFFC3C7FFFC3FC1FF83FFC07FBFFFC1FFBFFFC7FFBFFFDFFFBFFFDFFFBFFFDFFFBFFFDFFFBFFFDFFFBFFFDFFFBFFFDFFFBFFFDFFFBFFC1FFFBFC3DFFFBC3C1FFF83C3FFFFBC3FFFFF83FFFFFFBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC1FFFFFC007FFFC0001FF8000007F800001FF800007FF80001FFF80001FFF80001FFF80001FFF80001FFF80001FFF80001FFF80001FFF80001FFF80001FFF80001FFF8003FFFF803FFFFF83FFFFFFBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000F26A0451000000000000010000000000D8040000E8540400E8020000B0040000000000002800000020000000400000000100040000000000800200000000000000000000000000000000000000000000"
    ;~ ;ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $sTest = ' & $sTest & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
    ;~ $sTest = '67B[6:6]B76[0:19]56B[6:8]B65[0:17]56B[6:10]765[0:16]667[6:10]766[0:15]5[6:16]5[0:14][6:18][0:13]5[6:18]5[0:12]5[6:14]76665[0:12]56677676767676767665[0:12]566B[7:12]B665[0:12]566B7B[7:9]BB665[0:13]66BBB7B7B7BB7BBD65[0:14]56BD[B:10]D765[0:15]56BDDDBDBDBDDD66[0:16]366BE[D:6]EB655[0:17]5567BDEEDB7655[0:20]55[6:6]55[0:24][5:6][0:13][F:11]E7[F:6]81[F:6]00[F:6]00[F:6]00[F:6]00[F:6]00[F:5]E007FFFFE007FFFFE007FFFFC003FFFFC003FFFFC003FFFFC003FFFF8001FFFF0000FFFF0000FFFE00007FFE00007FFC00003FFC00003FFC00003FFC00003FFC00003FFE00007FFE00007FFF0000FFFF0000FFFF8001FFFFE007[F:5]81FFF[0:8]F26A0451[0:13]1[0:10]800300009053040030010000B004[0:12]28[0:6]2[0:7]4[0:8]10001[0:13]1[0:44][F:6]00[F:44]C1[F:5]C3C7FFFC3FC1FF83FFC07FBFFFC1FFBFFFC7FFBFFFDFFFBFFFDFFFBFFFDFFFBFFFDFFFBFFFDFFFBFFFDFFFBFFFDFFFBFFFDFFFBFFC1FFFBFC3DFFFBC3C1FFF83C3FFFFBC3[F:5]83[F:6]B[F:98]C1[F:5]C007FFFC0001FF8[0:5]7F800001FF800007FF80001FFF80001FFF80001FFF80001FFF80001FFF80001FFF80001FFF80001FFF80001FFF80001FFF80001FFF8003FFFF803[F:5]83[F:6]B[F:54][0:8]F26A0451[0:13]1[0:10]D8040000E8540400E8020000B004[0:12]28[0:6]2[0:7]4[0:8]10004[0:10]8002[0:44]'
    $stest = StringLeft($stest, 500000)

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    $len = StringLen($stest)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $len = ' & $len & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console

    [/autoit] [autoit][/autoit] [autoit]

    $t = TimerInit()
    $a = compbin($stest)
    ;ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $a = ' & $a & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
    ;ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $a = ' & $a & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console
    $m = TimerDiff($t)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $m = ' & $m & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
    $alen = StringLen($a)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $alen = ' & $alen & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
    $rate = Int($len / $m)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $rate = ' & $rate & " KB/s" & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    $t = TimerInit()
    $b = decompbin($a)
    ;ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $b = ' & $b & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console

    [/autoit] [autoit][/autoit] [autoit]

    $m = TimerDiff($t)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $m = ' & $m & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : len2 = ' & StringLen($b) & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
    $rate = Int($alen / $m)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $rate = ' & $rate & " KB/s" & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Exit

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func compbin($string)
    $len = StringLen($string)
    $ret = ""
    $p = 0
    For $i = 1 To $len ;kompletten string durchlaufen
    $aktuell = StringMid($string, $i, 1) ;aktuelles token
    $anz = 1 ;anzahl gleicher token
    For $a = $i + 1 To $i + 54 ;kommt es mehrfach vor?
    If StringMid($string, $a, 1) = $aktuell And $a <= $len Then ;kommt mehrfach vor
    $anz += 1
    Else
    $i = $a - 1 ;nicht mehrfach
    ExitLoop ;nächstes token
    EndIf
    Next

    [/autoit] [autoit][/autoit] [autoit]

    If $anz > 2 Then ;mehr als 2 gleiche token gefunden
    $ret &= $aktuell & Chr(70 + $anz) ;anzahl hinter token hängen
    $i = $a - 1
    ElseIf $anz = 2 Then
    If Asc($aktuell) < 56 Then ;bit 0-3 und 5-7 nehmen eine doppelte zahl auf
    $ret &= Chr((Asc($aktuell) - 48) * 17 + 127)
    Else
    $ret &= $aktuell & $aktuell
    EndIf
    Else
    $ret &= $aktuell ;nur einmal vorkommenden buchstaben anhängen
    EndIf
    Next
    $Perc = Round(StringLen($ret) / $len * 100)
    ConsoleWrite("!> Compression: " & $Perc & "%" & @CRLF)

    [/autoit] [autoit][/autoit] [autoit]

    Return $ret
    EndFunc ;==>compbin

    [/autoit] [autoit][/autoit] [autoit]

    Func decompbin($string)
    $ret = ""
    $len = StringLen($string)
    For $i = 1 To $len
    $decomp = StringMid($string, $i, 1);aktueller buchstabe ;
    $token = Asc($decomp) ;aktuelles token
    If $token >= 127 Then ;doppelte 0-7?
    $decomp = Chr((($token - 127) / 17) + 48);magic numbers FTW^^
    $decomp &= $decomp
    ElseIf $token > 70 Then ;komprimiertes Zeichen?
    $token -= 70 ;länge
    $akt = StringMid($string, $i - 1, 1) ;aktueller zu vervielfältigende buchstabe
    $decomp = ""
    For $a = 1 To $token - 1
    $decomp &= $akt
    Next
    Else
    $decomp = StringMid($string, $i, 1) ;einfache Ziffer/Buchstabe
    EndIf
    $ret &= $decomp

    [/autoit] [autoit][/autoit] [autoit]

    Next
    Return $ret

    [/autoit] [autoit][/autoit] [autoit]

    EndFunc ;==>decompbin

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit]

    eine äusserst billige Lauflängenkodierung, die bis zu 127 gleiche Buchstaben durch den Buchstaben und einen weiteren Token ersetzt, der die Anzahl bestimmt.
    Wem die Codes >127 nicht passen, der kann beim komprimieren die ascii-codes von 0-F um 12 vermindern und dann die Anzahl von 64 bis 128 festlegen.

    Btw, minx, dein Ursprungs-string ist auf 44% eingestampft 8o

    //EDIT Bug entfernt, Text geändert

    //EDIT 2, verbesserte Komprimierung, minimal langsamer, s. Post 7

    ciao
    Andy


    "Schlechtes Benehmen halten die Leute doch nur deswegen für eine Art Vorrecht, weil keiner ihnen aufs Maul haut." Klaus Kinski
    "Hint: Write comments after each line. So you can (better) see what your program does and what it not does. And we can see what you're thinking what your program does and we can point to the missunderstandings." A-Jay

    Wie man Fragen richtig stellt... Tutorial: Wie man Script-Fehler findet und beseitigt...X-Y-Problem

    4 Mal editiert, zuletzt von Andy (10. Februar 2013 um 02:27)

  • Ich habe einmal Testhalber Andy's Vorschlag _LZNTCompress gegenübergestellt:

    Spoiler anzeigen
    [autoit]

    $sTest = "67B666666B76000000000000000000056B66666666B650000000000000000056B666666666676500000000000000006676666666666766000000000000000566666666666666665000000000000006666666666666666660000000000000566666666666666666650000000000005666666666666667666500000000000056677676767676767665000000000000566B777777777777B665000000000000566B7B777777777BB665000000000000066BBB7B7B7BB7BBD650000000000000056BDBBBBBBBBBBD76500000000000000056BDDDBDBDBDDD660000000000000000366BEDDDDDDEB655000000000000000005567BDEEDB76550000000000000000000055666666550000000000000000000000005555550000000000000FFFFFFFFFFFE7FFFFFF81FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFE007FFFFE007FFFFE007FFFFC003FFFFC003FFFFC003FFFFC003FFFF8001FFFF0000FFFF0000FFFE00007FFE00007FFC00003FFC00003FFC00003FFC00003FFC00003FFE00007FFE00007FFF0000FFFF0000FFFF8001FFFFE007FFFFF81FFF00000000F26A0451000000000000010000000000800300009053040030010000B0040000000000002800000020000000400000000100010000000000000100000000000000000000000000000000000000000000FFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC1FFFFFC3C7FFFC3FC1FF83FFC07FBFFFC1FFBFFFC7FFBFFFDFFFBFFFDFFFBFFFDFFFBFFFDFFFBFFFDFFFBFFFDFFFBFFFDFFFBFFFDFFFBFFC1FFFBFC3DFFFBC3C1FFF83C3FFFFBC3FFFFF83FFFFFFBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC1FFFFFC007FFFC0001FF8000007F800001FF800007FF80001FFF80001FFF80001FFF80001FFF80001FFF80001FFF80001FFF80001FFF80001FFF80001FFF80001FFF8003FFFF803FFFFF83FFFFFFBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000F26A0451000000000000010000000000D8040000E8540400E8020000B0040000000000002800000020000000400000000100040000000000800200000000000000000000000000000000000000000000"
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $sTest = ' & $sTest & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
    ;$sTest = '67B[6:6]B76[0:19]56B[6:8]B65[0:17]56B[6:10]765[0:16]667[6:10]766[0:15]5[6:16]5[0:14][6:18][0:13]5[6:18]5[0:12]5[6:14]76665[0:12]56677676767676767665[0:12]566B[7:12]B665[0:12]566B7B[7:9]BB665[0:13]66BBB7B7B7BB7BBD65[0:14]56BD[B:10]D765[0:15]56BDDDBDBDBDDD66[0:16]366BE[D:6]EB655[0:17]5567BDEEDB7655[0:20]55[6:6]55[0:24][5:6][0:13][F:11]E7[F:6]81[F:6]00[F:6]00[F:6]00[F:6]00[F:6]00[F:5]E007FFFFE007FFFFE007FFFFC003FFFFC003FFFFC003FFFFC003FFFF8001FFFF0000FFFF0000FFFE00007FFE00007FFC00003FFC00003FFC00003FFC00003FFC00003FFE00007FFE00007FFF0000FFFF0000FFFF8001FFFFE007[F:5]81FFF[0:8]F26A0451[0:13]1[0:10]800300009053040030010000B004[0:12]28[0:6]2[0:7]4[0:8]10001[0:13]1[0:44][F:6]00[F:44]C1[F:5]C3C7FFFC3FC1FF83FFC07FBFFFC1FFBFFFC7FFBFFFDFFFBFFFDFFFBFFFDFFFBFFFDFFFBFFFDFFFBFFFDFFFBFFFDFFFBFFFDFFFBFFC1FFFBFC3DFFFBC3C1FFF83C3FFFFBC3[F:5]83[F:6]B[F:98]C1[F:5]C007FFFC0001FF8[0:5]7F800001FF800007FF80001FFF80001FFF80001FFF80001FFF80001FFF80001FFF80001FFF80001FFF80001FFF80001FFF80001FFF8003FFFF803[F:5]83[F:6]B[F:54][0:8]F26A0451[0:13]1[0:10]D8040000E8540400E8020000B004[0:12]28[0:6]2[0:7]4[0:8]10004[0:10]8002[0:44]'

    [/autoit] [autoit][/autoit] [autoit]

    For $i = 1 To 10
    $sTest &= $sTest
    Next

    [/autoit] [autoit][/autoit] [autoit]

    $len = StringLen($sTest)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $len = ' & $len & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console

    [/autoit] [autoit][/autoit] [autoit]

    $t = TimerInit()
    $a = compbin($sTest)
    ;ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $a = ' & $a & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console
    $m = TimerDiff($t)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $m = ' & $m & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console

    [/autoit] [autoit][/autoit] [autoit]

    $t = TimerInit()
    $b = decompbin($a)
    ;ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $b = ' & $b & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console
    $m = TimerDiff($t)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $m = ' & $m & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console

    [/autoit] [autoit][/autoit] [autoit]

    $t = TimerInit()
    $a = _LZNTCompress($sTest)
    ;ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $a = ' & $a & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console
    $m = TimerDiff($t)
    $b = _LZNTDecompress($a)
    ;ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $b = ' & $b & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console
    $m = TimerDiff($t)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $m = ' & $m & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
    Exit

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func compbin($string)
    $len = StringLen($string)
    $ret = ""
    For $i = 1 To $len ;kompletten string durchlaufen
    $aktuell = StringMid($string, $i, 1) ;aktuelles token
    $anz = 1 ;anzahl gleicher token
    For $a = $i + 1 To $i + 127 ;kommt es mehrfach vor?
    If StringMid($string, $a, 1) = $aktuell And $a < $len Then ;kommt mehrfach vor
    $anz += 1
    Else
    $i = $a - 1 ;nicht mehrfach
    ExitLoop ;nächstes token
    EndIf
    Next
    If $anz > 1 Then ;mehr als 2 gleiche token gefunden
    $ret &= $aktuell & Chr(127 + $anz) ;anzahl hinter token hängen
    Else
    $ret &= $aktuell ;nur einmal vorkommenden buchstaben anhängen
    EndIf
    Next
    $Perc = Round(StringLen($ret) / $len * 100)

    [/autoit] [autoit][/autoit] [autoit]

    ConsoleWrite("!> Compression: " & $Perc & "%" & @CRLF)

    [/autoit] [autoit][/autoit] [autoit]

    Return $ret

    [/autoit] [autoit][/autoit] [autoit]

    EndFunc ;==>compbin

    [/autoit] [autoit][/autoit] [autoit]

    Func decompbin($string)
    $ret = ""
    $len = StringLen($string)
    For $i = 1 To $len
    $decomp = StringMid($string, $i, 1);aktueller buchstabe
    $token = Asc($decomp) ;aktuelles token
    If $token > 127 Then ;komprimiertes Zeichen?
    $token -= 127 ;länge
    $akt = StringMid($string, $i - 1, 1) ;aktueller zu vervielfältigende buchstabe
    $decomp = ""
    For $a = 1 To $token - 1 ;langsamer gehts nicht, aber was solls^^
    $decomp &= $akt
    Next
    EndIf
    $ret &= $decomp

    [/autoit] [autoit][/autoit] [autoit]

    Next
    Return $ret

    [/autoit] [autoit][/autoit] [autoit]

    EndFunc ;==>decompbin

    [/autoit] [autoit][/autoit] [autoit]

    ; #FUNCTION# ;===============================================================================
    ;http://www.autoitscript.com/forum/index.ph…ndpost&p=627588
    ; Name...........: _LZNTCompress
    ; Description ...: Compresses input data.
    ; Syntax.........: _LZNTCompress ($vInput [, $iCompressionFormatAndEngine])
    ; Parameters ....: $vInput - Data to compress.
    ; $iCompressionFormatAndEngine - Compression format and engine type. Default is 2 (standard compression). Can be:
    ; |2 - COMPRESSION_FORMAT_LZNT1 | COMPRESSION_ENGINE_STANDARD
    ; |258 - COMPRESSION_FORMAT_LZNT1 | COMPRESSION_ENGINE_MAXIMUM
    ; Return values .: Success - Returns compressed binary data.
    ; - Sets @error to 0
    ; Failure - Returns empty string and sets @error:
    ; |1 - Error determining workspace buffer size.
    ; |2 - Error compressing.
    ; Author ........: trancexx
    ; Related .......: _LZNTDecompress
    ; Link ..........; http://msdn.microsoft.com/en-us/library/bb981783.aspx
    ;
    ;==========================================================================================
    Func _LZNTCompress($vInput, $iCompressionFormatAndEngine = 2)

    [/autoit] [autoit][/autoit] [autoit]

    If Not ($iCompressionFormatAndEngine = 258) Then
    $iCompressionFormatAndEngine = 2
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    Local $bBinary = Binary($vInput)

    [/autoit] [autoit][/autoit] [autoit]

    Local $tInput = DllStructCreate("byte[" & BinaryLen($bBinary) & "]")
    DllStructSetData($tInput, 1, $bBinary)

    [/autoit] [autoit][/autoit] [autoit]

    Local $a_Call = DllCall("ntdll.dll", "int", "RtlGetCompressionWorkSpaceSize", _
    "ushort", $iCompressionFormatAndEngine, _
    "dword*", 0, _
    "dword*", 0)

    [/autoit] [autoit][/autoit] [autoit]

    If @error Or $a_Call[0] Then
    Return SetError(1, 0, "") ; error determining workspace buffer size
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    Local $tWorkSpace = DllStructCreate("byte[" & $a_Call[2] & "]") ; workspace is needed for compression

    [/autoit] [autoit][/autoit] [autoit]

    Local $tBuffer = DllStructCreate("byte[" & 16 * DllStructGetSize($tInput) & "]") ; initially oversizing buffer

    [/autoit] [autoit][/autoit] [autoit]

    Local $a_Call = DllCall("ntdll.dll", "int", "RtlCompressBuffer", _
    "ushort", $iCompressionFormatAndEngine, _
    "ptr", DllStructGetPtr($tInput), _
    "dword", DllStructGetSize($tInput), _
    "ptr", DllStructGetPtr($tBuffer), _
    "dword", DllStructGetSize($tBuffer), _
    "dword", 4096, _
    "dword*", 0, _
    "ptr", DllStructGetPtr($tWorkSpace))

    [/autoit] [autoit][/autoit] [autoit]

    If @error Or $a_Call[0] Then
    Return SetError(2, 0, "") ; error compressing
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    Local $tOutput = DllStructCreate("byte[" & $a_Call[7] & "]", DllStructGetPtr($tBuffer))

    [/autoit] [autoit][/autoit] [autoit]

    Return SetError(0, 0, DllStructGetData($tOutput, 1))

    [/autoit] [autoit][/autoit] [autoit]

    EndFunc ;==>_LZNTCompress

    [/autoit] [autoit][/autoit] [autoit]

    ; #FUNCTION# ;===============================================================================
    ;
    ; Name...........: _LZNTDecompress
    ; Description ...: Decompresses input data.
    ; Syntax.........: _LZNTDecompress ($bBinary)
    ; Parameters ....: $vInput - Binary data to decompress.
    ; Return values .: Success - Returns decompressed binary data.
    ; - Sets @error to 0
    ; Failure - Returns empty string and sets @error:
    ; |1 - Error decompressing.
    ; Author ........: trancexx
    ; Related .......: _LZNTCompress
    ; Link ..........; http://msdn.microsoft.com/en-us/library/bb981784.aspx
    ;
    ;==========================================================================================
    Func _LZNTDecompress($bBinary)

    [/autoit] [autoit][/autoit] [autoit]

    $bBinary = Binary($bBinary)

    [/autoit] [autoit][/autoit] [autoit]

    Local $tInput = DllStructCreate("byte[" & BinaryLen($bBinary) & "]")
    DllStructSetData($tInput, 1, $bBinary)

    [/autoit] [autoit][/autoit] [autoit]

    Local $tBuffer = DllStructCreate("byte[" & 16 * DllStructGetSize($tInput) & "]") ; initially oversizing buffer

    [/autoit] [autoit][/autoit] [autoit]

    Local $a_Call = DllCall("ntdll.dll", "int", "RtlDecompressBuffer", _
    "ushort", 2, _
    "ptr", DllStructGetPtr($tBuffer), _
    "dword", DllStructGetSize($tBuffer), _
    "ptr", DllStructGetPtr($tInput), _
    "dword", DllStructGetSize($tInput), _
    "dword*", 0)

    [/autoit] [autoit][/autoit] [autoit]

    If @error Or $a_Call[0] Then
    Return SetError(1, 0, "") ; error decompressing
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    Local $tOutput = DllStructCreate("byte[" & $a_Call[6] & "]", DllStructGetPtr($tBuffer))

    [/autoit] [autoit][/autoit] [autoit]

    Return SetError(0, 0, DllStructGetData($tOutput, 1))

    [/autoit] [autoit][/autoit] [autoit]

    EndFunc ;==>_LZNTDecompress

    [/autoit] [autoit][/autoit] [autoit][/autoit]

    Das Ergebnis:

    überrascht mich nicht da ja Andy (bisher noch ) nicht in die Assembler Trickkiste gegriffen hat.

    mfg autoBert

  • autoBert,
    die Funktionen zur Kompression habe ich schon in DeskStream verwendet, da habe ich nicht nur Lauflängenkomprimierung, sondern nebenbei auch noch bissl Pixelkomprimierung in Assembler reingepfriemelt....Erklärung

    Die Geschichte mit dem "überflüssigen" Bit habe ich ja auch im vorliegenden Script verwendet....und gerade gesehen, dass da auch noch einiges zu kürzen ist^^

  • Nächtliches Update und Bugfixes im Post 4

    - Lauflängenkodierung mehrerer Ziffern bzw Buchstaben
    - wenn genau 2 gleiche Ziffern von 0-7 hintereinander vorliegen, werden diese in ein Byte gepackt:
    Bit 7=Kennung, dass doppelte Ziffer
    Bit 6-4 = Ziffer
    Bit 3 = nicht benutzt
    Bit 2-0 = Ziffer
    so wird aus "33" das byte 10110011
    sehr cool dabei:
    Lässt man das Bit 7 weg und schaut sich die restlichen Bits an, dann stellt man fest, dass der "Wert" aller bits immer 17fach höher ist, als eine der "Ziffern"
    Ziffern "1"=>Bytewert 17
    Ziffern "2"=>Bytewert 34
    Ziffern "3"=>Bytewert 51 usw^^
    Man kann beim komprimieren aus der Ziffer sehr schnell den Bytewert ausrechnen und beim dekomrimieren natürlich aus dem Bytewert sehr schnell die Ziffer ausrechnen 8o
    -

  • Nächtlicher Spätpost: (ich wollte das noch loswerden :D )

    Ich hab mal ein bisschen rumprobiert und versucht, die bestehende Funktion zu beschleunigen.
    Das Erste, was ich bemerkt habe: StringRegExpReplace() ist ca. 6x schneller als StringReplace()

    Das bringt schonmal was. Allerdings geht es auch ohne Replace, der jedes mal den ganzen String durchwühlt.
    Man fügt den String einfach nach und nach zusammen: (hat echt eine Weile gedauert, bis ich auf den Gedanken gekommen bin :pinch: )

    [autoit]

    Func Decompress($sString)
    Local $sRet = "", $aTemp = StringRegExp($sString, "(.*?)\[(.:\d*)\]", 3)
    For $i = 0 To Int((UBound($aTemp) - 1) / 2)
    $sRet &= $aTemp[$i*2] & _(StringLeft($aTemp[$i*2+1], 1), StringTrimLeft($aTemp[$i*2+1], 2))
    Next
    If Not (StringRight($sString, 1) = "]") Then Return $sRet & StringRegExpReplace($sString, ".*\]", "") ; Kann man auch durch eine Schleife ersetzen, die das ohne den Replace macht, kostet aber viele Bytes und auf das bisschen an Geschwindigkeit kommts dann auch nicht drauf an
    Return $sRet
    EndFunc

    [/autoit]


    Das macht dann bei mir ungefähr die zwölffache Geschwindigkeit.
    Ist zwar noch lange nicht akzeptabel, aber ich glaube nicht, dass man mit der bestehenden Methode noch viel mehr rausholen kann.

    Ich hoffe, es hilft trotzdem irgendwie ;)

    MfG black_skorpi

  • Moin. Genau für dieses Problem hatte ich schonmal ein Skript geschrieben.
    Die Auspackgeschwindigkeit ist dabei extrem flott. (wenige ms im Regelfall). Das Einpacken dauert aber ziemlich lange (es wird viel vergleichen um die zu ersetzenden Strings zu finden).

    Dabei habe ich gemerkt, dass Andys methode seltsame Zeichen einstreut die meine Methode beim 2ten Durchgang ziemlich den Wind aus den Segeln nimmt. Sämtliche seltenen Zeichen behindern das Ersetzungsprinzip und müssen gesondert gespeichtert werden damit die Dekompression klappt.

    Zusammen kommts bei mir beim TestString auf 29%
    Meine Methode alleine packt 30%
    Ich bin mir sicher, dass eine Modifikation von Andys Methode das Resultat unter 25% bringen kann.

    Bei mir lässt sich glaube ich nicht mehr viel rausholen ohne extremen Rechenaufwand. (Durchprobiert werden nur 2er Paare. Man kann das auch auf 3, 4, n ausweiten. Dann muss man aber die Permutationen berücksichtigen was den Rechenaufwand ins unermessliche steigen lässt. Das habe ich auch schonmal getestet. Bringt im Schnitt ca. 10% (also 27 statt 30 bei hundertfachem Aufwand^^))

    Spoiler anzeigen
    [autoit]


    _Test()

    [/autoit] [autoit][/autoit] [autoit]

    Func _Test()
    Local Static $sTest = "67B666666B76000000000000000000056B66666666B650000000000000000056B666666666676500000000000000006676666666666766000000000000000566666666666666665000000000000006666666666666666660000000000000566666666666666666650000000000005666666666666667666500000000000056677676767676767665000000000000566B777777777777B665000000000000566B7B777777777BB665000000000000066BBB7B7B7BB7BBD650000000000000056BDBBBBBBBBBBD76500000000000000056BDDDBDBDBDDD660000000000000000366BEDDDDDDEB655000000000000000005567BDEEDB76550000000000000000000055666666550000000000000000000000005555550000000000000FFFFFFFFFFFE7FFFFFF81FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFE007FFFFE007FFFFE007FFFFC003FFFFC003FFFFC003FFFFC003FFFF8001FFFF0000FFFF0000FFFE00007FFE00007FFC00003FFC00003FFC00003FFC00003FFC00003FFE00007FFE00007FFF0000FFFF0000FFFF8001FFFFE007FFFFF81FFF00000000F26A0451000000000000010000000000800300009053040030010000B0040000000000002800000020000000400000000100010000000000000100000000000000000000000000000000000000000000FFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC1FFFFFC3C7FFFC3FC1FF83FFC07FBFFFC1FFBFFFC7FFBFFFDFFFBFFFDFFFBFFFDFFFBFFFDFFFBFFFDFFFBFFFDFFFBFFFDFFFBFFFDFFFBFFC1FFFBFC3DFFFBC3C1FFF83C3FFFFBC3FFFFF83FFFFFFBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC1FFFFFC007FFFC0001FF8000007F800001FF800007FF80001FFF80001FFF80001FFF80001FFF80001FFF80001FFF80001FFF80001FFF80001FFF80001FFF80001FFF8003FFFF803FFFFF83FFFFFFBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000F26A0451000000000000010000000000D8040000E8540400E8020000B0040000000000002800000020000000400000000100040000000000800200000000000000000000000000000000000000000000"
    Local $sComp, $iTimer, $sDecomp

    [/autoit] [autoit][/autoit] [autoit]

    ConsoleWrite('Kombination beider Methoden (Andys als Vorstufe):' & @CRLF)
    $iTimer = TimerInit()
    $sComp = _Comp($sTest)
    $iTimer = TimerDiff($iTimer)
    ConsoleWrite('!> Comp Beide: ' & Round(StringLen($sComp)/StringLen($sTest)*100,0) & '%' & @CRLF)
    ConsoleWrite('> CompTime: ' & Round($iTimer) & ' ms' & @CRLF)

    [/autoit] [autoit][/autoit] [autoit]

    $iTimer = TimerInit()
    $sDecomp = _Decomp($sComp)
    $iTimer = TimerDiff($iTimer)
    ConsoleWrite('> DecompTime: ' & Round($iTimer) & ' ms' & @CRLF)

    [/autoit] [autoit][/autoit] [autoit]

    If Not ($sDecomp == $sTest) Then
    ConsoleWrite('! Error' & @CRLF)
    ConsoleWrite($sDecomp & @CRLF)
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    ConsoleWrite(@CRLF & 'Methode von Mars ohne Vorstufe:' & @CRLF)
    $iTimer = TimerInit()
    $sComp = _Ersetzung_Comp($sTest)
    $iTimer = TimerDiff($iTimer)
    ConsoleWrite('!> Comp Mars: ' & Round(StringLen($sComp)/StringLen($sTest)*100,0) & '%' & @CRLF)
    ConsoleWrite('> CompTime: ' & Round($iTimer) & ' ms' & @CRLF)

    [/autoit] [autoit][/autoit] [autoit]

    $iTimer = TimerInit()
    $sDecomp = _Ersetzung_DeComp($sComp)
    $iTimer = TimerDiff($iTimer)
    ConsoleWrite('> DecompTime: ' & Round($iTimer) & ' ms' & @CRLF)

    [/autoit] [autoit][/autoit] [autoit]

    If Not ($sDecomp == $sTest) Then
    ConsoleWrite('! Error' & @CRLF)
    ConsoleWrite($sDecomp & @CRLF)
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    ConsoleWrite(@CRLF)

    [/autoit] [autoit][/autoit] [autoit]

    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _Comp($sInput)
    Local $s = StringReplace(_CompAndy($sInput), Chr(0), '[NULL]', 0, 1), $l = StringLen($s)
    ;ConsoleWrite($s & @CRLF)
    $s = _Ersetzung_Comp($s)
    ConsoleWrite('!> Comp Mars: ' & Round(StringLen($s)/$l*100,0) & '%' & @CRLF)
    Return $s
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _Decomp($sInput)
    Local $s = StringReplace(_Ersetzung_DeComp($sInput), '[NULL]', Chr(0), 0, 1)
    $s = _DecompAndy($s)

    [/autoit] [autoit][/autoit] [autoit]

    Return $s
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _CompAndy($string)
    $len = StringLen($string)
    $ret = ""
    $p = 0
    For $i = 1 To $len ;kompletten string durchlaufen
    $aktuell = StringMid($string, $i, 1) ;aktuelles token
    $anz = 1 ;anzahl gleicher token
    For $a = $i + 1 To $i + 54 ;kommt es mehrfach vor?
    If StringMid($string, $a, 1) = $aktuell And $a <= $len Then ;kommt mehrfach vor
    $anz += 1
    Else
    $i = $a - 1 ;nicht mehrfach
    ExitLoop ;nächstes token
    EndIf
    Next

    [/autoit] [autoit][/autoit] [autoit]

    If $anz > 2 Then ;mehr als 2 gleiche token gefunden
    $ret &= $aktuell & Chr(70 + $anz) ;anzahl hinter token hängen
    $i = $a - 1
    ElseIf $anz = 2 Then
    If Asc($aktuell) < 56 Then ;bit 0-3 und 5-7 nehmen eine doppelte zahl auf
    $ret &= Chr((Asc($aktuell) - 48) * 17 + 127)
    Else
    $ret &= $aktuell & $aktuell
    EndIf
    Else
    $ret &= $aktuell ;nur einmal vorkommenden buchstaben anhängen
    EndIf
    Next
    $Perc = Round(StringLen($ret) / $len * 100)
    ConsoleWrite("!> Comp Andy: " & $Perc & "%" & @CRLF)

    [/autoit] [autoit][/autoit] [autoit]

    Return $ret
    EndFunc ;==>compbin

    [/autoit] [autoit][/autoit] [autoit]

    Func _DecompAndy($string)
    $ret = ""
    $len = StringLen($string)
    For $i = 1 To $len
    $decomp = StringMid($string, $i, 1);aktueller buchstabe ;
    $token = Asc($decomp) ;aktuelles token
    If $token >= 127 Then ;doppelte 0-7?
    $decomp = Chr((($token - 127) / 17) + 48);magic numbers FTW^^
    $decomp &= $decomp
    ElseIf $token > 70 Then ;komprimiertes Zeichen?
    $token -= 70 ;länge
    $akt = StringMid($string, $i - 1, 1) ;aktueller zu vervielfältigende buchstabe
    $decomp = ""
    For $a = 1 To $token - 1
    $decomp &= $akt
    Next
    Else
    $decomp = StringMid($string, $i, 1) ;einfache Ziffer/Buchstabe
    EndIf
    $ret &= $decomp

    [/autoit] [autoit][/autoit] [autoit]

    Next
    Return $ret

    [/autoit] [autoit][/autoit] [autoit]

    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _ZeichenArray($sDoNotUse = '')
    Local $sZ = '!"#%&,-/:;=@0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_`abcdefghijklmnopqrstuvwxyz~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ', $UBound = StringLen($sZ), $b[$UBound]
    For $i = 1 To StringLen($sDoNotUse) Step 1
    $sZ = StringReplace($sZ, StringMid($sDoNotUse, $i, 1), '', 0, 1)
    Next
    For $i = 0 To $UBound - 1 Step 1
    $b[$i] = StringLeft($sZ, 1)
    $sZ = StringTrimLeft($sZ, 1)
    Next
    Return $b
    EndFunc ;==>_ZeichenArray

    [/autoit] [autoit][/autoit] [autoit]

    Func _Ersetzung_DeComp($a)
    Local $aTmp = StringSplit($a, ' '), $sDoNotUse = $aTmp[$aTmp[0]]
    $a = StringTrimRight($a, StringLen($sDoNotUse) + 1)
    Local $n = Int('0x' & StringRight($a, 2)), $_____ZeichenReverse = _ZeichenArray($sDoNotUse), $st = ''
    $a = StringTrimRight($a, 2)
    _ArrayReverse2($_____ZeichenReverse, 0, $n - 1)
    For $i = 0 To $n - 1 Step 1
    $st = StringRight($a, 2)
    $a = StringTrimRight($a, 2)
    $a = StringReplace($a, $_____ZeichenReverse[$i], $st, 0, 1)
    Next
    Return $a
    EndFunc ;==>_Ersetzung_DeComp

    [/autoit] [autoit][/autoit] [autoit]

    Func _Ersetzung_Comp($a)
    Local $sTmp = $a, $sDoNotUse
    While $sTmp
    ;ConsoleWrite(StringLeft($sTmp, 1) & @CRLF)
    $sDoNotUse &= StringLeft($sTmp, 1)
    $sTmp = StringReplace($sTmp, StringLeft($sTmp, 1), '', 0, 1)
    WEnd
    ConsoleWrite('!--- DoNotUse Zeichen: ' & $sDoNotUse & @CRLF)
    Local $l_alt = StringLen($a), $l_neu = 0, $st, $er, $n = 0, $_____Zeichen = _ZeichenArray($sDoNotUse), $_____Zeichenmenge = UBound($_____Zeichen)
    While 1
    $st = _Analyse($a) ; $st = Meist vorkommender String
    $a = StringReplace($a, $st, $_____Zeichen[$n], 0, 1)
    $a &= $st ; Und rechts an $a angehängt. $a = Urspringsstring
    $l_neu = StringLen($a) ; Neue Stringlänge
    $n += 1 ; Durchläufe
    If ($n = $_____Zeichenmenge Or $l_neu >= $l_alt) Then ;Nur Abbrechen, wenn tatsächlich nix geht. (nicht wenn der 8er nicht klappt...)
    ExitLoop
    EndIf
    $l_alt = $l_neu
    WEnd
    Return $a & Hex($n, 2) & ' ' & $sDoNotUse ; Rückgabe ist der Komprimierte String und die Anzahl ersetzungen
    EndFunc ;==>_Ersetzung_Comp

    [/autoit] [autoit][/autoit] [autoit]

    Func _Analyse($sData, $l = 2)
    Local $StringLaenge = StringLen($sData), $Top[2], $StringPart, $Replacements, $BenutzteStrings[256][256]
    For $i = 0 To $StringLaenge - ($l - 1) Step 1
    $StringPart = StringMid($sData, $i, $l)
    If Not $BenutzteStrings[Asc(StringLeft($StringPart, 1))][Asc(StringRight($StringPart, 1))]Then ; Damit keine Strings doppelt getestet werden...
    $BenutzteStrings[Asc(StringLeft($StringPart, 1))][Asc(StringRight($StringPart, 1))] = True
    StringReplace($sData, $StringPart, $StringPart, 0, 1)
    $Replacements = @extended
    If $Replacements >= $Top[0] Then
    $Top[0] = $Replacements
    $Top[1] = $StringPart
    EndIf
    EndIf
    Next
    Return $Top[1]
    EndFunc ;==>_Analyse

    [/autoit] [autoit][/autoit] [autoit]

    Func _ArrayReverse2(ByRef $avArray, $iStart = 0, $iEnd = 0)
    Local $vTmp, $iUBound = UBound($avArray) - 1
    For $i = $iStart To Int(($iStart + $iEnd - 1) / 2)
    $vTmp = $avArray[$i]
    $avArray[$i] = $avArray[$iEnd]
    $avArray[$iEnd] = $vTmp
    $iEnd -= 1
    Next
    EndFunc ;==>_ArrayReverse

    [/autoit]
  • Hi,
    die Frage bei Kompressionen im Allgemeinen lautet doch, schnell oder hoch?
    Das eine schließt das andere aus....
    Ich benutze zum Testen meiner Kompressionsrate die AutoIt.exe, die mit den aktuellen Scripten auf 83% eingestampft wird.
    Folgende Tabelle gibt die Anzahl der vorkommenden identischen aufeinanderfolgenden Bytes wieder.

    Spoiler anzeigen

    Mit der "billigen" und schnellen Lauflängenkodierung sieht man deutlich, dass man niemals unter 80% kommen kann!

    Zitat

    Dabei habe ich gemerkt, dass Andys methode seltsame Zeichen einstreut

    Das ist im Prinzip schon totaler Mumpitz meinerseits^^. Bytewerte von 0-FF in 2 Byte zu "entpacken", damit man eine "Hex-Darstellung" bekommt, und dann nachher diese Hex-Darstellung zu "komprimieren" auf 80% (50% wenn es Bytes wären...omfg) ist ehrlich gesagt hochgradig geistiger D***schi***. Das macht nur dann Sinn, wenn man die 7 Bit-Codes verwenden MUSS, und dann auch auch entsprechend das Ergebnis einschränkt...

  • letzte Variante, AutoIt.exe auf 83% komprimiert ausschliesslich in ASCII-codes von 42="0" bis 122="z"

    Spoiler anzeigen
    [autoit]

    $stest = StringTrimLeft(StringToBinary(FileRead(@AutoItExe)), 2) ;0x entfernen

    [/autoit] [autoit][/autoit] [autoit]

    $len = StringLen($stest)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $len = ' & $len & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    $t = TimerInit()
    $a = compbin($stest)
    ;ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $a = ' & $a & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
    ;ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $a = ' & $a & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console
    $m = TimerDiff($t)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $m = ' & $m & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
    $alen = StringLen($a)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $alen = ' & $alen & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
    $rate = Int($len / $m)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $rate = ' & $rate & " KB/s" & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    $t = TimerInit()
    $b = decompbin($a)
    ;ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $b = ' & $b & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console

    [/autoit] [autoit][/autoit] [autoit]

    $m = TimerDiff($t)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $m = ' & $m & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : len2 = ' & StringLen($b) & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
    $rate = Int($alen / $m)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $rate = ' & $rate & " KB/s" & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Exit

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func compbin($string)
    $len=stringlen($string)
    For $p = 0 To 15
    $token = Hex($p, 1) ;0-F
    $l = ""
    For $m = 1 To 26
    $l &= $token
    Next

    [/autoit] [autoit][/autoit] [autoit]

    For $i = 26 To 3 Step -1 ;anzahl vorkommen
    $l = StringLeft($l, $i) ;
    $string = StringReplace($string, $l, $token & Chr(95 + $i), 0, 1)
    Next
    $string = StringReplace($string, $token & $token,Chr(Dec($token) + 71), 0, 1)

    [/autoit] [autoit][/autoit] [autoit]

    Next

    [/autoit] [autoit][/autoit] [autoit]

    $Perc = Round(StringLen($string) / $len * 100)
    ConsoleWrite("!> Compression: " & $Perc & "%" & @CRLF)

    [/autoit] [autoit][/autoit] [autoit]

    Return $string
    EndFunc ;==>compbin

    [/autoit] [autoit][/autoit] [autoit]

    Func decompbin($string)

    [/autoit] [autoit][/autoit] [autoit]

    For $i = 71 To 86
    $a = Hex($i - 71, 1)
    $string = StringReplace($string, Chr($i), $a & $a, 0, 1)
    Next
    For $i = 97 To 122 ;x-fache token
    $a = Chr($i)
    $pos = 1
    Do
    $pos = StringInStr($string, $a, 1, 1, $pos + 1)
    If $pos <> 0 Then
    $char = StringMid($string, $pos - 1, 1)
    $ersetzen = ""
    For $q = 1 To $i - 95
    $ersetzen &= $char
    Next
    $string = StringReplace($string, $char & $a, $ersetzen, 0, 1)
    EndIf
    Until $pos = 0
    Next
    Return $string

    [/autoit] [autoit][/autoit] [autoit]

    EndFunc ;==>decompbin

    [/autoit]

    Mars, sollte nun auch mit deiner Variante vesser funktionieren
    Btw, die Kompression von AutoIt.EXE mit deiner Variante habe ich nach 1h Laufzeit abgebrochen....

    Zitat

    Auf das Packen kann man ewig warten, das stört keinen

    ;)

    //EDIT falsches Script gepostet, entpackt jetzt mit >400Kb/s

    ciao
    Andy


    "Schlechtes Benehmen halten die Leute doch nur deswegen für eine Art Vorrecht, weil keiner ihnen aufs Maul haut." Klaus Kinski
    "Hint: Write comments after each line. So you can (better) see what your program does and what it not does. And we can see what you're thinking what your program does and we can point to the missunderstandings." A-Jay

    Wie man Fragen richtig stellt... Tutorial: Wie man Script-Fehler findet und beseitigt...X-Y-Problem

    Einmal editiert, zuletzt von Andy (11. Februar 2013 um 13:48)

  • Man kann auch die Funktionen aus der ntdll.dll benutzen, um String zu komprimieren/entpacken.

    Beispiel:

    Spoiler anzeigen
    [autoit]


    $sTest = '67B[6:6]B76[0:19]56B[6:8]B65[0:17]56B[6:10]765[0:16]667[6:10]766[0:15]5[6:16]5[0:14][6:18][0:13]5[6:18]5[0:12]5[6:14]76665[0:12]56677676767676767665[0:12]566B[7:12]B665[0:12]566B7B[7:9]BB665[0:13]66BBB7B7B7BB7BBD65[0:14]56BD[B:10]D765[0:15]56BDDDBDBDBDDD66[0:16]366BE[D:6]EB655[0:17]5567BDEEDB7655[0:20]55[6:6]55[0:24][5:6][0:13][F:11]E7[F:6]81[F:6]00[F:6]00[F:6]00[F:6]00[F:6]00[F:5]E007FFFFE007FFFFE007FFFFC003FFFFC003FFFFC003FFFFC003FFFF8001FFFF0000FFFF0000FFFE00007FFE00007FFC00003FFC00003FFC00003FFC00003FFC00003FFE00007FFE00007FFF0000FFFF0000FFFF8001FFFFE007[F:5]81FFF[0:8]F26A0451[0:13]1[0:10]800300009053040030010000B004[0:12]28[0:6]2[0:7]4[0:8]10001[0:13]1[0:44][F:6]00[F:44]C1[F:5]C3C7FFFC3FC1FF83FFC07FBFFFC1FFBFFFC7FFBFFFDFFFBFFFDFFFBFFFDFFFBFFFDFFFBFFFDFFFBFFFDFFFBFFFDFFFBFFFDFFFBFFC1FFFBFC3DFFFBC3C1FFF83C3FFFFBC3[F:5]83[F:6]B[F:98]C1[F:5]C007FFFC0001FF8[0:5]7F800001FF800007FF80001FFF80001FFF80001FFF80001FFF80001FFF80001FFF80001FFF80001FFF80001FFF80001FFF80001FFF8003FFFF803[F:5]83[F:6]B[F:54][0:8]F26A0451[0:13]1[0:10]D8040000E8540400E8020000B004[0:12]28[0:6]2[0:7]4[0:8]10004[0:10]8002[0:44]'
    $bCompressed = Compress(Binary($sTest))
    ConsoleWrite("Binary Length: " & BinaryLen(Binary($sTest)) & " bytes" & @LF)
    ConsoleWrite("Binary Length Compressed: " & BinaryLen($bCompressed) & " bytes" & @LF)
    ConsoleWrite("Effiency: " & StringFormat("%.2f%s", 100 * BinaryLen($bCompressed) / BinaryLen(Binary($sTest)), "% from original size") & @LF & @LF & @LF)
    ConsoleWrite("Decompressed String: " & DeCompress($bCompressed) & @LF)
    Exit

    [/autoit] [autoit][/autoit] [autoit]

    Func DeCompress($binString)
    Local $tSource = DllStructCreate('byte[' & BinaryLen($binString) & ']')
    DllStructSetData($tSource, 1, $binString)
    Local $tDecompress
    _WinAPI_LZNTDecompress($tSource, $tDecompress)
    $tSource = 0
    Return BinaryToString(Binary(DllStructGetData($tDecompress, 1)))
    EndFunc ;==>DeCompress

    [/autoit] [autoit][/autoit] [autoit]

    Func Compress($binString)
    Local $tCompressed
    Local $tSource = DllStructCreate('byte[' & BinaryLen($binString) & ']')
    DllStructSetData($tSource, 1, $binString)
    _WinAPI_LZNTCompress($tSource, $tCompressed, True)
    Local $binCompressed = DllStructGetData($tCompressed, 1)
    $tSource = 0
    Return Binary($binCompressed)
    EndFunc ;==>Compress

    [/autoit] [autoit][/autoit] [autoit]

    Func _WinAPI_LZNTDecompress(ByRef $tInput, ByRef $tOutput, $iBufferSize = 0x800000)
    Local $tBuffer, $Ret
    $tOutput = 0
    $tBuffer = DllStructCreate('byte[' & $iBufferSize & ']')
    If @error Then Return SetError(1, 0, 0)
    $Ret = DllCall('ntdll.dll', 'uint', 'RtlDecompressBuffer', 'ushort', 0x0002, 'ptr', DllStructGetPtr($tBuffer), 'ulong', $iBufferSize, 'ptr', DllStructGetPtr($tInput), 'ulong', DllStructGetSize($tInput), 'ulong*', 0)
    If @error Then Return SetError(2, 0, 0)
    If $Ret[0] Then Return SetError(3, $Ret[0], 0)
    $tOutput = DllStructCreate('byte[' & $Ret[6] & ']')
    If Not _WinAPI_MoveMemory(DllStructGetPtr($tOutput), DllStructGetPtr($tBuffer), $Ret[6]) Then
    $tOutput = 0
    Return SetError(4, 0, 0)
    EndIf
    Return $Ret[6]
    EndFunc ;==>_WinAPI_LZNTDecompress

    [/autoit] [autoit][/autoit] [autoit]

    ; #FUNCTION# ====================================================================================================================
    ; Name...........: _WinAPI_LZNTCompress
    ; Description....: Compresses an input data.
    ; Syntax.........: _WinAPI_LZNTCompress ( $tInput, ByRef $tOutput [, $fMaximum] )
    ; Parameters.....: $tInput - "byte[n]" or any other structure that contains the data to be compressed.
    ; $tOutput - "byte[n]" structure that is created by this function, and contain the compressed data.
    ; $fMaximum - Specifies whether use a maximum data compression, valid values:
    ; |TRUE - Uses an algorithm which provides maximum data compression but with relatively slower performance.
    ; |FALSE - Uses an algorithm which provides a balance between data compression and performance. (Default)
    ; Return values..: Success - The size of the compressed data, in bytes.
    ; Failure - 0 and sets the @error flag to non-zero, @extended flag may contain the NTSTATUS code.
    ; Author.........: trancexx
    ; Modified.......: Yashied, UEZ
    ; Remarks........: The input and output buffers must be different, otherwise, the function fails.
    ; Related........:
    ; Link...........: @@MsdnLink@@ RtlCompressBuffer
    ; Example........: Yes
    ; ===============================================================================================================================
    Func _WinAPI_LZNTCompress(ByRef $tInput, ByRef $tOutput, $fMaximum = True)
    Local $tBuffer, $tWorkSpace, $Ret
    Local $COMPRESSION_FORMAT_LZNT1 = 0x0002, $COMPRESSION_ENGINE_MAXIMUM = 0x0100
    If $fMaximum Then $COMPRESSION_FORMAT_LZNT1 = BitOR($COMPRESSION_FORMAT_LZNT1, $COMPRESSION_ENGINE_MAXIMUM)
    $tOutput = 0
    $Ret = DllCall('ntdll.dll', 'uint', 'RtlGetCompressionWorkSpaceSize', 'ushort', $COMPRESSION_FORMAT_LZNT1, 'ulong*', 0, 'ulong*', 0)
    If @error Then Return SetError(1, 0, 0)
    If $Ret[0] Then Return SetError(2, $Ret[0], 0)
    $tWorkSpace = DllStructCreate('byte[' & $Ret[2] & ']')
    $tBuffer = DllStructCreate('byte[' & (2 * DllStructGetSize($tInput)) & ']')
    $Ret = DllCall('ntdll.dll', 'uint', 'RtlCompressBuffer', 'ushort', $COMPRESSION_FORMAT_LZNT1, 'ptr', DllStructGetPtr($tInput), 'ulong', DllStructGetSize($tInput), 'ptr', DllStructGetPtr($tBuffer), 'ulong', DllStructGetSize($tBuffer), 'ulong', 4096, 'ulong*', 0, 'ptr', DllStructGetPtr($tWorkSpace))
    If @error Then Return SetError(3, 0, 0)
    If $Ret[0] Then Return SetError(4, $Ret[0], 0)
    $tOutput = DllStructCreate('byte[' & $Ret[7] & ']')
    If Not _WinAPI_MoveMemory(DllStructGetPtr($tOutput), DllStructGetPtr($tBuffer), $Ret[7]) Then
    $tOutput = 0
    Return SetError(5, 0, 0)
    EndIf
    Return $Ret[7]
    EndFunc ;==>_WinAPI_LZNTCompress

    [/autoit] [autoit][/autoit] [autoit]

    Func _WinAPI_MoveMemory($pDestination, $pSource, $iLenght)
    DllCall('ntdll.dll', 'none', 'RtlMoveMemory', 'ptr', $pDestination, 'ptr', $pSource, 'ulong_ptr', $iLenght)
    If @error Then Return SetError(1, 0, 0)
    Return 1
    EndFunc ;==>_WinAPI_MoveMemory

    [/autoit]

    Mit $fMaximum kann man den Grad der Komprimierung wählen -> True = max, False = normal.

    Für große Dateien ist Komprimierung relativ langsam, wenn man max. auswählt.

    Gruß,
    UEZ

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯

  • Meine Methode hat ein Problem mit Chr(0). Wenn dieses Zeichen im zu komprimierenden String vorkommt gibts Probleme.
    Für so große Dateien muss man die Funktion gesplittet anwenden. Dafür kann ich auch noch ein Skript basteln. Ich lass die autoit.exe bei mir einfach mal durchnudeln wenn ich daheim bin.

  • chr(0) sollte ja nicht vorkommen, es geht ja um die Kompression von Strings, die aus 0-F bestehen.

    Hatte im vorigen Post ein falsches Script gepostet, ist jetzt korrigiert.

  • Hi,

    mit einigen Zeilen mehr Code lässt sich das Ergebnis weiterhin verbessern, ohne großartig Performance zu verbraten!

    Die AutoIt.exe (1.5MB) wird auf 56% zusammengestampft, mit ca. 180Kb/s, also in ca. 8 Sekunden. Im komprimierten String werden nur Ascii-codes über 32 verwendet, d.h. keine Steuerzeichen.

    Das Entpacken geschieht ca. 2.5x schneller, also mit ca 430Kb/s, dauert auf meinem Rechner ca. 3 Sekunden.

    Nicht im anhängenden Script enthalten, habe ich noch weitere (einfachste) Verfahren angewendet, also simples Ersetzen von mehrfach vorkommenden 2-Byte-Strings durch 1 Byte.
    Allerdings steigt die Packzeit extrem an, welch ein Wunder^^
    Um die AutoIt.exe auf <50% zusammenzustampfen (damit bin ich gleichauf mit LZNT in der höchsten Stufe) braucht es schon über 10 min.
    Mit einem erfahrungsgemäß angenommenen Faktor 1000, den ein Assemblerscript schneller wäre, könnte man locker in den Bereich von LZNT kommen. Dann müsste man aber auch die Ascii-codes kleiner 32 benutzen, um das letzte bisschen Kompression rauszuholen^^


    Spoiler anzeigen
    [autoit]

    #include <array.au3>

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    $stest = StringTrimLeft(StringToBinary(FileRead(@AutoItExe)), 2) ;0x entfernen
    ;$stest = StringTrimLeft(StringToBinary(FileRead(@ScriptFullPath)), 2) ;0x entfernen

    [/autoit] [autoit][/autoit] [autoit]

    $len = StringLen($stest)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $len = ' & $len & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    $t = TimerInit()
    $a = compbin($stest)
    $m = TimerDiff($t)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $m = ' & $m & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
    $alen = StringLen($a)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $alen = ' & $alen & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
    $rate = Int($len / $m)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $rate = ' & $rate & " KB/s" & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
    ConsoleWrite(@CRLF)

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    $t = TimerInit()
    $b = decompbin($a)
    ;ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $b = ' & $b & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
    $m = TimerDiff($t)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $m = ' & $m & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
    $blen = StringLen($b)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $blen = ' & $blen & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
    $rate = Int($blen / $m)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $rate = ' & $rate & " KB/s" & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Exit

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func compbin($string)
    ;$len = StringLen($string)

    [/autoit] [autoit][/autoit] [autoit]

    For $p = 0 To 15
    $token = Hex($p, 1) ;0-F
    $l = ""
    For $m = 1 To 26
    $l &= $token
    Next

    [/autoit] [autoit][/autoit] [autoit]

    For $i = 26 To 3 Step -1 ;anzahl vorkommen
    $l = StringLeft($l, $i) ;
    $string = StringReplace($string, $l, $token & Chr(95 + $i), 0, 1)
    Next
    $string = StringReplace($string, $token & $token, Chr(Dec($token) + 71), 0, 1)

    [/autoit] [autoit][/autoit] [autoit]

    Next

    [/autoit] [autoit][/autoit] [autoit]

    Dim $array[16 * 16 + 1][2]
    For $d = 0 To 15
    For $b = 0 To 15
    $doublestring = Hex($d, 1) & Hex($b, 1) ;&hex($w,1)
    $dec = Dec($doublestring)
    StringReplace($string, $doublestring, $doublestring, 0, 1)
    $e = @extended
    $array[$dec][0] = $e
    $array[$dec][1] = $doublestring
    Next
    Next
    _ArraySort($array, 1) ;nach häufigkeit sortieren
    ;~ _ArrayDisplay($array)

    [/autoit] [autoit][/autoit] [autoit]

    $ersetzen_string = ""
    For $i = 0 To 120 ;ascii-zeichen hinter 130
    $s1 = $array[$i][1]
    If $array[$i][0] = 0 Then ExitLoop ;kein string zu ersetzen
    $s2 = Chr($i + 130)
    $ersetzen_string &= $s1 & $s2
    $string = StringReplace($string, $s1, $s2, 0, 1) ;2-byte durch 1-byte ersetzen
    Next
    $string = $ersetzen_string & $string

    [/autoit] [autoit][/autoit] [autoit]

    $Perc = Round(StringLen($string) / $len * 100)
    ConsoleWrite("!> Compression: " & $Perc & "%" & @CRLF)

    [/autoit] [autoit][/autoit] [autoit]

    Return $string
    EndFunc ;==>compbin

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func decompbin($string)

    [/autoit] [autoit][/autoit] [autoit]

    While 1
    $ersetzen = StringLeft($string, 3)
    If Asc(StringRight($ersetzen, 1)) < 130 Then ExitLoop
    $string = StringTrimLeft($string, 3)
    $string = StringReplace($string, StringRight($ersetzen, 1), StringLeft($ersetzen, 2), 0, 1) ;ein byte durch 2 byte ersetzen
    WEnd

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    For $i = 71 To 86
    $a = Hex($i - 71, 1)
    $string = StringReplace($string, Chr($i), $a & $a, 0, 1)
    Next
    For $i = 97 To 122 ;x-fache token
    $a = Chr($i)
    $pos = 1
    Do
    $pos = StringInStr($string, $a, 1, 1, $pos + 1)
    If $pos <> 0 Then
    $char = StringMid($string, $pos - 1, 1)
    $ersetzen = ""
    For $q = 1 To $i - 95
    $ersetzen &= $char
    Next
    $string = StringReplace($string, $char & $a, $ersetzen, 0, 1)
    EndIf
    Until $pos = 0
    Next
    Return $string

    [/autoit] [autoit][/autoit] [autoit]

    EndFunc ;==>decompbin

    [/autoit]
  • Geschwindigkeit beim komprimieren verdoppelt, bei nochmal reduzierter Kompressionsrate. Wie gehabt, reiner AutoIt-Code!

    Spoiler anzeigen
    [autoit]

    #include <array.au3>

    [/autoit] [autoit][/autoit] [autoit]

    $file = @AutoItExe
    $stest = StringTrimLeft(StringToBinary(FileRead($file)), 2) ;0x entfernen

    [/autoit] [autoit][/autoit] [autoit]

    $len = StringLen($stest)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $len = ' & $len & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    $t = TimerInit()
    $a = compbin($stest)
    $m = TimerDiff($t)
    $stest = ""
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $m = ' & $m & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
    $alen = StringLen($a)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $alen = ' & $alen & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
    $rate = Int($len / $m)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $rate = ' & $rate & " KB/s" & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
    ConsoleWrite(@CRLF)

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    $t = TimerInit()
    $b = decompbin($a)
    $m = TimerDiff($t)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $m = ' & $m & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
    $blen = StringLen($b)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $blen = ' & $blen & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
    $rate = Int($blen / $m)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $rate = ' & $rate & " KB/s" & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Exit

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func compbin(ByRef $string)
    $len = StringLen($string)

    [/autoit] [autoit][/autoit] [autoit]

    For $p = 0 To 15
    $token = Hex($p, 1) ;0-F
    $l = ""
    For $m = 1 To 7 ;0 bis 0000000, 1 bis 1111111 usw
    $l &= $token
    Next
    For $i = 7 To 3 Step -1 ;anzahl vorkommen
    $l = StringLeft($l, $i) ;
    $string = StringReplace($string, $l, $token & Chr(85 + $i), 0, 1);mehrfache ersetzen
    Next
    $string = StringReplace($string, $token & $token, Chr(Dec($token) + 71), 0, 1);doppelte ersetzen
    Next

    [/autoit] [autoit][/autoit] [autoit]

    Dim $array[16 * 16 + 1][2] ;anzahl der permutationen 00 bis FF
    For $d = 0 To 255
    $double = Hex($d, 2) ;00 bis FF
    StringReplace($string, $double, $double, 0, 1)
    $array[$d][0] = @extended ;anzahl vorkommen im string
    $array[$d][1] = $double ;ins array schreiben
    Next
    _ArraySort($array, 1) ;nach häufigkeit sortieren
    ; _ArrayDisplay($array)

    [/autoit] [autoit][/autoit] [autoit]

    $ersetzen_string = ""
    For $i = 0 To 160 ;ascii-zeichen von 105 -255
    $s1 = $array[$i][1] ;00 bis FF
    If $array[$i][0] = 0 Then ExitLoop ;kein string zu ersetzen
    $s2 = Chr($i + 95) ;doppelbyte wird ersetzt durch dieses byte
    $ersetzen_string &= $s1 & $s2 ;doppelbyte & byte
    $string = StringReplace($string, $s1, $s2, 0, 1) ;2-byte durch 1-byte ersetzen
    Next
    $string = $ersetzen_string & $string ; LUT vorne an string anhängen

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    $Perc = Round(StringLen($string) / $len * 100)
    ConsoleWrite("!> Compression: " & $Perc & "%" & @CRLF)

    [/autoit] [autoit][/autoit] [autoit]

    Return $string
    EndFunc ;==>compbin

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func decompbin($string)

    [/autoit] [autoit][/autoit] [autoit]

    While 1 ;1-byte durch 2-byte ersetzen
    $ersetzen = StringLeft($string, 3) ;erste 3 bytes im string
    If Asc(StringRight($ersetzen, 1)) < 95 Then ExitLoop;wenn 3.Zeichen kein ersetzen-byte, dann ende
    $string = StringTrimLeft($string, 3);erste 3 bytes abschneiden
    $string = StringReplace($string, StringRight($ersetzen, 1), StringLeft($ersetzen, 2), 0, 1) ;ein byte durch 2 byte ersetzen
    WEnd

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    For $i = 71 To 86 ;ersetzt G durch 00, H durch 11 usw
    $a = Hex($i - 71, 1)
    $string = StringReplace($string, Chr($i), $a & $a, 0, 1)
    Next
    For $i = 87 To 93 ;x-fache token
    $a = Chr($i) ;
    $pos = 1
    Do
    $pos = StringInStr($string, $a, 1, 1, $pos + 1)
    If $pos <> 0 Then
    $char = StringMid($string, $pos - 1, 1)
    $ersetzen = ""
    For $q = 1 To $i - 85
    $ersetzen &= $char
    Next
    $string = StringReplace($string, $char & $a, $ersetzen, 0, 1)
    EndIf
    Until $pos = 0
    Next
    Return $string

    [/autoit] [autoit][/autoit] [autoit]

    EndFunc ;==>decompbin

    [/autoit]

    Habe mal mit extrem grossen Exe-Files getestet (bis zum Speicherüberlauf), das ist besser zu profilen^^
    Knackpunkt ist folgende Schleife, die beim komprimieren die meiste Zeit braucht.
    Es werden im String alle 256 Permutationen von 0-F (also WORDs 00 bis FF) und die Anzahl der Vorkommen gesucht.

    [autoit]

    #include <Array.au3>
    $string = StringTrimLeft(StringToBinary(FileRead(@AutoItExe)), 2) ;0x entfernen
    Dim $array[16 * 16 + 1][2] ;anzahl der permutationen 00 bis FF
    For $d = 0 To 255
    $double = Hex($d, 2) ;00,01,02,03... bis FF
    StringReplace($string, $double, $double, 0, 1);anzahl vorkommen im string suchen
    $array[$d][0] = @extended ;anzahl vorkommen im string
    $array[$d][1] = $double ;ins array schreiben
    Next
    _ArraySort($array, 1) ;nach häufigkeit sortieren
    _ArrayDisplay($array)

    [/autoit]


    Anschliessend werden die am häufigsten im String vorkommenden WORDs durch ein BYTE ersetzt...

    Jetzt zur Frage:
    Der gleiche String wird 255 mal nach unterschiedlichen WORDs durchsucht, der Knackpunkt bei der Suche sind die permanenten Ladezyklen, da immer ein anderer Speicherblock geladen werden muss.
    Mal angenommen, ein RegEx würde (was ich nicht weiß) EINEN Block aus dem String (Speicher) laden und diesen dann nach den 255 Words durchsuchen, dann könnte die Performance sich signifikant verbessern!
    Leider reicht mein Regex-Skill nicht für diese Aufgabe^^, Regexen zur Füllung eines Arrays mit der Anzahl der jeweiligen Vorkommen von 00 bis FF sind willkommen!

    //EDIT
    Hab nun selbst mal geRegExed, immerhin habe ich schon die Gesamtanzahl der Treffer ermittelt:

    Spoiler anzeigen
    [autoit]

    #include <Array.au3>

    [/autoit] [autoit][/autoit] [autoit]

    $file = @AutoItExe
    $stest = StringTrimLeft(StringToBinary(FileRead($file)), 2) ;0x entfernen
    ;$text=stringleft($stest,10000)

    [/autoit] [autoit][/autoit] [autoit]

    ;$stest="AFabcde00000DExyzFBabcAFAF"
    $pattern = "([0-9A-F]{2})"

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    $t = TimerInit()
    $a = StringRegExp($stest, $pattern, 3)
    $m = TimerDiff($t)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $m = ' & $m & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console

    [/autoit] [autoit][/autoit] [autoit]

    $s = UBound($a)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $s = ' & $s & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console

    [/autoit] [autoit][/autoit] [autoit]

    ;_arraydisplay($a)

    [/autoit]

    Jetzt müsste ich nur noch herausfinden, wie man die Anzahl der Einzeltreffer, also für 00,01,02...bis...FE,FF ermittelt, hat jemand nen Tip für mich?

    ciao
    Andy


    "Schlechtes Benehmen halten die Leute doch nur deswegen für eine Art Vorrecht, weil keiner ihnen aufs Maul haut." Klaus Kinski
    "Hint: Write comments after each line. So you can (better) see what your program does and what it not does. And we can see what you're thinking what your program does and we can point to the missunderstandings." A-Jay

    Wie man Fragen richtig stellt... Tutorial: Wie man Script-Fehler findet und beseitigt...X-Y-Problem

    Einmal editiert, zuletzt von Andy (17. Februar 2013 um 20:01)

  • s. mein Problem voriger Post....RegEx

    In einem Bruchteil der Zeit, in der ich über das RegEx nachgedacht hatte, sind einfach einige Zeilen Assembler zustandegekommen, die das Problem völlig erschlagen :D
    Kompression bleibt, Geschwindigkeit auf >1Mb/s erhöht beim Packen

    Spoiler anzeigen
    [autoit]

    #include <array.au3>

    [/autoit] [autoit][/autoit] [autoit]

    ;~ #include <assembleit.au3>

    [/autoit] [autoit][/autoit] [autoit]

    ;~ Func _search()
    ;~ _("use32")
    ;~ _("mov esi,[esp+4]") ;pointer text
    ;~ _("mov edi,[esp+8]") ;pointer array
    ;~ _("mov ecx,[esp+12]") ;anzahl bytes im text
    ;~ _("")
    ;~ _("")
    ;~ _("start:")
    ;~ _("movsx eax,word[esi]") ;Bsp erstes word ist Ascii 4D -> EAX=0x00004434
    ;~ _("cmp al,70") ;byte grösser als F?
    ;~ _("ja weiter")
    ;~ _("cmp ah,70") ;byte grösser als F?
    ;~ _("ja weiter")
    ;~ _("sub eax,0x00003030") ;ascii nach binär umformen, aus AX=0x4434 muss AX=0x4D werden
    ;~ _("cmp ah,0x9") ;byte grösser als 9?
    ;~ _("jbe @f")
    ;~ _("sub ah,7") ;wenn byte >9 dann nochmal 7 abziehen, ascii A=0x41
    ;~ _("@@:")

    [/autoit] [autoit][/autoit] [autoit]

    ;~ _("cmp al,0x9") ;byte grösser als 9?
    ;~ _("jbe @f")
    ;~ _("sub al,7")
    ;~ _("@@:")
    ;~ _("xchg ah, al") ;ah+al tauschen -> AX=0x040D
    ;~ _("shl al,4") ;AL=0xD0
    ;~ _("shr ax,4") ;AX=0x004D
    ;~ _("add dword[edi+eax*4],1") ;zähler für dieses word um eins erhöhen
    ;~ _("weiter:")
    ;~ _("add esi,1") ;nächstes word holen
    ;~ _("loop start")
    ;~ _("")
    ;~ _("ret") ;bei DllCallAddress() MUSS hier ein RET 12 hin!!!!
    ;~ _("")
    ;~ EndFunc ;==>_search

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    $file = @AutoItExe
    $stest = StringTrimLeft(StringToBinary(FileRead($file)), 2) ;0x entfernen

    [/autoit] [autoit][/autoit] [autoit]

    $len = StringLen($stest)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $len = ' & $len & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    $t = TimerInit()
    $a = compbin($stest)
    $m = TimerDiff($t)
    $stest = ""
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $m = ' & $m & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
    $alen = StringLen($a)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $alen = ' & $alen & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
    $rate = Int($len / $m)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $rate = ' & $rate & " KB/s" & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
    ConsoleWrite(@CRLF)

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    $t = TimerInit()
    $b = decompbin($a)
    $m = TimerDiff($t)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $m = ' & $m & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
    $blen = StringLen($b)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $blen = ' & $blen & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
    $rate = Int($blen / $m)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $rate = ' & $rate & " KB/s" & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Exit

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func compbin(ByRef $string)
    $len = StringLen($string)
    For $p = 0 To 15
    $token = Hex($p, 1) ;0-F
    $l = ""
    For $m = 1 To 7 ;0 bis 0000000, 1 bis 1111111 usw
    $l &= $token
    Next
    For $i = 7 To 3 Step -1 ;anzahl vorkommen
    $l = StringLeft($l, $i) ;
    $string = StringReplace($string, $l, $token & Chr(85 + $i), 0, 1);mehrfache ersetzen
    Next
    $string = StringReplace($string, $token & $token, Chr(Dec($token) + 71), 0, 1);doppelte ersetzen
    Next

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    $t = TimerInit()
    $255struct = DllStructCreate("dword[" & 256 & "]")
    $textstruct = DllStructCreate("char[" & StringLen($string) & "]")
    DllStructSetData($textstruct, 1, $string) ;string in struct, ist 5-6x schneller als string in dllcalladdress-funktion zu übergeben

    [/autoit] [autoit][/autoit] [autoit]

    Global $tCodeBuffer = DllStructCreate("byte[64]") ;reserve Memory for opcodes
    DllStructSetData($tCodeBuffer, 1, "0x8B7424048B7C24088B4C240C0FBF063C46772580FC4677202D3030000080FC09760380EC073C0976022C0786E0C0E00466C1E8048304870183C601E2CFC20C00") ;write opcodes into memory

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ;~ $_assembleit_flag = 0
    ;~ _assembleit("ptr", "_search", "ptr", DllStructGetPtr($textstruct), "ptr", DllStructGetPtr($255struct), "uint", StringLen($string) - 1)

    [/autoit] [autoit][/autoit] [autoit]

    $ret = DllCallAddress("ptr", DllStructGetPtr($tCodeBuffer), "ptr", DllStructGetPtr($textstruct), "ptr", DllStructGetPtr($255struct), "uint", StringLen($string) - 1)

    [/autoit] [autoit][/autoit] [autoit]

    Dim $array[16 * 16 + 1][2] ;anzahl der permutationen 00 bis FF
    For $d = 0 To 255
    $double = Hex($d, 2) ;00 bis FF
    $array[$d][0] = DllStructGetData($255struct, 1, $d + 1) ;anzahl vorkommen im string
    $array[$d][1] = $double ;ins array schreiben
    Next

    [/autoit] [autoit][/autoit] [autoit]

    _ArraySort($array, 1) ;nach häufigkeit sortieren
    ; _ArrayDisplay($array)

    [/autoit] [autoit][/autoit] [autoit]

    $ersetzen_string = ""
    For $i = 0 To 160 ;ascii-zeichen von 105 -255
    $s1 = $array[$i][1] ;00 bis FF
    If $array[$i][0] = 0 Then ExitLoop ;kein string zu ersetzen
    $s2 = Chr($i + 95) ;doppelbyte wird ersetzt durch dieses byte
    $ersetzen_string &= $s1 & $s2 ;doppelbyte & byte
    $string = StringReplace($string, $s1, $s2, 0, 1) ;2-byte durch 1-byte ersetzen
    Next
    $string = $ersetzen_string & $string ; LUT vorne an string anhängen

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    $Perc = Round(StringLen($string) / $len * 100)
    ConsoleWrite("!> Compression: " & $Perc & "%" & @CRLF)

    [/autoit] [autoit][/autoit] [autoit]

    Return $string
    EndFunc ;==>compbin

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func decompbin($string)

    [/autoit] [autoit][/autoit] [autoit]

    While 1 ;1-byte durch 2-byte ersetzen
    $ersetzen = StringLeft($string, 3) ;erste 3 bytes im string
    If Asc(StringRight($ersetzen, 1)) < 95 Then ExitLoop;wenn 3.Zeichen kein ersetzen-byte, dann ende
    $string = StringTrimLeft($string, 3) ;erste 3 bytes abschneiden
    $string = StringReplace($string, StringRight($ersetzen, 1), StringLeft($ersetzen, 2), 0, 1) ;ein byte durch 2 byte ersetzen
    WEnd

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    For $i = 71 To 86 ;ersetzt G durch 00, H durch 11 usw
    $a = Hex($i - 71, 1)
    $string = StringReplace($string, Chr($i), $a & $a, 0, 1)
    Next
    For $i = 87 To 93 ;x-fache token
    $a = Chr($i) ;
    $pos = 1
    Do
    $pos = StringInStr($string, $a, 1, 1, $pos + 1)
    If $pos <> 0 Then
    $char = StringMid($string, $pos - 1, 1)
    $ersetzen = ""
    For $q = 1 To $i - 85
    $ersetzen &= $char
    Next
    $string = StringReplace($string, $char & $a, $ersetzen, 0, 1)
    EndIf
    Until $pos = 0
    Next
    Return $string

    [/autoit] [autoit][/autoit] [autoit]

    EndFunc ;==>decompbin

    [/autoit]


    Die AssembleIt()-Anwender werden feststellen, dass ich in diesem Beispiel den automatisch beim per $_assembleit_flag = 0 erstellten Code
    DllCall("user32.dll", "ptr", "CallWindowProcW",blablub
    durch
    DllCallAddress("ptr", DllStructGetPtr($tCodeBuffer),blablub
    ersetzt habe! Achtung! Dann ist es erforderlich, da DllCallAddress() den Stack nicht automatisch aufräumt, mit einem RET XX (Anzahl der Bytes der Parameter) den Stack "zu Fuss" aufzuräumen...
    Da ich aber auch nicht weiss, inwieweit DllCallAddress() in den älteren AutoItversionen funktioniert, ändere ich AssembleIt() nicht.
    Bei den Anwendern, bei denen DllCallAddress() nicht funktioniert, einfach die auskommentierten Zeilen aktivieren und nach F5 erscheint das Fenster mit dem C&P-Code.

    //Edit
    Es soll noch Leute geben, die mit einer Ascii-Code-Tabelle nichts anfangen können....
    In der AutoIt-Hilfe findet man sie im Anhang unter ASCII Zeichensatz, nicht schön aufgearbeitet bspw. hier.

    ciao
    Andy


    "Schlechtes Benehmen halten die Leute doch nur deswegen für eine Art Vorrecht, weil keiner ihnen aufs Maul haut." Klaus Kinski
    "Hint: Write comments after each line. So you can (better) see what your program does and what it not does. And we can see what you're thinking what your program does and we can point to the missunderstandings." A-Jay

    Wie man Fragen richtig stellt... Tutorial: Wie man Script-Fehler findet und beseitigt...X-Y-Problem

    Einmal editiert, zuletzt von Andy (20. Februar 2013 um 17:44)

  • Hi,

    Zitat

    dir sollte man den Dev-Titel verpassen.

    na die würden sich wundern :rofl:
    Dann müsste ich doch strukturiert programmieren, mich an alle möglichen und unmöglichen Vorgaben und Regeln halten, könnte nicht mehr einfach so drauflos tippern um schnell und simpel ein Problem zu lösen...
    Ne, lass mal stecken, in meiner wenigen Freizeit mach ich das, was mir Spass macht. ;)

    Vor den Dev´s habe ich allerhöchsten Respekt, und über Valik und seine liebreizende Art kann man sagen was man will, aber er hat sein Handwerk verstanden und mitgeholfen AutoIt zu dem zu machen, was es heute ist.
    Und wenn Profilneurotiker aufeinandertreffen, und jeder von beiden denkt er hat den höheren Skill, dann rappelt es eben. Ich finde es jedenfalls schade, dass er weg ist.