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 "OOoMetaDataParser.h"
25
26static NSSet *singleValueXMLElements;
27static NSSet *multiValueXMLElements;
28static NSDictionary *metaXML2MDIKeys;
29
30@implementation OOoMetaDataParser
31
32+ (void)initialize
33{
34    static BOOL isInitialized = NO;
35
36    if (isInitialized == NO) {
37        //set up the meta elements with only one value
38        NSMutableSet *temp = [NSMutableSet new];
39        [temp addObject:@"dc:title"];
40        [temp addObject:@"dc:description"];
41        [temp addObject:@"meta:user-defined"];
42        singleValueXMLElements = [[NSSet setWithSet:temp] retain];
43
44        //set up the meta elements that can have more than one value
45        [temp removeAllObjects];
46        [temp addObject:@"dc:subject"];
47        [temp addObject:@"meta:keyword"];
48        [temp addObject:@"meta:initial-creator"];
49        [temp addObject:@"dc:creator"];
50        multiValueXMLElements = [[NSSet setWithSet:temp] retain];
51        [temp release];
52
53        //set up the map to store the values with the correct MDI keys
54        NSMutableDictionary *tempDict = [NSMutableDictionary new];
55        [tempDict setObject:(NSString*)kMDItemTitle forKey:@"dc:title"];
56        [tempDict setObject:(NSString*)kMDItemDescription forKey:@"dc:description"];
57        [tempDict setObject:(NSString*)kMDItemKeywords forKey:@"dc:subject"];
58        [tempDict setObject:(NSString*)kMDItemAuthors forKey:@"meta:initial-creator"];
59        [tempDict setObject:(NSString*)kMDItemAuthors forKey:@"dc:creator"];
60        [tempDict setObject:(NSString*)kMDItemKeywords forKey:@"meta:keyword"];
61        [tempDict setObject:@"org_openoffice_opendocument_custominfo1" forKey:@"Info 1"];
62        [tempDict setObject:@"org_openoffice_opendocument_custominfo2" forKey:@"Info 2"];
63        [tempDict setObject:@"org_openoffice_opendocument_custominfo3" forKey:@"Info 3"];
64        [tempDict setObject:@"org_openoffice_opendocument_custominfo4" forKey:@"Info 4"];
65        metaXML2MDIKeys = [[NSDictionary dictionaryWithDictionary:tempDict] retain];
66        [tempDict release];
67
68        isInitialized = YES;
69    }
70}
71
72- (id)init
73{
74    if ((self = [super init]) != nil) {
75        shouldReadCharacters = NO;
76//        currentElement = nil;
77        textCurrentElement = nil;
78
79        return self;
80    }
81
82    return nil;
83}
84
85- (void)parseXML:(NSData*)data intoDictionary:(NSMutableDictionary*)dict
86{
87    metaValues = dict;
88
89    //NSLog(@"data: %@ %d", data, [data length]);
90
91    //init parser settings
92    shouldReadCharacters = NO;
93
94    NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
95
96    [parser setDelegate:self];
97    [parser setShouldResolveExternalEntities:NO];
98    [parser parse];
99
100    [parser release];
101
102    //NSLog(@"finished parsing meta");
103}
104
105- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict
106{
107//    NSLog(@"<%@>", elementName);
108    if ([singleValueXMLElements containsObject:elementName] == YES) {
109        shouldReadCharacters = YES;
110    } else if ([multiValueXMLElements containsObject:elementName] == YES) {
111        shouldReadCharacters = YES;
112    } else {
113        //we are not interested in this element
114        shouldReadCharacters = NO;
115        return;
116    }
117
118    if (shouldReadCharacters == YES) {
119        textCurrentElement = [NSMutableString new];
120        isCustom = [elementName isEqualToString:@"meta:user-defined"];
121        if (isCustom == YES) {
122            customAttribute = [[attributeDict objectForKey:@"meta:name"] retain];
123            //NSLog(customAttribute);
124        }
125    }
126
127    //NSLog(@"start element %@", elementName);
128}
129
130- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
131{
132//    NSLog(@"</%@>", elementName);
133    if (shouldReadCharacters == YES) {
134        NSString *mdiName = nil;
135        if (isCustom == YES) {
136            mdiName = (NSString*)[metaXML2MDIKeys objectForKey:customAttribute];
137        } else {
138            mdiName = (NSString*)[metaXML2MDIKeys objectForKey:elementName];
139        }
140        //NSLog(@"mdiName: %@", mdiName);
141
142        if (mdiName == nil) {
143            return;
144        }
145
146        if ([singleValueXMLElements containsObject:elementName] == YES) {
147            [metaValues setObject:textCurrentElement forKey:mdiName];
148        } else {
149            // must be multi-value
150            NSMutableArray *arr = [metaValues objectForKey:mdiName];
151            if (arr == nil) {
152                // we have no array yet, create it
153                arr = [[NSMutableArray new] autorelease];
154                // and store it
155                [metaValues setObject:arr forKey:mdiName];
156            }
157            // only store an element once, no need for duplicates
158            if ([arr containsObject:textCurrentElement] == NO) {
159                [arr addObject:textCurrentElement];
160            }
161        }
162        // cleanup part 1
163        [textCurrentElement release];
164        if (customAttribute != nil) {
165            [customAttribute release];
166        }
167    }
168
169    //cleanup part 2
170    shouldReadCharacters = NO;
171    isCustom = NO;
172}
173
174- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
175{
176//    NSLog(@"%@", string);
177    if (shouldReadCharacters == NO) {
178        return;
179    }
180
181    // this delegate method might be called several times for a single element,
182    // so we have to collect the received data
183    [textCurrentElement appendString:string];
184
185    //NSLog(@"chars read: %@", string);
186}
187
188- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError
189{
190    //NSLog(@"parsing finished with error");
191    NSLog([NSString stringWithFormat:@"Error %i, Description: %@, Line: %i, Column: %i", [parseError code],
192        [[parser parserError] localizedDescription], [parser lineNumber],
193        [parser columnNumber]]);
194}
195
196@end
197