Index: includes/ImageFunctions.php
===================================================================
--- includes/ImageFunctions.php	(revision 36333)
+++ includes/ImageFunctions.php	(working copy)
@@ -29,37 +29,90 @@
 }
 
 /**
- * Compatible with PHP getimagesize()
+ * Helper class used by wfGetSVGsize
+ * 
+ * @ingroup Media
+ */
+class SvgInfo {
+	
+	// Class Members
+	public $valid;
+	private $width;
+	private $height;
+	
+	private function startElement($parser, $name, $attrs) {
+		if( !$this->valid && $name == 'svg' ) {
+			$this->valid = true;
+			
+			foreach ( $attrs as $name => $value ) {
+				if ( $name == 'width' ) {
+					$this->width = wfScaleSVGUnit( $value );
+				} else if ( $name == 'height' ) {
+					$this->height = wfScaleSVGUnit( $value );
+				}
+			}
+		}
+	}
+	
+	/**
+	 * Constructor - set up the XML parser
+	 * @param $filename String: full name of the file (passed to php fopen()).
+	 */
+	public function __construct( $filename ) {
+		$this->valid = false;
+		$xml_parser = xml_parser_create( 'UTF-8' );
+		xml_set_object( $xml_parser, $this );
+		xml_parser_set_option( $xml_parser, XML_OPTION_CASE_FOLDING, false );
+		xml_set_element_handler( $xml_parser, 'startElement', '' );
+		
+		if( !( $file = fopen( $filename, "r" ) ) ) {
+			wfDebug( "SvgInfo: Couldn't open " . $filename );
+			return;
+		}
+		
+		$bytesRead = 0;
+		while ( !$this->valid && $bytesRead < 65536 && $data = fread( $file, 4096 ) ) { // limit amount of data read to prevent DoS attack
+			$bytesRead += 4086;
+			if ( !xml_parse( $xml_parser, $data, feof( $file ) ) ) {
+				wfDebug( sprintf( "SvgInfo XML error: %s at file '%s' line %d\n", 
+					$filename,
+					xml_error_string(xml_get_error_code( $xml_parser ) ),
+					xml_get_current_line_number( $xml_parser) ) );
+				xml_parser_free($xml_parser);
+				return;
+			}
+		}
+		xml_parser_free( $xml_parser );
+	}
+	
+	/**
+	 * Public accessor functions for $width and $height
+	 * We return 100% if no detectable width is provided.
+	 * 
+	 * @return string
+	 */
+	public function getWidth() {
+		if ( $this->width )	return $this->width;
+		else return '100%';
+	}
+	public function getHeight() {
+		if ( $this->height ) return $this->height;
+		else return '100%';
+	}
+}
+
+/**
  * @todo support gzipped SVGZ
- * @todo check XML more carefully
- * @todo sensible defaults
  *
- * @param $filename String: full name of the file (passed to php fopen()).
+ * @param $filename String: full name of the file (passed to new SvgInfo()).
  * @return array
  */
 function wfGetSVGsize( $filename ) {
-	$width = 256;
-	$height = 256;
+	$svg = new SvgInfo( $filename );
+	if ( !$svg->valid ) return false;
 
-	// Read a chunk of the file
-	$f = fopen( $filename, "rt" );
-	if( !$f ) return false;
-	$chunk = fread( $f, 4096 );
-	fclose( $f );
-
-	// Uber-crappy hack! Run through a real XML parser.
-	$matches = array();
-	if( !preg_match( '/<svg\s*([^>]*)\s*>/s', $chunk, $matches ) ) {
-		return false;
-	}
-	$tag = $matches[1];
-	if( preg_match( '/(?:^|\s)width\s*=\s*("[^"]+"|\'[^\']+\')/s', $tag, $matches ) ) {
-		$width = wfScaleSVGUnit( trim( substr( $matches[1], 1, -1 ) ) );
-	}
-	if( preg_match( '/(?:^|\s)height\s*=\s*("[^"]+"|\'[^\']+\')/s', $tag, $matches ) ) {
-		$height = wfScaleSVGUnit( trim( substr( $matches[1], 1, -1 ) ) );
-	}
-
+	$height = $svg->getHeight();
+	$width = $svg->getWidth();
 	return array( $width, $height, 'SVG',
 		"width=\"$width\" height=\"$height\"" );
 }
