v1.0 Release

This commit is contained in:
Milen Dzhumerov 2017-08-20 20:41:06 +01:00
commit bbb40b226e
44 changed files with 4620 additions and 0 deletions

18
.gitignore vendored Executable file
View File

@ -0,0 +1,18 @@
.DS_Store
/.build
/Packages
build/
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
*.xcworkspace
!default.xcworkspace
xcuserdata
profile
*.moved-aside
DerivedData

3
CHANGELOG.md Executable file
View File

@ -0,0 +1,3 @@
## [1.0](https://github.com/milend/hmap/releases/tag/1.0) (2017-08-20)
- Public release

21
LICENSE.md Executable file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017 Milen Dzhumerov
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:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
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.

18
Package.pins Executable file
View File

@ -0,0 +1,18 @@
{
"autoPin": true,
"pins": [
{
"package": "Commander",
"reason": null,
"repositoryURL": "git@github.com:kylef/Commander.git",
"version": "0.6.0"
},
{
"package": "Spectre",
"reason": null,
"repositoryURL": "https://github.com/kylef/Spectre",
"version": "0.7.2"
}
],
"version": 1
}

47
Package.swift Executable file
View File

@ -0,0 +1,47 @@
// swift-tools-version:3.1
import PackageDescription
let package = Package(
name: "hmap",
targets: [
Target(
name: "hmap",
dependencies: [
"HeaderMapCore",
"HeaderMapFrontend",
]
),
Target(
name: "HeaderMapCore"
),
Target(
name: "HeaderMapFrontend",
dependencies: [
"HeaderMapCore",
]
),
Target(
name: "HeaderMapTesting"
),
Target(
name: "HeaderMapCoreTests",
dependencies: [
"HeaderMapTesting",
]
),
Target(
name: "HeaderMapFrontendTests",
dependencies: [
"HeaderMapTesting",
]
)
],
dependencies: [
.Package(
url: "git@github.com:kylef/Commander.git",
"0.6.0"
),
],
swiftLanguageVersions: [3]
)

57
README.md Executable file
View File

