Skip to content

Commit db925d9

Browse files
authored
First upload
1 parent ec8ed91 commit db925d9

21 files changed

Lines changed: 91693 additions & 0 deletions

LICENSE.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Copyright 2025 Eduardo Gutiérrez de Oliveira
2+
3+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4+
5+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6+
7+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Package.swift

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// swift-tools-version: 6.1
2+
// The swift-tools-version declares the minimum version of Swift required to build this package.
3+
4+
import PackageDescription
5+
6+
let package = Package(
7+
name: "MAMEDBHandler",
8+
platforms: [
9+
.macOS(.v12)
10+
],
11+
products: [
12+
// Products define the executables and libraries a package produces, making them visible to other packages.
13+
.library(
14+
name: "MAMEDBHandler",
15+
targets: ["MAMEDBHandler"]),
16+
.executable(
17+
name: "MAMEDBTool",
18+
targets: ["MAMEDBTool"])
19+
],
20+
targets: [
21+
// Targets are the basic building blocks of a package, defining a module or a test suite.
22+
// Targets can depend on other targets in this package and products from dependencies.
23+
.target(
24+
name: "MAMEDBHandler",
25+
dependencies: [],
26+
resources: [
27+
.process("Resources")
28+
]),
29+
.executableTarget(
30+
name: "MAMEDBTool",
31+
dependencies: ["MAMEDBHandler"]),
32+
.testTarget(
33+
name: "MAMEDBHandlerTests",
34+
dependencies: ["MAMEDBHandler"]),
35+
]
36+
)

README.md

