]> err.no Git - sope/blobdiff - sope-xml/libxmlSAXDriver/libxmlSAXDriver.m
properly decode attribute values before passing them as events
[sope] / sope-xml / libxmlSAXDriver / libxmlSAXDriver.m
index d12055fee3cfa3daeda8cacdd42d02618d33a08b..eed749695563d3fe513717aafc6d594cd5cf9697 100644 (file)
@@ -79,6 +79,119 @@ static inline NSString *xmlCharsToString(const xmlChar *_s) {
   return s;
 }
 
+static inline NSString *xmlCharsToDecodedString(const xmlChar *_s) {
+  NSString *s;
+  BOOL     needsDecoding = NO;
+  unichar  (*charAt)(id, SEL, unsigned int);
+  unsigned i, len, last;
+
+  if (_s == NULL) return nil;
+  
+  if (NSStringClass == Nil)
+    NSStringClass = [NSString class];
+  
+  s      = [[NSStringClass alloc] initWithUTF8String:(const char *)_s];
+  len    = [s length];
+  charAt = (void *)[s methodForSelector:@selector(characterAtIndex:)];
+
+  for (i = 0; i < len; i++) {
+    if (charAt(s, @selector(characterAtIndex:), i) == '&') {
+      needsDecoding = YES;
+      last          = 0;
+      break;
+    }
+  }
+  if (needsDecoding) {
+    NSMutableString *ds;
+    
+    ds = [[NSMutableString alloc] initWithCapacity:len];
+    for (; i < len; i++) {
+      if (charAt(s, @selector(characterAtIndex:), i) == '&') {
+        NSRange r;
+        
+        r = NSMakeRange(last, i - last);
+        [ds appendString:[s substringWithRange:r]];
+        if (charAt(s, @selector(characterAtIndex:), i + 1) == '#') {
+          NSRange vr;
+          unichar c;
+
+          r = NSMakeRange(i + 2, len - i - 2);
+          r = [s rangeOfString:@";" options:0 range:r];
+          c = (unichar)charAt(s, @selector(characterAtIndex:), i + 2);
+          /* hex value? */
+          if (c == 'x' || c == 'X') {
+            unsigned value;
+            
+            vr    = NSMakeRange(i + 3, r.location - i - 3);
+            value = [[NSScanner scannerWithString:[s substringWithRange:vr]]
+                                                  scanHexInt:&value];
+            c = (unichar)value;
+          }
+          else {
+            vr = NSMakeRange(i + 2, r.location - i - 2);
+            c  = (unichar)[[s substringWithRange:vr] intValue];
+          }
+          [ds appendString:[NSString stringWithCharacters:&c length:1]];
+          i    = NSMaxRange(r);
+          last = i;
+        }
+        else {
+          if ((charAt(s, @selector(characterAtIndex:), i + 1) == 'a') &&
+              (charAt(s, @selector(characterAtIndex:), i + 2) == 'm') &&
+              (charAt(s, @selector(characterAtIndex:), i + 3) == 'p'))
+          {
+            [ds appendString:@"&"];
+            i += 5;
+          }
+          else if ((charAt(s, @selector(characterAtIndex:), i + 1) == 'q') &&
+                   (charAt(s, @selector(characterAtIndex:), i + 2) == 'u') &&
+                   (charAt(s, @selector(characterAtIndex:), i + 3) == 'o') &&
+                   (charAt(s, @selector(characterAtIndex:), i + 4) == 't'))
+          {
+            [ds appendString:@"\""];
+            i += 6;
+          }
+          else if ((charAt(s, @selector(characterAtIndex:), i + 1) == 'a') &&
+                   (charAt(s, @selector(characterAtIndex:), i + 2) == 'p') &&
+                   (charAt(s, @selector(characterAtIndex:), i + 3) == 'o') &&
+                   (charAt(s, @selector(characterAtIndex:), i + 4) == 's'))
+          {
+            [ds appendString:@"'"];
+            i += 6;
+          }
+          else if ((charAt(s, @selector(characterAtIndex:), i + 1) == 'l') &&
+                   (charAt(s, @selector(characterAtIndex:), i + 2) == 't'))
+          {
+            [ds appendString:@"<"];
+            i += 4;
+          }
+          else if ((charAt(s, @selector(characterAtIndex:), i + 1) == 'g') &&
+                   (charAt(s, @selector(characterAtIndex:), i + 2) == 't'))
+          {
+            [ds appendString:@">"];
+            i += 4;
+          }
+          else {
+            NSRange r;
+            
+            r = NSMakeRange(i + 1, len - i - 1);
+            r = [s rangeOfString:@";" options:0 range:r];
+            r = NSMakeRange(i, r.location - i);
+            [ds appendString:[s substringWithRange:r]];
+            i = NSMaxRange(r);
+          }
+          last = i;
+        }
+      }
+    }
+    if (last != (len - 1))
+      [ds appendString:[s substringFromIndex:last]];
+    [s release];
+    s = ds;
+  }
+  return s;
+}
+
 extern xmlParserCtxtPtr xmlCreateMemoryParserCtxt(char *buffer, int size);
 
 @implementation libxmlSAXDriver
@@ -824,7 +937,7 @@ _startElement(libxmlSAXDriver *self, const xmlChar *name, const xmlChar **atts)
       }
       
       type  = @"CDATA";
-      value = xmlCharsToString(atts[i + 1]);
+      value = xmlCharsToDecodedString(atts[i + 1]);
       
       [self->attrs
            addAttribute:name uri:uri rawName:rawName