1/*
2  Copyright (C) 2000-2005 SKYRIX Software AG
3
4  This file is part of SOPE.
5
6  SOPE is free software; you can redistribute it and/or modify it under
7  the terms of the GNU Lesser General Public License as published by the
8  Free Software Foundation; either version 2, or (at your option) any
9  later version.
10
11  SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
12  WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
14  License for more details.
15
16  You should have received a copy of the GNU Lesser General Public
17  License along with SOPE; see the file COPYING.  If not, write to the
18  Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
19  02111-1307, USA.
20*/
21
22#include "DOMSaxHandler.h"
23#include "DOMImplementation.h"
24#include "DOMDocument.h"
25#include "DOMElement.h"
26#include "common.h"
27#include <SaxObjC/SaxObjC.h>
28
29@interface NSObject(LineInfoProtocol)
30- (void)setLine:(int)_line;
31@end
32
33@implementation DOMSaxHandler
34
35static BOOL printErrors = NO;
36
37- (id)initWithDOMImplementation:(id)_domImpl {
38  if ((self = [super init])) {
39    self->dom = [_domImpl retain];
40    self->maxErrorCount = 100; // this also includes NPSOBJ in HTML !
41  }
42  return self;
43}
44- (id)init {
45  static id idom = nil;
46
47  if (idom == nil)
48    idom = [[NGDOMImplementation alloc] init];
49
50  return [self initWithDOMImplementation:idom];
51}
52
53- (void)dealloc {
54  [self->document release];
55  [self->dom      release];
56  [self->locator  release];
57  [self->fatals   release];
58  [self->errors   release];
59  [self->warnings release];
60  [super dealloc];
61}
62
63- (void)setDocumentLocator:(id<NSObject,SaxLocator>)_loc {
64  ASSIGN(self->locator, _loc);
65}
66
67- (id)document {
68  return self->document;
69}
70
71- (void)clear {
72  ASSIGN(self->document, (id)nil);
73  [self->fatals   removeAllObjects];
74  [self->errors   removeAllObjects];
75  [self->warnings removeAllObjects];
76  self->errorCount = 0;
77}
78
79- (int)errorCount {
80  return self->errorCount;
81}
82- (int)fatalErrorCount {
83  return [self->fatals count];
84}
85- (int)warningCount {
86  return [self->warnings count];
87}
88- (int)maxErrorCount {
89  return self->maxErrorCount;
90}
91
92- (NSArray *)warnings {
93  return [[self->warnings copy] autorelease];
94}
95- (NSArray *)errors {
96  return [[self->errors copy] autorelease];
97}
98- (NSArray *)fatalErrors {
99  return [[self->fatals copy] autorelease];
100}
101
102/* attributes */
103
104- (id)_nodeForSaxAttrWithName:(NSString *)_name
105  namespace:(NSString *)_uri
106  rawName:(NSString *)_rawName
107  type:(NSString *)_saxType value:(NSString *)_saxValue
108{
109  id attr;
110  NSString *nsPrefix;
111
112  attr = [self->document createAttribute:_name namespaceURI:_uri];
113  if (attr == nil)
114    return nil;
115
116  nsPrefix = nil;
117  if (_uri) {
118    NSRange r;
119
120    r = [_rawName rangeOfString:@":"];
121    if (r.length > 0)
122      nsPrefix = [_rawName substringToIndex:r.location];
123  }
124
125  if (nsPrefix)
126    [attr setPrefix:nsPrefix];
127
128  /* add content to attribute */
129
130  if ([_saxType isEqualToString:@"CDATA"] || (_saxType == nil)) {
131    id content;
132
133    NSAssert(self->document, @"missing document object");
134
135    if ((content = [self->document createTextNode:_saxValue]))
136      [attr appendChild:content];
137    else
138      NSLog(@"couldn't create text node !");
139  }
140  else
141    NSLog(@"unsupported sax attr type '%@' !", _saxType);
142
143  return attr;
144}
145
146/* document */
147
148- (void)startDocument {
149  id docType;
150
151  [self->document release]; self->document = nil;
152  self->errorCount = 0;
153  self->tagDepth   = 0;
154
155  docType = [self->dom createDocumentType:nil
156                       publicId:[self->locator publicId]
157                       systemId:[self->locator systemId]];
158
159  self->document = [self->dom createDocumentWithName:nil
160			      namespaceURI:nil
161			      documentType:docType];
162  self->document = [self->document retain];
163
164  //NSLog(@"started doc: %@", self->document);
165
166  self->currentElement = self->document;
167}
168- (void)endDocument {
169  self->currentElement = nil;
170}
171
172- (void)startPrefixMapping:(NSString *)_prefix uri:(NSString *)_uri {
173  //printf("ns-map: %s=%s\n", [_prefix cString], [_uri cString]);
174}
175- (void)endPrefixMapping:(NSString *)_prefix {
176  //printf("ns-unmap: %s\n", [_prefix cString]);
177}
178
179- (void)startElement:(NSString *)_localName
180  namespace:(NSString *)_ns
181  rawName:(NSString *)_rawName
182  attributes:(id<SaxAttributes>)_attrs
183{
184  id       elem;
185  NSString *nsPrefix;
186
187  self->tagDepth++;
188  elem = [self->document createElement:_localName namespaceURI:_ns];
189  if (elem == nil) {
190    NSLog(@"%s: couldn't create element for tag '%@'", __PRETTY_FUNCTION__,
191          _rawName);
192    return;
193  }
194  if ([elem respondsToSelector:@selector(setLine:)])
195    [elem setLine:[self->locator lineNumber]];
196
197  if (_ns) {
198    NSRange r;
199
200    r = [_rawName rangeOfString:@":"];
201    nsPrefix = (r.length > 0)
202      ? [_rawName substringToIndex:r.location]
203      : (NSString *)nil;
204  }
205  else
206    nsPrefix = nil;
207
208  if (nsPrefix)
209    [elem setPrefix:nsPrefix];
210
211  NSAssert(self->currentElement, @"no current element !");
212
213  [self->currentElement appendChild:elem];
214  self->currentElement = elem;
215
216  /* process attributes */
217  {
218    unsigned i, count;
219
220    for (i = 0, count = [_attrs count]; i < count; i++) {
221      id attr;
222
223      // NSLog(@"attr %@", [_attrs nameAtIndex:i]);
224
225      attr = [self _nodeForSaxAttrWithName:[_attrs nameAtIndex:i]
226		   namespace:[_attrs uriAtIndex:i]
227                   rawName:[_attrs rawNameAtIndex:i]
228		   type:[_attrs typeAtIndex:i]
229		   value:[_attrs valueAtIndex:i]];
230      if (attr == nil) {
231	NSLog(@"couldn't create attribute for SAX attr %@, element %@",
232	      attr, elem);
233	continue;
234      }
235
236      /* add node to element */
237
238      if ([elem setAttributeNodeNS:attr] == nil)
239	NSLog(@"couldn't add attribute %@ to element %@", attr, elem);
240    }
241  }
242}
243- (void)endElement:(NSString *)_localName
244  namespace:(NSString *)_ns
245  rawName:(NSString *)_rawName
246{
247  id parent;
248
249  parent = [self->currentElement parentNode];
250#if DEBUG
251  NSAssert1(parent, @"no parent for current element %@ !",
252            self->currentElement);
253#endif
254  self->currentElement = parent;
255  self->tagDepth--;
256}
257
258- (void)characters:(unichar *)_chars length:(NSUInteger)_len {
259  id       charNode;
260  NSString *data;
261
262  data     = [[NSString alloc] initWithCharacters:_chars length:_len];
263  charNode = [self->document createTextNode:data];
264  [data release]; data = nil;
265
266  [self->currentElement appendChild:charNode];
267}
268- (void)ignorableWhitespace:(unichar *)_chars length:(NSUInteger)_len {
269}
270
271- (void)processingInstruction:(NSString *)_pi data:(NSString *)_data {
272  id piNode;
273
274  piNode = [self->document createProcessingInstruction:_pi data:_data];
275
276  [self->currentElement appendChild:piNode];
277}
278
279#if 0
280- (xmlEntityPtr)getEntity:(NSString *)_name {
281  NSLog(@"get entity %@", _name);
282  return NULL;
283}
284- (xmlEntityPtr)getParameterEntity:(NSString *)_name {
285  NSLog(@"get para entity %@", _name);
286  return NULL;
287}
288#endif
289
290/* lexical handler */
291
292- (void)comment:(unichar *)_chars length:(int)_len {
293  id       commentNode;
294  NSString *data;
295
296  if (_len == 0)
297    return;
298
299  data = [[NSString alloc] initWithCharacters:_chars length:_len];
300  commentNode = [self->document createComment:data];
301  [data release]; data = nil;
302
303  [self->currentElement appendChild:commentNode];
304}
305
306- (void)startDTD:(NSString *)_name
307  publicId:(NSString *)_pub
308  systemId:(NSString *)_sys
309{
310  self->inDTD = YES;
311}
312- (void)endDTD {
313  self->inDTD = NO;
314}
315
316- (void)startCDATA {
317  self->inCDATA = YES;
318}
319- (void)endCDATA {
320  self->inCDATA = NO;
321}
322
323/* entities */
324
325- (id)resolveEntityWithPublicId:(NSString *)_pubId
326  systemId:(NSString *)_sysId
327{
328  NSLog(@"shall resolve entity with '%@' '%@'", _pubId, _sysId);
329  return nil;
330}
331
332/* errors */
333
334- (void)warning:(SaxParseException *)_exception {
335  NSString *sysId;
336  int line;
337
338  sysId = [[_exception userInfo] objectForKey:@"systemId"];
339  line  = [[[_exception userInfo] objectForKey:@"line"] intValue];
340
341  NSLog(@"DOM XML WARNING(%@:%i): %@", sysId, line, [_exception reason]);
342
343  if (self->warnings == nil)
344    self->warnings = [[NSMutableArray alloc] initWithCapacity:32];
345
346  if (_exception)
347    [self->warnings addObject:_exception];
348}
349
350- (void)error:(SaxParseException *)_exception {
351  self->errorCount++;
352
353  if (printErrors) {
354    NSString *sysId;
355    int line;
356
357    sysId = [[_exception userInfo] objectForKey:@"systemId"];
358    line  = [[[_exception userInfo] objectForKey:@"line"] intValue];
359
360    NSLog(@"DOM XML ERROR(%@:%i[%@]): %@ (errcount=%i,max=%i)", sysId, line,
361	  [[_exception userInfo] objectForKey:@"parser"],
362	  [_exception reason],
363	  self->errorCount, self->maxErrorCount);
364  }
365
366  if (self->errors == nil)
367    self->errors = [[NSMutableArray alloc] initWithCapacity:32];
368
369  if (_exception)
370    [self->errors addObject:_exception];
371}
372
373- (void)fatalError:(SaxParseException *)_exception {
374  NSString *sysId;
375  int line;
376
377  sysId = [[_exception userInfo] objectForKey:@"systemId"];
378  line  = [[[_exception userInfo] objectForKey:@"line"] intValue];
379
380  NSLog(@"DOM XML FATAL(%@:%i[%@]): %@", sysId, line,
381        [[_exception userInfo] objectForKey:@"parser"],
382        [_exception reason]);
383
384  if (self->fatals == nil)
385    self->fatals = [[NSMutableArray alloc] initWithCapacity:32];
386
387  if (_exception)
388    [self->fatals addObject:_exception];
389
390  [_exception raise];
391}
392
393/* DTD */
394
395- (void)notationDeclaration:(NSString *)_name
396  publicId:(NSString *)_pubId
397  systemId:(NSString *)_sysId
398{
399  NSLog(@"decl: notation %@ pub=%@ sys=%@", _name, _pubId, _sysId);
400}
401
402- (void)unparsedEntityDeclaration:(NSString *)_name
403  publicId:(NSString *)_pubId
404  systemId:(NSString *)_sysId
405  notationName:(NSString *)_notName
406{
407  NSLog(@"decl: unparsed entity %@ pub=%@ sys=%@ not=%@",
408        _name, _pubId, _sysId, _notName);
409}
410
411/* decl */
412
413- (void)attributeDeclaration:(NSString *)_attributeName
414  elementName:(NSString *)_elementName
415  type:(NSString *)_type
416  defaultType:(NSString *)_defType
417  defaultValue:(NSString *)_defValue
418{
419  NSLog(@"decl: attr %@[%@] type '%@' default '%@'[%@]",
420        _attributeName, _elementName, _type, _defValue, _defType);
421}
422
423- (void)elementDeclaration:(NSString *)_name contentModel:(NSString *)_model {
424  NSLog(@"decl: element %@ model %@", _name, _model);
425}
426
427- (void)externalEntityDeclaration:(NSString *)_name
428  publicId:(NSString *)_pub
429  systemId:(NSString *)_sys
430{
431  NSLog(@"decl: e-entity %@ pub %@ sys %@", _name, _pub, _sys);
432}
433
434- (void)internalEntityDeclaration:(NSString *)_name value:(NSString *)_value {
435  NSLog(@"decl: i-entity %@ value %@", _name, _value);
436}
437
438@end /* DOMSaxHandler */
439
440
441@implementation DOMSaxHandler(SubHandler)
442
443- (NSUInteger)tagDepth {
444  return self->tagDepth;
445}
446
447- (id)object {
448  return [self document];
449}
450
451- (void)setNamespaces:(NSString *)_namespaces {
452  // not yet implemented
453}
454
455@end /* DOMSaxHandler(SubHandler) */
456