15
15
#define CHUNK 16384
16
16
17
17
@interface SSZipArchive ()
18
- + (NSDate *)_dateFor1980 ;
18
+ + (NSDate *)_dateWithMSDOSFormat : ( UInt32 ) msdosDateTime ;
19
19
@end
20
20
21
21
@@ -60,7 +60,7 @@ + (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination o
60
60
int ret;
61
61
unsigned char buffer[4096 ] = {0 };
62
62
NSFileManager *fileManager = [NSFileManager defaultManager ];
63
- NSDate *nineteenEighty = [self _dateFor1980 ];
63
+ NSMutableSet *directoriesModificationDates = [[ NSMutableSet alloc ] init ];
64
64
65
65
do {
66
66
if ([password length ] == 0 ) {
@@ -102,15 +102,24 @@ + (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination o
102
102
strPath = [strPath stringByReplacingOccurrencesOfString: @" \\ " withString: @" /" ];
103
103
}
104
104
105
- NSString * fullPath = [destination stringByAppendingPathComponent: strPath];
105
+ NSString *fullPath = [destination stringByAppendingPathComponent: strPath];
106
+ NSError *err = nil ;
107
+ NSDate *modDate = [[self class ] _dateWithMSDOSFormat: (UInt32 )fileInfo.dosDate];
108
+ NSDictionary *directoryAttr = [NSDictionary dictionaryWithObjectsAndKeys: modDate, NSFileCreationDate , modDate, NSFileModificationDate , nil ];
106
109
107
110
if (isDirectory) {
108
- [fileManager createDirectoryAtPath: fullPath withIntermediateDirectories: YES attributes: nil error: nil ];
111
+ [fileManager createDirectoryAtPath: fullPath withIntermediateDirectories: YES attributes: directoryAttr error: &err ];
109
112
} else {
110
- [fileManager createDirectoryAtPath: [fullPath stringByDeletingLastPathComponent ] withIntermediateDirectories: YES attributes: nil error: nil ];
113
+ [fileManager createDirectoryAtPath: [fullPath stringByDeletingLastPathComponent ] withIntermediateDirectories: YES attributes: directoryAttr error: &err ];
111
114
}
115
+ if (nil != err) {
116
+ NSLog (@" [SSZipArchive] Error: %@ " , err.localizedDescription );
117
+ }
112
118
113
- if ([fileManager fileExistsAtPath: fullPath] && !isDirectory && !overwrite) {
119
+ [directoriesModificationDates addObject: [NSDictionary dictionaryWithObjectsAndKeys: fullPath, @" path" , modDate, @" modDate" , nil ]];
120
+
121
+
122
+ if ([fileManager fileExistsAtPath: fullPath] && !isDirectory && !overwrite) {
114
123
unzCloseCurrentFile (zip);
115
124
ret = unzGoToNextFile (zip);
116
125
continue ;
@@ -132,16 +141,15 @@ + (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination o
132
141
133
142
// Set the original datetime property
134
143
if (fileInfo.dosDate != 0 ) {
135
- NSDate *orgDate = [[NSDate alloc ] initWithTimeInterval: ( NSTimeInterval )fileInfo.dosDate sinceDate: nineteenEighty ];
144
+ NSDate *orgDate = [[self class ] _dateWithMSDOSFormat: ( UInt32 )fileInfo.dosDate];
136
145
NSDictionary *attr = [NSDictionary dictionaryWithObject: orgDate forKey: NSFileModificationDate ];
137
146
138
147
if (attr) {
139
148
if ([fileManager setAttributes: attr ofItemAtPath: fullPath error: nil ] == NO ) {
140
149
// Can't set attributes
141
- NSLog (@" Failed to set attributes" );
150
+ NSLog (@" [SSZipArchive] Failed to set attributes" );
142
151
}
143
152
}
144
- [orgDate release ];
145
153
}
146
154
}
147
155
@@ -152,6 +160,23 @@ + (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination o
152
160
// Close
153
161
unzClose (zip);
154
162
163
+ // The process of decompressing the .zip archive causes the modification times on the folders
164
+ // to be set to the present time. So, when we are done, they need to be explicitly set.
165
+ // set the modification date on all of the directories.
166
+ NSError * err = nil ;
167
+ for (NSDictionary * d in directoriesModificationDates) {
168
+ if (![[NSFileManager defaultManager ] setAttributes: [NSDictionary dictionaryWithObjectsAndKeys: [d objectForKey: @" modDate" ], NSFileModificationDate , nil ] ofItemAtPath: [d objectForKey: @" path" ] error: &err]) {
169
+ NSLog (@" [SSZipArchive] Set attributes failed for directory: %@ ." , [d objectForKey: @" path" ]);
170
+ }
171
+ if (err) {
172
+ NSLog (@" [SSZipArchive] Error setting directory file modification date attribute: %@ " ,err.localizedDescription );
173
+ }
174
+ }
175
+
176
+ #if !__has_feature(objc_arc)
177
+ [directoriesModificationDates release ];
178
+ #endif
179
+
155
180
return success;
156
181
}
157
182
@@ -167,7 +192,10 @@ + (BOOL)createZipFileAtPath:(NSString *)path withFilesAtPaths:(NSArray *)paths {
167
192
}
168
193
success = [zipArchive close ];
169
194
}
195
+
196
+ #if !__has_feature(objc_arc)
170
197
[zipArchive release ];
198
+ #endif
171
199
172
200
return success;
173
201
}
@@ -181,10 +209,12 @@ - (id)initWithPath:(NSString *)path {
181
209
}
182
210
183
211
212
+ #if !__has_feature(objc_arc)
184
213
- (void )dealloc {
185
- [_path release ];
214
+ [_path release ];
186
215
[super dealloc ];
187
216
}
217
+ #endif
188
218
189
219
190
220
- (BOOL )open {
@@ -249,25 +279,50 @@ - (BOOL)writeData:(NSData *)data filename:(NSString *)filename {
249
279
return YES ;
250
280
}
251
281
282
+
252
283
- (BOOL )close {
253
- NSAssert ((_zip != NULL ), @"Attempting to close an archive which was never opened");
284
+ NSAssert ((_zip != NULL ), @"[SSZipArchive] Attempting to close an archive which was never opened");
254
285
zipClose (_zip, NULL );
255
286
return YES ;
256
287
}
257
288
258
289
259
290
#pragma mark - Private
260
291
261
- + (NSDate *)_dateFor1980 {
262
- NSDateComponents *comps = [[NSDateComponents alloc ] init ];
263
- [comps setDay: 1 ];
264
- [comps setMonth: 1 ];
265
- [comps setYear: 1980 ];
292
+ // Format from http://newsgroups.derkeiler.com/Archive/Comp/comp.os.msdos.programmer/2009-04/msg00060.html
293
+ // Two consecutive words, or a longword, YYYYYYYMMMMDDDDD hhhhhmmmmmmsssss
294
+ // YYYYYYY is years from 1980 = 0
295
+ // sssss is (seconds/2).
296
+ //
297
+ // 3658 = 0011 0110 0101 1000 = 0011011 0010 11000 = 27 2 24 = 2007-02-24
298
+ // 7423 = 0111 0100 0010 0011 - 01110 100001 00011 = 14 33 2 = 14:33:06
299
+ + (NSDate *)_dateWithMSDOSFormat : (UInt32 )msdosDateTime {
300
+ static const UInt32 kYearMask = 0xFE000000 ;
301
+ static const UInt32 kMonthMask = 0x1E00000 ;
302
+ static const UInt32 kDayMask = 0x1F0000 ;
303
+ static const UInt32 kHourMask = 0xF800 ;
304
+ static const UInt32 kMinuteMask = 0x7E0 ;
305
+ static const UInt32 kSecondMask = 0x1F ;
306
+
266
307
NSCalendar *gregorian = [[NSCalendar alloc ] initWithCalendarIdentifier: NSGregorianCalendar ];
267
- NSDate *date = [gregorian dateFromComponents: comps ];
308
+ NSDateComponents *components = [[ NSDateComponents alloc ] init ];
268
309
269
- [comps release ];
310
+ NSAssert (0xFFFFFFFF == (kYearMask | kMonthMask | kDayMask | kHourMask | kMinuteMask | kSecondMask ), @"[SSZipArchive] MSDOS date masks don't add up");
311
+
312
+ [components setYear: 1980 + ((msdosDateTime & kYearMask ) >> 25 )];
313
+ [components setMonth: (msdosDateTime & kMonthMask ) >> 21 ];
314
+ [components setDay: (msdosDateTime & kDayMask ) >> 16 ];
315
+ [components setHour: (msdosDateTime & kHourMask ) >> 11 ];
316
+ [components setMinute: (msdosDateTime & kMinuteMask ) >> 5 ];
317
+ [components setSecond: (msdosDateTime & kSecondMask ) * 2 ];
318
+
319
+ NSDate *date = [NSDate dateWithTimeInterval: 0 sinceDate: [gregorian dateFromComponents: components]];
320
+
321
+ #if !__has_feature(objc_arc)
270
322
[gregorian release ];
323
+ [components release ];
324
+ #endif
325
+
271
326
return date;
272
327
}
273
328
0 commit comments