OS X: implement the metadata (Spotlight) importer for the memory cards.
git-svn-id: https://pcsxr.svn.codeplex.com/svn/pcsxr@90603 e17a0e51-4ae3-4d35-97c3-1a29b211df97
This commit is contained in:
parent
99d48611d9
commit
3bd0bcc5df
|
@ -179,6 +179,8 @@
|
|||
5525BC6B19421A760018AF2F /* GetMetadataForFile.m in Sources */ = {isa = PBXBuildFile; fileRef = 5525BC6A19421A760018AF2F /* GetMetadataForFile.m */; };
|
||||
5525BC7819421D4F0018AF2F /* schema.xml in Resources */ = {isa = PBXBuildFile; fileRef = 5525BC7719421D4F0018AF2F /* schema.xml */; };
|
||||
5525BC7C194221EC0018AF2F /* schema.strings in Resources */ = {isa = PBXBuildFile; fileRef = 5525BC7E194221EC0018AF2F /* schema.strings */; };
|
||||
5525BC80194228460018AF2F /* PcsxrMemoryObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 55A90228147D89380037E18F /* PcsxrMemoryObject.m */; };
|
||||
5525BC8119423FA90018AF2F /* Psx-Memcard.mdimporter in Copy Spotlight Plug-Ins */ = {isa = PBXBuildFile; fileRef = 5525BC5D19421A750018AF2F /* Psx-Memcard.mdimporter */; };
|
||||
55268A5A1876244E00A82269 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 551A74A317868B110052D185 /* Foundation.framework */; };
|
||||
5529EA11169CBE3400BAA2A5 /* RecentItemsMenu.m in Sources */ = {isa = PBXBuildFile; fileRef = 5550D2721683C923006C56B5 /* RecentItemsMenu.m */; };
|
||||
553FECEE18DF5A8300C7B007 /* AddPluginSheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = 553FECB818DF5A8300C7B007 /* AddPluginSheet.xib */; };
|
||||
|
@ -407,13 +409,15 @@
|
|||
name = "Copy QuickLook Plug-In";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
5525BC58194219B80018AF2F /* CopyFiles */ = {
|
||||
5525BC58194219B80018AF2F /* Copy Spotlight Plug-Ins */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = Contents/Library/Spotlight;
|
||||
dstSubfolderSpec = 1;
|
||||
files = (
|
||||
5525BC8119423FA90018AF2F /* Psx-Memcard.mdimporter in Copy Spotlight Plug-Ins */,
|
||||
);
|
||||
name = "Copy Spotlight Plug-Ins";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
71AD2DF010C3573400365243 /* Copy Plug-Ins */ = {
|
||||
|
@ -1829,7 +1833,7 @@
|
|||
2BB3D6C505427FE200831ACB /* Frameworks */,
|
||||
71AD2DF010C3573400365243 /* Copy Plug-Ins */,
|
||||
55202EBA18E73E3E00C631AA /* Copy QuickLook Plug-In */,
|
||||
5525BC58194219B80018AF2F /* CopyFiles */,
|
||||
5525BC58194219B80018AF2F /* Copy Spotlight Plug-Ins */,
|
||||
55F41A3317EF8CFF00605DF8 /* Strip Headers */,
|
||||
);
|
||||
buildRules = (
|
||||
|
@ -2503,6 +2507,7 @@
|
|||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
5525BC80194228460018AF2F /* PcsxrMemoryObject.m in Sources */,
|
||||
5525BC6919421A760018AF2F /* main.c in Sources */,
|
||||
5525BC6B19421A760018AF2F /* GetMetadataForFile.m in Sources */,
|
||||
);
|
||||
|
|
|
@ -19,7 +19,7 @@ NSString *const memoryAnimateTimerKey = @"PCSXR Memory Card Image Animate";
|
|||
@property (readwrite) uint8_t startingIndex;
|
||||
@property (readwrite) uint8_t blockSize;
|
||||
|
||||
@property (readwrite, nonatomic) NSInteger memImageIndex;
|
||||
@property (nonatomic) NSInteger memImageIndex;
|
||||
@property (strong) NSArray *memImages;
|
||||
@property (readwrite) PCSXRMemFlags flagNameIndex;
|
||||
@end
|
||||
|
|
|
@ -9,6 +9,14 @@
|
|||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
#include "GetMetadataForFile.h"
|
||||
#include "PcsxrMemoryObject.h"
|
||||
|
||||
#define MAX_MEMCARD_BLOCKS 15
|
||||
#define kPCSXRSaveNames @"com_codeplex_pcsxr_memcard_savenames"
|
||||
#define kPCSXRMemCount @"com_codeplex_pcsxr_memcard_memcount"
|
||||
#define kPCSXRFreeBlocks @"com_codeplex_pcsxr_memcard_freeblocks"
|
||||
#define kPCSXRMemNames @"com_codeplex_pcsxr_memcard_memnames"
|
||||
#define kPCSXRMemIDs @"com_codeplex_pcsxr_memcard_memids"
|
||||
|
||||
//==============================================================================
|
||||
//
|
||||
|
@ -20,13 +28,202 @@
|
|||
//
|
||||
//==============================================================================
|
||||
|
||||
static void trimPriv(char *str) {
|
||||
int pos = 0;
|
||||
char *dest = str;
|
||||
|
||||
// skip leading blanks
|
||||
while (str[pos] <= ' ' && str[pos] > 0)
|
||||
pos++;
|
||||
|
||||
while (str[pos]) {
|
||||
*(dest++) = str[pos];
|
||||
pos++;
|
||||
}
|
||||
|
||||
*(dest--) = '\0'; // store the null
|
||||
|
||||
// remove trailing blanks
|
||||
while (dest >= str && *dest <= ' ' && *dest > 0)
|
||||
*(dest--) = '\0';
|
||||
}
|
||||
|
||||
static void GetSoloBlockInfo(unsigned char *data, int block, McdBlock *Info)
|
||||
{
|
||||
unsigned char *ptr, *str, *sstr;
|
||||
unsigned short clut[16];
|
||||
unsigned short c;
|
||||
int i, x;
|
||||
|
||||
memset(Info, 0, sizeof(McdBlock));
|
||||
|
||||
ptr = data + block * 8192 + 2;
|
||||
|
||||
Info->IconCount = *ptr & 0x3;
|
||||
|
||||
ptr += 2;
|
||||
|
||||
x = 0;
|
||||
|
||||
str = Info->Title;
|
||||
sstr = Info->sTitle;
|
||||
|
||||
for (i = 0; i < 48; i++) {
|
||||
c = *(ptr) << 8;
|
||||
c |= *(ptr + 1);
|
||||
if (!c) break;
|
||||
|
||||
// Convert ASCII characters to half-width
|
||||
if (c >= 0x8281 && c <= 0x829A)
|
||||
c = (c - 0x8281) + 'a';
|
||||
else if (c >= 0x824F && c <= 0x827A)
|
||||
c = (c - 0x824F) + '0';
|
||||
else if (c == 0x8140) c = ' ';
|
||||
else if (c == 0x8143) c = ',';
|
||||
else if (c == 0x8144) c = '.';
|
||||
else if (c == 0x8146) c = ':';
|
||||
else if (c == 0x8147) c = ';';
|
||||
else if (c == 0x8148) c = '?';
|
||||
else if (c == 0x8149) c = '!';
|
||||
else if (c == 0x815E) c = '/';
|
||||
else if (c == 0x8168) c = '"';
|
||||
else if (c == 0x8169) c = '(';
|
||||
else if (c == 0x816A) c = ')';
|
||||
else if (c == 0x816D) c = '[';
|
||||
else if (c == 0x816E) c = ']';
|
||||
else if (c == 0x817C) c = '-';
|
||||
else {
|
||||
str[i] = ' ';
|
||||
sstr[x++] = *ptr++; sstr[x++] = *ptr++;
|
||||
continue;
|
||||
}
|
||||
|
||||
str[i] = sstr[x++] = c;
|
||||
ptr += 2;
|
||||
}
|
||||
|
||||
trimPriv(str);
|
||||
trimPriv(sstr);
|
||||
|
||||
ptr = data + block * 8192 + 0x60; // icon palette data
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
clut[i] = *((unsigned short *)ptr);
|
||||
ptr += 2;
|
||||
}
|
||||
|
||||
for (i = 0; i < Info->IconCount; i++) {
|
||||
short *icon = &Info->Icon[i * 16 * 16];
|
||||
|
||||
ptr = data + block * 8192 + 128 + 128 * i; // icon data
|
||||
|
||||
for (x = 0; x < 16 * 16; x++) {
|
||||
icon[x++] = clut[*ptr & 0xf];
|
||||
icon[x] = clut[*ptr >> 4];
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
|
||||
ptr = data + block * 128;
|
||||
|
||||
Info->Flags = *ptr;
|
||||
|
||||
ptr += 0xa;
|
||||
strlcpy(Info->ID, ptr, 12);
|
||||
ptr += 12;
|
||||
strlcpy(Info->Name, ptr, 16);
|
||||
}
|
||||
|
||||
static Boolean PopulateMemCards(NSData *fileData, NSArray **outArray)
|
||||
{
|
||||
NSMutableArray *memArray = [[NSMutableArray alloc] initWithCapacity:MAX_MEMCARD_BLOCKS];
|
||||
if (!fileData) {
|
||||
*outArray = @[];
|
||||
return FALSE;
|
||||
}
|
||||
const unsigned char *memPtr = [fileData bytes];
|
||||
if ([fileData length] == MCD_SIZE + 64)
|
||||
memPtr += 64;
|
||||
else if([fileData length] == MCD_SIZE + 3904)
|
||||
memPtr += 3904;
|
||||
else if ([fileData length] != MCD_SIZE)
|
||||
return FALSE;
|
||||
|
||||
int i = 0, x;
|
||||
while (i < MAX_MEMCARD_BLOCKS) {
|
||||
x = 1;
|
||||
McdBlock memBlock;
|
||||
GetSoloBlockInfo((unsigned char *)memPtr, i + 1, &memBlock);
|
||||
|
||||
if ([PcsxrMemoryObject memFlagsFromBlockFlags:memBlock.Flags] == memFlagFree) {
|
||||
//Free space: ignore
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
do {
|
||||
McdBlock tmpBlock;
|
||||
GetSoloBlockInfo((unsigned char *)memPtr, 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);
|
||||
@autoreleasepool {
|
||||
PcsxrMemoryObject *obj = [[PcsxrMemoryObject alloc] initWithMcdBlock:&memBlock startingIndex:i size:x];
|
||||
[memArray addObject:obj];
|
||||
}
|
||||
i += x;
|
||||
}
|
||||
|
||||
*outArray = [[NSArray alloc] initWithArray:memArray];
|
||||
return true;
|
||||
}
|
||||
|
||||
Boolean GetMetadataForFile(void *thisInterface, CFMutableDictionaryRef attributes, CFStringRef contentTypeUTI, CFStringRef pathToFile)
|
||||
{
|
||||
Boolean ok = FALSE;
|
||||
@autoreleasepool {
|
||||
short freeBlocks = MAX_MEMCARD_BLOCKS;
|
||||
short memCount = 0;
|
||||
NSMutableArray *enNames = [[NSMutableArray alloc] initWithCapacity:MAX_MEMCARD_BLOCKS];
|
||||
NSMutableArray *jpNames = [[NSMutableArray alloc] initWithCapacity:MAX_MEMCARD_BLOCKS];
|
||||
NSMutableArray *memNames = [[NSMutableArray alloc] initWithCapacity:MAX_MEMCARD_BLOCKS];
|
||||
NSMutableArray *memIDs = [[NSMutableArray alloc] initWithCapacity:MAX_MEMCARD_BLOCKS];
|
||||
NSMutableDictionary *attr = (__bridge NSMutableDictionary*)attributes;
|
||||
NSString *path = (__bridge NSString*)pathToFile;
|
||||
NSArray *cardArrays;
|
||||
NSData *fileData = [[NSData alloc] initWithContentsOfFile:path options:NSDataReadingMappedIfSafe error:NULL];
|
||||
if (!fileData) {
|
||||
return FALSE;
|
||||
}
|
||||
ok = PopulateMemCards(fileData, &cardArrays);
|
||||
if (!ok) {
|
||||
return FALSE;
|
||||
}
|
||||
for (PcsxrMemoryObject *obj in cardArrays) {
|
||||
// Ignore deleted blocks
|
||||
if (obj.flagNameIndex == memFlagDeleted) {
|
||||
continue;
|
||||
}
|
||||
freeBlocks -= obj.blockSize;
|
||||
memCount++;
|
||||
[enNames addObject:obj.englishName];
|
||||
[jpNames addObject:obj.sjisName];
|
||||
[memNames addObject:obj.memName];
|
||||
[memIDs addObject:obj.memID];
|
||||
}
|
||||
|
||||
|
||||
attr[kPCSXRSaveNames] = @{@"en": [enNames copy],
|
||||
@"jp": [jpNames copy]};
|
||||
attr[kPCSXRMemCount] = @(memCount);
|
||||
attr[kPCSXRFreeBlocks] = @(freeBlocks);
|
||||
attr[kPCSXRMemNames] = [memNames copy];
|
||||
attr[kPCSXRMemIDs] = [memIDs copy];
|
||||
}
|
||||
|
||||
// Return the status
|
||||
|
|
|
@ -13,8 +13,18 @@
|
|||
/* The form is: "myMetadataKey" = "My Metadata Key"; */
|
||||
/* The name on the left is the name defined in schema.xml */
|
||||
/* The name on the right is what the user will see */
|
||||
"com_codeplex_pcsxr_memcard_memcount" = "Saves";
|
||||
"com_codeplex_pcsxr_memcard_freeblocks" = "Free Blocks";
|
||||
"com_codeplex_pcsxr_memcard_savenames" = "Saved Games";
|
||||
"com_codeplex_pcsxr_memcard_memnames" = "Memory Block Names";
|
||||
"com_codeplex_pcsxr_memcard_memids" = "Memory Block IDs";
|
||||
|
||||
/* Localized Description of you custom metadata attributes */
|
||||
/* The form is: "myMetadataKey.Description" = "stuff";
|
||||
/* com_Foo_YourAttrName should be definded in the schema.xml file */
|
||||
/* The value on the right will be displayed by the Finder etc.. */
|
||||
"com_codeplex_pcsxr_memcard_memcount.Description" = "Number of individual save games";
|
||||
"com_codeplex_pcsxr_memcard_freeblocks.Description" = "Number of blocks that are free";
|
||||
"com_codeplex_pcsxr_memcard_savenames.Description" = "The names of the games saved on the memory card";
|
||||
"com_codeplex_pcsxr_memcard_memnames.Description" = "The names of the memory blocks";
|
||||
"com_codeplex_pcsxr_memcard_memids.Descriptions" = "IDs of memory cards";
|
||||
|
|
|
@ -25,16 +25,11 @@
|
|||
-->
|
||||
|
||||
<attributes>
|
||||
<!--
|
||||
<attribute name="net_sourceforge_playerpro_tracker_instumentlist" multivalued="true" type="CFString"/>
|
||||
<attribute name="net_sourceforge_playerpro_tracker_patternlist" multivalued="true" type="CFString"/>
|
||||
<attribute name="net_sourceforge_playerpro_tracker_totalpatterns" multivalued="false" nosearch="true" type="CFNumber"/>
|
||||
<attribute name="net_sourceforge_playerpro_tracker_partitionlength" multivalued="false" nosearch="true" type="CFNumber"/>
|
||||
<attribute name="net_sourceforge_playerpro_tracker_totalinstruments" multivalued="false" nosearch="true" type="CFNumber"/>
|
||||
<attribute name="net_sourceforge_playerpro_tracker_totaltracks" multivalued="false" nosearch="true" type="CFNumber"/>
|
||||
<attribute name="net_sourceforge_playerpro_tracker_formatdescription" multivalued="false" nosearch="true" type="CFString"/>
|
||||
<attribute name="net_sourceforge_playerpro_tracker_madkinfo" multivalued="false" type="CFString" />
|
||||
-->
|
||||
<attribute name="com_codeplex_pcsxr_memcard_memcount" multivalued="false" nosearch="true" type="CFNumber"/>
|
||||
<attribute name="com_codeplex_pcsxr_memcard_freeblocks" multivalued="false" nosearch="true" type="CFNumber"/>
|
||||
<attribute name="com_codeplex_pcsxr_memcard_savenames" multivalued="true" type="CFString"/>
|
||||
<attribute name="com_codeplex_pcsxr_memcard_memnames" multivalued="true" type="CFString"/>
|
||||
<attribute name="com_codeplex_pcsxr_memcard_memids" multivalued="true" type="CFString"/>
|
||||
</attributes>
|
||||
|
||||
<types>
|
||||
|
@ -43,15 +38,17 @@
|
|||
<!-- 'allattrs' is a whitespace separated list of all of the attributes that this UTI type normally has.
|
||||
It does not have to be exhaustive. -->
|
||||
<allattrs>
|
||||
kMDItemTitle
|
||||
kMDItemDurationSeconds
|
||||
kMDItemCodecs
|
||||
com_codeplex_pcsxr_memcard_memcount
|
||||
com_codeplex_pcsxr_memcard_freeblocks
|
||||
com_codeplex_pcsxr_memcard_savenames
|
||||
com_codeplex_pcsxr_memcard_memnames
|
||||
com_codeplex_pcsxr_memcard_memids
|
||||
</allattrs>
|
||||
<!-- 'displayattrs' is a whitespace separated list of the attributes that should normally be displayed when previewing files of this UTI type. -->
|
||||
<displayattrs>
|
||||
kMDItemTitle
|
||||
kMDItemDurationSeconds
|
||||
kMDItemCodecs
|
||||
com_codeplex_pcsxr_memcard_memcount
|
||||
com_codeplex_pcsxr_memcard_freeblocks
|
||||
com_codeplex_pcsxr_memcard_savenames
|
||||
</displayattrs>
|
||||
</type>
|
||||
|
||||
|
|
Loading…
Reference in New Issue