diff --git a/.gitignore b/.gitignore index 7495c35..a33bc13 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ # xcode noise build/ xcuserdata/ +xcshareddata/ # old skool .svn @@ -12,3 +13,5 @@ xcuserdata/ *~ *.swp + + diff --git a/swift/XMLReader.xcodeproj/project.pbxproj b/swift/XMLReader.xcodeproj/project.pbxproj index dba322e..cc8150d 100644 --- a/swift/XMLReader.xcodeproj/project.pbxproj +++ b/swift/XMLReader.xcodeproj/project.pbxproj @@ -164,7 +164,7 @@ 712B9011198FB02F0041D48D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0600; + LastUpgradeCheck = 1140; ORGANIZATIONNAME = Epershand; TargetAttributes = { 712B9019198FB02F0041D48D = { @@ -177,10 +177,11 @@ }; buildConfigurationList = 712B9014198FB02F0041D48D /* Build configuration list for PBXProject "XMLReader" */; compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; + developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, + Base, ); mainGroup = 712B9010198FB02F0041D48D; productRefGroup = 712B901B198FB02F0041D48D /* Products */; @@ -247,21 +248,33 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", @@ -293,13 +306,23 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -308,6 +331,7 @@ ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; @@ -317,6 +341,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; @@ -335,9 +360,11 @@ INFOPLIST_FILE = XMLReader/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = ""; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; @@ -353,8 +380,10 @@ INFOPLIST_FILE = XMLReader/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = ""; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; @@ -372,6 +401,7 @@ ); INFOPLIST_FILE = XMLReaderTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "io.epershand.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; @@ -385,6 +415,7 @@ ); INFOPLIST_FILE = XMLReaderTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "io.epershand.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; diff --git a/swift/XMLReader.xcodeproj/xcshareddata/xcschemes/XMLReader.xcscheme b/swift/XMLReader.xcodeproj/xcshareddata/xcschemes/XMLReader.xcscheme index 2d77b9d..5fa4b1e 100644 --- a/swift/XMLReader.xcodeproj/xcshareddata/xcschemes/XMLReader.xcscheme +++ b/swift/XMLReader.xcodeproj/xcshareddata/xcschemes/XMLReader.xcscheme @@ -1,6 +1,6 @@ + shouldUseLaunchSchemeArgsEnv = "YES"> + + + + @@ -39,24 +48,16 @@ - - - - - - + shouldUseLaunchSchemeArgsEnv = "YES"> + + + + @@ -39,24 +48,16 @@ - - - - - - CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier - io.epershand.${PRODUCT_NAME:rfc1034identifier} + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName diff --git a/swift/XMLReader/StringExtensions.swift b/swift/XMLReader/StringExtensions.swift index a0d61d6..cf999af 100644 --- a/swift/XMLReader/StringExtensions.swift +++ b/swift/XMLReader/StringExtensions.swift @@ -11,72 +11,13 @@ import Foundation // part borrowed from https://github.com/pNre/ExSwift/blob/master/ExSwift/String.swift extension String { - /** - Strip specified characters from the start of a string - - :param: set The character set to be trim from the start of the string - - :returns: Stripped string - */ - func ltrimCharactersInSet(set: NSCharacterSet) -> String { - if let range = rangeOfCharacterFromSet(set.invertedSet) { - return self[range.startIndex.. String { - return self.ltrimCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()) - } - - /** - Strip specified characters from the end of a string - - :param: set The character set to be trim from the end of the string - - :returns: Stripped string - */ - func rtrimCharactersInSet(set: NSCharacterSet) -> String { - if let range = rangeOfCharacterFromSet(set.invertedSet, options: NSStringCompareOptions.BackwardsSearch) { - return self[startIndex.. String { - return self.rtrimCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()) - } - /** Strip whitespaces and newlines from both the start and the end of a string - - :param: set The character set to be trim from the start and the end of the string - - :returns: Stripped string - */ - func trimCharactersInSet(set: NSCharacterSet) -> String { - return ltrimCharactersInSet(set).rtrimCharactersInSet(set) - } - - /** - Strip whitespaces and newlines from both the start and the end of a string - - :returns: Stripped string + - returns: A string with trimmed whitespaces and newlines from both ends */ - func trim() -> String { - return ltrim().rtrim() + func trimWhitespacesAndNewlines() -> String { + let set = CharacterSet.whitespacesAndNewlines + return self.trimmingCharacters(in: set) } } diff --git a/swift/XMLReader/XMLReader.h b/swift/XMLReader/XMLReader.h index f4c6d88..36a1ca0 100644 --- a/swift/XMLReader/XMLReader.h +++ b/swift/XMLReader/XMLReader.h @@ -8,4 +8,4 @@ #import -#import \ No newline at end of file +//#import diff --git a/swift/XMLReader/XMLReader.swift b/swift/XMLReader/XMLReader.swift index 59dafaf..f9d3a2f 100644 --- a/swift/XMLReader/XMLReader.swift +++ b/swift/XMLReader/XMLReader.swift @@ -13,71 +13,62 @@ typealias XMLDictionary = Dictionary let kXMLReaderTextNodeKey: String = "text" let kXMLReaderAttributePrefix: String = "@" -//enum XMLReaderOptions: UInt8 { -// case None = 0 -// -// /// Specifies whether the receiver reports the namespace and the qualified name of an element. -// case ProcessNamespaces = 0b00000001 -// -// /// Specifies whether the receiver reports the scope of namespace declarations. -// case ReportNamespacePrefixes = 0b00000010 -// -// /// Specifies whether the receiver reports declarations of external entities. -// case ResolveExternalEntities = 0b00000100 -//} -// -//func == (lhs: XMLReaderOptions, rhs: XMLReaderOptions) -> Bool { -// let res = lhs & rhs -// return (res != 0) -//} - - /// -struct XMLReaderOptions : RawOptionSetType { - var value: UInt = 0 +struct XMLReaderOptions : OptionSet{ + var rawValue: UInt - init(_ value: UInt) { self.value = value } - func toRaw() -> UInt { return self.value } + init(rawValue: RawValue) { + self.rawValue = rawValue + } + + typealias RawValue = UInt // conforms to BooleanType var boolValue: Bool { get { - return self.value != 0 + return self.rawValue != 0 } } // conforms to RawOptionSetType - static func fromMask(raw: UInt) -> XMLReaderOptions { return self(raw) } + static func fromMask(raw: UInt) -> XMLReaderOptions { return self.init(rawValue: raw) } - static func fromRaw(raw: UInt) -> XMLReaderOptions? { return self(raw) } + static func fromRaw(raw: UInt) -> XMLReaderOptions? { return self.init(rawValue: raw) } // conforms to NilLiteralConvertible - static func convertFromNilLiteral() -> XMLReaderOptions { return self(0) } + static func convertFromNilLiteral() -> XMLReaderOptions { return self.init(rawValue: 0) } // Options - static var None: XMLReaderOptions { return self(0) } + static var None: XMLReaderOptions { return self.init(rawValue: 0) } /// Specifies whether the receiver reports the namespace and the qualified name of an element. - static var ProcessNamespaces: XMLReaderOptions { return XMLReaderOptions(1 << 0) } + static var ProcessNamespaces: XMLReaderOptions { return XMLReaderOptions(rawValue: 1 << 0) } /// Specifies whether the receiver reports the scope of namespace declarations. - static var ReportNamespacePrefixes: XMLReaderOptions { return XMLReaderOptions(1 << 1) } + static var ReportNamespacePrefixes: XMLReaderOptions { return XMLReaderOptions(rawValue: 1 << 1) } /// Specifies whether the receiver reports declarations of external entities. - static var ResolveExternalEntities: XMLReaderOptions { return XMLReaderOptions(1 << 2) } + static var ResolveExternalEntities: XMLReaderOptions { return XMLReaderOptions(rawValue: 1 << 2) } } // conforms to Equatable func == (lhs: XMLReaderOptions, rhs: XMLReaderOptions) -> Bool { - return lhs.value == rhs.value + return lhs.rawValue == rhs.rawValue +} + +enum XMLReaderError : Error { + + case invalidEncoding + case unknownValueType + } /// -class XMLReader: NSObject, NSXMLParserDelegate { +class XMLReader: NSObject, XMLParserDelegate { var dictionaryStack: [XMLDictionary] var textInProgress: String - var error: NSError? + var error: Error? override init() { self.dictionaryStack = [] @@ -91,7 +82,7 @@ class XMLReader: NSObject, NSXMLParserDelegate { :param: data :param: completion */ - class func parse(#data: NSData, completion: (xml: NSDictionary, error: NSError?) -> ()) { + class func parse(data: NSData, completion: @escaping (_ xml: NSDictionary, _ error: Error?) -> ()) { let reader = XMLReader() reader.parse(data: data, options: .None, completion: completion) } @@ -102,8 +93,11 @@ class XMLReader: NSObject, NSXMLParserDelegate { :param: string :param: completion */ - class func parse(#string: NSString, completion: (xml: NSDictionary, error: NSError?) -> ()) { - let data = string.dataUsingEncoding(NSUTF8StringEncoding) + class func parse(string: NSString, completion: @escaping (_ xml: NSDictionary, _ error: Error?) -> ()) { + guard let data = (string as String).data(using: .utf8) as NSData? else { + completion([:], XMLReaderError.invalidEncoding as NSError) + return + } XMLReader.parse(data: data, completion: completion) } @@ -114,7 +108,7 @@ class XMLReader: NSObject, NSXMLParserDelegate { :param: options :param: completion */ - class func parse(#data: NSData, options: XMLReaderOptions, completion: (xml: NSDictionary, error: NSError?) -> ()) { + class func parse(data: NSData, options: XMLReaderOptions, completion: @escaping (_ xml: NSDictionary, _ error: Error?) -> ()) { let reader = XMLReader() reader.parse(data: data, options: options, completion: completion) } @@ -126,8 +120,11 @@ class XMLReader: NSObject, NSXMLParserDelegate { :param: options :param: completion */ - class func parse(#string: NSString, options: XMLReaderOptions, completion: (xml: NSDictionary, error: NSError?) -> ()) { - let data = string.dataUsingEncoding(NSUTF8StringEncoding) + class func parse(string: NSString, options: XMLReaderOptions, completion: @escaping (_ xml: NSDictionary, _ error: Error?) -> ()) { + guard let data = (string as String).data(using: .utf8) as NSData? else { + completion([:], XMLReaderError.invalidEncoding as NSError) + return + } XMLReader.parse(data: data, options: options, completion: completion) } @@ -139,20 +136,19 @@ class XMLReader: NSObject, NSXMLParserDelegate { :returns: */ - func parse(#data: NSData, options: XMLReaderOptions, completion: (xml: NSDictionary, error: NSError?) -> ()) + func parse(data: NSData, options: XMLReaderOptions, completion: @escaping (_ xml: NSDictionary, _ error: Error?) -> ()) { - let parser: NSXMLParser = NSXMLParser(data: data) + let parser: XMLParser = XMLParser(data: data as Data) parser.shouldProcessNamespaces = (options == .ProcessNamespaces) parser.shouldReportNamespacePrefixes = (options == .ReportNamespacePrefixes) parser.shouldResolveExternalEntities = (options == .ResolveExternalEntities) parser.delegate = self; - - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)) { + DispatchQueue.global(qos: .background).async { parser.parse() - dispatch_async(dispatch_get_main_queue()) { - completion(xml: self.dictionaryStack.first!, error: self.error) + DispatchQueue.main.async { + completion((self.dictionaryStack.first! as NSDictionary), self.error) } } } @@ -161,10 +157,7 @@ class XMLReader: NSObject, NSXMLParserDelegate { // MARK: - NSXMLParserDelegate // sent when the parser begins parsing of the document. - func parserDidStartDocument(parser: NSXMLParser!) - { - NSLog("parserDidStartDocument") - + func parserDidStartDocument(_ parser: XMLParser) { // Clear out any old data self.dictionaryStack = []; self.textInProgress = "" @@ -174,15 +167,12 @@ class XMLReader: NSObject, NSXMLParserDelegate { } // sent when the parser has completed parsing. If this is encountered, the parse was successful. - func parserDidEndDocument(parser: NSXMLParser!) + func parserDidEndDocument(_ parser: XMLParser) { - NSLog("parserDidEndDocument") + } - func parser(parser: NSXMLParser!, didStartElement elementName: String!, namespaceURI: String!, qualifiedName qName: String!, attributes attributeDict: [NSObject : AnyObject]!) - { - NSLog("didStartElement") - + func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) { // Get the dictionary for the current level in the stack var parentDict: XMLDictionary? = self.dictionaryStack.last @@ -191,50 +181,47 @@ class XMLReader: NSObject, NSXMLParserDelegate { // Add new values for (k, v) in attributeDict { - childDict.updateValue(v, forKey: k as String) + childDict.updateValue(v as AnyObject, forKey: k as String) } // If there's already an item for this key, it means we need to create an array if let existingValue: AnyObject = parentDict![elementName] { var array: [XMLDictionary]? = nil - if existingValue is [XMLDictionary] { + if let existingValue = existingValue as? [XMLDictionary] { // The array exists, so use it - array! = existingValue as [XMLDictionary] - } else if existingValue is XMLDictionary { + array! = existingValue + } else if let existingValue = existingValue as? XMLDictionary { // Create an array if it doesn't exist array! = [XMLDictionary]() - array!.append(existingValue as XMLDictionary) + array!.append(existingValue) // Replace the child dictionary with an array of children dictionaries - parentDict!.updateValue(array!, forKey: elementName) + parentDict!.updateValue(array! as AnyObject, forKey: elementName) } else { - NSLog("Something weird happened") + self.error = XMLReaderError.unknownValueType } // Add the new child dictionary to the array array!.append(childDict) } else { // No existing value, so update the dictionary - parentDict!.updateValue(childDict, forKey: elementName) + parentDict!.updateValue(childDict as AnyObject, forKey: elementName) } // Update the stack self.dictionaryStack.append(childDict) } - func parser(parser: NSXMLParser!, didEndElement elementName: String!, namespaceURI: String!, qualifiedName qName: String!) - { - NSLog("didEndElement") - + func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) { // Update the parent dict with text info var dictInProgress: XMLDictionary? = self.dictionaryStack.last // Set the text property if !self.textInProgress.isEmpty { // Trim whitespaces and newlines when end of element is reached - dictInProgress![kXMLReaderTextNodeKey] = self.textInProgress.ltrim() - + dictInProgress![kXMLReaderTextNodeKey] = self.textInProgress.trimWhitespacesAndNewlines() as AnyObject + // Reset the text self.textInProgress = "" } @@ -243,19 +230,13 @@ class XMLReader: NSObject, NSXMLParserDelegate { self.dictionaryStack.removeLast() } - func parser(parser: NSXMLParser!, foundCharacters string: String!) - { - NSLog("foundCharacters: %s", string) - + func parser(_ parser: XMLParser, foundCharacters string: String) { // Build the text value self.textInProgress += string } - func parser(parser: NSXMLParser!, parseErrorOccurred parseError: NSError!) - { - NSLog("parseErrorOccurred: %@", parseError) - - self.error = parseError + func parser(_ parser: XMLParser, parseErrorOccurred parseError: Error) { + self.error = parseError as NSError } } diff --git a/swift/XMLReaderTests/Info.plist b/swift/XMLReaderTests/Info.plist index 9feb2fc..6d32c15 100644 --- a/swift/XMLReaderTests/Info.plist +++ b/swift/XMLReaderTests/Info.plist @@ -7,7 +7,7 @@ CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier - io.epershand.${PRODUCT_NAME:rfc1034identifier} + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName