Список форумов shedevr.org.ru shedevr.org.ru
Группа перевода приставочных игр "ШЕДЕВР"
 
 FAQFAQ   ПоискПоиск   ПользователиПользователи   ГруппыГруппы   РегистрацияРегистрация 
 ПрофильПрофиль   Войти и проверить личные сообщенияВойти и проверить личные сообщения   ВходВход 

Сжатие графики

 
Начать новую тему   Ответить на тему    Список форумов shedevr.org.ru -> Экстремальный ромхакинг
Предыдущая тема :: Следующая тема  
Автор Сообщение
Shiru



Зарегистрирован: 25.10.2006
Сообщения: 295
Откуда: Russia, Moscow

СообщениеДобавлено: Пн Окт 22, 2007 10:20 pm    Заголовок сообщения: Сжатие графики Ответить с цитатой

Вопрос не имеет отношения к переводам игр, но, думаю, местные ромхакеры могут на него ответить.

Ищутся алгоритмы и процедуры сжатия графики, для которых написаны упаковщики (и распаковщики). В основном интересуют алгоритмы, распаковывающие графику непосредственно в видеопамять, без буфера в основной памяти (большого, по крайней мере) - когда распаковщик не использует уже распакованные данные (как LZ-подобные алгоритмы), или использует только небольшую их часть. Самые простейшие реализации RLE, конечно, не интересуют.

Нужно это для нахождения наиболее эффективного алгоритма для последующего использования в homebrew-разработках для SMD (м.б. и для других платформ). Требуется наличие исходного кода пакера-депакера на любом языке. Предполагаю, что у тех, кто занимался заменой сжатой графики в играх, найдётся что-нибудь подходящее.
Вернуться к началу
Посмотреть профиль Отправить личное сообщение Посетить сайт автора
HoRRoR
RRC2008
RRC2008


Зарегистрирован: 21.06.2006
Сообщения: 2341
Откуда: Ростов-на-Дону

СообщениеДобавлено: Пн Окт 22, 2007 10:46 pm    Заголовок сообщения: Ответить с цитатой

У Джинна есть отличные коды, но без его согласия выкладывать не буду.
Вот, например, процедуры распаковки/запаковки LZ77. Алгоритм оперирует Word'ами:
Код:

Procedure UnPack(var Buffer: Pointer);
var BW: pointer; B: ^byte; W, Pos, RPos, WPos: ^Word; CByte, Size, CurSize: DWord;
DW: ^DWord; Flag: Boolean;
n, m: Integer;  Back, TW: Word;
Count: byte;
begin
CurSize:=0;
DW:=Addr(Buffer^);
Inc(DW);
Size:=DW^;
GetMem(BW,Size);
Inc(DW);
Pos:=Addr(Buffer^);
WPos:=Addr(BW^);
While CurSize<Size do
begin
  CByte:=DW^;
  Pos:=Addr(DW^);
  Inc(Pos,2);
  Inc(DW,17);
  For n:=0 to 31 do
  begin
    If CurSize>Size then break;
    Flag:=Boolean((CByte shr n) and 1); //Выдвигаем байт
    If Flag=True then //Просто копируем
    begin
      WPos^:=Pos^;
      Inc(Wpos); Inc(Pos); Inc(CurSize,2);
    end else
    begin
      B:=Addr(Pos^);
      Count:=B^;
      Back:=B^;
      Inc(B);
      TW:=B^;
      Back:=(Back SHR 5)+(TW SHL 3);
      Count:= Count SHL 3;
      Count:= Count SHR 3;

       If Back=0 then Back:=$7FF;
       RPos:=Addr(WPos^);
       Inc(RPos, -Back);
       For m:=0 to Count+1 do
       begin
        If Back*2<=CurSize then
        begin
          WPos^:=RPos^;
          Inc(WPos); Inc(RPos); Inc(CurSize, 2);
        end else
        begin
          WPos^:=0;
          Inc(WPos); Inc(RPos); Inc(CurSize, 2);
        end;
       end;
       Inc(Pos);
    end;
  end;
end;
FreeMem(Buffer);
Buffer:=BW;
end;


Запаковка вроде работает, но игра не всегда принимает:
Код:

