Skip to content

Commit

Permalink
[PropertyListSerialization] Possible implementation of `propertyList(…
Browse files Browse the repository at this point in the history
…with:options:format:)`

Currently toll-free bridging between InputStream and CFReadStream is not implemented, so `InputStream._stream` is exposed and used instead.
  • Loading branch information
ikesyo committed Jan 16, 2017
1 parent d83cbfd commit 5d1bdb5
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 15 deletions.
2 changes: 1 addition & 1 deletion Docs/Status.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ There is no _Complete_ status for test coverage because there are always additio
| `NSKeyedUnarchiver` | Mostly Complete | Substantial | `decodingFailurePolicy.set` remains unimplemented |
| `NSKeyedArchiverHelpers` | N/A | N/A | For internal use only |
| `NSCoder` | Incomplete | N/A | Decoding methods which require a concrete implementation remain unimplemented |
| `PropertyListSerialization` | Mostly Complete | Incomplete | `propertyList(with:options:format:)` remains unimplemented |
| `PropertyListSerialization` | Complete | Incomplete | |

* **XML**: A group of classes for parsing and representing XML documents and elements.

Expand Down
11 changes: 4 additions & 7 deletions Foundation/NSKeyedUnarchiver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ open class NSKeyedUnarchiver : NSCoder {

private enum Stream {
case data(Data)
case stream(InputStream)
case stream(CFReadStream)
}

private var _stream : Stream
Expand Down Expand Up @@ -74,7 +74,7 @@ open class NSKeyedUnarchiver : NSCoder {
return nil
}

let keyedUnarchiver = NSKeyedUnarchiver(stream: Stream.stream(unsafeBitCast(readStream, to: InputStream.self)))
let keyedUnarchiver = NSKeyedUnarchiver(stream: Stream.stream(readStream))
do {
try root = keyedUnarchiver.decodeTopLevelObject(forKey: NSKeyedArchiveRootObjectKey)
keyedUnarchiver.finishDecoding()
Expand Down Expand Up @@ -113,11 +113,8 @@ open class NSKeyedUnarchiver : NSCoder {
switch self._stream {
case .data(let data):
try plist = PropertyListSerialization.propertyList(from: data, options: [], format: &format)
case .stream(let inputStream):
try plist = PropertyListSerialization.propertyList(with: unsafeBitCast(inputStream, to: CFReadStream.self),
length: 0,
options: [],
format: &format)
case .stream(let readStream):
try plist = PropertyListSerialization.propertyList(with: readStream, options: [], format: &format)
}

guard let unwrappedPlist = plist as? Dictionary<String, Any> else {
Expand Down
6 changes: 3 additions & 3 deletions Foundation/NSPropertyList.swift
Original file line number Diff line number Diff line change
Expand Up @@ -88,12 +88,12 @@ open class PropertyListSerialization : NSObject {
}
}

internal class func propertyList(with stream: CFReadStream, length streamLength: Int, options opt: ReadOptions, format: UnsafeMutablePointer <PropertyListFormat>?) throws -> Any {
internal class func propertyList(with stream: CFReadStream, options opt: ReadOptions, format: UnsafeMutablePointer <PropertyListFormat>?) throws -> Any {
var fmt = kCFPropertyListBinaryFormat_v1_0
var error: Unmanaged<CFError>? = nil
let decoded = withUnsafeMutablePointer(to: &fmt) { (outFmt: UnsafeMutablePointer<CFPropertyListFormat>) -> NSObject? in
withUnsafeMutablePointer(to: &error) { (outErr: UnsafeMutablePointer<Unmanaged<CFError>?>) -> NSObject? in
return unsafeBitCast(CFPropertyListCreateWithStream(kCFAllocatorSystemDefault, stream, streamLength, CFOptionFlags(CFIndex(opt.rawValue)), outFmt, outErr), to: NSObject.self)
return unsafeBitCast(CFPropertyListCreateWithStream(kCFAllocatorSystemDefault, stream, 0, CFOptionFlags(CFIndex(opt.rawValue)), outFmt, outErr), to: NSObject.self)
}
}
#if os(OSX) || os(iOS)
Expand All @@ -109,6 +109,6 @@ open class PropertyListSerialization : NSObject {
}

open class func propertyList(with stream: InputStream, options opt: ReadOptions = [], format: UnsafeMutablePointer<PropertyListFormat>?) throws -> Any {
NSUnimplemented()
return try propertyList(with: stream._stream, options: opt, format: format)
}
}
2 changes: 1 addition & 1 deletion Foundation/NSStream.swift
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ open class Stream: NSObject {
// Subclassers are required to implement these methods.
open class InputStream: Stream {

private var _stream: CFReadStream!
internal let _stream: CFReadStream!

// reads up to length bytes into the supplied buffer, which must be at least of size len. Returns the actual number of bytes read.
open func read(_ buffer: UnsafeMutablePointer<UInt8>, maxLength len: Int) -> Int {
Expand Down
33 changes: 30 additions & 3 deletions TestFoundation/TestNSPropertyList.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ import SwiftXCTest
class TestNSPropertyList : XCTestCase {
static var allTests: [(String, (TestNSPropertyList) -> () throws -> Void)] {
return [
("test_BasicConstruction", test_BasicConstruction ),
("test_decode", test_decode ),
("test_BasicConstruction", test_BasicConstruction),
("test_decodeData", test_decodeData),
("test_decodeStream", test_decodeStream),
]
}

Expand All @@ -39,7 +40,7 @@ class TestNSPropertyList : XCTestCase {
XCTAssertEqual(data!.count, 42, "empty dictionary should be 42 bytes")
}

func test_decode() {
func test_decodeData() {
var decoded: Any?
var fmt = PropertyListSerialization.PropertyListFormat.binary
let path = testBundle().url(forResource: "Test", withExtension: "plist")
Expand All @@ -63,4 +64,30 @@ class TestNSPropertyList : XCTestCase {
XCTFail("value stored is not a string")
}
}

func test_decodeStream() {
var decoded: Any?
var fmt = PropertyListSerialization.PropertyListFormat.binary
let path = testBundle().url(forResource: "Test", withExtension: "plist")
let stream = InputStream(url: path!)!
stream.open()
do {
decoded = try withUnsafeMutablePointer(to: &fmt) { (format: UnsafeMutablePointer<PropertyListSerialization.PropertyListFormat>) -> Any in
return try PropertyListSerialization.propertyList(with: stream, options: [], format: format)
}
} catch {

}

XCTAssertNotNil(decoded)
let dict = decoded as! Dictionary<String, Any>
XCTAssertEqual(dict.count, 3)
let val = dict["Foo"]
XCTAssertNotNil(val)
if let str = val as? String {
XCTAssertEqual(str, "Bar")
} else {
XCTFail("value stored is not a string")
}
}
}

0 comments on commit 5d1bdb5

Please sign in to comment.