Что нового

_WinAPI_DecompressBuffer - проблемы с распаковкой ранее упакованных данных

veretragna

Как писал, так и работает.
Сообщения
140
Репутация
10
Доброго вечера.
Сразу вопрос.

В описании функций _WinAPI_DecompressBuffer() и _WinAPI_CompressBuffer() указано, что они могут работать в том числе и с форматом $COMPRESSION_FORMAT_XPRESS_HUFF. Но на практике оказалось, что не совсем.

Если сжимать и распаковать данные с помощью формата $COMPRESSION_FORMAT_XPRESS (без _HUFF), данные распаковываются нормально. А если сжать и распаковать с помощью $COMPRESSION_FORMAT_XPRESS_HUFF, то распакованная строка оказывается заполненной нулями, @error выставляется в 10, а @extended - в C00000E8.

Собственно, почему $COMPRESSION_FORMAT_XPRESS_HUFF не работает, как надо?
Прошу помочь с определением проблемы, код внизу.

Или подскажите рабочую библиотечку для сильного сжатия данных прямо в памяти (типа LZMA), если есть актуальная версия.
Заранее спасибо.

UPD: Но ведь разобраться интереснее! :laugh:

Код:
#include <APISysConstants.au3>
#include <WinAPISys.au3>

$data = "binbinbinbinbinbinbinbinbinbinbinbinbinbinbinbinbinbinbinbinbinbinbinbinbinbinbinbin"

$Ret = _DB_CompressData($data)
$Ret = _DB_DeCompressData($Ret)
MsgBox(0, "uncompressed data", $Ret)

Func _DB_CompressData($data)

	Local $Size_O, $Size_C, $a_pBuffer[2], $ret[3]
	$Size_O = BinaryLen($data)
	$a_pBuffer[0] = _WinAPI_CreateBuffer($Size_O)
	$a_pBuffer[1] = _WinAPI_CreateBuffer($Size_O)
	DllStructSetData(DllStructCreate('byte[' & $Size_O & ']', $a_pBuffer[0]), 1, $data)
	$Size_C = _WinAPI_CompressBuffer($a_pBuffer[0], $Size_O, $a_pBuffer[1], $Size_O, BitOR($COMPRESSION_FORMAT_XPRESS_HUFF, $COMPRESSION_ENGINE_MAXIMUM))
	; сжимает нормально, бинарные данные в порядке
	;$Size_C = _WinAPI_CompressBuffer($a_pBuffer[0], $Size_O, $a_pBuffer[1], $Size_O, BitOR($COMPRESSION_FORMAT_XPRESS, $COMPRESSION_ENGINE_MAXIMUM)) ; работает!
	$ret[0] = DllStructGetData(DllStructCreate('byte[' & $Size_C & ']', $a_pBuffer[1]), 1)
	$ret[1] = $Size_O
	$ret[2] = $Size_C
	_WinAPI_FreeMemory($a_pBuffer[0])
	_WinAPI_FreeMemory($a_pBuffer[1])
	
	Return $ret

EndFunc   ;==>_CompressData

