Gotta redesign the whole decoder layer. Managed to sketch a way to tackle with these php scripter fantasies in the MaxMind DB spec on the whiteboard.
Signed-off-by: Adam Rocska <adam.rocska@adams.solutions>
This commit is contained in:
parent
d236f8ce4e
commit
f02cb01293
|
@ -32,6 +32,11 @@ let package = Package(
|
||||||
dependencies: ["MaxMindDecoder"],
|
dependencies: ["MaxMindDecoder"],
|
||||||
path: "Sources/Metadata"
|
path: "Sources/Metadata"
|
||||||
),
|
),
|
||||||
|
.target(
|
||||||
|
name: "Decoder",
|
||||||
|
dependencies: [],
|
||||||
|
path: "Sources/Decoder"
|
||||||
|
),
|
||||||
|
|
||||||
.target(
|
.target(
|
||||||
name: "DataSection",
|
name: "DataSection",
|
||||||
|
@ -75,6 +80,11 @@ let package = Package(
|
||||||
dependencies: ["MaxMindDecoder"]
|
dependencies: ["MaxMindDecoder"]
|
||||||
),
|
),
|
||||||
|
|
||||||
|
.testTarget(
|
||||||
|
name: "DecoderTests",
|
||||||
|
dependencies: ["Decoder"]
|
||||||
|
),
|
||||||
|
|
||||||
.testTarget(
|
.testTarget(
|
||||||
name: "DataSectionTests",
|
name: "DataSectionTests",
|
||||||
dependencies: ["DataSection", "Metadata"]
|
dependencies: ["DataSection", "Metadata"]
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
enum ControlByte {
|
||||||
|
|
||||||
|
case pointer(payloadSize: UInt32, strayBits: UInt8)
|
||||||
|
case utf8String(payloadSize: UInt32)
|
||||||
|
case double(payloadSize: UInt32)
|
||||||
|
case bytes(payloadSize: UInt32)
|
||||||
|
case uInt16(payloadSize: UInt32)
|
||||||
|
case uInt32(payloadSize: UInt32)
|
||||||
|
case map(payloadSize: UInt32)
|
||||||
|
case int32(payloadSize: UInt32)
|
||||||
|
case uInt64(payloadSize: UInt32)
|
||||||
|
case uInt128(payloadSize: UInt32)
|
||||||
|
case array(payloadSize: UInt32)
|
||||||
|
case dataCacheContainer(payloadSize: UInt32)
|
||||||
|
case endMarker(payloadSize: UInt32)
|
||||||
|
case boolean(payloadSize: UInt32)
|
||||||
|
case float(payloadSize: UInt32)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension ControlByte {
|
||||||
|
var type: DataType {
|
||||||
|
switch self {
|
||||||
|
case .pointer: return DataType.pointer
|
||||||
|
case .utf8String: return DataType.utf8String
|
||||||
|
case .double: return DataType.double
|
||||||
|
case .bytes: return DataType.bytes
|
||||||
|
case .uInt16: return DataType.uInt16
|
||||||
|
case .uInt32: return DataType.uInt32
|
||||||
|
case .map: return DataType.map
|
||||||
|
case .int32: return DataType.int32
|
||||||
|
case .uInt64: return DataType.uInt64
|
||||||
|
case .uInt128: return DataType.uInt128
|
||||||
|
case .array: return DataType.array
|
||||||
|
case .dataCacheContainer: return DataType.dataCacheContainer
|
||||||
|
case .endMarker: return DataType.endMarker
|
||||||
|
case .boolean: return DataType.boolean
|
||||||
|
case .float: return DataType.float
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
enum Data {
|
||||||
|
case pointer(UInt32)
|
||||||
|
case utf8String(String)
|
||||||
|
case double(Double)
|
||||||
|
case bytes(Foundation.Data)
|
||||||
|
case uInt16(UInt16)
|
||||||
|
case uInt32(UInt32)
|
||||||
|
indirect case map([String: Data])
|
||||||
|
case int32(Int32)
|
||||||
|
case uInt64(UInt64)
|
||||||
|
case uInt128(Foundation.Data)
|
||||||
|
indirect case array([Data])
|
||||||
|
indirect case dataCacheContainer([Data])
|
||||||
|
case endMarker
|
||||||
|
case boolean(Bool)
|
||||||
|
case float(Float)
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
enum DataType: UInt8 {
|
||||||
|
case pointer = 1
|
||||||
|
case utf8String = 2
|
||||||
|
case double = 3
|
||||||
|
case bytes = 4
|
||||||
|
case uInt16 = 5
|
||||||
|
case uInt32 = 6
|
||||||
|
case map = 7
|
||||||
|
case int32 = 8
|
||||||
|
case uInt64 = 9
|
||||||
|
case uInt128 = 10
|
||||||
|
case array = 11
|
||||||
|
case dataCacheContainer = 12
|
||||||
|
case endMarker = 13
|
||||||
|
case boolean = 14
|
||||||
|
case float = 15
|
||||||
|
}
|
|
@ -5,6 +5,28 @@ public extension MaxMindDecoder {
|
||||||
private func resolveKey(_ iterator: MaxMindIterator) -> String? {
|
private func resolveKey(_ iterator: MaxMindIterator) -> String? {
|
||||||
switch iterator.next() {
|
switch iterator.next() {
|
||||||
case .some(let cb) where cb.type == .pointer:
|
case .some(let cb) where cb.type == .pointer:
|
||||||
|
let resolver = MaxMindPointerResolver(dataSequence: iterator, decoder: self)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// print(resolver.resolve(MaxMindPointer(1)))
|
||||||
|
print(resolver.resolve(MaxMindPointer(719)))
|
||||||
|
// print(resolver.resolve(MaxMindPointer(12)))
|
||||||
|
// print(resolver.resolve(MaxMindPointer(122)))
|
||||||
|
// print(resolver.resolve(MaxMindPointer(20)))
|
||||||
|
// print(resolver.resolve(MaxMindPointer(2144)))
|
||||||
|
// print(resolver.resolve(MaxMindPointer(35)))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
let pointer = decode(iterator.next(cb), strayBits: cb.strayBits)
|
||||||
|
print(pointer)
|
||||||
|
guard let resolvedValue = resolver.resolve(pointer) else { return nil }
|
||||||
|
if resolvedValue.controlByte.type == .utf8String {
|
||||||
|
return resolvedValue.value as! String
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
case .some(let cb) where cb.type == .utf8String:
|
case .some(let cb) where cb.type == .utf8String:
|
||||||
return decode(iterator.next(cb))
|
return decode(iterator.next(cb))
|
||||||
|
@ -20,6 +42,13 @@ public extension MaxMindDecoder {
|
||||||
|
|
||||||
guard let valueControlByte = iterator.next() else { break }
|
guard let valueControlByte = iterator.next() else { break }
|
||||||
switch valueControlByte.type {
|
switch valueControlByte.type {
|
||||||
|
case .pointer:
|
||||||
|
if valueControlByte.payloadSize == 0 {print("büdös szakmunkás parasztok")}
|
||||||
|
let resolver = MaxMindPointerResolver(dataSequence: iterator, decoder: self)
|
||||||
|
let valueBinary = iterator.next(valueControlByte)
|
||||||
|
let mindPointer = decode(valueBinary, strayBits: valueControlByte.strayBits)
|
||||||
|
print(mindPointer)
|
||||||
|
result[key] = resolver.resolve(mindPointer)?.value
|
||||||
case .map, .array:
|
case .map, .array:
|
||||||
result[key] = decode(iterator, as: valueControlByte)
|
result[key] = decode(iterator, as: valueControlByte)
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
class MaxMindPointerResolver {
|
||||||
|
|
||||||
|
typealias ResolvedValue = (controlByte: ControlByte, value: Any)
|
||||||
|
|
||||||
|
private let dataSequence: PeekableDataSequence
|
||||||
|
private let decoder: MaxMindDecoder
|
||||||
|
|
||||||
|
init(dataSequence: PeekableDataSequence, decoder: MaxMindDecoder) {
|
||||||
|
self.dataSequence = dataSequence
|
||||||
|
self.decoder = decoder
|
||||||
|
}
|
||||||
|
|
||||||
|
func resolve(_ pointer: MaxMindPointer) -> ResolvedValue? {
|
||||||
|
let pointerPosition = Int(pointer)
|
||||||
|
guard let controlByte = dataSequence.peek(at: pointerPosition) else { return nil }
|
||||||
|
let controlByteOffset = Int(controlByte.definitionSize)
|
||||||
|
guard let data = dataSequence.peek(controlByte, at: pointerPosition + controlByteOffset) else { return nil }
|
||||||
|
return (
|
||||||
|
controlByte: controlByte,
|
||||||
|
value: decoder.decode(data, as: controlByte)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
import Foundation
|
||||||
|
import XCTest
|
||||||
|
@testable import Decoder
|
||||||
|
|
||||||
|
class ControlByteTest: XCTestCase {
|
||||||
|
|
||||||
|
func testTypeResolution() {
|
||||||
|
XCTAssertEqual(DataType.pointer, ControlByte.pointer(payloadSize: 123, strayBits: 0b0000_0110).type)
|
||||||
|
XCTAssertEqual(DataType.utf8String, ControlByte.utf8String(payloadSize: 123).type)
|
||||||
|
XCTAssertEqual(DataType.double, ControlByte.double(payloadSize: 123).type)
|
||||||
|
XCTAssertEqual(DataType.bytes, ControlByte.bytes(payloadSize: 123).type)
|
||||||
|
XCTAssertEqual(DataType.uInt16, ControlByte.uInt16(payloadSize: 123).type)
|
||||||
|
XCTAssertEqual(DataType.uInt32, ControlByte.uInt32(payloadSize: 123).type)
|
||||||
|
XCTAssertEqual(DataType.map, ControlByte.map(payloadSize: 123).type)
|
||||||
|
XCTAssertEqual(DataType.int32, ControlByte.int32(payloadSize: 123).type)
|
||||||
|
XCTAssertEqual(DataType.uInt64, ControlByte.uInt64(payloadSize: 123).type)
|
||||||
|
XCTAssertEqual(DataType.uInt128, ControlByte.uInt128(payloadSize: 123).type)
|
||||||
|
XCTAssertEqual(DataType.array, ControlByte.array(payloadSize: 123).type)
|
||||||
|
XCTAssertEqual(DataType.dataCacheContainer, ControlByte.dataCacheContainer(payloadSize: 123).type)
|
||||||
|
XCTAssertEqual(DataType.endMarker, ControlByte.endMarker(payloadSize: 123).type)
|
||||||
|
XCTAssertEqual(DataType.boolean, ControlByte.boolean(payloadSize: 123).type)
|
||||||
|
XCTAssertEqual(DataType.float, ControlByte.float(payloadSize: 123).type)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue