void slot_autodetect(int slot, int device, t_slot *ptr) { if (!ptr) return; char filename[MAXPATHLEN]; memset(ptr,0,sizeof(t_slot)); if (!device) { /* FAT support */ if (slot > 0) sprintf (filename,"%s/saves/%s.gp%d", DEFAULT_PATH, rom_filename, slot - 1); else sprintf (filename,"%s/saves/%s.srm", DEFAULT_PATH, rom_filename); /* Open file */ FILE *fp = fopen(filename, "rb"); if (fp) { /* Retrieve date & close */ struct stat filestat; stat(filename, &filestat); struct tm *timeinfo = localtime(&filestat.st_mtime); ptr->year = 1900 + timeinfo->tm_year; ptr->month = timeinfo->tm_mon; ptr->day = timeinfo->tm_mday; ptr->hour = timeinfo->tm_hour; ptr->min = timeinfo->tm_min; fclose(fp); ptr->valid = 1; } } else { /* Memory Card support */ if (slot > 0) sprintf(filename,"MD-%04X.gp%d", rominfo.realchecksum, slot - 1); else sprintf(filename,"MD-%04X.srm", rominfo.realchecksum); /* Initialise the CARD system */ memset(&SysArea, 0, CARD_WORKAREA); CARD_Init("GENP", "00"); /* CARD slot */ device--; /* Mount CARD */ if (CardMount(device)) { /* Open file */ card_file CardFile; if (CARD_Open(device, filename, &CardFile) == CARD_ERROR_READY) { /* Retrieve date & close */ card_stat CardStatus; CARD_GetStatus(device, CardFile.filenum, &CardStatus); time_t rawtime = CardStatus.time; struct tm *timeinfo = localtime(&rawtime); ptr->year = 1900 + timeinfo->tm_year; ptr->month = timeinfo->tm_mon; ptr->day = timeinfo->tm_mday; ptr->hour = timeinfo->tm_hour; ptr->min = timeinfo->tm_min; CARD_Close(&CardFile); ptr->valid = 1; } CARD_Unmount(device); } } }
// This is only called where length = file.size int deviceHandler_CARD_readFile(file_handle* file, void* buffer, unsigned int length){ unsigned int slot = file->fileBase>>24, ret = 0, file_no = file->fileBase&0xFFFFFF; void *dst = buffer; // Get the sector size u32 SectorSize = 0; CARD_GetSectorSize (slot, &SectorSize); // Create the .gci header card_stat CardStat; GCI gci; CARD_GetStatus(slot,file_no,&CardStat); memset(&gci, 0xFF, sizeof(GCI)); /*** Populate the GCI ***/ memcpy(&gci.gamecode, &CardStat.gamecode, 4); memcpy(&gci.company, &CardStat.company, 2); gci.banner_fmt = CardStat.banner_fmt; memcpy(&gci.filename, &CardStat.filename, 0x20); gci.time = CardStat.time; gci.icon_addr = CardStat.icon_addr; gci.icon_fmt = CardStat.icon_fmt; gci.icon_speed = CardStat.icon_speed; gci.unknown1 = gci.unknown2 = 0; gci.index = 32; gci.filesize8 = (CardStat.len / 8192); gci.comment_addr = CardStat.comment_addr; memcpy(dst, &gci, sizeof(GCI)); dst+= sizeof(GCI); // Re-init the card with the original file gamecode & company char game_code[16]; memcpy(&game_code[0],&gci.gamecode, 4); game_code[4] = 0; CARD_SetGamecode((const char *)&game_code[0]); memcpy(&game_code[0],&gci.company, 2); game_code[2] = 0; CARD_SetCompany((const char *)&game_code[0]); // Use the original file name char file_name[CARD_FILENAMELEN]; memset(&file_name[0],0,CARD_FILENAMELEN); memcpy(&file_name[0], file->name,strlen(file->name)-4); print_gecko("Try to open: [%s]\r\n",&file_name[0]); // Read the actual file data now char *read_buffer = NULL; card_file *memcard_file = NULL; memcard_file = (card_file*)memalign(32,sizeof(card_file)); if(!memcard_file) { return -2; } memset(memcard_file, 0, sizeof(card_file)); // Open the Entry if((ret = CARD_Open(slot, (const char*)&file_name[0], memcard_file)) != CARD_ERROR_NOFILE){ /* Allocate the read buffer */ u32 readSize = ((memcard_file->len % SectorSize) != 0) ? ((memcard_file->len/SectorSize)+1) * SectorSize : memcard_file->len; read_buffer = memalign(32,SectorSize); if(!read_buffer) { free(memcard_file); return -2; } print_gecko("Reading: [%i] bytes\r\n",readSize); /* Read the file */ int i = 0; for(i=0;i<(readSize/SectorSize);i++) { ret = CARD_Read(memcard_file,read_buffer, SectorSize, i*SectorSize); if(!ret) { memcpy(dst,read_buffer,(i==(readSize/SectorSize)-1) ? (memcard_file->len % SectorSize):SectorSize); } dst+=SectorSize; print_gecko("Read: [%i] bytes ret [%i]\r\n",SectorSize,ret); } } else { print_gecko("ret: [%i]\r\n",ret); } CARD_Close(memcard_file); free(read_buffer); free(memcard_file); return !ret ? length : ret; }
int slot_save(int slot, int device) { char filename[MAXPATHLEN]; int filesize, done = 0; int offset = device ? 2112 : 0; u8 *savebuffer; if (slot > 0) { /* allocate buffer */ savebuffer = (u8 *)memalign(32,STATE_SIZE); if (!savebuffer) { GUI_WaitPrompt("Error","Unable to allocate memory !"); return 0; } GUI_MsgBoxOpen("Information","Saving State ...",1); filesize = state_save(&savebuffer[offset]); } else { if (!sram.on) { GUI_WaitPrompt("Error","SRAM is disabled !"); return 0; } /* allocate buffer */ savebuffer = (u8 *)memalign(32,0x10000+offset); if (!savebuffer) { GUI_WaitPrompt("Error","Unable to allocate memory !"); return 0; } GUI_MsgBoxOpen("Information","Saving SRAM ...",1); memcpy(&savebuffer[offset], sram.sram, 0x10000); sram.crc = crc32(0, sram.sram, 0x10000); filesize = 0x10000; } if (!device) { /* FAT support */ if (slot > 0) sprintf(filename, "%s/saves/%s.gp%d", DEFAULT_PATH, rom_filename, slot - 1); else sprintf(filename, "%s/saves/%s.srm", DEFAULT_PATH, rom_filename); /* Open file */ FILE *fp = fopen(filename, "wb"); if (!fp) { GUI_WaitPrompt("Error","Unable to open file !"); free(savebuffer); return 0; } /* Write from buffer (2k blocks) */ while (filesize > FILECHUNK) { fwrite(savebuffer + done, FILECHUNK, 1, fp); done += FILECHUNK; filesize -= FILECHUNK; } /* Write remaining bytes */ fwrite(savebuffer + done, filesize, 1, fp); done += filesize; fclose(fp); } else { /* Memory Card support */ if (slot > 0) sprintf(filename, "MD-%04X.gp%d", rominfo.realchecksum, slot - 1); else sprintf(filename, "MD-%04X.srm", rominfo.realchecksum); /* Initialise the CARD system */ char action[64]; memset(&SysArea, 0, CARD_WORKAREA); CARD_Init("GENP", "00"); /* CARD slot */ device--; /* Attempt to mount the card */ if (!CardMount(device)) { GUI_WaitPrompt("Error","Unable to mount memory card"); free(savebuffer); return 0; } /* Retrieve the sector size */ u32 SectorSize = 0; int CardError = CARD_GetSectorSize(device, &SectorSize); if (!SectorSize) { sprintf(action, "Invalid sector size (%d)", CardError); GUI_WaitPrompt("Error",action); CARD_Unmount(device); free(savebuffer); return 0; } /* Build the output buffer */ char comment[2][32] = { {"Genesis Plus GX"}, {"SRAM Save"} }; strcpy (comment[1], filename); memcpy (&savebuffer[0], &icon, 2048); memcpy (&savebuffer[2048], &comment[0], 64); /* Adjust file size */ filesize += 2112; if (filesize % SectorSize) filesize = ((filesize / SectorSize) + 1) * SectorSize; /* Check if file already exists */ card_file CardFile; if (CARD_Open(device, filename, &CardFile) == CARD_ERROR_READY) { int size = filesize - CardFile.len; CARD_Close(&CardFile); memset(&CardFile,0,sizeof(CardFile)); /* Check file new size */ if (size > 0) { CardError = CARD_Create(device, "TEMP", size, &CardFile); if (CardError) { sprintf(action, "Unable to increase file size (%d)", CardError); GUI_WaitPrompt("Error",action); CARD_Unmount(device); free(savebuffer); return 0; } /* delete temporary file */ CARD_Close(&CardFile); memset(&CardFile,0,sizeof(CardFile)); CARD_Delete(device, "TEMP"); } /* delete previously existing file */ CARD_Delete(device, filename); } /* Create a new file */ CardError = CARD_Create(device, filename, filesize, &CardFile); if (CardError) { sprintf(action, "Unable to create file (%d)", CardError); GUI_WaitPrompt("Error",action); CARD_Unmount(device); free(savebuffer); return 0; } /* Update file informations */ time_t rawtime; time(&rawtime); card_stat CardStatus; CARD_GetStatus(device, CardFile.filenum, &CardStatus); CardStatus.icon_addr = 0x0; CardStatus.icon_fmt = 2; CardStatus.icon_speed = 1; CardStatus.comment_addr = 2048; CardStatus.time = rawtime; CARD_SetStatus(device, CardFile.filenum, &CardStatus); /* Write file sectors */ while (filesize > 0) { CARD_Write(&CardFile, &savebuffer[done], SectorSize, done); filesize -= SectorSize; done += SectorSize; } /* Close file */ CARD_Close(&CardFile); CARD_Unmount(device); } GUI_MsgBoxClose(); free(savebuffer); /* Save screenshot */ if (slot && !device) { sprintf(filename,"%s/saves/%s__%d.png", DEFAULT_PATH, rom_filename, slot - 1); gxSaveScreenshot(filename); } return 1; }
/**************************************************************************** * CardReadFile * * Retrieve a file from the previously populated list. * Place in filebuffer space, for collection by SMB write. ****************************************************************************/ int CardReadFile (int slot, int id) { int bytesdone = 0; int err; u32 SectorSize; char company[4]; char gamecode[6]; int filesize; if (id >= cardcount) { WaitPrompt("Bad id"); return 0; /*** Bad id ***/ } /*** Clear the work buffers ***/ memset (FileBuffer, 0, MAXFILEBUFFER); memset (SysArea, 0, CARD_WORKAREA); //add null char company[2] = gamecode[4] = 0; memcpy (company, &CardList[id].company, 2); memcpy (gamecode, &CardList[id].gamecode, 4); /*** Mount the card ***/ err = MountCard(slot); if (err < 0) { WaitCardError("CardMount", err); return 0; /*** Unable to mount the card ***/ } /*** Retrieve sector size ***/ CARD_GetSectorSize (slot, &SectorSize); /*** Initialise for this company & gamecode ***/ CARD_SetCompany(company); CARD_SetGamecode(gamecode); /*** Open the file ***/ err = CARD_Open (slot, (char *) &CardList[id].filename, &CardFile); if (err < 0) { CARD_Unmount (slot); WaitCardError("CardOpen", err); return 0; } #ifdef STATUSOGC /*** Get card status info ***/ CARD_GetStatus (slot, CardFile.filenum, &CardStatus); CARD_GetAttributes(slot,CardFile.filenum, &permission); GCIMakeHeader(); #else //get directory entry (same as gci header, but with all the data) memset(&gci,0,sizeof(GCI)); __card_getstatusex(slot,CardFile.filenum,&gci); /*** Copy to head of buffer ***/ memcpy(FileBuffer, &gci, sizeof(GCI)); #endif /*** Copy the file contents to the buffer ***/ filesize = CardFile.len; while (bytesdone < filesize) { CARD_Read (&CardFile, FileBuffer + MCDATAOFFSET + bytesdone, SectorSize, bytesdone); bytesdone += SectorSize; } /*** Close the file ***/ CARD_Close (&CardFile); /*** Unmount the card ***/ CARD_Unmount (slot); return filesize + MCDATAOFFSET; }
/**************************************************************************** * SaveMCFile * Write savebuffer to Memory Card file ***************************************************************************/ int SaveMCFile (char *buf, int slot, char *filename, int datasize, bool silent) { card_file CardFile; card_stat CardStatus; int CardError; unsigned int blocks; unsigned int SectorSize; int byteswritten = 0; int bytesleft = 0; if(datasize <= 0) return 0; // add save icon and comments memmove(buf+sizeof(saveicon)+64, buf, datasize); memcpy(buf, saveicon, sizeof(saveicon)); memcpy(buf+sizeof(saveicon), savecomments, 64); datasize += (sizeof(saveicon)+64); // Try to mount the card CardError = MountMC(slot, NOTSILENT); if (CardError == 0) { // Get Sector Size CARD_GetSectorSize (slot, &SectorSize); // Calculate number of blocks required blocks = (datasize / SectorSize) * SectorSize; if (datasize % SectorSize) blocks += SectorSize; // Delete existing file (if present) memset(&CardStatus, 0, sizeof(card_stat)); CardError = CARD_Open (slot, filename, &CardFile); if(CardError == 0) { CARD_Close (&CardFile); CardError = CARD_Delete(slot, filename); if (CardError) { ErrorPrompt("Unable to delete existing file!"); goto done; } } // Create new file memset(&CardStatus, 0, sizeof(card_stat)); CardError = CARD_Create (slot, filename, blocks, &CardFile); if (CardError) { if (CardError == CARD_ERROR_INSSPACE) ErrorPrompt("Insufficient space to create file!"); else ErrorPrompt("Unable to create card file!"); goto done; } // Now, have an open file handle, ready to send out the data CARD_GetStatus (slot, CardFile.filenum, &CardStatus); CardStatus.icon_addr = 0x0; CardStatus.icon_fmt = 2; CardStatus.icon_speed = 1; CardStatus.comment_addr = 2048; CARD_SetStatus (slot, CardFile.filenum, &CardStatus); bytesleft = blocks; while (bytesleft > 0) { CardError = CARD_Write (&CardFile, buf + byteswritten, SectorSize, byteswritten); if(CardError) { ErrorPrompt("Error writing file!"); byteswritten = 0; break; } bytesleft -= SectorSize; byteswritten += SectorSize; ShowProgress ("Saving...", byteswritten, blocks); } CARD_Close (&CardFile); CancelAction(); if (byteswritten > 0 && GCSettings.VerifySaves) { // Verify the written file if (!VerifyMCFile (buf, slot, filename, byteswritten) ) byteswritten = 0; } done: CARD_Unmount (slot); } free(SysArea); return byteswritten; }
//TODO: get icon and banner settings int CardReadFileHeader (int slot, int id) { int bytesdone = 0; int err; u32 SectorSize; char company[4]; char gamecode[6]; int filesize; int i; u16 check_fmt, check_speed; if (id >= cardcount) { WaitPrompt("Bad id"); return 0; /*** Bad id ***/ } /*** Clear the work buffers ***/ memset (FileBuffer, 0, MAXFILEBUFFER); memset (CommentBuffer, 0, 64); memset (SysArea, 0, CARD_WORKAREA); //add null char company[2] = gamecode[4] = 0; memcpy (company, &CardList[id].company, 2); memcpy (gamecode, &CardList[id].gamecode, 4); /*** Mount the card ***/ err = MountCard(slot); if (err < 0) { WaitCardError("CardMount", err); return 0; /*** Unable to mount the card ***/ } /*** Retrieve sector size ***/ CARD_GetSectorSize (slot, &SectorSize); /*** Initialise for this company & gamecode ***/ CARD_SetCompany((const char*)company); CARD_SetGamecode((const char*)gamecode); /*** Open the file ***/ err = CARD_Open (slot, (char *) &CardList[id].filename, &CardFile); if (err < 0) { CARD_Unmount (slot); WaitCardError("CardOpen", err); return 0; } #ifdef STATUSOGC /*** Get card status info ***/ CARD_GetStatus (slot, CardFile.filenum, &CardStatus); CARD_GetAttributes(slot,CardFile.filenum, &permission); GCIMakeHeader(); #else //get directory entry (same as gci header, but with all the data) memset(&gci,0,sizeof(GCI)); __card_getstatusex(slot,CardFile.filenum,&gci); /*** Copy to head of buffer ***/ memcpy(FileBuffer, &gci, sizeof(GCI)); #endif /*** Copy the file contents to the buffer ***/ filesize = CardFile.len; while (bytesdone < filesize) { CARD_Read (&CardFile, FileBuffer + MCDATAOFFSET + bytesdone, SectorSize, bytesdone); bytesdone += SectorSize; } /*** Get the Banner/Icon Data from the memory card file. Very specific if/else setup to minimize data copies. ***/ u8* offset = FileBuffer + MCDATAOFFSET + gci.icon_addr; /*** Get the Banner/Icon Data from the save file ***/ if ((gci.banner_fmt&CARD_BANNER_MASK) == CARD_BANNER_RGB) { //RGB banners are 96*32*2 in size memcpy(bannerdata, offset, 6144); offset += 6144; } else if ((gci.banner_fmt&CARD_BANNER_MASK) == CARD_BANNER_CI) { memcpy(bannerdataCI, offset, 3072); offset += 3072; memcpy(tlutbanner, offset, 512); offset += 512; } //Icon data int shared_pal = 0; lastframe = 0; numicons = 0; int j =0; i=0; int current_icon = 0; for (current_icon=0;i<CARD_MAXICONS;++current_icon){ //no need to clear all values since we will only use the ones until lasticon frametable[current_icon] = 0; iconindex[current_icon] = 0; //Animation speed is mandatory to be set even for a single icon //When a speed is 0 there are no more icons //Some games may have bits set after the "blank icon" both in //speed (Baten Kaitos) and format (Wario Ware Inc.) bytes, which are just garbage if (!SDCARD_GetIconSpeed(gci.icon_speed,current_icon)){ break; }else {//We've got a frame lastframe+=SDCARD_GetIconSpeed(gci.icon_speed,current_icon)*4;//Count the total frames frametable[current_icon]=lastframe; //Store the end frame of the icon if (SDCARD_GetIconFmt(gci.icon_fmt,current_icon) != 0) { //count the number of real icons numicons++; iconindex[current_icon]=current_icon; //Map the icon //CI with shared palette if (SDCARD_GetIconFmt(gci.icon_fmt,current_icon) == 1) { memcpy(icondata[current_icon], offset, 1024); offset += 1024; shared_pal = 1; } //CI with palette after the icon else if (SDCARD_GetIconFmt(gci.icon_fmt,current_icon) == 3) { memcpy(icondata[current_icon], offset, 1024); offset += 1024; memcpy(tlut[current_icon], offset, 512); offset += 512; } //RGB 16 bit icon else if (SDCARD_GetIconFmt(gci.icon_fmt,current_icon) == 2) { memcpy(icondataRGB[current_icon], offset, 2048); offset += 2048; } }else { //Get next real icon for(j=current_icon;j<CARD_MAXICONS;++j){ if (SDCARD_GetIconFmt(gci.icon_fmt,j) != 0) { iconindex[current_icon]=j; //Map blank frame to next real icon break; } } } } } lasticon = current_icon-1; //Now get icon indexes for ping-pong style icons if (SDCARD_GetIconAnim(gci.banner_fmt) == CARD_ANIM_BOUNCE && current_icon>1) //We need at least 3 icons { j=current_icon; for (i = current_icon-2; 0 < i; --i, ++j) { lastframe += SDCARD_GetIconSpeed(gci.icon_speed,i)*4; frametable[j] = lastframe; iconindex[j] = iconindex[i]; } lasticon = j-1; } //Get the shared palette if (shared_pal) memcpy(tlut[8], offset, 512); /*** Get the comment (two 32 byte strings) into buffer ***/ memcpy(CommentBuffer, FileBuffer + MCDATAOFFSET + gci.comment_addr, 64); /*** Close the file ***/ CARD_Close (&CardFile); /*** Unmount the card ***/ CARD_Unmount (slot); return filesize + MCDATAOFFSET; }
/**************************************************************************** * ManageState * * Here is the main Freeze File Management stuff. * The output file contains an icon (2K), 64 bytes comment and the STATE (~128k) * * direction == 0 save, 1 load. ****************************************************************************/ int ManageState (u8 direction, u8 device) { if (!smsromsize) return 0; char filename[MAXJOLIET]; /* clean buffer */ memset(savebuffer, 0, 0x12000); if (direction) ShowAction ("Loading State ..."); else ShowAction ("Saving State ..."); if (device == 0) { /* FAT support */ sprintf (filename, "%s.spz", rom_filename); return FAT_ManageFile(filename,direction); } /* Memory CARD support */ char action[80]; int CardError; unsigned int SectorSize = 0; int blocks; char comment[2][32] = { {"SMS Plus 1.3 [FRZ]"}, {"Freeze State"} }; int outbytes = 0; int sbo; int state_size = 0; /* First, build a filename */ sprintf (filename, "%08X.spz", (u32)crc32 (0, &cart.rom[0], smsromsize)); strcpy (comment[1], filename); /* set MCARD slot nr. */ u8 CARDSLOT = device - 1; /* Saving */ if (direction == 0) { /*** Build the output buffer ***/ memcpy (&savebuffer, &icon, 2048); memcpy (&savebuffer[2048], &comment[0], 64); state_size = system_save_state(&savebuffer[2112]); } outbytes = 2048 + 64 + state_size; /*** Initialise the CARD system ***/ memset (&SysArea, 0, CARD_WORKAREA); CARD_Init ("SMSP", "00"); /*** Attempt to mount the card ***/ CardError = MountTheCard (CARDSLOT); if (CardError) { /*** Retrieve the sector size ***/ CardError = CARD_GetSectorSize (CARDSLOT, &SectorSize); if (SectorSize) { switch (direction) { case 0: /*** Saving ***/ /*** Determine number of blocks on this card ***/ blocks = (outbytes / SectorSize) * SectorSize; if (outbytes % SectorSize) blocks += SectorSize; /*** Check if a previous save exists ***/ if (CardFileExists (filename,CARDSLOT)) { CardError = CARD_Open (CARDSLOT, filename, &CardFile); if (CardError) { sprintf (action, "Error Open : %d", CardError); WaitPrompt (action); CARD_Unmount (CARDSLOT); return 0; } int size = CardFile.len; CARD_Close (&CardFile); if (size < blocks) { /* new size is bigger: check if there is enough space left */ CardError = CARD_Create (CARDSLOT, "TEMP", blocks-size, &CardFile); if (CardError) { sprintf (action, "Error Update : %d", CardError); WaitPrompt (action); CARD_Unmount (CARDSLOT); return 0; } CARD_Close (&CardFile); CARD_Delete(CARDSLOT, "TEMP"); } /* always delete existing slot */ CARD_Delete(CARDSLOT, filename); } /*** Create a new slot ***/ CardError = CARD_Create (CARDSLOT, filename, blocks, &CardFile); if (CardError) { sprintf (action, "Error create : %d %d", CardError, CARDSLOT); WaitPrompt (action); CARD_Unmount (CARDSLOT); return 0; } /*** Continue and save ***/ CARD_GetStatus (CARDSLOT, CardFile.filenum, &CardStatus); CardStatus.icon_addr = 0x0; CardStatus.icon_fmt = 2; CardStatus.icon_speed = 1; CardStatus.comment_addr = 2048; CARD_SetStatus (CARDSLOT, CardFile.filenum, &CardStatus); /*** And write the blocks out ***/ sbo = 0; while (outbytes > 0) { CardError = CARD_Write (&CardFile, &savebuffer[sbo], SectorSize, sbo); outbytes -= SectorSize; sbo += SectorSize; } CARD_Close (&CardFile); CARD_Unmount (CARDSLOT); sprintf (action, "Saved %d bytes successfully", blocks); WaitPrompt (action); return 1; default: /*** Loading ***/ if (!CardFileExists (filename, CARDSLOT)) { WaitPrompt ("No Savestate Found"); CARD_Unmount (CARDSLOT); return 0; } memset (&CardFile, 0, sizeof (CardFile)); CardError = CARD_Open (CARDSLOT, filename, &CardFile); if (CardError) { sprintf (action, "Error Open : %d", CardError); WaitPrompt (action); CARD_Unmount (CARDSLOT); return 0; } blocks = CardFile.len; if (blocks < SectorSize) blocks = SectorSize; if (blocks % SectorSize) blocks++; /*** Just read the file back in ***/ sbo = 0; int size = blocks; while (blocks > 0) { CARD_Read (&CardFile, &savebuffer[sbo], SectorSize, sbo); sbo += SectorSize; blocks -= SectorSize; } CARD_Close (&CardFile); CARD_Unmount (CARDSLOT); /*** Load State ***/ system_load_state(&savebuffer[2112]); /*** Inform user ***/ sprintf (action, "Loaded %d bytes successfully", size); WaitPrompt (action); return 1; } } WaitPrompt ("Invalid sector size"); return 0; } WaitPrompt ("Unable to mount memory card"); return 0; /*** Signal failure ***/ }
s32 deviceHandler_CARD_readFile(file_handle* file, void* buffer, u32 length){ card_file cardfile; void *dst = buffer; card_dir* cd = (card_dir*)&file->other; char *filename = getRelativeName(file->name); unsigned int slot = (!strncmp((const char*)initial_CARDB.name, file->name, 7)), ret = 0; if(cd->company[0] == '\0' && cd->gamecode[0] == '\0') { // Find the file we don't know about and populate this file_handle if we find it. if(!findFile(file)) { return CARD_ERROR_NOFILE; } CARD_SetCompany((const char*)cd->company); CARD_SetGamecode((const char*)cd->gamecode); } else { CARD_SetCompany((const char*)cd->company); CARD_SetGamecode((const char*)cd->gamecode); } int swissFile = !strncmp((const char*)cd->gamecode, "SWIS", 4) && !strncmp((const char*)cd->company, "S0", 2); // Open the file based on the slot & file name ret = CARD_Open(slot,filename, &cardfile); print_gecko("Tried to open: [%s] in slot %s got res: %i\r\n",filename, slot ? "B":"A", ret); if(ret != CARD_ERROR_READY) return ret; u8 *read_buffer = (u8*)memalign(32,card_sectorsize[slot]); if(!read_buffer) { return -1; } /* Read from the file */ u32 amountRead = 0; // If this file was put here by swiss, then skip the first 8192 bytes if(swissFile && !isCopyGCIMode) { print_gecko("Swiss copied file detected, skipping icon\r\n"); file->offset += 8192; } if(isCopyGCIMode) { // Write out a .GCI card_stat cardstat; GCI gci; CARD_GetStatus(slot, cardfile.filenum, &cardstat); memset(&gci, 0, sizeof(GCI)); memcpy(&gci.gamecode,cd->gamecode,4); memcpy(&gci.company,cd->company,2); memcpy(&gci.filename,file->name,CARD_FILENAMELEN); gci.reserved01 = 0xFF; gci.banner_fmt = cardstat.banner_fmt; gci.time = cardstat.time; gci.icon_addr = cardstat.icon_addr; gci.icon_fmt = cardstat.icon_fmt; gci.icon_speed = cardstat.icon_speed; gci.unknown1 = cd->permissions; gci.filesize8 = cardstat.len / 8192; gci.reserved02 = 0xFFFF; gci.comment_addr = cardstat.comment_addr; memcpy(dst, &gci, sizeof(GCI)); dst+=sizeof(GCI); length-=sizeof(GCI); amountRead += sizeof(GCI); } while(length > 0 && file->offset < file->size) { int readsize = length > card_sectorsize[slot] ? card_sectorsize[slot] : length; print_gecko("Need to read: [%i] more bytes\r\n", length); if(file->offset&0x1ff) { ret = CARD_ReadUnaligned(&cardfile, read_buffer, card_sectorsize[slot], file->offset, slot); } else { ret = CARD_Read(&cardfile, read_buffer, card_sectorsize[slot], file->offset); // Sometimes reads fail the first time stupidly, retry at least once. print_gecko("Read: [%i] bytes ret [%i] from offset [%i]\r\n",card_sectorsize[slot],ret, file->offset); if(ret == CARD_ERROR_BUSY) { print_gecko("Read retry\r\n"); usleep(2000); ret = CARD_Read(&cardfile, read_buffer, card_sectorsize[slot], file->offset); } } if(ret == CARD_ERROR_READY) memcpy(dst,read_buffer,readsize); else return ret; dst+=readsize; file->offset += readsize; length -= readsize; amountRead += readsize; } // For swiss adjusted files, don't trail off the end. if(swissFile && length != 0) { amountRead+= length; } DCFlushRange(dst, amountRead); CARD_Close(&cardfile); free(read_buffer); return amountRead; }
/**************************************************************************** * SaveMCFile * Write savebuffer to Memory Card file ***************************************************************************/ int SaveMCFile (char *buf, int slot, char *filename, int datasize, bool silent) { int CardError; unsigned int blocks; unsigned int SectorSize; char msg[80]; if(datasize <= 0) return 0; /*** Initialize Card System ***/ memset (SysArea, 0, CARD_WORKAREA); CARD_Init ("VBA0", "00"); /*** Try to mount the card ***/ CardError = MountCard(slot, NOTSILENT); if (CardError == 0) { /*** Get Sector Size ***/ CARD_GetSectorSize (slot, &SectorSize); /*** Calculate number of blocks required ***/ blocks = (datasize / SectorSize) * SectorSize; if (datasize % SectorSize) blocks += SectorSize; /*** Does this file exist ? ***/ if (CardFileExists (filename, slot)) { /*** Try to open the file ***/ CardError = CARD_Open (slot, filename, &CardFile); if (CardError) { CARD_Unmount (slot); WaitPrompt("Unable to open card file!"); return 0; } if ( (s32)blocks > CardFile.len ) /*** new data is longer ***/ { CARD_Close (&CardFile); /*** Try to create temp file to check available space ***/ CardError = CARD_Create (slot, "TEMPFILESNES9XGX201", blocks, &CardFile); if (CardError) { CARD_Unmount (slot); WaitPrompt("Not enough space to update file!"); return 0; } /*** Delete the temporary file ***/ CARD_Close (&CardFile); CardError = CARD_Delete(slot, "TEMPFILESNES9XGX201"); if (CardError) { CARD_Unmount (slot); WaitPrompt("Unable to delete temporary file!"); return 0; } /*** Delete the existing shorter file ***/ CardError = CARD_Delete(slot, filename); if (CardError) { CARD_Unmount (slot); WaitPrompt("Unable to delete existing file!"); return 0; } /*** Create new, longer file ***/ CardError = CARD_Create (slot, filename, blocks, &CardFile); if (CardError) { CARD_Unmount (slot); WaitPrompt("Unable to create updated card file!"); return 0; } } } else /*** no file existed, create new one ***/ { /*** Create new file ***/ CardError = CARD_Create (slot, filename, blocks, &CardFile); if (CardError) { CARD_Unmount (slot); if ( CardError == CARD_ERROR_INSSPACE ) WaitPrompt("Not enough space to create file!"); else WaitPrompt("Unable to create card file!"); return 0; } } /*** Now, have an open file handle, ready to send out the data ***/ CARD_GetStatus (slot, CardFile.filenum, &CardStatus); CardStatus.icon_addr = 0x0; CardStatus.icon_fmt = 2; CardStatus.icon_speed = 1; CardStatus.comment_addr = 2048; CARD_SetStatus (slot, CardFile.filenum, &CardStatus); int byteswritten = 0; int bytesleft = blocks; while (bytesleft > 0) { CardError = CARD_Write (&CardFile, buf + byteswritten, SectorSize, byteswritten); bytesleft -= SectorSize; byteswritten += SectorSize; sprintf (msg, "Wrote %d of %d bytes", byteswritten, blocks); ShowProgress (msg, byteswritten, blocks); } CARD_Close (&CardFile); CARD_Unmount (slot); if ( GCSettings.VerifySaves ) { /*** Verify the written file, but only up to the length we wrote because the file could be longer due to past writes ***/ if ( VerifyMCFile (buf, slot, filename, byteswritten) ) return byteswritten; else return 0; } else return byteswritten; } else if (slot == CARD_SLOTA) WaitPrompt("Unable to Mount Slot A Memory Card!"); else WaitPrompt("Unable to Mount Slot B Memory Card!"); return 0; }
void MCManage(int mode, int slot) { char mcFilename[80]; int CardError; card_dir CardDir; card_file CardFile; int SectorSize; int found = 0; int FileSize; int actualSize; int savedBytes=0; char debug[128]; CARDSLOT = slot; /*** Build the file name ***/ sprintf(mcFilename, "FCEU-%08x.fcs", iNESGameCRC32); /*** Mount the Card ***/ CARD_Init("FCEU", "00"); /*** Try for memory card in slot A ***/ CardError = CARD_Mount(CARDSLOT, SysArea, CardRemoved ); if ( CardError >= 0 ) { /*** Get card sector size ***/ CardError = CARD_GetSectorSize(CARDSLOT, &SectorSize); switch ( mode ) { case 0 : { /*** Save Game ***/ /*** Look for this file ***/ CardError = CARD_FindFirst(CARDSLOT, &CardDir, true); found = 0; card_stat CardStatus; while ( CardError != CARD_ERROR_NOFILE ) { CardError = CARD_FindNext(&CardDir); if ( strcmp(CardDir.filename, mcFilename) == 0 ) found = 1; } /*** Determine number of sectors required ***/ savedBytes = actualSize = GCFCEUSS_Save(); sprintf(debug, "Saving in MC ..."); ShowAction(debug); FileSize = ( actualSize / SectorSize ) * SectorSize; if ( actualSize % SectorSize ) FileSize += SectorSize; /*** Now write the file out ***/ if ( !found ) CardError = CARD_Create(CARDSLOT, mcFilename, FileSize, &CardFile); else CardError = CARD_Open(CARDSLOT, mcFilename, &CardFile); CARD_GetStatus( CARDSLOT, CardFile.filenum, &CardStatus); CardStatus.icon_addr = 0; CardStatus.icon_fmt = 2; CardStatus.icon_speed = 1; CardStatus.comment_addr = sizeof(saveicon); CARD_SetStatus( CARDSLOT, CardFile.filenum, &CardStatus); /*** Haha! libogc only write one block at a time! ***/ if ( CardError == 0 ) { int sbo = 0; while ( actualSize > 0 ) { CardError = CARD_Write(&CardFile, &statebuffer[sbo], SectorSize, sbo ); actualSize -= SectorSize; sbo += SectorSize; } CardError = CARD_Close(&CardFile); sprintf(debug, "Saved %d bytes successfully!", savedBytes); WaitPrompt(debug); } else WaitPrompt("Save Failed!"); CARD_Unmount(CARDSLOT); } break; /*** End save ***/ case 1: { /*** Load state ***/ /*** Look for this file ***/ CardError = CARD_FindFirst(CARDSLOT, &CardDir, true); memopen(); /*** Clear the buffer ***/ found = 0; while ( CardError != CARD_ERROR_NOFILE ) { CardError = CARD_FindNext(&CardDir); if ( strcmp(CardDir.filename, mcFilename) == 0 ) found = 1; } if ( found == 0 ) { WaitPrompt("No Save Game Found"); CARD_Unmount(CARDSLOT); return; } /*** Load the file into memory ***/ CardError = CARD_Open(CARDSLOT, mcFilename, &CardFile); CardError = CARD_Read(&CardFile, &statebuffer, SectorSize, 0); /*** Get actual size of the file ***/ memcpy(&actualSize, &statebuffer[FILESIZEOFFSET], 4); savedBytes = actualSize; int sbo = SectorSize; actualSize -= SectorSize; while( actualSize > 0 ) { CARD_Read(&CardFile, &statebuffer[sbo], SectorSize, sbo); actualSize -= SectorSize; sbo += SectorSize; } CARD_Close(&CardFile); /*** Finally, do load ***/ GCFCEUSS_Load(); CARD_Unmount(CARDSLOT); sprintf(debug, "Loaded %d bytes successfully!", savedBytes); WaitPrompt(debug); } break; /*** End load ***/ default: break; } } else { WaitPrompt("Cannot Mount Memory Card!"); } }