Lines changed: 264 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,264 @@
1+
# MAMEDBHandler
2+
3+
A Swift package for managing MAME arcade game emulator databases that provides functionality to query and retrieve information about arcade games, their ROM sets, and perform compliance checking.
4+
5+
## Features
6+
7+
- Create SQLite databases from MAME XML files
8+
- Query for game and ROM information
9+
- Support for multiple ROM set formats (split, merged, non-merged, etc.)
10+
- Efficient memory usage with actor-based concurrency
11+
- Game categorization and metadata support
12+
13+
Please note this library expects to read information from the SQLite databases it creates itself and not from other conversions from MAME's XML into SQLite. This library's SQLite Mame Databases are optimized only towards size by focusing only on machine details and ROM/bios/devices details.
14+
15+
## Requirements
16+
17+
- macOS 12.0+
18+
- Swift 5.5+
19+
20+
## Installation
21+
22+
### Swift Package Manager
23+
24+
Add MAMEDBHandler to your Package.swift:
25+
26+
```swift
27+
dependencies: [
28+
.package(url: "https://github.com/yourusername/MAMEDBHandler.git", from: "1.0.0")
29+
]
30+
```
31+
32+
## Quick Start
33+
34+
```swift
35+
import MAMEDBHandler
36+
37+
// Initialize with an existing database
38+
let dbPath = "/path/to/mame.sqlite"
39+
if let manager = await MameDBManager.forDatabase(at: dbPath) {
40+
// Get information about a game
41+
let gameData = try await manager.loadGameDetails(for: "pacman")
42+
43+
// Get merged ROM set
44+
let mergedRoms = MameDBManager.getMergedSetRoms(from: gameData)
45+
46+
// Print ROM information
47+
for rom in mergedRoms {
48+
print("\(rom.name): \(rom.size) bytes, CRC: \(rom.crc)")
49+
}
50+
}
51+
52+
// Create a database from XML
53+
let xmlPath = "/path/to/mame.xml"
54+
let outputPath = "/path/to/output.sqlite"
55+
let manager = try await MameDBManager.createDatabase(
56+
from: URL(fileURLWithPath: xmlPath),
57+
savingTo: URL(fileURLWithPath: outputPath),
58+
overwrite: true
59+
)
60+
```
61+
62+
## ROM Set Types
63+
64+
The package supports several ROM set formats:
65+
66+
- **Split**: Only ROMs specific to a game
67+
- **Merged**: ROMs from a game and its parent/clones
68+
- **Non-merged**: Game ROMs plus parent ROMs
69+
- **MergedPlus**: Merged set plus device ROMs
70+
- **MergedFull**: Merged set plus device and BIOS ROMs
71+
- **NonMergedPlus**: Non-merged set plus device ROMs
72+
- **NonMergedFull**: Non-merged set plus device and BIOS ROMs
73+
74+
# MAMEDBHandler API Documentation
75+
76+
## Core Components
77+
78+
### MameDBManager
79+
80+
The primary interface for interacting with MAME databases.
81+
82+
#### Initialization
83+
84+
```swift
85+
// Initialize with an existing database
86+
public static func forDatabase(at path: String) async -> MameDBManager?
87+
88+
// Create a new database from MAME XML
89+
public static func createDatabase(
90+
from xmlURL: URL,
91+
savingTo outputURL: URL,
92+
overwrite: Bool = false
93+
) async throws -> MameDBManager
94+
```
95+
96+
#### Game Information
97+
98+
```swift
99+
// Get MAME version from database
100+
public func getMameVersion() async throws -> String
101+
102+
// Load detailed information about a specific game
103+
public func loadGameDetails(for gameId: String) async throws -> MachineData
104+
105+
// Get list of all machines/games
106+
public func loadAllMachines() async throws -> [MachineInfo]
107+
108+
// Find a machine by ROM CRCs
109+
public func findMachineWithCRCs(_ crcs: [String]) async throws -> Int?
110+
111+
// Get game name for a machine ID
112+
public func getGameNameForMachine(_ machineId: Int) async throws -> String?
113+
```
114+
115+
#### ROM Set Processing
116+
117+
```swift
118+
// Get split set (game-specific ROMs only)
119+
public static func getSplitSetRoms(from data: MachineData) -> [RomInfo]
120+
121+
// Get merged set (game + parent/clone ROMs)
122+
public static func getMergedSetRoms(from data: MachineData) -> [RomInfo]
123+
124+
// Get non-merged set (game ROMs + required parent ROMs)
125+
public static func getNonMergedSetRoms(from data: MachineData) -> [RomInfo]
126+
127+
// Variants with device and BIOS ROMs
128+
public static func getMergedPlusSetRoms(from data: MachineData) -> [RomInfo]
129+
public static func getMergedFullSetRoms(from data: MachineData) -> [RomInfo]
130+
public static func getNonMergedPlusSetRoms(from data: MachineData) -> [RomInfo]
131+
public static func getNonMergedFullSetRoms(from data: MachineData) -> [RomInfo]
132+
133+
// Generic function accepting SetType enum
134+
public static func getRomSet(type: SetType, from data: MachineData) -> [RomInfo]
135+
```
136+
137+
### MasterListManager
138+
139+
Manages cached lists of games to improve performance.
140+
141+
```swift
142+
// Get the shared instance
143+
public static let shared: MasterListManager
144+
145+
// Get or load the master list for a specific database version
146+
public func getMasterList(
147+
for version: String,
148+
databasePath: String? = nil
149+
) async throws -> [MameGame]
150+
```
151+
152+
## Data Models
153+
154+
### MachineInfo
155+
156+
Contains metadata about MAME machines (games).
157+
158+
```swift
159+
public struct MachineInfo {
160+
public let description: String
161+
public let name: String
162+
public let year: String
163+
public let manufacturer: String
164+
public let cloneof: String?
165+
public let parent_name: String?
166+
public let parent_year: String?
167+
}
168+
```
169+
170+
### RomInfo
171+
172+
Represents information about ROM files.
173+
174+
```swift
175+
public struct RomInfo {
176+
public enum RomType: String {
177+
case gameRom = "game"
178+
case cloneRom = "clone"
179+
case biosRom = "bios"
180+
case deviceRom = "device"
181+
}
182+
183+
public let name: String
184+
public let size: Int64
185+
public let crc: String
186+
public let status: String?
187+
public let merge: String?
188+
public let type: RomType
189+
}
190+
```
191+
192+
### MameGame
193+
194+
Comprehensive representation of a MAME game with metadata.
195+
196+
```swift
197+
public struct MameGame: Identifiable {
198+
public var id: String { name }
199+
200+
public let name: String
201+
public let description: String
202+
public let year: String
203+
public let manufacturer: String
204+
public var roms: [RomInfo]
205+
public let gameRating: GameRating?
206+
public let languages: [String]
207+
public let machineType: String?
208+
public let category: String?
209+
public let subcategory: String?
210+
public let isMature: Bool
211+
public let shortTitle: String?
212+
public var source: GameSource
213+
public var parent: String?
214+
// Additional properties...
215+
}
216+
```
217+
218+
### MachineData
219+
220+
Comprehensive data structure for a machine and its ROMs.
221+
222+
```swift
223+
public struct MachineData {
224+
public let machine: MachineInfo
225+
public let parent: MachineInfo?
226+
public let allRoms: [RomWithMetadata]
227+
228+
// Derived properties
229+
public var directRoms: [RomWithMetadata]
230+
public var parentRoms: [RomWithMetadata]
231+
public var deviceRoms: [RomWithMetadata]
232+
public var biosRoms: [RomWithMetadata]
233+
}
234+
```
235+
236+
## Error Handling
237+
238+
```swift
239+
public enum DBError: LocalizedError {
240+
case queryPreparationFailed
241+
case recordNotFound
242+
case deviceRecursionLimit
243+
case databaseNotInitialized
244+
case operationFailed(String)
245+
}
246+
```
247+
248+
## Constants and Enums
249+
250+
```swift
251+
public enum SetType: String {
252+
case split
253+
case merged
254+
case nonmerged
255+
case mergedplus
256+
case mergedfull
257+
case nonmergedplus
258+
case nonmergedfull
259+
}
260+
```
261+
262+
## License
263+
264+
MIT License
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import Foundation
2+
import SQLite3
3+
4+
public actor DatabaseActor {
5+
/// The SQLite database connection
6+
private var db: OpaquePointer?
7+
8+
/// Initializes a new DatabaseActor
9+
public init() {}
10+
11+
/// Sets the database connection
12+
/// - Parameter db: The SQLite database connection pointer
13+
public func setDB(_ db: OpaquePointer?) {
14+
self.db = db
15+
}
16+
17+
/// Closes the database connection
18+
public func closeDB() {
19+
if let db = db {
20+
sqlite3_close(db)
21+
}
22+
self.db = nil
23+
}
24+
25+
/// Performs an operation with the database connection
26+
/// - Parameter block: The block to execute with the database connection
27+
/// - Returns: The result of the block
28+
/// - Throws: Any error thrown by the block
29+
public func perform<T: Sendable>(_ block: @Sendable (OpaquePointer?) throws -> T) async throws -> T {
30+
guard let db = db else {
31+
throw DBError.databaseNotInitialized
32+
}
33+
return try block(db)
34+
}
35+
}

0 commit comments

Comments
 (0)