Function Pack(var Buf: Pointer; Size: Integer; Lev: Word): Integer;
var BW: Pointer; W: ^Word; B: ^Byte; DW: ^DWord; CurSize, ASize: DWord;
Pos, CPos, CRPos, BPos, RPos, WPos: ^Word; BestRes: Word; lv, Cnt: Integer;
n,m,l: Integer;
UDWord: ^DWord;
begin
  GetMem(BW, Size+(Size div 64)+8);
  Pos:=Addr(Buf^);
  Inc(Pos,$800);
  WPos:=Addr(BW^);
  WPos^:=$7057; Inc(WPos); WPos^:=$3631; Inc(Wpos);
  WPos^:=Size AND $0000FFFF; Inc(WPos); WPos^:=Size SHR 16; Inc(WPos);
  CurSize:=0;
  ASize:=8;
  While CurSize<Size do
  begin
    UDWord:=Addr(WPos^);
    UDWord^:=0;
    Inc(WPos,2);
    Inc(ASize,4);
    For n:=0 to 31 do
    begin
      UDWord^:=UDWord^ SHR 1;
      BestRes:=0;
      //-
      RPos:=Addr(Pos^);
      If CurSize<lev*2 then lv:=CurSize div 2+8 else lv:=lev;
      Inc(RPos, -lv);
      For m:=0 to lv-1 do
      begin
        If BestRes>=32 then break;
        If RPos^=Pos^ then
        begin
          CPos:=Addr(Pos^);
          CRPos:= Addr(RPos^);
          Inc(CPos); Inc(CRPos);
          Cnt:=1;
          While (CPos^=CRPos^) and (Cnt<=32) and (CRPos<>Pos) and (CurSize+Cnt<Size) do
          begin
            Inc(CPos); Inc(CRPos);  Inc(Cnt);
          end;
          If {Integer(CRPos)-Integer(RPos)+1}Cnt>=BestRes then
          begin
            BestRes:=Cnt{Integer(CRPos)-Integer(RPos)-1};
            BPos:=Addr(RPos^);
          end;
        end;
        Inc(RPos);
      end;

      //If BestRes>=31 then WriteLn(IntToStr(BestRes));
      If BestRes>1 Then
      begin
        WPos^:=(((Integer(Pos)-Integer(BPos){-1}) div 2) SHL 5)+BestRes-2;
        Inc(WPos);
        Inc(CurSize,(BestRes-1)*2);
        Inc(ASize,2);
        Inc(Pos, BestRes);
      end else
      begin
        Inc(UDWord^,$80000000);
        WPos^:=Pos^;
        Inc(WPos); Inc(Pos);
        Inc(ASize,2); Inc(CurSize,2);
      end;
      //WriteLn(IntToHex(UDWord^,8));
      If CurSize>Size then break;
    end;
  end;
  Result:=ASize;
  FreeMem(Buf);
  Buf:=BW;
end;

Ещё есть процедуры на VB, но это были пробы пера. Вроде и на Дельфи ещё были... Если найду - выложу.
--
З.Ы. Посмотрел я на этот свой недавний код (который чуть выше)... Мда... Сейчас бы сделал намного лучше и оптимальней.
_________________
Работаю за деньги
KILL ALL HUMANS!!!!!111
Вернуться к началу
Посмотреть профиль Отправить личное сообщение Отправить e-mail Посетить сайт автора
Djinn
RRC2008
RRC2008


Зарегистрирован: 16.03.2004
Сообщения: 633
Откуда: Москва

СообщениеДобавлено: Чт Ноя 01, 2007 7:04 pm    Заголовок сообщения: Ответить с цитатой

Huffman на GBA

Распаковка:
Код:

Function HuffDecompress(Var Source, Dest): Integer;
Var
 Src, Dst, Header, TreeSize, TreeStart, Mask, Data, RootNode: DWord;
 CurrentNode, WriteValue, HalfLen, Value, Pos, ByteShift: DWord;
 ByteCount: Integer; WriteData: Boolean; Len: Integer;
