From a0ea70a18b10ea397052cdf4d7ca8cf0199631fa Mon Sep 17 00:00:00 2001 From: dborth Date: Mon, 13 Oct 2008 18:15:03 +0000 Subject: [PATCH] 7z support (not working) --- Makefile.wii | 2 +- source/ngc/dvd.c | 140 ++++++++++- source/ngc/dvd.h | 1 + source/ngc/fileop.c | 35 ++- source/ngc/fileop.h | 1 + source/ngc/filesel.c | 175 ++++++++++---- source/ngc/filesel.h | 1 + source/ngc/gcunzip.c | 549 ++++++++++++++++++------------------------- source/ngc/gcunzip.h | 3 + source/ngc/smbop.c | 51 +++- source/ngc/smbop.h | 5 +- source/sz/7zTypes.h | 12 +- 12 files changed, 590 insertions(+), 385 deletions(-) diff --git a/Makefile.wii b/Makefile.wii index 47c9ae7..874ade7 100644 --- a/Makefile.wii +++ b/Makefile.wii @@ -21,7 +21,7 @@ BUILD := build_wii SOURCES := source/fceultra source/fceultra/boards \ source/fceultra/drivers/common source/fceultra/input \ source/fceultra/mappers source/fceultra/mbshare \ - source/ngc + source/ngc source/sz DATA := data INCLUDES := source/fceultra source/ngc LANG := ENGLISH # Supported languages: ENGLISH diff --git a/source/ngc/dvd.c b/source/ngc/dvd.c index f8a43de..fb4946f 100644 --- a/source/ngc/dvd.c +++ b/source/ngc/dvd.c @@ -36,7 +36,6 @@ volatile unsigned long *dvd = (volatile unsigned long *) 0xCC006000; unsigned char DVDreadbuffer[2048] ATTRIBUTE_ALIGN (32); unsigned char dvdbuffer[2048]; - /**************************************************************************** * dvd_read * @@ -83,6 +82,135 @@ dvd_read (void *dst, unsigned int len, u64 offset) return 0; } +/**************************************************************************** + * dvd_buffered_read + * + * the GC's dvd drive only supports offsets and length which are a multiple + * of 32 bytes additionally the max length of a read is 2048 bytes + * this function removes these limitations + * additionally the 7zip SDK does often read data in 1 byte parts from the + * DVD even when it could read 32 bytes. the dvdsf_buffer has been added to + * avoid having to read the same sector over and over again + ***************************************************************************/ + +#define DVD_LENGTH_MULTIPLY 32 +#define DVD_OFFSET_MULTIPLY 32 +#define DVD_MAX_READ_LENGTH 2048 +#define DVD_SECTOR_SIZE 2048 + +unsigned char dvdsf_buffer[DVD_SECTOR_SIZE]; +u64 dvdsf_last_offset = 0; +u64 dvdsf_last_length = 0; + +int dvd_buffered_read(void *dst, u32 len, u64 offset) +{ + int ret = 0; + + // only read data if the data inside dvdsf_buffer cannot be used + if(offset != dvdsf_last_offset || len > dvdsf_last_length) + { + memset(&dvdsf_buffer, '\0', DVD_SECTOR_SIZE); + ret = dvd_read(&dvdsf_buffer, len, offset); + dvdsf_last_offset = offset; + dvdsf_last_length = len; + } + + memcpy(dst, &dvdsf_buffer, len); + return ret; +} + +int dvd_safe_read(void *dst_v, u32 len, u64 offset) +{ + unsigned char buffer[DVD_SECTOR_SIZE]; // buffer for one dvd sector + + // if read size and length are a multiply of DVD_(OFFSET,LENGTH)_MULTIPLY and length < DVD_MAX_READ_LENGTH + // we don't need to fix anything + if(len % DVD_LENGTH_MULTIPLY == 0 && offset % DVD_OFFSET_MULTIPLY == 0 && len <= DVD_MAX_READ_LENGTH) + { + int ret = dvd_buffered_read(buffer, len, offset); + memcpy(dst_v, &buffer, len); + return ret; + } + else + { + // no errors yet -> ret = 0 + // the return value of dvd_read will be OR'd with ret + // because dvd_read does return 1 on error and 0 on success and + // because 0 | 1 = 1 ret will also contain 1 if at least one error + // occured and 0 otherwise ;) + int ret = 0; // return value of dvd_read + + // we might need to fix all 3 issues + unsigned char *dst = (unsigned char *)dst_v; // gcc will not allow to use var[num] on void* types + u64 bytesToRead; // the number of bytes we still need to read & copy to the output buffer + u64 currentOffset; // the current dvd offset + u64 bufferOffset; // the current buffer offset + u64 i, j, k; // temporary variables which might be used for different stuff + // unsigned char buffer[DVD_SECTOR_SIZE]; // buffer for one dvd sector + + currentOffset = offset; + bytesToRead = len; + bufferOffset = 0; + + // fix first issue (offset is not a multiply of 32) + if(offset % DVD_OFFSET_MULTIPLY) + { + // calculate offset of the prior 32 byte position + i = currentOffset - (currentOffset % DVD_OFFSET_MULTIPLY); + + // calculate the offset from which the data of the dvd buffer will be copied + j = currentOffset % DVD_OFFSET_MULTIPLY; + + // calculate the number of bytes needed to reach the next DVD_OFFSET_MULTIPLY byte mark + k = DVD_OFFSET_MULTIPLY - j; + + // maybe we'll only need to copy a few bytes and we therefore don't even reach the next sector + if(k > len) + { + k = len; + } + + // read 32 bytes from the last 32 byte position + ret |= dvd_buffered_read(buffer, DVD_OFFSET_MULTIPLY, i); + + // copy the bytes to the output buffer and update currentOffset, bufferOffset and bytesToRead + memcpy(&dst[bufferOffset], &buffer[j], k); + currentOffset += k; + bufferOffset += k; + bytesToRead -= k; + } + + // fix second issue (more than 2048 bytes are needed) + if(bytesToRead > DVD_MAX_READ_LENGTH) + { + // calculate the number of 2048 bytes sector needed to get all data + i = (bytesToRead - (bytesToRead % DVD_MAX_READ_LENGTH)) / DVD_MAX_READ_LENGTH; + + // read data in 2048 byte sector + for(j = 0; j < i; j++) + { + ret |= dvd_buffered_read(buffer, DVD_MAX_READ_LENGTH, currentOffset); // read sector + memcpy(&dst[bufferOffset], buffer, DVD_MAX_READ_LENGTH); // copy to output buffer + + // update currentOffset, bufferOffset and bytesToRead + currentOffset += DVD_MAX_READ_LENGTH; + bufferOffset += DVD_MAX_READ_LENGTH; + bytesToRead -= DVD_MAX_READ_LENGTH; + } + } + + // fix third issue (length is not a multiply of 32) + if(bytesToRead) + { + ret |= dvd_buffered_read(buffer, DVD_MAX_READ_LENGTH, currentOffset); // read 32 byte from the dvd + memcpy(&dst[bufferOffset], buffer, bytesToRead); // copy bytes to output buffer + } + + //free(tmp); + return ret; + } +} + /** Minimal ISO Directory Definition **/ #define RECLEN 0 /* Record length */ #define EXTENT 6 /* Extent */ @@ -449,7 +577,11 @@ LoadDVDFile (unsigned char *buffer, int length) { dvd_read (readbuffer, 2048, discoffset); - if (!IsZipFile (readbuffer)) + if (IsZipFile (readbuffer)) + { + return UnZipDVDFile (buffer, discoffset); // unzip from dvd + } + else { for (i = 0; i < blocks; i++) { @@ -467,10 +599,6 @@ LoadDVDFile (unsigned char *buffer, int length) memcpy (buffer + offset, readbuffer, i); } } - else - { - return UnZipDVDFile (buffer, discoffset); // unzip from dvd - } } return dvddirlength; } diff --git a/source/ngc/dvd.h b/source/ngc/dvd.h index 27ad386..2927778 100644 --- a/source/ngc/dvd.h +++ b/source/ngc/dvd.h @@ -17,6 +17,7 @@ int ParseDVDdirectory (); int LoadDVDFile (unsigned char *buffer, int length); bool TestDVD(); int dvd_read (void *dst, unsigned int len, u64 offset); +int dvd_safe_read (void *dst, unsigned int len, u64 offset); bool SwitchDVDFolder(char dir[]); #endif diff --git a/source/ngc/fileop.c b/source/ngc/fileop.c index 93255bd..fb376a1 100644 --- a/source/ngc/fileop.c +++ b/source/ngc/fileop.c @@ -147,6 +147,7 @@ ParseFATdirectory(int method) strncpy(filelist[nbfiles].displayname, filename, MAXDISPLAY+1); // crop name for display filelist[nbfiles].length = filestat.st_size; filelist[nbfiles].flags = (filestat.st_mode & _IFDIR) == 0 ? 0 : 1; // flag this as a dir + filelist[nbfiles].offset = 0; nbfiles++; } } @@ -162,7 +163,9 @@ ParseFATdirectory(int method) /**************************************************************************** * LoadFATFile - ****************************************************************************/ + * length > 0 - partial file read (starting from start) + * length = 0 - full read + ***************************************************************************/ int LoadFATFile (char * rbuffer, int length) { @@ -171,10 +174,7 @@ LoadFATFile (char * rbuffer, int length) FILE *handle; u32 size; - /* Check filename length */ - if ((strlen(currentdir)+1+strlen(filelist[selection].filename)) < MAXPATHLEN) - sprintf(filepath, "%s/%s",currentdir,filelist[selection].filename); - else + if (!MakeROMPath(filepath, METHOD_SD)) { WaitPrompt((char*) "Maximum filepath length reached!"); return -1; @@ -194,7 +194,7 @@ LoadFATFile (char * rbuffer, int length) if (IsZipFile (zipbuffer)) { - size = UnZipFATFile ((unsigned char *)rbuffer, handle); // unzip from FAT + size = UnZipFATFile ((unsigned char *)rbuffer, handle); // unzip from FAT } else { @@ -216,6 +216,29 @@ LoadFATFile (char * rbuffer, int length) } } +/**************************************************************************** + * LoadFATSzFile + * Loads the selected file # from the specified 7z into rbuffer + * Returns file size + ***************************************************************************/ +int +LoadFATSzFile(char * filepath, unsigned char * rbuffer) +{ + u32 size; + FILE *handle = fopen (filepath, "rb"); + if (handle > 0) + { + size = SzExtractFile(filelist[selection].offset, rbuffer); + fclose (handle); + return size; + } + else + { + WaitPrompt((char*) "Error opening file"); + return 0; + } +} + /**************************************************************************** * Load savebuffer from FAT file ***************************************************************************/ diff --git a/source/ngc/fileop.h b/source/ngc/fileop.h index 2b778a3..b4dce38 100644 --- a/source/ngc/fileop.h +++ b/source/ngc/fileop.h @@ -24,6 +24,7 @@ bool ChangeFATInterface(int method, bool silent); int ParseFATdirectory(int method); +int LoadFATSzFile(char * filepath, unsigned char * rbuffer); int LoadFATFile (char * fbuffer, int length); int SaveBufferToFAT (char *filepath, int datasize, bool silent); int LoadSaveBufferFromFAT (char *filepath, bool silent); diff --git a/source/ngc/filesel.c b/source/ngc/filesel.c index 5365bad..d77d021 100644 --- a/source/ngc/filesel.c +++ b/source/ngc/filesel.c @@ -34,6 +34,7 @@ int offset; int selection; char currentdir[MAXPATHLEN]; +char szpath[MAXPATHLEN]; char romFilename[200]; int nesGameType; int maxfiles; @@ -44,6 +45,7 @@ extern int dvddirlength; // Global file entry table FILEENTRIES filelist[MAXFILES]; +bool inSz = false; unsigned char savebuffer[SAVEBUFFERSIZE]; @@ -164,6 +166,28 @@ int UpdateDirName(int method) } } +bool MakeROMPath(char filepath[], int method) +{ + char temppath[MAXPATHLEN]; + + // Check filename length + if ((strlen(currentdir)+1+strlen(filelist[selection].filename)) < MAXPATHLEN) + { + sprintf(temppath, "%s/%s",currentdir,filelist[selection].filename); + + if(method == METHOD_SMB) + strcpy(filepath, SMBPath(temppath)); + else + strcpy(filepath, temppath); + return true; + } + else + { + filepath[0] = 0; + return false; + } +} + /*************************************************************************** * FileSortCallback * @@ -216,12 +240,14 @@ bool IsValidROM(int method) if (p != NULL) { - if(stricmp(p, ".zip") == 0) + if(stricmp(p, ".zip") == 0 && !inSz) { // we need to check the file extension of the first file in the archive char * zippedFilename = GetFirstZipFilename (method); - if(strlen(zippedFilename) > 4) + if(zippedFilename == NULL) // we don't want to run strlen on NULL + p = NULL; + else if(strlen(zippedFilename) > 4) p = strrchr(zippedFilename, '.'); else p = NULL; @@ -247,6 +273,25 @@ bool IsValidROM(int method) return false; } +/**************************************************************************** + * IsSz + * + * Checks if the specified file is a 7z + ***************************************************************************/ + +bool IsSz() +{ + if (strlen(filelist[selection].filename) > 4) + { + char * p = strrchr(filelist[selection].filename, '.'); + + if (p != NULL) + if(stricmp(p, ".7z") == 0) + return true; + } + return false; +} + /**************************************************************************** * StripExt * @@ -318,10 +363,29 @@ int FileSelector (int method) { if ( selectit ) selectit = 0; + if (filelist[selection].flags) // This is directory { /* update current directory and set new entry list if directory has changed */ - int status = UpdateDirName(method); + + int status; + + if(inSz && selection == 0) // inside a 7z, requesting to leave + { + if(method == METHOD_DVD) + { + dvddir = filelist[0].offset; + dvddirlength = filelist[0].length; + } + inSz = false; + status = 1; + SzClose(); + } + else + { + status = UpdateDirName(method); + } + if (status == 1) // ok, open directory { switch (method) @@ -351,48 +415,76 @@ int FileSelector (int method) haverom = 1; // quit menu } } - else // this is a file + else // this is a file { - // check that this is a valid ROM - if(!IsValidROM(method)) - return 0; - - // store the filename (w/o ext) - used for state saving - StripExt(romFilename, filelist[selection].filename); - - ShowAction ((char *)"Loading..."); - - int size = 0; - - switch (method) + // 7z file - let's open it up to select a file inside + if(IsSz()) { - case METHOD_SD: - case METHOD_USB: - size = LoadFATFile((char *)nesrom, 0); - break; - - case METHOD_DVD: - dvddir = filelist[selection].offset; - dvddirlength = filelist[selection].length; - size = LoadDVDFile(nesrom, 0); - break; - - case METHOD_SMB: - size = LoadSMBFile((char *)nesrom, 0); - break; - } - - if (size > 0) - { - if(GCMemROM(method, size) > 0) - return 1; - else - return 0; + // we'll store the 7z filepath for extraction later + if(!MakeROMPath(szpath, method)) + { + WaitPrompt((char*) "Maximum filepath length reached!"); + return -1; + } + maxfiles = SzParse(szpath, method); + if(maxfiles) + inSz = true; } else { - WaitPrompt((char*) "Error loading ROM!"); - return 0; + // check that this is a valid ROM + if(!IsValidROM(method)) + return 0; + + // store the filename (w/o ext) - used for state saving + StripExt(romFilename, filelist[selection].filename); + + ShowAction ((char *)"Loading..."); + + int size = 0; + + switch (method) + { + case METHOD_SD: + case METHOD_USB: + if(inSz) + size = LoadFATSzFile(szpath, nesrom); + else + size = LoadFATFile((char *)nesrom, 0); + break; + + case METHOD_DVD: + if(inSz) + size = SzExtractFile(filelist[selection].offset, nesrom); + else + { + dvddir = filelist[selection].offset; + dvddirlength = filelist[selection].length; + size = LoadDVDFile(nesrom, 0); + } + break; + + case METHOD_SMB: + if(inSz) + size = LoadSMBSzFile(szpath, nesrom); + else + size = LoadSMBFile((char *)nesrom, 0); + break; + } + inSz = false; + + if (size > 0) + { + if(GCMemROM(method, size) > 0) + return 1; + else + return 0; + } + else + { + WaitPrompt((char*) "Error loading ROM!"); + return 0; + } } } redraw = 1; @@ -413,7 +505,8 @@ int FileSelector (int method) else if ( strcmp(filelist[1].filename,"..") == 0 ) { selection = selectit = 1; - } else { + } else + { return 0; } } // End of B diff --git a/source/ngc/filesel.h b/source/ngc/filesel.h index cd88d97..a145cf8 100644 --- a/source/ngc/filesel.h +++ b/source/ngc/filesel.h @@ -39,6 +39,7 @@ extern char romFilename[]; extern int nesGameType; void ClearSaveBuffer (); +bool MakeROMPath(char filepath[], int method); int OpenROM (int method); int autoLoadMethod(); int autoSaveMethod(); diff --git a/source/ngc/gcunzip.c b/source/ngc/gcunzip.c index 3899709..9d677a2 100644 --- a/source/ngc/gcunzip.c +++ b/source/ngc/gcunzip.c @@ -15,6 +15,10 @@ #include #include +#include "../sz/7zCrc.h" +#include "../sz/7zIn.h" +#include "../sz/7zExtract.h" + #include "fceuconfig.h" #include "dvd.h" #include "smbop.h" @@ -22,6 +26,10 @@ #include "menudraw.h" #include "gcunzip.h" +FILE* fatfile; // FAT +u64 discoffset; // DVD +SMBFILE smbfile; // SMB + /* * PKWare Zip Header - adopted into zip standard */ @@ -60,7 +68,6 @@ FLIP16 (u16 b) * IsZipFile * * Returns 1 when Zip signature is found - * Returns 2 when 7z signature is found ****************************************************************************/ int IsZipFile (char *buffer) @@ -71,28 +78,17 @@ IsZipFile (char *buffer) if (check[0] == 0x504b0304) // ZIP file return 1; - // 7z signature - static Byte Signature[6] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C}; - - int i; - for(i = 0; i < 6; i++) - if(buffer[i] != Signature[i]) - return 0; - - return 2; // 7z archive found + return 0; } /***************************************************************************** - * unzip + * UnZipBuffer * * It should be noted that there is a limit of 5MB total size for any ROM ******************************************************************************/ -FILE* fatfile; // FAT -u64 discoffset; // DVD -SMBFILE smbfile; // SMB int -UnZipBuffer (unsigned char *outbuffer, short where) +UnZipBuffer (unsigned char *outbuffer, int method) { PKZIPHEADER pkzip; int zipoffset = 0; @@ -107,18 +103,19 @@ UnZipBuffer (unsigned char *outbuffer, short where) char msg[128]; /*** Read Zip Header ***/ - switch (where) + switch (method) { - case 0: // SD Card + case METHOD_SD: + case METHOD_USB: fseek(fatfile, 0, SEEK_SET); fread (readbuffer, 1, ZIPCHUNK, fatfile); break; - case 1: // DVD + case METHOD_DVD: dvd_read (readbuffer, ZIPCHUNK, discoffset); break; - case 2: // From SMB + case METHOD_SMB: SMB_ReadFile(readbuffer, ZIPCHUNK, 0, smbfile); break; } @@ -184,18 +181,19 @@ UnZipBuffer (unsigned char *outbuffer, short where) zipoffset = 0; zipchunk = ZIPCHUNK; - switch (where) + switch (method) { - case 0: // SD Card + case METHOD_SD: + case METHOD_USB: fread (readbuffer, 1, ZIPCHUNK, fatfile); break; - case 1: // DVD + case METHOD_DVD: readoffset += ZIPCHUNK; dvd_read (readbuffer, ZIPCHUNK, discoffset+readoffset); break; - case 2: // From SMB + case METHOD_SMB: readoffset += ZIPCHUNK; SMB_ReadFile(readbuffer, ZIPCHUNK, readoffset, smbfile); break; @@ -220,21 +218,21 @@ int UnZipFATFile (unsigned char *outbuffer, FILE* infile) { fatfile = infile; - return UnZipBuffer(outbuffer, 0); + return UnZipBuffer(outbuffer, METHOD_SD); } // Reading from DVD int UnZipDVDFile (unsigned char *outbuffer, u64 inoffset) { discoffset = inoffset; - return UnZipBuffer(outbuffer, 1); + return UnZipBuffer(outbuffer, METHOD_DVD); } // Reading from SMB int UnZipSMBFile (unsigned char *outbuffer, SMBFILE infile) { smbfile = infile; - return UnZipBuffer(outbuffer, 2); + return UnZipBuffer(outbuffer, METHOD_SMB); } /**************************************************************************** @@ -247,81 +245,38 @@ UnZipSMBFile (unsigned char *outbuffer, SMBFILE infile) char * GetFirstZipFilename (int method) { - char testbuffer[ZIPCHUNK]; + char * firstFilename = NULL; + char tempbuffer[ZIPCHUNK]; // read start of ZIP switch (method) { case METHOD_SD: // SD Card case METHOD_USB: // USB - LoadFATFile (testbuffer, ZIPCHUNK); + LoadFATFile (tempbuffer, ZIPCHUNK); break; case METHOD_DVD: // DVD - LoadDVDFile ((unsigned char *)testbuffer, ZIPCHUNK); + LoadDVDFile ((unsigned char *)tempbuffer, ZIPCHUNK); break; case METHOD_SMB: // From SMB - LoadSMBFile (testbuffer, ZIPCHUNK); + LoadSMBFile (tempbuffer, ZIPCHUNK); break; } - testbuffer[28] = 0; // truncate - filename length is 2 bytes long (bytes 26-27) - int namelength = testbuffer[26]; // filename length starts 26 bytes in + tempbuffer[28] = 0; // truncate - filename length is 2 bytes long (bytes 26-27) + int namelength = tempbuffer[26]; // filename length starts 26 bytes in - char * firstFilename = &testbuffer[30]; // first filename of a ZIP starts 31 bytes in + firstFilename = &tempbuffer[30]; // first filename of a ZIP starts 31 bytes in firstFilename[namelength] = 0; // truncate at filename length return firstFilename; } -/* - * 7-zip functions are below. Have to be written to work with above. - * -else if (selection == 0 && inSz == true) { - rootdir = filelist[1].offset; - rootdirlength = filelist[1].length; - offset = 0; - maxfiles = parsedir(); - inSz = false; - SzClose(); -} -else if (inSz == false && SzDvdIsArchive(filelist[selection].offset) == SZ_OK) { - // parse the 7zip file - ShowAction("Found 7z"); - SzParse(); - if(SzRes == SZ_OK) { - inSz = true; - offset = selection = 0; - } else { - SzDisplayError(SzRes); - } -} -else if (inSz == true) { - // extract the selected ROM from the 7zip file to the buffer - if(SzExtractROM(filelist[selection].offset, nesrom) == true) { - haverom = 1; - inSz = false; - - // go one directory up - rootdir = filelist[1].offset; - rootdirlength = filelist[1].length; - offset = selection = 0; - maxfiles = parsedir(); - } -} -*/ - - - - -/* - * 7-zip functions are below. Have to be written to work with above. - - -#include "7zCrc.h" -#include "7zIn.h" -#include "7zExtract.h" +/**************************************************************************** + * 7z functions + ***************************************************************************/ typedef struct _SzFileInStream { @@ -331,9 +286,6 @@ typedef struct _SzFileInStream u64 pos; // current position of the file pointer } SzFileInStream; - - - // 7zip error list char szerrormsg[][30] = { "7z: Data error", @@ -357,131 +309,52 @@ size_t SzOutSizeProcessed; CFileItem *SzF; char sz_buffer[2048]; -// the GC's dvd drive only supports offsets and length which are a multiply of 32 bytes -// additionally the max length of a read is 2048 bytes -// this function removes these limitations -// additionally the 7zip SDK does often read data in 1 byte parts from the DVD even when -// it could read 32 bytes. the dvdsf_buffer has been added to avoid having to read the same sector -// over and over again -unsigned char dvdsf_buffer[DVD_SECTOR_SIZE]; -u64 dvdsf_last_offset = 0; -u64 dvdsf_last_length = 0; +/**************************************************************************** + * Is7ZipFile + * + * Returns 1 when 7z signature is found + ****************************************************************************/ +int +Is7ZipFile (char *buffer) +{ + unsigned int *check; + check = (unsigned int *) buffer; -int dvd_buffered_read(void *dst, u32 len, u64 offset) { - int ret = 0; + // 7z signature + static Byte Signature[6] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C}; - // only read data if the data inside dvdsf_buffer cannot be used - if(offset != dvdsf_last_offset || len > dvdsf_last_length) { - char msg[1024]; - sprintf(msg, "buff_read: len=%d, offset=%llX, UseSD=%d", len, offset, UseSDCARD); - //WaitPrompt(msg); - memset(&dvdsf_buffer, '\0', DVD_SECTOR_SIZE); - if (UseSDCARD) { - if (filehandle == NULL) - GetSDInfo(); + int i; + for(i = 0; i < 6; i++) + if(buffer[i] != Signature[i]) + return 0; - fseek(filehandle, offset, SEEK_SET); - fread(&dvdsf_buffer, len, 1, filehandle); - } else if (!UseWiiSDCARD) - ret = dvd_read(&dvdsf_buffer, len, offset); - dvdsf_last_offset = offset; - dvdsf_last_length = len; - } - - memcpy(dst, &dvdsf_buffer, len); - return ret; + return 1; // 7z archive found } -int dvd_safe_read(void *dst_v, u32 len, u64 offset) { - unsigned char buffer[DVD_SECTOR_SIZE]; // buffer for one dvd sector - - // if read size and length are a multiply of DVD_(OFFSET,LENGTH)_MULTIPLY and length < DVD_MAX_READ_LENGTH - // we don't need to fix anything - if(len % DVD_LENGTH_MULTIPLY == 0 && offset % DVD_OFFSET_MULTIPLY == 0 && len <= DVD_MAX_READ_LENGTH) { - char msg[1024]; - sprintf(msg, "simple_safe_read: len=%d, offset=%llX, UseSD=%d", len, offset, UseSDCARD); - //WaitPrompt(msg); - int ret = dvd_buffered_read(buffer, len, offset); - memcpy(dst_v, &buffer, len); - return ret; - } else { - char msg[1024]; - sprintf(msg, "complex_safe_read: len=%d, offset=%llX, UseSD=%d", len, offset, UseSDCARD); - //WaitPrompt(msg); - // no errors yet -> ret = 0 - // the return value of dvd_read will be OR'd with ret - // because dvd_read does return 1 on error and 0 on success and - // because 0 | 1 = 1 ret will also contain 1 if at least one error - // occured and 0 otherwise ;) - int ret = 0; // return value of dvd_read - - // we might need to fix all 3 issues - unsigned char *dst = (unsigned char *)dst_v; // gcc will not allow to use var[num] on void* types - u64 bytesToRead; // the number of bytes we still need to read & copy to the output buffer - u64 currentOffset; // the current dvd offset - u64 bufferOffset; // the current buffer offset - u64 i, j, k; // temporary variables which might be used for different stuff - // unsigned char buffer[DVD_SECTOR_SIZE]; // buffer for one dvd sector - - currentOffset = offset; - bytesToRead = len; - bufferOffset = 0; - - // fix first issue (offset is not a multiply of 32) - if(offset % DVD_OFFSET_MULTIPLY) { - // calcualte offset of the prior 32 byte position - i = currentOffset - (currentOffset % DVD_OFFSET_MULTIPLY); - - // calculate the offset from which the data of the dvd buffer will be copied - j = currentOffset % DVD_OFFSET_MULTIPLY; - - // calculate the number of bytes needed to reach the next DVD_OFFSET_MULTIPLY byte mark - k = DVD_OFFSET_MULTIPLY - j; - - // maybe we'll only need to copy a few bytes and we therefore don't even reach the next sector - if(k > len) { - k = len; - } - - // read 32 bytes from the last 32 byte position - ret |= dvd_buffered_read(buffer, DVD_OFFSET_MULTIPLY, i); - - // copy the bytes to the output buffer and update currentOffset, bufferOffset and bytesToRead - memcpy(&dst[bufferOffset], &buffer[j], k); - currentOffset += k; - bufferOffset += k; - bytesToRead -= k; - } - - // fix second issue (more than 2048 bytes are needed) - if(bytesToRead > DVD_MAX_READ_LENGTH) { - // calculate the number of 2048 bytes sector needed to get all data - i = (bytesToRead - (bytesToRead % DVD_MAX_READ_LENGTH)) / DVD_MAX_READ_LENGTH; - - // read data in 2048 byte sector - for(j = 0; j < i; j++) { - ret |= dvd_buffered_read(buffer, DVD_MAX_READ_LENGTH, currentOffset); // read sector - memcpy(&dst[bufferOffset], buffer, DVD_MAX_READ_LENGTH); // copy to output buffer - - // update currentOffset, bufferOffset and bytesToRead - currentOffset += DVD_MAX_READ_LENGTH; - bufferOffset += DVD_MAX_READ_LENGTH; - bytesToRead -= DVD_MAX_READ_LENGTH; - } - } - - // fix third issue (length is not a multiply of 32) - if(bytesToRead) { - ret |= dvd_buffered_read(buffer, DVD_MAX_READ_LENGTH, currentOffset); // read 32 byte from the dvd - memcpy(&dst[bufferOffset], buffer, bytesToRead); // copy bytes to output buffer - } - - //free(tmp); - return ret; - } +// display an error message +void SzDisplayError(SZ_RESULT res) +{ + WaitPrompt(szerrormsg[(res - 1)]); } -// function used by the 7zip SDK to read data from the DVD (fread) +// function used by the 7zip SDK to read data from FAT +SZ_RESULT SzFatFileReadImp(void *object, void **buffer, size_t maxRequiredSize, size_t *processedSize) +{ + // the void* object is a SzFileInStream + SzFileInStream *s = (SzFileInStream *)object; + + // read data + fseek(fatfile, s->pos, SEEK_SET); + fread (sz_buffer, 1, maxRequiredSize, fatfile); + + *buffer = sz_buffer; + *processedSize = maxRequiredSize; + s->pos += *processedSize; + + return SZ_OK; +} + +// function used by the 7zip SDK to read data from DVD SZ_RESULT SzDvdFileReadImp(void *object, void **buffer, size_t maxRequiredSize, size_t *processedSize) { // the void* object is a SzFileInStream @@ -504,8 +377,24 @@ SZ_RESULT SzDvdFileReadImp(void *object, void **buffer, size_t maxRequiredSize, return SZ_OK; } -// function used by the 7zip SDK to change the filepointer (fseek(object, pos, SEEK_SET)) -SZ_RESULT SzDvdFileSeekImp(void *object, CFileSize pos) +// function used by the 7zip SDK to read data from SMB +SZ_RESULT SzSMBFileReadImp(void *object, void **buffer, size_t maxRequiredSize, size_t *processedSize) +{ + // the void* object is a SzFileInStream + SzFileInStream *s = (SzFileInStream *)object; + + // read data + SMB_ReadFile(sz_buffer, maxRequiredSize, s->pos, smbfile); + + *buffer = sz_buffer; + *processedSize = maxRequiredSize; + s->pos += *processedSize; + + return SZ_OK; +} + +// function used by the 7zip SDK to change the filepointer +SZ_RESULT SzFileSeekImp(void *object, CFileSize pos) { // the void* object is a SzFileInStream SzFileInStream *s = (SzFileInStream *)object; @@ -522,126 +411,156 @@ SZ_RESULT SzDvdFileSeekImp(void *object, CFileSize pos) return SZ_OK; } -SZ_RESULT SzDvdIsArchive(u64 dvd_offset) { - // 7z signautre - static Byte Signature[6] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C}; - Byte Candidate[6]; +/**************************************************************************** + * SzParse + * + * Opens a 7z file, and parses it + * Right now doesn't parse 7z, since we'll always use the first file + * But it could parse the entire 7z for full browsing capability + ***************************************************************************/ - // read the data from the DVD - int res = dvd_safe_read (&Candidate, 6, dvd_offset); - char msg[1024]; - - size_t i; - for(i = 0; i < 6; i++) { - if(Candidate[i] != Signature[i]) { - return SZE_FAIL; - } - } - - return SZ_OK; -} - -// display an error message -void SzDisplayError(SZ_RESULT res) +int SzParse(char * filepath, int method) { - WaitPrompt(szerrormsg[(res - 1)]); + int nbfiles = 0; + + // save the offset and the length of this file inside the archive stream structure + SzArchiveStream.offset = filelist[selection].offset; + SzArchiveStream.len = filelist[selection].length; + SzArchiveStream.pos = 0; + + // set handler functions for reading data from FAT/SMB/DVD + switch (method) + { + case METHOD_SD: + case METHOD_USB: + fatfile = fopen (filepath, "rb"); + SzArchiveStream.InStream.Read = SzFatFileReadImp; + break; + case METHOD_DVD: + SzArchiveStream.InStream.Read = SzDvdFileReadImp; + break; + case METHOD_SMB: + smbfile = OpenSMBFile(filepath); + SzArchiveStream.InStream.Read = SzSMBFileReadImp; + break; + } + + SzArchiveStream.InStream.Seek = SzFileSeekImp; + + // set default 7Zip SDK handlers for allocation and freeing memory + SzAllocImp.Alloc = SzAlloc; + SzAllocImp.Free = SzFree; + SzAllocTempImp.Alloc = SzAllocTemp; + SzAllocTempImp.Free = SzFreeTemp; + + // prepare CRC and 7Zip database structures + InitCrcTable(); + SzArDbExInit(&SzDb); + + // open the archive + SzRes = SzArchiveOpen(&SzArchiveStream.InStream, &SzDb, &SzAllocImp, + &SzAllocTempImp); + + if (SzRes != SZ_OK) + { + // free memory used by the 7z SDK + SzArDbExFree(&SzDb, SzAllocImp.Free); + } + else // archive opened successfully + { + if(SzDb.Database.NumFiles > 0) + { + // Parses the 7z into a full file listing + + // store the current 7z data + unsigned int oldLength = filelist[selection].length; + u64 oldOffset = filelist[selection].offset; + + // erase all previous entries + memset(&filelist, 0, sizeof(FILEENTRIES) * MAXFILES); + + // add '..' folder + strncpy(filelist[0].displayname, "..", 2); + filelist[0].flags = 1; + filelist[0].length = oldLength; + filelist[0].offset = oldOffset; // in case the user wants exit 7z + + // get contents and parse them into file list structure + unsigned int SzI, SzJ; + SzJ = 1; + for (SzI = 0; SzI < SzDb.Database.NumFiles; SzI++) + { + SzF = SzDb.Database.Files + SzI; + + // skip directories + if (SzF->IsDirectory) + continue; + + // do not exceed MAXFILES to avoid possible buffer overflows + if (SzJ == (MAXFILES - 1)) + break; + + // parse information about this file to the dvd file list structure + strncpy(filelist[SzJ].filename, SzF->Name, MAXJOLIET); // copy joliet name (useless...) + filelist[SzJ].filename[MAXJOLIET] = 0; // terminate string + strncpy(filelist[SzJ].displayname, SzF->Name, MAXDISPLAY+1); // crop name for display + filelist[SzJ].length = SzF->Size; // filesize + filelist[SzJ].offset = SzI; // the extraction function identifies the file with this number + filelist[SzJ].flags = 0; // only files will be displayed (-> no flags) + SzJ++; + } + + // update maxfiles and select the first entry + offset = selection = 0; + nbfiles = SzJ; + } + else + { + SzArDbExFree(&SzDb, SzAllocImp.Free); + } + } + // close file + switch (method) + { + case METHOD_SD: + case METHOD_USB: + fclose(fatfile); + break; + case METHOD_SMB: + SMB_CloseFile (smbfile); + break; + } + return nbfiles; } -static u64 rootdir; -static int rootdirlength; +/**************************************************************************** + * SzClose + * + * Closes a 7z file + ***************************************************************************/ -void SzParse(void) { - // save the offset and the length of this file inside the archive stream structure - SzArchiveStream.offset = filelist[selection].offset; - SzArchiveStream.len = filelist[selection].length; - SzArchiveStream.pos = 0; - - // set handler functions for reading data from DVD and setting the position - SzArchiveStream.InStream.Read = SzDvdFileReadImp; - SzArchiveStream.InStream.Seek = SzDvdFileSeekImp; - - // set default 7Zip SDK handlers for allocation and freeing memory - SzAllocImp.Alloc = SzAlloc; - SzAllocImp.Free = SzFree; - SzAllocTempImp.Alloc = SzAllocTemp; - SzAllocTempImp.Free = SzFreeTemp; - - // prepare CRC and 7Zip database structures - InitCrcTable(); - SzArDbExInit(&SzDb); - - // open the archive - SzRes = SzArchiveOpen(&SzArchiveStream.InStream, &SzDb, &SzAllocImp, &SzAllocTempImp); - - if(SzRes != SZ_OK) - { - // free memory used by the 7z SDK - SzArDbExFree(&SzDb, SzAllocImp.Free); - return; - } - else - { - // archive opened successfully - - // erase all previous entries - memset(&filelist, 0, sizeof(FILEENTRIES) * MAXFILES); - - // add '../' folder - strncpy(filelist[0].filename, "../", 3); - filelist[0].length = rootdirlength; // store rootdir in case the user wants to go one folder up - filelist[0].offset = rootdir; // -''- rootdir length -''- - filelist[0].flags = 0; - - // get contents and parse them into the dvd file list structure - unsigned int SzI, SzJ; - SzJ = 1; - for(SzI = 0; SzI < SzDb.Database.NumFiles; SzI++) - { - SzF = SzDb.Database.Files + SzI; - - // skip directories - if(SzF->IsDirectory) - { - continue; - } - - // do not exceed MAXFILES to avoid possible buffer overflows - if(SzJ == (MAXFILES - 1)) - { - break; - } - - // parse information about this file to the dvd file list structure - strncpy(filelist[SzJ].filename, SzF->Name, MAXJOLIET); // copy joliet name (useless...) - filelist[SzJ].filename[MAXJOLIET] = 0; // terminate string - filelist[SzJ].length = SzF->Size; // filesize - filelist[SzJ].offset = SzI; // the extraction function identifies the file with this number - filelist[SzJ].flags = 0; // only files will be displayed (-> no flags) - SzJ++; - } - - // update maxfiles and select the first entry - maxfiles = SzJ; - offset = selection = 0; - return; - } -} - -void SzClose(void) +void SzClose() { - SzArDbExFree(&SzDb, SzAllocImp.Free); + if(SzDb.Database.NumFiles > 0) + SzArDbExFree(&SzDb, SzAllocImp.Free); } -bool SzExtractROM(int i, unsigned char *buffer) -{ +/**************************************************************************** + * SzExtractFile + * + * Extracts the given file # into the buffer specified + * Must parse the 7z BEFORE running this function + ***************************************************************************/ +int SzExtractFile(int i, unsigned char *buffer) +{ // prepare some variables SzBlockIndex = 0xFFFFFFFF; SzOffset = 0; // Unzip the file - //ShowAction("Un7zipping file. Please wait..."); - WaitPrompt("Un7zipping file. Please wait..."); + ShowAction("Unzipping file. Please wait..."); + SzRes = SzExtract2( &SzArchiveStream.InStream, &SzDb, @@ -654,18 +573,18 @@ bool SzExtractROM(int i, unsigned char *buffer) &SzAllocImp, &SzAllocTempImp); + // close 7Zip archive and free memory + SzClose(); + // check for errors if(SzRes != SZ_OK) { - // display error message + // display error message WaitPrompt(szerrormsg[(SzRes - 1)]); - return false; + return 0; } else { - // close 7Zip archive and free memory - SzArDbExFree(&SzDb, SzAllocImp.Free); - return true; + return SzOutSizeProcessed; } } -*/ diff --git a/source/ngc/gcunzip.h b/source/ngc/gcunzip.h index f27e3c8..932f084 100644 --- a/source/ngc/gcunzip.h +++ b/source/ngc/gcunzip.h @@ -19,6 +19,9 @@ char * GetFirstZipFilename(int method); int UnZipFATFile (unsigned char *outbuffer, FILE* infile); // Reading from FAT int UnZipDVDFile (unsigned char *outbuffer, u64 inoffset); // Reading from DVD int UnZipSMBFile (unsigned char *outbuffer, SMBFILE infile); // Reading from SMB +int SzParse(char * filepath, int method); +int SzExtractFile(int i, unsigned char *buffer); +void SzClose(); /* * Zip file header definition diff --git a/source/ngc/smbop.c b/source/ngc/smbop.c index c049c3a..258e4ed 100644 --- a/source/ngc/smbop.c +++ b/source/ngc/smbop.c @@ -201,6 +201,7 @@ ParseSMBdirectory () filelist[filecount].displayname[MAXDISPLAY] = 0; strcpy (filelist[filecount].filename, smbdir.name); + filelist[filecount].offset = 0; filecount++; } } while (SMB_FindNext (&smbdir, smbconn) == SMB_SUCCESS); @@ -214,25 +215,58 @@ ParseSMBdirectory () return filecount; } +/**************************************************************************** + * Open SMB file + ***************************************************************************/ + +SMBFILE OpenSMBFile(char * filepath) +{ + return SMB_OpenFile (SMBPath(filepath), SMB_OPEN_READING, SMB_OF_OPEN, smbconn); +} + /**************************************************************************** * Load SMB file * rom - pointer to memory where ROM will be stored * length - # bytes to read (0 for all) - ****************************************************************************/ + ***************************************************************************/ int LoadSMBFile (char * rom, int length) { char filepath[MAXPATHLEN]; /* Check filename length */ - if ((strlen(currentdir)+1+strlen(filelist[selection].filename)) < MAXPATHLEN) - sprintf(filepath, "%s/%s",currentdir,filelist[selection].filename); - else + if (!MakeROMPath(filepath, METHOD_SMB)) { WaitPrompt((char*) "Maximum filepath length reached!"); return -1; } - return LoadBufferFromSMB(rom, SMBPath(filepath), length, NOTSILENT); + return LoadBufferFromSMB(rom, filepath, length, NOTSILENT); +} + +/**************************************************************************** + * LoadSMBSzFile + * Loads the selected file # from the specified 7z into rbuffer + * Returns file size + ***************************************************************************/ +int +LoadSMBSzFile(char * filepath, unsigned char * rbuffer) +{ + if(!ConnectShare (NOTSILENT)) + return 0; + + SMBFILE smbfile = OpenSMBFile(filepath); + + if (smbfile) + { + u32 size = SzExtractFile(filelist[selection].offset, rbuffer); + SMB_CloseFile (smbfile); + return size; + } + else + { + WaitPrompt((char*) "Error opening file"); + return 0; + } } /**************************************************************************** @@ -282,7 +316,7 @@ SaveBufferToSMB (char *filepath, int datasize, bool silent) /**************************************************************************** * Load up a buffer from SMB file - ****************************************************************************/ + ***************************************************************************/ // no buffer is specified - so use savebuffer int @@ -297,13 +331,10 @@ LoadBufferFromSMB (char * sbuffer, char *filepath, int length, bool silent) if(!ConnectShare (NOTSILENT)) return 0; - SMBFILE smbfile; + SMBFILE smbfile = OpenSMBFile(filepath); int ret; int boffset = 0; - smbfile = - SMB_OpenFile (SMBPath(filepath), SMB_OPEN_READING, SMB_OF_OPEN, smbconn); - if (!smbfile) { if(!silent) diff --git a/source/ngc/smbop.h b/source/ngc/smbop.h index 5b2c9f6..2a3822d 100644 --- a/source/ngc/smbop.h +++ b/source/ngc/smbop.h @@ -10,15 +10,18 @@ ****************************************************************************/ #ifndef _SMBOP_H_ - #define _SMBOP_H_ +#include + bool InitializeNetwork(bool silent); bool ConnectShare (bool silent); char * SMBPath(char * path); int UpdateSMBdirname(); int ParseSMBdirectory (); +SMBFILE OpenSMBFile(); int LoadSMBFile (char * fbuffer, int length); +int LoadSMBSzFile(char * filepath, unsigned char * rbuffer); int LoadSaveBufferFromSMB (char *filepath, bool silent); int LoadBufferFromSMB (char * sbuffer, char *filepath, int length, bool silent); int SaveBufferToSMB (char *filepath, int datasize, bool silent); diff --git a/source/sz/7zTypes.h b/source/sz/7zTypes.h index 817d921..d58904a 100644 --- a/source/sz/7zTypes.h +++ b/source/sz/7zTypes.h @@ -5,13 +5,15 @@ #ifndef _7ZIP_BYTE_DEFINED #define _7ZIP_BYTE_DEFINED +#ifndef ZCONF_H typedef unsigned char Byte; -#endif +#endif +#endif #ifndef _7ZIP_UINT16_DEFINED #define _7ZIP_UINT16_DEFINED typedef unsigned short UInt16; -#endif +#endif #ifndef _7ZIP_UINT32_DEFINED #define _7ZIP_UINT32_DEFINED @@ -20,7 +22,7 @@ typedef unsigned long UInt32; #else typedef unsigned int UInt32; #endif -#endif +#endif /* #define _SZ_NO_INT_64 */ /* define it your compiler doesn't support long long int */ @@ -44,9 +46,9 @@ typedef unsigned long long int UInt64; #ifndef CFileSize #ifdef _SZ_FILE_SIZE_64 -typedef UInt64 CFileSize; +typedef UInt64 CFileSize; #else -typedef UInt32 CFileSize; +typedef UInt32 CFileSize; #endif #endif