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