begin
 LastHufSize := 0;
 Src := DWord(Addr(Source));
 Dst := DWord(Addr(Dest));
 Header := PDWord(Src)^;
 Inc(Src, 4);
 Inc(LastHufSize, 4);
 TreeSize := PByte(Src)^;
 TreeStart := Src + 1;
 Inc(Src, (TreeSize + 1) shl 1);
 Inc(LastHufSize, (TreeSize + 1) shl 1);
 Len := Header shr 8;
 Result := Len;
 Mask := $80000000;
 Data := PDWord(Src)^;
 Inc(Src, 4);
 Inc(LastHufSize, 4);
 Pos := 0;
 RootNode := PByte(TreeStart)^;
 CurrentNode := RootNode;
 WriteData := False;
 ByteShift := 0;
 ByteCount := 0;
 WriteValue := 0;
 if Header and $0F = 8 then
 begin
  While Len > 0 do
  begin
   If Pos = 0 then Inc(Pos) Else Inc(Pos, (((CurrentNode and $3F) + 1) shl 1));
   If Data and Mask <> 0 then
   begin
    If CurrentNode and $40 <> 0 then WriteData := True;
    CurrentNode := PByte(TreeStart + Pos + 1)^;
   end Else
   begin
    If CurrentNode and $80 <> 0 then WriteData := True;
    CurrentNode := PByte(TreeStart + Pos)^;
   end;
   If WriteData then
   begin
    WriteValue := WriteValue or (CurrentNode shl ByteShift);
    Inc(ByteCount);
    Inc(ByteShift, 8);
    Pos := 0;
    CurrentNode := RootNode;
    WriteData := False;
    If ByteCount = 4 then
    begin
     ByteCount := 0;
     ByteShift := 0;
     PDWord(Dst)^ := WriteValue;
     WriteValue := 0;
     Inc(Dst, 4);
     Dec(Len, 4);
    end;
   end;
   Mask := Mask shr 1;
   If Mask = 0 then
   begin
    Mask := $80000000;
    Data := PDWord(Src)^;
    Inc(Src, 4);
    Inc(LastHufSize, 4);
   end;
  end;
 end Else
 begin
  HalfLen := 0;
  Value := 0;
  While Len > 0 do
  begin
   If Pos = 0 then Inc(Pos) Else Inc(Pos, (((CurrentNode and $3F) + 1) shl 1));
   If Data and Mask <> 0 then
   begin
    If CurrentNode and $40 <> 0 then WriteData := True;
    CurrentNode := PByte(TreeStart + Pos + 1)^;
   end Else
   begin
    If CurrentNode and $80 <> 0 then WriteData := True;
    CurrentNode := PByte(TreeStart + Pos)^;
   end;
   If WriteData then
   begin
    If HalfLen = 0 then
     Value := Value or CurrentNode Else
     Value := Value or (CurrentNode shl 4);
    Inc(HalfLen, 4);
    If HalfLen = 8 then
    begin
     WriteValue := WriteValue or (Value shl ByteShift);
     Inc(ByteCount);
     Inc(ByteShift, 8);
     HalfLen := 0;
     Value := 0;
     If ByteCount = 4 then
     begin
      ByteCount := 0;
      ByteShift := 0;
      PDWord(Dst)^ := WriteValue;
      WriteValue := 0;
      Inc(Dst, 4);
      Dec(Len, 4);
     end;
    end;
    Pos := 0;
    CurrentNode := RootNode;
    WriteData := False;
   end;
   Mask := Mask shr 1;
   If Mask = 0 then
   begin
    Mask := $80000000;
    Data := PDWord(Src)^;
    Inc(Src, 4);
    Inc(LastHufSize, 4);
   end;
  end;
 end;
end;


Упаковка:
Код:
Type
 PFreq = ^TFreq;
 TFreq = Record
  Count: Integer;
  Code: Integer;
  HCode: DWord;
  LRbit: DWord;
  Pos: Integer;
  Left: PFreq;
  Right: PFreq;
  Next: PFreq;
 end;
 TFreqs = Class
  Root: PFreq;
  Count: Integer;
  Constructor Create;
  Function Add: PFreq;
  Function MakeParent: Boolean;
  Destructor Destroy; override;
 end;

Constructor TFreqs.Create;
begin
 Root := NIL;
 Count := 0;
end;

Function TFreqs.Add: PFreq;
begin
 New(Result);
 FillChar(Result^, SizeOf(TFreq), 0);
 Result^.Code := -1;
 Result^.Next := Root;
 Root := Result;
 Inc(Count);
end;

