Skip to content

Commit 7475bdf

Browse files
authored
Merge pull request #2877 from dhoepfl/SR-2301
2 parents df14b6e + 9d62092 commit 7475bdf

File tree

3 files changed

+47
-41
lines changed

3 files changed

+47
-41
lines changed

CoreFoundation/Parsing.subproj/CFXMLInterface.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
// This source file is part of the Swift.org open source project
22
//
3-
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
3+
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
44
// Licensed under Apache License v2.0 with Runtime Library Exception
55
//
66
// See http://swift.org/LICENSE.txt for license information
77
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
88
//
99

1010
/* CFXMLInterface.c
11-
Copyright (c) 2015 Apple Inc. and the Swift project authors
11+
Copyright (c) 2020 Apple Inc. and the Swift project authors
1212
*/
1313

1414
#include <CoreFoundation/CFRuntime.h>
@@ -216,7 +216,8 @@ void _CFXMLInterfaceCtxtUseOptions(_CFXMLInterfaceParserContext ctx, CFIndex opt
216216
}
217217

218218
int _CFXMLInterfaceParseChunk(_CFXMLInterfaceParserContext ctxt, const char *chunk, int size, int terminate) {
219-
return xmlParseChunk(ctxt, chunk, size, terminate);
219+
int ret = xmlParseChunk(ctxt, chunk, size, terminate);
220+
return ret == XML_ERR_DOCUMENT_END && terminate ? XML_ERR_OK : ret;
220221
}
221222

