Skip to content

Commit 3b79610

Browse files
committed
Added basic code documentation. Added a convenience method for writing contents to disk as part of NSDocument save routine.
1 parent a19d17c commit 3b79610

File tree

3 files changed

+275
-3
lines changed

3 files changed

+275
-3
lines changed

LSFileWrapper.h

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
//
22
// Copyright (c) 2013 Luke Scott
33
// https://github.com/lukescott/LSFileWrapper
4+
// Copyright (c) 2020 Adam Kopeć
5+
// https://github.com/admkopec/LSFileWrapper
46
// Distributed under MIT license
57
//
68

@@ -20,38 +22,225 @@ FOUNDATION_EXPORT const unsigned char LSFileWrapperVersionString[];
2022

2123
@interface LSFileWrapper : NSObject
2224

25+
/**
26+
* @brief Initializes a new LSFileWrapper of type File.
27+
*/
2328
- (id)initFile;
29+
30+
/**
31+
* @brief Initializes a new LSFileWrapper of type Directory.
32+
*/
2433
- (id)initDirectory;
34+
35+
/**
36+
* @brief Loads and initializes LSFileWrapper with the contents of supplied url.
37+
*
38+
* @param url The origin url from which LSFileWrapper should be loaded.
39+
* @param isDir Boolean indicating whether the passed url is a Directory. When unknown NO should be passed, as the method will automatically detect the correct wrapper type based on the supplied url.
40+
*/
2541
- (id)initWithURL:(NSURL *)url isDirectory:(BOOL)isDir;
2642

43+
// MARK: - File Wrapper Methods
44+
45+
/**
46+
* @brief Loads and returns the stored data as NSData.
47+
*
48+
* @warning Should only be called on the LSFileWrapper of type File.
49+
*
50+
* @return Stored data in the current LSFileWrapper as NSString.
51+
*/
2752
- (NSData *)data;
53+
54+
/**
55+
* @brief Loads and returns the stored data as NSString.
56+
*
57+
* @warning Should only be called on the LSFileWrapper of type File.
58+
*
59+
* @return Stored data in the current LSFileWrapper as NSString.
60+
*/
2861
- (NSString *)string;
62+
63+
/**
64+
* @brief Loads and returns the stored data as NSDictionary.
65+
*
66+
* @warning Should only be called on the LSFileWrapper of type File.
67+
*
68+
* @return Stored data in the current LSFileWrapper as NSDictionary.
69+
*/
2970
- (NSDictionary *)dictionary;
71+
3072
#if TARGET_OS_IPHONE || TARGET_OS_SIMULATOR
73+
/**
74+
* @brief Loads and returns the stored data as UIImage.
75+
*
76+
* @warning Should only be called on the LSFileWrapper of type File.
77+
*
78+
* @return Stored data in the current LSFileWrapper as UIImage.
79+
*/
3180
- (UIImage *)image;
3281
#else
82+
/**
83+
* @brief Loads and returns the stored data as NSImage.
84+
*
85+
* @warning Should only be called on the LSFileWrapper of type File.
86+
*
87+
* @return Stored data in the current LSFileWrapper as NSImage.
88+
*/
3389
- (NSImage *)image;
3490
#endif
3591

92+
/**
93+
* @brief Replaces currently stored contents with passed content.
94+
*
95+
* @warning Should only be called on the LSFileWrapper of type File.
96+
*
97+
* @param content New contents to store.
98+
*/
3699
- (void)updateContent:(id<NSObject>)content;
100+
101+
/**
102+
* @brief Clears currently stored contents.
103+
*
104+
* @warning Should only be called on the LSFileWrapper of type File.
105+
*/
37106
- (void)deleteContent;
38107

108+
// MARK: -
109+
39110
- (void)incReserve;
40111
- (void)decReserve;
41112
- (void)deleteUnreserved;
42113

