1/**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements.  See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership.  The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License.  You may obtain a copy of the License at
10 *
11 *   http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied.  See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24#import "OOoSpotlightImporter.h"
25#import "OOoMetaDataParser.h"
26#import "OOoContentDataParser.h"
27
28#define CASESENSITIVITY (0)
29#define BUFFER_SIZE (4096)
30
31/* a dictionary to hold the UTIs */
32static NSDictionary *uti2kind;
33
34@implementation OOoSpotlightImporter
35
36/* initialize is only called once the first time this class is loaded */
37+ (void)initialize
38{
39    static BOOL isInitialized = NO;
40    if (isInitialized == NO) {
41        NSMutableDictionary *temp = [NSMutableDictionary new];
42        [temp setObject:@"OpenOffice.org 1.0 Text" forKey:@"org.openoffice.text"];
43        [temp setObject:@"OpenDocument Text" forKey:@"org.oasis.opendocument.text"];
44        [temp setObject:@"OpenOffice.org 1.0 Spreadsheet" forKey:@"org.openoffice.spreadsheet"];
45        [temp setObject:@"OpenDocument Spreadsheet" forKey:@"org.oasis.opendocument.spreadsheet"];
46        [temp setObject:@"OpenOffice.org 1.0 Presentation" forKey:@"org.openoffice.presentation"];
47        [temp setObject:@"OpenDocument Presentation" forKey:@"org.oasis.opendocument.presentation"];
48        [temp setObject:@"OpenOffice.org 1.0 Drawing" forKey:@"org.openoffice.graphics"];
49        [temp setObject:@"OpenDocument Drawing" forKey:@"org.oasis.opendocument.graphics"];
50        [temp setObject:@"OpenOffice.org 1.0 Master" forKey:@"org.openoffice.text-master"];
51        [temp setObject:@"OpenDocument Master" forKey:@"org.oasis.opendocument.text-master"];
52        [temp setObject:@"OpenOffice.org 1.0 Formula" forKey:@"org.openoffice.formula"];
53        [temp setObject:@"OpenDocument Formula" forKey:@"org.oasis.opendocument.formula"];
54        [temp setObject:@"OpenOffice.org 1.0 Text Template" forKey:@"org.openoffice.text-template"];
55        [temp setObject:@"OpenDocument Text Template" forKey:@"org.oasis.opendocument.text-template"];
56        [temp setObject:@"OpenOffice.org 1.0 Spreadsheet Template" forKey:@"org.openoffice.spreadsheet-template"];
57        [temp setObject:@"OpenDocument Spreadsheet Template" forKey:@"org.oasis.opendocument.spreadsheet-template"];
58        [temp setObject:@"OpenOffice.org 1.0 Presentation Template" forKey:@"org.openoffice.presentation-template"];
59        [temp setObject:@"OpenDocument Presentation Template" forKey:@"org.oasis.opendocument.presentation-template"];
60        [temp setObject:@"OpenOffice.org 1.0 Drawing Template" forKey:@"org.openoffice.graphics-template"];
61        [temp setObject:@"OpenDocument Drawing Template" forKey:@"org.oasis.opendocument.graphics-template"];
62        [temp setObject:@"OpenOffice.org 1.0 Database" forKey:@"org.openoffice.database"];
63        [temp setObject:@"OpenDocument Chart" forKey:@"org.oasis.opendocument.chart"];
64
65        uti2kind = [[NSDictionary dictionaryWithDictionary:temp] retain];
66        [temp release];
67
68        isInitialized = YES;
69    }
70}
71
72/* importDocument is the real starting point for our plugin */
73- (BOOL)importDocument:(NSString*)pathToFile contentType:(NSString*)contentTypeUTI attributes:(NSMutableDictionary*)attributes
74{
75    //NSLog(contentTypeUTI);
76    //NSLog(pathToFile);
77
78    NSString *itemKind = [uti2kind objectForKey:contentTypeUTI];
79    if (itemKind != nil) {
80        [attributes setObject:itemKind forKey:(NSString*)kMDItemKind];
81    }
82
83    //first check to see if this is a valid zipped file that contains a file "meta.xml"
84    unzFile unzipFile = [self openZipFileAtPath:pathToFile];
85
86    //
87    if (unzipFile == nil) {
88        //NSLog(@"zip file not open");
89        return YES;
90    }
91
92    //first get the metadata
93    NSData *metaData = [self metaDataFileFromZip:unzipFile];
94    if (metaData == nil) {
95        unzClose(unzipFile);
96        return YES;
97    }
98
99    [metaData retain];
100
101    OOoMetaDataParser *parser = [OOoMetaDataParser new];
102    if (parser != nil) {
103	//parse and extract the data
104	[parser parseXML:metaData intoDictionary:attributes];
105    }
106
107    [metaData release];
108    [parser release];
109
110    //and now get the content
111    NSData *contentData = [self contentDataFileFromZip:unzipFile];
112    if (contentData == nil) {
113        unzClose(unzipFile);
114        return YES;
115    }
116
117    [contentData retain];
118
119    OOoContentDataParser *parser2 = [OOoContentDataParser new];
120    if (parser2 != nil) {
121	//parse and extract the data
122	[parser2 parseXML:contentData intoDictionary:attributes];
123    }
124
125    [contentData release];
126    [parser2 release];
127
128    unzClose(unzipFile);
129
130    return YES;
131}
132
133/* openZipFileAtPath returns the file as a valid data structure or nil otherwise*/
134- (unzFile)openZipFileAtPath:(NSString*)pathToFile
135{
136    unzFile unzipFile = nil;
137
138    const char *zipfilename = [pathToFile UTF8String];
139
140    if (zipfilename != nil)
141    {
142        unzipFile = unzOpen(zipfilename);
143    }
144
145    if (unzipFile == nil)
146    {
147        //NSLog(@"Cannot open %s",zipfilename);
148        return nil;
149    }
150
151    //NSLog(@"%s opened",zipfilename);
152
153    return unzipFile;
154}
155
156/* metaDataFileFromZip extracts the file meta.xml from the zip file and returns it as an NSData* structure
157   or nil if the metadata is not present */
158- (NSData*) metaDataFileFromZip:(unzFile)unzipFile
159{
160    //search and set the cursor to meta.xml
161    if (unzLocateFile(unzipFile, "meta.xml", CASESENSITIVITY) != UNZ_OK) {
162        //we hit an error, do cleanup
163        unzCloseCurrentFile(unzipFile);
164        return nil;
165    }
166
167    //open the current file
168    if (unzOpenCurrentFile(unzipFile) != UNZ_OK) {
169        //we hit an error, do cleanup
170        unzCloseCurrentFile(unzipFile);
171        unzClose(unzipFile);
172        return nil;
173    }
174
175    NSMutableData *data = [NSMutableData new];
176
177    unsigned buffer[BUFFER_SIZE];
178    int bytesRead = 0;
179    while ((bytesRead = unzReadCurrentFile(unzipFile, buffer, sizeof(buffer))) > 0) {
180        //append the data until we are finished
181        [data appendData:[NSData dataWithBytes:(const void *)buffer length:bytesRead]];
182    }
183
184    //we no longer need the file, so close it
185    unzCloseCurrentFile(unzipFile);
186
187    NSData *returnValue = [NSData dataWithData:data];
188    [data release];
189
190    return returnValue;
191}
192
193/* contentDataFileFromZip extracts the file content.xml from the zip file and returns it as an NSData* structure
194   or nil if the metadata is not present */
195- (NSData*) contentDataFileFromZip:(unzFile)unzipFile
196{
197    //search and set the cursor to content.xml
198    if (unzLocateFile(unzipFile, "content.xml", CASESENSITIVITY) != UNZ_OK) {
199        //we hit an error, do cleanup
200        unzCloseCurrentFile(unzipFile);
201        return nil;
202    }
203
204    //open the current file
205    if (unzOpenCurrentFile(unzipFile) != UNZ_OK) {
206        //we hit an error, do cleanup
207        unzCloseCurrentFile(unzipFile);
208        unzClose(unzipFile);
209        return nil;
210    }
211
212    NSMutableData *data = [NSMutableData new];
213
214    unsigned buffer[BUFFER_SIZE];
215    int bytesRead = 0;
216    while ((bytesRead = unzReadCurrentFile(unzipFile, buffer, sizeof(buffer))) > 0) {
217        //append the data
218        [data appendData:[NSData dataWithBytes:(const void *)buffer length:bytesRead]];
219    }
220
221    //we no longer need the file, so close it
222    unzCloseCurrentFile(unzipFile);
223
224    NSData *returnValue = [NSData dataWithData:data];
225    [data release];
226
227    return returnValue;
228}
229
230
231@end
232