222223
void _CFXMLInterfaceStopParser(_CFXMLInterfaceParserContext ctx) {

Sources/FoundationXML/XMLParser.swift

Lines changed: 42 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// This source file is part of the Swift.org open source project
22
//
3-
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
3+
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
44
// Licensed under Apache License v2.0 with Runtime Library Exception
55
//
66
// See http://swift.org/LICENSE.txt for license information
@@ -486,8 +486,9 @@ open class XMLParser : NSObject {
486486
return false
487487
}
488488

489-
internal func parseData(_ data: Data) -> Bool {
489+
internal func parseData(_ data: Data, lastChunkOfData: Bool = false) -> Bool {
490490
_CFXMLInterfaceSetStructuredErrorFunc(interface, _structuredErrorFunc)
491+
defer { _CFXMLInterfaceSetStructuredErrorFunc(interface, nil) }
491492

492493
let handler: _CFXMLInterfaceSAXHandler? = (delegate != nil ? _handler : nil)
493494
let unparsedData: Data
@@ -504,7 +505,7 @@ open class XMLParser : NSObject {
504505
// If we have not received 4 bytes, save the bomChunk for next pass
505506
if bomChunk.count < 4 {
506507
_bomChunk = bomChunk
507-
return false
508+
return true
508509
}
509510
// Prepare options (substitute entities, recover on errors)
510511
var options = _kCFXMLInterfaceRecover | _kCFXMLInterfaceNoEnt
@@ -520,6 +521,12 @@ open class XMLParser : NSObject {
520521
let bytes = rawBuffer.baseAddress!.assumingMemoryBound(to: CChar.self)
521522
_parserContext = _CFXMLInterfaceCreatePushParserCtxt(handler, interface, bytes, 4, nil)
522523
}
524+
guard _parserContext != nil else {
525+
if _parserError == nil {
526+
_parserError = NSError(domain: XMLParser.errorDomain, code: ErrorCode.outOfMemoryError.rawValue)
527+
}
528+
return false
529+
};
523530
_CFXMLInterfaceCtxtUseOptions(_parserContext, options)
524531
// Prepare the remaining data for parsing
525532
let dataRange = bomChunk.indices
@@ -532,57 +539,54 @@ open class XMLParser : NSObject {
532539

533540
let parseResult = unparsedData.withUnsafeBytes { (rawBuffer: UnsafeRawBufferPointer) -> Int32 in
534541
let bytes = rawBuffer.baseAddress!.assumingMemoryBound(to: CChar.self)
535-
return _CFXMLInterfaceParseChunk(_parserContext, bytes, Int32(unparsedData.count), 0)
542+
return _CFXMLInterfaceParseChunk(_parserContext, bytes, Int32(unparsedData.count), lastChunkOfData ? 1 : 0)
536543
}
537544

538545
let result = _handleParseResult(parseResult)
539-
_CFXMLInterfaceSetStructuredErrorFunc(interface, nil)
540546
return result
541547
}
542548

543-
internal func parseFromStream() -> Bool {
549+
internal func parseFrom(_ stream : InputStream) -> Bool {
544550
var result = true
545-
XMLParser.setCurrentParser(self)
546-
defer { XMLParser.setCurrentParser(nil) }
547-
if let stream = _stream {
548-
stream.open()
549-
defer { stream.close() }
550-
let buffer = malloc(_chunkSize)!.bindMemory(to: UInt8.self, capacity: _chunkSize)
551-
defer { free(buffer) }
552-
var len = stream.read(buffer, maxLength: _chunkSize)
553-
if len != -1 {
554-
while len > 0 {
555-
let data = Data(bytesNoCopy: buffer, count: len, deallocator: .none)
556-
result = parseData(data)
557-
len = stream.read(buffer, maxLength: _chunkSize)
558-
}
559-
} else {
551+
552+
guard let buffer = malloc(_chunkSize)?.bindMemory(to: UInt8.self, capacity: _chunkSize) else { return false }
553+
defer { free(buffer) }
554+
555+
stream.open()
556+
defer { stream.close() }
557+
parseLoop: while result {
558+
switch stream.read(buffer, maxLength: _chunkSize) {
559+
case let len where len > 0:
560+
let data = Data(bytesNoCopy: buffer, count: len, deallocator: .none)
561+
result = parseData(data)
562+
case 0:
563+
result = parseData(Data(), lastChunkOfData: true)
564+
break parseLoop
565+
default: // See SR-13516, should be `case ..<0:`
560566
result = false
561-
}
562-
} else if var data = _data {
563-
let buffer = malloc(_chunkSize)!.bindMemory(to: UInt8.self, capacity: _chunkSize)
564-
defer { free(buffer) }
565-
var range = NSRange(location: 0, length: min(_chunkSize, data.count))
566-
while result {
567-
let chunk = data.withUnsafeMutableBytes { (rawBuffer: UnsafeMutableRawBufferPointer) -> Data in
568-
let ptr = rawBuffer.baseAddress!.advanced(by: range.location)
569-
return Data(bytesNoCopy: ptr, count: range.length, deallocator: .none)
570-
}
571-
result = parseData(chunk)
572-
if range.location + range.length >= data.count {
573-
break
567+
if _parserError == nil {
568+
_parserError = stream.streamError
574569
}
575-
range = NSRange(location: range.location + range.length, length: min(_chunkSize, data.count - (range.location + range.length)))
570+
571+
break parseLoop
576572
}
577-
} else {
578-
result = false
579573
}
574+
580575
return result
581576
}
582577

583578
// called to start the event-driven parse. Returns YES in the event of a successful parse, and NO in case of error.
584579
open func parse() -> Bool {
585-
return parseFromStream()
580+
XMLParser.setCurrentParser(self)
581+
defer { XMLParser.setCurrentParser(nil) }
582+
583+
if _stream != nil {
584+
return parseFrom(_stream!)
585+
} else if _data != nil {
586+
return parseData(_data!, lastChunkOfData: true)
587+
}
588+
589+
return false
586590
}
587591

588592
// called by the delegate to stop the parse. The delegate will get an error message sent to it.

Tests/Foundation/Tests/TestXMLParser.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ class TestXMLParser : XCTestCase {
9595
.foundCharacters("bar"),
9696
.didEndElement("foo", uri, namespaces ? "foo" : nil),
9797
.didEndElement("test", uri, namespaces ? "test" : nil),
98+
.endDocument,
9899
]
99100
}
100101

0 commit comments

Comments
 (0)