114+
// MARK: - Directory Wrapper Methods
115+
116+
/**
117+
* @brief Finds child wrapper at supplied path in the current LSFileWrapper and its children traversing by path.
118+
*
119+
* @warning Should only be called on the LSFileWrapper of type Directory.
120+
*
121+
* @param path The path of child wrapper as NSString.
122+
*
123+
* @return Optional stored child wrapper as LSFileWrapper.
124+
*/
43125
- (LSFileWrapper *)fileWrapperWithPath:(NSString *)path;
126+
127+
/**
128+
* @brief Finds child wrapper at supplied path in the current LSFileWrapper and its children traversing by path.
129+
*
130+
* @warning Should only be called on the LSFileWrapper of type Directory.
131+
*
132+
* @param path The path of child wrapper as NSString.
133+
* @param create Boolean indicating if LSFileWrapper should be created at specified path when none is found.
134+
* @param isDir Boolean indicating if LSFileWrapper that should be created at specified path should be of type Directory.
135+
*
136+
* @return Optional stored child wrapper as LSFileWrapper.
137+
*/
44138
- (LSFileWrapper *)fileWrapperWithPath:(NSString *)path create:(BOOL)create isDirectory:(BOOL)isDir;
45139

140+
/**
141+
* @brief Adds a new child wrapper with the supplied name to the current LSFileWrapper. If a wrapper is already present with the same name, then the new wrapper will be saved under the returned named to prevent collisions.
142+
*
143+
* @warning Should only be called on the LSFileWrapper of type Directory.
144+
* @warning Actual returned wrapper name may be different than supplied filename.
145+
*
146+
* @param fileWrapper Child wrapper which should be added to current LSFileWrapper as LSFileWrapper.
147+
* @param filename Desired name of the child wrapper.
148+
*
149+
* @return Nil on error or the name of the added child wrapper as NSString.
150+
*/
46151
- (NSString *)addFileWrapper:(LSFileWrapper *)fileWrapper withFilename:(NSString *)filename;
152+
153+
/**
154+
* @brief Adds a new child wrapper with the supplied name to the current LSFileWrapper. If a wrapper is already present with the same name, then the new wrapper will replace it.
155+
*
156+
* @warning Should only be called on the LSFileWrapper of type Directory.
157+
* @warning This method will replace any wrappers currently stored under the supplied filename.
158+
*
159+
* @param fileWrapper Child wrapper which should be stored in the current LSFileWrapper as LSFileWrapper.
160+
* @param filename Name of the child wrapper.
161+
*/
47162
- (void)setFileWrapper:(LSFileWrapper *)fileWrapper withFilename:(NSString *)filename;
163+
164+
/**
165+
* @brief Removes the supplied child wrapper from the current LSFileWrapper.
166+
*
167+
* @warning Should only be called on the LSFileWrapper of type Directory.
168+
*
169+
* @param fileWrapper Child wrapper which should be added to current LSFileWrapper as LSFileWrapper.
170+
*/
48171
- (void)removeFileWrapper:(LSFileWrapper *)fileWrapper;
172+
173+
/**
174+
* @brief Adds a new child wrapper of type File with the supplied name to the current LSFileWrapper. If a wrapper is already present with the same name, then the new wrapper will be saved under the returned named to prevent collisions.
175+
*
176+
* @warning Should only be called on the LSFileWrapper of type Directory.
177+
* @warning Actual returned wrapper name may be different than supplied filename.
178+
*
179+
* @param content_ Content which should be added to current LSFileWrapper.
180+
* @param filename Desired name of the child file wrapper.
181+
*
182+
* @return Nil on error or the name of the added child file wrapper as NSString.
183+
*/
49184
- (NSString *)addContent:(id<NSObject>)content_ withFilename:(NSString *)filename;
185+
186+
/**
187+
* @brief Adds a new child wrapper of type File with the supplied name to the current LSFileWrapper. If a wrapper is already present with the same name, then the new wrapper will replace it.
188+
*
189+
* @warning Should only be called on the LSFileWrapper of type Directory.
190+
* @warning This method will replace any wrappers currently stored under the supplied filename.
191+
*
192+
* @param content_ Content which should be stored in the current LSFileWrapper.
193+
* @param filename Name of the child file wrapper.
194+
*/
50195
- (void)setContent:(id<NSObject>)content_ withFilename:(NSString *)filename;
51196