@ -0,0 +1,57 @@
# What is this?
`hmap` is a command line tool to work with Clang header maps produced by Xcode.
It is written in Swift.
# How to Get
- Grab a [release](https://github.com/milend/hmap/releases) from GitHub.
- Build from source. See instructions below.
# How to Use
To print the contents of a header map:
hmap print ~/path/to/header_map.hmap
To convert the contents of a binary header map to JSON:
hmap convert ~/header_map.hmap ~/header_map.json
`hmap` deduces file formats by looking at the file extensions of the paths.
You can also use the `convert` command to create a binary header map from JSON:
hmap convert ~/header_map.json ~/header_map.hmap
You can discover all the commands and options by using `hmap --help`.
# Building from Source
## Xcode
The easiest way to build `hmap` is to use the provided Xcode project.
## Swift Package Manager
If you would like to build from the command line, run:
swift build
To produce a release build suitable for distribution, run:
swift build -c release -Xswiftc -static-stdlib
# Contributing
To generate an Xcode project, run:
swift package generate-xcodeproj
You must manually add the test files for the test targets as the Swift Package
Manager does not yet have such functionality (tracked by
[SR-2866](https://bugs.swift.org/browse/SR-2866)).
If you end up adding new dependencies, remember to run:
swift package update

View File

@ -0,0 +1,310 @@
// MIT License
//
// Copyright (c) 2017 Milen Dzhumerov
//
// 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:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// 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.
import Foundation
protocol Packable {
static var packedSize: Int { get }
}
/**
This implements v1 of the Clang header map format. For reference, see the
following files in the Clang source tree:
- HeaderMap.h
- HeaderMap.cpp
- HeaderMapTypes.h
*/
struct BinaryHeaderMap {
static let StringEncoding: String.Encoding = .utf8
struct DataHeader: Packable {
typealias MagicType = Magic
typealias VersionType = Version
typealias ReservedType = Reserved
typealias StringSectionOffsetType = UInt32
typealias StringCountType = UInt32
typealias BucketCountType = UInt32
typealias MaxValueLengthType = UInt32
let magic: MagicType
let version: VersionType
let reserved: ReservedType
let stringSectionOffset: StringSectionOffsetType
let stringCount: StringCountType
let bucketCount: BucketCountType // Must be power of 2
let maxValueLength: MaxValueLengthType
static var packedSize: Int {
return
MemoryLayout<Magic.RawValue>.size +
MemoryLayout<Version.RawValue>.size +
MemoryLayout<Reserved.RawValue>.size +
MemoryLayout<UInt32>.size +
MemoryLayout<UInt32>.size +
MemoryLayout<UInt32>.size +
MemoryLayout<UInt32>.size;
}
}
enum Magic: UInt32 {
case hmap = 0x68_6D_61_70 // 'hmap'
}
enum Version: UInt16 {
case version1 = 1
}
enum Reserved: UInt16 {
case none = 0
}
struct Bucket: Packable {
typealias OffsetType = StringSectionOffset
let key: OffsetType
let prefix: OffsetType
let suffix: OffsetType
// MARK: Packable
static var packedSize: Int {
return OffsetType.packedSize * 3;
}
}
struct StringSectionOffset: Packable {
typealias OffsetType = UInt32
/** Indicates an invalid offset */
static let Reserved = OffsetType(0)
let offset: OffsetType
init?(offset: OffsetType) {
if offset == StringSectionOffset.Reserved {
// The first byte is reserved and means 'empty'.
return nil
}
self.offset = offset
}
static var packedSize: Int {
return MemoryLayout<OffsetType>.size;
}
}
fileprivate let data: Data
fileprivate let header: DataHeader
fileprivate let byteSwap: Bool
public init(data: Data) throws {
let parseResult = try parseHeaderMap(data: data)
self.data = data
self.header = parseResult.dataHeader
self.byteSwap = parseResult.byteSwap
}
}
// MARK: - Private
enum ProbeAction<T> {
case keepProbing
case stop(value: T?)
}
func probeHashTable<T>(
bucketCount: BinaryHeaderMap.DataHeader.BucketCountType,
start: UInt32,
_ body: (UInt32) -> ProbeAction<T>) -> T? {
var probeAttempts = BinaryHeaderMap.DataHeader.BucketCountType(0)
var nextUnboundedBucketIndex = start
while (probeAttempts < bucketCount) {
// Takes advantage of the fact that buckets are a power of 2
let nextBucketIndex = nextUnboundedBucketIndex & (bucketCount - 1)
switch body(nextBucketIndex) {
case .keepProbing:
break
case .stop(let value):
return value
}
nextUnboundedBucketIndex += 1
probeAttempts += 1
}
return nil
}
extension BinaryHeaderMap {
func getBucket(at index: UInt32) -> Bucket? {
let offset =
BinaryHeaderMap.DataHeader.packedSize + Int(index) * Bucket.packedSize
return withBoundsCheckedBytes(at: offset, count: Bucket.packedSize) {
(bytesPointer) in
return BinaryHeaderMap.Bucket(bytes: bytesPointer, byteSwap: byteSwap)
}
}
var bucketCount: UInt32 {
return header.bucketCount
}
func getString(at offset: StringSectionOffset) -> String? {
let begin = Int(header.stringSectionOffset + offset.offset)
guard begin < data.count else { return nil }
let nullByteIndex = data.withUnsafeBytes {
(bytes: UnsafePointer<UInt8>) -> Int? in
for i in begin..<data.count {
if bytes.advanced(by: i).pointee == 0x0 {
return i
}
}
return nil
}
return nullByteIndex.flatMap { (nullIndex) in
let stringData = data.subdata(in: begin..<nullIndex)
return String(data: stringData, encoding: BinaryHeaderMap.StringEncoding)
}
}
func withBoundsCheckedBytes<Result>(
at offset: Int,
count: Int,
_ body: (UnsafePointer<UInt8>) throws -> Result?
) rethrows -> Result? {
guard offset + count < data.count else {
return nil
}
return try data.withUnsafeBytes {
return try body($0.advanced(by: offset))
}
}
}
// MARK: - Bucket
extension BinaryHeaderMap.Bucket {
init?(bytes: UnsafePointer<UInt8>, byteSwap: Bool) {
let decoder = ByteBufferDecoder(bytes: bytes, byteSwap: byteSwap)
guard
let keyOffset = BinaryHeaderMap.StringSectionOffset(
offset: decoder.advance()),
let prefixOffset = BinaryHeaderMap.StringSectionOffset(
offset: decoder.advance()),
let suffixOffset = BinaryHeaderMap.StringSectionOffset(
offset: decoder.advance())
else { return nil }
self.init(
key: keyOffset,
prefix: prefixOffset,
suffix: suffixOffset)
}
}
// MARK: - Header
struct DataHeaderParseResult {
let dataHeader: BinaryHeaderMap.DataHeader
let byteSwap: Bool
}
func parseHeaderMap(data: Data) throws -> DataHeaderParseResult {
if data.count < BinaryHeaderMap.DataHeader.packedSize {
throw HeaderMapParseError.missingDataHeader
}
return try data.withUnsafeBytes { (headerBytes: UnsafePointer<UInt8>) in
typealias H = BinaryHeaderMap.DataHeader
let decoder = ByteBufferDecoder(bytes: headerBytes, byteSwap: false)
let magicValue = decoder.advanceByteSwappable(
expect: H.MagicType.hmap.rawValue
)
let versionValue: H.VersionType.RawValue = decoder.advance()
let reseredValue: H.ReservedType.RawValue = decoder.advance()
let stringSectionOffset: H.StringSectionOffsetType = decoder.advance()
let stringCount: H.StringCountType = decoder.advance()
let bucketCount: H.BucketCountType = decoder.advance()
let maxValueLength: H.MaxValueLengthType = decoder.advance()
guard let magic = H.MagicType(rawValue: magicValue) else {
throw HeaderMapParseError.unknownFileMagic
}
let expectedVersion = BinaryHeaderMap.Version.version1
guard versionValue == expectedVersion.rawValue else {
throw HeaderMapParseError.invalidVersion(
expected: expectedVersion.rawValue,
found: versionValue)
}
let expectedReserved = BinaryHeaderMap.Reserved.none
guard reseredValue == expectedReserved.rawValue else {
throw HeaderMapParseError.reservedValueMismatch(
expected: expectedReserved.rawValue,
found: reseredValue)
}
guard bucketCount.isPowerOf2 else {
throw HeaderMapParseError.bucketCountNotPowerOf2(found: bucketCount)
}
guard Int(stringSectionOffset) < data.count else {
throw HeaderMapParseError.outOfBoundsStringSectionOffset
}
let bucketsSectionSize = Int(bucketCount) * BinaryHeaderMap.Bucket.packedSize
let headerAndBucketsSectionSize = H.packedSize + bucketsSectionSize
guard headerAndBucketsSectionSize < data.count else {
throw HeaderMapParseError.bucketsSectionOverflow
}
guard headerAndBucketsSectionSize <= Int(stringSectionOffset) else {
throw HeaderMapParseError.invalidStringSectionOffset
}
return DataHeaderParseResult(
dataHeader: BinaryHeaderMap.DataHeader(
magic: magic,
version: expectedVersion,
reserved: expectedReserved,
stringSectionOffset: stringSectionOffset,
stringCount: stringCount,
bucketCount: bucketCount,
maxValueLength: maxValueLength),
byteSwap: decoder.byteSwap)
}
}

View File

@ -0,0 +1,86 @@
// MIT License
//
// Copyright (c) 2017 Milen Dzhumerov
//
// 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:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// 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.
import Foundation
class ByteBufferDecoder {
private let bytes: UnsafePointer<UInt8>
private var offset: Int
private(set) var byteSwap: Bool
init(bytes: UnsafePointer<UInt8>, byteSwap: Bool) {
self.bytes = bytes
self.offset = 0
self.byteSwap = byteSwap
}
func advance<T: ByteSwappable & Equatable>() -> T {
return advance {
// Needs temporary `result` due to Swift's type inference
let result: T = castBytes()
return result.byte(swapped: byteSwap)
}
}
func advanceByteSwappable<T: ByteSwappable & Equatable>(expect expectedValue: T) -> T {
return advance {
let memoryValue: T = castBytes()
let swappedValue = expectedValue.byte(swapped: true)
if memoryValue == expectedValue || memoryValue == swappedValue {
byteSwap = (memoryValue == swappedValue)
return expectedValue
}
return memoryValue
}
}
fileprivate func castBytes<T>() -> T {
return bytes.advanced(by: offset).withMemoryRebound(to: T.self, capacity: 1) {
return $0.pointee
}
}
private func advance<T>(_ body: () -> T) -> T {
let value = body()
offset += MemoryLayout<T>.size
return value
}
}
class ByteBufferEncoder {
private(set) var bytes = Data()
func encode<T>(_ value: T) {
var mutableValue = value
withUnsafeBytes(of: &mutableValue) { (pointer) in
let valueBytes = Array(pointer[0..<pointer.count])
bytes.append(contentsOf: valueBytes)
}
}
func append(_ data: Data) {
bytes.append(data)
}
}

View File

@ -0,0 +1,118 @@
// MIT License
//
// Copyright (c) 2017 Milen Dzhumerov
//
// 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:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// 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.
import Foundation
public struct HeaderMap {
public struct Entry {
public let key: String
public let prefix: String
public let suffix: String
public init(key: String, prefix: String, suffix: String) {
self.key = key
self.prefix = prefix
self.suffix = suffix
}
}
public init(data: Data) throws {
let binaryHeader = try BinaryHeaderMap(data: data)
self.entries = try makeIndexedEntries(from: binaryHeader.makeEntries())
}
public init(entries: [Entry]) throws {
self.entries = try makeIndexedEntries(from: entries)
}
fileprivate typealias EntryIndex = [Data: Entry]
fileprivate let entries: EntryIndex
}
// MARK: - Private
fileprivate extension BinaryHeaderMap {
func makeEntries() -> [HeaderMap.Entry] {
return (0..<bucketCount).flatMap { (index) in
return getBucket(at: index).flatMap { (bucket) in
return makeEntry(forBucket: bucket)
}
}
}
func makeEntry(forBucket bucket: Bucket) -> HeaderMap.Entry? {
guard
let key = getString(at: bucket.key),
let prefix = getString(at: bucket.prefix),
let suffix = getString(at: bucket.suffix)
else { return nil }
return HeaderMap.Entry(
key: key,
prefix: prefix,
suffix: suffix)
}
}
fileprivate func makeIndexedEntries(from entries: [HeaderMap.Entry]) throws -> HeaderMap.EntryIndex {
return try sanitize(headerEntries: entries).dictionaryMap { (entry) in
let lowercasedBytes = try entry.key.clangLowercasedBytes()
return (lowercasedBytes, entry)
}
}
// MARK: - Public
extension HeaderMap {
public subscript(key: String) -> HeaderMap.Entry? {
guard let lowercasedBytes = try? key.clangLowercasedBytes() else {
return nil
}
return entries[lowercasedBytes]
}
public func makeEntryList() -> [HeaderMap.Entry] {
return entries.map { (_, entry) in
return entry
}
}
}
extension HeaderMap {
public static func makeBinary(withEntries entries: [Entry]) throws -> Data {
return try makeHeaderMapBinaryData(withEntries: entries)
}
}
extension HeaderMap.Entry: Hashable {
public var hashValue: Int {
return key.hashValue ^ prefix.hashValue ^ suffix.hashValue
}
public static func ==(lhs: HeaderMap.Entry, rhs: HeaderMap.Entry) -> Bool {
return lhs.key == rhs.key &&
lhs.prefix == rhs.prefix &&
lhs.suffix == rhs.suffix
}
}

View File

@ -0,0 +1,95 @@
// MIT License
//
// Copyright (c) 2017 Milen Dzhumerov
//
// 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:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// 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.
import Foundation
public enum HeaderMapError: LocalizedError {
case unencodableString
}
public enum HeaderMapParseError: LocalizedError {
case missingDataHeader
case unknownFileMagic
case invalidVersion(expected: UInt16, found: UInt16)
case reservedValueMismatch(expected: UInt16, found: UInt16)
case outOfBoundsStringSectionOffset
case bucketCountNotPowerOf2(found: UInt32)
case bucketsSectionOverflow
case invalidStringSectionOffset
}
public enum HeaderMapCreateError: LocalizedError {
case invalidStringSectionOffset
case noEntries
case stringWithoutOffsetInTable
case hashTableFull
case unhashableKey
}
extension HeaderMapError {
public var errorDescription: String? {
switch self {
case .unencodableString:
return "String cannot be encoded"
}
}
}
extension HeaderMapParseError {
public var errorDescription: String? {
switch self {
case .missingDataHeader:
return "File is missing a header section"
case .unknownFileMagic:
return "File magic is unknown"
case .invalidVersion(let expected, let found):
return "Found invalid version \(found), expected \(expected)"
case .reservedValueMismatch(let expected, let found):
return "Found invalid reserved value \(found), expected \(expected)"
case .outOfBoundsStringSectionOffset:
return "String offset is out of bounds"
case .bucketCountNotPowerOf2(let buckets):
return "Bucket count is not a power of 2, found \(buckets) buckets"
case .bucketsSectionOverflow:
return "Bucket section overflows"
case .invalidStringSectionOffset:
return "The string section offset is invalid"
}
}
}
extension HeaderMapCreateError {
public var errorDescription: String? {
switch self {
case .invalidStringSectionOffset:
return "The string section offset is invalid"
case .noEntries:
return "Header map needs to contain at least one entry"
case .stringWithoutOffsetInTable:
return "String not present in string section"
case .hashTableFull:
return "Header map is full"
case .unhashableKey:
return "Key cannot be hashed"
}
}
}

View File

@ -0,0 +1,216 @@
// MIT License
//
// Copyright (c) 2017 Milen Dzhumerov
//
// 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:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// 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.
import Foundation
func makeHeaderMapBinaryData(
withEntries unsafeEntries: [HeaderMap.Entry]) throws -> Data {
guard unsafeEntries.count > 0 else {
throw HeaderMapCreateError.noEntries
}
let safeEntries = sanitize(headerEntries: unsafeEntries)
let allStrings = Set(safeEntries.flatMap { [$0.key, $0.prefix, $0.suffix] })
let stringSection = try makeStringSection(allStrings: allStrings)
let bucketSection = try makeBucketSection(
forEntries: safeEntries,
stringSection: stringSection)
let maxValueLength = safeEntries.max(by: { lhs, rhs in
return lhs.valueLength < rhs.valueLength
}).map { $0.valueLength } ?? 0
let headerSize = BinaryHeaderMap.DataHeader.packedSize
let stringSectionOffset = headerSize + bucketSection.data.count
let header = BinaryHeaderMap.DataHeader(
magic: .hmap,
version: .version1,
reserved: .none,
stringSectionOffset: UInt32(stringSectionOffset),
stringCount: UInt32(stringSection.stringCount),
bucketCount: UInt32(bucketSection.bucketCount),
maxValueLength: UInt32(maxValueLength))
let encoder = ByteBufferEncoder()
encoder.encode(header.magic.rawValue)
encoder.encode(header.version.rawValue)
encoder.encode(header.reserved.rawValue)
encoder.encode(header.stringSectionOffset)
encoder.encode(header.stringCount)
encoder.encode(header.bucketCount)
encoder.encode(header.maxValueLength)
encoder.append(bucketSection.data)
encoder.append(stringSection.data)
return encoder.bytes
}
fileprivate struct BucketSection {
let data: Data
let bucketCount: Int
}
fileprivate struct StringSection {
let data: Data
let stringCount: Int
let offsets: [String: BinaryHeaderMap.StringSectionOffset]
}
fileprivate func makeStringSection(
allStrings: Set<String>) throws -> StringSection {
var buffer = Data()
buffer.append(UInt8(BinaryHeaderMap.StringSectionOffset.Reserved))
var offsets = Dictionary<String, BinaryHeaderMap.StringSectionOffset>()
for string in allStrings {
guard let stringBytes = string.data(using: BinaryHeaderMap.StringEncoding) else {
throw HeaderMapError.unencodableString
}
let bufferCount = UInt32(buffer.count)
guard
let offset = BinaryHeaderMap.StringSectionOffset(offset: bufferCount)
else {
throw HeaderMapCreateError.invalidStringSectionOffset
}
offsets[string] = offset
buffer.append(stringBytes)
buffer.append(0x0) // NUL character
}
return StringSection(
data: buffer,
stringCount: allStrings.count,
offsets: offsets)
}
fileprivate func isBucketSlotEmpty(
bytePointer: UnsafeMutablePointer<UInt8>,
index: UInt32) -> Bool {
let slotOffset = Int(index) * BinaryHeaderMap.Bucket.packedSize
let slotPointer = bytePointer.advanced(by: slotOffset)
return slotPointer.withMemoryRebound(
to: BinaryHeaderMap.StringSectionOffset.OffsetType.self,
capacity: 1) {
return $0.pointee == BinaryHeaderMap.StringSectionOffset.Reserved
}
}
fileprivate func writeTo<T>(bytePointer: UnsafeMutablePointer<UInt8>, value: T) {
var mutableValue = value
withUnsafeBytes(of: &mutableValue) { (pointer) in
let valueBytes = Array(pointer[0..<pointer.count])
for (index, byte) in valueBytes.enumerated() {
bytePointer.advanced(by: index).pointee = byte
}
}
}
fileprivate func makeBucketSection(
forEntries entries: [HeaderMap.Entry],
stringSection: StringSection) throws -> BucketSection {
assert(entries.count > 0)
let bucketCount = numberOfBuckets(forEntryCount: entries.count)
var bytes = Data(count: bucketCount * BinaryHeaderMap.Bucket.packedSize)
try bytes.withUnsafeMutableBytes {
(bytePointer: UnsafeMutablePointer<UInt8>) in
try entries.forEach { (entry) in
guard let keyHash = entry.key.headerMapHash else {
throw HeaderMapCreateError.unhashableKey
}
guard
let keyOffset = stringSection.offsets[entry.key],
let prefixOffset = stringSection.offsets[entry.prefix],
let suffixOffset = stringSection.offsets[entry.suffix]
else {
throw HeaderMapCreateError.stringWithoutOffsetInTable
}
let maybeEmptySlotIndex: UInt32? = probeHashTable(
bucketCount: UInt32(bucketCount),
start: keyHash) { (probeIndex) in
if isBucketSlotEmpty(bytePointer: bytePointer, index: probeIndex) {
return .stop(value: probeIndex)
}
return .keepProbing
}
guard let emptySlotIndex = maybeEmptySlotIndex else {
throw HeaderMapCreateError.hashTableFull
}
let slotPointer = bytePointer.advanced(
by: Int(emptySlotIndex) * BinaryHeaderMap.Bucket.packedSize)
let fieldSize = MemoryLayout<BinaryHeaderMap.Bucket.OffsetType>.size
writeTo(
bytePointer: slotPointer,
value: keyOffset.offset)
writeTo(
bytePointer: slotPointer.advanced(by: fieldSize),
value: prefixOffset.offset)
writeTo(
bytePointer: slotPointer.advanced(by: 2 * fieldSize),
value: suffixOffset.offset)
}
}
return BucketSection(data: bytes, bucketCount: bucketCount)
}
fileprivate func numberOfBuckets(forEntryCount entryCount: Int) -> Int {
assert(entryCount > 0)
let minimumSlots = Int(ceil(Double(entryCount) * (1.0 / 0.7)))
var bucketCount = 1
while bucketCount < minimumSlots {
bucketCount <<= 1
}
return bucketCount
}
func sanitize(headerEntries entries: [HeaderMap.Entry]) -> [HeaderMap.Entry] {
var allKeys = Set<String>()
return entries.flatMap { (entry) in
guard !allKeys.contains(entry.key) else { return nil }
allKeys.insert(entry.key)
return entry
}
}
fileprivate extension HeaderMap.Entry {
var valueLength: Int {
return prefix.lengthOfBytes(using: BinaryHeaderMap.StringEncoding) +
suffix.lengthOfBytes(using: BinaryHeaderMap.StringEncoding)
}
}

View File

@ -0,0 +1,184 @@
// MIT License
//
// Copyright (c) 2017 Milen Dzhumerov
//
// 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:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// 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.
import Foundation
public struct JSONHeaderMap {
public struct Entry {
public let prefix: String
public let suffix: String
public init(prefix: String, suffix: String) {
self.prefix = prefix
self.suffix = suffix
}
}
public let entries: [String: Entry]
public init(entries: [String: Entry]) {
self.entries = entries
}
}
// MARK: - Error
enum JSONHeaderMapError: LocalizedError {
case invalidTopLevelObject
case invalidEntryObject
case missingPrefix
case missingSuffix
}
extension JSONHeaderMapError {
public var errorDescription: String? {
switch self {
case .invalidTopLevelObject:
return "The top level object in the JSON is invalid."
case .invalidEntryObject:
return "The entry object in the JSON is invalid."
case .missingPrefix:
return "An entry object does not have a value for the 'prefix' key."
case .missingSuffix:
return "An entry object does not have a value for the 'suffix' key."
}
}
}
// MARK: - Decode
extension JSONHeaderMap.Entry {
init(json: Any) throws {
guard let dict = json as? [String: String] else {
throw JSONHeaderMapError.invalidEntryObject
}
guard let prefix = dict[JSONHeaderMapEntryKey.prefix.rawValue] else {
throw JSONHeaderMapError.missingPrefix
}
guard let suffix = dict[JSONHeaderMapEntryKey.suffix.rawValue] else {
throw JSONHeaderMapError.missingSuffix
}
self.prefix = prefix
self.suffix = suffix
}
}
public extension JSONHeaderMap {
public init(json: Any) throws {
guard let dict = json as? [String: Any] else {
throw JSONHeaderMapError.invalidTopLevelObject
}
self.entries = try dict.dictionaryMap { (key, jsonValue) in
let entry = try Entry(json: jsonValue)
return (key, entry)
}
}
public init(jsonData: Data) throws {
let jsonObj = try JSONSerialization.jsonObject(with: jsonData, options: [])
try self.init(json: jsonObj)
}
}
// MARK: - Encode
extension JSONHeaderMap.Entry {
var jsonValue: Any {
return [
JSONHeaderMapEntryKey.prefix.rawValue: prefix,
JSONHeaderMapEntryKey.suffix.rawValue: suffix,
]
}
}
extension JSONHeaderMap {
public var jsonValue: Any {
return entries.dictionaryMap { (key, entry) in
return (key, entry.jsonValue)
}
}
public func makeJSONData(prettyPrinted: Bool = true) throws -> Data {
let opts = prettyPrinted ? JSONSerialization.WritingOptions.prettyPrinted : []
return try JSONSerialization.data(withJSONObject: jsonValue, options: opts)
}
}
// MARK: - Keys
enum JSONHeaderMapEntryKey: String {
case prefix = "prefix"
case suffix = "suffix"
}
// MARK: - Conversion
public extension HeaderMap.Entry {
public var jsonEntry: JSONHeaderMap.Entry {
return JSONHeaderMap.Entry(
prefix: prefix,
suffix: suffix
)
}
}
extension JSONHeaderMap.Entry: Hashable {
public var hashValue: Int {
return prefix.hashValue ^ suffix.hashValue
}
public static func ==(lhs: JSONHeaderMap.Entry, rhs: JSONHeaderMap.Entry) -> Bool {
return lhs.prefix == rhs.prefix && lhs.suffix == rhs.suffix
}
}
public extension HeaderMap {
public func makeJSONHeaderMap() -> JSONHeaderMap {
let jsonEntries = makeEntryList().dictionaryMap { (entry) in
return (entry.key, entry.jsonEntry)
}
return JSONHeaderMap(entries: jsonEntries)
}
public static func binaryDataFrom(jsonHeaderMap: JSONHeaderMap) throws -> Data {
let hmapEntries = jsonHeaderMap.entries.map { (key, jsonEntry) in
return HeaderMap.Entry(
key: key,
prefix: jsonEntry.prefix,
suffix: jsonEntry.suffix)
}
return try HeaderMap.makeBinary(withEntries: hmapEntries)
}
}
public extension JSONHeaderMap {
public func makeHeaderMapEntries() -> [HeaderMap.Entry] {
return entries.map { (key, value) in
return HeaderMap.Entry(key: key, prefix: value.prefix, suffix: value.suffix)
}
}
}

View File

@ -0,0 +1,34 @@
// MIT License
//
// Copyright (c) 2017 Milen Dzhumerov
//
// 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:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// 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.
import Foundation
extension Array {
func dictionaryMap<Key: Hashable, Value>(_ mapper: (Element) throws -> (Key, Value)) rethrows -> Dictionary<Key, Value> {
var dict = Dictionary<Key, Value>()
for element in self {
let (key, value) = try mapper(element)
dict[key] = value
}
return dict
}
}

View File

@ -0,0 +1,34 @@
// MIT License
//
// Copyright (c) 2017 Milen Dzhumerov
//
// 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:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// 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.
import Foundation
extension Dictionary {
func dictionaryMap<NewKey: Hashable, NewValue>(_ mapper: ((Key, Value)) throws -> (NewKey, NewValue)) rethrows -> Dictionary<NewKey, NewValue> {
var dict = Dictionary<NewKey, NewValue>()
for keyValuePair in self {
let (newKey, newValue) = try mapper(keyValuePair)
dict[newKey] = newValue
}
return dict
}
}

View File

@ -0,0 +1,45 @@
// MIT License
//
// Copyright (c) 2017 Milen Dzhumerov
//
// 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:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// 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.
import Foundation
protocol ByteSwappable {
func byte(swapped: Bool) -> Self
}
extension UInt16: ByteSwappable {
func byte(swapped: Bool) -> UInt16 {
return swapped ? byteSwapped : self
}
}
extension UInt32: ByteSwappable {
func byte(swapped: Bool) -> UInt32 {
return swapped ? byteSwapped : self
}
}
extension UInt32 {
var isPowerOf2: Bool {
return (self != 0) && ((self & (self - 1)) == 0);
}
}

View File

@ -0,0 +1,62 @@
// MIT License
//
// Copyright (c) 2017 Milen Dzhumerov
//
// 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:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// 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.
import Foundation
extension String {
func clangLowercasedBytes() throws -> Data {
guard let charBytes = data(using: BinaryHeaderMap.StringEncoding) else {
throw HeaderMapError.unencodableString
}
let lowercasedBytes = charBytes.map { $0.asciiLowercased() }
return Data(bytes: lowercasedBytes)
}
func clangLowercased() throws -> String? {
return try String(data: clangLowercasedBytes(), encoding: BinaryHeaderMap.StringEncoding)
}
var headerMapHash: UInt32? {
guard
let characterBytes = try? clangLowercasedBytes()
else { return nil }
return characterBytes.withUnsafeBytes {
(charBlockPointer: UnsafePointer<UInt8>) -> UInt32 in
var result = UInt32(0)
for i in 0 ..< characterBytes.count {
let charPointer = charBlockPointer.advanced(by: i)
result += UInt32(charPointer.pointee) * 13
}
return result
}
}
}
fileprivate extension UInt8 {
func asciiLowercased() -> UInt8 {
let isUppercase = (65 <= self && self <= 90)
return self + (isUppercase ? 32 : 0)
}
}

View File

@ -0,0 +1,29 @@
// MIT License
//
// Copyright (c) 2017 Milen Dzhumerov
//
// 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:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// 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.
public protocol ToolCommand {
associatedtype InputType
associatedtype OutputType
static func perform(input: InputType) throws -> OutputType
}

View File

@ -0,0 +1,152 @@
// MIT License
//
// Copyright (c) 2017 Milen Dzhumerov
//
// 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:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// 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.
import Foundation
import HeaderMapCore
// MARK: - Command Definitions
public struct MemoryConvertCommand {
public struct Input {
public let data: Data
public let from: HeaderMapFileFormat
public let to: HeaderMapFileFormat
public init(data: Data,
from: HeaderMapFileFormat,
to: HeaderMapFileFormat) {
self.data = data
self.from = from
self.to = to
}
}
public struct Output {
public let data: Data
}
public enum Error: LocalizedError {
case sameFormat(format: HeaderMapFileFormat)
}
}
public struct FileConvertCommand {
public struct Input {
public struct TypedFile {
public let url: URL
public let format: HeaderMapFileFormat
public init(url: URL) throws {
self.url = url
self.format = try url.resolveHeaderMapFormat()
}
}
public let from: TypedFile
public let to: TypedFile
public init(from: TypedFile, to: TypedFile) {
self.from = from
self.to = to
}
}
public enum Error: LocalizedError {
case unknownFormat(url: URL)
}
}
// MARK: - Memory Convert
extension MemoryConvertCommand: ToolCommand {
public typealias InputType = Input
public typealias OutputType = Output
public static func perform(input: Input) throws -> Output {
switch (input.from, input.to) {
case (.hmap, .json):
let hmap = try HeaderMap(data: input.data)
let jsonHmap = hmap.makeJSONHeaderMap()
let jsonData = try jsonHmap.makeJSONData(prettyPrinted: true)
return Output(data: jsonData)
case (.json, .hmap):
let jsonHmap = try JSONHeaderMap(jsonData: input.data)
let hmapData = try HeaderMap.binaryDataFrom(jsonHeaderMap: jsonHmap)
return Output(data: hmapData)
case (.json, .json),
(.hmap, .hmap):
throw MemoryConvertCommand.Error.sameFormat(format: input.from)
}
}
}
// MARK: - File Convert
extension FileConvertCommand: ToolCommand {
public typealias InputType = Input
public typealias OutputType = Void
public static func perform(input: Input) throws -> Void {
let fromData = try Data(contentsOf: input.from.url)
let outputData = try MemoryConvertCommand.perform(
input: MemoryConvertCommand.Input(
data: fromData, from: input.from.format, to: input.to.format)
)
try outputData.data.write(to: input.to.url, options: [.atomic])
}
}
fileprivate extension URL {
func resolveHeaderMapFormat() throws -> HeaderMapFileFormat {
switch pathExtension {
case "json":
return .json
case "hmap":
return .hmap
default:
throw FileConvertCommand.Error.unknownFormat(url: self)
}
}
}
// MARK: - Error Descriptions
extension MemoryConvertCommand.Error {
public var errorDescription: String? {
switch self {
case .sameFormat(_):
return "Must specify different formats for conversion."
}
}
}
extension FileConvertCommand.Error {
public var errorDescription: String? {
switch self {
case .unknownFormat(let url):
return "The format of the file at path \(url.path) could not be determined."
}
}
}

View File

@ -0,0 +1,28 @@
// MIT License
//
// Copyright (c) 2017 Milen Dzhumerov
//
// 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:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// 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.
public enum HeaderMapFileFormat: String {
/** Binary format as defined by Clang */
case hmap
/** JSON format as defined by hmap */
case json
}

View File

@ -0,0 +1,36 @@
// MIT License
//
// Copyright (c) 2017 Milen Dzhumerov
//
// 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:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// 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.
import Foundation
enum PrintCommandError: LocalizedError {
case cannotOpenFile(path: String)
}
extension PrintCommandError {
public var errorDescription: String? {
switch self {
case .cannotOpenFile(let path):
return "Could not open file at path: \(path)."
}
}
}

View File

@ -0,0 +1,76 @@
// MIT License
//
// Copyright (c) 2017 Milen Dzhumerov
//
// 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:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// 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.
import Foundation
import HeaderMapCore
public struct PrintCommandOutput {
public let text: String
}
public struct FilePrintCommand: ToolCommand {
public typealias InputType = Input
public typealias OutputType = PrintCommandOutput
public struct Input {
public let headerMapFile: URL
public let argumentPath: String
public init(headerMapFile: URL, argumentPath: String) {
self.headerMapFile = headerMapFile
self.argumentPath = argumentPath
}
}
public static func perform(input: Input) throws -> PrintCommandOutput {
guard let headerMapData = try? Data(contentsOf: input.headerMapFile) else {
throw PrintCommandError.cannotOpenFile(path: input.argumentPath)
}
return try MemoryPrintCommand.perform(
input: MemoryPrintCommand.Input(headerMap: headerMapData)
)
}
}
public struct MemoryPrintCommand: ToolCommand {
public typealias InputType = Input
public typealias OutputType = PrintCommandOutput
public struct Input {
public let headerMap: Data
public init(headerMap: Data) {
self.headerMap = headerMap
}
}
public static func perform(input: Input) throws -> PrintCommandOutput {
let headerMap = try HeaderMap(data: input.headerMap)
let entries = headerMap.makeEntryList().sorted { return $0.key < $1.key }
let textLines = entries.flatMap { (entry) -> String? in
return "\(entry.key) -> \(entry.prefix)\(entry.suffix)"
}
let output = textLines.joined(separator: "\n")
return PrintCommandOutput(text: output)
}
}

View File

@ -0,0 +1,48 @@
// MIT License
//
// Copyright (c) 2017 Milen Dzhumerov
//
// 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:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// 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.
import Foundation
import XCTest
public enum OptionalError: Error {
case unwrappedNil
}
extension Optional {
public func unwrap(file: StaticString = #file, line: UInt = #line) throws -> Wrapped {
guard let unwrapped = self else {
XCTFail("Unwrapped nil: \(file):\(line)")
throw OptionalError.unwrappedNil
}
return unwrapped
}
}
public extension XCTestCase {
public func loadFile(named name: String, extension ext: String? = nil) throws -> Data? {
let url = Bundle(for: type(of: self)).url(forResource: name, withExtension: ext)
return try url.map { try Data(contentsOf: $0) }
}
}

54
Sources/hmap/Convert.swift Executable file
View File

@ -0,0 +1,54 @@
// MIT License
//
// Copyright (c) 2017 Milen Dzhumerov
//
// 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:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// 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.
import Commander
import Foundation
import HeaderMapFrontend
func addConvertCommand(to group: Group) {
let sourceFileArgument = Argument<String>(
"source_file",
description: "Path to the file to be converted"
)
let destFileArgument = Argument<String>(
"dest_file",
description: "Path to the converted file"
)
group.command("convert", sourceFileArgument, destFileArgument) {
(from, to) in
do {
let fromUrl = URL(fileURLWithPath: from)
let fromFile = try FileConvertCommand.Input.TypedFile(url: fromUrl)
let toUrl = URL(fileURLWithPath: to)
let toFile = try FileConvertCommand.Input.TypedFile(url: toUrl)
let input = FileConvertCommand.Input(from: fromFile, to: toFile)
try FileConvertCommand.perform(input: input)
} catch (let error) {
Swift.print(error.localizedDescription)
exit(ToolReturnCode.failure.rawValue)
}
}
}

45
Sources/hmap/Print.swift Executable file
View File

@ -0,0 +1,45 @@
// MIT License
//
// Copyright (c) 2017 Milen Dzhumerov
//
// 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:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// 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.
import Commander
import Foundation
import HeaderMapFrontend
func addPrintCommand(to group: Group) {
let fileArgument = Argument<String>(
"file",
description: "Path to header map file"
)
group.command("print", fileArgument) { (file) in
do {
let url = file.expandedFileURL
let output = try FilePrintCommand.perform(
input: FilePrintCommand.Input(headerMapFile: url, argumentPath: file)
)
Swift.print(output.text)
} catch (let error) {
Swift.print(error.localizedDescription)
exit(ToolReturnCode.failure.rawValue)
}
}
}

25
Sources/hmap/ReturnCodes.swift Executable file
View File

@ -0,0 +1,25 @@
// MIT License
//
// Copyright (c) 2017 Milen Dzhumerov
//
// 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:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// 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.
enum ToolReturnCode: Int32 {
case failure = 1
}

View File

@ -0,0 +1,29 @@
// MIT License
//
// Copyright (c) 2017 Milen Dzhumerov
//
// 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:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// 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.
import Foundation
extension String {
var expandedFileURL: URL {
return URL(fileURLWithPath: (self as NSString).expandingTildeInPath)
}
}

33
Sources/hmap/main.swift Executable file
View File

@ -0,0 +1,33 @@
// MIT License
//
// Copyright (c) 2017 Milen Dzhumerov
//
// 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:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// 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.
import Commander
import HeaderMapFrontend
public let version = "1.0.0"
let commandGroup = Group()
addPrintCommand(to: commandGroup)
addConvertCommand(to: commandGroup)
commandGroup.run(version)

View File

@ -0,0 +1,133 @@
// MIT License
//
// Copyright (c) 2017 Milen Dzhumerov
//
// 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:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// 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.
import XCTest
import HeaderMapCore
import HeaderMapTesting
class HeaderMapTests: XCTestCase {
func testHeaderMapASCIIKeyMatching() throws {
let entries = [
HeaderMap.Entry(
key: "Foo/Foo.h",
prefix: "/Users/Foo/Source",
suffix: "Foo.h"),
]
let hmap = try HeaderMap(entries: entries)
let fooEntryExactCase = hmap["Foo/Foo.h"]
XCTAssertNotNil(fooEntryExactCase)
XCTAssertEqual(fooEntryExactCase, entries.first)
let fooEntryLowercase = hmap["foo/foo.h"]
XCTAssertNotNil(fooEntryLowercase)
XCTAssertEqual(fooEntryLowercase, entries.first)
}
func testHeaderMapUnicodeKeyMatching() throws {
let lowercaseAUmlaut = "\u{00E4}"
let uppercaseAUmlaut = "\u{00C4}"
let entries = [
HeaderMap.Entry(
key: uppercaseAUmlaut,
prefix: "/Users/Foo/Source",
suffix: uppercaseAUmlaut),
]
let hmap = try HeaderMap(entries: entries)
let fooEntryExactCase = hmap[uppercaseAUmlaut]
XCTAssertNotNil(fooEntryExactCase)
XCTAssertEqual(fooEntryExactCase, entries.first)
// By definition, lowercasing is ASCII-only
let fooEntryLowercase = hmap[lowercaseAUmlaut]
XCTAssertNil(fooEntryLowercase)
}
func testHeaderMap8BitKeyMatching() throws {
let eAcute = "\u{E9}"
let combinedEAcute = "\u{65}\u{301}"
XCTAssertEqual(eAcute, combinedEAcute)
let entries = [
HeaderMap.Entry(key: eAcute, prefix: "", suffix: ""),
]
let hmap = try HeaderMap(entries: entries)
// By definition, key comparison is not Unicode-aware
XCTAssertNotNil(hmap[eAcute])
XCTAssertNil(hmap[combinedEAcute])
}
func testRealmHeaderMap() throws {
let hmapData = try loadFile(named: "Realm", extension: "hmap").unwrap()
let headerMap = try HeaderMap(data: hmapData)
let jsonData = try loadFile(named: "Realm", extension: "json").unwrap()
let jsonHeaderMap = try JSONHeaderMap(jsonData: jsonData)
let entries = Set<HeaderMap.Entry>(headerMap.makeEntryList())
let jsonEntries = Set<HeaderMap.Entry>(jsonHeaderMap.makeHeaderMapEntries())
XCTAssertEqual(entries, jsonEntries)
}
func testHeaderMapBinaryFormat() throws {
let entries = Set<HeaderMap.Entry>([
HeaderMap.Entry(key: "A", prefix: "B", suffix: "C"),
HeaderMap.Entry(key: "D", prefix: "E", suffix: "F"),
HeaderMap.Entry(key: "G", prefix: "H", suffix: "I"),
])
let hmapBinaryData = try HeaderMap.makeBinary(withEntries: Array(entries))
let hmap = try HeaderMap(data: hmapBinaryData)
let hmapEntries = Set<HeaderMap.Entry>(hmap.makeEntryList())
XCTAssertEqual(entries, hmapEntries)
}
func testHeaderMapJSONFormat() throws {
let entries = [
"A": JSONHeaderMap.Entry(prefix: "B", suffix: "C"),
"D": JSONHeaderMap.Entry(prefix: "E", suffix: "F"),
]
let jsonData = try JSONHeaderMap(entries: entries).makeJSONData()
let decodedEntries = try JSONHeaderMap(jsonData: jsonData).entries
XCTAssertEqual(entries, decodedEntries)
}
func testHeaderMapFormatConversions() throws {
let entries = [
"A": JSONHeaderMap.Entry(prefix: "B", suffix: "C"),
"D": JSONHeaderMap.Entry(prefix: "E", suffix: "F"),
]
let jsonHeaderMap = JSONHeaderMap(entries: entries)
let hmapEntries = jsonHeaderMap.makeHeaderMapEntries()
let hmap = try HeaderMap(entries: hmapEntries)
let decodedEntries = hmap.makeJSONHeaderMap().entries
XCTAssertEqual(entries, decodedEntries)
}
}

Binary file not shown.

View File

@ -0,0 +1,786 @@
{
"list_notifier.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/ObjectStore\/src\/impl\/",
"suffix" : "list_notifier.hpp"
},
"list.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/ObjectStore\/src\/",
"suffix" : "list.hpp"
},
"Realm\/NSError+RLMSync.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "NSError+RLMSync.h"
},
"RLMSyncCredentials.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMSyncCredentials.h"
},
"RLMCollection_Private.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMCollection_Private.hpp"
},
"Realm\/Realm.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "Realm.h"
},
"RLMCollection_Private.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMCollection_Private.h"
},
"thread_safe_reference.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/ObjectStore\/src\/",
"suffix" : "thread_safe_reference.hpp"
},
"RLMObservation.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMObservation.hpp"
},
"Realm\/RLMSyncPermissionOffer.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMSyncPermissionOffer.h"
},
"Realm\/RLMSchema.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMSchema.h"
},
"Realm\/RLMThreadSafeReference.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMThreadSafeReference.h"
},
"RLMSyncPermissionResults_Private.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMSyncPermissionResults_Private.hpp"
},
"RLMQueryUtil.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMQueryUtil.hpp"
},
"RLMListBase.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMListBase.h"
},
"RLMCollection.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMCollection.h"
},
"Realm\/RLMSyncPermissionResults.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMSyncPermissionResults.h"
},
"aligned_union.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/ObjectStore\/src\/util\/",
"suffix" : "aligned_union.hpp"
},
"Realm\/RLMSyncSession.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMSyncSession.h"
},
"binding_context.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/ObjectStore\/src\/",
"suffix" : "binding_context.hpp"
},
"RLMAccessor.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMAccessor.hpp"
},
"Realm\/RLMObjectBase_Dynamic.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMObjectBase_Dynamic.h"
},
"RLMAccessor.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMAccessor.h"
},
"RLMThreadSafeReference.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMThreadSafeReference.h"
},
"Realm\/RLMRealmConfiguration.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMRealmConfiguration.h"
},
"atomic_shared_ptr.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/ObjectStore\/src\/util\/",
"suffix" : "atomic_shared_ptr.hpp"
},
"RLMSyncManager.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMSyncManager.h"
},
"Realm\/RLMSyncConfiguration.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMSyncConfiguration.h"
},
"sync_session.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/ObjectStore\/src\/sync\/",
"suffix" : "sync_session.hpp"
},
"system_configuration.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/ObjectStore\/src\/sync\/impl\/apple\/",
"suffix" : "system_configuration.hpp"
},
"RLMAssertions.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/Tests\/",
"suffix" : "RLMAssertions.h"
},
"event_loop_signal.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/ObjectStore\/src\/util\/",
"suffix" : "event_loop_signal.hpp"
},
"RLMSyncSessionRefreshHandle.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMSyncSessionRefreshHandle.hpp"
},
"sync_file.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/ObjectStore\/src\/sync\/impl\/",
"suffix" : "sync_file.hpp"
},
"RLMProperty_Private.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMProperty_Private.hpp"
},
"RLMArray_Private.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMArray_Private.hpp"
},
"Realm\/RLMRealmConfiguration_Private.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMRealmConfiguration_Private.h"
},
"results.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/ObjectStore\/src\/",
"suffix" : "results.hpp"
},
"RLMObjectSchema.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMObjectSchema.h"
},
"RLMSyncPermissionValue_Private.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMSyncPermissionValue_Private.hpp"
},
"binding_callback_thread_observer.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/ObjectStore\/src\/",
"suffix" : "binding_callback_thread_observer.hpp"
},
"Realm\/RLMSyncPermissionOffer_Private.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMSyncPermissionOffer_Private.h"
},
"Realm\/RLMSyncCredentials.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMSyncCredentials.h"
},
"RLMTestUtils.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/ObjectServerTests\/",
"suffix" : "RLMTestUtils.h"
},
"Realm\/RLMProperty.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMProperty.h"
},
"RLMPredicateUtil.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMPredicateUtil.hpp"
},
"RLMTestCase.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/Tests\/",
"suffix" : "RLMTestCase.h"
},
"RLMRealmConfiguration_Private.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMRealmConfiguration_Private.hpp"
},
"Realm\/RLMSyncPermissionOfferResponse_Private.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMSyncPermissionOfferResponse_Private.h"
},
"RLMObjectStore.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMObjectStore.h"
},
"Realm\/RLMResults_Private.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMResults_Private.h"
},
"RLMObjectBase_Private.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMObjectBase_Private.h"
},
"weak_realm_notifier.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/ObjectStore\/src\/impl\/",
"suffix" : "weak_realm_notifier.hpp"
},
"RLMResults.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMResults.h"
},
"object_accessor.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/ObjectStore\/src\/",
"suffix" : "object_accessor.hpp"
},
"Realm\/RLMSyncUser.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMSyncUser.h"
},
"RLMSyncUser_Private.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMSyncUser_Private.hpp"
},
"RLMRealm_Private.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMRealm_Private.h"
},
"RLMObjectBase_Dynamic.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMObjectBase_Dynamic.h"
},
"RLMRealmConfiguration_Private.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMRealmConfiguration_Private.h"
},
"RLMNetworkClient.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMNetworkClient.h"
},
"RLMResults_Private.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMResults_Private.h"
},
"RLMSwiftBridgingHeader.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMSwiftBridgingHeader.h"
},
"Realm\/RLMObjectSchema_Private.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMObjectSchema_Private.h"
},
"sync_metadata.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/ObjectStore\/src\/sync\/impl\/",
"suffix" : "sync_metadata.hpp"
},
"Realm\/RLMArray.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMArray.h"
},
"Realm\/RLMProperty_Private.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMProperty_Private.h"
},
"Realm\/RLMSwiftSupport.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMSwiftSupport.h"
},
"results_notifier.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/ObjectStore\/src\/impl\/",
"suffix" : "results_notifier.hpp"
},
"RLMPrefix.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMPrefix.h"
},
"Realm\/RLMCollection.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMCollection.h"
},
"Realm\/RLMAccessor.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMAccessor.h"
},
"Swift-Tests-Bridging-Header.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/Tests\/Swift\/",
"suffix" : "Swift-Tests-Bridging-Header.h"
},
"RLMSyncPermission.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMSyncPermission.h"
},
"RLMSyncUtil_Private.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMSyncUtil_Private.hpp"
},
"RLMOptionalBase.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMOptionalBase.h"
},
"RLMObject_Private.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMObject_Private.hpp"
},
"RealmSwiftTests-BridgingHeader.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/RealmSwift\/Tests\/",
"suffix" : "RealmSwiftTests-BridgingHeader.h"
},
"schema.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/ObjectStore\/src\/",
"suffix" : "schema.hpp"
},
"RLMSyncUser+ObjectServerTests.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/ObjectServerTests\/",
"suffix" : "RLMSyncUser+ObjectServerTests.h"
},
"Realm\/RLMObject_Private.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMObject_Private.h"
},
"realm_coordinator.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/ObjectStore\/src\/impl\/",
"suffix" : "realm_coordinator.hpp"
},
"RLMSyncPermissionOfferResponse.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMSyncPermissionOfferResponse.h"
},
"RLMSyncSession.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMSyncSession.h"
},
"Realm\/RLMSyncConfiguration_Private.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMSyncConfiguration_Private.h"
},
"property.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/ObjectStore\/src\/",
"suffix" : "property.hpp"
},
"RLMSyncPermissionOfferResponse_Private.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMSyncPermissionOfferResponse_Private.h"
},
"RLMSchema_Private.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMSchema_Private.h"
},
"RLMArray.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMArray.h"
},
"RLMSyncPermissionValue.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMSyncPermissionValue.h"
},
"RLMSyncManager_Private.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMSyncManager_Private.h"
},
"object_accessor_impl.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/ObjectStore\/src\/impl\/",
"suffix" : "object_accessor_impl.hpp"
},
"network_reachability.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/ObjectStore\/src\/sync\/impl\/",
"suffix" : "network_reachability.hpp"
},
"object_store.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/ObjectStore\/src\/",
"suffix" : "object_store.hpp"
},
"NSError+RLMSync.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "NSError+RLMSync.h"
},
"TestUtils.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/Tests\/",
"suffix" : "TestUtils.h"
},
"Realm\/RLMSyncPermission.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMSyncPermission.h"
},
"RLMMigration.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMMigration.h"
},
"RLMRealm_Dynamic.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMRealm_Dynamic.h"
},
"RLMRealm_Private.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMRealm_Private.hpp"
},
"Realm\/RLMResults.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMResults.h"
},
"RLMSchema_Private.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMSchema_Private.hpp"
},
"keychain_helper.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/ObjectStore\/src\/impl\/apple\/",
"suffix" : "keychain_helper.hpp"
},
"RLMUtil.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMUtil.hpp"
},
"Realm\/RLMSyncPermissionChange.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMSyncPermissionChange.h"
},
"network_reachability_observer.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/ObjectStore\/src\/sync\/impl\/apple\/",
"suffix" : "network_reachability_observer.hpp"
},
"RLMSyncConfiguration_Private.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMSyncConfiguration_Private.hpp"
},
"RLMMigration_Private.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMMigration_Private.h"
},
"collection_notifier.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/ObjectStore\/src\/impl\/",
"suffix" : "collection_notifier.hpp"
},
"RLMSyncPermissionOffer.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMSyncPermissionOffer.h"
},
"Realm\/RLMSyncPermission_Private.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMSyncPermission_Private.h"
},
"Realm\/RLMObject.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMObject.h"
},
"Realm\/RLMMigration.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMMigration.h"
},
"RLMUpdateChecker.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMUpdateChecker.hpp"
},
"RLMSyncSession_Private.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMSyncSession_Private.hpp"
},
"object_notifier.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/ObjectStore\/src\/impl\/",
"suffix" : "object_notifier.hpp"
},
"feature_checks.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/ObjectStore\/src\/",
"suffix" : "feature_checks.hpp"
},
"RLMMultiProcessTestCase.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/Tests\/",
"suffix" : "RLMMultiProcessTestCase.h"
},
"RLMSyncPermissionResults.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMSyncPermissionResults.h"
},
"sync_config.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/ObjectStore\/src\/sync\/",
"suffix" : "sync_config.hpp"
},
"RLMSyncSessionRefreshHandle.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMSyncSessionRefreshHandle.h"
},
"RLMObject_Private.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMObject_Private.h"
},
"Realm\/RLMSyncManager.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMSyncManager.h"
},
"RLMObjectSchema_Private.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMObjectSchema_Private.h"
},
"Realm\/RLMSyncPermissionChange_Private.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMSyncPermissionChange_Private.h"
},
"execution_context_id.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/ObjectStore\/src\/",
"suffix" : "execution_context_id.hpp"
},
"format.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/ObjectStore\/src\/util\/",
"suffix" : "format.hpp"
},
"RLMSyncPermission_Private.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMSyncPermission_Private.h"
},
"tagged_bool.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/ObjectStore\/src\/util\/",
"suffix" : "tagged_bool.hpp"
},
"RLMSyncPermissionChange_Private.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMSyncPermissionChange_Private.h"
},
"RLMRealm.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMRealm.h"
},
"collection_notifications.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/ObjectStore\/src\/",
"suffix" : "collection_notifications.hpp"
},
"RLMSwiftSupport.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMSwiftSupport.h"
},
"RLMSyncPermissionChange.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMSyncPermissionChange.h"
},
"Realm\/RLMSyncUtil_Private.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMSyncUtil_Private.h"
},
"RLMSyncSessionRefreshHandle+ObjectServerTests.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/ObjectServerTests\/",
"suffix" : "RLMSyncSessionRefreshHandle+ObjectServerTests.h"
},
"RLMProperty.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMProperty.h"
},
"Realm\/RLMObjectBase.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMObjectBase.h"
},
"compiler.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/ObjectStore\/src\/util\/",
"suffix" : "compiler.hpp"
},
"Realm\/RLMConstants.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMConstants.h"
},
"Realm\/RLMListBase.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMListBase.h"
},
"descriptor_ordering.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/ObjectStore\/src\/",
"suffix" : "descriptor_ordering.hpp"
},
"RLMSchema.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMSchema.h"
},
"sync_permission.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/ObjectStore\/src\/sync\/",
"suffix" : "sync_permission.hpp"
},
"Realm.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "Realm.h"
},
"Realm\/RLMSchema_Private.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMSchema_Private.h"
},
"RLMRealmUtil.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMRealmUtil.hpp"
},
"RLMTestObjects.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/Tests\/",
"suffix" : "RLMTestObjects.h"
},
"index_set.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/ObjectStore\/src\/",
"suffix" : "index_set.hpp"
},
"RLMSyncConfiguration.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMSyncConfiguration.h"
},
"RLMProperty_Private.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMProperty_Private.h"
},
"RLMJSONModels.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMJSONModels.h"
},
"RLMObjectBase.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMObjectBase.h"
},
"RLMSyncManager+ObjectServerTests.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/ObjectServerTests\/",
"suffix" : "RLMSyncManager+ObjectServerTests.h"
},
"RLMSyncUser.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMSyncUser.h"
},
"Realm\/RLMObjectStore.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMObjectStore.h"
},
"Realm\/RLMRealmConfiguration+Sync.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMRealmConfiguration+Sync.h"
},
"RLMObject.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMObject.h"
},
"external_commit_helper.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/ObjectStore\/src\/impl\/",
"suffix" : "external_commit_helper.hpp"
},
"Realm\/RLMArray_Private.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMArray_Private.h"
},
"sync_manager.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/ObjectStore\/src\/sync\/",
"suffix" : "sync_manager.hpp"
},
"RLMArray_Private.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMArray_Private.h"
},
"object.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/ObjectStore\/src\/",
"suffix" : "object.hpp"
},
"Realm\/RLMRealm.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMRealm.h"
},
"RLMRealmConfiguration+Sync.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMRealmConfiguration+Sync.h"
},
"RLMSyncConfiguration_Private.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMSyncConfiguration_Private.h"
},
"RLMRealmConfiguration.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMRealmConfiguration.h"
},
"Realm\/RLMSyncPermissionValue.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMSyncPermissionValue.h"
},
"sync_client.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/ObjectStore\/src\/sync\/impl\/",
"suffix" : "sync_client.hpp"
},
"object_schema.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/ObjectStore\/src\/",
"suffix" : "object_schema.hpp"
},
"RLMObjectSchema_Private.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMObjectSchema_Private.hpp"
},
"Realm\/RLMRealm_Dynamic.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMRealm_Dynamic.h"
},
"RLMSyncTestCase.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/ObjectServerTests\/",
"suffix" : "RLMSyncTestCase.h"
},
"any.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/ObjectStore\/src\/util\/",
"suffix" : "any.hpp"
},
"Realm\/RLMObjectBase_Private.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMObjectBase_Private.h"
},
"Realm\/RLMSyncUtil.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMSyncUtil.h"
},
"Object-Server-Tests-Bridging-Header.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/ObjectServerTests\/",
"suffix" : "Object-Server-Tests-Bridging-Header.h"
},
"collection_change_builder.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/ObjectStore\/src\/impl\/",
"suffix" : "collection_change_builder.hpp"
},
"uuid.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/ObjectStore\/src\/util\/",
"suffix" : "uuid.hpp"
},
"Realm\/RLMOptionalBase.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMOptionalBase.h"
},
"RLMThreadSafeReference_Private.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMThreadSafeReference_Private.hpp"
},
"Realm\/RLMSyncPermissionOfferResponse.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMSyncPermissionOfferResponse.h"
},
"Realm\/RLMCollection_Private.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMCollection_Private.h"
},
"RLMSyncPermissionOffer_Private.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMSyncPermissionOffer_Private.h"
},
"transact_log_handler.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/ObjectStore\/src\/impl\/",
"suffix" : "transact_log_handler.hpp"
},
"Realm\/RLMObjectSchema.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMObjectSchema.h"
},
"shared_realm.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/ObjectStore\/src\/",
"suffix" : "shared_realm.hpp"
},
"RLMSyncUtil_Private.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMSyncUtil_Private.h"
},
"RLMSyncUtil.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMSyncUtil.h"
},
"Realm\/RLMMigration_Private.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMMigration_Private.h"
},
"RLMAnalytics.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMAnalytics.hpp"
},
"RLMConstants.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMConstants.h"
},
"sync_user.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/ObjectStore\/src\/sync\/",
"suffix" : "sync_user.hpp"
},
"RLMClassInfo.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMClassInfo.hpp"
},
"time.hpp" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/ObjectStore\/src\/util\/",
"suffix" : "time.hpp"
},
"Realm\/RLMRealm_Private.h" : {
"prefix" : "\/Users\/milen\/Downloads\/realm-cocoa\/Realm\/",
"suffix" : "RLMRealm_Private.h"
}
}