Destructor TFreqs.Destroy;
Procedure FreeNodes(Node: PFreq);
begin
 If Node <> NIL then
 begin
  FreeNodes(Node^.Left);
  FreeNodes(Node^.Right);
  Dispose(Node^.Left);
  Dispose(Node^.Right);
 end;
end;
Var N: PFreq;
begin
 While Root <> NIL do
 begin
  With Root^ do
  begin
   N := Next;
   FreeNodes(Left);
   Dispose(Left);
   FreeNodes(Right);
   Dispose(Right);
  end;
  Dispose(Root);
  Root := N;
 end;
 Count := 0;
 Inherited Destroy;
end;

Function TFreqs.MakeParent: Boolean;
Function FindMin: PFreq;
Var I: Integer; P, N: PFreq;
begin
 I := $7FFFFFFF;
 N := Root;
 P := NIL;
 While N <> NIL do With N^ do
 begin
  If I > Count then
  begin
   I := Count;
   P := N;
  end;
  N := Next;
 end;
 N := Root;
 If N = P then
 begin
  Root := N^.Next;
  P^.Next := NIL;
  Dec(Count);
  Result := P;
  Exit;
 end;
 While N <> NIL do
 begin
  If P = N^.Next then
  begin
   N^.Next := P^.Next;
   P^.Next := NIL;
   Dec(Count);
   Result := P;
   Exit;
  end;
  N := N^.Next;
 end;
 Result := NIL;
end;
Var A, B, N: PFreq;
begin
 Result := False;
 A := FindMin;
 B := FindMin;
 If B = NIL then
 begin
  Root := A;
  Exit;
 end;
 If Root <> NIL then With Add^ do
 begin
  Left := B;
  Right := A;
  Code := -1;
  Count := A^.Count + B^.Count;
  Result := True;
 end Else
 begin
  New(N);
  FillChar(N^, SizeOf(TFreq), 0);
  With N^ do
  begin
   Left := B;
   Right := A;
   Code := -1;
   Count := A^.Count + B^.Count;
  end;
  Root := N;
  Inc(Count);
  Result := False;
 end;
end;

Var HVar: Boolean;

Function CreateTree(Var Dest; Root: PFreq): DWord;
Function NodePos(L, R: PFreq; Pos: DWord): DWord;
begin
 If L <> NIL then
 begin
  L^.Pos := Pos;
  R^.Pos := Pos + 1;
  Result := NodePos(R^.Left, R^.Right, NodePos(L^.Left, L^.Right, Pos + 2));
 end Else Result := Pos;
end;
Var B: PBytes;
Procedure PutNode(N: PFreq);
Var I: Integer;
begin
 If HVar then Exit;
 If N <> NIL then With N^ do
 begin
  If Code = -1 then
  begin
   I := (Left^.Pos - (Pos - Integer(not Odd(Pos)))) shr 1 - 1;
   If I > $3F then
   begin
    HVar := True;
    Exit;
   end;
   B^[Pos] := I + Byte(Left^.Left = NIL) shl 7 +
                     Byte(Right^.Left = NIL) shl 6;
  end Else
   B^[Pos] := Code;
  PutNode(Left);
  PutNode(Right);
 end;
end;
begin
 Result := 0;
 If Root = NIL then Exit;
 With Root^ do
 begin
  Pos := 0;
  Result := NodePos(Left, Right, 1);
 end;
 B := Addr(Dest);
 HVar := False;
 PutNode(Root);
 If HVar then Result := 0;
end;
Function HuffCompress(Var Source, Dest; SrcLen: Integer; Bit8: Boolean): Integer;
Var Codes: Array[Byte] of Packed Record Code: DWord; Size: DWord end;
Procedure AnalizeCodes(Node: PFreq; A, B: Integer);
Var I: Integer;
begin
 I := Node^.Code;
 If I <> -1 then
 begin
  Codes[I].Size := A;
  Codes[I].Code := B;
 end;
 With Node^ do
 begin
  HCode := B;
  If Left = NIL then Exit;
  Left^.LRbit := 1;
  Right^.LRbit := 0;
  AnalizeCodes(Left, A + 1, B + B);
  AnalizeCodes(Right, A + 1, (B + B) or 1);
 end;
