/* Copyright 2007,2008 Luigi Auriemma This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA http://www.gnu.org/licenses/gpl.txt */ #define _LARGE_FILES // if it's not supported the tool will work #define __USE_LARGEFILE64 // without support for large files #define __USE_FILE_OFFSET64 #define _LARGEFILE_SOURCE #define _LARGEFILE64_SOURCE #define _FILE_OFFSET_BITS 64 #include #include #include #include #include typedef uint8_t u8; typedef uint16_t u16; typedef uint32_t u32; typedef uint64_t u64; #define VER "0.1.1" #define BBIS_SIGN 0x73696262 #define BLHR_SIGN 0x72686c62 #define BSDR_SIGN 0x72647362 #define PRINTF64(x) (u32)(x >> 32), (u32)(x) // I64x, llx? blah #if defined(__MINGW32__) && defined(_LARGE_FILES) #define off_t off64_t #define fopen fopen64 #define fseek fseeko64 #define ftell ftello64 #endif u8 *show_hash(u8 *hash); void myalloc(u8 **data, unsigned wantsize, unsigned *currsize); void myfr(FILE *fd, void *data, unsigned size); void myfw(FILE *fd, void *data, unsigned size); int unzip(z_stream *z, u8 *in, int insz, u8 *out, int outsz); void std_err(void); #pragma pack(2) typedef struct { u32 sign; // blhr u32 size; // size of the data plus ver and num u32 ver; // ignored u32 num; // number of blhr_data structures } blhr_t; typedef struct { u64 offset; // input offset u32 zsize; // block size u32 sector; // where to place the output u32 size; // size in sectors! u32 type; // type } blhr_data_t; typedef struct { u32 sign; // bbis u32 unknown1; // ignored, probably the size of the structure u16 ver; // version, 1 u32 image_type; // 8 u16 padding; // ignored u32 sectors; // number of sectors of the ISO u32 sectorsz; // CD use sectors and this is the size of them (chunks) u32 unknown2; // almost ignored u64 blhr; // where is located the blhr header u32 blhrbbissz; // total size of the blhr and bbis headers u8 hash[16]; // hash? what algo? u32 unknown3; // ignored u32 unknown4; // ignored } bbis_t; #pragma pack() int main(int argc, char *argv[]) { z_stream z; blhr_data_t *blhr_data; blhr_t blhr; bbis_t bbis; FILE *fdi, *fdo; u64 tot, file_size; int i, insz, outsz; u8 ans[8], *filei, *fileo, *in, *out; setbuf(stdout, NULL); fputs("\n" "UIF2ISO "VER"\n" "by Luigi Auriemma\n" "e-mail: aluigi@autistici.org\n" "web: aluigi.org\n" "\n", stdout); if(argc < 3) { printf("\n" "Usage: %s \n" "\n", argv[0]); exit(1); } filei = argv[1]; fileo = argv[2]; printf("- open %s\n", filei); fdi = fopen(filei, "rb"); if(!fdi) std_err(); printf("- create %s\n", fileo); fdo = fopen(fileo, "rb"); if(fdo) { fclose(fdo); printf("- the output file already exists, do you want to overwrite it (y/N)? "); if(!fgets(ans, sizeof(ans), stdin)) exit(1); if((ans[0] != 'y') && (ans[0] != 'Y')) exit(1); } fdo = fopen(fileo, "wb"); if(!fdo) std_err(); z.zalloc = (alloc_func)0; z.zfree = (free_func)0; z.opaque = (voidpf)0; if(inflateInit2(&z, 15)) { printf("\nError: zlib initialization error\n"); exit(1); } fseek(fdi, 0, SEEK_END); file_size = ftell(fdi); if(fseek(fdi, file_size - sizeof(bbis), SEEK_SET)) { if(((file_size - sizeof(bbis)) > 0x7fffffff) && ((file_size - sizeof(bbis)) < file_size)) printf(" an error here means that your exe has no full LARGE_FILES 64 bit support!\n"); std_err(); } myfr(fdi, &bbis, sizeof(bbis)); if(bbis.sign != BBIS_SIGN) { printf("\nError: wrong bbis signature (%08x)\n", bbis.sign); exit(1); } printf("\n" " file size %08x%08x\n" " version %hu\n" " image type %u\n" " padding %hu\n" " sectors %u\n" " sectors size %u\n" " blhr offset %08x%08x\n" " blhr size %u\n" " hash %s\n" " unknowns %08x %08x %08x %08x\n", PRINTF64(file_size), bbis.ver, bbis.image_type, bbis.padding, bbis.sectors, bbis.sectorsz, PRINTF64(bbis.blhr), bbis.blhrbbissz, show_hash(bbis.hash), bbis.unknown1, bbis.unknown2, bbis.unknown3, bbis.unknown4); if(fseek(fdi, bbis.blhr, SEEK_SET)) std_err(); myfr(fdi, &blhr, sizeof(blhr)); if(blhr.sign != BLHR_SIGN) { if(blhr.sign == BSDR_SIGN) { printf("\nError: the input UIF is password protected (not yet supported)\n"); } else { printf("\nError: wrong blhr signature (%08x)\n", blhr.sign); } exit(1); } in = out = NULL; insz = outsz = 0; tot = 0; myalloc(&in, blhr.size - 8, &insz); myfr(fdi, in, insz); blhr_data = (void *)malloc(sizeof(blhr_data_t) * blhr.num); if(!blhr_data) std_err(); unzip(&z, in, insz, (void *)blhr_data, sizeof(blhr_data_t) * blhr.num); for(i = 0; i < blhr.num; i++) { printf(" %03d%%\r", (i * 100) / blhr.num); #ifdef VERBOSE printf("\n" "offset %08x%08x\n" "input size %08x\n" "output sector %08x\n" "sectors %08x\n", PRINTF64(blhr_data[i].offset), blhr_data[i].zsize, blhr_data[i].sector, blhr_data[i].size); #endif myalloc(&in, blhr_data[i].zsize, &insz); if(blhr_data[i].zsize) { if(fseek(fdi, blhr_data[i].offset, SEEK_SET)) std_err(); myfr(fdi, in, blhr_data[i].zsize); } blhr_data[i].size *= bbis.sectorsz; myalloc(&out, blhr_data[i].size, &outsz); switch(blhr_data[i].type) { case 1: { // non compressed if(blhr_data[i].zsize > blhr_data[i].size) { printf("\nError: input size is bigger than output\n"); exit(1); } memcpy(out, in, blhr_data[i].zsize); memset(out + blhr_data[i].zsize, 0, blhr_data[i].size - blhr_data[i].zsize); // needed? break; } case 3: { // multi byte memset(out, 0, blhr_data[i].size); break; } case 5: { // compressed unzip(&z, in, blhr_data[i].zsize, out, blhr_data[i].size); break; } default: { printf("\nError: unknown type (%d)\n", blhr_data[i].type); exit(1); } } if(fseek(fdo, blhr_data[i].sector * bbis.sectorsz, SEEK_SET)) std_err(); myfw(fdo, out, blhr_data[i].size); tot += blhr_data[i].size; } printf(" 100%%\n" "- 0x%08x%08x bytes written\n", PRINTF64(tot)); inflateEnd(&z); fclose(fdi); fclose(fdo); return(0); } u8 *show_hash(u8 *hash) { int i; static u8 vis[33]; static const char hex[16] = "0123456789abcdef"; u8 *p; p = vis; for(i = 0; i < 16; i++) { *p++ = hex[hash[i] >> 4]; *p++ = hex[hash[i] & 15]; } *p = 0; return(vis); } void myalloc(u8 **data, unsigned wantsize, unsigned *currsize) { if(wantsize <= *currsize) return; *data = realloc(*data, wantsize); if(!*data) std_err(); *currsize = wantsize; } void myfr(FILE *fd, void *data, unsigned size) { if(fread(data, 1, size, fd) == size) return; printf("\nError: incomplete input file, can't read %u bytes\n", size); exit(1); } void myfw(FILE *fd, void *data, unsigned size) { if(fwrite(data, 1, size, fd) == size) return; printf("\nError: problems during the writing of the output file\n"); exit(1); } int unzip(z_stream *z, u8 *in, int insz, u8 *out, int outsz) { inflateReset(z); z->next_in = in; z->avail_in = insz; z->next_out = out; z->avail_out = outsz; if(inflate(z, Z_SYNC_FLUSH) != Z_STREAM_END) { printf("\nError: the compressed input is wrong or incomplete\n"); exit(1); } return(z->total_out); } void std_err(void) { perror("\nError"); exit(1); }