Func _DB_DeCompressData($data)

	Local $Size_O, $Size_C, $BinData, $a_pBuffer[2], $ret

	$Size_O = $data[1]
	$Size_C = $data[2]
	$BinData = $data[0]

	$a_pBuffer[0] = _WinAPI_CreateBuffer($Size_O)
	$a_pBuffer[1] = _WinAPI_CreateBuffer($Size_C)
	DllStructSetData(DllStructCreate('byte[' & $Size_C & ']', $a_pBuffer[1]), 1, $BinData)
	_WinAPI_DecompressBuffer($a_pBuffer[0], $Size_O, $a_pBuffer[1], $Size_C, $COMPRESSION_FORMAT_XPRESS_HUFF)
	; не работает =( @error = 10, Hex(@extended) = c00000e8
	;_WinAPI_DecompressBuffer($a_pBuffer[0], $Size_O, $a_pBuffer[1], $Size_C, $COMPRESSION_FORMAT_XPRESS) ; работает!
	MsgBox(0, @error, Hex(@extended))
	
	$Ret = BinaryToString(DllStructGetData(DllStructCreate('byte[' & $Size_O & ']', $a_pBuffer[0]), 1), 1)
	_WinAPI_FreeMemory($a_pBuffer[0])
	_WinAPI_FreeMemory($a_pBuffer[1])
	
	Return $Ret

EndFunc   ;==>_CompressData
 

joiner

Модератор
Локальный модератор
Сообщения
3,556
Репутация
628
года три назад я тоже с этим столкнулся и не нашел решения. на самом деле это ошибка размера буфера. запусти код ниже
Код:
#include <APISysConstants.au3>
#include <WinAPISys.au3>
#include <WinAPI.au3>
#include <WinAPIDiag.au3>
$data = "binbinbinbinbinbinbinbinbinbinbinbinbinbinbinbinbinbinbinbinbinbinbinbinbinbinbinbin"

$Ret = _DB_CompressData($data)
$Ret = _DB_DeCompressData($Ret)
;MsgBox(0, "uncompressed data", $Ret)

Func _DB_CompressData($data)

    Local $Size_O, $Size_C, $a_pBuffer[2], $ret[3]
    $Size_O = BinaryLen($data)
    $a_pBuffer[0] = _WinAPI_CreateBuffer($Size_O)
    $a_pBuffer[1] = _WinAPI_CreateBuffer($Size_O)
    DllStructSetData(DllStructCreate('byte[' & $Size_O & ']', $a_pBuffer[0]), 1, $data)
    $Size_C = _WinAPI_CompressBuffer($a_pBuffer[0], $Size_O, $a_pBuffer[1], $Size_O, BitOR($COMPRESSION_FORMAT_XPRESS_HUFF, $COMPRESSION_ENGINE_MAXIMUM))
	  MsgBox(0, @error, _WinAPI_GetErrorMessage(_WinAPI_NtStatusToDosError (@extended)))
    ; сжимает нормально, бинарные данные в порядке
    ;$Size_C = _WinAPI_CompressBuffer($a_pBuffer[0], $Size_O, $a_pBuffer[1], $Size_O, BitOR($COMPRESSION_FORMAT_XPRESS, $COMPRESSION_ENGINE_MAXIMUM)) ; работает!
    $ret[0] = DllStructGetData(DllStructCreate('byte[' & $Size_C & ']', $a_pBuffer[1]), 1)
    $ret[1] = $Size_O
    $ret[2] = $Size_C
    _WinAPI_FreeMemory($a_pBuffer[0])
    _WinAPI_FreeMemory($a_pBuffer[1])

    Return $ret

EndFunc   ;==>_CompressData

Func _DB_DeCompressData($data)

    Local $Size_O, $Size_C, $BinData, $a_pBuffer[2], $ret

    $Size_O = $data[1]
    $Size_C = $data[2]
    $BinData = $data[0]

    $a_pBuffer[0] = _WinAPI_CreateBuffer($Size_O)
    $a_pBuffer[1] = _WinAPI_CreateBuffer($Size_C)
    DllStructSetData(DllStructCreate('byte[' & $Size_C & ']', $a_pBuffer[1]), 1, $BinData)
    _WinAPI_DecompressBuffer($a_pBuffer[0], $Size_O, $a_pBuffer[1], $Size_C, $COMPRESSION_FORMAT_XPRESS_HUFF)
    ; не работает =( @error = 10, Hex(@extended) = c00000e8
    ;_WinAPI_DecompressBuffer($a_pBuffer[0], $Size_O, $a_pBuffer[1], $Size_C, $COMPRESSION_FORMAT_XPRESS) ; работает!
    MsgBox(0, @error, _WinAPI_GetErrorMessage(_WinAPI_NtStatusToDosError (@extended)))

    $Ret = BinaryToString(DllStructGetData(DllStructCreate('byte[' & $Size_O & ']', $a_pBuffer[0]), 1), 1)
    _WinAPI_FreeMemory($a_pBuffer[0])
    _WinAPI_FreeMemory($a_pBuffer[1])

    Return $Ret

EndFunc   ;==>_CompressData
 
Автор
veretragna

veretragna

Как писал, так и работает.
Сообщения
140
Репутация
10
Нашел на просторах интернета библиотечку BZIP2 и в ее экспорте служебную функцию BZ2_bzBuffToBuffCompress с очень похожим синтаксисом. Выглядит перспективно! Получится - отпишусь.


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

Вроде все делаю правильно, а DllCall() к библиотеке BZIP2 выдает @error = 1 - "unable to use the DLL file". Что я делаю не так?
Пример во вложениях, dll-ка в архиве есть.


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

Собственно, вот прототип функции. Может, это я где допустил ошибку?

Код:
int BZ2_bzBuffToBuffCompress( char*         dest,
                              unsigned int* destLen,
                              char*         source,
                              unsigned int  sourceLen,
                              int           blockSize100k,
                              int           verbosity,
                              int           workFactor );


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

Задал этот же вопрос на англофоруме, вдруг там кто отозвется. Больше народу - больше вариантов


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

Может, у кого завалялась копия вот этой библиотеки с англофорума? Там ее уже нет, "файл не существует". тыц
 

Вложения

  • test_bzip2_compress.rar
    28.8 КБ · Просмотры: 5

Garrett

Модератор
Локальный модератор
Сообщения
3,999
Репутация
967
veretragna [?]
Вроде все делаю правильно, а DllCall() к библиотеке BZIP2 выдает @error = 1
Код:
$sSource = "Hello Autoit!"
$iBlockSize = 8
$iVerbosity = 4
$iWorkFactor = 30

$pDest = DllStructCreate("char["& StringLen($sSource)*4 &"]")

$iSize = _BZ2_bzBuffToBuffCompress($pDest, $sSource, $iBlockSize, $iVerbosity, $iWorkFactor)

MsgBox(0, "", StringFormat("> DestLength: %s\n> Destination: %s\n", $iSize, DllStructGetData($pDest, 1)))

#Region

Func _BZ2_bzBuffToBuffCompress($p_Dest, $s_Source, $i_BlockSize, $i_Verbosity, $i_WorkFactor)

   $a_Ret = DllCall("bzip2.dll", "int:cdecl", "BZ2_bzBuffToBuffCompress", "ptr", DllStructGetPtr($p_Dest), "uint*", DllStructGetSize($p_Dest), _
																		  "str", $s_Source, "uint", StringLen($s_Source), _
																		  "int", $i_BlockSize, "int", $i_Verbosity, "int", $i_WorkFactor)
   If $a_Ret[0] Then
	  ConsoleWrite(StringFormat("> ERROR: %s\n", $a_Ret[0]))
	  Return SetError(1, 0, 0)
   EndIf

   Return SetError(0, 0, $a_Ret[2])
EndFunc ;==> _BZ2_bzBuffToBuffCompress

#EndRegion
 
Автор
veretragna

veretragna

Как писал, так и работает.
Сообщения
140
Репутация
10
Выглядит еще перспективнее! Огромная благодарность! Доберусь до компа и погоняю, как следует.

К слову, почему бы не сделать UDF?
 

joiner

Модератор
Локальный модератор
Сообщения
3,556
Репутация
628
Автор, а насчет вопроса темы уже интереса нет?
Garrett, есть ли какие мысли по поводу ошибки, при использовании метода Хаффмана ?
 

Garrett

Модератор
Локальный модератор
Сообщения
3,999
Репутация
967
joiner
Запустил ваш пример. Пишет, что указанный формат сжатия не поддерживается.
Win7x32
 
Автор
veretragna

veretragna

Как писал, так и работает.
Сообщения
140
Репутация
10
Автор с телефона сидит =)
На андроиде, к сожалению, не идут скрипты. Доберусь домой и погоняю.
Вообще моя цель - сжать данные для хранения в sqlite, тут сойдет любое сильное сжатие. А bzip2 уже включает алгоритм Хаффмана, насколько я знаю.
Изначальный вопрос не снимается, просто у меня нет идей, как это перебороть, а с bzip2 уже можно работать.


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

7zip.au3 не подходит потому, что ориентирован на работу с файлами. Мне же нужно сжимать строку в памяти без посредника в виде временного файла.


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

Увидел свой косяк даже с телефона. Я обзывал аргументы DllCall() по имени, а надо было по типу передаваемых данных. Тормоз настоящий


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

Garrett
Увы, Ваш код у меня не работает. Сразу после $a_Ret = DllCall(...) @error выставляется в единичку - unable to use the DLL file. Autoit 3.3.12.0 x86, bzip2.dll - x86, винда - 10х64 про.

А тем временем мне подкинули давно потерянную UDF для сильного LZMA-сжатия строк в памяти.
Прикрепляю её здесь, потому что эта библиотечка 100% работает и отлично жмет данные. Она не должна больше теряться. В среднем один текстовый блоб жмется до 8-9%.
Автор оригинальной UDF - Ward.
 

Вложения

  • lzma.zip
    51.4 КБ · Просмотры: 8

joiner

Модератор
Локальный модератор
Сообщения
3,556
Репутация
628
veretragna [?]
Увы, Ваш код у меня не работает
а у меня работает - autoit 3.3.12.0


А тем временем мне подкинули давно потерянную UDF для сильного LZMA-сжатия строк в памяти.Прикрепляю её здесь, потому что эта библиотечка 100% работает и отлично жмет данные. Она не должна больше теряться. В среднем один текстовый блоб жмется до 8-9%.Автор оригинальной UDF - Ward.
могу предложить еще вариант библиотеки. Только без dll. Она не нужна
 

Вложения

  • LZMA.au3
    63.6 КБ · Просмотры: 8
Автор
veretragna

veretragna

Как писал, так и работает.
Сообщения
140
Репутация
10
joiner,
Библиотека Ward'a тоже работает с MemoryDll, только там по-другому сделано. Если включить "LZMA.dll.au3", скрипт работает с памятью, а если не включать, будет искать LZMA.dll в папке скрипта и работать как с файлом. Для некоторых целей может это быть полезно, поэтому просто обращаю Ваше внимание.

В дело взял Вашу версию, т.к. она позволяет обойтись без LzmaInit() в начале и LzmaExit() в конце скрипта.

Могу сказать, что в целом проблема решена.
Хоть и не вышло у меня заставить работать bzip2.dll в 64-битной системе (хотя казалось бы! AutoIt имеет разрядность 32, dll тоже!) и не вышло побороть глюки с алгоритмом Хаффмана в _WinAPI_DecompressBuffer(), все же я сжимаю данные сильным алгоритмом и помещаю в базу. 20 мегабайт текстовых блобов в итоге сжались до 1,7 мб. Это очень хорошо.
Благодарю всех за посильную помощь :smile:
 

joiner

Модератор
Локальный модератор
Сообщения
3,556
Репутация
628
Это тоже библиотека Ward'а, только более новый вариант, судя по тому, что в нынешних версиях autoit уже есть Memory.au3
veretragna [?]
Для некоторых целей может это быть полезно, поэтому просто обращаю Ваше внимание
я это знаю. в скрипте уже включен нужный файл(в виде бинарной строки) для запуска его в памяти. это лучше, чем таскать dll

joiner [?]
а у меня работает - autoit 3.3.12.0
забыл сказать, что у меня тоже Win 10 PRO x64. и вариант с bzip2.dll от Garrett'а работает в моей системе
сама библиотека уже старая. возможны глюки.
 
Верх