Skip to content

Commit 7865d69

Browse files
authored
Implement NSArray writeToURL and initWithContentsOfURL (microsoft#2218)
Implement [NSArray writeToURL:atomically:], [NSArray arrayWithContentsOfURL:], and [NSArray initWithContentsOfURL:]. Fixes microsoft#2069
1 parent 2f10e0c commit 7865d69

File tree

3 files changed

+65
-33
lines changed

3 files changed

+65
-33
lines changed

Frameworks/Foundation/NSArray.mm

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737

3838
static const wchar_t* TAG = L"NSArray";
3939

40+
static const CFPropertyListFormat sc_plistFormat = kCFPropertyListBinaryFormat_v1_0;
41+
4042
@implementation NSArray
4143

4244
BASE_CLASS_REQUIRED_IMPLS(NSArray, NSArrayPrototype, CFArrayGetTypeID);
@@ -809,16 +811,14 @@ - (void)enumerateObjectsWithOptions:(NSEnumerationOptions)options usingBlock:(vo
809811
reverse = false;
810812
}
811813

812-
_enumerateWithBlock(enumerator,
813-
options,
814-
^(id key, BOOL* stop) {
815-
block(key, index, stop);
816-
if (reverse) {
817-
index--;
818-
} else {
819-
index++;
820-
}
821-
});
814+
_enumerateWithBlock(enumerator, options, ^(id key, BOOL* stop) {
815+
block(key, index, stop);
816+
if (reverse) {
817+
index--;
818+
} else {
819+
index++;
820+
}
821+
});
822822
}
823823

824824
/**
@@ -915,10 +915,10 @@ - (NSArray*)objectsAtIndexes:(NSIndexSet*)indexes {
915915
@Notes
916916
*/
917917
- (void)addObserver:(NSObject*)anObserver
918-
toObjectsAtIndexes:(NSIndexSet*)indexes
919-
forKeyPath:(NSString*)keyPath
920-
options:(NSKeyValueObservingOptions)options
921-
context:(void*)context {
918+
toObjectsAtIndexes:(NSIndexSet*)indexes
919+
forKeyPath:(NSString*)keyPath
920+
options:(NSKeyValueObservingOptions)options
921+
context:(void*)context {
922922
UNIMPLEMENTED();
923923
}
924924

@@ -939,12 +939,11 @@ - (void)removeObserver:(NSObject*)observer fromObjectsAtIndexes:(NSIndexSet*)ind
939939
}
940940

941941
/**
942-
@Status Stub
942+
@Status Interoperable
943943
@Notes
944944
*/
945945
+ (NSArray*)arrayWithContentsOfURL:(NSURL*)aURL {
946-
UNIMPLEMENTED();
947-
return StubReturn();
946+
return [[[self alloc] initWithContentsOfURL:aURL] autorelease];
948947
}
949948

950949
/**
@@ -996,21 +995,29 @@ - (NSIndexSet*)indexesOfObjectsAtIndexes:(NSIndexSet*)indexSet
996995
}
997996

998997
/**
999-
@Status Stub
998+
@Status Interoperable
1000999
@Notes
10011000
*/
10021001
- (NSArray*)initWithContentsOfURL:(NSURL*)aURL {
1003-
UNIMPLEMENTED();
1004-
return StubReturn();
1002+
NSData* data = [NSData dataWithContentsOfURL:aURL];
1003+
return static_cast<NSArray*>(
1004+
CFPropertyListCreateWithData(nullptr, static_cast<CFDataRef>(data), kCFPropertyListImmutable, nullptr, nullptr));
10051005
}
10061006

10071007
/**
1008-
@Status Stub
1009-
@Notes
1008+
@Status Caveat
1009+
@Notes Only file:// URLs supported. atomically parameter not supported.
10101010
*/
10111011
- (BOOL)writeToURL:(NSURL*)aURL atomically:(BOOL)flag {
1012-
UNIMPLEMENTED();
1013-
return StubReturn();
1012+
CFPropertyListRef plist = static_cast<CFPropertyListRef>(self);
1013+
if (CFPropertyListIsValid(plist, sc_plistFormat)) {
1014+
auto data = woc::AutoCF<CFDataRef>(CFPropertyListCreateData(nullptr, plist, sc_plistFormat, 0, nullptr));
1015+
if (data) {
1016+
return [static_cast<NSData*>(data.get()) writeToURL:aURL atomically:flag];
1017+
}
1018+
}
1019+
1020+
return NO;
10141021
}
10151022