View File

@ -0,0 +1,54 @@
// MIT License
//
// Copyright (c) 2017 Milen Dzhumerov
//
// 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:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// 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.
import XCTest
import HeaderMapCore
import HeaderMapFrontend
import HeaderMapTesting
class CommandTests: XCTestCase {
func testReadCommand() throws {
let hmapData = try loadFile(named: "map", extension: "hmap").unwrap()
let input = MemoryPrintCommand.Input(headerMap: hmapData)
let output = try MemoryPrintCommand.perform(input: input)
let printoutData = try loadFile(named: "map", extension: "txt").unwrap()
let printoutText = try String(data: printoutData, encoding: .utf8).unwrap()
XCTAssertEqual(output.text, printoutText)
}
func testConvertCommand() throws {
let hmapData = try loadFile(named: "map", extension: "hmap").unwrap()
let input = MemoryConvertCommand.Input(
data: hmapData,
from: .hmap,
to: .json)
let output = try MemoryConvertCommand.perform(input: input)
let jsonFileData = try loadFile(named: "map", extension: "json").unwrap()
let jsonHeaderFromFile = try JSONHeaderMap(jsonData: jsonFileData)
let jsonHeaderFromCommand = try JSONHeaderMap(jsonData: output.data)
XCTAssertEqual(jsonHeaderFromFile.entries, jsonHeaderFromCommand.entries)
}
}

