// // PcsxrMemCardArray.m // Pcsxr // // Created by C.W. Betts on 7/6/13. // // #import "PcsxrMemCardArray.h" #import "ARCBridge.h" #import "ConfigurationController.h" #include "sio.h" #define MAX_MEMCARD_BLOCKS 15 static inline void CopyMemcardData(char *from, char *to, int srci, int dsti, char *str) { // header memmove(to + (dsti + 1) * 128, from + (srci + 1) * 128, 128); SaveMcd(str, to, (dsti + 1) * 128, 128); // data memmove(to + (dsti + 1) * 1024 * 8, from + (srci+1) * 1024 * 8, 1024 * 8); SaveMcd(str, to, (dsti + 1) * 1024 * 8, 1024 * 8); //printf("data = %s\n", from + (srci+1) * 128); } static inline char* CreateBlankHeader() { struct PSXMemHeader { unsigned int allocState; unsigned int fileSize; unsigned short nextBlock; char fileName[21]; unsigned char garbage[96]; unsigned char checksum; }; struct PSXMemHeader *toReturn = calloc(sizeof(struct PSXMemHeader), 1); toReturn->allocState = 0x000000a0; toReturn->nextBlock = 0xFFFF; unsigned char *bytePtr = (unsigned char*)toReturn; for (int i = 0; i < sizeof(struct PSXMemHeader) - sizeof(unsigned char); i++) { toReturn->checksum = toReturn->checksum ^ bytePtr[i]; } return (char*)toReturn; } static inline void ClearMemcardData(char *to, int dsti, char *str) { // header char *header = CreateBlankHeader(); memcpy(to + (dsti + 1) * 128, header, 128); SaveMcd(str, to, (dsti + 1) * 128, 128); free(header); // data memset(to + (dsti + 1) * 1024 * 8, 0, 1024 * 8); SaveMcd(str, to, (dsti + 1) * 1024 * 8, 1024 * 8); } @interface PcsxrMemCardArray () @property (arcretain) NSArray *rawArray; @property (readonly) char* memDataPtr; @end @implementation PcsxrMemCardArray @synthesize rawArray; //@synthesize memDataPtr; - (char*)memDataPtr { if (cardNumber == 1) { return Mcd1Data; } else { return Mcd2Data; } } - (const char *)memCardCPath { if (cardNumber == 1) { return Config.Mcd1; } else { return Config.Mcd2; } } - (id)initWithMemoryCardNumber:(int)carNum { NSParameterAssert(carNum == 1 || carNum == 2); if (self = [super init]) { NSMutableArray *tmpMemArray = [[NSMutableArray alloc] initWithCapacity:MAX_MEMCARD_BLOCKS]; cardNumber = carNum; int i, x; i = 0; while (i < MAX_MEMCARD_BLOCKS) { x = 1; McdBlock memBlock, tmpBlock; GetMcdBlockInfo(carNum, i + 1, &memBlock); if ([PcsxrMemoryObject memFlagsFromBlockFlags:memBlock.Flags] == memFlagFree) { //Free space: ignore i++; continue; } do { GetMcdBlockInfo(carNum, i + x + 1, &tmpBlock); if ((tmpBlock.Flags & 0x3) == 0x3) { x++; break; } else if ((tmpBlock.Flags & 0x2) == 0x2) { x++; } else { break; } } while (i + x - 1 < MAX_MEMCARD_BLOCKS); PcsxrMemoryObject *obj = [[PcsxrMemoryObject alloc] initWithMcdBlock:&memBlock startingIndex:i size:x]; [tmpMemArray addObject:obj]; RELEASEOBJ(obj); i += x; } self.rawArray = [NSArray arrayWithArray:tmpMemArray]; RELEASEOBJ(tmpMemArray); } return self; } - (int)indexOfFreeBlocksWithSize:(int)asize { int foundcount = 0, i = 0; McdBlock obj; // search for empty (formatted) blocks first while (i < MAX_MEMCARD_BLOCKS && foundcount < asize) { GetMcdBlockInfo(cardNumber, 1 + i++, &obj); //&Blocks[target_card][++i]; if ((obj.Flags & 0xFF) == 0xA0) { // if A0 but not A1 foundcount++; } else if (foundcount >= 1) { // need to find n count consecutive blocks foundcount = 0; } else { //i++; } //printf("formatstatus=%x\n", Info->Flags); } if (foundcount == asize) return (i-foundcount); // no free formatted slots, try to find a deleted one foundcount = i = 0; while (i < MAX_MEMCARD_BLOCKS && foundcount < asize) { GetMcdBlockInfo(cardNumber, 1 + i++, &obj); if ((obj.Flags & 0xF0) == 0xA0) { // A2 or A6 f.e. foundcount++; } else if (foundcount >= 1) { // need to find n count consecutive blocks foundcount = 0; } else { //i++; } //printf("delstatus=%x\n", Info->Flags); } if (foundcount == asize) return (i-foundcount); return -1; } - (BOOL)moveBlockAtIndex:(int)idx toMemoryCard:(PcsxrMemCardArray*)otherCard { if (idx == [rawArray count]) { #ifdef DEBUG NSLog(@"Trying to get an object one more than the length of the raw array. Perhaps you were trying to \"move\" the free blocks"); #endif return NO; } PcsxrMemoryObject *tmpObj = [rawArray objectAtIndex:idx]; int memSize = tmpObj.blockSize; if ([otherCard availableBlocks] < memSize) { NSLog(@"Failing because the other card does not have enough space!"); return NO; } int toCopy = [otherCard indexOfFreeBlocksWithSize:memSize]; if (toCopy == -1) { NSLog(@"Not enough consecutive blocks. Compacting the other card."); [otherCard compactMemory]; toCopy = [otherCard indexOfFreeBlocksWithSize:memSize]; NSAssert(toCopy != -1, @"Compacting the card should have made space!"); } int memIdx = tmpObj.startingIndex; int i; for (i = 0; i < memSize; i++) { CopyMemcardData([self memDataPtr], [otherCard memDataPtr], (memIdx+i), (toCopy+i), (char*)otherCard.memCardCPath); } return YES; } - (int)freeBlocks { int memSize = 15; for (PcsxrMemoryObject *memObj in rawArray) { memSize -= memObj.blockSize; } return memSize; } - (int)availableBlocks { int memSize = MAX_MEMCARD_BLOCKS; for (PcsxrMemoryObject *memObj in rawArray) { if (memObj.flagNameIndex != memFlagDeleted) { memSize -= memObj.blockSize; } } return memSize; } - (NSArray*)memoryArray { int freeSize = [self freeBlocks]; if (freeSize) { McdBlock theBlock; //Create a blank "block" that will be used for theBlock.Flags = 0xA0; theBlock.IconCount = 0; PcsxrMemoryObject *freeObj = [[PcsxrMemoryObject alloc] initWithMcdBlock:&theBlock startingIndex:MAX_MEMCARD_BLOCKS - 1 - freeSize size:freeSize]; return [rawArray arrayByAddingObject:AUTORELEASEOBJ(freeObj)]; } else return rawArray; } - (NSURL*)memCardURL { if (cardNumber == 1) { return [[NSUserDefaults standardUserDefaults] URLForKey:@"Mcd1"]; } else { return [[NSUserDefaults standardUserDefaults] URLForKey:@"Mcd2"]; } } - (int)memorySizeAtIndex:(int)idx { if (idx == [rawArray count]) { #ifdef DEBUG NSLog(@"Trying to get an object one more than the length of the raw array. Perhaps you were trying to \"count\" the free blocks"); #endif return [self freeBlocks]; } return [[rawArray objectAtIndex:idx] blockSize]; } - (void)compactMemory { int i = 0, x = 1; while (i < MAX_MEMCARD_BLOCKS && x < MAX_MEMCARD_BLOCKS) { x = i; McdBlock baseBlock; GetMcdBlockInfo(cardNumber, i+1, &baseBlock); PCSXRMemFlags theFlags = [PcsxrMemoryObject memFlagsFromBlockFlags:baseBlock.Flags]; if (theFlags == memFlagDeleted || theFlags == memFlagFree) { PCSXRMemFlags up1Flags = theFlags; while ((up1Flags == memFlagDeleted || up1Flags == memFlagFree) && x < MAX_MEMCARD_BLOCKS){ x++; McdBlock up1Block; GetMcdBlockInfo(cardNumber, x+1, &up1Block); up1Flags = [PcsxrMemoryObject memFlagsFromBlockFlags:up1Block.Flags]; } if (x >= MAX_MEMCARD_BLOCKS) { break; } CopyMemcardData(self.memDataPtr, self.memDataPtr, x, i, (char*)[[self.memCardURL path] fileSystemRepresentation]); ClearMemcardData(self.memDataPtr, x, (char*)self.memCardCPath ); } i++; } while (i < MAX_MEMCARD_BLOCKS) { ClearMemcardData(self.memDataPtr, i, (char*)self.memCardCPath); i++; } LoadMcd(cardNumber, (char*)self.memCardCPath); #if 0 [[NSNotificationCenter defaultCenter] postNotificationName:memChangeNotifier object:nil userInfo:[NSDictionary dictionaryWithObject:@(cardNumber) forKey:memCardChangeNumberKey]]; #endif } - (void)deleteMemoryBlocksAtIndex:(int)slotnum { int xor = 0, i, j; char *data, *ptr, *filename; if (cardNumber == 1) { filename = Config.Mcd1; data = Mcd1Data; } else { filename = Config.Mcd2; data = Mcd2Data; } if (slotnum == [rawArray count]) { #ifdef DEBUG NSLog(@"Trying to get an object one more than the length of the raw array. Perhaps you were trying to \"delete\" the free blocks"); #endif return; } PcsxrMemoryObject *theObj = [rawArray objectAtIndex:slotnum]; McdBlock flagBlock; for(i = theObj.startingIndex +1; i < (theObj.startingIndex + theObj.blockSize +1); i++) { GetMcdBlockInfo(cardNumber, i, &flagBlock); ptr = data + i * 128; if ((flagBlock.Flags & 0xF0) == 0xA0) { if ((flagBlock.Flags & 0xF) >= 1 && (flagBlock.Flags & 0xF) <= 3) { // deleted *ptr = 0x50 | (flagBlock.Flags & 0xF); } else return; } else if ((flagBlock.Flags & 0xF0) == 0x50) { // used *ptr = 0xA0 | (flagBlock.Flags & 0xF); } else { continue; } for (j = 0; j < 127; j++) xor ^= *ptr++; *ptr = xor; SaveMcd(filename, data, i * 128, 128); } } #if !__has_feature(objc_arc) - (void)dealloc { self.rawArray = nil; [super dealloc]; } #endif @end