10161023
/**

include/Foundation/NSArray.h

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,14 @@ FOUNDATION_EXPORT_CLASS
4242
+ (instancetype)array;
4343
+ (instancetype)arrayWithArray:(NSArray<ObjectType>*)anArray;
4444
+ (instancetype)arrayWithContentsOfFile:(NSString*)aPath;
45-
+ (instancetype)arrayWithContentsOfURL:(NSURL*)aURL STUB_METHOD;
45+
+ (instancetype)arrayWithContentsOfURL:(NSURL*)aURL;
4646
+ (instancetype)arrayWithObject:(ObjectType)anObject;
4747
+ (instancetype)arrayWithObjects:(ObjectType)firstObj, ...;
4848
+ (instancetype)arrayWithObjects:(const ObjectType _Nonnull[])objects count:(NSUInteger)count;
4949
- (instancetype)initWithArray:(NSArray<ObjectType>*)anArray;
5050
- (instancetype)initWithArray:(NSArray<ObjectType>*)array copyItems:(BOOL)flag;
5151
- (instancetype)initWithContentsOfFile:(NSString*)aPath;
52-
- (instancetype)initWithContentsOfURL:(NSURL*)aURL STUB_METHOD;
52+
- (instancetype)initWithContentsOfURL:(NSURL*)aURL;
5353
- (instancetype)initWithObjects:(ObjectType)firstObj, ...;
5454
- (instancetype)initWithObjects:(const ObjectType _Nonnull[])objects count:(NSUInteger)count;
5555
- (BOOL)containsObject:(ObjectType)anObject;
@@ -110,17 +110,17 @@ FOUNDATION_EXPORT_CLASS
110110
- (NSString*)descriptionWithLocale:(id)locale STUB_METHOD;
111111
- (NSString*)descriptionWithLocale:(id)locale indent:(NSUInteger)level STUB_METHOD;
112112
- (BOOL)writeToFile:(NSString*)path atomically:(BOOL)flag;
113-
- (BOOL)writeToURL:(NSURL*)aURL atomically:(BOOL)flag STUB_METHOD;
113+
- (BOOL)writeToURL:(NSURL*)aURL atomically:(BOOL)flag;
114114
- (NSArray<NSString*>*)pathsMatchingExtensions:(NSArray<NSString*>*)filterTypes;
115115
- (void)removeObserver:(NSObject*)observer
116-
fromObjectsAtIndexes:(NSIndexSet*)indexes
116+
fromObjectsAtIndexes:(NSIndexSet*)indexes
117+
forKeyPath:(NSString*)keyPath
118+
context:(void*)context STUB_METHOD;
119+
- (void)addObserver:(NSObject*)anObserver
120+
toObjectsAtIndexes:(NSIndexSet*)indexes
117121
forKeyPath:(NSString*)keyPath
122+
options:(NSKeyValueObservingOptions)options
118123
context:(void*)context STUB_METHOD;
119-
- (void)addObserver:(NSObject*)anObserver
120-
toObjectsAtIndexes:(NSIndexSet*)indexes
121-
forKeyPath:(NSString*)keyPath
122-
options:(NSKeyValueObservingOptions)options
123-
context:(void*)context STUB_METHOD;
124124
- (void)removeObserver:(NSObject*)anObserver fromObjectsAtIndexes:(NSIndexSet*)indexes forKeyPath:(NSString*)keyPath STUB_METHOD;
125125
- (void)setValue:(id)value forKey:(NSString*)key;
126126
- (id)valueForKey:(NSString*)key;

tests/unittests/Foundation/NSArrayTests.mm

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,4 +434,29 @@ static unsigned long int objectIndexInArray(NSArray* array, int value, int start
434434
EXPECT_ANY_THROW([arr replaceObjectAtIndex:0 withObject:nil]);
435435
EXPECT_OBJCEQ(@"hello", arr[0]);
436436
EXPECT_EQ(1, [arr count]);
437+
}
438+
439+
TEST(NSArray, ReadWriteURL) {
440+
NSURL* url = [NSURL fileURLWithPath:@"arrayTestData.txt" isDirectory:NO];
441+
NSArray* arr = @[ @1, @[ @2, @"3" ], @"4", @{ @"5" : @6 } ];
442+
EXPECT_TRUE([arr writeToURL:url atomically:NO]);
443+
NSArray* read = [NSArray arrayWithContentsOfURL:url];
444+
EXPECT_OBJCEQ(arr, read);
445+
}
446+
447+
TEST(NSArray, ShouldNotBeAbleToWriteInvalidToURL) {
448+
NSURL* url = [NSURL fileURLWithPath:@"arrayTestData.txt" isDirectory:NO];
449+
450+
// Keys in dictionary must be NSString* to be written
451+
NSArray* arr = @[ @1, @{ @2 : @"3" } ];
452+
EXPECT_FALSE([arr writeToURL:url atomically:NO]);
453+
454+
// NSURL* is not a PropertyList object so cannot be written
455+
NSArray* arr2 = @[ url, @1 ];
456+
EXPECT_FALSE([arr2 writeToURL:url atomically:NO]);
457+
458+
// Array cannot have a circular dependency
459+
NSMutableArray* mutableArr = [NSMutableArray arrayWithObject:@1];
460+
[mutableArr addObject:mutableArr];
461+
EXPECT_FALSE([mutableArr writeToURL:url atomically:NO]);
437462
}

0 commit comments

Comments
 (0)