Поскольку депресняк пока не думает отступать, а время идет, решил кинуть код анпакера GGD в таком виде, в каком он есть. Он полностью работоспособен, не хватает разве что комментариев и кода проверки GGD-файлов по идентификатору.
#include <stdio.h>
#include <windows.h>
int ExtractGGD( HANDLE hFile, BYTE *pDst, DWORD Size );
int BufferizedRead( HANDLE hFile, BYTE *lpBuf, DWORD NumOfBytesToRead, BOOL IsInit );
int main( int argc, char **argv)
{
struct t_GGDHeader {
BYTE id[4];
WORD width;
WORD height;
} GGDHeader;
char szoutf[ MAX_PATH ];
HANDLE hFile, hOutf;
DWORD BytesRead, BytesWritten, DataLen;
BYTE *pGGDData;
printf( "IKURA GGD images extractor 0.01\n" );
printf( "Extraction code is a courtesy of IKURA;-)\n" );
if( argc > 1 )
{
hFile = CreateFile( argv[1], GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL );
if( hFile != INVALID_HANDLE_VALUE )
{
ReadFile( hFile, &GGDHeader, sizeof( GGDHeader ), &BytesRead, NULL );
DataLen = ( ( ( GGDHeader.width * 3 + 3 ) >> 2 ) << 2 ) * GGDHeader.height;
pGGDData = (BYTE *)malloc( DataLen );
ExtractGGD( hFile, pGGDData, DataLen );
wsprintf( szoutf, "%s%s", argv[1], ".unpacked" );
hOutf = CreateFile( szoutf, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL );
WriteFile( hOutf, pGGDData, DataLen, &BytesWritten, NULL );
free( pGGDData );
CloseHandle( hOutf );
CloseHandle( hFile );
}
else
printf( "Cannot open file %s\n", argv[1] );
}
else
printf( "Usage: unpack_ggd filename<.ggd>\n" );
return 0;
}
//////////////////////////////////////////////////////////////////////////////
// Глобальные переменные, используемые ф-ей BufferizedRead //
struct t_cyc_buf {
BYTE array1[0x800];
BYTE array2[0x800];
} cyc_buf;
DWORD DataBlockLen;
BYTE *pDataBlockCurrByte;
BOOL IsLastBlock;
int ExtractGGD( HANDLE hFile, BYTE *pDst, DWORD Size )
{
BYTE *pDstEnd, *pSrc;
BYTE ctrlb;
BYTE buf[8];
int i;
BufferizedRead( NULL, NULL, 0, TRUE ); // инициализация глобальных переменных используемых ф-ей BufferizedRead()
pDstEnd = Size + pDst;
while( pDst < pDstEnd )
{
if( BufferizedRead( hFile, &ctrlb, 1, FALSE ) == -1 )
return 1;
switch( ctrlb )
{
case 0:
if( BufferizedRead( hFile, buf, 1, FALSE ) == -1 )
return 1;
buf[1] = *( pDst - 3 );
buf[2] = *( pDst - 2 );
buf[3] = *( pDst - 1 );
for( i = 0; i < buf[0]; i++ )
{
*pDst++ = buf[1];
*pDst++ = buf[2];
*pDst++ = buf[3];
}
break;
case 1:
if( BufferizedRead( hFile, buf, 2, FALSE ) == -1 )
return 1;
pSrc = pDst - ( buf[1] * 3 );
for( i = 0; i < buf[0] * 3; i++ )
*pDst++ = *pSrc++;
break;
case 2:
if( BufferizedRead( hFile, buf, 3, FALSE ) == -1 )
return 1;
pSrc = pDst - MAKEWORD( buf[1], buf[2] ) * 3;
for( i = 0; i < buf[0] * 3; i++ )
*pDst++ = *pSrc++;
break;
case 3:
if( BufferizedRead( hFile, buf, 1, FALSE ) == -1 )
return 1;
pSrc = pDst - ( buf[0] * 3 );
*pDst++ = *pSrc++;
*pDst++ = *pSrc++;
*pDst++ = *pSrc;
break;
case 4:
if( BufferizedRead( hFile, buf, 2, FALSE ) == -1 )
return 1;
pSrc = pDst - MAKEWORD( buf[0], buf[1] ) * 3;
*pDst++ = *pSrc++;
*pDst++ = *pSrc++;
*pDst++ = *pSrc;
break;
default:
for( i = 0; i < ctrlb - 4; i++ )
{
if( BufferizedRead( hFile, buf, 3, FALSE ) == -1 )
return 1;
*pDst++ = buf[0];
*pDst++ = buf[1];
*pDst++ = buf[2];
}
break;
}
}
return 1;
}
int BufferizedRead( HANDLE hFile, BYTE *lpBuf, DWORD NumOfBytesToRead, BOOL IsInit )
{
int i;
void *pTemp;
DWORD BytesRead;
if( IsInit )
{
pDataBlockCurrByte = NULL;
DataBlockLen = 0;
IsLastBlock = FALSE;
return 0;
}
if( pDataBlockCurrByte == NULL )
{
ReadFile( hFile, cyc_buf.array1, 0x1000, &DataBlockLen, NULL );
if( DataBlockLen < 0 )
return -1;
pDataBlockCurrByte = cyc_buf.array1;
if( DataBlockLen < 0x1000 )
IsLastBlock = TRUE;
}
if( (DataBlockLen <= 0) || (DataBlockLen < NumOfBytesToRead) )
return -1;
for( i = 0; i < NumOfBytesToRead; i++ )
{
lpBuf[ i ] = *pDataBlockCurrByte++;
DataBlockLen--;
if( pDataBlockCurrByte > &cyc_buf.array2[0x7FF] )
pDataBlockCurrByte = cyc_buf.array1;
}
if( (DataBlockLen >= 0x800) || IsLastBlock )
return NumOfBytesToRead;
pTemp = cyc_buf.array1;
if( pDataBlockCurrByte < cyc_buf.array2 )
pTemp = cyc_buf.array2;
ReadFile( hFile, pTemp, 0x800, &BytesRead, NULL );
if( BytesRead >= 0 )
{
if( BytesRead < 0x800 )
IsLastBlock = TRUE;
DataBlockLen += BytesRead;
return NumOfBytesToRead;
}
IsLastBlock = TRUE;
return NumOfBytesToRead;
}
Идентификатор id в GGDHeader это строка (НЕ оканчивающаяся нулем) зашифрованная по методу NOT (или XOR 0xFF, если так больше нравится). Может иметь значения 'FULL', 'HIGH', '256G' и возможно, какие-то еще.
Если будешь писать конвертер графики, выложу соответствующую информацию.
Функция буферизованого чтения (BufferizedRead) вытащена исключительно из любви к искусству. Тебе она, по большому гамбургскому счету, нафиг не нужна - проще прочитать один раз весь файл в память, а затем 'скармливать' его функции распаковки по кусочкам, как это делает анпакер GG2.
Вопросы сюда. >__<
EDIT: слегка подправил код.
Сообщение отредактировал Serke: 19 Февраль 2008 - 18:13