Skip to content

Commit f41bd30

Browse files
authored
Merge pull request #1958 from millenomi/fix-nsdata-bridging-4.x
[4.2] Fix PropertyListSerialization not doing a roundtrip of Data correctly.
2 parents cd14fe0 + 88e4b71 commit f41bd30

File tree

5 files changed

+134
-13
lines changed

5 files changed

+134
-13
lines changed

CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,13 @@ struct _NSNumberBridge {
239239
bool (*_Nonnull _getValue)(CFTypeRef number, void *value, CFNumberType type);
240240
};
241241

242+
struct _NSDataBridge {
243+
_Nonnull CFTypeRef (*_Nonnull copy)(CFTypeRef obj);
244+
CFIndex (*_Nonnull length)(CFTypeRef obj);
245+
const void *_Nonnull (*_Nonnull bytePtr)(CFTypeRef obj);
246+
void (*_Nonnull getBytes)(CFTypeRef obj, CFRange range, void *_Nonnull buffer);
247+
};
248+
242249
struct _CFSwiftBridge {
243250
struct _NSObjectBridge NSObject;
244251
struct _NSArrayBridge NSArray;
@@ -254,6 +261,7 @@ struct _CFSwiftBridge {
254261
struct _NSCharacterSetBridge NSCharacterSet;
255262
struct _NSMutableCharacterSetBridge NSMutableCharacterSet;
256263
struct _NSNumberBridge NSNumber;
264+
struct _NSDataBridge NSData;
257265
};
258266

259267
CF_EXPORT struct _CFSwiftBridge __CFSwiftBridge;
@@ -423,6 +431,14 @@ static inline unsigned int _dev_minor(dev_t rdev) {
423431
return minor(rdev);
424432
}
425433

434+
#pragma mark - Data Functions
435+
436+
CF_CROSS_PLATFORM_EXPORT CFDataRef _CFDataCreateCopyNoBridging(CFAllocatorRef allocator, CFDataRef data);
437+
CF_CROSS_PLATFORM_EXPORT const uint8_t *_CFDataGetBytePtrNoBridging(CFDataRef data);
438+
CF_CROSS_PLATFORM_EXPORT uint8_t *_CFDataGetMutableBytePtrNoBridging(CFDataRef data);
439+
CF_CROSS_PLATFORM_EXPORT void _CFDataGetBytesNoBridging(CFDataRef data, CFRange range, void *buffer);
440+
CF_CROSS_PLATFORM_EXPORT CFIndex _CFDataGetLengthNoBridging(CFDataRef data);
441+
426442
_CF_EXPORT_SCOPE_END
427443

428444
#endif /* __COREFOUNDATION_FORSWIFTFOUNDATIONONLY__ */

CoreFoundation/Collections.subproj/CFData.c

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -456,11 +456,13 @@ CFDataRef CFDataCreateWithBytesNoCopy(CFAllocatorRef allocator, const uint8_t *b
456456
return __CFDataInit(allocator, kCFImmutable, length, bytes, length, bytesDeallocator);
457457
}
458458

459-
CFDataRef CFDataCreateCopy(CFAllocatorRef allocator, CFDataRef data) {
459+
static CFDataRef _CFDataCreateCopyAllowingBridging(CFAllocatorRef allocator, CFDataRef data, Boolean allowBridging) {
460460
Boolean allowRetain = true;
461461
if (allowRetain) {
462-
CF_OBJC_FUNCDISPATCHV(CFDataGetTypeID(), CFDataRef, (NSData *)data, copy);
463-
CF_SWIFT_FUNCDISPATCHV(CFDataGetTypeID(), CFDataRef, (CFSwiftRef)data, NSObject.copyWithZone, NULL);
462+
if (allowBridging) {
463+
CF_OBJC_FUNCDISPATCHV(CFDataGetTypeID(), CFDataRef, (NSData *)data, copy);
464+
CF_SWIFT_FUNCDISPATCHV(CFDataGetTypeID(), CFDataRef, (CFSwiftRef)data, NSData.copy);
465+
}
464466

465467
// If the data isn't mutable...
466468
if (!__CFDataIsMutable(data)) {
@@ -485,6 +487,16 @@ CFDataRef CFDataCreateCopy(CFAllocatorRef allocator, CFDataRef data) {
485487
return __CFDataInit(allocator, kCFImmutable, length, CFDataGetBytePtr(data), length, NULL);
486488
}
487489

490+
CFDataRef CFDataCreateCopy(CFAllocatorRef allocator, CFDataRef data) {
491+
return _CFDataCreateCopyAllowingBridging(allocator, data, true);
492+
}
493+
494+
#if DEPLOYMENT_RUNTIME_SWIFT
495+
CF_CROSS_PLATFORM_EXPORT CFDataRef _CFDataCreateCopyNoBridging(CFAllocatorRef allocator, CFDataRef data) {
496+
return _CFDataCreateCopyAllowingBridging(allocator, data, false);
497+
}
498+
#endif
499+
488500
CF_PRIVATE CFMutableDataRef _CFDataCreateFixedMutableWithBuffer(CFAllocatorRef allocator, CFIndex capacity, const uint8_t *bytes, CFAllocatorRef bytesDeallocator) {
489501
return (CFMutableDataRef)__CFDataInit(allocator, kCFFixedMutable, capacity, bytes, 0, bytesDeallocator);
490502
}
@@ -501,9 +513,17 @@ CFMutableDataRef CFDataCreateMutableCopy(CFAllocatorRef allocator, CFIndex capac
501513

502514
CFIndex CFDataGetLength(CFDataRef data) {
503515
CF_OBJC_FUNCDISPATCHV(CFDataGetTypeID(), CFIndex, (NSData *)data, length);
516+
CF_SWIFT_FUNCDISPATCHV(CFDataGetTypeID(), CFIndex, (CFSwiftRef)data, NSData.length);
517+
__CFGenericValidateType(data, CFDataGetTypeID());
518+
return __CFDataLength(data);
519+
}
520+
521+
#if DEPLOYMENT_RUNTIME_SWIFT
522+
CF_CROSS_PLATFORM_EXPORT CFIndex _CFDataGetLengthNoBridging(CFDataRef data) {
504523
__CFGenericValidateType(data, CFDataGetTypeID());
505524
return __CFDataLength(data);
506525
}
526+
#endif
507527

508528
CF_PRIVATE uint8_t *_CFDataGetBytePtrNonObjC(CFDataRef data) {
509529
__CFGenericValidateType(data, CFDataGetTypeID());
@@ -512,21 +532,42 @@ CF_PRIVATE uint8_t *_CFDataGetBytePtrNonObjC(CFDataRef data) {
512532

513533
const uint8_t *CFDataGetBytePtr(CFDataRef data) {
514534
CF_OBJC_FUNCDISPATCHV(CFDataGetTypeID(), const uint8_t *, (NSData *)data, bytes);
535+
CF_SWIFT_FUNCDISPATCHV(CFDataGetTypeID(), const uint8_t *, (CFSwiftRef)data, NSData.bytePtr);
515536
return _CFDataGetBytePtrNonObjC(data);
516537
}
517538

539+
#if DEPLOYMENT_RUNTIME_SWIFT
540+
CF_CROSS_PLATFORM_EXPORT const uint8_t *_CFDataGetBytePtrNoBridging(CFDataRef data) {
541+
return _CFDataGetBytePtrNonObjC(data);
542+
}
543+
#endif
544+
518545
uint8_t *CFDataGetMutableBytePtr(CFMutableDataRef data) {
519546
CF_OBJC_FUNCDISPATCHV(CFDataGetTypeID(), uint8_t *, (NSMutableData *)data, mutableBytes);
520547
CFAssert1(__CFDataIsMutable(data), __kCFLogAssertion, "%s(): data is immutable", __PRETTY_FUNCTION__);
521548
return _CFDataGetBytePtrNonObjC(data);
522549
}
523550

551+
#if DEPLOYMENT_RUNTIME_SWIFT
552+
CF_CROSS_PLATFORM_EXPORT uint8_t *_CFDataGetMutableBytePtrNoBridging(CFDataRef data) {
553+
return _CFDataGetBytePtrNonObjC(data);
554+
}
555+
#endif
556+
524557
void CFDataGetBytes(CFDataRef data, CFRange range, uint8_t *buffer) {
525558
CF_OBJC_FUNCDISPATCHV(CFDataGetTypeID(), void, (NSData *)data, getBytes:(void *)buffer range:NSMakeRange(range.location, range.length));
559+
CF_SWIFT_FUNCDISPATCHV(CFDataGetTypeID(), void, (CFSwiftRef)data, NSData.getBytes, range, buffer);
526560
__CFDataValidateRange(data, range, __PRETTY_FUNCTION__);
527561
memmove(buffer, _CFDataGetBytePtrNonObjC(data) + range.location, range.length);
528562
}
529563

564+
#if DEPLOYMENT_RUNTIME_SWIFT
565+
CF_CROSS_PLATFORM_EXPORT void _CFDataGetBytesNoBridging(CFDataRef data, CFRange range, void *buffer) {
566+
__CFDataValidateRange(data, range, __PRETTY_FUNCTION__);
567+
memmove(buffer, _CFDataGetBytePtrNonObjC(data) + range.location, range.length);
568+
}
569+
#endif
570+
530571
/* Allocates new block of data with at least numNewValues more bytes than the current length. If clear is true, the new bytes up to at least the new length with be zeroed. */
531572
static void __CFDataGrow(CFMutableDataRef data, CFIndex numNewValues, Boolean clear) {
532573
CFIndex oldLength = __CFDataLength(data);

Foundation/NSData.swift

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -977,17 +977,28 @@ open class NSMutableData : NSData {
977977
super.init(base64Encoded: base64Data, options: options)
978978
}
979979

980+
open override var bytes: UnsafeRawPointer {
981+
return UnsafeRawPointer(_CFDataGetBytePtrNoBridging(_cfObject))
982+
}
983+
984+
open override func copy() -> Any {
985+
return _CFDataCreateCopyNoBridging(kCFAllocatorSystemDefault, _cfObject)._nsObject
986+
}
980987

981988
// MARK: - Funnel Methods
982989
/// A pointer to the data contained by the mutable data object.
983990
open var mutableBytes: UnsafeMutableRawPointer {
984-
return UnsafeMutableRawPointer(CFDataGetMutableBytePtr(_cfMutableObject))
991+
return UnsafeMutableRawPointer(_CFDataGetMutableBytePtrNoBridging(_cfMutableObject))
992+
}
993+
994+
open override func getBytes(_ buffer: UnsafeMutableRawPointer, range: NSRange) {
995+
return _CFDataGetBytesNoBridging(_cfObject, CFRange(range), buffer)
985996
}
986997

987998
/// The number of bytes contained in the mutable data object.
988999
open override var length: Int {
9891000
get {
990-
return CFDataGetLength(_cfObject)
1001+
return _CFDataGetLengthNoBridging(_cfObject)
9911002
}
9921003
set {
9931004
CFDataSetLength(_cfMutableObject, newValue)
@@ -1064,3 +1075,19 @@ extension NSData : _StructTypeBridgeable {
10641075
return Data._unconditionallyBridgeFromObjectiveC(self)
10651076
}
10661077
}
1078+
1079+
internal func _CFSwiftDataCreateCopy(_ data: AnyObject) -> Unmanaged<AnyObject> {
1080+
return Unmanaged<AnyObject>.passRetained((data as! NSData).copy() as! NSObject)
1081+
}
1082+
1083+
internal func _CFSwiftDataGetLength(_ data: AnyObject) -> CFIndex {
1084+
return CFIndex((data as! NSData).length)
1085+
}
1086+
1087+
internal func _CFSwiftDataGetBytePtr(_ data: AnyObject) -> UnsafeRawPointer {
1088+
return (data as! NSData).bytes
1089+
}
1090+
1091+
internal func _CFSwiftDataGetBytes(_ data: AnyObject, _ range: CFRange, _ buffer: UnsafeMutableRawPointer) {
1092+
(data as! NSData).getBytes(buffer, range: NSRange(range))
1093+
}

Foundation/NSSwiftRuntime.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,11 @@ internal func __CFInitializeSwift() {
286286
__CFSwiftBridge.NSNumber._getValue = _CFSwiftNumberGetValue
287287
__CFSwiftBridge.NSNumber.boolValue = _CFSwiftNumberGetBoolValue
288288

289+
__CFSwiftBridge.NSData.copy = _CFSwiftDataCreateCopy
290+
__CFSwiftBridge.NSData.bytePtr = _CFSwiftDataGetBytePtr
291+
__CFSwiftBridge.NSData.length = _CFSwiftDataGetLength
292+
__CFSwiftBridge.NSData.getBytes = _CFSwiftDataGetBytes
293+
289294
// __CFDefaultEightBitStringEncoding = UInt32(kCFStringEncodingUTF8)
290295
}
291296

TestFoundation/TestPropertyListSerialization.swift

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,6 @@
88
//
99

1010
class TestPropertyListSerialization : XCTestCase {
11-
static var allTests: [(String, (TestPropertyListSerialization) -> () throws -> Void)] {
12-
return [
13-
("test_BasicConstruction", test_BasicConstruction),
14-
("test_decodeData", test_decodeData),
15-
("test_decodeStream", test_decodeStream),
16-
]
17-
}
18-
1911
func test_BasicConstruction() {
2012
let dict = NSMutableDictionary(capacity: 0)
2113
// dict["foo"] = "bar"
@@ -79,4 +71,44 @@ class TestPropertyListSerialization : XCTestCase {
7971
XCTFail("value stored is not a string")
8072
}
8173
}
74+
75+
func test_roundtripBasicTypes() throws {
76+
let name: String = "my name"
77+
let age: Int = 100
78+
let data: Data = "helloworld".data(using: .utf8)!
79+
80+
let properties: [String: Any] = [
81+
"name": name,
82+
"age": age,
83+
"data": data
84+
]
85+
86+
// pack
87+
let serialized = try PropertyListSerialization.data(fromPropertyList: properties, format: .binary, options: 0)
88+
89+
// unpack
90+
let deserialized = try PropertyListSerialization.propertyList(from: serialized, options: [], format: nil)
91+
let dictionary = try (deserialized as? [String: Any]).unwrapped()
92+
93+
XCTAssertNotNil(dictionary["name"])
94+
XCTAssertNotNil(dictionary["name"] as? String)
95+
XCTAssertEqual(name, dictionary["name"] as? String)
96+
97+
XCTAssertNotNil(dictionary["age"])
98+
XCTAssertNotNil(dictionary["age"] as? Int)
99+
XCTAssertEqual(age, dictionary["age"] as? Int)
100+
101+
XCTAssertNotNil(dictionary["data"])
102+
XCTAssertNotNil(dictionary["data"] as? Data)
103+
XCTAssertEqual(data, dictionary["data"] as? Data)
104+
}
105+
106+
static var allTests: [(String, (TestPropertyListSerialization) -> () throws -> Void)] {
107+
return [
108+
("test_BasicConstruction", test_BasicConstruction),
109+
("test_decodeData", test_decodeData),
110+
("test_decodeStream", test_decodeStream),
111+
("test_roundtripBasicTypes", test_roundtripBasicTypes),
112+
]
113+
}
82114
}

0 commit comments

Comments
 (0)