end;
Var
 S: PBytes; Dst: DWord; I: Integer; Bit: DWord;
 Frs: TFreqs; Freqs: Array[Byte] of DWord; DataSize, Old: DWord;
 Header: DWord Absolute Dest; TSZ: PByte; NCount: Integer;
 MasX: DWord;
Procedure AddCode(aCode: Byte);
Var Mask: DWord;
begin
 With Codes[aCode] do
 begin
  Mask := 1 shl (Size - 1);
  While Mask > 0 do
  begin
   If aCode and Mask = 0 then
    PDWord(DST)^ := PDWord(DST)^ and not MasX Else
    PDWord(DST)^ := PDWord(DST)^ or MasX;
   Mask := Mask shr 1;
   MasX := MasX shr 1;
   If MasX = 0 then
   begin
    Inc(Dst, 4);
    MasX := $80000000;
   end;
  end;
  Inc(Bit, Size);
  If Bit div 32 > Old then
  begin
   Inc(DataSize, 4);
   Old := Bit div 32;
  end;
 end;
end;
begin
 FillChar(Freqs, SizeOf(Freqs), 0);
 S := Addr(Source);
 Dst := DWord(Addr(Dest));
 Frs := TFreqs.Create;
 If not Bit8 then
 begin
  For I := 0 to SrcLen - 1 do
  begin
   Inc(Freqs[S^[I] and $0F]);
   Inc(Freqs[S^[I] shr 4]);
  end;
 end Else For I := 0 to SrcLen - 1 do Inc(Freqs[S^[I]]);
 With Frs do
 begin
  For I := 0 to 255 do If Freqs[I] <> 0 then With Add^ do
  begin
   Code := I;
   Count := Freqs[I];
  end;
  While MakeParent do;
  FillChar(Codes, SizeOf(Codes), 0);
  AnalizeCodes(Root, 0, 0);
  Header := SrcLen shl 8 + $24;
  If Bit8 then Inc(Header, 4);
  Inc(Dst, 4);
  Tsz := PByte(Dst);
  NCount := CreateTree(Pointer(Dst + 1)^, Root) + 1;
  While NCount mod 4 > 0 do Inc(NCount);
  Inc(Dst, NCount);
  NCount := NCount shr 1 - 1;
  If not HVar and (NCount <= 255) then
  begin
   Tsz^ := NCount;
   Result := (NCount + 1) shl 1 + 4;
   Bit := 0; DataSize := 4; Old := 0;
   MasX := $80000000;
   If Bit8 then For I := 0 to SrcLen - 1 do AddCode(S^[I]) Else
   For I := 0 to SrcLen - 1 do
   begin
    AddCode(S^[I] and $0F);
    AddCode(S^[I] shr 4);
   end;
   Inc(Result, DataSize);
  end Else Result := 0;
 end;
 Frs.Free;
end;
Вернуться к началу
Посмотреть профиль Отправить личное сообщение Отправить e-mail Посетить сайт автора
HoRRoR
RRC2008
RRC2008


Зарегистрирован: 21.06.2006
Сообщения: 2341
Откуда: Ростов-на-Дону

СообщениеДобавлено: Ср Дек 19, 2007 12:20 am    Заголовок сообщения: Ответить с цитатой

http://consolgames.4bb.ru/viewtopic.php?id=27
Второй пост.
_________________
Работаю за деньги
KILL ALL HUMANS!!!!!111
Вернуться к началу
Посмотреть профиль Отправить личное сообщение Отправить e-mail Посетить сайт автора
org



Зарегистрирован: 03.10.2007
Сообщения: 6

СообщениеДобавлено: Ср Дек 19, 2007 3:24 pm    Заголовок сообщения: Ответить с цитатой

Алгоритм сжатия 'SZP' (модифицированный вариант LZ), используемый на Gamecube:

Код:
#define SZP_ALLOC   malloc
#define SZP_FREE    free
#define SZP_MAGIC   (('0'<<24)+('y'<<16)+('a'<<8)+'Y')  // Yay0

typedef struct SZP_S        // Szp Header.
{
    u32 check;
    u32 decodedSize;
    u32 linkOffset;
    u32 chunkOffset;
    #pragma warning (disable: 4200)
    u32 flagTable[];
} SZP_S;

