buildimage: Convert the XML parser to use XML::LibXML.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2017-10-19 16:51:39 +02:00
parent 05111a34d5
commit 9e0c990be1
1 changed files with 75 additions and 97 deletions

View File

@ -20,7 +20,7 @@
use strict; use strict;
use warnings; use warnings;
use XML::Parser; use XML::LibXML;
use MIME::Base64; use MIME::Base64;
use File::Copy; use File::Copy;
@ -58,6 +58,13 @@ $SIG{"HUP"} = "cleanup";
$SIG{"TERM"} = "cleanup"; $SIG{"TERM"} = "cleanup";
$SIG{"__DIE__"} = "cleanup"; $SIG{"__DIE__"} = "cleanup";
my %label =
(
'ico' => 'icon:(\d*)-(\d*)',
'cur' => 'cursor:(\d*)-(\d*)',
'bmp' => 'bitmap:(\d*)-(\d*)',
);
# run a shell command and die on error # run a shell command and die on error
sub shell(@) sub shell(@)
{ {
@ -65,105 +72,18 @@ sub shell(@)
system(@args) == 0 or die "@args failed: $?"; system(@args) == 0 or die "@args failed: $?";
} }
sub svg_element_start # add an image to the icon/cursor
sub add_image($$)
{ {
my($expat, $element, %attr) = @_; my ($file, $size) = @_;
# Parse the id for icon/bitmap render directives
my $id = $attr{'id'};
return unless defined($id);
my $size = 0;
my $depth = 0;
my $width = 0;
my $height = 0;
if ($id =~ /hotspot:(\d*)/)
{
$hotspot[$1] = [ $attr{x}, $attr{y} ];
return;
}
if($ext eq "ico") {
return unless $id =~ /icon:(\d*)-(\d*)/;
$size = $1;
$depth = $2;
} elsif($ext eq "cur") {
return unless $id =~ /cursor:(\d*)-(\d*)/;
$size = $1;
$depth = $2;
} elsif($ext eq "bmp") {
return unless $id =~ /bitmap:(\d*)-(\d*)/;
$size = $1;
$depth = $2;
}
return unless defined($size) and defined($depth);
warn "Unexpected depth" unless
$depth == 1 or $depth == 4 or $depth == 8 or $depth == 24 or $depth == 32;
my $pngFileName = "$outName-$size-$depth.png";
if($element eq "svg") {
if ($ext eq "bmp") {
if ($depth == 24) {
shell $convert, $renderedSVGFileName, "+matte", $outFileName;
} else {
shell $convert, $renderedSVGFileName, $outFileName;
}
cleanup();
exit(0);
}
# The whole file is tagged
$pngFileName = $renderedSVGFileName;
} elsif($element eq "rect") {
# Extract SVG vector images
my $x = $attr{'x'};
my $y = $attr{'y'};
$width = $attr{'width'};
$height = $attr{'height'};
if(defined($x) and defined($y)) {
if($x =~ /\d*/ and $y =~ /\d*/) {
shell $convert, $renderedSVGFileName, "-crop", "${width}x${height}+$x+$y", "-depth", $depth, $pngFileName;
}
}
} elsif($element eq "image" ) {
# Extract Base64 encoded PNG data to files
my $xlinkHref = $attr{'xlink:href'};
if(defined($xlinkHref)) {
$xlinkHref =~ /data:image\/png;base64(.*)/;
my $imageEncodedData = $1;
if(defined $imageEncodedData) {
open(FILE, '>' . $pngFileName) or die "$!";
print FILE decode_base64($imageEncodedData);
close FILE;
}
}
} else {
return;
}
if (defined $hotspot[$size]) if (defined $hotspot[$size])
{ {
my @coords = @{$hotspot[$size]}; my @coords = @{$hotspot[$size]};
push @icotool_args, "--hotspot-x=$coords[0]", "--hotspot-y=$coords[1]"; push @icotool_args, "--hotspot-x=$coords[0]", "--hotspot-y=$coords[1]";
} }
push @icotool_args, $size >= 128 ? "--raw=$file" : $file;
if ($width >= 128 && $height >= 128) push @pngFiles, $file;
{
push @icotool_args, "--raw=$pngFileName";
}
else
{
push @icotool_args, $pngFileName;
}
push @pngFiles, $pngFileName;
} }
# Render the SVG image # Render the SVG image
@ -175,9 +95,67 @@ push(@rsvgCmd, $renderedSVGFileName);
shell @rsvgCmd; shell @rsvgCmd;
# Render the images in the SVG # Render the images in the SVG
my $parser = new XML::Parser( my $xml = XML::LibXML->load_xml( location => $svgFileName );
Handlers => {Start => \&svg_element_start}); my $xc = XML::LibXML::XPathContext->new($xml);
$parser->parsefile("$svgFileName"); $xc->registerNs('x', 'http://www.w3.org/2000/svg');
if ($ext eq "bmp")
{
foreach my $element ($xc->findnodes("/x:svg"))
{
next unless $element->{id} =~ /bitmap:(\d*)-(\d*)/;
my $size = $1;
my $depth = $2;
if ($depth == 24) {
shell $convert, $renderedSVGFileName, "+matte", $outFileName;
} else {
shell $convert, $renderedSVGFileName, $outFileName;
}
cleanup();
exit(0);
}
}
# fetch hotspot rectangles for the various sizes
if ($ext eq "cur")
{
foreach my $element ($xc->findnodes("/x:svg/x:rect"))
{
next unless $element->{id} =~ /hotspot:(\d*)/;
$hotspot[$1] = [ $element->{x}, $element->{y} ];
}
}
# extract rectangles from the rendered svg
foreach my $element ($xc->findnodes("/x:svg/*[\@id]"))
{
next unless $element->{id} =~ /$label{$ext}/;
my $size = $1;
my $depth = $2;
warn "Unexpected depth" unless
$depth == 1 or $depth == 4 or $depth == 8 or $depth == 24 or $depth == 32;
my $file = "$outName-$size-$depth.png";
my $x = $element->{x};
my $y = $element->{y};
my $width = $element->{width};
my $height = $element->{height};
if ($element->{'xlink:href'})
{
# extract base64-encoded png image
(my $data = $element->{'xlink:href'}) =~ s/data:image\/png;base64//;
open FILE, ">$file" or die "$!";
print FILE decode_base64($data);
close FILE;
}
else
{
shell $convert, $renderedSVGFileName, "-crop", "${width}x${height}+$x+$y", "-depth", $depth, $file;
}
add_image( $file, $size );
}
die "no render directive found in $svgFileName" unless @pngFiles; die "no render directive found in $svgFileName" unless @pngFiles;