Работа с LZMA-сжатием (lzma.dll), проблемы

Discussion in 'С/С++, C#, Rust, Swift, Go, Java, Perl, Ruby' started by groundhog, 23 Feb 2009.

  1. groundhog

    groundhog Elder - Старейшина

    Joined:
    12 May 2007
    Messages:
    1,159
    Likes Received:
    425
    Reputations:
    180
    Всем известен архиватор 7ZIP. Основа его ценности - метод сжатия lzma (улучшенная и оптимизированная версия алгоритма LZ77). Появилась необходимость использовать его в своей программе. Изучил страницу http://7-zip.org.ua/ru/sdk.html. Скачал это SDK. Собрал lzma.dll. Пытаюсь работать с ней через LoadLibrary/GetProcAddress. По идее мне всего-то и нужны реализации функций LzmaCompress/LzmaUncompress из этой либы, но проблема в том, что в таблице экспорта lzma.dll есть только:

    CreateObject
    GetMethodProperty
    GetNumberOfMethods

    То есть по идее, то, что я собрал - какой-то wrapper на эту либу и соответственно вызовы GetProcAddress на LzmaCompress/LzmaUncompress проваливаются.

    Пишу на WINAPI/С++. Если кто сталкивался с использованием LZMA в своём приложении, обладает какими-то тематическими исходниками, обладает "нормальной" версией DLL, или может поддать пинка в нужном для осмысления направлении - плиз, помогите разобраться с работой этой либы.
     
  2. spider-intruder

    spider-intruder Elder - Старейшина

    Joined:
    9 Dec 2005
    Messages:
    700
    Likes Received:
    339
    Reputations:
    37
    В LZMA,txt в корне СДК вроде есть описание How To USE


    Сам собирать не пробовал но пишут что ее чуть ли не собирать по разному надо в зависимости от того как юзать собираешься - щас попробую ))

    Посмотри тут \lzma\CPP\7zip\UI\Client7z\Client7z.cpp
    В main() пример использования
     
    #2 spider-intruder, 23 Feb 2009
    Last edited: 23 Feb 2009
  3. groundhog

    groundhog Elder - Старейшина

    Joined:
    12 May 2007
    Messages:
    1,159
    Likes Received:
    425
    Reputations:
    180
    Угу, спасибо, Спайд. Там всё через COM-интерфейсы сделано, что для меня не есть гуд. Решил взять из SDK только LzmaDec.h, LzmaDec.c и Types.h. Ну то есть только реализацию алгоритма декомпрессии покопался в исходниках, наваял тестовый код, который должен был бы из памяти в память распаковать кое-какой файл, но проблема в том, что функция возвращает либо SZ_OK и пустой результат, либо SZ_ERROR_DATA и какой-то мусор. Ночью, как буду дома выложу тестовый код сюда, посмотри плиз, может поймёшь где я лажаю.
     
  4. spider-intruder

    spider-intruder Elder - Старейшина

    Joined:
    9 Dec 2005
    Messages:
    700
    Likes Received:
    339
    Reputations:
    37
    А что обязательно его юзать?! Возьми APLIB компресия будет не хуже
     
  5. groundhog

    groundhog Elder - Старейшина

    Joined:
    12 May 2007
    Messages:
    1,159
    Likes Received:
    425
    Reputations:
    180
    Ок, Спайд, ещё раз спасибо. Попробую прикурочить аплиб к приложению. В свою очередь выкладываю злосчастный исходник с LZMA memory to memory распаковщиком.

    Файлы проекта, собранные под 2003 студией лежат тут: http://groundhog.ru/lzma_test.zip

    Ниже привожу исходник. Постарался всё откоментировать, чтобы вам удобнее было понять. Может кому что бросится в глаза, и вы прольёте свет на то, где я лажаю, мне уже ничего не лезет в голову.

    Code:
    /*
    
    	Работать будем с файлом test.7z. Архив содержит в себе всего один файл test.txt, который
    	в свою очередь содержит строчку ASCII-текста "This is a simple text file! ;)".
    
    	Метод сжатия: LZMA
    	Формат архива: 7z
    	Уровень сжатия: нормальный
    
    	Вытяжка из lzma.txt
    
    	Single-call Decompressing
    	-------------------------
    	When to use: RAM->RAM decompressing
    	Compile files: LzmaDec.h + LzmaDec.c + Types.h
    	Compile defines: no defines
    	Memory Requirements:
    		- Input buffer: compressed size
    		- Output buffer: uncompressed size
    		- LZMA Internal Structures: state_size (16 KB for default settings) 
    
    	Interface:
    		int LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
    			const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, 
    			ELzmaStatus *status, ISzAlloc *alloc);
    	In: 
    		dest     - output data
    		destLen  - output data size
    		src      - input data
    		srcLen   - input data size
    		propData - LZMA properties  (5 bytes)
    		propSize - size of propData buffer (5 bytes)
    		finishMode - It has meaning only if the decoding reaches output limit (*destLen).
    			LZMA_FINISH_ANY - Decode just destLen bytes.
    			LZMA_FINISH_END - Stream must be finished after (*destLen).
    
    			You can use LZMA_FINISH_END, when you know that 
    			current output buffer covers last bytes of stream. 
    		alloc - Memory allocator.
    	Out: 
    		destLen  - processed output size 
    		srcLen   - processed input size 
    	Output:
    		SZ_OK
    			status:
    				LZMA_STATUS_FINISHED_WITH_MARK
    				LZMA_STATUS_NOT_FINISHED 
    				LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
    		SZ_ERROR_DATA - Data error
    		SZ_ERROR_MEM  - Memory allocation error
    		SZ_ERROR_UNSUPPORTED - Unsupported properties
    		SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src).
    
    		If LZMA decoder sees end_marker before reaching output limit, it returns OK result,
    		and output value of destLen will be less than output buffer size limit.
    
    		You can use multiple checks to test data integrity after full decompression:
    			1) Check Result and "status" variable.
    			2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize.
    			3) Check that output(srcLen) = compressedSize, if you know real compressedSize. 
    		You must use correct finish mode in that case.
    
    */ 
    
    #include <windows.h>   // Подключаем windows-говнище
    
    extern "C" {
    	#include "LzmaDec.h"   // Подключаем LZMA-говнище (только метод распаковки)
    	#include "Types.h"   // Подключаем LZMA-говнище (определение типов)
    }
    
    
    // Мой макрос. Показывает описание последней ошибки согласно GetLastError()
    #define SHOW_LAST_ERROR() \
    	{ \
    	LPVOID lpMsgBuf; \
    	FormatMessage( \
    	FORMAT_MESSAGE_ALLOCATE_BUFFER | \
    	FORMAT_MESSAGE_FROM_SYSTEM | \
    	FORMAT_MESSAGE_IGNORE_INSERTS, \
    	NULL, \
    	GetLastError(), \
    	0, \
    	(LPTSTR) &lpMsgBuf, \
    	0, \
    	NULL \
    	); \
    	MessageBox(NULL, (LPCTSTR)lpMsgBuf, TEXT("Error"), MB_OK | MB_ICONERROR); \
    	LocalFree(lpMsgBuf); \
    	}
    
    // Объявление прототипов функций, основное описание ниже
    VOID *MyAlloc (size_t);
    VOID MyFree (VOID *);
    
    // Определяем два указателя на функции-враперы. Один указатель на врапер
    // выделения памяти, второй - указатель на врапер освобождения памяти
    static void *SzAlloc(VOID *p, size_t size) { p = p; return MyAlloc(size); }
    static void SzFree(VOID *p, VOID *address) { p = p; MyFree(address); }
    
    // Структурка (глобальная), описывающая врапер выделения и освобождения памяти 
    static ISzAlloc g_Alloc = { SzAlloc, SzFree };
    
    // Функция выделения заданного числа байт памяти
    VOID *MyAlloc (size_t size) {
    	return VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE);;
    }
    
    // Функция освобождения выделеного блока памяти
    VOID MyFree (VOID *address) {
    	VirtualFree(address, 0, MEM_RELEASE);
    }
    
    // Функция-реализация алгоритма распаковки LZMA
    INT LzmaUncompress(UCHAR *dest, size_t *destLen, const UCHAR *src, size_t *srcLen, const UCHAR *props, size_t propsSize) {
    	ELzmaStatus status;
    	return LzmaDecode(dest, destLen, src, srcLen, props, (UINT)propsSize, LZMA_FINISH_ANY, &status, &g_Alloc);
    }
    
    
    INT WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLine, INT nCmdShow) {
    	TCHAR szSomeBuff[1024] = {0};
    
    	// Открываем файл на чтение
    	HANDLE hFile = CreateFile(TEXT("test.7z"), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
    	if (INVALID_HANDLE_VALUE == hFile) {
    		SHOW_LAST_ERROR();
    		return ERROR_FILE_NOT_FOUND;
    	}
    
    	// Получаем размер этого файла
    	DWORD dwLowFileSize = 0, dwHighFileSize = 0;
    
    	dwLowFileSize = GetFileSize(hFile, &dwHighFileSize);
    	if (dwHighFileSize != NULL && dwLowFileSize == INVALID_FILE_SIZE && GetLastError != NO_ERROR) {
    		SHOW_LAST_ERROR();
    		return ERROR_FILE_INVALID;
    	}
    
    	LONG nFileSize = MAKELONG(dwLowFileSize, dwHighFileSize);
    
    	// Показываем информацию о размере файла
    	ZeroMemory(szSomeBuff, 1024);
    	wsprintf(szSomeBuff, TEXT("Размер целевого файла: %10d байт"), nFileSize);
    	MessageBox(NULL, szSomeBuff, TEXT("Debug"), MB_OK);
    
    	// Выделяем память необходимого объёма
    	LPVOID lpFileInputData = MyAlloc(nFileSize);
    	if (lpFileInputData == NULL) {
    		SHOW_LAST_ERROR();
    		return ERROR_GEN_FAILURE;
    	}
    
    	DWORD dwBytesRead = 0;
    
    	// Читаем файл в память
    	BOOL bResult = ReadFile(hFile, lpFileInputData, nFileSize, &dwBytesRead, NULL);
    	if (!bResult) {
    		SHOW_LAST_ERROR();
    		return ERROR_GEN_FAILURE;
    	}
    
    	// Показываем информацию о количестве прочитанных байт
    	ZeroMemory(szSomeBuff, 1024);
    	wsprintf(szSomeBuff, TEXT("Из файла считано: %10d байт"), dwBytesRead);
    	MessageBox(NULL, szSomeBuff, TEXT("Debug"), MB_OK);
    
    	// Буфер для хранения распакованных данных. 16Кб хватит?
    	size_t nOutputDataLen = 16384;
    	LPVOID lpFileOutputData = MyAlloc(nOutputDataLen);
    	if (lpFileOutputData == NULL) {
    		SHOW_LAST_ERROR();
    		return ERROR_GEN_FAILURE;
    	}
    
    	nFileSize = nFileSize - LZMA_PROPS_SIZE;
    
    	// Вызов функции распаковки
    	bResult = LzmaUncompress(
    		(UCHAR *)lpFileOutputData,   // Буфер куда будет распакован файл
    		&nOutputDataLen,   // Длина буфера
    		(UCHAR *)lpFileInputData + LZMA_PROPS_SIZE + 1,   // Указатель на данные файла (отступаем ZMA_PROPS_SIZE байт от начала - это заголовок)
    		(size_t *) &nFileSize,   // Размер данных (без учёта заголовка)
    		(UCHAR *)lpFileInputData,   // Указатель на заголовок
    		LZMA_PROPS_SIZE   // Размер заголовка
    	);
    
    	ZeroMemory(szSomeBuff, 1024);
    
    	// Анализируем значение, которое вернула функция
    	switch (bResult) {
    		case SZ_OK :
    			wsprintf(szSomeBuff, TEXT("Функция вернула: %s"), TEXT("SZ_OK"));
    		break;
    		case SZ_ERROR_DATA :
    			wsprintf(szSomeBuff, TEXT("Функция вернула: %s"), TEXT("SZ_ERROR_DATA"));
    		break;
    		case SZ_ERROR_MEM :
    			wsprintf(szSomeBuff, TEXT("Функция вернула: %s"), TEXT("SZ_ERROR_MEM"));
    		break;
    		case SZ_ERROR_UNSUPPORTED :
    			wsprintf(szSomeBuff, TEXT("Функция вернула: %s"), TEXT("SZ_ERROR_UNSUPPORTED"));
    		break;
    		case SZ_ERROR_INPUT_EOF :
    			wsprintf(szSomeBuff, TEXT("Функция вернула: %s"), TEXT("SZ_ERROR_INPUT_EOF"));
    		break;
    	}
        
    	MessageBox(NULL, szSomeBuff, TEXT("Debug"), MB_OK);
    
    	// Показываем результат распаковки
    	ZeroMemory(szSomeBuff, 1024);
    	wsprintf(szSomeBuff, TEXT("Буфер распаковки: %s"), lpFileOutputData);
    	MessageBox(NULL, szSomeBuff, TEXT("Debug"), MB_OK);
    
    	return 0;
    }
     
    #5 groundhog, 25 Feb 2009
    Last edited: 25 Feb 2009
  6. spider-intruder

    spider-intruder Elder - Старейшина

    Joined:
    9 Dec 2005
    Messages:
    700
    Likes Received:
    339
    Reputations:
    37
    Вот тебе длл с 2мя нужными тебе методами http://www.sendspace.com/file/dbzpfb

    Юзай либо через

    HMODULE hLib = LoadLibrary("lzma.dll");
    *(FARPROC*)&Uncompress= GetProcAddress(hLib,LzmaUncompress);
    *(FARPROC*)&Compress= GetProcAddress(hLib,LzmaCompress);

    (Параметры описаны в LzmaLib.h)

    Ну либо подруби C,h файлы из сдк. Либу возьми скомпилив вот это lzma\C\LzmaLib\LzmaLib.dsw
     
    #6 spider-intruder, 25 Feb 2009
    Last edited: 25 Feb 2009