Binary file not shown.

View File

@ -0,0 +1,14 @@
{
"A": {
"prefix": "A1",
"suffix": "A2"
},
"B": {
"prefix": "B1",
"suffix": "B2"
},
"C": {
"prefix": "C1",
"suffix": "C2"
}
}

View File

@ -0,0 +1,3 @@
A -> A1A2
B -> B1B2
C -> C1C2

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>

1377
hmap.xcodeproj/project.pbxproj Executable file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,163 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "9999"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "OBJ_68"
BuildableName = "Spectre.framework"
BlueprintName = "Spectre"
ReferencedContainer = "container:hmap.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "OBJ_82"
BuildableName = "Commander.framework"
BlueprintName = "Commander"
ReferencedContainer = "container:hmap.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "OBJ_99"
BuildableName = "hmap"
BlueprintName = "hmap"
ReferencedContainer = "container:hmap.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "OBJ_117"
BuildableName = "HeaderMapCore.framework"
BlueprintName = "HeaderMapCore"
ReferencedContainer = "container:hmap.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "OBJ_139"
BuildableName = "HeaderMapTesting.framework"
BlueprintName = "HeaderMapTesting"
ReferencedContainer = "container:hmap.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "OBJ_119"
BuildableName = "HeaderMapFrontend.framework"
BlueprintName = "HeaderMapFrontend"
ReferencedContainer = "container:hmap.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "OBJ_166"
BuildableName = "HeaderMapCoreTests.xctest"
BlueprintName = "HeaderMapCoreTests"
ReferencedContainer = "container:hmap.xcodeproj">
</BuildableReference>
</TestableReference>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "OBJ_179"
BuildableName = "HeaderMapFrontendTests.xctest"
BlueprintName = "HeaderMapFrontendTests"
ReferencedContainer = "container:hmap.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "OBJ_68"
BuildableName = "Spectre.framework"
BlueprintName = "Spectre"
ReferencedContainer = "container:hmap.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<plist version="1.0">
<dict>
<key>SchemeUserState</key>
<dict>
<key>hmap.xcscheme</key>
<dict></dict>
</dict>
<key>SuppressBuildableAutocreation</key>
<dict></dict>
</dict>
</plist>