Что нового

Кодирование/Декодирование UUE и XXE

Andrey_A

Продвинутый
Сообщения
325
Репутация
68
Подскажите пожалуйста функции кодирования и декодирования формата UUE и XXE.

Есть функции кодирования base64:
Код:
Func _Encoding_Base64Decode($sData)
  $struct=DllStructCreate("int")
  $a_Call=DllCall("Crypt32.dll","int","CryptStringToBinary","str",$sData,"int",0,"int",1,"ptr",0,"ptr",DllStructGetPtr($struct,1),"ptr",0,"ptr",0)
  If @error Or Not $a_Call[0] Then Return SetError(1,0,"")
  $a=DllStructCreate("byte["&DllStructGetData($struct,1)&"]")
  $a_Call=DllCall("Crypt32.dll","int","CryptStringToBinary", "str",$sData,"int",0,"int",1,"ptr",DllStructGetPtr($a),"ptr",DllStructGetPtr($struct,1),"ptr",0,"ptr",0)
  If @error Or Not $a_Call[0] Then Return SetError(2,0,"")
  Return BinaryToString(DllStructGetData($a,1))
EndFunc

Func _Encoding_Base64Encode($sData)
  $sData=Binary($sData)
  $struct=DllStructCreate("byte["&BinaryLen($sData)&"]")
  DllStructSetData($struct,1,$sData)
  Local $strc=DllStructCreate("int"),$a_Call=DllCall("Crypt32.dll","int","CryptBinaryToString","ptr",DllStructGetPtr($struct),"int",DllStructGetSize($struct), "int",1,"ptr",0,"ptr",DllStructGetPtr($strc))
  If @error Or Not $a_Call[0] Then Return SetError(1,0,"")
  $ast=DllStructCreate("char["&DllStructGetData($strc,1)&"]")
  $a_Call=DllCall("Crypt32.dll","int","CryptBinaryToString","ptr",DllStructGetPtr($struct),"int",DllStructGetSize($struct),"int",1,"ptr",DllStructGetPtr($ast),"ptr",DllStructGetPtr($strc))
  If @error Or Not $a_Call[0] Then Return SetError(2,0,""); error encoding
  Return BinaryToString(DllStructGetData($ast,1))
EndFunc


base64, UUE и XXE похожи, но есть различия, есть статья

Из файла Test.txt с текстом
Код:
12345

В XXE вывод:
Код:
begin 644 Test.txt
3AH6nB1I+
+
end
sum -r/size 4197/5

