diff --git a/Package.swift b/Package.swift index 979a243..7841a7b 100644 --- a/Package.swift +++ b/Package.swift @@ -32,6 +32,11 @@ let package = Package( dependencies: ["MaxMindDecoder"], path: "Sources/Metadata" ), + .target( + name: "Decoder", + dependencies: [], + path: "Sources/Decoder" + ), .target( name: "DataSection", @@ -75,6 +80,11 @@ let package = Package( dependencies: ["MaxMindDecoder"] ), + .testTarget( + name: "DecoderTests", + dependencies: ["Decoder"] + ), + .testTarget( name: "DataSectionTests", dependencies: ["DataSection", "Metadata"] diff --git a/Sources/Decoder/ControlByte.swift b/Sources/Decoder/ControlByte.swift new file mode 100644 index 0000000..8399e5f --- /dev/null +++ b/Sources/Decoder/ControlByte.swift @@ -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 + } + } +} \ No newline at end of file diff --git a/Sources/Decoder/Data.swift b/Sources/Decoder/Data.swift new file mode 100644 index 0000000..dc8bfd5 --- /dev/null +++ b/Sources/Decoder/Data.swift @@ -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) +} diff --git a/Sources/Decoder/DataType.swift b/Sources/Decoder/DataType.swift new file mode 100644 index 0000000..6155fc0 --- /dev/null +++ b/Sources/Decoder/DataType.swift @@ -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 +} diff --git a/Sources/MaxMindDecoder/MaxMindDecoderMap.swift b/Sources/MaxMindDecoder/MaxMindDecoderMap.swift index d381f7e..8da60b8 100644 --- a/Sources/MaxMindDecoder/MaxMindDecoderMap.swift +++ b/Sources/MaxMindDecoder/MaxMindDecoderMap.swift @@ -5,6 +5,28 @@ public extension MaxMindDecoder { private func resolveKey(_ iterator: MaxMindIterator) -> String? { switch iterator.next() { 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 case .some(let cb) where cb.type == .utf8String: return decode(iterator.next(cb)) @@ -20,6 +42,13 @@ public extension MaxMindDecoder { guard let valueControlByte = iterator.next() else { break } 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: result[key] = decode(iterator, as: valueControlByte) default: diff --git a/Sources/MaxMindDecoder/MaxMindPointerResolver.swift b/Sources/MaxMindDecoder/MaxMindPointerResolver.swift new file mode 100644 index 0000000..f556afe --- /dev/null +++ b/Sources/MaxMindDecoder/MaxMindPointerResolver.swift @@ -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) + ) + } + +} diff --git a/Tests/DecoderTests/ControlByteTest.swift b/Tests/DecoderTests/ControlByteTest.swift new file mode 100644 index 0000000..804fac6 --- /dev/null +++ b/Tests/DecoderTests/ControlByteTest.swift @@ -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) + } + +}