From bbb40b226ed6a4ded1d68be127901ccef74d5dc4 Mon Sep 17 00:00:00 2001 From: Milen Dzhumerov Date: Sun, 20 Aug 2017 20:41:06 +0100 Subject: [PATCH] v1.0 Release --- .gitignore | 18 + CHANGELOG.md | 3 + LICENSE.md | 21 + Package.pins | 18 + Package.swift | 47 + README.md | 57 + Sources/HeaderMapCore/BinaryHeaderMap.swift | 310 ++++ Sources/HeaderMapCore/ByteBuffer.swift | 86 + Sources/HeaderMapCore/HeaderMap.swift | 118 ++ Sources/HeaderMapCore/HeaderMapError.swift | 95 ++ Sources/HeaderMapCore/HeaderMapMaker.swift | 216 +++ Sources/HeaderMapCore/JSONHeaderMap.swift | 184 +++ .../extensions/ArrayExtensions.swift | 34 + .../extensions/DictionaryExtensions.swift | 34 + .../extensions/NumberExtensions.swift | 45 + .../extensions/StringExtensions.swift | 62 + Sources/HeaderMapFrontend/Command.swift | 29 + .../HeaderMapFrontend/ConvertCommands.swift | 152 ++ Sources/HeaderMapFrontend/FileFormat.swift | 28 + .../HeaderMapFrontend/FrontendErrors.swift | 36 + Sources/HeaderMapFrontend/PrintCommands.swift | 76 + .../HeaderMapTesting/TestingExtensions.swift | 48 + Sources/hmap/Convert.swift | 54 + Sources/hmap/Print.swift | 45 + Sources/hmap/ReturnCodes.swift | 25 + Sources/hmap/StringExtensions.swift | 29 + Sources/hmap/main.swift | 33 + Tests/HeaderMapCoreTests/HeaderMapTests.swift | 133 ++ Tests/HeaderMapCoreTests/TestFiles/Realm.hmap | Bin 0 -> 11345 bytes Tests/HeaderMapCoreTests/TestFiles/Realm.json | 786 ++++++++++ .../HeaderMapFrontendTests/CommandTests.swift | 54 + .../HeaderMapFrontendTests/TestFiles/map.hmap | Bin 0 -> 97 bytes .../HeaderMapFrontendTests/TestFiles/map.json | 14 + .../HeaderMapFrontendTests/TestFiles/map.txt | 3 + hmap.xcodeproj/Commander_Info.plist | 25 + hmap.xcodeproj/HeaderMapCoreTests_Info.plist | 25 + hmap.xcodeproj/HeaderMapCore_Info.plist | 25 + .../HeaderMapFrontendTests_Info.plist | 25 + hmap.xcodeproj/HeaderMapFrontend_Info.plist | 25 + hmap.xcodeproj/HeaderMapTesting_Info.plist | 25 + hmap.xcodeproj/Spectre_Info.plist | 25 + hmap.xcodeproj/project.pbxproj | 1377 +++++++++++++++++ .../xcshareddata/xcschemes/hmap.xcscheme | 163 ++ .../xcschemes/xcschememanagement.plist | 12 + 44 files changed, 4620 insertions(+) create mode 100755 .gitignore create mode 100755 CHANGELOG.md create mode 100755 LICENSE.md create mode 100755 Package.pins create mode 100755 Package.swift create mode 100755 README.md create mode 100755 Sources/HeaderMapCore/BinaryHeaderMap.swift create mode 100755 Sources/HeaderMapCore/ByteBuffer.swift create mode 100755 Sources/HeaderMapCore/HeaderMap.swift create mode 100755 Sources/HeaderMapCore/HeaderMapError.swift create mode 100755 Sources/HeaderMapCore/HeaderMapMaker.swift create mode 100755 Sources/HeaderMapCore/JSONHeaderMap.swift create mode 100755 Sources/HeaderMapCore/extensions/ArrayExtensions.swift create mode 100755 Sources/HeaderMapCore/extensions/DictionaryExtensions.swift create mode 100755 Sources/HeaderMapCore/extensions/NumberExtensions.swift create mode 100755 Sources/HeaderMapCore/extensions/StringExtensions.swift create mode 100755 Sources/HeaderMapFrontend/Command.swift create mode 100755 Sources/HeaderMapFrontend/ConvertCommands.swift create mode 100755 Sources/HeaderMapFrontend/FileFormat.swift create mode 100755 Sources/HeaderMapFrontend/FrontendErrors.swift create mode 100755 Sources/HeaderMapFrontend/PrintCommands.swift create mode 100755 Sources/HeaderMapTesting/TestingExtensions.swift create mode 100755 Sources/hmap/Convert.swift create mode 100755 Sources/hmap/Print.swift create mode 100755 Sources/hmap/ReturnCodes.swift create mode 100755 Sources/hmap/StringExtensions.swift create mode 100755 Sources/hmap/main.swift create mode 100755 Tests/HeaderMapCoreTests/HeaderMapTests.swift create mode 100755 Tests/HeaderMapCoreTests/TestFiles/Realm.hmap create mode 100755 Tests/HeaderMapCoreTests/TestFiles/Realm.json create mode 100755 Tests/HeaderMapFrontendTests/CommandTests.swift create mode 100755 Tests/HeaderMapFrontendTests/TestFiles/map.hmap create mode 100755 Tests/HeaderMapFrontendTests/TestFiles/map.json create mode 100755 Tests/HeaderMapFrontendTests/TestFiles/map.txt create mode 100755 hmap.xcodeproj/Commander_Info.plist create mode 100755 hmap.xcodeproj/HeaderMapCoreTests_Info.plist create mode 100755 hmap.xcodeproj/HeaderMapCore_Info.plist create mode 100755 hmap.xcodeproj/HeaderMapFrontendTests_Info.plist create mode 100755 hmap.xcodeproj/HeaderMapFrontend_Info.plist create mode 100755 hmap.xcodeproj/HeaderMapTesting_Info.plist create mode 100755 hmap.xcodeproj/Spectre_Info.plist create mode 100755 hmap.xcodeproj/project.pbxproj create mode 100755 hmap.xcodeproj/xcshareddata/xcschemes/hmap.xcscheme create mode 100755 hmap.xcodeproj/xcshareddata/xcschemes/xcschememanagement.plist diff --git a/.gitignore b/.gitignore new file mode 100755 index 0000000..cc341f2 --- /dev/null +++ b/.gitignore @@ -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 \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100755 index 0000000..8403470 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,3 @@ +## [1.0](https://github.com/milend/hmap/releases/tag/1.0) (2017-08-20) + +- Public release \ No newline at end of file diff --git a/LICENSE.md b/LICENSE.md new file mode 100755 index 0000000..dfdd901 --- /dev/null +++ b/LICENSE.md @@ -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. \ No newline at end of file diff --git a/Package.pins b/Package.pins new file mode 100755 index 0000000..bb13ea2 --- /dev/null +++ b/Package.pins @@ -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 +} \ No newline at end of file diff --git a/Package.swift b/Package.swift new file mode 100755 index 0000000..fc48417 --- /dev/null +++ b/Package.swift @@ -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] +) diff --git a/README.md b/README.md new file mode 100755 index 0000000..b9dc412 --- /dev/null +++ b/README.md @@ -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 diff --git a/Sources/HeaderMapCore/BinaryHeaderMap.swift b/Sources/HeaderMapCore/BinaryHeaderMap.swift new file mode 100755 index 0000000..905fbe4 --- /dev/null +++ b/Sources/HeaderMapCore/BinaryHeaderMap.swift @@ -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.size + + MemoryLayout.size + + MemoryLayout.size + + MemoryLayout.size + + MemoryLayout.size + + MemoryLayout.size + + MemoryLayout.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.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 { + case keepProbing + case stop(value: T?) +} + +func probeHashTable( + bucketCount: BinaryHeaderMap.DataHeader.BucketCountType, + start: UInt32, + _ body: (UInt32) -> ProbeAction) -> 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) -> Int? in + + for i in begin..( + at offset: Int, + count: Int, + _ body: (UnsafePointer) 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, 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) 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) + } +} + diff --git a/Sources/HeaderMapCore/ByteBuffer.swift b/Sources/HeaderMapCore/ByteBuffer.swift new file mode 100755 index 0000000..bd31732 --- /dev/null +++ b/Sources/HeaderMapCore/ByteBuffer.swift @@ -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 + private var offset: Int + + private(set) var byteSwap: Bool + + init(bytes: UnsafePointer, byteSwap: Bool) { + self.bytes = bytes + self.offset = 0 + self.byteSwap = byteSwap + } + + func advance() -> T { + return advance { + // Needs temporary `result` due to Swift's type inference + let result: T = castBytes() + return result.byte(swapped: byteSwap) + } + } + + func advanceByteSwappable(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 { + return bytes.advanced(by: offset).withMemoryRebound(to: T.self, capacity: 1) { + return $0.pointee + } + } + + private func advance(_ body: () -> T) -> T { + let value = body() + offset += MemoryLayout.size + return value + } +} + +class ByteBufferEncoder { + private(set) var bytes = Data() + + func encode(_ value: T) { + var mutableValue = value + withUnsafeBytes(of: &mutableValue) { (pointer) in + let valueBytes = Array(pointer[0.. [HeaderMap.Entry] { + return (0.. 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 + } +} + diff --git a/Sources/HeaderMapCore/HeaderMapError.swift b/Sources/HeaderMapCore/HeaderMapError.swift new file mode 100755 index 0000000..abfc1fa --- /dev/null +++ b/Sources/HeaderMapCore/HeaderMapError.swift @@ -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" + } + } +} diff --git a/Sources/HeaderMapCore/HeaderMapMaker.swift b/Sources/HeaderMapCore/HeaderMapMaker.swift new file mode 100755 index 0000000..3c594e4 --- /dev/null +++ b/Sources/HeaderMapCore/HeaderMapMaker.swift @@ -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) throws -> StringSection { + + var buffer = Data() + buffer.append(UInt8(BinaryHeaderMap.StringSectionOffset.Reserved)) + var offsets = Dictionary() + + 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, + 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(bytePointer: UnsafeMutablePointer, value: T) { + var mutableValue = value + withUnsafeBytes(of: &mutableValue) { (pointer) in + let valueBytes = Array(pointer[0.. BucketSection { + + assert(entries.count > 0) + + let bucketCount = numberOfBuckets(forEntryCount: entries.count) + var bytes = Data(count: bucketCount * BinaryHeaderMap.Bucket.packedSize) + try bytes.withUnsafeMutableBytes { + (bytePointer: UnsafeMutablePointer) 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.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() + 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) + } +} diff --git a/Sources/HeaderMapCore/JSONHeaderMap.swift b/Sources/HeaderMapCore/JSONHeaderMap.swift new file mode 100755 index 0000000..6f390cd --- /dev/null +++ b/Sources/HeaderMapCore/JSONHeaderMap.swift @@ -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) + } + } +} diff --git a/Sources/HeaderMapCore/extensions/ArrayExtensions.swift b/Sources/HeaderMapCore/extensions/ArrayExtensions.swift new file mode 100755 index 0000000..68fa9df --- /dev/null +++ b/Sources/HeaderMapCore/extensions/ArrayExtensions.swift @@ -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(_ mapper: (Element) throws -> (Key, Value)) rethrows -> Dictionary { + var dict = Dictionary() + for element in self { + let (key, value) = try mapper(element) + dict[key] = value + } + return dict + } +} diff --git a/Sources/HeaderMapCore/extensions/DictionaryExtensions.swift b/Sources/HeaderMapCore/extensions/DictionaryExtensions.swift new file mode 100755 index 0000000..3084192 --- /dev/null +++ b/Sources/HeaderMapCore/extensions/DictionaryExtensions.swift @@ -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(_ mapper: ((Key, Value)) throws -> (NewKey, NewValue)) rethrows -> Dictionary { + var dict = Dictionary() + for keyValuePair in self { + let (newKey, newValue) = try mapper(keyValuePair) + dict[newKey] = newValue + } + return dict + } +} diff --git a/Sources/HeaderMapCore/extensions/NumberExtensions.swift b/Sources/HeaderMapCore/extensions/NumberExtensions.swift new file mode 100755 index 0000000..c6ad6c4 --- /dev/null +++ b/Sources/HeaderMapCore/extensions/NumberExtensions.swift @@ -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); + } +} diff --git a/Sources/HeaderMapCore/extensions/StringExtensions.swift b/Sources/HeaderMapCore/extensions/StringExtensions.swift new file mode 100755 index 0000000..9c79394 --- /dev/null +++ b/Sources/HeaderMapCore/extensions/StringExtensions.swift @@ -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) -> 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) + } +} diff --git a/Sources/HeaderMapFrontend/Command.swift b/Sources/HeaderMapFrontend/Command.swift new file mode 100755 index 0000000..fa2b302 --- /dev/null +++ b/Sources/HeaderMapFrontend/Command.swift @@ -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 +} + diff --git a/Sources/HeaderMapFrontend/ConvertCommands.swift b/Sources/HeaderMapFrontend/ConvertCommands.swift new file mode 100755 index 0000000..8087e02 --- /dev/null +++ b/Sources/HeaderMapFrontend/ConvertCommands.swift @@ -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." + } + } +} diff --git a/Sources/HeaderMapFrontend/FileFormat.swift b/Sources/HeaderMapFrontend/FileFormat.swift new file mode 100755 index 0000000..26c33a9 --- /dev/null +++ b/Sources/HeaderMapFrontend/FileFormat.swift @@ -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 +} diff --git a/Sources/HeaderMapFrontend/FrontendErrors.swift b/Sources/HeaderMapFrontend/FrontendErrors.swift new file mode 100755 index 0000000..d7e5b90 --- /dev/null +++ b/Sources/HeaderMapFrontend/FrontendErrors.swift @@ -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)." + } + } +} diff --git a/Sources/HeaderMapFrontend/PrintCommands.swift b/Sources/HeaderMapFrontend/PrintCommands.swift new file mode 100755 index 0000000..5cad277 --- /dev/null +++ b/Sources/HeaderMapFrontend/PrintCommands.swift @@ -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) + } +} diff --git a/Sources/HeaderMapTesting/TestingExtensions.swift b/Sources/HeaderMapTesting/TestingExtensions.swift new file mode 100755 index 0000000..1b1f11b --- /dev/null +++ b/Sources/HeaderMapTesting/TestingExtensions.swift @@ -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) } + } +} + + diff --git a/Sources/hmap/Convert.swift b/Sources/hmap/Convert.swift new file mode 100755 index 0000000..6015ed9 --- /dev/null +++ b/Sources/hmap/Convert.swift @@ -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( + "source_file", + description: "Path to the file to be converted" + ) + let destFileArgument = Argument( + "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) + } + } +} diff --git a/Sources/hmap/Print.swift b/Sources/hmap/Print.swift new file mode 100755 index 0000000..e8859ea --- /dev/null +++ b/Sources/hmap/Print.swift @@ -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( + "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) + } + } +} diff --git a/Sources/hmap/ReturnCodes.swift b/Sources/hmap/ReturnCodes.swift new file mode 100755 index 0000000..72aae24 --- /dev/null +++ b/Sources/hmap/ReturnCodes.swift @@ -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 +} diff --git a/Sources/hmap/StringExtensions.swift b/Sources/hmap/StringExtensions.swift new file mode 100755 index 0000000..1268e3f --- /dev/null +++ b/Sources/hmap/StringExtensions.swift @@ -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) + } +} diff --git a/Sources/hmap/main.swift b/Sources/hmap/main.swift new file mode 100755 index 0000000..7145899 --- /dev/null +++ b/Sources/hmap/main.swift @@ -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) + diff --git a/Tests/HeaderMapCoreTests/HeaderMapTests.swift b/Tests/HeaderMapCoreTests/HeaderMapTests.swift new file mode 100755 index 0000000..57b43d3 --- /dev/null +++ b/Tests/HeaderMapCoreTests/HeaderMapTests.swift @@ -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.makeEntryList()) + let jsonEntries = Set(jsonHeaderMap.makeHeaderMapEntries()) + XCTAssertEqual(entries, jsonEntries) + } + + func testHeaderMapBinaryFormat() throws { + let entries = Set([ + 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(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) + } +} + diff --git a/Tests/HeaderMapCoreTests/TestFiles/Realm.hmap b/Tests/HeaderMapCoreTests/TestFiles/Realm.hmap new file mode 100755 index 0000000000000000000000000000000000000000..4ad7d4060c808a0996ed5e1c0d2910f5d76c190a GIT binary patch literal 11345 zcmd5=Z-^aN6`#b~*lMk*`H-pzS}jUk9~HzuC^p?HX}X)F*{lkF7-r|qdpq5EGp{rA zve^$JSVaO2f+!*pZ9oN)stBbDqP8ghS5QI_6f6~DQwx3&{{>pl@7~|coSA*|nBDBE z2j2c>&OPVcGv}Op@3}knMyq=q$2oY=aegT1>~);`1->A^TZ#K$V4vS0*ha7c`S~`1 zj{JQxKkNW^gFbkZ<6L}+;{bPx`Y(5!SI7_8M$a>b2d}G3{OpDHdx4ML>^MXD0WZAN zagNFl*oAHv9moTt>#a@T6pMmN(3U>p7UMb>BFkLVBZ zbGJCoJLL!LLI-cKb__~UqLywIypu5jUb)fof!}4Ef!~z6Ky3hTWKMy*K?nG~z^&3R z`7OZRpzko|Ku!Oa+C@Bp|0_C6AAm=gM_?O${$-A{EI**856C*fS_5i2MEl2Pd}Ac_ zfj9s)J;=3lUhrZ125h4*(GIW+eR-dq_ZNasvbKS3*cIq8=dD|-<~m7 zn{F5WImQb3826K(%-B!5*xV_ZJGplOU&(#x4na*vUTotG>_XpSO#)A`27qmJn(GnR zg}%9?%y zzX)pjIQbVE{Hqch#0RM95`6%+(Iv+DAA*{G!(0IW$Xo*tQ{HXJYhC@EvfhB6?8V3_ zu#L`hUf@<~nYj)HHNBO4Z@;9g{ScmkR|WBmd-3ZTE8L6G z4}lNd4SGt}-*pFMFA;o}zTy7+71>9y9|9lX8U%id&%nP)-J@p!evLlQy8nKH@<2^b z$P2y^_;%(O*o7{0kHY=;Jl7ZS8}t*X>D9Ck+%MmTa}%iP=kktk2X>(~`hffIqqGl1 z--GW0qVK^o@YCE|fL-V+dlH}~^gXaStN%gYW9Ah^--G97|8tAP0KGbJtMpOE9QbR_ zh5Il19?aG3f0l&@zAr!YJ$MFQmbsA&Ao?EgoBa>^9`Kv}kFd5)=zCzZ+5fzW{s1+h z?}2>R{zvQX_A~k(_y&BAc>$vD0l(S*?6yDJ{yF-9`|lm}6ZhYbah(D+U6dF2{EYn2 z1K}Bnz6Z}hO=p=eU>p64GQc*v$h8SX--EfD{ZE^27ygI2266x0GMx;(Xw*Bl^xia0 z(nBW~7MC_+|IMpTZ#fIntTzgyAnx6rtjAH}^|M|I@i{;76R&4goz1#-!2A_UHSEa@ zhkZZDvLwY={mu9SUYdFv94;PfWA2GGJniLylF_U}c0P%sz|X@Zwu1Hd%~ION!eS+@ z`IT0js~oJoZj#Y%EG(9?nqBA|U%6jC+`3jh z*GIM9!lISZyt;Jt9age<-z??cy%Bq(5LG0(tfV!6idHS9N=xzUT1)Fwikv=af;vtqBoI>(Mnv8=qXJPBNriAuqVX=_Z+(M&V zTnmfkV{J?aoidtLmsO!IWEHC>JD`XwGgeXo=~Tjt>SpK9&3BzzjWY zzUhF`*8(%_NR5w^xHzinp)hu|KnFW|+NpjO_O#%1yIg)%jaLy;L(_HN??scT=`9De z-jehswE|QOEr;Hya;JE!N#tRqB>2{p(BE!@v@DXETWFkGO#`pLK?XVgX>`m$=tKxb9WWtsDlmu2_FgQSp})&yD6qf5t+Ehhb-*awaU`FfJB z%}1eZ5BA&bk=dMs2dUXDH;+kZrL!|xu=AXdy(RRe*+Xm!w}d$e&)8WupO04YzDba7 zXeD!&G-up=>P(f;cA8Ctoz865cco!}7{mlo-%V zwi@A&@OxQ#M%DOm_o*}5c-qfwZgr)>9Rho^m^c}+1S+;GFj2c zytK&1>b8ReLp{fs8x@Td5(xVehq7ZTcv*3R6^w~Fs^o1g*pRG+v5w%j-7-1z#^WgH zIbIYFV=19YTx{CgHY+PeO2LceiXqX4Y}08SpF$tUxL$e)<{;8v73n( zp3U|kNk^VtM7cK{if=1PVu$i@BwL#ppG>$QV|#2NixQueFbeaH9okMz@^q-OjVupF zEDYYAj5pJq*nz^aOUo3C&tti$i-E+@%wTIP$UWJ1 A1A2 +B -> B1B2 +C -> C1C2 \ No newline at end of file diff --git a/hmap.xcodeproj/Commander_Info.plist b/hmap.xcodeproj/Commander_Info.plist new file mode 100755 index 0000000..57ada9f --- /dev/null +++ b/hmap.xcodeproj/Commander_Info.plist @@ -0,0 +1,25 @@ + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSPrincipalClass + + + diff --git a/hmap.xcodeproj/HeaderMapCoreTests_Info.plist b/hmap.xcodeproj/HeaderMapCoreTests_Info.plist new file mode 100755 index 0000000..7c23420 --- /dev/null +++ b/hmap.xcodeproj/HeaderMapCoreTests_Info.plist @@ -0,0 +1,25 @@ + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSPrincipalClass + + + diff --git a/hmap.xcodeproj/HeaderMapCore_Info.plist b/hmap.xcodeproj/HeaderMapCore_Info.plist new file mode 100755 index 0000000..57ada9f --- /dev/null +++ b/hmap.xcodeproj/HeaderMapCore_Info.plist @@ -0,0 +1,25 @@ + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSPrincipalClass + + + diff --git a/hmap.xcodeproj/HeaderMapFrontendTests_Info.plist b/hmap.xcodeproj/HeaderMapFrontendTests_Info.plist new file mode 100755 index 0000000..7c23420 --- /dev/null +++ b/hmap.xcodeproj/HeaderMapFrontendTests_Info.plist @@ -0,0 +1,25 @@ + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSPrincipalClass + + + diff --git a/hmap.xcodeproj/HeaderMapFrontend_Info.plist b/hmap.xcodeproj/HeaderMapFrontend_Info.plist new file mode 100755 index 0000000..57ada9f --- /dev/null +++ b/hmap.xcodeproj/HeaderMapFrontend_Info.plist @@ -0,0 +1,25 @@ + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSPrincipalClass + + + diff --git a/hmap.xcodeproj/HeaderMapTesting_Info.plist b/hmap.xcodeproj/HeaderMapTesting_Info.plist new file mode 100755 index 0000000..57ada9f --- /dev/null +++ b/hmap.xcodeproj/HeaderMapTesting_Info.plist @@ -0,0 +1,25 @@ + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSPrincipalClass + + + diff --git a/hmap.xcodeproj/Spectre_Info.plist b/hmap.xcodeproj/Spectre_Info.plist new file mode 100755 index 0000000..57ada9f --- /dev/null +++ b/hmap.xcodeproj/Spectre_Info.plist @@ -0,0 +1,25 @@ + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSPrincipalClass + + + diff --git a/hmap.xcodeproj/project.pbxproj b/hmap.xcodeproj/project.pbxproj new file mode 100755 index 0000000..9053294 --- /dev/null +++ b/hmap.xcodeproj/project.pbxproj @@ -0,0 +1,1377 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + F3DE1C901F4A0FBD00A29229 /* Realm.hmap in Resources */ = {isa = PBXBuildFile; fileRef = F3DE1C8D1F4A0FAF00A29229 /* Realm.hmap */; }; + F3DE1C911F4A0FBD00A29229 /* Realm.json in Resources */ = {isa = PBXBuildFile; fileRef = F3DE1C8E1F4A0FAF00A29229 /* Realm.json */; }; + F3DE1C961F4A0FC600A29229 /* map.hmap in Resources */ = {isa = PBXBuildFile; fileRef = F3DE1C931F4A0FC600A29229 /* map.hmap */; }; + F3DE1C971F4A0FC600A29229 /* map.json in Resources */ = {isa = PBXBuildFile; fileRef = F3DE1C941F4A0FC600A29229 /* map.json */; }; + F3DE1C981F4A0FC600A29229 /* map.txt in Resources */ = {isa = PBXBuildFile; fileRef = F3DE1C951F4A0FC600A29229 /* map.txt */; }; + F3DE1C9A1F4A0FCF00A29229 /* map.hmap in Resources */ = {isa = PBXBuildFile; fileRef = F3DE1C931F4A0FC600A29229 /* map.hmap */; }; + F3DE1C9B1F4A0FCF00A29229 /* map.json in Resources */ = {isa = PBXBuildFile; fileRef = F3DE1C941F4A0FC600A29229 /* map.json */; }; + F3DE1C9C1F4A103800A29229 /* map.txt in Resources */ = {isa = PBXBuildFile; fileRef = F3DE1C951F4A0FC600A29229 /* map.txt */; }; + OBJ_104 /* Convert.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_9 /* Convert.swift */; }; + OBJ_105 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_10 /* main.swift */; }; + OBJ_106 /* Print.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_11 /* Print.swift */; }; + OBJ_107 /* ReturnCodes.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_12 /* ReturnCodes.swift */; }; + OBJ_108 /* StringExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_13 /* StringExtensions.swift */; }; + OBJ_110 /* Spectre.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = OBJ_60 /* Spectre.framework */; }; + OBJ_111 /* Commander.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = OBJ_61 /* Commander.framework */; }; + OBJ_112 /* HeaderMapCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = OBJ_63 /* HeaderMapCore.framework */; }; + OBJ_113 /* HeaderMapFrontend.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = OBJ_65 /* HeaderMapFrontend.framework */; }; + OBJ_124 /* BinaryHeaderMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_15 /* BinaryHeaderMap.swift */; }; + OBJ_125 /* ByteBuffer.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_16 /* ByteBuffer.swift */; }; + OBJ_126 /* HeaderMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_17 /* HeaderMap.swift */; }; + OBJ_127 /* HeaderMapError.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_18 /* HeaderMapError.swift */; }; + OBJ_128 /* HeaderMapMaker.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_19 /* HeaderMapMaker.swift */; }; + OBJ_129 /* JSONHeaderMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_20 /* JSONHeaderMap.swift */; }; + OBJ_130 /* ArrayExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_22 /* ArrayExtensions.swift */; }; + OBJ_131 /* DictionaryExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_23 /* DictionaryExtensions.swift */; }; + OBJ_132 /* NumberExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_24 /* NumberExtensions.swift */; }; + OBJ_133 /* StringExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_25 /* StringExtensions.swift */; }; + OBJ_135 /* Spectre.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = OBJ_60 /* Spectre.framework */; }; + OBJ_136 /* Commander.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = OBJ_61 /* Commander.framework */; }; + OBJ_144 /* TestingExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_27 /* TestingExtensions.swift */; }; + OBJ_146 /* Spectre.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = OBJ_60 /* Spectre.framework */; }; + OBJ_147 /* Commander.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = OBJ_61 /* Commander.framework */; }; + OBJ_154 /* Command.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_29 /* Command.swift */; }; + OBJ_155 /* ConvertCommands.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_30 /* ConvertCommands.swift */; }; + OBJ_156 /* FileFormat.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_31 /* FileFormat.swift */; }; + OBJ_157 /* FrontendErrors.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_32 /* FrontendErrors.swift */; }; + OBJ_158 /* PrintCommands.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_33 /* PrintCommands.swift */; }; + OBJ_160 /* Spectre.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = OBJ_60 /* Spectre.framework */; }; + OBJ_161 /* Commander.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = OBJ_61 /* Commander.framework */; }; + OBJ_162 /* HeaderMapCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = OBJ_63 /* HeaderMapCore.framework */; }; + OBJ_171 /* HeaderMapTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_36 /* HeaderMapTests.swift */; }; + OBJ_173 /* Spectre.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = OBJ_60 /* Spectre.framework */; }; + OBJ_174 /* Commander.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = OBJ_61 /* Commander.framework */; }; + OBJ_175 /* HeaderMapTesting.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = OBJ_64 /* HeaderMapTesting.framework */; }; + OBJ_184 /* CommandTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_38 /* CommandTests.swift */; }; + OBJ_186 /* Spectre.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = OBJ_60 /* Spectre.framework */; }; + OBJ_187 /* Commander.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = OBJ_61 /* Commander.framework */; }; + OBJ_188 /* HeaderMapTesting.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = OBJ_64 /* HeaderMapTesting.framework */; }; + OBJ_73 /* Case.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_51 /* Case.swift */; }; + OBJ_74 /* Context.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_52 /* Context.swift */; }; + OBJ_75 /* Expectation.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_53 /* Expectation.swift */; }; + OBJ_76 /* Failure.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_54 /* Failure.swift */; }; + OBJ_77 /* Global.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_55 /* Global.swift */; }; + OBJ_78 /* GlobalContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_56 /* GlobalContext.swift */; }; + OBJ_79 /* Reporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_57 /* Reporter.swift */; }; + OBJ_80 /* Reporters.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_58 /* Reporters.swift */; }; + OBJ_87 /* ArgumentConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_41 /* ArgumentConvertible.swift */; }; + OBJ_88 /* ArgumentDescription.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_42 /* ArgumentDescription.swift */; }; + OBJ_89 /* ArgumentParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_43 /* ArgumentParser.swift */; }; + OBJ_90 /* Command.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_44 /* Command.swift */; }; + OBJ_91 /* CommandRunner.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_45 /* CommandRunner.swift */; }; + OBJ_92 /* Commands.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_46 /* Commands.swift */; }; + OBJ_93 /* CommandType.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_47 /* CommandType.swift */; }; + OBJ_94 /* Error.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_48 /* Error.swift */; }; + OBJ_95 /* Group.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_49 /* Group.swift */; }; + OBJ_97 /* Spectre.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = OBJ_60 /* Spectre.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + F3DE1C7A1F4A0F9600A29229 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = OBJ_1 /* Project object */; + proxyType = 1; + remoteGlobalIDString = OBJ_68; + remoteInfo = Spectre; + }; + F3DE1C7B1F4A0F9600A29229 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = OBJ_1 /* Project object */; + proxyType = 1; + remoteGlobalIDString = OBJ_68; + remoteInfo = Spectre; + }; + F3DE1C7C1F4A0F9600A29229 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = OBJ_1 /* Project object */; + proxyType = 1; + remoteGlobalIDString = OBJ_82; + remoteInfo = Commander; + }; + F3DE1C7D1F4A0F9600A29229 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = OBJ_1 /* Project object */; + proxyType = 1; + remoteGlobalIDString = OBJ_117; + remoteInfo = HeaderMapCore; + }; + F3DE1C7E1F4A0F9600A29229 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = OBJ_1 /* Project object */; + proxyType = 1; + remoteGlobalIDString = OBJ_68; + remoteInfo = Spectre; + }; + F3DE1C7F1F4A0F9600A29229 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = OBJ_1 /* Project object */; + proxyType = 1; + remoteGlobalIDString = OBJ_82; + remoteInfo = Commander; + }; + F3DE1C801F4A0F9600A29229 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = OBJ_1 /* Project object */; + proxyType = 1; + remoteGlobalIDString = OBJ_119; + remoteInfo = HeaderMapFrontend; + }; + F3DE1C811F4A0F9600A29229 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = OBJ_1 /* Project object */; + proxyType = 1; + remoteGlobalIDString = OBJ_68; + remoteInfo = Spectre; + }; + F3DE1C821F4A0F9600A29229 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = OBJ_1 /* Project object */; + proxyType = 1; + remoteGlobalIDString = OBJ_82; + remoteInfo = Commander; + }; + F3DE1C831F4A0F9600A29229 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = OBJ_1 /* Project object */; + proxyType = 1; + remoteGlobalIDString = OBJ_117; + remoteInfo = HeaderMapCore; + }; + F3DE1C841F4A0F9600A29229 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = OBJ_1 /* Project object */; + proxyType = 1; + remoteGlobalIDString = OBJ_68; + remoteInfo = Spectre; + }; + F3DE1C851F4A0F9600A29229 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = OBJ_1 /* Project object */; + proxyType = 1; + remoteGlobalIDString = OBJ_82; + remoteInfo = Commander; + }; + F3DE1C861F4A0F9600A29229 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = OBJ_1 /* Project object */; + proxyType = 1; + remoteGlobalIDString = OBJ_68; + remoteInfo = Spectre; + }; + F3DE1C871F4A0F9600A29229 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = OBJ_1 /* Project object */; + proxyType = 1; + remoteGlobalIDString = OBJ_82; + remoteInfo = Commander; + }; + F3DE1C881F4A0F9600A29229 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = OBJ_1 /* Project object */; + proxyType = 1; + remoteGlobalIDString = OBJ_139; + remoteInfo = HeaderMapTesting; + }; + F3DE1C891F4A0F9600A29229 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = OBJ_1 /* Project object */; + proxyType = 1; + remoteGlobalIDString = OBJ_68; + remoteInfo = Spectre; + }; + F3DE1C8A1F4A0F9600A29229 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = OBJ_1 /* Project object */; + proxyType = 1; + remoteGlobalIDString = OBJ_82; + remoteInfo = Commander; + }; + F3DE1C8B1F4A0F9600A29229 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = OBJ_1 /* Project object */; + proxyType = 1; + remoteGlobalIDString = OBJ_139; + remoteInfo = HeaderMapTesting; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + F3DE1C8D1F4A0FAF00A29229 /* Realm.hmap */ = {isa = PBXFileReference; lastKnownFileType = file; path = Realm.hmap; sourceTree = ""; }; + F3DE1C8E1F4A0FAF00A29229 /* Realm.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = Realm.json; sourceTree = ""; }; + F3DE1C931F4A0FC600A29229 /* map.hmap */ = {isa = PBXFileReference; lastKnownFileType = file; path = map.hmap; sourceTree = ""; }; + F3DE1C941F4A0FC600A29229 /* map.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = map.json; sourceTree = ""; }; + F3DE1C951F4A0FC600A29229 /* map.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = map.txt; sourceTree = ""; }; + OBJ_10 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; + OBJ_11 /* Print.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Print.swift; sourceTree = ""; }; + OBJ_12 /* ReturnCodes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReturnCodes.swift; sourceTree = ""; }; + OBJ_13 /* StringExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringExtensions.swift; sourceTree = ""; }; + OBJ_15 /* BinaryHeaderMap.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BinaryHeaderMap.swift; sourceTree = ""; }; + OBJ_16 /* ByteBuffer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ByteBuffer.swift; sourceTree = ""; }; + OBJ_17 /* HeaderMap.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeaderMap.swift; sourceTree = ""; }; + OBJ_18 /* HeaderMapError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeaderMapError.swift; sourceTree = ""; }; + OBJ_19 /* HeaderMapMaker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeaderMapMaker.swift; sourceTree = ""; }; + OBJ_20 /* JSONHeaderMap.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSONHeaderMap.swift; sourceTree = ""; }; + OBJ_22 /* ArrayExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArrayExtensions.swift; sourceTree = ""; }; + OBJ_23 /* DictionaryExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DictionaryExtensions.swift; sourceTree = ""; }; + OBJ_24 /* NumberExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NumberExtensions.swift; sourceTree = ""; }; + OBJ_25 /* StringExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringExtensions.swift; sourceTree = ""; }; + OBJ_27 /* TestingExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestingExtensions.swift; sourceTree = ""; }; + OBJ_29 /* Command.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Command.swift; sourceTree = ""; }; + OBJ_30 /* ConvertCommands.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConvertCommands.swift; sourceTree = ""; }; + OBJ_31 /* FileFormat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileFormat.swift; sourceTree = ""; }; + OBJ_32 /* FrontendErrors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FrontendErrors.swift; sourceTree = ""; }; + OBJ_33 /* PrintCommands.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrintCommands.swift; sourceTree = ""; }; + OBJ_36 /* HeaderMapTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeaderMapTests.swift; sourceTree = ""; }; + OBJ_38 /* CommandTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommandTests.swift; sourceTree = ""; }; + OBJ_41 /* ArgumentConvertible.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArgumentConvertible.swift; sourceTree = ""; }; + OBJ_42 /* ArgumentDescription.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArgumentDescription.swift; sourceTree = ""; }; + OBJ_43 /* ArgumentParser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArgumentParser.swift; sourceTree = ""; }; + OBJ_44 /* Command.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Command.swift; sourceTree = ""; }; + OBJ_45 /* CommandRunner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommandRunner.swift; sourceTree = ""; }; + OBJ_46 /* Commands.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Commands.swift; sourceTree = ""; }; + OBJ_47 /* CommandType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommandType.swift; sourceTree = ""; }; + OBJ_48 /* Error.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Error.swift; sourceTree = ""; }; + OBJ_49 /* Group.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Group.swift; sourceTree = ""; }; + OBJ_51 /* Case.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Case.swift; sourceTree = ""; }; + OBJ_52 /* Context.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Context.swift; sourceTree = ""; }; + OBJ_53 /* Expectation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Expectation.swift; sourceTree = ""; }; + OBJ_54 /* Failure.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Failure.swift; sourceTree = ""; }; + OBJ_55 /* Global.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Global.swift; sourceTree = ""; }; + OBJ_56 /* GlobalContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlobalContext.swift; sourceTree = ""; }; + OBJ_57 /* Reporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Reporter.swift; sourceTree = ""; }; + OBJ_58 /* Reporters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Reporters.swift; sourceTree = ""; }; + OBJ_6 /* Package.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; path = Package.swift; sourceTree = ""; }; + OBJ_60 /* Spectre.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Spectre.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + OBJ_61 /* Commander.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Commander.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + OBJ_62 /* hmap */ = {isa = PBXFileReference; lastKnownFileType = text; path = hmap; sourceTree = BUILT_PRODUCTS_DIR; }; + OBJ_63 /* HeaderMapCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = HeaderMapCore.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + OBJ_64 /* HeaderMapTesting.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = HeaderMapTesting.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + OBJ_65 /* HeaderMapFrontend.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = HeaderMapFrontend.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + OBJ_66 /* HeaderMapCoreTests.xctest */ = {isa = PBXFileReference; lastKnownFileType = file; path = HeaderMapCoreTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + OBJ_67 /* HeaderMapFrontendTests.xctest */ = {isa = PBXFileReference; lastKnownFileType = file; path = HeaderMapFrontendTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + OBJ_9 /* Convert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Convert.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + OBJ_109 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 0; + files = ( + OBJ_110 /* Spectre.framework in Frameworks */, + OBJ_111 /* Commander.framework in Frameworks */, + OBJ_112 /* HeaderMapCore.framework in Frameworks */, + OBJ_113 /* HeaderMapFrontend.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + OBJ_134 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 0; + files = ( + OBJ_135 /* Spectre.framework in Frameworks */, + OBJ_136 /* Commander.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + OBJ_145 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 0; + files = ( + OBJ_146 /* Spectre.framework in Frameworks */, + OBJ_147 /* Commander.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + OBJ_159 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 0; + files = ( + OBJ_160 /* Spectre.framework in Frameworks */, + OBJ_161 /* Commander.framework in Frameworks */, + OBJ_162 /* HeaderMapCore.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + OBJ_172 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 0; + files = ( + OBJ_173 /* Spectre.framework in Frameworks */, + OBJ_174 /* Commander.framework in Frameworks */, + OBJ_175 /* HeaderMapTesting.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + OBJ_185 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 0; + files = ( + OBJ_186 /* Spectre.framework in Frameworks */, + OBJ_187 /* Commander.framework in Frameworks */, + OBJ_188 /* HeaderMapTesting.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + OBJ_81 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + OBJ_96 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 0; + files = ( + OBJ_97 /* Spectre.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + F3DE1C8C1F4A0FAF00A29229 /* TestFiles */ = { + isa = PBXGroup; + children = ( + F3DE1C8D1F4A0FAF00A29229 /* Realm.hmap */, + F3DE1C8E1F4A0FAF00A29229 /* Realm.json */, + ); + path = TestFiles; + sourceTree = ""; + }; + F3DE1C921F4A0FC600A29229 /* TestFiles */ = { + isa = PBXGroup; + children = ( + F3DE1C931F4A0FC600A29229 /* map.hmap */, + F3DE1C941F4A0FC600A29229 /* map.json */, + F3DE1C951F4A0FC600A29229 /* map.txt */, + ); + path = TestFiles; + sourceTree = ""; + }; + OBJ_14 /* HeaderMapCore */ = { + isa = PBXGroup; + children = ( + OBJ_15 /* BinaryHeaderMap.swift */, + OBJ_16 /* ByteBuffer.swift */, + OBJ_17 /* HeaderMap.swift */, + OBJ_18 /* HeaderMapError.swift */, + OBJ_19 /* HeaderMapMaker.swift */, + OBJ_20 /* JSONHeaderMap.swift */, + OBJ_21 /* extensions */, + ); + name = HeaderMapCore; + path = Sources/HeaderMapCore; + sourceTree = SOURCE_ROOT; + }; + OBJ_21 /* extensions */ = { + isa = PBXGroup; + children = ( + OBJ_22 /* ArrayExtensions.swift */, + OBJ_23 /* DictionaryExtensions.swift */, + OBJ_24 /* NumberExtensions.swift */, + OBJ_25 /* StringExtensions.swift */, + ); + path = extensions; + sourceTree = ""; + }; + OBJ_26 /* HeaderMapTesting */ = { + isa = PBXGroup; + children = ( + OBJ_27 /* TestingExtensions.swift */, + ); + name = HeaderMapTesting; + path = Sources/HeaderMapTesting; + sourceTree = SOURCE_ROOT; + }; + OBJ_28 /* HeaderMapFrontend */ = { + isa = PBXGroup; + children = ( + OBJ_29 /* Command.swift */, + OBJ_30 /* ConvertCommands.swift */, + OBJ_31 /* FileFormat.swift */, + OBJ_32 /* FrontendErrors.swift */, + OBJ_33 /* PrintCommands.swift */, + ); + name = HeaderMapFrontend; + path = Sources/HeaderMapFrontend; + sourceTree = SOURCE_ROOT; + }; + OBJ_34 /* Tests */ = { + isa = PBXGroup; + children = ( + OBJ_35 /* HeaderMapCoreTests */, + OBJ_37 /* HeaderMapFrontendTests */, + ); + name = Tests; + sourceTree = SOURCE_ROOT; + }; + OBJ_35 /* HeaderMapCoreTests */ = { + isa = PBXGroup; + children = ( + F3DE1C8C1F4A0FAF00A29229 /* TestFiles */, + OBJ_36 /* HeaderMapTests.swift */, + ); + name = HeaderMapCoreTests; + path = Tests/HeaderMapCoreTests; + sourceTree = SOURCE_ROOT; + }; + OBJ_37 /* HeaderMapFrontendTests */ = { + isa = PBXGroup; + children = ( + F3DE1C921F4A0FC600A29229 /* TestFiles */, + OBJ_38 /* CommandTests.swift */, + ); + name = HeaderMapFrontendTests; + path = Tests/HeaderMapFrontendTests; + sourceTree = SOURCE_ROOT; + }; + OBJ_39 /* Dependencies */ = { + isa = PBXGroup; + children = ( + OBJ_40 /* Commander 0.6.0 */, + OBJ_50 /* Spectre 0.7.2 */, + ); + name = Dependencies; + sourceTree = ""; + }; + OBJ_40 /* Commander 0.6.0 */ = { + isa = PBXGroup; + children = ( + OBJ_41 /* ArgumentConvertible.swift */, + OBJ_42 /* ArgumentDescription.swift */, + OBJ_43 /* ArgumentParser.swift */, + OBJ_44 /* Command.swift */, + OBJ_45 /* CommandRunner.swift */, + OBJ_46 /* Commands.swift */, + OBJ_47 /* CommandType.swift */, + OBJ_48 /* Error.swift */, + OBJ_49 /* Group.swift */, + ); + name = "Commander 0.6.0"; + path = ".build/checkouts/Commander.git-1040763989236346507/Sources"; + sourceTree = SOURCE_ROOT; + }; + OBJ_5 /* */ = { + isa = PBXGroup; + children = ( + OBJ_6 /* Package.swift */, + OBJ_7 /* Sources */, + OBJ_34 /* Tests */, + OBJ_39 /* Dependencies */, + OBJ_59 /* Products */, + ); + name = ""; + sourceTree = ""; + }; + OBJ_50 /* Spectre 0.7.2 */ = { + isa = PBXGroup; + children = ( + OBJ_51 /* Case.swift */, + OBJ_52 /* Context.swift */, + OBJ_53 /* Expectation.swift */, + OBJ_54 /* Failure.swift */, + OBJ_55 /* Global.swift */, + OBJ_56 /* GlobalContext.swift */, + OBJ_57 /* Reporter.swift */, + OBJ_58 /* Reporters.swift */, + ); + name = "Spectre 0.7.2"; + path = ".build/checkouts/Spectre--9185491864710013835/Sources"; + sourceTree = SOURCE_ROOT; + }; + OBJ_59 /* Products */ = { + isa = PBXGroup; + children = ( + OBJ_60 /* Spectre.framework */, + OBJ_61 /* Commander.framework */, + OBJ_62 /* hmap */, + OBJ_63 /* HeaderMapCore.framework */, + OBJ_64 /* HeaderMapTesting.framework */, + OBJ_65 /* HeaderMapFrontend.framework */, + OBJ_66 /* HeaderMapCoreTests.xctest */, + OBJ_67 /* HeaderMapFrontendTests.xctest */, + ); + name = Products; + sourceTree = BUILT_PRODUCTS_DIR; + }; + OBJ_7 /* Sources */ = { + isa = PBXGroup; + children = ( + OBJ_8 /* hmap */, + OBJ_14 /* HeaderMapCore */, + OBJ_26 /* HeaderMapTesting */, + OBJ_28 /* HeaderMapFrontend */, + ); + name = Sources; + sourceTree = SOURCE_ROOT; + }; + OBJ_8 /* hmap */ = { + isa = PBXGroup; + children = ( + OBJ_9 /* Convert.swift */, + OBJ_10 /* main.swift */, + OBJ_11 /* Print.swift */, + OBJ_12 /* ReturnCodes.swift */, + OBJ_13 /* StringExtensions.swift */, + ); + name = hmap; + path = Sources/hmap; + sourceTree = SOURCE_ROOT; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + OBJ_117 /* HeaderMapCore */ = { + isa = PBXNativeTarget; + buildConfigurationList = OBJ_120 /* Build configuration list for PBXNativeTarget "HeaderMapCore" */; + buildPhases = ( + OBJ_123 /* Sources */, + OBJ_134 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + OBJ_137 /* PBXTargetDependency */, + OBJ_138 /* PBXTargetDependency */, + ); + name = HeaderMapCore; + productName = HeaderMapCore; + productReference = OBJ_63 /* HeaderMapCore.framework */; + productType = "com.apple.product-type.framework"; + }; + OBJ_119 /* HeaderMapFrontend */ = { + isa = PBXNativeTarget; + buildConfigurationList = OBJ_150 /* Build configuration list for PBXNativeTarget "HeaderMapFrontend" */; + buildPhases = ( + OBJ_153 /* Sources */, + OBJ_159 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + OBJ_163 /* PBXTargetDependency */, + OBJ_164 /* PBXTargetDependency */, + OBJ_165 /* PBXTargetDependency */, + ); + name = HeaderMapFrontend; + productName = HeaderMapFrontend; + productReference = OBJ_65 /* HeaderMapFrontend.framework */; + productType = "com.apple.product-type.framework"; + }; + OBJ_139 /* HeaderMapTesting */ = { + isa = PBXNativeTarget; + buildConfigurationList = OBJ_140 /* Build configuration list for PBXNativeTarget "HeaderMapTesting" */; + buildPhases = ( + OBJ_143 /* Sources */, + OBJ_145 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + OBJ_148 /* PBXTargetDependency */, + OBJ_149 /* PBXTargetDependency */, + ); + name = HeaderMapTesting; + productName = HeaderMapTesting; + productReference = OBJ_64 /* HeaderMapTesting.framework */; + productType = "com.apple.product-type.framework"; + }; + OBJ_166 /* HeaderMapCoreTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = OBJ_167 /* Build configuration list for PBXNativeTarget "HeaderMapCoreTests" */; + buildPhases = ( + OBJ_170 /* Sources */, + OBJ_172 /* Frameworks */, + F3DE1C8F1F4A0FB500A29229 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + OBJ_176 /* PBXTargetDependency */, + OBJ_177 /* PBXTargetDependency */, + OBJ_178 /* PBXTargetDependency */, + ); + name = HeaderMapCoreTests; + productName = HeaderMapCoreTests; + productReference = OBJ_66 /* HeaderMapCoreTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + OBJ_179 /* HeaderMapFrontendTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = OBJ_180 /* Build configuration list for PBXNativeTarget "HeaderMapFrontendTests" */; + buildPhases = ( + OBJ_183 /* Sources */, + OBJ_185 /* Frameworks */, + F3DE1C991F4A0FCA00A29229 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + OBJ_189 /* PBXTargetDependency */, + OBJ_190 /* PBXTargetDependency */, + OBJ_191 /* PBXTargetDependency */, + ); + name = HeaderMapFrontendTests; + productName = HeaderMapFrontendTests; + productReference = OBJ_67 /* HeaderMapFrontendTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + OBJ_68 /* Spectre */ = { + isa = PBXNativeTarget; + buildConfigurationList = OBJ_69 /* Build configuration list for PBXNativeTarget "Spectre" */; + buildPhases = ( + OBJ_72 /* Sources */, + OBJ_81 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Spectre; + productName = Spectre; + productReference = OBJ_60 /* Spectre.framework */; + productType = "com.apple.product-type.framework"; + }; + OBJ_82 /* Commander */ = { + isa = PBXNativeTarget; + buildConfigurationList = OBJ_83 /* Build configuration list for PBXNativeTarget "Commander" */; + buildPhases = ( + OBJ_86 /* Sources */, + OBJ_96 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + OBJ_98 /* PBXTargetDependency */, + ); + name = Commander; + productName = Commander; + productReference = OBJ_61 /* Commander.framework */; + productType = "com.apple.product-type.framework"; + }; + OBJ_99 /* hmap */ = { + isa = PBXNativeTarget; + buildConfigurationList = OBJ_100 /* Build configuration list for PBXNativeTarget "hmap" */; + buildPhases = ( + OBJ_103 /* Sources */, + OBJ_109 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + OBJ_114 /* PBXTargetDependency */, + OBJ_115 /* PBXTargetDependency */, + OBJ_116 /* PBXTargetDependency */, + OBJ_118 /* PBXTargetDependency */, + ); + name = hmap; + productName = hmap; + productReference = OBJ_62 /* hmap */; + productType = "com.apple.product-type.tool"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + OBJ_1 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 9999; + }; + buildConfigurationList = OBJ_2 /* Build configuration list for PBXProject "hmap" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = OBJ_5 /* */; + productRefGroup = OBJ_59 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + OBJ_68 /* Spectre */, + OBJ_82 /* Commander */, + OBJ_99 /* hmap */, + OBJ_117 /* HeaderMapCore */, + OBJ_139 /* HeaderMapTesting */, + OBJ_119 /* HeaderMapFrontend */, + OBJ_166 /* HeaderMapCoreTests */, + OBJ_179 /* HeaderMapFrontendTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + F3DE1C8F1F4A0FB500A29229 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F3DE1C981F4A0FC600A29229 /* map.txt in Resources */, + F3DE1C901F4A0FBD00A29229 /* Realm.hmap in Resources */, + F3DE1C911F4A0FBD00A29229 /* Realm.json in Resources */, + F3DE1C971F4A0FC600A29229 /* map.json in Resources */, + F3DE1C961F4A0FC600A29229 /* map.hmap in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F3DE1C991F4A0FCA00A29229 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F3DE1C9C1F4A103800A29229 /* map.txt in Resources */, + F3DE1C9A1F4A0FCF00A29229 /* map.hmap in Resources */, + F3DE1C9B1F4A0FCF00A29229 /* map.json in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + OBJ_103 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 0; + files = ( + OBJ_104 /* Convert.swift in Sources */, + OBJ_105 /* main.swift in Sources */, + OBJ_106 /* Print.swift in Sources */, + OBJ_107 /* ReturnCodes.swift in Sources */, + OBJ_108 /* StringExtensions.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + OBJ_123 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 0; + files = ( + OBJ_124 /* BinaryHeaderMap.swift in Sources */, + OBJ_125 /* ByteBuffer.swift in Sources */, + OBJ_126 /* HeaderMap.swift in Sources */, + OBJ_127 /* HeaderMapError.swift in Sources */, + OBJ_128 /* HeaderMapMaker.swift in Sources */, + OBJ_129 /* JSONHeaderMap.swift in Sources */, + OBJ_130 /* ArrayExtensions.swift in Sources */, + OBJ_131 /* DictionaryExtensions.swift in Sources */, + OBJ_132 /* NumberExtensions.swift in Sources */, + OBJ_133 /* StringExtensions.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + OBJ_143 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 0; + files = ( + OBJ_144 /* TestingExtensions.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + OBJ_153 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 0; + files = ( + OBJ_154 /* Command.swift in Sources */, + OBJ_155 /* ConvertCommands.swift in Sources */, + OBJ_156 /* FileFormat.swift in Sources */, + OBJ_157 /* FrontendErrors.swift in Sources */, + OBJ_158 /* PrintCommands.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + OBJ_170 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 0; + files = ( + OBJ_171 /* HeaderMapTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + OBJ_183 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 0; + files = ( + OBJ_184 /* CommandTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + OBJ_72 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 0; + files = ( + OBJ_73 /* Case.swift in Sources */, + OBJ_74 /* Context.swift in Sources */, + OBJ_75 /* Expectation.swift in Sources */, + OBJ_76 /* Failure.swift in Sources */, + OBJ_77 /* Global.swift in Sources */, + OBJ_78 /* GlobalContext.swift in Sources */, + OBJ_79 /* Reporter.swift in Sources */, + OBJ_80 /* Reporters.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + OBJ_86 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 0; + files = ( + OBJ_87 /* ArgumentConvertible.swift in Sources */, + OBJ_88 /* ArgumentDescription.swift in Sources */, + OBJ_89 /* ArgumentParser.swift in Sources */, + OBJ_90 /* Command.swift in Sources */, + OBJ_91 /* CommandRunner.swift in Sources */, + OBJ_92 /* Commands.swift in Sources */, + OBJ_93 /* CommandType.swift in Sources */, + OBJ_94 /* Error.swift in Sources */, + OBJ_95 /* Group.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + OBJ_114 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = OBJ_68 /* Spectre */; + targetProxy = F3DE1C7B1F4A0F9600A29229 /* PBXContainerItemProxy */; + }; + OBJ_115 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = OBJ_82 /* Commander */; + targetProxy = F3DE1C7C1F4A0F9600A29229 /* PBXContainerItemProxy */; + }; + OBJ_116 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = OBJ_117 /* HeaderMapCore */; + targetProxy = F3DE1C7D1F4A0F9600A29229 /* PBXContainerItemProxy */; + }; + OBJ_118 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = OBJ_119 /* HeaderMapFrontend */; + targetProxy = F3DE1C801F4A0F9600A29229 /* PBXContainerItemProxy */; + }; + OBJ_137 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = OBJ_68 /* Spectre */; + targetProxy = F3DE1C7E1F4A0F9600A29229 /* PBXContainerItemProxy */; + }; + OBJ_138 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = OBJ_82 /* Commander */; + targetProxy = F3DE1C7F1F4A0F9600A29229 /* PBXContainerItemProxy */; + }; + OBJ_148 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = OBJ_68 /* Spectre */; + targetProxy = F3DE1C841F4A0F9600A29229 /* PBXContainerItemProxy */; + }; + OBJ_149 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = OBJ_82 /* Commander */; + targetProxy = F3DE1C851F4A0F9600A29229 /* PBXContainerItemProxy */; + }; + OBJ_163 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = OBJ_68 /* Spectre */; + targetProxy = F3DE1C811F4A0F9600A29229 /* PBXContainerItemProxy */; + }; + OBJ_164 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = OBJ_82 /* Commander */; + targetProxy = F3DE1C821F4A0F9600A29229 /* PBXContainerItemProxy */; + }; + OBJ_165 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = OBJ_117 /* HeaderMapCore */; + targetProxy = F3DE1C831F4A0F9600A29229 /* PBXContainerItemProxy */; + }; + OBJ_176 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = OBJ_68 /* Spectre */; + targetProxy = F3DE1C861F4A0F9600A29229 /* PBXContainerItemProxy */; + }; + OBJ_177 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = OBJ_82 /* Commander */; + targetProxy = F3DE1C871F4A0F9600A29229 /* PBXContainerItemProxy */; + }; + OBJ_178 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = OBJ_139 /* HeaderMapTesting */; + targetProxy = F3DE1C881F4A0F9600A29229 /* PBXContainerItemProxy */; + }; + OBJ_189 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = OBJ_68 /* Spectre */; + targetProxy = F3DE1C891F4A0F9600A29229 /* PBXContainerItemProxy */; + }; + OBJ_190 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = OBJ_82 /* Commander */; + targetProxy = F3DE1C8A1F4A0F9600A29229 /* PBXContainerItemProxy */; + }; + OBJ_191 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = OBJ_139 /* HeaderMapTesting */; + targetProxy = F3DE1C8B1F4A0F9600A29229 /* PBXContainerItemProxy */; + }; + OBJ_98 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = OBJ_68 /* Spectre */; + targetProxy = F3DE1C7A1F4A0F9600A29229 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + OBJ_101 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PLATFORM_DIR)/Developer/Library/Frameworks", + ); + HEADER_SEARCH_PATHS = "$(inherited)"; + INFOPLIST_FILE = hmap.xcodeproj/hmap_Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(TOOLCHAIN_DIR)/usr/lib/swift/macosx @executable_path"; + OTHER_LDFLAGS = "$(inherited)"; + OTHER_SWIFT_FLAGS = "$(inherited)"; + SWIFT_FORCE_DYNAMIC_LINK_STDLIB = YES; + SWIFT_FORCE_STATIC_LINK_STDLIB = NO; + TARGET_NAME = hmap; + }; + name = Debug; + }; + OBJ_102 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PLATFORM_DIR)/Developer/Library/Frameworks", + ); + HEADER_SEARCH_PATHS = "$(inherited)"; + INFOPLIST_FILE = hmap.xcodeproj/hmap_Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(TOOLCHAIN_DIR)/usr/lib/swift/macosx @executable_path"; + OTHER_LDFLAGS = "$(inherited)"; + OTHER_SWIFT_FLAGS = "$(inherited)"; + SWIFT_FORCE_DYNAMIC_LINK_STDLIB = YES; + SWIFT_FORCE_STATIC_LINK_STDLIB = NO; + TARGET_NAME = hmap; + }; + name = Release; + }; + OBJ_121 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ENABLE_TESTABILITY = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PLATFORM_DIR)/Developer/Library/Frameworks", + ); + HEADER_SEARCH_PATHS = "$(inherited)"; + INFOPLIST_FILE = hmap.xcodeproj/HeaderMapCore_Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(TOOLCHAIN_DIR)/usr/lib/swift/macosx"; + OTHER_LDFLAGS = "$(inherited)"; + OTHER_SWIFT_FLAGS = "$(inherited)"; + PRODUCT_BUNDLE_IDENTIFIER = HeaderMapCore; + PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + TARGET_NAME = HeaderMapCore; + }; + name = Debug; + }; + OBJ_122 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ENABLE_TESTABILITY = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PLATFORM_DIR)/Developer/Library/Frameworks", + ); + HEADER_SEARCH_PATHS = "$(inherited)"; + INFOPLIST_FILE = hmap.xcodeproj/HeaderMapCore_Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(TOOLCHAIN_DIR)/usr/lib/swift/macosx"; + OTHER_LDFLAGS = "$(inherited)"; + OTHER_SWIFT_FLAGS = "$(inherited)"; + PRODUCT_BUNDLE_IDENTIFIER = HeaderMapCore; + PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + TARGET_NAME = HeaderMapCore; + }; + name = Release; + }; + OBJ_141 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ENABLE_TESTABILITY = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PLATFORM_DIR)/Developer/Library/Frameworks", + ); + HEADER_SEARCH_PATHS = "$(inherited)"; + INFOPLIST_FILE = hmap.xcodeproj/HeaderMapTesting_Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(TOOLCHAIN_DIR)/usr/lib/swift/macosx"; + OTHER_LDFLAGS = "$(inherited)"; + OTHER_SWIFT_FLAGS = "$(inherited)"; + PRODUCT_BUNDLE_IDENTIFIER = HeaderMapTesting; + PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + TARGET_NAME = HeaderMapTesting; + }; + name = Debug; + }; + OBJ_142 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ENABLE_TESTABILITY = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PLATFORM_DIR)/Developer/Library/Frameworks", + ); + HEADER_SEARCH_PATHS = "$(inherited)"; + INFOPLIST_FILE = hmap.xcodeproj/HeaderMapTesting_Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(TOOLCHAIN_DIR)/usr/lib/swift/macosx"; + OTHER_LDFLAGS = "$(inherited)"; + OTHER_SWIFT_FLAGS = "$(inherited)"; + PRODUCT_BUNDLE_IDENTIFIER = HeaderMapTesting; + PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + TARGET_NAME = HeaderMapTesting; + }; + name = Release; + }; + OBJ_151 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ENABLE_TESTABILITY = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PLATFORM_DIR)/Developer/Library/Frameworks", + ); + HEADER_SEARCH_PATHS = "$(inherited)"; + INFOPLIST_FILE = hmap.xcodeproj/HeaderMapFrontend_Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(TOOLCHAIN_DIR)/usr/lib/swift/macosx"; + OTHER_LDFLAGS = "$(inherited)"; + OTHER_SWIFT_FLAGS = "$(inherited)"; + PRODUCT_BUNDLE_IDENTIFIER = HeaderMapFrontend; + PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + TARGET_NAME = HeaderMapFrontend; + }; + name = Debug; + }; + OBJ_152 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ENABLE_TESTABILITY = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PLATFORM_DIR)/Developer/Library/Frameworks", + ); + HEADER_SEARCH_PATHS = "$(inherited)"; + INFOPLIST_FILE = hmap.xcodeproj/HeaderMapFrontend_Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(TOOLCHAIN_DIR)/usr/lib/swift/macosx"; + OTHER_LDFLAGS = "$(inherited)"; + OTHER_SWIFT_FLAGS = "$(inherited)"; + PRODUCT_BUNDLE_IDENTIFIER = HeaderMapFrontend; + PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + TARGET_NAME = HeaderMapFrontend; + }; + name = Release; + }; + OBJ_168 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + EMBEDDED_CONTENT_CONTAINS_SWIFT = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PLATFORM_DIR)/Developer/Library/Frameworks", + ); + HEADER_SEARCH_PATHS = "$(inherited)"; + INFOPLIST_FILE = hmap.xcodeproj/HeaderMapCoreTests_Info.plist; + LD_RUNPATH_SEARCH_PATHS = "@loader_path/../Frameworks @loader_path/Frameworks"; + OTHER_LDFLAGS = "$(inherited)"; + OTHER_SWIFT_FLAGS = "$(inherited)"; + TARGET_NAME = HeaderMapCoreTests; + }; + name = Debug; + }; + OBJ_169 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + EMBEDDED_CONTENT_CONTAINS_SWIFT = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PLATFORM_DIR)/Developer/Library/Frameworks", + ); + HEADER_SEARCH_PATHS = "$(inherited)"; + INFOPLIST_FILE = hmap.xcodeproj/HeaderMapCoreTests_Info.plist; + LD_RUNPATH_SEARCH_PATHS = "@loader_path/../Frameworks @loader_path/Frameworks"; + OTHER_LDFLAGS = "$(inherited)"; + OTHER_SWIFT_FLAGS = "$(inherited)"; + TARGET_NAME = HeaderMapCoreTests; + }; + name = Release; + }; + OBJ_181 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + EMBEDDED_CONTENT_CONTAINS_SWIFT = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PLATFORM_DIR)/Developer/Library/Frameworks", + ); + HEADER_SEARCH_PATHS = "$(inherited)"; + INFOPLIST_FILE = hmap.xcodeproj/HeaderMapFrontendTests_Info.plist; + LD_RUNPATH_SEARCH_PATHS = "@loader_path/../Frameworks @loader_path/Frameworks"; + OTHER_LDFLAGS = "$(inherited)"; + OTHER_SWIFT_FLAGS = "$(inherited)"; + TARGET_NAME = HeaderMapFrontendTests; + }; + name = Debug; + }; + OBJ_182 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + EMBEDDED_CONTENT_CONTAINS_SWIFT = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PLATFORM_DIR)/Developer/Library/Frameworks", + ); + HEADER_SEARCH_PATHS = "$(inherited)"; + INFOPLIST_FILE = hmap.xcodeproj/HeaderMapFrontendTests_Info.plist; + LD_RUNPATH_SEARCH_PATHS = "@loader_path/../Frameworks @loader_path/Frameworks"; + OTHER_LDFLAGS = "$(inherited)"; + OTHER_SWIFT_FLAGS = "$(inherited)"; + TARGET_NAME = HeaderMapFrontendTests; + }; + name = Release; + }; + OBJ_3 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_OBJC_ARC = YES; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_NS_ASSERTIONS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + MACOSX_DEPLOYMENT_TARGET = 10.10; + ONLY_ACTIVE_ARCH = YES; + OTHER_SWIFT_FLAGS = "-DXcode"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator appletvos appletvsimulator watchos watchsimulator"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = SWIFT_PACKAGE; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; + USE_HEADERMAP = NO; + }; + name = Debug; + }; + OBJ_4 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_OBJC_ARC = YES; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_OPTIMIZATION_LEVEL = s; + MACOSX_DEPLOYMENT_TARGET = 10.10; + OTHER_SWIFT_FLAGS = "-DXcode"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator appletvos appletvsimulator watchos watchsimulator"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = SWIFT_PACKAGE; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 3.0; + USE_HEADERMAP = NO; + }; + name = Release; + }; + OBJ_70 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ENABLE_TESTABILITY = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PLATFORM_DIR)/Developer/Library/Frameworks", + ); + HEADER_SEARCH_PATHS = "$(inherited)"; + INFOPLIST_FILE = hmap.xcodeproj/Spectre_Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(TOOLCHAIN_DIR)/usr/lib/swift/macosx"; + OTHER_LDFLAGS = "$(inherited)"; + OTHER_SWIFT_FLAGS = "$(inherited)"; + PRODUCT_BUNDLE_IDENTIFIER = Spectre; + PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + TARGET_NAME = Spectre; + }; + name = Debug; + }; + OBJ_71 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ENABLE_TESTABILITY = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PLATFORM_DIR)/Developer/Library/Frameworks", + ); + HEADER_SEARCH_PATHS = "$(inherited)"; + INFOPLIST_FILE = hmap.xcodeproj/Spectre_Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(TOOLCHAIN_DIR)/usr/lib/swift/macosx"; + OTHER_LDFLAGS = "$(inherited)"; + OTHER_SWIFT_FLAGS = "$(inherited)"; + PRODUCT_BUNDLE_IDENTIFIER = Spectre; + PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + TARGET_NAME = Spectre; + }; + name = Release; + }; + OBJ_84 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ENABLE_TESTABILITY = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PLATFORM_DIR)/Developer/Library/Frameworks", + ); + HEADER_SEARCH_PATHS = "$(inherited)"; + INFOPLIST_FILE = hmap.xcodeproj/Commander_Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(TOOLCHAIN_DIR)/usr/lib/swift/macosx"; + OTHER_LDFLAGS = "$(inherited)"; + OTHER_SWIFT_FLAGS = "$(inherited)"; + PRODUCT_BUNDLE_IDENTIFIER = Commander; + PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + TARGET_NAME = Commander; + }; + name = Debug; + }; + OBJ_85 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ENABLE_TESTABILITY = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PLATFORM_DIR)/Developer/Library/Frameworks", + ); + HEADER_SEARCH_PATHS = "$(inherited)"; + INFOPLIST_FILE = hmap.xcodeproj/Commander_Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(TOOLCHAIN_DIR)/usr/lib/swift/macosx"; + OTHER_LDFLAGS = "$(inherited)"; + OTHER_SWIFT_FLAGS = "$(inherited)"; + PRODUCT_BUNDLE_IDENTIFIER = Commander; + PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + TARGET_NAME = Commander; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + OBJ_100 /* Build configuration list for PBXNativeTarget "hmap" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + OBJ_101 /* Debug */, + OBJ_102 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; + OBJ_120 /* Build configuration list for PBXNativeTarget "HeaderMapCore" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + OBJ_121 /* Debug */, + OBJ_122 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; + OBJ_140 /* Build configuration list for PBXNativeTarget "HeaderMapTesting" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + OBJ_141 /* Debug */, + OBJ_142 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; + OBJ_150 /* Build configuration list for PBXNativeTarget "HeaderMapFrontend" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + OBJ_151 /* Debug */, + OBJ_152 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; + OBJ_167 /* Build configuration list for PBXNativeTarget "HeaderMapCoreTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + OBJ_168 /* Debug */, + OBJ_169 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; + OBJ_180 /* Build configuration list for PBXNativeTarget "HeaderMapFrontendTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + OBJ_181 /* Debug */, + OBJ_182 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; + OBJ_2 /* Build configuration list for PBXProject "hmap" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + OBJ_3 /* Debug */, + OBJ_4 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; + OBJ_69 /* Build configuration list for PBXNativeTarget "Spectre" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + OBJ_70 /* Debug */, + OBJ_71 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; + OBJ_83 /* Build configuration list for PBXNativeTarget "Commander" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + OBJ_84 /* Debug */, + OBJ_85 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; +/* End XCConfigurationList section */ + }; + rootObject = OBJ_1 /* Project object */; +} diff --git a/hmap.xcodeproj/xcshareddata/xcschemes/hmap.xcscheme b/hmap.xcodeproj/xcshareddata/xcschemes/hmap.xcscheme new file mode 100755 index 0000000..29c7f97 --- /dev/null +++ b/hmap.xcodeproj/xcshareddata/xcschemes/hmap.xcscheme @@ -0,0 +1,163 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/hmap.xcodeproj/xcshareddata/xcschemes/xcschememanagement.plist b/hmap.xcodeproj/xcshareddata/xcschemes/xcschememanagement.plist new file mode 100755 index 0000000..01609e1 --- /dev/null +++ b/hmap.xcodeproj/xcshareddata/xcschemes/xcschememanagement.plist @@ -0,0 +1,12 @@ + + + + SchemeUserState + + hmap.xcscheme + + + SuppressBuildableAutocreation + + +