// Encodes a data range in a SZP block.
// In: Memory mapped source buffer and its length in bytes.
// Out: Pre-allocated destination buffer (recommended length is twice as source),
// compressed buffer length in bytes.
void SZP_Compress(void *dest, int *encodedSize, void *src, int srcLen)
{
    #define OFSBITS     12

    u8 * decodedBuffer = (u8 *)src, *encodedBuffer = (u8 *)dest;
    u32 decodedSize = srcLen;
    u8 * decPtr, * decEndPtr;
    SZP_S * header;

    // masks buffer
    u32 maskMaxSize = (decodedSize + 32) >> 3; // 1 bit per byte
    u32 maskSize = 0;
    u32 maskBitCount = 0, mask = 0;
    u32 * maskBuffer, * maskPtr,  * maskEndPtr;

    // links buffer
    u32 linkMaxSize = decodedSize;
    u32 linkSize = 0;
    u16 link = 0;
    u16 linkOffset;
    u16 * linkBuffer, * linkPtr,  * linkEndPtr;
    u16 maxOffset = 1 << OFSBITS;
    u16 minCount = 3, maxCount = 273;

    // chunks buffer
    u32 chunkMaxSize = decodedSize;
    u32 chunkSize = 0;
    u8 chunk = 0;
    u8 * chunkBuffer, * chunkPtr,  * chunkEndPtr;

    u8 *windowPtr;
    int windowLen = 0, length, maxlen;

    // Re-allocate memory needed

    maskBuffer = (u32 *) SZP_ALLOC(maskMaxSize);
    linkBuffer = (u16 *) SZP_ALLOC(linkMaxSize);
    chunkBuffer = (u8 *) SZP_ALLOC(chunkMaxSize);

    if (maskBuffer == NULL || linkBuffer == NULL || chunkBuffer == NULL) {
        SZP_FREE(maskBuffer);
        SZP_FREE(linkBuffer);
        SZP_FREE(chunkBuffer);
        return;
    }

    memset(maskBuffer, 0, maskMaxSize);
    //memset(linkBuffer, 0, linkMaxSize);       // Unnecessary.
    //memset(chunkBuffer, 0, chunkMaxSize);

    //set pointers
    decPtr = decodedBuffer;
    decEndPtr = decPtr + decodedSize;

    maskPtr = maskBuffer;
    maskEndPtr = (u32 *)((u8 *)maskPtr + maskMaxSize);

    linkPtr = linkBuffer;
    linkEndPtr = (u16 *)((u8 *)linkPtr + linkMaxSize);

    chunkPtr = chunkBuffer;
    chunkEndPtr = chunkPtr + chunkMaxSize;
    windowPtr = decPtr;

    // start enconding
    while (decPtr < decEndPtr) {

        if(windowLen >= (1 << OFSBITS))
        {
            windowLen = windowLen - (1 << OFSBITS);
            windowPtr = decPtr - windowLen;
        }

        if((decEndPtr - decPtr) < maxCount) maxCount = (decEndPtr - decPtr);

        // Scan through the window.
        maxlen = 0;
        for(int i=0; i<windowLen; i++)
        {
            for(length=0; length<(windowLen-i) && length<maxCount; length++)
            {
                if(decPtr[length] != windowPtr[length+i]) break;
            }
            if(length > maxlen)
            {
                maxlen = length;
                linkOffset = windowLen - i;
            }
        }
        length = maxlen;

        mask <<= 1;
        if(length >= minCount)      // Add Link
        {
            link = (linkOffset - 1) & 0x0FFF;

            if (length < 18) {
                link |= ((length - 2) << 12) ;
            }
            else{
                // store current count as a chunk.
                *chunkPtr++ = (u8)(length - 18);
            }

            *linkPtr++ = Swap16(link);
            decPtr += length;
            windowLen += length;
        }
        else                        // Add single byte, increase Window.
        {
            *chunkPtr++ = *decPtr++;
            windowLen++;
            mask |= 1;
        }

        maskBitCount++;
        if (maskBitCount == 32) {
            // store current mask
            *maskPtr = Swap32(mask);
            maskPtr++;
            maskBitCount = 0;
        }
    }

    //flush mask
    if (maskBitCount > 0) {
        mask <<= (32 - maskBitCount);
        // store current mask
        *maskPtr = Swap32(mask);
        maskPtr++;
        maskBitCount = 0;
    }

    // now join all pieces
    maskSize = (u32)((u8 *)maskPtr - (u8 *)maskBuffer);
    linkSize = (u32)((u8 *)linkPtr - (u8 *)linkBuffer);
    chunkSize = (u32)((u8 *)chunkPtr - (u8 *)chunkBuffer);

    *encodedSize = sizeof(SZP_S) + maskSize + linkSize + chunkSize;
    header = (SZP_S *)encodedBuffer;

    // swap arch. dependent data
    header->check = SZP_MAGIC;
    header->decodedSize = Swap32(decodedSize);
    header->linkOffset = Swap32(sizeof(SZP_S) + maskSize);
    header->chunkOffset = Swap32(sizeof(SZP_S) + maskSize + linkSize);

    // copy all buffer to final buffer
    memcpy((u8 *)header + sizeof(SZP_S), maskBuffer, maskSize);
    memcpy((u8 *)header + sizeof(SZP_S) + maskSize, linkBuffer, linkSize);
    memcpy((u8 *)header + sizeof(SZP_S) + maskSize + linkSize, chunkBuffer, chunkSize);

    SZP_FREE(maskBuffer);
    SZP_FREE(linkBuffer);
    SZP_FREE(chunkBuffer);
}

