├── .gitattributes ├── lzss.c ├── lzss.h ├── ungi.c └── unsa.c /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /lzss.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "lzss.h" 3 | 4 | uint_fast32_t decompress( const uint8_t * input, uint8_t * output, uint_fast32_t inlength, uint_fast32_t outlength ) 5 | { 6 | uint_fast32_t inptr = 0; 7 | uint_fast32_t outptr = 0; 8 | while( 1 ) 9 | { 10 | if( inptr >= inlength ) return outptr; 11 | uint_fast32_t control = (uint_fast32_t)input[ inptr++ ] << 24; 12 | if( inptr >= inlength ) return outptr; 13 | control |= (uint_fast32_t)input[ inptr++ ] << 16; 14 | control |= 0xffff; 15 | while( control & 0xffff ) 16 | { 17 | if( control & 0x80000000 ) 18 | { 19 | if( inptr >= inlength ) return outptr; 20 | uint_fast16_t run = (uint_fast16_t)input[ inptr++ ] << 8; 21 | if( inptr >= inlength ) return outptr; 22 | run |= (uint_fast16_t)input[ inptr++ ]; 23 | ptrdiff_t runptr = (run >> 4) << 1; 24 | runptr = (ptrdiff_t)outptr - runptr;//runptr < outptr ? outptr - runptr : outptr; 25 | run = ((run & 0xf) + 1) << 1; 26 | for( uint_fast16_t i = 0; i < run; i++ ) 27 | { 28 | output[ outptr++ ] = output[ runptr++ ]; 29 | if( outptr >= outlength ) return outptr; 30 | } 31 | } 32 | else 33 | { 34 | if( inptr >= inlength ) return outptr; 35 | output[ outptr++ ] = input[ inptr++ ]; 36 | if( outptr >= outlength ) return outptr; 37 | if( inptr >= inlength ) return outptr; 38 | output[ outptr++ ] = input[ inptr++ ]; 39 | if( outptr >= outlength ) return outptr; 40 | } 41 | control <<= 1; 42 | } 43 | } 44 | return outptr; 45 | } 46 | -------------------------------------------------------------------------------- /lzss.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | uint_fast32_t decompress( const uint8_t * input, uint8_t * output, uint_fast32_t inlength, uint_fast32_t outlength ); 4 | -------------------------------------------------------------------------------- /ungi.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "lzss.h" 6 | 7 | static inline void * checked_malloc( size_t size ) 8 | { 9 | void * x = malloc( size ); 10 | if( !x ) 11 | { 12 | fprintf( stderr, "Allocation of 0x%zX bytes failed\n", size ); 13 | exit( EXIT_FAILURE ); 14 | } 15 | return memset( x, 0, size ); 16 | } 17 | 18 | int main( const int argc, const char * const * const argv ) 19 | { 20 | if( argc < 2 || argc > 3 ) 21 | { 22 | fprintf( stderr, "Usage: ungi compressed.gi [uncompressed.bin]\n" ); 23 | return argv ? EXIT_FAILURE : EXIT_SUCCESS; 24 | } 25 | FILE * infile = fopen( argv[1], "rb" ); 26 | if( !infile ) 27 | { 28 | fprintf( stderr, "Can't open file: %s\n", argv[1] ); 29 | return EXIT_FAILURE; 30 | } 31 | FILE * outfile = NULL; 32 | if( argc == 3 ) 33 | { 34 | outfile = fopen( argv[2], "wb" ); 35 | if( !outfile ) 36 | { 37 | fprintf( stderr, "Can't open file: %s\n", argv[2] ); 38 | return EXIT_FAILURE; 39 | } 40 | } 41 | else 42 | { 43 | size_t i = strlen( argv[1] ); 44 | char * filename = checked_malloc( i + 5 ); 45 | memcpy( filename, argv[1], i ); 46 | filename[i] = '.'; 47 | filename[i + 1] = 'b'; 48 | filename[i + 2] = 'i'; 49 | filename[i + 3] = 'n'; 50 | outfile = fopen( filename, "wb" ); 51 | if( !outfile ) 52 | { 53 | fprintf( stderr, "Can't open file: %s\n", filename ); 54 | return EXIT_FAILURE; 55 | } 56 | free( filename ); 57 | } 58 | 59 | uint8_t * input = checked_malloc( 0x20 ); 60 | if( !fread( input, 0x20, 1, infile ) ) 61 | { 62 | fprintf( stderr, "Can't read file: %s\n", argv[1] ); 63 | return EXIT_FAILURE; 64 | } 65 | uint_fast32_t inlength = (uint_fast32_t)input[2] | 66 | (uint_fast32_t)input[3] << 8 | 67 | (uint_fast32_t)input[4] << 16 | 68 | (uint_fast32_t)input[5] << 24; 69 | //fprintf( stdout, "Input length: %08" PRIXFAST32 "\n", inlength ); 70 | uint_fast32_t outlength = (uint_fast32_t)input[6] | 71 | (uint_fast32_t)input[7] << 8 | 72 | (uint_fast32_t)input[8] << 16 | 73 | (uint_fast32_t)input[9] << 24; 74 | //fprintf( stdout, "Output length: %08" PRIXFAST32 "\n", outlength ); 75 | free( input ); 76 | input = checked_malloc( inlength ); 77 | if( !fread( input, inlength, 1, infile ) ) 78 | { 79 | fprintf( stderr, "Can't read file: %s\n", argv[1] ); 80 | return EXIT_FAILURE; 81 | } 82 | uint_fast32_t offset = (uint_fast32_t)(input[0] & ~0xc0) << 24 | 83 | (uint_fast32_t)input[1] << 16 | 84 | (uint_fast32_t)input[2] << 8 | 85 | (uint_fast32_t)input[3]; 86 | if( offset != 0x100000 ) 87 | { 88 | fprintf( stderr, "Unexpected offset! (0x%08" PRIXFAST32 ")\n", offset ); 89 | } 90 | uint8_t * output = checked_malloc( outlength ); 91 | for( uint_fast32_t i = 0; i < inlength; i += 0x13c8 ) 92 | { 93 | uint_fast32_t start = ((uint_fast32_t)(input[i] & ~0xc0) << 24 | 94 | (uint_fast32_t)input[i + 1] << 16 | 95 | (uint_fast32_t)input[i + 2] << 8 | 96 | (uint_fast32_t)input[i + 3]) - offset; 97 | uint_fast32_t length = (uint_fast32_t)input[i + 4] << 9 | 98 | (uint_fast32_t)input[i + 5] << 1; 99 | fprintf( stdout, "Debug: %08" PRIXFAST32 " %02" PRIX8 " %08" PRIXFAST32 " %05" PRIXFAST32 "\n", i+0x20, input[i], start, length ); 100 | if( input[i] & 0x80 ) 101 | { 102 | memcpy( output + start, input + i + 6, length ); 103 | } 104 | else 105 | { 106 | if( decompress( input + i + 6, output + start, 0x13c2, length ) != length ) 107 | { 108 | fprintf( stderr, "Invalid compressed data!\n" ); 109 | return EXIT_FAILURE; 110 | } 111 | } 112 | } 113 | fwrite( output, outlength, 1, outfile ); 114 | return EXIT_SUCCESS; 115 | } 116 | -------------------------------------------------------------------------------- /unsa.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "lzss.h" 6 | 7 | static inline void * checked_malloc( size_t size ) 8 | { 9 | void * x = malloc( size ); 10 | if( !x ) 11 | { 12 | fprintf( stderr, "Allocation of 0x%zX bytes failed\n", size ); 13 | exit( EXIT_FAILURE ); 14 | } 15 | return memset( x, 0, size ); 16 | } 17 | 18 | int main( const int argc, const char * const * const argv ) 19 | { 20 | if( argc < 2 || argc > 3 ) 21 | { 22 | fprintf( stderr, "Usage: unsa compressed.sa [uncompressed.bin]\n" ); 23 | return argv ? EXIT_FAILURE : EXIT_SUCCESS; 24 | } 25 | FILE * infile = fopen( argv[1], "rb" ); 26 | if( !infile ) 27 | { 28 | fprintf( stderr, "Can't open file: %s\n", argv[1] ); 29 | return EXIT_FAILURE; 30 | } 31 | FILE * outfile = NULL; 32 | if( argc == 3 ) 33 | { 34 | outfile = fopen( argv[2], "wb" ); 35 | if( !outfile ) 36 | { 37 | fprintf( stderr, "Can't open file: %s\n", argv[2] ); 38 | return EXIT_FAILURE; 39 | } 40 | } 41 | else 42 | { 43 | size_t i = strlen( argv[1] ); 44 | char * filename = checked_malloc( i + 5 ); 45 | memcpy( filename, argv[1], i ); 46 | filename[i] = '.'; 47 | filename[i + 1] = 'b'; 48 | filename[i + 2] = 'i'; 49 | filename[i + 3] = 'n'; 50 | outfile = fopen( filename, "wb" ); 51 | if( !outfile ) 52 | { 53 | fprintf( stderr, "Can't open file: %s\n", filename ); 54 | return EXIT_FAILURE; 55 | } 56 | free( filename ); 57 | } 58 | 59 | uint8_t * input = checked_malloc( 0x34 ); 60 | if( !fread( input, 0x34, 1, infile ) ) 61 | { 62 | fprintf( stderr, "Can't read file: %s\n", argv[1] ); 63 | return EXIT_FAILURE; 64 | } 65 | uint_fast32_t inlength = (uint_fast32_t)input[2] << 24 | 66 | (uint_fast32_t)input[3] << 16 | 67 | (uint_fast32_t)input[4] << 8 | 68 | (uint_fast32_t)input[5]; 69 | //fprintf( stdout, "Input length: %08" PRIXFAST32 "\n", inlength ); 70 | uint_fast32_t outlength = (uint_fast32_t)input[6] << 24 | 71 | (uint_fast32_t)input[7] << 16 | 72 | (uint_fast32_t)input[8] << 8 | 73 | (uint_fast32_t)input[9]; 74 | //fprintf( stdout, "Output length: %08" PRIXFAST32 "\n", outlength ); 75 | free( input ); 76 | input = checked_malloc( inlength ); 77 | if( !fread( input, inlength, 1, infile ) ) 78 | { 79 | fprintf( stderr, "Can't read file: %s\n", argv[1] ); 80 | return EXIT_FAILURE; 81 | } 82 | uint8_t * output = checked_malloc( outlength ); 83 | if( decompress( input, output, inlength, outlength ) != outlength ) 84 | { 85 | fprintf( stderr, "Invalid compressed data!\n" ); 86 | return EXIT_FAILURE; 87 | } 88 | fwrite( output, outlength, 1, outfile ); 89 | return EXIT_SUCCESS; 90 | } 91 | --------------------------------------------------------------------------------