@@ -42,7 +42,8 @@ extension XMLParser {
42
42
}
43
43
}
44
44
45
- private func UTF8STRING( _ bytes: UnsafePointer < UInt8 > ) -> String ? {
45
+ private func UTF8STRING( _ bytes: UnsafePointer < UInt8 > ? ) -> String ? {
46
+ guard let bytes = bytes else { return nil }
46
47
// strlen operates on the wrong type, char*. We can't rebind the memory to a different type without knowing it's length,
47
48
// but since we know strlen is in libc, its safe to directly bitcast the pointer without worrying about multiple accesses
48
49
// of different types visible to the compiler.
@@ -243,16 +244,10 @@ internal func _colonSeparatedStringFromPrefixAndSuffix(_ prefix: UnsafePointer<U
243
244
return " \( prefixString!) : \( suffixString!) "
244
245
}
245
246
246
- internal func _NSXMLParserStartElementNs( _ ctx: _CFXMLInterface , localname: UnsafePointer < UInt8 > , prefix: UnsafePointer < UInt8 > ? , URI: UnsafePointer < UInt8 > , nb_namespaces: Int32 , namespaces: UnsafeMutablePointer < UnsafePointer < UInt8 > ? > , nb_attributes: Int32 , nb_defaulted: Int32 , attributes: UnsafeMutablePointer < UnsafePointer < UInt8 > ? > ) -> Void {
247
+ internal func _NSXMLParserStartElementNs( _ ctx: _CFXMLInterface , localname: UnsafePointer < UInt8 > , prefix: UnsafePointer < UInt8 > ? , URI: UnsafePointer < UInt8 > ? , nb_namespaces: Int32 , namespaces: UnsafeMutablePointer < UnsafePointer < UInt8 > ? > , nb_attributes: Int32 , nb_defaulted: Int32 , attributes: UnsafeMutablePointer < UnsafePointer < UInt8 > ? > ) -> Void {
247
248
let parser = ctx. parser
248
- let reportQNameURI = parser. shouldProcessNamespaces
249
249
let reportNamespaces = parser. shouldReportNamespacePrefixes
250
- // Since strlen is in libc, it's safe to bitcast the UInt8 pointer argument to an Int8 (char *) pointer.
251
- let prefixLen = prefix != nil ? UInt ( strlen ( unsafeBitCast ( prefix!, to: UnsafePointer< Int8> . self ) ) ) : 0
252
- let localnameString = ( prefixLen == 0 || reportQNameURI) ? UTF8STRING ( localname) : nil
253
- let qualifiedNameString = prefixLen != 0 ? _colonSeparatedStringFromPrefixAndSuffix ( prefix!, UInt ( prefixLen) , localname, UInt ( strlen ( unsafeBitCast ( localname, to: UnsafePointer< Int8> . self ) ) ) ) : localnameString
254
- let namespaceURIString = reportQNameURI ? UTF8STRING ( URI) : nil
255
-
250
+
256
251
var nsDict = [ String: String] ( )
257
252
var attrDict = [ String: String] ( )
258
253
if nb_attributes + nb_namespaces > 0 {
@@ -274,7 +269,7 @@ internal func _NSXMLParserStartElementNs(_ ctx: _CFXMLInterface, localname: Unsa
274
269
nsDict [ k] = v
275
270
}
276
271
}
277
- if !reportQNameURI {
272
+ if !parser . shouldProcessNamespaces {
278
273
if let k = asAttrNamespaceNameString,
279
274
let v = namespaceValueString {
280
275
attrDict [ k] = v
@@ -323,37 +318,47 @@ internal func _NSXMLParserStartElementNs(_ ctx: _CFXMLInterface, localname: Unsa
323
318
}
324
319
325
320
}
326
-
327
- if let delegate = parser. delegate {
328
- if reportQNameURI {
329
- delegate. parser ( parser, didStartElement: localnameString!, namespaceURI: ( namespaceURIString != nil ? namespaceURIString : " " ) , qualifiedName: ( qualifiedNameString != nil ? qualifiedNameString : " " ) , attributes: attrDict)
330
- } else {
331
- delegate. parser ( parser, didStartElement: qualifiedNameString!, namespaceURI: nil , qualifiedName: nil , attributes: attrDict)
321
+
322
+ var elementName : String = UTF8STRING ( localname) !
323
+ var namespaceURI : String ? = nil
324
+ var qualifiedName : String ? = nil
325
+ if parser. shouldProcessNamespaces {
326
+ namespaceURI = UTF8STRING ( URI) ?? " "
327
+ qualifiedName = elementName
328
+ if let prefix = UTF8STRING ( prefix) {
329
+ qualifiedName = elementName + " : " + prefix
332
330
}
333
331
}
332
+ else if let prefix = UTF8STRING ( prefix) {
333
+ elementName = elementName + " : " + prefix
334
+ }
335
+
336
+ parser. delegate? . parser ( parser, didStartElement: elementName, namespaceURI: namespaceURI, qualifiedName: qualifiedName, attributes: attrDict)
334
337
}
335
338
336
- internal func _NSXMLParserEndElementNs( _ ctx: _CFXMLInterface , localname: UnsafePointer < UInt8 > , prefix: UnsafePointer < UInt8 > ? , URI: UnsafePointer < UInt8 > ) -> Void {
339
+ internal func _NSXMLParserEndElementNs( _ ctx: _CFXMLInterface , localname: UnsafePointer < UInt8 > , prefix: UnsafePointer < UInt8 > ? , URI: UnsafePointer < UInt8 > ? ) -> Void {
337
340
let parser = ctx. parser
338
- let reportQNameURI = parser. shouldProcessNamespaces
339
- let prefixLen = prefix != nil ? strlen ( unsafeBitCast ( prefix!, to: UnsafePointer< Int8> . self ) ) : 0
340
- let localnameString = ( prefixLen == 0 || reportQNameURI) ? UTF8STRING ( localname) : nil
341
- let nilStr : String ? = nil
342
- let qualifiedNameString = ( prefixLen != 0 ) ? _colonSeparatedStringFromPrefixAndSuffix ( prefix!, UInt ( prefixLen) , localname, UInt ( strlen ( unsafeBitCast ( localname, to: UnsafePointer< Int8> . self ) ) ) ) : nilStr
343
- let namespaceURIString = reportQNameURI ? UTF8STRING ( URI) : nilStr
344
-
345
-
346
- if let delegate = parser. delegate {
347
- if reportQNameURI {
348
- // When reporting namespace info, the delegate parameters are not passed in nil
349
- delegate. parser ( parser, didEndElement: localnameString!, namespaceURI: namespaceURIString == nil ? " " : namespaceURIString, qualifiedName: qualifiedNameString == nil ? " " : qualifiedNameString)
350
- } else {
351
- delegate. parser ( parser, didEndElement: qualifiedNameString!, namespaceURI: nil , qualifiedName: nil )
341
+
342
+ var elementName : String = UTF8STRING ( localname) !
343
+ var namespaceURI : String ? = nil
344
+ var qualifiedName : String ? = nil
345
+ if parser. shouldProcessNamespaces {
346
+ namespaceURI = UTF8STRING ( URI) ?? " "
347
+ qualifiedName = elementName
348
+ if let prefix = UTF8STRING ( prefix) {
349
+ qualifiedName = elementName + " : " + prefix
352
350
}
353
351
}
354
-
352
+ else if let prefix = UTF8STRING ( prefix) {
353
+ elementName = elementName + " : " + prefix
354
+ }
355
+
356
+ parser. delegate? . parser ( parser, didEndElement: elementName, namespaceURI: namespaceURI, qualifiedName: qualifiedName)
357
+
355
358
// Pop the last namespaces that were pushed (safe since XML is balanced)
356
- parser. _popNamespaces ( )
359
+ if parser. shouldReportNamespacePrefixes {
360
+ parser. _popNamespaces ( )
361
+ }
357
362
}
358
363
359
364
internal func _NSXMLParserCharacters( _ ctx: _CFXMLInterface , ch: UnsafePointer < UInt8 > , len: Int32 ) -> Void {
@@ -410,8 +415,10 @@ open class XMLParser : NSObject {
410
415
private var _handler : _CFXMLInterfaceSAXHandler
411
416
internal var _stream : InputStream ?
412
417
internal var _data : Data ?
418
+
413
419
internal var _chunkSize = Int ( 4096 * 32 ) // a suitably large number for a decent chunk size
414
- internal var _haveDetectedEncoding = false
420
+ // This chunk of data stores the head of the stream. We know we have enough information for encoding
421
+ // when there are atleast 4 bytes in here.
415
422
internal var _bomChunk : Data ?
416
423
fileprivate var _parserContext : _CFXMLInterfaceParserContext ?
417
424
internal var _delegateAborted = false
@@ -500,72 +507,52 @@ open class XMLParser : NSObject {
500
507
501
508
internal func parseData( _ data: Data ) -> Bool {
502
509
_CFXMLInterfaceSetStructuredErrorFunc ( interface, _structuredErrorFunc)
503
- var result = true
504
- /* The vast majority of this method just deals with ensuring we do a single parse
505
- on the first 4 received bytes before continuing on to the actual incremental section */
506
- if _haveDetectedEncoding {
507
- var totalLength = data. count
508
- if let chunk = _bomChunk {
509
- totalLength += chunk. count
510
- }
511
- if ( totalLength < 4 ) {
512
- if let chunk = _bomChunk {
513
- var newData = Data ( )
514
- newData. append ( chunk)
515
- newData. append ( data)
516
- _bomChunk = newData
517
- } else {
518
- _bomChunk = data
519
- }
520
- } else {
521
- var allExistingData : Data
522
- if let chunk = _bomChunk {
523
- var newData = Data ( )
524
- newData. append ( chunk)
525
- newData. append ( data)
526
- allExistingData = newData
527
- } else {
528
- allExistingData = data
529
- }
530
-
531
- var handler : _CFXMLInterfaceSAXHandler ? = nil
532
- if delegate != nil {
533
- handler = _handler
534
- }
535
-
536
- _parserContext = allExistingData. withUnsafeBytes { ( bytes: UnsafePointer < Int8 > ) -> _CFXMLInterfaceParserContext in
537
- return _CFXMLInterfaceCreatePushParserCtxt ( handler, interface, bytes, 4 , nil )
538
- }
539
510
540
- var options = _kCFXMLInterfaceRecover | _kCFXMLInterfaceNoEnt // substitute entities, recover on errors
541
- if shouldResolveExternalEntities {
542
- options |= _kCFXMLInterfaceDTDLoad
543
- }
544
-
545
- if handler == nil {
546
- options |= ( _kCFXMLInterfaceNoError | _kCFXMLInterfaceNoWarning)
547
- }
548
-
549
- _CFXMLInterfaceCtxtUseOptions ( _parserContext, options)
550
- _haveDetectedEncoding = true
551
- _bomChunk = nil
552
-
553
- if ( totalLength > 4 ) {
554
- let remainingData = allExistingData. withUnsafeMutableBytes { ( bytes: UnsafeMutablePointer < UInt8 > ) -> Data in
555
- let ptr = bytes. advanced ( by: 4 )
556
- return Data ( bytesNoCopy: ptr, count: totalLength - 4 , deallocator: . none)
557
- }
558
-
559
- let _ = parseData ( remainingData)
511
+ let handler : _CFXMLInterfaceSAXHandler ? = ( delegate != nil ? _handler : nil )
512
+ let unparsedData : Data
513
+ // If the parser context is nil, we have not received enough bytes to create the push parser
514
+ if _parserContext == nil {
515
+ // Look at the bomChunk and this data
516
+ let bomChunk : Data = {
517
+ guard var bomChunk = _bomChunk else {
518
+ return data
560
519
}
520
+ bomChunk. append ( data)
521
+ return bomChunk
522
+ } ( )
523
+ // If we have not received 4 bytes, save the bomChunk for next pass
524
+ if bomChunk. count < 4 {
525
+ _bomChunk = bomChunk
526
+ return false
561
527
}
562
- } else {
563
- let parseResult = data. withUnsafeBytes { ( bytes: UnsafePointer < Int8 > ) -> Int32 in
564
- return _CFXMLInterfaceParseChunk ( _parserContext, bytes, Int32 ( data. count) , 0 )
528
+ // Prepare options (substitute entities, recover on errors)
529
+ var options = _kCFXMLInterfaceRecover | _kCFXMLInterfaceNoEnt
530
+ if shouldResolveExternalEntities {
531
+ options |= _kCFXMLInterfaceDTDLoad
532
+ }
533
+ if handler == nil {
534
+ options |= ( _kCFXMLInterfaceNoError | _kCFXMLInterfaceNoWarning)
535
+ }
536
+
537
+ // Create the push context with the first 4 bytes
538
+ bomChunk. withUnsafeBytes { bytes in
539
+ _parserContext = _CFXMLInterfaceCreatePushParserCtxt ( handler, interface, bytes, 4 , nil )
565
540
}
566
-
567
- result = _handleParseResult ( parseResult)
541
+ _CFXMLInterfaceCtxtUseOptions ( _parserContext, options)
542
+ // Prepare the remaining data for parsing
543
+ let dataRange = bomChunk. indices
544
+ let unparsed = Range ( uncheckedBounds: ( dataRange. startIndex. advanced ( by: 4 ) , dataRange. endIndex) )
545
+ unparsedData = bomChunk. subdata ( in: unparsed)
546
+ }
547
+ else {
548
+ unparsedData = data
568
549
}
550
+
551
+ let parseResult = unparsedData. withUnsafeBytes { ( bytes: UnsafePointer < Int8 > ) -> Int32 in
552
+ return _CFXMLInterfaceParseChunk ( _parserContext, bytes, Int32 ( unparsedData. count) , 0 )
553
+ }
554
+
555
+ let result = _handleParseResult ( parseResult)
569
556
_CFXMLInterfaceSetStructuredErrorFunc ( interface, nil )
570
557
return result
571
558
}
@@ -745,13 +732,13 @@ public protocol XMLParserDelegate: class {
745
732
func parser( _ parser: XMLParser , resolveExternalEntityName name: String , systemID: String ? ) -> Data ?
746
733
// this gives the delegate an opportunity to resolve an external entity itself and reply with the resulting data.
747
734
748
- func parser( _ parser: XMLParser , parseErrorOccurred parseError: NSError )
735
+ func parser( _ parser: XMLParser , parseErrorOccurred parseError: Error )
749
736
// ...and this reports a fatal error to the delegate. The parser will stop parsing.
750
737
751
- func parser( _ parser: XMLParser , validationErrorOccurred validationError: NSError )
738
+ func parser( _ parser: XMLParser , validationErrorOccurred validationError: Error )
752
739
}
753
740
754
- extension XMLParserDelegate {
741
+ public extension XMLParserDelegate {
755
742
756
743
func parserDidStartDocument( _ parser: XMLParser ) { }
757
744
func parserDidEndDocument( _ parser: XMLParser ) { }
@@ -788,9 +775,9 @@ extension XMLParserDelegate {
788
775
789
776
func parser( _ parser: XMLParser , resolveExternalEntityName name: String , systemID: String ? ) -> Data ? { return nil }
790
777
791
- func parser( _ parser: XMLParser , parseErrorOccurred parseError: NSError ) { }
778
+ func parser( _ parser: XMLParser , parseErrorOccurred parseError: Error ) { }
792
779
793
- func parser( _ parser: XMLParser , validationErrorOccurred validationError: NSError ) { }
780
+ func parser( _ parser: XMLParser , validationErrorOccurred validationError: Error ) { }
794
781
}
795
782
796
783
extension XMLParser {
0 commit comments