2018-01-01 21:04:13 +00:00
|
|
|
//
|
|
|
|
// CSROMFetcher.m
|
|
|
|
// Clock Signal
|
|
|
|
//
|
|
|
|
// Created by Thomas Harte on 01/01/2018.
|
2018-05-13 19:19:52 +00:00
|
|
|
// Copyright 2018 Thomas Harte. All rights reserved.
|
2018-01-01 21:04:13 +00:00
|
|
|
//
|
|
|
|
|
|
|
|
#import <Foundation/Foundation.h>
|
|
|
|
#include "CSROMFetcher.hpp"
|
|
|
|
|
|
|
|
#import "NSBundle+DataResource.h"
|
|
|
|
#import "NSData+StdVector.h"
|
2021-06-06 18:24:38 +00:00
|
|
|
#import "NSData+CRC32.h"
|
2018-01-01 21:04:13 +00:00
|
|
|
|
|
|
|
#include <string>
|
|
|
|
|
2021-06-06 18:24:38 +00:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
NSString *directoryFor(const ROM::Description &description) {
|
|
|
|
return [@"ROMImages/" stringByAppendingString:[NSString stringWithUTF8String:description.machine_name.c_str()]];
|
|
|
|
}
|
|
|
|
|
|
|
|
NSArray<NSURL *> *urlsFor(const ROM::Description &description, const std::string &file_name) {
|
|
|
|
NSMutableArray<NSURL *> *const urls = [[NSMutableArray alloc] init];
|
|
|
|
NSArray<NSURL *> *const supportURLs = [[NSFileManager defaultManager] URLsForDirectory:NSApplicationSupportDirectory inDomains:NSUserDomainMask];
|
|
|
|
NSString *const subdirectory = directoryFor(description);
|
|
|
|
|
|
|
|
for(NSURL *supportURL in supportURLs) {
|
|
|
|
[urls addObject:[[supportURL URLByAppendingPathComponent:subdirectory]
|
|
|
|
URLByAppendingPathComponent:[NSString stringWithUTF8String:file_name.c_str()]]];
|
|
|
|
}
|
|
|
|
|
|
|
|
return urls;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL CSInstallROM(NSURL *url) {
|
|
|
|
NSData *const data = [NSData dataWithContentsOfURL:url];
|
|
|
|
if(!data) return NO;
|
|
|
|
|
|
|
|
// Try for a direct CRC match.
|
|
|
|
std::optional<ROM::Description> target_description;
|
|
|
|
target_description = ROM::Description::from_crc(uint32_t(data.crc32.integerValue));
|
|
|
|
|
|
|
|
// See whether there's an acceptable trimming that creates a CRC match.
|
|
|
|
if(!target_description) {
|
|
|
|
const std::vector<ROM::Description> descriptions = ROM::all_descriptions();
|
|
|
|
for(const auto &description: descriptions) {
|
|
|
|
if(description.size > data.length) continue;
|
|
|
|
|
|
|
|
NSData *const trimmedData = [data subdataWithRange:NSMakeRange(0, description.size)];
|
|
|
|
if(description.crc32s.find(uint32_t(trimmedData.crc32.unsignedIntValue)) != description.crc32s.end()) {
|
|
|
|
target_description = description;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If no destination was found, stop.
|
|
|
|
if(!target_description) {
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Copy the data to its destination and report success.
|
|
|
|
NSURL *const targetURL = [urlsFor(*target_description, target_description->file_names[0]) firstObject];
|
2021-06-06 18:56:43 +00:00
|
|
|
[[NSFileManager defaultManager] createDirectoryAtPath:targetURL.URLByDeletingLastPathComponent.path withIntermediateDirectories:YES attributes:nil error:nil];
|
|
|
|
[data writeToURL:targetURL atomically:NO];
|
2021-06-06 18:24:38 +00:00
|
|
|
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
2021-06-05 02:24:31 +00:00
|
|
|
ROMMachine::ROMFetcher CSROMFetcher(ROM::Request *missing) {
|
|
|
|
return [missing] (const ROM::Request &roms) -> ROM::Map {
|
|
|
|
ROM::Map results;
|
|
|
|
for(const auto &description: roms.all_descriptions()) {
|
|
|
|
for(const auto &file_name: description.file_names) {
|
|
|
|
NSData *fileData;
|
|
|
|
|
|
|
|
// Check for this file first within the application support directories.
|
2021-06-06 18:24:38 +00:00
|
|
|
for(NSURL *fileURL in urlsFor(description, file_name)) {
|
|
|
|
fileData = [NSData dataWithContentsOfURL:fileURL];
|
2021-06-05 02:24:31 +00:00
|
|
|
if(fileData) break;
|
|
|
|
}
|
2018-01-01 21:04:13 +00:00
|
|
|
|
2021-06-05 02:24:31 +00:00
|
|
|
// Failing that, check inside the application bundle.
|
|
|
|
if(!fileData) {
|
|
|
|
fileData = [[NSBundle mainBundle]
|
|
|
|
dataForResource:[NSString stringWithUTF8String:file_name.c_str()]
|
|
|
|
withExtension:nil
|
2021-06-06 18:24:38 +00:00
|
|
|
subdirectory:directoryFor(description)];
|
2021-06-05 02:24:31 +00:00
|
|
|
}
|
2019-07-21 22:41:00 +00:00
|
|
|
|
2021-06-05 02:24:31 +00:00
|
|
|
// Store an appropriate result.
|
|
|
|
if(fileData) {
|
|
|
|
results[description.name] = fileData.stdVector8;
|
2019-07-21 22:41:00 +00:00
|
|
|
}
|
|
|
|
}
|
2018-01-01 21:04:13 +00:00
|
|
|
}
|
|
|
|
|
2021-06-06 18:24:38 +00:00
|
|
|
if(missing) {
|
|
|
|
*missing = roms.subtract(results);
|
|
|
|
}
|
2021-06-05 02:24:31 +00:00
|
|
|
|
2018-01-01 21:04:13 +00:00
|
|
|
return results;
|
2018-01-25 23:28:19 +00:00
|
|
|
};
|
2018-01-01 21:04:13 +00:00
|
|
|
}
|