Skip to content

Commit

Permalink
initial commit, incomplete
Browse files Browse the repository at this point in the history
  • Loading branch information
sfomuseumbot committed Jan 3, 2025
0 parents commit 68bafb5
Show file tree
Hide file tree
Showing 6 changed files with 303 additions and 0 deletions.
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.DS_Store
/.build
/Packages
xcuserdata/
DerivedData/
.swiftpm/configuration/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc
*~
14 changes: 14 additions & 0 deletions Package.resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"pins" : [
{
"identity" : "swift-log",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-log.git",
"state" : {
"revision" : "96a2f8a0fa41e9e09af4585e2724c4e825410b91",
"version" : "1.6.2"
}
}
],
"version" : 2
}
34 changes: 34 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// swift-tools-version: 5.9
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
name: "PMTiles",
platforms: [
.iOS(.v14),
.macOS(.v11)
],
products: [
// Products define the executables and libraries a package produces, making them visible to other packages.
.library(
name: "PMTiles",
targets: ["PMTiles"]),
],
dependencies: [
.package(url: "https://github.com/apple/swift-log.git", from: "1.6.2")
],
targets: [
// Targets are the basic building blocks of a package, defining a module or a test suite.
// Targets can depend on other targets in this package and products from dependencies.
.target(
name: "PMTiles",
dependencies: [
.product(name: "Logging", package: "swift-log")
]
),
.testTarget(
name: "swift-pmtilesTests",
dependencies: ["PMTiles"]),
]
)
37 changes: 37 additions & 0 deletions Sources/swift-pmtiles/PMTilesReader.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import Foundation
import Logging

public struct PMTilesReader {

private var reader: reader
public var Logger: Logger?
// private var mu: DispatchSemaphore

public init(db: URL, use_file_descriptor: Bool = false) throws {

reader = PMTiles.reader(database: db, use_file_descriptor: use_file_descriptor)

if case .failure(let error) = reader.open() {
throw error
}

// mu = DispatchSemaphore(value: 1)
}

public func Size() -> Result<UInt64, Error> {
return self.reader.size()
}

public func Read(from: UInt64, to: UInt64) -> Result<Data, Error> {

if case .failure(let error) = reader.seek(from:0, to:to) {
return .failure(error)
}

return self.reader.readBytes(from: from, to: to)
}

public mutating func Close() -> Result<Void, Error> {
return self.reader.close()
}
}
197 changes: 197 additions & 0 deletions Sources/swift-pmtiles/reader.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
import Foundation
import System

internal enum readerError: Error {
case notOpen
case readError
case unknown
}

internal struct reader {

private var db_url: URL
private var db_path: String

private var use_fd: Bool
private var fh: FileHandle?
private var fd: FileDescriptor?
private var mu: DispatchSemaphore
private var is_open: Bool = false

internal init(database: URL, use_file_descriptor: Bool) {
db_url = database
db_path = db_url.absoluteString
use_fd = use_file_descriptor
mu = DispatchSemaphore(value: 1)
}

internal mutating func open() -> Result<Void, Error> {

self.mu.wait()

defer {
self.mu.signal()
}

if !is_open {

do {

if self.use_fd {
let fp = FilePath(self.db_url.absoluteString.replacingOccurrences(of: "file://", with: ""))
fd = try FileDescriptor.open(fp, .readOnly)
} else {
fh = try FileHandle(forReadingFrom: self.db_url)
}

} catch {
return .failure(error)
}

is_open = true
}

return .success(())
}

internal mutating func close() -> Result<Void, Error> {

self.mu.wait()

defer {
self.mu.signal()
}

if !is_open {
return .failure(readerError.notOpen)
}

do {

if self.use_fd {
try fd!.close()
} else {
try fh!.close()
}

} catch (let error) {
return .failure(error)
}

is_open = false

return .success(())
}

internal func size() -> Result<UInt64, Error> {

self.mu.wait()

defer {
self.mu.signal()
}

if !is_open{
return .failure(readerError.notOpen)
}

var size: UInt64 = 0

do {
if self.use_fd {
let size_int64 = try fd!.seek(offset: 0, from: FileDescriptor.SeekOrigin.end)
size = UInt64(size_int64)
} else {
size = try fh!.seekToEnd()
}
} catch (let error){
return .failure(error)
}

return .success(size)
}

internal func readBytes(from: UInt64, to: UInt64) -> Result<Data, Error> {

self.mu.wait()

defer {
self.mu.signal()
}

if !is_open{
return .failure(readerError.notOpen)
}

let next = to + 1
let body: Data!

if self.use_fd {

let read_len = Int(UInt64(next) - from)

guard let data = readData(from: fd!.rawValue, length: Int(read_len)) else {
return .failure(readerError.readError)
}

body = data

} else {

do {
body = try fh?.read(upToCount: Int(next))
} catch (let error){
return .failure(error)
}
}

return .success(body)
}

internal func seek(from: UInt64, to: UInt64) -> Result<Void, Error> {

self.mu.wait()

defer {
self.mu.signal()
}

if !is_open{
return .failure(readerError.notOpen)
}

do {

if self.use_fd {
try fd!.seek(offset: Int64(from), from: FileDescriptor.SeekOrigin.start)
} else {
fh!.seek(toFileOffset: from)
}

} catch {
return .failure(error)
}

return .success(())
}

private func readData(from fileDescriptor: Int32, length: Int) -> Data? {
// Create a Data buffer of the desired length
var data = Data(count: length)

// Read the data into the Data buffer
let bytesRead = data.withUnsafeMutableBytes { buffer -> Int in
guard let baseAddress = buffer.baseAddress else { return -1 }
return read(fileDescriptor, baseAddress, length)
}

// Handle errors or end-of-file
guard bytesRead > 0 else {
return nil // Return nil if no bytes were read
}

// Resize the Data object to the actual number of bytes read
data.removeSubrange(bytesRead..<data.count)
return data
}
}
12 changes: 12 additions & 0 deletions Tests/swift-pmtilesTests/swift_pmtilesTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import XCTest
@testable import swift_pmtiles

final class swift_pmtilesTests: XCTestCase {
func testExample() throws {
// XCTest Documentation
// https://developer.apple.com/documentation/xctest

// Defining Test Cases and Test Methods
// https://developer.apple.com/documentation/xctest/defining_test_cases_and_test_methods
}
}

0 comments on commit 68bafb5

Please sign in to comment.