197+
// MARK: - Disk Write Methods
198+
199+
/**
200+
* @brief Writes only the modifications since last write call of the LSFileWrapper to passed url.
201+
*
202+
* @warning Should only be called on the Main LSFileWrapper.
203+
*
204+
* @param url NSURL where LSFileWrapper updates should be written to.
205+
* @param outError Optional pointer to NSError instance for error handling.
206+
*
207+
* @return Boolean indicating success or failure of the write operation.
208+
*/
52209
- (BOOL)writeUpdatesToURL:(NSURL *)url error:(NSError *__autoreleasing *)outError;
210+
211+
/**
212+
* @brief Writes all contents of LSFileWrapper to passed url.
213+
*
214+
* @warning Should only be called on the Main LSFileWrapper.
215+
*
216+
* @param url NSURL where LSFileWrapper should be written to.
217+
* @param outError Optional pointer to NSError instance for error handling.
218+
*
219+
* @return Boolean indicating success or failure of the write operation.
220+
*/
53221
- (BOOL)writeToURL:(NSURL *)url error:(NSError *__autoreleasing *)outError;
54222

223+
#if TARGET_OS_OSX
224+
/**
225+
* @brief Writes the contents of LSFileWrapper to passed url based on NSDocument save operation type.
226+
*
227+
* @discussion This method is designed to be used in NSDocument's writeToURL forSaveOperation.
228+
*
229+
* @warning Should only be called on the Main LSFileWrapper.
230+
*
231+
* @param url NSURL where LSFileWrapper should be written to.
232+
* @param saveOperation NSSaveOperationType passed from NSDcoument.
233+
* @param absoluteOriginalContentsURL Optional NSURL where the current NSDocument – LSFileWrapper contents are already present.
234+
* @param backupFileURL Optional NSURL for backup of current NSDocument.
235+
* @param outError Optional pointer to NSError instance for error handling.
236+
*
237+
* @return Boolean indicating success or failure of the write operation.
238+
*/
239+
- (BOOL)writeToURL:(NSURL *)url forSaveOperation:(NSSaveOperationType)saveOperation originalContentsURL:(NSURL *)absoluteOriginalContentsURL backupDocumentURL:(NSURL *)backupFileURL error:(NSError *__autoreleasing *)outError;
240+
#endif
241+
242+
// MARK: - Instance Properties
243+
55244
@property (readonly, strong, nonatomic) NSString *filename;
56245
@property (readonly, strong, nonatomic) NSString *fileType;
57246
@property (readonly, strong, nonatomic) NSMutableDictionary<NSString*, LSFileWrapper*> *fileWrappers;

LSFileWrapper.m

Lines changed: 83 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
//
22
// Copyright (c) 2013 Luke Scott
33
// https://github.com/lukescott/LSFileWrapper
4+
// Copyright (c) 2020 Adam Kopeć
5+
// https://github.com/admkopec/LSFileWrapper
46
// Distributed under MIT license
57
//
68

@@ -333,6 +335,85 @@ - (BOOL)writeToURL:(NSURL *)url error:(NSError *__autoreleasing *)outError {
333335
return [self writeUpdates:updates filemanager:[[NSFileManager alloc] init] error:outError];
334336
}
335337