// Decodes an SZP block. Decoding is incredibly fast!
// In: Memory mapped compressed buffer and its length in bytes.
// Out: Pre-allocated destination buffer (length can be obtained from buffer's
// header), decompressed buffer length in bytes.
void SZP_Decompress(void *dest, int *destLen, void *src, int srcLen)
{
    u8 * encodedBuffer = (u8 *)src;
    SZP_S * header;
    u8 * decodedBuffer;

    u32 decodedBytes, decodedSize, linkOffset, chunkOffset;
    u32 mask, maskBitsLeft, maskOffset;

    u32 aux;
    header =  (SZP_S *)encodedBuffer;
    decodedSize = Swap32(header->decodedSize);      // size of decoded data
    linkOffset = Swap32(header->linkOffset);      // link table
    chunkOffset = Swap32(header->chunkOffset);     // byte chunks and count modifiers
    decodedBytes = 0;                     // current offset in dest buffer
    maskBitsLeft = 0;                   // mask bit counter
    maskOffset = 16;                    // current offset in mask table

    decodedBuffer = (u8 *)dest;

    //memset(decodedBuffer, 0, decodedSize);
    *destLen = decodedSize;

    do
    {

        // if all bits are done, get next mask
        if(maskBitsLeft == 0)
        {
            // read word from mask data block
            mask = Swap32(*(u32 *)(encodedBuffer + maskOffset));
            maskOffset += 4;
            maskBitsLeft = 32;   // bit counter
        }

        // if next bit is set, chunk is non-linked
        if(mask & 0x80000000)
        {
            // get next byte
            *(u8 *)(decodedBuffer + decodedBytes) = *(u8 *)(encodedBuffer + chunkOffset);
            chunkOffset++, decodedBytes++;
        }
        // do copy, otherwise
        else
        {
            u16 link;
            u32 count;
            u8 * pointer;

            // read 16-bit from link table
            link = Swap16(*(u16 *)(encodedBuffer + linkOffset));

            linkOffset += 2;
             // 'offset'
            pointer = decodedBuffer + decodedBytes - ( (link & 0xfff) + 1);
             // 'count'
            count = link >> 12;

            if(count == 0)
            {
                // get 'count' from chunks table
                count = *(u8 *)(encodedBuffer + chunkOffset) + 18;
                chunkOffset++;
            }
            else count += 2;

            // do block copy
            for(aux=0; aux<count; aux++)
            {
                *(u8 *)(decodedBuffer + decodedBytes) = *pointer;
                decodedBytes++, pointer++;
            }
   
        }

        // next bit in mask
        mask <<= 1;
        maskBitsLeft--;
    } while(decodedBytes < decodedSize);
}
Вернуться к началу
Посмотреть профиль Отправить личное сообщение
Показать сообщения:   
Начать новую тему   Ответить на тему    Список форумов shedevr.org.ru -> Экстремальный ромхакинг Часовой пояс: GMT + 3
Страница 1 из 1

 
Перейти:  
Вы не можете начинать темы
Вы можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах


Powered by phpBB © 2001, 2005 phpBB Group