├── README.md ├── explode.c ├── explode.h ├── gui ├── gwimp.ico ├── gwimp.lpi ├── gwimp.lpr ├── gwimp_Icon.ico ├── uFimp.pas ├── uMain.lfm └── uMain.pas ├── implode.c └── implode.h /README.md: -------------------------------------------------------------------------------- 1 | # AmigaImploder 2 | Amiga Imploder Open Source (decompiled) 3 | 4 | Fully restored (decompiled) Amiga's Imploder compression algorithm. 5 | -------------------------------------------------------------------------------- /explode.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | static unsigned char explode_token_base[4] = { 6, 10, 10, 18 }; 4 | static unsigned char static_token_extra_bits[12] = { 1, 1, 1, 1, 2, 3, 3, 4, 4, 5, 7, 14 }; 5 | 6 | unsigned char *src, *cmpr_data; 7 | unsigned int write_pos, src_size, src_end /*a4*/, token_run_len /*d2*/; 8 | int cmpr_pos /*a3*/; 9 | 10 | unsigned char token; 11 | 12 | unsigned short run_base_off_tbl[8]; 13 | unsigned char run_extra_bits_tbl[12]; 14 | 15 | static void copy_bytes(unsigned char *dst, unsigned char *src, int count){ 16 | for (int i = 0; i < count; i++){ 17 | dst[i] = src[i]; 18 | } 19 | } 20 | 21 | static unsigned short read_word(unsigned char *buf){ 22 | return ((buf[0] << 8) | buf[1]); 23 | } 24 | 25 | static unsigned int read_dword(unsigned char *buf){ 26 | return ((read_word(&buf[0]) << 16) | read_word(&buf[2])); 27 | } 28 | 29 | static void write_word(unsigned char *dst, unsigned short value){ 30 | dst[0] = (value >> 8) & 0xFF; 31 | dst[1] = (value >> 0) & 0xFF; 32 | } 33 | 34 | static void write_dword(unsigned char *dst, unsigned int value){ 35 | write_word(&dst[0], (value >> 16) & 0xFFFF); 36 | write_word(&dst[2], (value >> 0) & 0xFFFF); 37 | } 38 | 39 | unsigned int read_bits(unsigned char count){ 40 | unsigned int retn = 0; 41 | 42 | for (int i = 0; i < count; i++){ 43 | char bit = (token >> 7); 44 | token <<= 1; 45 | 46 | if (!token){ 47 | token = (cmpr_data[cmpr_pos-1] << 1) | bit; 48 | bit = (cmpr_data[--cmpr_pos] >> 7); 49 | } 50 | 51 | retn <<= 1; 52 | retn |= bit; 53 | } 54 | return retn; 55 | } 56 | 57 | int check_imp(unsigned char *input){ 58 | unsigned int id, end_off, out_len; 59 | 60 | if (!input){ 61 | return 0; 62 | } 63 | 64 | id = read_dword(&input[0]); 65 | out_len = read_dword(&input[4]); 66 | end_off = read_dword(&input[8]); 67 | 68 | /* check for magic ID 'IMP!', or one of the other IDs used by Imploder 69 | clones; ATN!, BDPI, CHFI, Dupa, EDAM, FLT!, M.H., PARA and RDC9 */ 70 | if (id != 0x494d5021 && id != 0x41544e21 && id != 0x42445049 && id != 0x43484649 && id != 0x44757061 && 71 | id != 0x4544414d && id != 0x464c5421 && id != 0x4d2e482e && id != 0x50415241 && id != 0x52444339){ 72 | return 0; 73 | } 74 | 75 | /* sanity checks */ 76 | return !((end_off & 1) || (end_off < 14) || ((end_off + 0x26) > out_len)); 77 | } 78 | 79 | int explode(unsigned char *input){ 80 | if (!check_imp(input)){ 81 | return 0; 82 | } 83 | 84 | write_pos = 0, src_size = 0, src_end = 0 /*a4*/, token_run_len = 0 /*d2*/; 85 | cmpr_pos = 0 /*a3*/; 86 | token = 0; 87 | 88 | src = input; 89 | src_end = src_size = read_dword(&src[0x04]); 90 | cmpr_data = &src[read_dword(&src[0x08])]; 91 | cmpr_pos = 0; 92 | 93 | write_dword(&src[0x08], read_dword(&cmpr_data[0x00])); 94 | write_dword(&src[0x04], read_dword(&cmpr_data[0x04])); 95 | write_dword(&src[0x00], read_dword(&cmpr_data[0x08])); 96 | 97 | token_run_len = read_dword(&cmpr_data[0x0C]); 98 | 99 | if (!(cmpr_data[0x10] & 0x80)){ 100 | cmpr_pos--; 101 | } 102 | 103 | token /*d3*/ = cmpr_data[0x11]; 104 | 105 | for (int i = 0; i < 8; i++){ 106 | /*a1*/run_base_off_tbl[i] = read_word(&cmpr_data[0x12+i*2]); 107 | } 108 | 109 | copy_bytes(&run_extra_bits_tbl[0], &cmpr_data[0x22], 12); 110 | //int cnt = 0; 111 | while (1){ 112 | for (int i = 0; (i < token_run_len) && (src_end > 0); i++){ 113 | src[--src_end] = cmpr_data[--cmpr_pos]; 114 | } 115 | 116 | if (src_end == 0){ 117 | break; 118 | } 119 | 120 | unsigned int match_len, selector; 121 | 122 | if (read_bits(1)){ 123 | if (read_bits(1)){ 124 | if (read_bits(1)){ 125 | if (read_bits(1)){ 126 | if (read_bits(1)){ 127 | match_len = cmpr_data[--cmpr_pos]; 128 | selector = 3; 129 | } 130 | else{ 131 | match_len = read_bits(3) + 6; 132 | selector = 3; 133 | } 134 | } 135 | else{ 136 | match_len = 5; 137 | selector = 3; 138 | } 139 | } 140 | else{ 141 | match_len = 4; 142 | selector = 2; 143 | } 144 | } 145 | else{ 146 | match_len = 3; 147 | selector = 1; 148 | } 149 | } 150 | else{ 151 | match_len = 2; 152 | selector = 0; 153 | } 154 | 155 | if (read_bits(1)){ 156 | if (read_bits(1)){ 157 | token_run_len = read_bits(static_token_extra_bits[selector+8]) + explode_token_base[selector]; 158 | } 159 | else{ 160 | token_run_len = read_bits(static_token_extra_bits[selector+4]) + 2; 161 | } 162 | } 163 | else{ 164 | token_run_len = read_bits(static_token_extra_bits[selector]); 165 | } 166 | 167 | unsigned char *match; 168 | 169 | if (read_bits(1)){ 170 | if (read_bits(1)){ 171 | match = &src[src_end + read_bits(run_extra_bits_tbl[8+selector]) + run_base_off_tbl[4+selector] + 1]; 172 | } 173 | else{ 174 | match = &src[src_end + read_bits(run_extra_bits_tbl[4+selector]) + run_base_off_tbl[selector] + 1]; 175 | } 176 | } 177 | else{ 178 | match = &src[src_end + read_bits(run_extra_bits_tbl[selector]) + 1]; 179 | } 180 | 181 | //printf("%06X-%06X\n", match_len, src_end); cnt++; 182 | 183 | for (int i = 0; (i < match_len) && (src_end > 0); i++){ 184 | src[--src_end] = *--match; 185 | } 186 | } 187 | 188 | return src_size; 189 | } 190 | 191 | int imploded_size(unsigned char *input){ 192 | if(!check_imp(input)) return 0; 193 | 194 | return read_dword(&input[8]) + 0x32; 195 | } 196 | 197 | int exploded_size(unsigned char *input){ 198 | if(!check_imp(input)) return 0; 199 | 200 | return read_dword(&input[4]); 201 | } 202 | -------------------------------------------------------------------------------- /explode.h: -------------------------------------------------------------------------------- 1 | int explode(unsigned char *input); 2 | int imploded_size(unsigned char *input); 3 | int check_imp(unsigned char *input); 4 | int exploded_size(unsigned char *input); 5 | -------------------------------------------------------------------------------- /gui/gwimp.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lab313ru/AmigaImploder/8056f12a4d0866781215da039d59aae47652803e/gui/gwimp.ico -------------------------------------------------------------------------------- /gui/gwimp.lpi: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | <UseAppBundle Value="False"/> 16 | <ResourceType Value="res"/> 17 | <UseXPManifest Value="True"/> 18 | <XPManifest> 19 | <DpiAware Value="True"/> 20 | </XPManifest> 21 | <Icon Value="0"/> 22 | </General> 23 | <i18n> 24 | <EnableI18N LFM="False"/> 25 | </i18n> 26 | <VersionInfo> 27 | <StringTable ProductVersion=""/> 28 | </VersionInfo> 29 | <BuildModes Count="2"> 30 | <Item1 Name="Debug" Default="True"/> 31 | <Item2 Name="Release"> 32 | <CompilerOptions> 33 | <Version Value="11"/> 34 | <PathDelim Value="\"/> 35 | <SearchPaths> 36 | <IncludeFiles Value="$(ProjOutDir)"/> 37 | </SearchPaths> 38 | <CodeGeneration> 39 | <SmartLinkUnit Value="True"/> 40 | <TargetCPU Value="i386"/> 41 | <TargetOS Value="win32"/> 42 | <Optimizations> 43 | <OptimizationLevel Value="3"/> 44 | </Optimizations> 45 | </CodeGeneration> 46 | <Linking> 47 | <Debugging> 48 | <GenerateDebugInfo Value="False"/> 49 | </Debugging> 50 | <LinkSmart Value="True"/> 51 | <Options> 52 | <Win32> 53 | <GraphicApplication Value="True"/> 54 | </Win32> 55 | </Options> 56 | </Linking> 57 | </CompilerOptions> 58 | </Item2> 59 | </BuildModes> 60 | <PublishOptions> 61 | <Version Value="2"/> 62 | </PublishOptions> 63 | <RunParams> 64 | <local> 65 | <FormatVersion Value="1"/> 66 | </local> 67 | </RunParams> 68 | <RequiredPackages Count="1"> 69 | <Item1> 70 | <PackageName Value="LCL"/> 71 | </Item1> 72 | </RequiredPackages> 73 | <Units Count="3"> 74 | <Unit0> 75 | <Filename Value="gwimp.lpr"/> 76 | <IsPartOfProject Value="True"/> 77 | </Unit0> 78 | <Unit1> 79 | <Filename Value="uMain.pas"/> 80 | <IsPartOfProject Value="True"/> 81 | <ComponentName Value="frmMain"/> 82 | <HasResources Value="True"/> 83 | <ResourceBaseClass Value="Form"/> 84 | </Unit1> 85 | <Unit2> 86 | <Filename Value="uFimp.pas"/> 87 | <IsPartOfProject Value="True"/> 88 | </Unit2> 89 | </Units> 90 | </ProjectOptions> 91 | <CompilerOptions> 92 | <Version Value="11"/> 93 | <PathDelim Value="\"/> 94 | <SearchPaths> 95 | <IncludeFiles Value="$(ProjOutDir)"/> 96 | </SearchPaths> 97 | <Parsing> 98 | <SyntaxOptions> 99 | <SyntaxMode Value="Delphi"/> 100 | <IncludeAssertionCode Value="True"/> 101 | </SyntaxOptions> 102 | </Parsing> 103 | <CodeGeneration> 104 | <Checks> 105 | <IOChecks Value="True"/> 106 | <RangeChecks Value="True"/> 107 | <OverflowChecks Value="True"/> 108 | <StackChecks Value="True"/> 109 | </Checks> 110 | <TargetCPU Value="i386"/> 111 | <TargetOS Value="win32"/> 112 | </CodeGeneration> 113 | <Linking> 114 | <Debugging> 115 | <DebugInfoType Value="dsDwarf2Set"/> 116 | <UseHeaptrc Value="True"/> 117 | <UseExternalDbgSyms Value="True"/> 118 | </Debugging> 119 | <Options> 120 | <Win32> 121 | <GraphicApplication Value="True"/> 122 | </Win32> 123 | </Options> 124 | </Linking> 125 | </CompilerOptions> 126 | <Debugging> 127 | <Exceptions Count="3"> 128 | <Item1> 129 | <Name Value="EAbort"/> 130 | </Item1> 131 | <Item2> 132 | <Name Value="ECodetoolError"/> 133 | </Item2> 134 | <Item3> 135 | <Name Value="EFOpenError"/> 136 | </Item3> 137 | </Exceptions> 138 | </Debugging> 139 | </CONFIG> 140 | -------------------------------------------------------------------------------- /gui/gwimp.lpr: -------------------------------------------------------------------------------- 1 | program gwimp; 2 | 3 | {$MODE Delphi} 4 | 5 | uses 6 | Forms, Interfaces, 7 | uMain in 'uMain.pas' {frmMain}, 8 | uFimp in 'uFimp.pas'; 9 | 10 | {.$R *.res} 11 | 12 | {$R *.res} 13 | 14 | begin 15 | Application.Initialize; 16 | Application.Title := 'WinImploder GUI [by Lab 313]'; 17 | Application.CreateForm(TfrmMain, frmMain); 18 | Application.Run; 19 | end. 20 | -------------------------------------------------------------------------------- /gui/gwimp_Icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lab313ru/AmigaImploder/8056f12a4d0866781215da039d59aae47652803e/gui/gwimp_Icon.ico -------------------------------------------------------------------------------- /gui/uFimp.pas: -------------------------------------------------------------------------------- 1 | unit uFimp; 2 | 3 | {$MODE Delphi} 4 | 5 | interface 6 | 7 | type 8 | PBytesArray = ^TBytesArray; 9 | TBytesArray = array[0..$800000-1] of Byte; 10 | 11 | function implode(input: PBytesArray; len: Integer; mode: Byte): Integer; cdecl; external 'win_imploder.dll' name 'implode'; 12 | function explode(input: PBytesArray): Integer; cdecl; external 'win_imploder.dll' name 'explode'; 13 | function check_imp(input: PBytesArray): Integer; cdecl; external 'win_imploder.dll' name 'check_imp'; 14 | function imploded_size(input: PBytesArray): Integer; cdecl; external 'win_imploder.dll' name 'imploded_size'; 15 | function exploded_size(input: PBytesArray): Integer; cdecl; external 'win_imploder.dll' name 'exploded_size'; 16 | 17 | implementation 18 | 19 | end. 20 | -------------------------------------------------------------------------------- /gui/uMain.lfm: -------------------------------------------------------------------------------- 1 | object frmMain: TfrmMain 2 | Left = 234 3 | Height = 304 4 | Top = 213 5 | Width = 458 6 | AutoSize = True 7 | BorderIcons = [biSystemMenu] 8 | BorderStyle = bsSingle 9 | Caption = 'WinImploder GUI v2.1 [by Lab 313]' 10 | ClientHeight = 304 11 | ClientWidth = 458 12 | Color = clBtnFace 13 | Font.Color = clWindowText 14 | Font.Height = -11 15 | Font.Name = 'Tahoma' 16 | Icon.Data = { 17 | BE1000000000010001002020000000000000A810000016000000280000002000 18 | 0000400000000100200000000000801000000000000000000000000000000000 19 | 0000000000010000000100000000050101180A0303370E0404470F04044C0D03 20 | 03460D0303480D0404490E0404480D0404470D0404460D0404450D0404440C03 21 | 03430C0303440C0303430C0303430D0303440C0303440C0404450D0404470D04 22 | 04450C0404460E04044A0F0504500F0404470B03033907020223010000090000 23 | 000000000002000000000500001B0E01014A11030356100404450E0505380905 24 | 052F0905052B0804042907040426070404250704042407040525070505260705 25 | 0426070405270804052708040427080404280704042708040428080404270704 26 | 0427070404270804042A0C05053D150808621609096015060665120404610E03 27 | 034400000000040000130D0000440C00003F0B0000330500004D0B0000821500 28 | 00BE150000BA160000BB150000BA150000BA150000B9150000B8140000B71400 29 | 00B5140000B5140000B5140000B5130000B5130000B5140000B8160000BB1700 30 | 00BF190000C71A0000CD1A0000CD1D0000D910000096050000271205055C0C02 31 | 024A010000030A0000340D0000420900002C130000796E5454F48A7374FF9582 32 | 82FFA59494FFA99798FFA99798FFA89697FFA49293FFA49292FFA59293FFA593 33 | 94FFA59393FFA49393FFA39191FFA39091FFA29091FFA39091FFA79596FFAD9C 34 | 9CFFB0A1A1FFB1A1A1FFAF9E9FFFA08E8EFF836B6AFF2C1616A5020000340401 35 | 0116050000150C0000420D0202371800009E553A3AFBFDFCFCFFFFFFFFFDFFFF 36 | FFFDFFFFFFFDFFFFFFFDFFFFFFFDFFFFFFFDFFFFFFFDFFFFFFFDFFFFFFFDFFFF 37 | FFFDFFFFFFFDFFFFFFFEFFFFFFFDFFFFFFFEFFFFFFFEFFFFFFFEFFFFFFFEFFFF 38 | FFFDFFFFFFFDFFFFFFFDFFFFFFFDFFFFFFFDFFFFFFFDDBD1D1FF381C1CCE1C02 39 | 02A90A0001390B00003915060658200000F4978686FDFFFFFFFDCFCFCFFEA8A8 40 | A8FEB0B0B0FEB2B2B2FEB5B4B4FFB5B5B5FDB8B7B7FDBCBBBBFDAFAFAFFEB0AF 41 | AFFDB3B2B2FDB6B6B6FEBCBBBBFDC2C2C2FECFCECEFDC9C9C9FDBCBBBBFEB7B7 42 | B7FDB7B7B7FDBEBDBDFECAC9C9FEE2E2E2FEFDFDFDFFFFFFFFFD816869FD2300 43 | 00FF0F0204560901012E19060678230000F7B8ACACFCFEFEFEFE787777FB0000 44 | 00FE000000FE000000FF000000FF000000FE000000FE1B1C1CFD010101FE0000 45 | 00FE000000FE000000FE020202FE050505FE262626FC1A1A1AFD000000FE0000 46 | 00FE000000FE030303FE090909FE313232FCD1D1D1FDFDFDFDFF927F7FFA2701 47 | 02F20D02034E0A01022F170505772B0405FBC7BDBEFDFFFFFFFF838282FC0101 48 | 01FF040505FF010101FF010101FF010101FF010101FF292A2AFE0E0E0EFE0404 49 | 04FF040404FF040404FF040404FF020101FF323333FE202020FE020202FF0404 50 | 04FF030303FF050505FF010101FF303131FEA8A9A9FDFFFFFFFF9C8A8BFC2E09 51 | 0AF60C01034B0A01022E1603037A330D0EFDD2CACAFDFFFFFFFF858585FD0000 52 | 00FF030303FF000000FF000000FF000000FF000000FF272626FE010101FD0000 53 | 00FE000000FF000000FE000000FF000000FF181919FC0B0C0CFD000000FE0000 54 | 00FE000000FF000000FF000000FE363636FCB0B1B1FDFEFEFEFE9F8B8CFE2F0A 55 | 0BF10C0103470A02022E1502027A381213FED7D0D1FDFFFFFFFF888888FC0000 56 | 00FF030303FF000000FF000000FF010101FF000000FF353636FE606060FC6061 57 | 61FC656666FD6C6C6CFC747575FC7B7C7CFC8F8F8FFC868787FB757575FD7171 58 | 71FC6F6F6FFC717171FD727272FC969696FCE8E7E7FEFFFFFFFE9B8788FD1E01 59 | 01C80B0103430B02022D1502027B391415FFD9D2D2FDFFFFFFFE8C8D8DFD0000 60 | 00FF020202FF000000FF000000FF020202FF000000FF636464FDFFFFFFFEFFFF 61 | FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF 62 | FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF9F7F8FC5C4040EE0C00 63 | 00720A0103400B02022D1502027D391315FFD8D2D1FCFFFFFFFE8F8F8FFD0000 64 | 00FF010101FF000000FF000000FF020202FF000000FF676767FDFEFEFEFEFAFA 65 | FAFEF1EEEEFEEEEBEBFDEFECECFDF2F0EFFCE6E2E2FBEAE7E8FBEEECECFCEEEB 66 | EBFBEDEAEAFBE9E6E6FBE2DDDDF9D6D0D0F8AA9B9BF75B3C3DFF1E0000C10902 67 | 022A0A01023D0A01022C1602027D381213FFD7CFCFFCFFFFFFFF919191FC0202 68 | 02FE070707FE050505FE050505FE080808FE020202FE6C6C6CFCFFFFFFFFF1F0 69 | EFFD958384F8836C6DFE755A5AFF5D3F3EFD432020FA442323FA472727FC4827 70 | 27FD482627FF452223FF3F1A1BFF360E0FFF250000FF150000A3070202200600 71 | 00280901023B0A01022C1602027D361011FFD5CECFFDFFFFFFFE9F9F9FFC2323 72 | 23FD313232FC2F3030FC2F2F2FFC323333FC232424FC7E7E7EFBFFFFFFFFF0ED 73 | EDFD401F20F6180000D31D0000C31D0000C2210102C0200001C01F0000C01F00 74 | 01BE1E0001BB1D0001AE1A00019C18020285130505590603031C090101391003 75 | 03560901023A0A01022D1602027E350F10FFD3CCCCFCFFFFFFFE929292FD0303 76 | 03FE070707FE050505FE050505FE080808FE030303FF6F6F6FFCFFFFFFFEEEEB 77 | ECFE4A2728FA0B03034E0905051C0B0304330B0303380C03033A0C03043B0B03 78 | 03390B0303350A0303310903032F080202310B02023F0F030357100303540D02 79 | 0248090102390A01022C1602027D350F10FFD3CCCCFCFFFFFFFE908F8FFC0000 80 | 00FF010101FF000000FF000000FF020202FF000000FF6B6B6BFDFFFFFFFEEEEA 81 | EAFF452525F30400003E0C0303390F0303540E0202490E0202490E0202490D02 82 | 02480E02024A0E0202490E0202480E0202440B020235080101200500000D0301 83 | 01040901023A0A01022D1602027E350F0FFFD3CCCCFCFFFFFFFF8D8E8EFB0000 84 | 00FF020202FF000000FF000000FF030303FF000000FF696969FCFFFFFFFEEEEA 85 | EAFF432323EE0500003E100405520D0202430300000E0400000E0200000B0400 86 | 0009040000070200000401000000020000000000000000000000000000000000 87 | 00000901023A0A01022D1602027D361011FFD4CDCDFCFFFFFFFF8B8B8BFC0000 88 | 00FF030303FF000000FF000000FF030303FF000000FF676666FDFFFFFFFEEFEB 89 | ECFF432323EA0600003D100405540A02023A0000000000000000000000000000 90 | 0000000000000000000100000001000000010000000200000002000000020000 91 | 00010A01023B0A01022D1602027D381112FFD6CFD0FCFFFFFFFE898989FC0000 92 | 00FF030303FF000000FF000000FF030303FF000000FF646464FAFFFFFFFDEFEC 93 | ECFF412223E60600003D110505560A0202370000000100000003000000020000 94 | 0001000000010000000100000001000000010000000100000001000000010000 95 | 00010A01033D0B02022D1502027D391415FFD9D3D2FCFFFFFFFF878787FD0000 96 | 00FF030303FF000000FF000000FF030303FF000000FF616161FAFFFFFFFDEFEB 97 | ECFF412222E50500003C110505560A0202350000000000000002000000010000 98 | 0001000000010000000100000001000000010000000100000001000000010000 99 | 00010A0103420B02022E1502017D3A1516FFDAD3D3FDFFFFFFFF848383FD0000 100 | 00FF030303FF000000FF000000FF030303FF000000FF5F6060FCFFFFFFFDEFEB 101 | ECFF402222E40500003A110505560A0202350000000000000002000000010000 102 | 0001000000010000000100000001000000010000000100000001000000010000 103 | 00010D0103470B02022E1502027E391314FFD8D1D2FCFFFFFFFF828282FC0000 104 | 00FF030303FF000000FF000000FF030303FF000000FF606060FCFFFFFFFDEFEA 105 | EBFF3F2021E204000036110405560A0202350000000000000002000000010000 106 | 0001000000010000000100000001000000010000000100000001000000010000 107 | 00010D01034C0A01022D1602027E350E0FFFD3CCCCFCFFFFFFFF808080FC0000 108 | 00FF030303FF000000FF000000FF030303FF000000FF636363FBFFFFFFFDEDE8 109 | E9FF3E1F20DE04000032110405560A0202330000000000000002000000010000 110 | 0001000000010000000100000001000000010000000100000001000000010000 111 | 00010E0103500A01022E1804057D2D0505FDC9BFBFFCFFFFFFFE808080FC0202 112 | 02FF050505FF020202FF020202FF050505FF020202FF686868FCFFFFFFFDEAE4 113 | E6FF3B1D1ED60200002B110505580901012F0000000000000002000000010000 114 | 0001000000010000000100000001000000010000000100000001000000010000 115 | 00011102045A0901022C1B070783250000FDB7ACADFCFEFEFEFF767575FB0000 116 | 00FF000000FE000000FE000000FE000000FE000000FF656565FCFEFEFEFCE6DF 117 | E0FF381D1DC90100002411050559080101270000000000000002000000010000 118 | 0001000000010000000100000001000000010000000100000001000000010000 119 | 00010D0102470A000034180607651F0000F6958484FBFFFFFFFFC7C6C6FD9594 120 | 94FEA09F9FFDA0A0A0FCA1A0A0FCA1A0A0FD969595FEC3C2C2FCFFFFFFFCEAE2 121 | E3FF2E1718AB0100001D1105055A0601011E0000000000000002000000010000 122 | 0001000000010000000100000001000000010000000100000001000000010000 123 | 00010600001B0D0000400D020235250404D7482A2BFEEEECECF9FFFFFFFFFFFF 124 | FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1F0F0F78A73 125 | 74FF180202930501011E110303560301010F0000000000000001000000010000 126 | 0001000000010000000100000001000000010000000100000001000000010000 127 | 0001020000060B0000390A0000331F07078F2D0304FF583939FF998989FAAB9F 128 | 9FFAB7ABABFABBB1B1F9BAB0B0FAB5A8A8FBA49696FB897576FA513132FF2600 129 | 00FF1904057E0A02023C0E030347000000010000000100000001000000010000 130 | 0001000000010000000100000001000000010000000100000001000000010000 131 | 000100000000050000180D0000410A0000321B06067F230000D8220000FD2500 132 | 00FF270000FF290102FF290101FF270000FF240000FF210000FA230000D41906 133 | 066D0C01013E1003035504010113000000000000000200000001000000010000 134 | 0001000000010000000100000001000000010000000100000001000000010000 135 | 00010000000201000000090000270F0101500A0000370E03033F180607651F07 136 | 098B220708A2220808A62107089D1E0708881906076F1606065A0D0303380A00 137 | 00320E03034C0401011400000000000000010000000100000001000000010000 138 | 0001000000010000000100000001000000010000000100000001000000010000 139 | 00010000000100000001010000030C02023C120202670F01015B0B0000370A00 140 | 002F0A00002F0A00002E0A00002E090000300A0000310C00003D110202600D01 141 | 01400300000B0000000000000002000000010000000100000001000000010000 142 | 0001000000010000000100000001000000010000000100000001000000010000 143 | 0001000000010000000100000000010000000701011C090101270900002B0B00 144 | 00340B0000390C00003B0C00003B0C0000390B0000340900002D0B0101290200 145 | 0008000000000000000300000001000000010000000100000001000000010000 146 | 0001000000010000000100000001000000010000000100000001000000010000 147 | 0001000000000000000000000000000000000000000000000000000000000000 148 | 0000000000000000000000000000000000000000000000000000000000000000 149 | 0000000000000000000000000000000000000000000000000000000000000000 150 | 0000000000000000000000000000000000000000000000000000000000000000 151 | 0000 152 | } 153 | Position = poScreenCenter 154 | LCLVersion = '1.6.0.4' 155 | object edtInput: TLabeledEdit 156 | Left = 49 157 | Height = 21 158 | Top = 0 159 | Width = 360 160 | AutoSize = False 161 | EditLabel.AnchorSideTop.Control = edtInput 162 | EditLabel.AnchorSideTop.Side = asrCenter 163 | EditLabel.AnchorSideRight.Control = edtInput 164 | EditLabel.AnchorSideBottom.Control = edtInput 165 | EditLabel.AnchorSideBottom.Side = asrBottom 166 | EditLabel.Left = 16 167 | EditLabel.Height = 13 168 | EditLabel.Top = 4 169 | EditLabel.Width = 30 170 | EditLabel.Caption = 'Input:' 171 | EditLabel.ParentColor = False 172 | EditLabel.Layout = tlCenter 173 | Enabled = False 174 | LabelPosition = lpLeft 175 | ReadOnly = True 176 | TabOrder = 0 177 | OnChange = edtInputChange 178 | end 179 | object edtOutput: TLabeledEdit 180 | Left = 49 181 | Height = 21 182 | Top = 24 183 | Width = 360 184 | AutoSize = False 185 | EditLabel.AnchorSideTop.Control = edtOutput 186 | EditLabel.AnchorSideTop.Side = asrCenter 187 | EditLabel.AnchorSideRight.Control = edtOutput 188 | EditLabel.AnchorSideBottom.Control = edtOutput 189 | EditLabel.AnchorSideBottom.Side = asrBottom 190 | EditLabel.Left = 8 191 | EditLabel.Height = 13 192 | EditLabel.Top = 28 193 | EditLabel.Width = 38 194 | EditLabel.Caption = 'Output:' 195 | EditLabel.ParentColor = False 196 | EditLabel.Layout = tlCenter 197 | Enabled = False 198 | LabelPosition = lpLeft 199 | ReadOnly = True 200 | TabOrder = 1 201 | OnChange = edtInputChange 202 | end 203 | object btnBrowseIn: TButton 204 | Left = 417 205 | Height = 21 206 | Top = 0 207 | Width = 33 208 | Caption = '...' 209 | OnClick = btnBrowseInClick 210 | TabOrder = 2 211 | end 212 | object btnBrowseOut: TButton 213 | Left = 417 214 | Height = 21 215 | Top = 24 216 | Width = 33 217 | Caption = '...' 218 | OnClick = btnBrowseOutClick 219 | TabOrder = 3 220 | end 221 | object mmoLog: TMemo 222 | Left = 0 223 | Height = 161 224 | Top = 126 225 | Width = 458 226 | Font.CharSet = ANSI_CHARSET 227 | Font.Color = clWindowText 228 | Font.Height = -13 229 | Font.Name = 'Consolas' 230 | ParentFont = False 231 | ReadOnly = True 232 | ScrollBars = ssVertical 233 | TabOrder = 4 234 | end 235 | object btnRun: TButton 236 | Left = 8 237 | Height = 73 238 | Hint = 'Start selected job' 239 | Top = 47 240 | Width = 75 241 | Caption = 'RUN' 242 | Enabled = False 243 | OnClick = btnRunClick 244 | ParentShowHint = False 245 | ShowHint = True 246 | TabOrder = 5 247 | end 248 | object grpMode: TGroupBox 249 | Left = 88 250 | Height = 73 251 | Top = 48 252 | Width = 361 253 | Caption = 'Mode:' 254 | ClientHeight = 55 255 | ClientWidth = 357 256 | TabOrder = 6 257 | object rbExplode: TRadioButton 258 | Left = 14 259 | Height = 19 260 | Hint = 'Explode data from file with selected offset' 261 | Top = 4 262 | Width = 71 263 | Caption = 'Explode at' 264 | Checked = True 265 | OnClick = rbExplodeClick 266 | ParentShowHint = False 267 | ShowHint = True 268 | TabOrder = 0 269 | TabStop = True 270 | end 271 | object rbImplode: TRadioButton 272 | Left = 214 273 | Height = 19 274 | Top = 4 275 | Width = 58 276 | Caption = 'Implode' 277 | OnClick = rbImplodeClick 278 | TabOrder = 1 279 | end 280 | object seImpMode: TSpinEdit 281 | Left = 278 282 | Height = 21 283 | Hint = 'Imploding mode' 284 | Top = 2 285 | Width = 57 286 | AutoSelect = False 287 | Enabled = False 288 | MaxValue = 11 289 | ParentShowHint = False 290 | ShowHint = True 291 | TabOrder = 2 292 | Value = 5 293 | end 294 | object rbImplodeTest: TRadioButton 295 | Left = 214 296 | Height = 19 297 | Hint = 'Find best mode' 298 | Top = 30 299 | Width = 90 300 | Caption = 'Imploding Test' 301 | OnClick = rbImplodeTestClick 302 | ParentShowHint = False 303 | ShowHint = True 304 | TabOrder = 3 305 | end 306 | object rbExplodeAll: TRadioButton 307 | Left = 14 308 | Height = 19 309 | Hint = 'Explode all imploded archives from file' 310 | Top = 30 311 | Width = 72 312 | Caption = 'Explode All' 313 | OnClick = rbImplodeTestClick 314 | ParentShowHint = False 315 | ShowHint = True 316 | TabOrder = 4 317 | end 318 | object edtOffset: TEdit 319 | Left = 94 320 | Height = 21 321 | Hint = 'Offset to start exploding from' 322 | Top = 2 323 | Width = 57 324 | CharCase = ecUppercase 325 | OnExit = edtOffsetExit 326 | OnKeyPress = edtOffsetKeyPress 327 | ParentShowHint = False 328 | ShowHint = True 329 | TabOrder = 5 330 | Text = '000000' 331 | end 332 | object rbImplodedMode: TRadioButton 333 | Left = 94 334 | Height = 19 335 | Hint = 'Get imploding mode of selected file' 336 | Top = 30 337 | Width = 87 338 | Caption = 'Get Imp Mode' 339 | OnClick = rbImplodeTestClick 340 | ParentShowHint = False 341 | ShowHint = True 342 | TabOrder = 6 343 | end 344 | end 345 | object pbProgress: TProgressBar 346 | Left = 0 347 | Height = 17 348 | Top = 287 349 | Width = 458 350 | Align = alBottom 351 | TabOrder = 7 352 | end 353 | object dlgOpen: TOpenDialog 354 | Title = 'Select input file...' 355 | DefaultExt = '.bin' 356 | Filter = 'All Files (*.*)|*.*' 357 | Options = [ofHideReadOnly, ofNoChangeDir, ofFileMustExist, ofEnableSizing, ofForceShowHidden] 358 | left = 240 359 | top = 152 360 | end 361 | object dlgSave: TSaveDialog 362 | Title = 'Select output file...' 363 | DefaultExt = '.bin' 364 | Filter = 'All Files (*.*)|*.*' 365 | Options = [ofOverwritePrompt, ofHideReadOnly, ofNoChangeDir, ofEnableSizing, ofForceShowHidden] 366 | left = 272 367 | top = 152 368 | end 369 | end 370 | -------------------------------------------------------------------------------- /gui/uMain.pas: -------------------------------------------------------------------------------- 1 | unit uMain; 2 | 3 | {$MODE Delphi} 4 | 5 | interface 6 | 7 | uses 8 | LCLIntf, LCLType, SysUtils, Variants, Classes, Graphics, Controls, Forms, 9 | Dialogs, StdCtrls, ExtCtrls, Spin, ComCtrls; 10 | 11 | type 12 | TfrmMain = class(TForm) 13 | edtInput: TLabeledEdit; 14 | edtOutput: TLabeledEdit; 15 | btnBrowseIn: TButton; 16 | btnBrowseOut: TButton; 17 | mmoLog: TMemo; 18 | btnRun: TButton; 19 | grpMode: TGroupBox; 20 | rbExplode: TRadioButton; 21 | rbImplode: TRadioButton; 22 | seImpMode: TSpinEdit; 23 | dlgOpen: TOpenDialog; 24 | dlgSave: TSaveDialog; 25 | rbImplodeTest: TRadioButton; 26 | rbExplodeAll: TRadioButton; 27 | edtOffset: TEdit; 28 | pbProgress: TProgressBar; 29 | rbImplodedMode: TRadioButton; 30 | procedure rbExplodeClick(Sender: TObject); 31 | procedure rbImplodeClick(Sender: TObject); 32 | procedure edtInputChange(Sender: TObject); 33 | procedure btnRunClick(Sender: TObject); 34 | procedure btnBrowseInClick(Sender: TObject); 35 | procedure btnBrowseOutClick(Sender: TObject); 36 | procedure rbImplodeTestClick(Sender: TObject); 37 | procedure edtOffsetKeyPress(Sender: TObject; var Key: Char); 38 | procedure edtOffsetExit(Sender: TObject); 39 | private 40 | { Private declarations } 41 | function HexToInt(HexStr : string) : Integer; 42 | public 43 | { Public declarations } 44 | end; 45 | 46 | var 47 | frmMain: TfrmMain; 48 | 49 | implementation 50 | 51 | {$R *.lfm} 52 | 53 | uses 54 | uFimp; 55 | 56 | procedure TfrmMain.rbExplodeClick(Sender: TObject); 57 | begin 58 | seImpMode.Enabled := false; 59 | edtInputChange(Self); 60 | end; 61 | 62 | procedure TfrmMain.rbImplodeClick(Sender: TObject); 63 | begin 64 | seImpMode.Enabled := true; 65 | edtInputChange(Self); 66 | end; 67 | 68 | procedure TfrmMain.edtInputChange(Sender: TObject); 69 | begin 70 | btnRun.Enabled := FileExists(edtInput.Text) and 71 | ((edtOutput.Text <> '') or rbImplodeTest.Checked or rbExplodeAll.Checked or 72 | rbImplodedMode.Checked) and 73 | (edtInput.Text <> edtOutput.Text); 74 | end; 75 | 76 | procedure TfrmMain.btnRunClick(Sender: TObject); 77 | var 78 | inp, outp: TFileStream; 79 | inbuf, original: PBytesArray; 80 | inlen, imp_size, outlen, i, min_size, min_i, offset, count: Integer; 81 | messg, path, save, ifname, ofname: string; 82 | begin 83 | mmoLog.Clear; 84 | ifname := edtInput.Text; 85 | ofname := edtOutput.Text; 86 | 87 | inp := TFileStream.Create(ifname, fmOpenRead, fmShareExclusive); 88 | New(inbuf); 89 | New(original); 90 | 91 | inlen := inp.Size; 92 | inp.Read(original^[0], inlen); 93 | inp.Free; 94 | 95 | offset := HexToInt(edtOffset.Text); 96 | if (offset + $30) > inlen then 97 | offset := 0; 98 | 99 | if rbExplode.Checked then 100 | begin 101 | imp_size := imploded_size(@original^[offset]); 102 | outlen := explode(@original^[offset]); 103 | 104 | if outlen = 0 then 105 | messg := 'Exploding error!;' 106 | else 107 | messg := Format('Output size: %.4X;' + #13#10 + 'Done!', [outlen]); 108 | 109 | mmoLog.Text := Format('Mode: Explosion;' + #13#10 + 110 | 'Input size: %.4X;' + #13#10 + 111 | 'Input offset: %.6X;' + #13#10 + messg, [imp_size, offset]); 112 | 113 | if outlen <> 0 then 114 | begin 115 | outp := TFileStream.Create(ofname, fmOpenWrite or fmCreate, fmShareExclusive); 116 | outp.Write(original^[offset], outlen); 117 | outp.Free; 118 | end; 119 | end 120 | else if rbImplode.Checked then 121 | begin 122 | outlen := implode(@original^[0], inlen, Byte(seImpMode.Value)); 123 | 124 | if outlen = 0 then 125 | messg := 'Exploding error!' 126 | else 127 | messg := Format('Output size: %.4X;' + #13#10 + 'Done!', [outlen]); 128 | 129 | mmoLog.Text := Format('Mode: Implosion;' + #13#10 + 130 | 'Input size: %.4X;' + #13#10 + messg, [inlen]); 131 | 132 | if outlen <> 0 then 133 | begin 134 | outp := TFileStream.Create(ofname, fmOpenWrite or fmCreate, fmShareExclusive); 135 | outp.Write(original^[0], outlen); 136 | outp.Free; 137 | end; 138 | end 139 | else if rbImplodeTest.Checked then 140 | begin 141 | mmoLog.Lines.Add('Mode: Implosion test;' + #13#10); 142 | 143 | min_size := MaxInt; 144 | min_i := 0; 145 | for i := 0 to 11 do 146 | begin 147 | Move(original^, inbuf^, inlen); 148 | 149 | outlen := implode(@inbuf^[0], inlen, Byte(i)); 150 | 151 | if (min_size > outlen) and (outlen <> 0) then 152 | begin 153 | min_size := outlen; 154 | min_i := i; 155 | end; 156 | 157 | mmoLog.Lines.Add(Format('Mode %.2d: %d bytes', [i, outlen])); 158 | 159 | Application.ProcessMessages; 160 | end; 161 | 162 | mmoLog.Lines.Add(Format(#13#10 + 'Best mode is: %.2d (%.4X bytes).' + #13#10 + 'Done!', [min_i, min_size])); 163 | seImpMode.Value := min_i; 164 | rbImplode.Checked := True; 165 | rbImplodeClick(Self); 166 | end 167 | else if rbExplodeAll.Checked then 168 | begin 169 | offset := 0; 170 | count := 0; 171 | btnRun.Enabled := False; 172 | pbProgress.Max := inlen; 173 | path := ExtractFilePath(ifname); 174 | 175 | mmoLog.Lines.Add('Mode: Explode all archives;' + #13#10); 176 | 177 | 178 | while (offset + $30) < inlen do 179 | begin 180 | pbProgress.Position := offset; 181 | imp_size := imploded_size(@original^[offset]); 182 | 183 | if (imp_size <> 0) and (offset+imp_size <= inlen) then 184 | begin 185 | Move(original^[offset], inbuf^[0], imp_size); 186 | outlen := explode(@inbuf^[0]); 187 | if outlen = 0 then 188 | begin 189 | Inc(offset); 190 | Continue; 191 | end; 192 | 193 | save := Format('%.3d_%.6X_exp.bin', [count + 1, offset]); 194 | 195 | outp := TFileStream.Create(path + save, fmOpenWrite or fmCreate, fmShareExclusive); 196 | outp.Write(inbuf^[0], outlen); 197 | outp.Free; 198 | 199 | mmoLog.Lines.Add(Format('Exploded at: %.6X (%.4X -> %.4X bytes)', [offset, imp_size, outlen])); 200 | Inc(count); 201 | end 202 | else 203 | imp_size := 1; 204 | 205 | Inc(offset, imp_size); 206 | 207 | Application.ProcessMessages; 208 | end; 209 | 210 | mmoLog.Lines.Add(Format(#13#10 + 'Done! Exploded archives count: %d', [count])); 211 | btnRun.Enabled := True; 212 | end 213 | else 214 | begin 215 | btnRun.Enabled := False; 216 | mmoLog.Lines.Add('Mode: Get imploding mode of file;' + #13#10); 217 | 218 | imp_size := imploded_size(@original^[offset]); 219 | outlen := explode(@original^[offset]); 220 | 221 | if imp_size = 0 then 222 | begin 223 | mmoLog.Lines.Add('It''s not an Imploder file!'); 224 | end 225 | else 226 | for i := 0 to 11 do 227 | begin 228 | Move(original^[offset], inbuf^[0], outlen); 229 | 230 | inlen := implode(@inbuf^[0], outlen, Byte(i)); 231 | 232 | seImpMode.Value := i; 233 | seImpMode.Update; 234 | if imp_size = inlen then 235 | begin 236 | mmoLog.Lines.Add(Format('File mode is: %.2d;' + #13#10 + 'Done!', [i])); 237 | break; 238 | end; 239 | Application.ProcessMessages; 240 | end; 241 | btnRun.Enabled := True; 242 | end; 243 | 244 | Dispose(original); 245 | Dispose(inbuf); 246 | end; 247 | 248 | procedure TfrmMain.btnBrowseInClick(Sender: TObject); 249 | begin 250 | if not dlgOpen.Execute then Exit; 251 | 252 | edtInput.Text := dlgOpen.FileName; 253 | end; 254 | 255 | procedure TfrmMain.btnBrowseOutClick(Sender: TObject); 256 | begin 257 | if not dlgSave.Execute then Exit; 258 | 259 | edtOutput.Text := dlgSave.FileName; 260 | end; 261 | 262 | procedure TfrmMain.rbImplodeTestClick(Sender: TObject); 263 | begin 264 | seImpMode.Enabled := false; 265 | edtInputChange(Self); 266 | end; 267 | 268 | procedure TfrmMain.edtOffsetKeyPress(Sender: TObject; var Key: Char); 269 | begin 270 | if not (Key in ['0'..'9', 'A'..'F', 'a'..'f', #$2E, #$08]) then Key := #0; 271 | end; 272 | 273 | function TfrmMain.HexToInt(HexStr : string) : Integer; 274 | var RetVar : Integer; 275 | i : byte; 276 | begin 277 | if Length(HexStr) = 0 then 278 | begin 279 | Result := 0; 280 | Exit; 281 | end; 282 | 283 | HexStr := UpperCase(HexStr); 284 | if HexStr[length(HexStr)] = 'H' then 285 | Delete(HexStr,length(HexStr),1); 286 | RetVar := 0; 287 | 288 | for i := 1 to length(HexStr) do begin 289 | RetVar := RetVar shl 4; 290 | if (HexStr[i] in ['0'..'9']) then 291 | RetVar := RetVar + (byte(HexStr[i]) - 48) 292 | else 293 | if (HexStr[i] in ['A'..'F']) then 294 | RetVar := RetVar + (byte(HexStr[i]) - 55) 295 | else begin 296 | Retvar := 0; 297 | break; 298 | end; 299 | end; 300 | 301 | Result := RetVar; 302 | end; 303 | 304 | procedure TfrmMain.edtOffsetExit(Sender: TObject); 305 | begin 306 | edtOffset.Text := Format('%.6X', [HexToInt(edtOffset.Text)]); 307 | end; 308 | 309 | end. 310 | -------------------------------------------------------------------------------- /implode.c: -------------------------------------------------------------------------------- 1 | #include <stdlib.h> 2 | #include <stdio.h> 3 | 4 | static unsigned int MAX_SIZES[12] = { 0x80, 0x100, 0x200, 0x400, 0x700, 0xD00, 0x1500, 0x2500, 0x5100, 0x9200, 0x10900, 0x10900, } ; 5 | 6 | static unsigned char MODE_INIT[12][12] = 7 | { 8 | { 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06 }, // mode 0 9 | { 0x05, 0x06, 0x07, 0x07, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x06, 0x06 }, // mode 1 10 | { 0x05, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x08 }, // mode 2 11 | { 0x05, 0x06, 0x07, 0x08, 0x07, 0x07, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09 }, // mode 3 12 | { 0x06, 0x07, 0x07, 0x08, 0x07, 0x08, 0x09, 0x09, 0x08, 0x09, 0x0A, 0x0A }, // mode 4 13 | { 0x06, 0x07, 0x07, 0x08, 0x07, 0x09, 0x09, 0x0A, 0x08, 0x0A, 0x0B, 0x0B }, // mode 5 14 | { 0x06, 0x07, 0x08, 0x08, 0x07, 0x09, 0x09, 0x0A, 0x08, 0x0A, 0x0B, 0x0C }, // mode 6 15 | { 0x06, 0x07, 0x08, 0x08, 0x07, 0x09, 0x09, 0x0A, 0x09, 0x0A, 0x0C, 0x0D }, // mode 7 16 | { 0x06, 0x07, 0x07, 0x08, 0x07, 0x09, 0x09, 0x0C, 0x09, 0x0A, 0x0C, 0x0E }, // mode 8 17 | { 0x06, 0x07, 0x08, 0x09, 0x07, 0x09, 0x0A, 0x0C, 0x09, 0x0B, 0x0D, 0x0F }, // mode 9 18 | { 0x06, 0x07, 0x08, 0x08, 0x07, 0x0A, 0x0B, 0x0B, 0x09, 0x0C, 0x0D, 0x10 }, // mode A 19 | { 0x06, 0x08, 0x08, 0x09, 0x07, 0x0B, 0x0C, 0x0C, 0x09, 0x0D, 0x0E, 0x11 }, // mode B 20 | } ; 21 | 22 | static unsigned short static_token_lens[12] = { 2, 2, 2, 2, 6, 0x0A, 0x0A, 0x12, 0x16, 0x2A, 0x8A, 0x4012 }; 23 | static unsigned char static_reps[4] = { 0, 2, 6, 14 }; 24 | static unsigned char static_rep_bits_cnts[4] = { 1, 2, 3, 4 }; 25 | static unsigned char static_token_extra_bits[12] = { 1, 1, 1, 1, 2, 3, 3, 4, 4, 5, 7, 14 }; 26 | 27 | unsigned char *src; 28 | 29 | unsigned int read_pos, src_size, max_encoded_size, endoffset, token_run_len; 30 | unsigned char write_byte; 31 | 32 | unsigned short last_reps, encoded_reps, last_token_len, encoded_token_len; 33 | unsigned char last_reps_bits_cnt, encoded_reps_bits_cnt, last_token_len_bits_cnt, encoded_token_len_bits_cnt, last_offset_bits_cnt, encoded_offset_bits_cnt; 34 | unsigned int last_offset, encoded_offset; 35 | 36 | char write_bits_cnt; 37 | 38 | unsigned char counts[8]; 39 | unsigned int offsets[8]; 40 | 41 | unsigned int run_base_offs[12]; 42 | unsigned char run_extra_bits[12]; 43 | 44 | static unsigned short word_get_bits_right(unsigned short value, unsigned char count){ 45 | return (unsigned short)(((1 << count)-1) & (value >> 0)); 46 | } 47 | 48 | static unsigned int long_get_bits_right(unsigned int value, unsigned char count){ 49 | return (unsigned int)(((1 << count)-1) & (value >> 0)); 50 | } 51 | 52 | static void copy_bytes(unsigned char *dst, unsigned char *src, int count){ 53 | for (int i = 0; i < count; i++){ 54 | dst[i] = src[i]; 55 | } 56 | } 57 | 58 | static unsigned short read_word(unsigned char *buf){ 59 | return ((buf[0] << 8) | buf[1]); 60 | } 61 | 62 | static unsigned int read_dword(unsigned char *buf){ 63 | return ((read_word(&buf[0]) << 16) | read_word(&buf[2])); 64 | } 65 | 66 | static void write_word(unsigned char *dst, unsigned short value){ 67 | dst[0] = (value >> 8) & 0xFF; 68 | dst[1] = (value >> 0) & 0xFF; 69 | } 70 | 71 | static void write_dword(unsigned char *dst, unsigned int value){ 72 | write_word(&dst[0], (value >> 16) & 0xFFFF); 73 | write_word(&dst[2], (value >> 0) & 0xFFFF); 74 | } 75 | 76 | static unsigned int checksum(unsigned char *buf, unsigned int size){ 77 | unsigned int sum = 0; 78 | 79 | size >>= 1; 80 | for (int i = 0; i < size; i++){ 81 | sum += read_word(&buf[i*2]); 82 | } 83 | 84 | return (sum+7); 85 | } 86 | 87 | void find_repeats(){ 88 | for (int i = 0; i < 8; i++){ 89 | counts[i] = 0; 90 | } 91 | 92 | unsigned int limit = read_pos + max_encoded_size; 93 | 94 | if (limit > src_size){ 95 | limit = src_size; 96 | } 97 | 98 | int min_reps = 1; 99 | unsigned int offset = read_pos; 100 | 101 | while (offset < limit){ 102 | while (src[++offset] != src[read_pos] && offset < limit); 103 | 104 | int reps = 1; 105 | 106 | while (src[read_pos+reps] == src[offset+reps] && reps < 0xFF && (offset+reps) < limit){ 107 | reps++; 108 | } 109 | 110 | if (reps > min_reps){ 111 | min_reps = reps; 112 | 113 | if (reps <= 8){ 114 | if (counts[reps-2] == 0){ 115 | counts[reps-2] = reps; 116 | 117 | offsets[reps-2] = offset - read_pos - 1; 118 | } 119 | } 120 | else{ 121 | counts[7] = reps; 122 | offsets[7] = offset - read_pos - 1; 123 | 124 | if (reps == 0xFF){ 125 | break; 126 | } 127 | } 128 | } 129 | } 130 | } 131 | 132 | int encode_match(unsigned char count, unsigned int offset){ 133 | count -= 2; 134 | if (count <= 3){ 135 | last_reps = static_reps[count]; 136 | last_reps_bits_cnt = static_rep_bits_cnts[count]; 137 | } 138 | else{ 139 | if (count <= 11){ 140 | last_reps = 0xF0 | (count-4); 141 | last_reps_bits_cnt = 8; 142 | } 143 | else{ 144 | last_reps = 0x1F00 | (count+2); 145 | last_reps_bits_cnt = 13; 146 | } 147 | count = 3; 148 | } 149 | 150 | if (static_token_lens[count] > token_run_len){ 151 | last_token_len_bits_cnt = static_token_extra_bits[count]+1; 152 | last_token_len = /*00+*/ word_get_bits_right(token_run_len, static_token_extra_bits[count]); 153 | } 154 | else if (static_token_lens[count+4] > token_run_len){ 155 | last_token_len_bits_cnt = static_token_extra_bits[count+4]+2; 156 | last_token_len = /*10+*/ (2 << static_token_extra_bits[count+4]) | word_get_bits_right(token_run_len - static_token_lens[count], static_token_extra_bits[count+4]); 157 | } 158 | else if (static_token_lens[count+8] > token_run_len){ 159 | last_token_len_bits_cnt = static_token_extra_bits[count+8]+2; 160 | last_token_len = /*11+*/ (3 << static_token_extra_bits[count+8]) | word_get_bits_right(token_run_len - static_token_lens[count+4], static_token_extra_bits[count+8]); 161 | } 162 | else{ 163 | return 0; 164 | } 165 | 166 | if (run_base_offs[count] > offset){ 167 | last_offset_bits_cnt = run_extra_bits[count]+1; 168 | last_offset = /*00+*/ long_get_bits_right(offset, run_extra_bits[count]); 169 | } 170 | else if (run_base_offs[count+4] > offset){ 171 | last_offset_bits_cnt = run_extra_bits[count+4]+2; 172 | last_offset = /*10+*/ (2 << run_extra_bits[count+4]) | long_get_bits_right(offset - run_base_offs[count], run_extra_bits[count+4]); 173 | } 174 | else if (run_base_offs[count+8] > offset){ 175 | last_offset_bits_cnt = run_extra_bits[count+8]+2; 176 | last_offset = /*11+*/ (3 << run_extra_bits[count+8]) | long_get_bits_right(offset - run_base_offs[count+4], run_extra_bits[count+8]); 177 | } 178 | else{ 179 | return 0; 180 | } 181 | 182 | //printf("%02X-%02X-%02X-%02X-%04X-%04X-%02X\n", cnt_, encoded_token_len_bits_cnt, encoded_token_len & 0xFF, encoded_offset_bits_cnt, encoded_offset, encoded_reps, encoded_reps_bits_cnt); 183 | 184 | return -1; 185 | } 186 | 187 | unsigned short find_best_match_and_encode(){ 188 | short max = 0; 189 | unsigned short retn = 0; 190 | 191 | for (int i = 0; i < 8; i++){ 192 | if (counts[i] && encode_match(counts[i], offsets[i])){ 193 | short encoded = (counts[i] << 3) - (last_reps_bits_cnt + last_offset_bits_cnt + last_token_len_bits_cnt); 194 | if (encoded >= max){ 195 | encoded_reps = last_reps; 196 | encoded_reps_bits_cnt = last_reps_bits_cnt; 197 | encoded_token_len = last_token_len; 198 | encoded_token_len_bits_cnt = last_token_len_bits_cnt; 199 | encoded_offset = last_offset; 200 | encoded_offset_bits_cnt = last_offset_bits_cnt; 201 | 202 | max = encoded; 203 | retn = counts[i]; 204 | } 205 | } 206 | } 207 | return retn; 208 | } 209 | 210 | int nn = 0; 211 | void write_bits(unsigned char count, unsigned int value){ 212 | //printf("%02X-%06X\n", count, value); nn++; 213 | for (int i = 0; i < count; i++){ 214 | write_byte >>= 1; 215 | write_byte |= ((value & 1) << 7); 216 | value >>= 1; 217 | 218 | write_bits_cnt--; 219 | if (write_bits_cnt < 0){ 220 | write_bits_cnt = 7; 221 | src[endoffset++] = write_byte; 222 | //printf("%02X\n", write_byte); 223 | write_byte = 0; 224 | } 225 | } 226 | } 227 | 228 | unsigned int implode(unsigned char *input, unsigned int size, unsigned char mode){ 229 | if (!input || size < 0x40){ 230 | return 0; 231 | } 232 | 233 | read_pos = src_size = max_encoded_size = endoffset = token_run_len = 0; 234 | write_byte = 0; 235 | last_reps = encoded_reps = last_token_len = encoded_token_len = 0; 236 | last_reps_bits_cnt = encoded_reps_bits_cnt = last_token_len_bits_cnt = 0; 237 | encoded_token_len_bits_cnt = last_offset_bits_cnt = encoded_offset_bits_cnt = 0; 238 | last_offset = encoded_offset = 0; 239 | write_bits_cnt = 0; 240 | 241 | src_size = size; 242 | read_pos = 0; 243 | src = input; 244 | endoffset = 0; 245 | 246 | write_byte = 0; 247 | write_bits_cnt = 0; 248 | 249 | if (mode >= 0x0C){ 250 | mode = 0; 251 | } 252 | 253 | max_encoded_size = MAX_SIZES[mode]+1; 254 | 255 | if (max_encoded_size > src_size){ 256 | max_encoded_size = src_size-1; 257 | } 258 | 259 | unsigned char size_mode = 0; 260 | while (max_encoded_size-1 > MAX_SIZES[size_mode]){ 261 | size_mode++; 262 | } 263 | 264 | for (int i = 0; i < 0x0C; i++){ 265 | run_extra_bits[i] = MODE_INIT[size_mode][i]; 266 | run_base_offs[i] = (1 << MODE_INIT[size_mode][i]); 267 | } 268 | 269 | for (int i = 0; i < 8; i++){ 270 | run_base_offs[4+i] += run_base_offs[i]; 271 | } 272 | 273 | write_bits_cnt = 7; 274 | 275 | while (read_pos < src_size-2){ 276 | find_repeats(); 277 | 278 | unsigned short len = find_best_match_and_encode(); 279 | //printf("%02X\n", len); 280 | if (!len){ 281 | src[endoffset++] = src[read_pos++]; 282 | token_run_len++; 283 | 284 | if (token_run_len >= 0x4012){ 285 | break; 286 | } 287 | } 288 | else{ 289 | token_run_len = 0; 290 | 291 | read_pos += len; 292 | write_bits(encoded_offset_bits_cnt, encoded_offset); 293 | write_bits(encoded_token_len_bits_cnt, encoded_token_len); 294 | 295 | if (encoded_reps_bits_cnt == 13){ 296 | src[endoffset++] = encoded_reps & 0xFF; 297 | write_bits(5, 0x1F); 298 | } 299 | else{ 300 | write_bits(encoded_reps_bits_cnt, encoded_reps); 301 | } 302 | } 303 | } 304 | 305 | while (read_pos != src_size){ 306 | src[endoffset++] = src[read_pos++]; 307 | token_run_len++; 308 | } 309 | 310 | if (endoffset >= 0x0C && (src_size - endoffset > 54)){ 311 | if (endoffset & 1){ 312 | src[endoffset++] = 0; 313 | /*+0x10, SMART WORD*/ write_word(&src[endoffset+0x10], (write_byte & 0xFE) | (1 << write_bits_cnt)); 314 | } 315 | else{ 316 | /*+0x10, SMART WORD*/ write_word(&src[endoffset+0x10], 0xFF00 | (write_byte & 0xFE) | (1 << write_bits_cnt)); 317 | } 318 | 319 | unsigned int cmp_dword_1 = read_dword(&src[0x00]); 320 | unsigned int cmp_dword_2 = read_dword(&src[0x04]); 321 | unsigned int cmp_dword_3 = read_dword(&src[0x08]); 322 | /*HEADER*/ 323 | /*+0x00, MAGIC DWORD */ write_dword(&src[0x00], 0x494d5021); // "IMP!" 324 | /*+0x04, UNCOMPRESSED SIZE */ write_dword(&src[0x04], src_size); 325 | /*+0x08, CMPR DATA OFFSET */ write_dword(&src[0x08], endoffset); 326 | /*+0x0C, COMPRESSED DWORD AS IS: SRC[0x0C], NO NEED TO REPLACE */ 327 | 328 | /*CMPR DATA (+0x10)*/ 329 | /*+0x00, CMPR DATA DWORD 3 */ write_dword(&src[endoffset+0x00], cmp_dword_3); 330 | /*+0x04, CMPR DATA DWORD 2 */ write_dword(&src[endoffset+0x04], cmp_dword_2); 331 | /*+0x08, CMPR DATA DWORD 1 */ write_dword(&src[endoffset+0x08], cmp_dword_1); 332 | /*+0x0C, LITERAL RUN LEN */ write_dword(&src[endoffset+0x0C], token_run_len); 333 | 334 | /*+0x12, BASE OFFSETS TABLE*/ 335 | for (int i = 0; i < 8; i++){ 336 | write_word(&src[endoffset+0x12+i*2], run_base_offs[i] & 0xFFFF); 337 | } 338 | 339 | /*+0x22, EXTRA BITS TABLE */ 340 | copy_bytes(&src[endoffset+0x22], &run_extra_bits[0], 12); 341 | 342 | /*+0x2E, CHECKSUM OF DATA */ write_dword(&src[endoffset+0x2E], checksum(&src[0], endoffset+0x2E)); 343 | return (endoffset + 0x2E + 4); 344 | } 345 | return 0; 346 | } 347 | -------------------------------------------------------------------------------- /implode.h: -------------------------------------------------------------------------------- 1 | unsigned int implode(unsigned char *input, unsigned int size, unsigned char mode); 2 | --------------------------------------------------------------------------------