338+
#if TARGET_OS_OSX
339+
- (BOOL)writeToURL:(NSURL *)url forSaveOperation:(NSSaveOperationType)saveOperation originalContentsURL:(nullable NSURL *)absoluteOriginalContentsURL backupDocumentURL:(nullable NSURL *)backupFileURL error:(NSError *__autoreleasing *)outError {
340+
[url startAccessingSecurityScopedResource];
341+
switch (saveOperation) {
342+
case NSAutosaveInPlaceOperation:
343+
// Auto overwrite
344+
case NSSaveOperation:
345+
// Overwrite
346+
if (backupFileURL) {
347+
// Optional Backup propagation
348+
[[NSFileManager defaultManager] copyItemAtURL:url toURL:backupFileURL error:nil];
349+
[backupFileURL setResourceValues:@{NSURLIsHiddenKey: @YES} error:nil];
350+
}
351+
if (absoluteOriginalContentsURL) {
352+
if (![self writeUpdatesToURL:absoluteOriginalContentsURL error:outError]) {
353+
[url stopAccessingSecurityScopedResource];
354+
return NO;
355+
}
356+
if (![url isEqual:absoluteOriginalContentsURL]) {
357+
if(![[NSFileManager defaultManager] copyItemAtURL:absoluteOriginalContentsURL toURL:url error:outError]) {
358+
[url stopAccessingSecurityScopedResource];
359+
return NO;
360+
}
361+
}
362+
} else {
363+
if(![self writeToURL:url error:outError]) {
364+
[url stopAccessingSecurityScopedResource];
365+
return NO;
366+
}
367+
}
368+
break;
369+
case NSAutosaveAsOperation:
370+
// Auto new with switch
371+
case NSSaveAsOperation:
372+
// New with switch
373+
if(![self writeToURL:url error:outError]) {
374+
[url stopAccessingSecurityScopedResource];
375+
return NO;
376+
}
377+
// Switches self to new NSURL
378+
if (self) {
379+
filename = [url lastPathComponent];
380+
writtenURL = url;
381+
isDirectory = YES;
382+
_reserve = 0;
383+
fileWrappers = [[NSMutableDictionary alloc] init];
384+
for (NSURL *childUrl in [[NSFileManager defaultManager] contentsOfDirectoryAtURL:url
385+
includingPropertiesForKeys:nil
386+
options:0
387+
error:nil]) {
388+
LSFileWrapper *fileWrapper = [[LSFileWrapper alloc] initWithURL:childUrl isDirectory:NO];
389+
[fileWrapper setParent:self];
390+
[fileWrappers setObject:fileWrapper forKey:[childUrl lastPathComponent]];
391+
}
392+
}
393+
[url setResourceValues:@{NSURLIsHiddenKey: @YES} error:nil];
394+
break;
395+
case NSAutosaveElsewhereOperation:
396+
// Auto totally new
397+
case NSSaveToOperation:
398+
// Totally new
399+
if(![self writeToURL:url error:outError]) {
400+
[url stopAccessingSecurityScopedResource];
401+
return NO;
402+
}
403+
[url setResourceValues:@{NSURLIsHiddenKey: @YES} error:nil];
404+
break;
405+
default:
406+
break;
407+
}
408+
BOOL success = [url setResourceValues:@{NSURLContentModificationDateKey: [NSDate date]} error:outError];
409+
[url stopAccessingSecurityScopedResource];
410+
if (!success) {
411+
return NO;
412+
}
413+
return YES;
414+
}
415+
#endif
416+
336417
@end
337418

338419
@implementation LSFileWrapper (Internal)
@@ -494,10 +575,10 @@ - (BOOL)writeImage:(NSImage *)image_ toURL:(NSURL *)url error:(NSError *__autore
494575
[image_ unlockFocus];
495576

496577
if ([extension isEqualToString:@"png"]) {
497-
imageData = [bitmapRep representationUsingType:NSPNGFileType properties:nil];
578+
imageData = [bitmapRep representationUsingType:NSPNGFileType properties:@{}];
498579
}
499580
else if ([extension isEqualToString:@"jpg"] || [extension isEqualToString:@"jpeg"]) {
500-
imageData = [bitmapRep representationUsingType:NSJPEGFileType properties:nil];
581+
imageData = [bitmapRep representationUsingType:NSJPEGFileType properties:@{}];
501582
}
502583

503584
return [imageData writeToURL:url options:NSDataWritingAtomic error:outError];

LSFileWrapper.xcodeproj/project.pbxproj

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@
157157
3B1C07B122D8922900244E2D /* Project object */ = {
158158
isa = PBXProject;
159159
attributes = {
160-
LastUpgradeCheck = 1100;
160+
LastUpgradeCheck = 1230;
161161
ORGANIZATIONNAME = "Adam Kopeć";
162162
TargetAttributes = {
163163
3B1C07B922D8922900244E2D = {
@@ -251,6 +251,7 @@
251251
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
252252
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
253253
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
254+
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
254255
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
255256
CLANG_WARN_STRICT_PROTOTYPES = YES;
256257
CLANG_WARN_SUSPICIOUS_MOVE = YES;
@@ -313,6 +314,7 @@
313314
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
314315
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
315316
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
317+
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
316318
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
317319
CLANG_WARN_STRICT_PROTOTYPES = YES;
318320
CLANG_WARN_SUSPICIOUS_MOVE = YES;

0 commit comments

Comments
 (0)