Line data Source code
1 0 : /*
2 :
3 : NSDataOOExtensions.m
4 :
5 : Extensions to NSData.
6 :
7 :
8 : Copyright (C) 2008-2013 Jens Ayton and contributors
9 :
10 : Permission is hereby granted, free of charge, to any person obtaining a copy
11 : of this software and associated documentation files (the "Software"), to deal
12 : in the Software without restriction, including without limitation the rights
13 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 : copies of the Software, and to permit persons to whom the Software is
15 : furnished to do so, subject to the following conditions:
16 :
17 : The above copyright notice and this permission notice shall be included in all
18 : copies or substantial portions of the Software.
19 :
20 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 : SOFTWARE.
27 :
28 : */
29 :
30 : #import "OOCocoa.h"
31 : #import "unzip.h"
32 :
33 0 : #define ZIP_BUFFER_SIZE 8192
34 :
35 : @implementation NSData (OOExtensions)
36 :
37 : + (instancetype) oo_dataWithOXZFile:(NSString *)path
38 : {
39 : NSUInteger i, cl;
40 : NSArray *components = [path pathComponents];
41 : cl = [components count];
42 : for (i = 0 ; i < cl ; i++)
43 : {
44 : NSString *component = [components objectAtIndex:i];
45 : if ([[[component pathExtension] lowercaseString] isEqualToString:@"oxz"])
46 : {
47 : break;
48 : }
49 : }
50 : // if i == cl then the path is entirely uncompressed
51 : if (i == cl)
52 : {
53 : /* -initWithContentsOfMappedFile fails quietly under OS X if there's no file,
54 : but GNUstep complains. */
55 : #if OOLITE_MAC_OS_X
56 : return [[[NSData alloc] initWithContentsOfMappedFile:path] autorelease];
57 : #else
58 : NSFileManager *fmgr = [NSFileManager defaultManager];
59 : BOOL dir;
60 :
61 : if ([fmgr fileExistsAtPath:path isDirectory:&dir])
62 : {
63 : if (!dir)
64 : {
65 : if ([[fmgr fileAttributesAtPath:path traverseLink:NO] fileSize] == 0)
66 : {
67 : OOLog(kOOLogFileNotFound, @"Expected file but found empty file at %@", path);
68 : }
69 : else
70 : {
71 : return [[[NSData alloc] initWithContentsOfMappedFile:path] autorelease];
72 : }
73 : }
74 : else
75 : {
76 : OOLog(kOOLogFileNotFound, @"Expected file but found directory at %@", path);
77 : }
78 : }
79 : return nil;
80 : #endif
81 : }
82 : // otherwise components 0..i are the OXZ path, and i+1..n are the
83 : // path inside the OXZ
84 : NSRange range;
85 : range.location = 0; range.length = i+1;
86 : NSString *zipFile = [NSString pathWithComponents:[components subarrayWithRange:range]];
87 : range.location = i+1; range.length = cl-(i+1);
88 : NSString *containedFile = [NSString pathWithComponents:[components subarrayWithRange:range]];
89 :
90 : unzFile uf = NULL;
91 : const char* zipname = [zipFile UTF8String];
92 : if (zipname != NULL)
93 : {
94 : uf = unzOpen64(zipname);
95 : }
96 : if (uf == NULL)
97 : {
98 : // This is not necessarily an error - the OXZ manager tries to
99 : // do this as a test for the presence of managed OXZs
100 : // OOLog(kOOLogFileNotFound, @"Could not unzip OXZ at %@", zipFile);
101 : return nil;
102 : }
103 : const char* filename = [containedFile UTF8String];
104 : // unzLocateFile(*, *, 1) = case-sensitive extract
105 : if (unzLocateFile(uf, filename, 1) != UNZ_OK)
106 : {
107 : unzClose(uf);
108 : /* Much of the time this function is called with the
109 : * expectation that the file may not necessarily exist -
110 : * e.g. on plist merges, config scans, etc. So don't add log
111 : * entries for this failure mode */
112 : // OOLog(kOOLogFileNotFound, @"Could not find %@ within OXZ at %@", containedFile, zipFile);
113 : return nil;
114 : }
115 :
116 : int err = UNZ_OK;
117 : unz_file_info64 file_info = {0};
118 : err = unzGetCurrentFileInfo64(uf, &file_info, NULL, 0, NULL, 0, NULL, 0);
119 : if (err != UNZ_OK)
120 : {
121 : unzClose(uf);
122 : OOLog(kOOLogFileNotFound, @"Could not get properties of %@ within OXZ at %@", containedFile, zipFile);
123 : return nil;
124 : }
125 :
126 : err = unzOpenCurrentFile(uf);
127 : if (err != UNZ_OK)
128 : {
129 : unzClose(uf);
130 : OOLog(kOOLogFileNotFound, @"Could not read %@ within OXZ at %@", containedFile, zipFile);
131 : return nil;
132 : }
133 :
134 :
135 :
136 : NSMutableData *tmp = [NSMutableData dataWithCapacity:file_info.uncompressed_size];
137 : void *buf = (void*)malloc(ZIP_BUFFER_SIZE);
138 : do
139 : {
140 : err = unzReadCurrentFile(uf, buf, ZIP_BUFFER_SIZE);
141 : if (err < 0)
142 : {
143 : OOLog(kOOLogFileNotFound, @"Could not read %@ within OXZ at %@ (err %d)", containedFile, zipFile, err);
144 : break;
145 : }
146 : if (err == 0)
147 : {
148 : break;
149 : }
150 : [tmp appendBytes:buf length:err];
151 : }
152 : while (err > 0);
153 : free(buf);
154 :
155 : err = unzCloseCurrentFile(uf);
156 : if (err != UNZ_OK)
157 : {
158 : unzClose(uf);
159 : OOLog(kOOLogFileNotFound, @"Could not close %@ within OXZ at %@", containedFile, zipFile);
160 : return nil;
161 : }
162 :
163 : unzClose(uf);
164 : return [[tmp retain] autorelease];
165 :
166 : }
167 :
168 : @end
|