В UUE вывод:
Код:
begin 644 Test.txt
%,3(S-#4`
`
end
sum -r/size 4197/5
 

inververs

AutoIT Гуру
Сообщения
2,135
Репутация
465
А утилита http://www.izarc.org/ не подойдет? есть поддержка командной строки
 
Автор
A

Andrey_A

Продвинутый
Сообщения
325
Репутация
68
Код:
А утилита http://www.izarc.org/ не подойдет? есть поддержка командной строки
inververs, спасибо, утилит полно, а нужен код для автоматизации...
 

inververs

AutoIT Гуру
Сообщения
2,135
Репутация
465
Не знаю, рабочая или нет, но вот что получилось:
удалено
 
Автор
A

Andrey_A

Продвинутый
Сообщения
325
Репутация
68
inververs [?]
Не знаю, рабочая или нет, но вот что получилось:

Уже близко!, но что-то теряется, вот пример оригинала:

Код:
h+++-++E+A1++++2+6+0c7E++FU+++0+U+++-+0++e-+++CsZ+++M4++++E+U
h+6U7++0KBU++2-++++2+6+-c-+++5Y+++0U++++k++++M+++++2+6+++++++
hU0I++++++++++++++++++++++++++++++++++0Eh7l6V8WEbwkA1oDs-+Tzy
h+E5zzU2-zrYD1Tw80UXz++++zk+++Dw+++1z++++zk+++Dw+++1z++++zk++
скрипт выдаёт:
Код:
h+++-++E+++++++2++++c+E+++U+++++U+++-++++++++++sZ+++M+++++E+U
h++U7+++K+U++++++++2++++c+++++U++++U++++k++++++++++2+++++++++
h++I+++++++++++++++++++++++++++++++++++Eh+k6V+UEb+kA1++s-+Ewy
h+E2z+U2-+kYD+Ew8+UUz+++++k++++w++++z+++++k++++w++++z+++++k++
 

inververs

AutoIT Гуру
Сообщения
2,135
Репутация
465
не судьба значит. Нету времени разбираться.
 

inververs

AutoIT Гуру
Сообщения
2,135
Репутация
465
http://habrahabr.ru/post/146722/

Код:
$fileName = '1.txt'
$hFile = FileOpen($fileName, 16)
$data = FileRead($hFile)
FileClose($hFile)

bin2xxe($data, $fileName)

Func bin2xxe($src, $fname)
	$src = Binary($src)
	Local $xxe = StringSplit('+-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', '', 3)

	Local $n = BinaryLen($src) - 1
	Local $pt = 1
	Local $sz = 12 + StringLen($fname)
	Local $i = 0, $s

	For $_i = 1 To (($n + 1) / 45) * 63 + (Mod(($n + 1), 45)) * 4 / 3 + 280
		$s &= ' '
	Next
;~ 	или StringFormat('%' & $count & 's', '')

	Mid($s, 1, $sz, "begin 644 " & $fname & @CRLF)
	$pt = $pt + $sz + 1
	$sz = $pt - 1

	While $i <= $n
		Switch Mod($i, 3)
			Case 0
				Mid($s, $pt, 1, $xxe[Int(Dec(Hex(BinaryMid($src, $i + 1, 1))) / 4)])
				$pt = $pt + 1
				$t = BitAND(Dec(Hex(BinaryMid($src, $i + 1, 1))), 3) * 16
			Case 1
				Mid($s, $pt, 1, $xxe[$t + Int(Dec(Hex(BinaryMid($src, $i + 1, 1))) / 16)])
				$pt = $pt + 1
				$t = BitAND(Dec(Hex(BinaryMid($src, $i + 1, 1))), 15) * 4
			Case 2
				Mid($s, $pt, 2, $xxe[$t + Int(Dec(Hex(BinaryMid($src, $i + 1, 1))) / 64)] & _
						$xxe[BitAND(Dec(Hex(BinaryMid($src, $i + 1, 1))), 63)])
				$pt = $pt + 2
				$t = 0
		EndSwitch
		If Mod($i, 45) = 44 Then
			Mid($s, $sz, 1, 'h')
			Mid($s, $pt, 2, @CRLF)
			$pt = $pt + 3
			$sz = $pt - 1
		EndIf
		$i = $i + 1
	WEnd

	If Mod($n + 1, 3) <> 0 Then
		Mid($s, $pt, 1, $xxe[$t])
		$pt = $pt + 1
	EndIf

	$t = Mod($n, 45) + 1

	If $t <> 45 Then
		Mid($s, $sz, 1, $xxe[$t])
		Mid($s, $pt, 3, "+" & @CRLF)
		$pt = $pt + 3
	EndIf

	Mid($s, $pt, 3, "end")
	$sz = $pt + 2
	$bin2xxe = StringLeft($s, $sz)

	ConsoleWrite($bin2xxe & @LF)
	Return $bin2xxe
EndFunc   ;==>bin2xxe

Func Mid(ByRef $s, $start, $count, $string)
	$s = StringReplace($s, $start, $string)
EndFunc   ;==>Mid



Добавлено:
Сообщение автоматически объединено:

Скорость конечно его отвратительная. Где то видимо медленная функция :smile:
 
Автор
A

Andrey_A

Продвинутый
Сообщения
325
Репутация
68
inververs, отличная работа - Ваш код работает!!!

По поводу скорости - попробую поэкспериментировать...

Не сочтите за наглость, ещё бы декодирование)
(начал было сам , но запутался...)

----------------- Добавил:

Скорость увеличил, сделав такое:
Позже увидел, что при больших файлах это работает, при маленьких нет - ... условие надо ... через часа 2 исправил
Код:
Local $n = BinaryLen($src) - 1
    Local $pt = 1
    Local $sz = 12 + StringLen($fname)
    Local $i = 0, $s


    $count=(($n + 1) / 45) * 63 + (Mod(($n + 1), 45)) * 4 / 3 + 280
    $space='  '
    $len=StringLen($src)
    If $len<256 Then
      For $k=1 To $count/$len/8+1
        $space&='        '
      Next
    EndIf
    $s=StringRegExpReplace($src, '[\H]', $space)
    $s=StringLeft($s,$count)


Ещё вопрос: в конец текста нужно добавить... Если файл с текстом
Код:
12345

то добавляется:

Код:
end
sum -r/size 4197/5

5 - понятно размер файла в кб
а вот что может быть 4197 ? Это некая сумма для проверки Как посчитать ?

-----------
Код отрабатывает нормально, но концовка под вопросом, а именно переменную $n необходимо увеличивать перед циклом While , а где нет. Иначе пару ++ в конец не добавляется. Может потому что $count дробный, по идее должен быть целым






Добавлено:
Сообщение автоматически объединено:

Кое-что получилось из 3-х вариантов... код работает более менее быстро, единственное непонятным остался вопрос с последним символом "+" перед концовкой:
Код:
+
end
2230 bytes
в одних случаях всё чётко, в других не хватает последнего "+"... увеличиваешь $n на 1 - появляется, но тогда в первых случаях он лишний...

Код:
Func _Encoding_XXE($FileName)
    $hFile=FileOpen($FileName,16)
    $Data=FileRead($hFile)
    FileClose($hFile)
    $src=Binary($Data)
    $xxe=StringSplit('+-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz','',2)
    Local $n=BinaryLen($src),$i=0,$s

    While $i<=$n
        $iDec=Dec(Hex(BinaryMid($src,$i+1,1)))
        Switch Mod($i,3)
            Case 0
                $s&=$xxe[Int($iDec/ 4)]
                $t=BitAND($iDec,3)*16
            Case 1
                $s&=$xxe[$t+Int($iDec/ 16)]
                $t=BitAND($iDec,15)*4
            Case 2
                $s&=$xxe[$t+Int($iDec/ 64)]&$xxe[BitAND($iDec,63)]
                $t=0
        EndSwitch
        If Mod($i,45)=44 Then $s&=@CRLF&'h'
        $i=$i+1
    WEnd

    If Mod($n+1,3)<>0 Then $s&=$xxe[$t]
    $t=Mod($n,45)+1
    If $t<>45 Then
      $k=StringInStr($s,@CRLF,0,-1)
      If $k Then
        $s='h'&StringLeft($s,$k)&$xxe[$t-1]&StringMid($s,$k+3)&'+'&@CRLF
      Else
        $s=$xxe[$t-1]&$s&'+'&@CRLF
      EndIf
    EndIf
    $s='begin 644 '&StringRegExpReplace($FileName,'(^.*)\\(.*)$','\2')&@CRLF&$s&'+'&@CRLF&'end'&@CRLF&$n&' bytes'&@CRLF
    Return $s
EndFunc   ;==>_Encoding_XXE


Осталось декодирование. Конечно огромное спасибо inververs, те скрипты, что вы показывали, я видел и до этого, но с вашим преобразованием, взглянул по-новому.
------------------------- Добавлено
Скорость увеличена, но всё равно не то...
Надо как-то до цикла разбивать строку в 8 бит, затем по 6 бит и заменять символы... к сожалению не работал с бинарными данными (
 

inververs

AutoIT Гуру
Сообщения
2,135
Репутация
465
Andrey_A [?]
а вот что может быть 4197 ? Это некая сумма для проверки Как посчитать ?
это контрольная сумма, алгоритм вроде есть в википедии

в одних случаях всё чётко, в других не хватает последнего "+"... увеличиваешь $n на 1 - появляется, но тогда в первых случаях он лишний...
Незнаю, я слепо переписал алгоритм со статьи даже не вникая в него, поэтому может где то и ошибся.

Скорость увеличена, но всё равно не то...
Тут упираешься в производительность AutoIT/ Мне кажется это не тот инструмент в котором можно производить такие расчеты. Пустой цикл с пол миллионом итераций уже обрабатываеться долго. Если добавить в нем еще операции BitAND MOD, или простые операторы сравнения, то время вырастает в разы. Я так и не смог дождаться когда закодируется файл размером в 500КБ. Хотя когда этот же файл кодировал с помощью этого алгоритма в VBA то он обработался за секунду.


Надо как-то до цикла разбивать строку в 8 бит, затем по 6 бит и заменять символы...
Да, вот тут для меня осталось тоже загадкой, как доставать по 6 бит :smile: Подозреваю что алгоритм еще можно улучшить. Но, я бы ва советовал искать dll. :smile:
 
Автор
A

Andrey_A

Продвинутый
Сообщения
325
Репутация
68
inververs,

1. с 4197 и с "+" оказалось необязательным - декодирует сторонними утилитами нормально.

2. Производительность можно увеличить, только если кто поможет:
На одном из сайтов встретил такое, ну мы наверно это и делали
Код:
Перевод текста в UUE:

Исходный текст : M        o        d
Hомера по ASCII: 77       111      100
По словам(8bit): 01001101 01101111 01100100

По словам(6bit): 010011 010110 111101 100100
Hомера по ASCII: 19     22     61     36
                 Прибавляем код пробела (32 по ASCII)
Hомера по ASCII: 51     54     93     68
Текст UUE      : 3      6      ]       D

Итог           : Mod > 36]D


Но, что хотелось бы:
1. Как получить из бинарной строки Mod строку вида
010011010110111101100100 ?
если это можно получить, то до цикла её разбиваем по 6 символов с пробелом и просто заменяем 64 буквы...

[конечно если логика на правильном пути]

Я знаю про производительность Autoit... поэтому везде стараюсь работать с текстовыми строками и меньше доверять работу циклам.

inververs [?]
Спасибо, так вот где ж её искать :smile:
 

inververs

AutoIT Гуру
Сообщения
2,135
Репутация
465
Andrey_A [?]
Спасибо, так вот где ж её искать
Если вам очень нужно, закажите разработку. Алгоритм простой. Библиотека получится мальнькой. Встроете ее напрямую в скрипт, и через DllCallAddress вызываете функии. И никаких дополнительных файлов :ok:
 
Автор
A

Andrey_A

Продвинутый
Сообщения
325
Репутация
68
inververs, подскажите в какой теме это можно сделать?

------
Создал тему, если кто поможет с созданием библиотеки, поможете большой группе людей в автоматизации TCIMG

Заранее спасибо!

Создал тему
 
Автор
A

Andrey_A

Продвинутый
Сообщения
325
Репутация
68
Skif_off
спасибо за ваш вариант, в теме sims создал dll 12kb
Всем спасибо за участие. Тема решена.
 
Верх