blob: 1294a17a8f64e37b098662fc7db9670889285acd [file] [log] [blame]
###########################################################################
# Module for ABI Compliance Checker to create ABI dumps in XML format
#
# Copyright (C) 2009-2011 Institute for System Programming, RAS
# Copyright (C) 2011-2012 Nokia Corporation and/or its subsidiary(-ies)
# Copyright (C) 2011-2012 ROSA Laboratory
# Copyright (C) 2012-2015 Andrey Ponomarenko's ABI Laboratory
#
# Written by Andrey Ponomarenko
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License or the GNU Lesser
# General Public License as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# and the GNU Lesser General Public License along with this program.
# If not, see <http://www.gnu.org/licenses/>.
###########################################################################
use strict;
my $TAG_ID = 0;
my $INDENT = " ";
sub createXmlDump($)
{
my $ABI = $_[0];
my $ABI_DUMP = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
$ABI_DUMP .= "<ABI_dump version=\"".$ABI->{"ABI_DUMP_VERSION"}."\"";
$ABI_DUMP .= " xml_format=\"".$ABI->{"XML_ABI_DUMP_VERSION"}."\"";
$ABI_DUMP .= " acc=\"".$ABI->{"ABI_COMPLIANCE_CHECKER_VERSION"}."\">\n";
$ABI_DUMP .= addTag("library", $ABI->{"LibraryName"});
$ABI_DUMP .= addTag("library_version", $ABI->{"LibraryVersion"});
$ABI_DUMP .= addTag("language", $ABI->{"Language"});
$ABI_DUMP .= addTag("gcc", $ABI->{"GccVersion"});
$ABI_DUMP .= addTag("architecture", $ABI->{"Arch"});
$ABI_DUMP .= addTag("target", $ABI->{"Target"});
$ABI_DUMP .= addTag("word_size", $ABI->{"WordSize"});
if($ABI->{"Mode"}) {
$ABI_DUMP .= addTag("mode", $ABI->{"Mode"});
}
if($ABI->{"SrcBin"}) {
$ABI_DUMP .= addTag("kind", "SrcBin");
}
elsif($ABI->{"BinOnly"}) {
$ABI_DUMP .= addTag("kind", "BinOnly");
}
if(my @Headers = keys(%{$ABI->{"Headers"}}))
{
@Headers = sort {$ABI->{"Headers"}{$a}<=>$ABI->{"Headers"}{$b}} @Headers;
$ABI_DUMP .= openTag("headers");
foreach my $Name (@Headers) {
$ABI_DUMP .= addTag("name", $Name);
}
$ABI_DUMP .= closeTag("headers");
}
if(my @NameSpaces = keys(%{$ABI->{"NameSpaces"}}))
{
$ABI_DUMP .= openTag("namespaces");
foreach my $NameSpace (sort {lc($a) cmp lc($b)} @NameSpaces) {
$ABI_DUMP .= addTag("name", $NameSpace);
}
$ABI_DUMP .= closeTag("namespaces");
}
if(my @TypeInfo = keys(%{$ABI->{"TypeInfo"}}))
{
$ABI_DUMP .= openTag("type_info");
foreach my $ID (sort {$a<=>$b} @TypeInfo)
{
my %TInfo = %{$ABI->{"TypeInfo"}{$ID}};
$ABI_DUMP .= openTag("data_type");
$ABI_DUMP .= addTag("id", $ID);
foreach my $Attr ("Name", "Type", "Size",
"Header", "Line", "NameSpace", "Class", "Return", "Algn")
{
if(defined $TInfo{$Attr}) {
$ABI_DUMP .= addTag(lc($Attr), $TInfo{$Attr});
}
}
if($TInfo{"Private"}) {
$ABI_DUMP .= addTag("access", "private");
}
if($TInfo{"Protected"}) {
$ABI_DUMP .= addTag("access", "protected");
}
if(my @Positions = keys(%{$TInfo{"Memb"}}))
{
$ABI_DUMP .= openTag("members");
foreach my $Pos (sort { $a<=>$b } @Positions)
{
$ABI_DUMP .= openTag("field");
$ABI_DUMP .= addTag("name", $TInfo{"Memb"}{$Pos}{"name"});
if(my $MTid = $TInfo{"Memb"}{$Pos}{"type"}) {
$ABI_DUMP .= addTag("type", $MTid);
}
if(my $Access = $TInfo{"Memb"}{$Pos}{"access"}) {
$ABI_DUMP .= addTag("access", $Access);
}
my $Val = $TInfo{"Memb"}{$Pos}{"value"};
if(defined $Val) {
$ABI_DUMP .= addTag("value", $Val);
}
if(my $Align = $TInfo{"Memb"}{$Pos}{"algn"}) {
$ABI_DUMP .= addTag("algn", $Align);
}
if(my $Bitfield = $TInfo{"Memb"}{$Pos}{"bitfield"}) {
$ABI_DUMP .= addTag("bitfield", $Bitfield);
}
if($TInfo{"Memb"}{$Pos}{"mutable"}) {
$ABI_DUMP .= addTag("spec", "mutable");
}
$ABI_DUMP .= addTag("pos", $Pos);
$ABI_DUMP .= closeTag("field");
}
$ABI_DUMP .= closeTag("members");
}
if(my @Positions = keys(%{$TInfo{"Param"}}))
{
$ABI_DUMP .= openTag("parameters");
foreach my $Pos (sort { $a<=>$b } @Positions)
{
$ABI_DUMP .= openTag("param");
if(my $PTid = $TInfo{"Param"}{$Pos}{"type"}) {
$ABI_DUMP .= addTag("type", $PTid);
}
$ABI_DUMP .= addTag("pos", $Pos);
$ABI_DUMP .= closeTag("param");
}
$ABI_DUMP .= closeTag("parameters");
}
if(my @Positions = keys(%{$TInfo{"TParam"}}))
{
$ABI_DUMP .= openTag("template_parameters");
foreach my $Pos (sort { $a<=>$b } @Positions)
{
$ABI_DUMP .= openTag("param");
$ABI_DUMP .= addTag("name", $TInfo{"TParam"}{$Pos}{"name"});
$ABI_DUMP .= addTag("pos", $Pos);
$ABI_DUMP .= closeTag("param");
}
$ABI_DUMP .= closeTag("template_parameters");
}
if(my @Offsets = keys(%{$TInfo{"VTable"}}))
{
$ABI_DUMP .= openTag("vtable");
foreach my $Offset (sort { $a<=>$b } @Offsets)
{
$ABI_DUMP .= openTag("entry");
$ABI_DUMP .= addTag("offset", $Offset);
$ABI_DUMP .= addTag("value", $TInfo{"VTable"}{$Offset});
$ABI_DUMP .= closeTag("entry");
}
$ABI_DUMP .= closeTag("vtable");
}
if(my $BTid = $TInfo{"BaseType"}) {
$ABI_DUMP .= addTag("base_type", $BTid);
}
if(my @BaseIDs = keys(%{$TInfo{"Base"}}))
{
@BaseIDs = sort { $TInfo{"Base"}{$a}{"pos"}<=>$TInfo{"Base"}{$b}{"pos"} } @BaseIDs;
$ABI_DUMP .= openTag("base");
foreach my $BaseID (@BaseIDs)
{
$ABI_DUMP .= openTag("class");
$ABI_DUMP .= addTag("id", $BaseID);
if(my $Access = $TInfo{"Base"}{$BaseID}{"access"}) {
$ABI_DUMP .= addTag("access", $Access);
}
if(my $Virt = $TInfo{"Base"}{$BaseID}{"virtual"}) {
$ABI_DUMP .= addTag("inherit", "virtual");
}
$ABI_DUMP .= addTag("pos", $TInfo{"Base"}{$BaseID}{"pos"});
$ABI_DUMP .= closeTag("class");
}
$ABI_DUMP .= closeTag("base");
}
if($TInfo{"Copied"}) {
$ABI_DUMP .= addTag("note", "copied");
}
if($TInfo{"Spec"}) {
$ABI_DUMP .= addTag("note", "specialization");
}
if($TInfo{"Forward"}) {
$ABI_DUMP .= addTag("note", "forward");
}
$ABI_DUMP .= closeTag("data_type");
}
$ABI_DUMP .= closeTag("type_info");
}
if(my @Constants = keys(%{$ABI->{"Constants"}}))
{
$ABI_DUMP .= openTag("constants");
foreach my $Constant (@Constants)
{
my %CInfo = %{$ABI->{"Constants"}{$Constant}};
$ABI_DUMP .= openTag("constant");
$ABI_DUMP .= addTag("name", $Constant);
$ABI_DUMP .= addTag("value", $CInfo{"Value"});
$ABI_DUMP .= addTag("header", $CInfo{"Header"});
$ABI_DUMP .= closeTag("constant");
}
$ABI_DUMP .= closeTag("constants");
}
if(my @SymbolInfo = keys(%{$ABI->{"SymbolInfo"}}))
{
my %TR = (
"MnglName" => "mangled",
"ShortName" => "short"
);
$ABI_DUMP .= openTag("symbol_info");
foreach my $ID (sort {$a<=>$b} @SymbolInfo)
{
my %SInfo = %{$ABI->{"SymbolInfo"}{$ID}};
$ABI_DUMP .= openTag("symbol");
$ABI_DUMP .= addTag("id", $ID);
foreach my $Attr ("MnglName", "ShortName", "Class",
"Header", "Line", "Return", "NameSpace", "Value")
{
if(defined $SInfo{$Attr})
{
my $Tag = $Attr;
if($TR{$Attr}) {
$Tag = $TR{$Attr};
}
$ABI_DUMP .= addTag(lc($Tag), $SInfo{$Attr});
}
}
if($SInfo{"Constructor"}) {
$ABI_DUMP .= addTag("kind", "constructor");
}
if($SInfo{"Destructor"}) {
$ABI_DUMP .= addTag("kind", "destructor");
}
if($SInfo{"Data"}) {
$ABI_DUMP .= addTag("kind", "data");
}
if($SInfo{"Virt"}) {
$ABI_DUMP .= addTag("spec", "virtual");
}
elsif($SInfo{"PureVirt"}) {
$ABI_DUMP .= addTag("spec", "pure virtual");
}
elsif($SInfo{"Static"}) {
$ABI_DUMP .= addTag("spec", "static");
}
if($SInfo{"InLine"}) {
$ABI_DUMP .= addTag("spec", "inline");
}
if($SInfo{"Const"}) {
$ABI_DUMP .= addTag("spec", "const");
}
if($SInfo{"Volatile"}) {
$ABI_DUMP .= addTag("spec", "volatile");
}
if($SInfo{"Private"}) {
$ABI_DUMP .= addTag("access", "private");
}
if($SInfo{"Protected"}) {
$ABI_DUMP .= addTag("access", "protected");
}
if($SInfo{"Artificial"}) {
$ABI_DUMP .= addTag("note", "artificial");
}
if(my $Lang = $SInfo{"Lang"}) {
$ABI_DUMP .= addTag("lang", $Lang);
}
if(my @Positions = keys(%{$SInfo{"Param"}}))
{
$ABI_DUMP .= openTag("parameters");
foreach my $Pos (sort { $a<=>$b } @Positions)
{
$ABI_DUMP .= openTag("param");
if(my $PName = $SInfo{"Param"}{$Pos}{"name"}) {
$ABI_DUMP .= addTag("name", $PName);
}
if(my $PTid = $SInfo{"Param"}{$Pos}{"type"}) {
$ABI_DUMP .= addTag("type", $PTid);
}
my $Default = $SInfo{"Param"}{$Pos}{"default"};
if(defined $Default) {
$ABI_DUMP .= addTag("default", $Default);
}
if(my $Align = $SInfo{"Param"}{$Pos}{"algn"}) {
$ABI_DUMP .= addTag("algn", $Align);
}
if(defined $SInfo{"Param"}{$Pos}{"reg"}) {
$ABI_DUMP .= addTag("call", "register");
}
$ABI_DUMP .= addTag("pos", $Pos);
$ABI_DUMP .= closeTag("param");
}
$ABI_DUMP .= closeTag("parameters");
}
if(my @Positions = keys(%{$SInfo{"TParam"}}))
{
$ABI_DUMP .= openTag("template_parameters");
foreach my $Pos (sort { $a<=>$b } @Positions)
{
$ABI_DUMP .= openTag("param");
$ABI_DUMP .= addTag("name", $SInfo{"TParam"}{$Pos}{"name"});
$ABI_DUMP .= closeTag("param");
}
$ABI_DUMP .= closeTag("template_parameters");
}
$ABI_DUMP .= closeTag("symbol");
}
$ABI_DUMP .= closeTag("symbol_info");
}
if(my @Libs = keys(%{$ABI->{"Symbols"}}))
{
$ABI_DUMP .= openTag("symbols");
foreach my $Lib (sort {lc($a) cmp lc($b)} @Libs)
{
$ABI_DUMP .= openTag("library", "name", $Lib);
foreach my $Symbol (sort {lc($a) cmp lc($b)} keys(%{$ABI->{"Symbols"}{$Lib}}))
{
if((my $Size = $ABI->{"Symbols"}{$Lib}{$Symbol})<0)
{ # data
$ABI_DUMP .= addTag("symbol", $Symbol, "size", -$Size);
}
else
{ # functions
$ABI_DUMP .= addTag("symbol", $Symbol);
}
}
$ABI_DUMP .= closeTag("library");
}
$ABI_DUMP .= closeTag("symbols");
}
if(my @DepLibs = keys(%{$ABI->{"DepSymbols"}}))
{
$ABI_DUMP .= openTag("dep_symbols");
foreach my $Lib (sort {lc($a) cmp lc($b)} @DepLibs)
{
$ABI_DUMP .= openTag("library", "name", $Lib);
foreach my $Symbol (sort {lc($a) cmp lc($b)} keys(%{$ABI->{"DepSymbols"}{$Lib}}))
{
if((my $Size = $ABI->{"DepSymbols"}{$Lib}{$Symbol})<0)
{ # data
$ABI_DUMP .= addTag("symbol", $Symbol, "size", -$Size);
}
else
{ # functions
$ABI_DUMP .= addTag("symbol", $Symbol);
}
}
$ABI_DUMP .= closeTag("library");
}
$ABI_DUMP .= closeTag("dep_symbols");
}
if(my @VSymbols = keys(%{$ABI->{"SymbolVersion"}}))
{
$ABI_DUMP .= openTag("symbol_version");
foreach my $Symbol (sort {lc($a) cmp lc($b)} @VSymbols)
{
$ABI_DUMP .= openTag("symbol");
$ABI_DUMP .= addTag("name", $Symbol);
$ABI_DUMP .= addTag("version", $ABI->{"SymbolVersion"}{$Symbol});
$ABI_DUMP .= closeTag("symbol");
}
$ABI_DUMP .= closeTag("symbol_version");
}
if(my @SkipTypes = keys(%{$ABI->{"SkipTypes"}}))
{
$ABI_DUMP .= openTag("skip_types");
foreach my $Name (sort {lc($a) cmp lc($b)} @SkipTypes) {
$ABI_DUMP .= addTag("name", $Name);
}
$ABI_DUMP .= closeTag("skip_types");
}
if(my @SkipSymbols = keys(%{$ABI->{"SkipSymbols"}}))
{
$ABI_DUMP .= openTag("skip_symbols");
foreach my $Name (sort {lc($a) cmp lc($b)} @SkipSymbols) {
$ABI_DUMP .= addTag("name", $Name);
}
$ABI_DUMP .= closeTag("skip_symbols");
}
if(my @SkipNameSpaces = keys(%{$ABI->{"SkipNameSpaces"}}))
{
$ABI_DUMP .= openTag("skip_namespaces");
foreach my $Name (sort {lc($a) cmp lc($b)} @SkipNameSpaces) {
$ABI_DUMP .= addTag("name", $Name);
}
$ABI_DUMP .= closeTag("skip_namespaces");
}
if(my @SkipHeaders = keys(%{$ABI->{"SkipHeaders"}}))
{
$ABI_DUMP .= openTag("skip_headers");
foreach my $Name (sort {lc($a) cmp lc($b)} @SkipHeaders) {
$ABI_DUMP .= addTag("name", $Name);
}
$ABI_DUMP .= closeTag("skip_headers");
}
if(my @TargetHeaders = keys(%{$ABI->{"TargetHeaders"}}))
{
$ABI_DUMP .= openTag("target_headers");
foreach my $Name (sort {lc($a) cmp lc($b)} @TargetHeaders) {
$ABI_DUMP .= addTag("name", $Name);
}
$ABI_DUMP .= closeTag("target_headers");
}
$ABI_DUMP .= "</ABI_dump>\n";
checkTags();
return $ABI_DUMP;
}
sub readXmlDump($)
{
my $ABI_DUMP = readFile($_[0]);
my %ABI = {};
$ABI{"LibraryName"} = parseTag(\$ABI_DUMP, "library");
$ABI{"LibraryVersion"} = parseTag(\$ABI_DUMP, "library_version");
$ABI{"Language"} = parseTag(\$ABI_DUMP, "language");
$ABI{"GccVersion"} = parseTag(\$ABI_DUMP, "gcc");
$ABI{"Arch"} = parseTag(\$ABI_DUMP, "architecture");
$ABI{"Target"} = parseTag(\$ABI_DUMP, "target");
$ABI{"WordSize"} = parseTag(\$ABI_DUMP, "word_size");
my $Pos = 0;
if(my $Headers = parseTag(\$ABI_DUMP, "headers"))
{
while(my $Name = parseTag(\$Headers, "name")) {
$ABI{"Headers"}{$Name} = $Pos++;
}
}
if(my $NameSpaces = parseTag(\$ABI_DUMP, "namespaces"))
{
while(my $Name = parseTag(\$NameSpaces, "name")) {
$ABI{"NameSpaces"}{$Name} = 1;
}
}
if(my $TypeInfo = parseTag(\$ABI_DUMP, "type_info"))
{
while(my $DataType = parseTag(\$TypeInfo, "data_type"))
{
my %TInfo = ();
my $ID = parseTag(\$DataType, "id");
if(my $Members = parseTag(\$DataType, "members"))
{
$Pos = 0;
while(my $Field = parseTag(\$Members, "field"))
{
my %MInfo = ();
$MInfo{"name"} = parseTag(\$Field, "name");
if(my $Tid = parseTag(\$Field, "type")) {
$MInfo{"type"} = $Tid;
}
if(my $Access = parseTag(\$Field, "access")) {
$MInfo{"access"} = $Access;
}
my $Val = parseTag(\$Field, "value");
if(defined $Val) {
$MInfo{"value"} = $Val;
}
if(my $Align = parseTag(\$Field, "algn")) {
$MInfo{"algn"} = $Align;
}
if(my $Bitfield = parseTag(\$Field, "bitfield")) {
$MInfo{"bitfield"} = $Bitfield;
}
if(my $Spec = parseTag(\$Field, "spec")) {
$MInfo{$Spec} = 1;
}
$TInfo{"Memb"}{$Pos++} = \%MInfo;
}
}
if(my $Parameters = parseTag(\$DataType, "parameters"))
{
$Pos = 0;
while(my $Parameter = parseTag(\$Parameters, "param"))
{
my %PInfo = ();
if(my $Tid = parseTag(\$Parameter, "type")) {
$PInfo{"type"} = $Tid;
}
$TInfo{"Param"}{$Pos++} = \%PInfo;
}
}
if(my $TParams = parseTag(\$DataType, "template_parameters"))
{
$Pos = 0;
while(my $TParam = parseTag(\$TParams, "param")) {
$TInfo{"TParam"}{$Pos++}{"name"} = parseTag(\$TParam, "name");
}
}
if(my $VTable = parseTag(\$DataType, "vtable"))
{
$Pos = 0;
while(my $Entry = parseTag(\$VTable, "entry")) {
$TInfo{"VTable"}{parseTag(\$Entry, "offset")} = parseTag(\$Entry, "value");
}
}
if(my $BTid = parseTag(\$DataType, "base_type")) {
$TInfo{"BaseType"} = $BTid;
}
if(my $Base = parseTag(\$DataType, "base"))
{
$Pos = 0;
while(my $Class = parseTag(\$Base, "class"))
{
my %CInfo = ();
$CInfo{"pos"} = parseTag(\$Class, "pos");
if(my $Access = parseTag(\$Class, "access")) {
$CInfo{"access"} = $Access;
}
if(my $Inherit = parseTag(\$Class, "inherit"))
{
if($Inherit eq "virtual") {
$CInfo{"virtual"} = 1;
}
}
$TInfo{"Base"}{parseTag(\$Class, "id")} = \%CInfo;
}
}
while(my $Note = parseTag(\$DataType, "note"))
{
if($Note eq "copied") {
$TInfo{"Copied"} = 1;
}
elsif($Note eq "specialization") {
$TInfo{"Spec"} = 1;
}
elsif($Note eq "forward") {
$TInfo{"Forward"} = 1;
}
}
foreach my $Attr ("Name", "Type", "Size",
"Header", "Line", "NameSpace", "Class", "Return", "Algn")
{
my $Val = parseTag(\$DataType, lc($Attr));
if(defined $Val) {
$TInfo{$Attr} = $Val;
}
}
if(my $Access = parseTag(\$DataType, "access")) {
$TInfo{ucfirst($Access)} = 1;
}
$ABI{"TypeInfo"}{$ID} = \%TInfo;
}
}
if(my $Constants = parseTag(\$ABI_DUMP, "constants"))
{
while(my $Constant = parseTag(\$Constants, "constant"))
{
if(my $Name = parseTag(\$Constant, "name"))
{
my %CInfo = ();
$CInfo{"Value"} = parseTag(\$Constant, "value");
$CInfo{"Header"} = parseTag(\$Constant, "header");
$ABI{"Constants"}{$Name} = \%CInfo;
}
}
}
if(my $SymbolInfo = parseTag(\$ABI_DUMP, "symbol_info"))
{
my %TR = (
"MnglName"=>"mangled",
"ShortName"=>"short"
);
while(my $Symbol = parseTag(\$SymbolInfo, "symbol"))
{
my %SInfo = ();
my $ID = parseTag(\$Symbol, "id");
if(my $Parameters = parseTag(\$Symbol, "parameters"))
{
$Pos = 0;
while(my $Parameter = parseTag(\$Parameters, "param"))
{
my %PInfo = ();
if(my $PName = parseTag(\$Parameter, "name")) {
$PInfo{"name"} = $PName;
}
if(my $PTid = parseTag(\$Parameter, "type")) {
$PInfo{"type"} = $PTid;
}
my $Default = parseTag(\$Parameter, "default", "spaces");
if(defined $Default) {
$PInfo{"default"} = $Default;
}
if(my $Align = parseTag(\$Parameter, "algn")) {
$PInfo{"algn"} = $Align;
}
if(my $Call = parseTag(\$Parameter, "call"))
{
if($Call eq "register") {
$PInfo{"reg"} = 1;
}
}
$SInfo{"Param"}{$Pos++} = \%PInfo;
}
}
if(my $TParams = parseTag(\$Symbol, "template_parameters"))
{
$Pos = 0;
while(my $TParam = parseTag(\$TParams, "param")) {
$SInfo{"TParam"}{$Pos++}{"name"} = parseTag(\$TParam, "name");
}
}
foreach my $Attr ("MnglName", "ShortName", "Class",
"Header", "Line", "Return", "NameSpace", "Value")
{
my $Tag = lc($Attr);
if($TR{$Attr}) {
$Tag = $TR{$Attr};
}
my $Val = parseTag(\$Symbol, $Tag);
if(defined $Val) {
$SInfo{$Attr} = $Val;
}
}
if(my $Kind = parseTag(\$Symbol, "kind")) {
$SInfo{ucfirst($Kind)} = 1;
}
while(my $Spec = parseTag(\$Symbol, "spec"))
{
if($Spec eq "virtual") {
$SInfo{"Virt"} = 1;
}
elsif($Spec eq "pure virtual") {
$SInfo{"PureVirt"} = 1;
}
elsif($Spec eq "inline") {
$SInfo{"InLine"} = 1;
}
else
{ # const, volatile, static
$SInfo{ucfirst($Spec)} = 1;
}
}
if(my $Access = parseTag(\$Symbol, "access")) {
$SInfo{ucfirst($Access)} = 1;
}
if(my $Note = parseTag(\$Symbol, "note")) {
$SInfo{ucfirst($Note)} = 1;
}
if(my $Lang = parseTag(\$Symbol, "lang")) {
$SInfo{"Lang"} = $Lang;
}
$ABI{"SymbolInfo"}{$ID} = \%SInfo;
}
}
if(my $Symbols = parseTag(\$ABI_DUMP, "symbols"))
{
my %LInfo = ();
while(my $LibSymbols = parseTag_E(\$Symbols, "library", \%LInfo))
{
my %SInfo = ();
while(my $Symbol = parseTag_E(\$LibSymbols, "symbol", \%SInfo))
{
if(my $Size = $SInfo{"size"}) {
$ABI{"Symbols"}{$LInfo{"name"}}{$Symbol} = -$Size;
}
else {
$ABI{"Symbols"}{$LInfo{"name"}}{$Symbol} = 1;
}
%SInfo = ();
}
%LInfo = ();
}
}
if(my $DepSymbols = parseTag(\$ABI_DUMP, "dep_symbols"))
{
my %LInfo = ();
while(my $LibSymbols = parseTag_E(\$DepSymbols, "library", \%LInfo))
{
my %SInfo = ();
while(my $Symbol = parseTag_E(\$LibSymbols, "symbol", \%SInfo))
{
if(my $Size = $SInfo{"size"}) {
$ABI{"DepSymbols"}{$LInfo{"name"}}{$Symbol} = -$Size;
}
else {
$ABI{"DepSymbols"}{$LInfo{"name"}}{$Symbol} = 1;
}
%SInfo = ();
}
%LInfo = ();
}
}
$ABI{"SymbolVersion"} = {};
if(my $SymbolVersion = parseTag(\$ABI_DUMP, "symbol_version"))
{
while(my $Symbol = parseTag(\$SymbolVersion, "symbol")) {
$ABI{"SymbolVersion"}{parseTag(\$Symbol, "name")} = parseTag(\$Symbol, "version");
}
}
$ABI{"SkipTypes"} = {};
if(my $SkipTypes = parseTag(\$ABI_DUMP, "skip_types"))
{
while(my $Name = parseTag(\$SkipTypes, "name")) {
$ABI{"SkipTypes"}{$Name} = 1;
}
}
$ABI{"SkipSymbols"} = {};
if(my $SkipSymbols = parseTag(\$ABI_DUMP, "skip_symbols"))
{
while(my $Name = parseTag(\$SkipSymbols, "name")) {
$ABI{"SkipSymbols"}{$Name} = 1;
}
}
$ABI{"SkipNameSpaces"} = {};
if(my $SkipNameSpaces = parseTag(\$ABI_DUMP, "skip_namespaces"))
{
while(my $Name = parseTag(\$SkipNameSpaces, "name")) {
$ABI{"SkipNameSpaces"}{$Name} = 1;
}
}
$ABI{"SkipHeaders"} = {};
if(my $SkipHeaders = parseTag(\$ABI_DUMP, "skip_headers"))
{
while(my $Name = parseTag(\$SkipHeaders, "name")) {
$ABI{"SkipHeaders"}{$Name} = 1;
}
}
if(my $TargetHeaders = parseTag(\$ABI_DUMP, "target_headers"))
{
while(my $Name = parseTag(\$TargetHeaders, "name")) {
$ABI{"TargetHeaders"}{$Name} = 1;
}
}
if(my $Mode = parseTag(\$ABI_DUMP, "mode")) {
$ABI{"Mode"} = $Mode;
}
if(my $Kind = parseTag(\$ABI_DUMP, "kind"))
{
if($Kind eq "BinOnly") {
$ABI{"BinOnly"} = 1;
}
elsif($Kind eq "SrcBin") {
$ABI{"SrcBin"} = 1;
}
}
my %RInfo = ();
parseTag_E(\$ABI_DUMP, "ABI_dump", \%RInfo);
$ABI{"ABI_DUMP_VERSION"} = $RInfo{"version"};
$ABI{"XML_ABI_DUMP_VERSION"} = $RInfo{"xml_format"};
$ABI{"ABI_COMPLIANCE_CHECKER_VERSION"} = $RInfo{"acc"};
return \%ABI;
}
sub parseTag_E($$$)
{
my ($CodeRef, $Tag, $Info) = @_;
if(not $Tag or not $CodeRef
or not $Info) {
return undef;
}
if(${$CodeRef}=~s/\<\Q$Tag\E(\s+([^<>]+)|)\>((.|\n)*?)\<\/\Q$Tag\E\>//)
{
my ($Ext, $Content) = ($2, $3);
$Content=~s/\A\s+//g;
$Content=~s/\s+\Z//g;
if($Ext)
{
while($Ext=~s/(\w+)\=\"([^\"]*)\"//)
{
my ($K, $V) = ($1, $2);
$Info->{$K} = xmlSpecChars_R($V);
}
}
if(substr($Content, 0, 1) ne "<") {
$Content = xmlSpecChars_R($Content);
}
return $Content;
}
return undef;
}
sub addTag(@)
{
my $Tag = shift(@_);
my $Val = shift(@_);
my @Ext = @_;
my $Content = openTag($Tag, @Ext);
chomp($Content);
$Content .= xmlSpecChars($Val);
$Content .= "</$Tag>\n";
$TAG_ID-=1;
return $Content;
}
sub openTag(@)
{
my $Tag = shift(@_);
my @Ext = @_;
my $Content = "";
foreach (1 .. $TAG_ID) {
$Content .= $INDENT;
}
$TAG_ID+=1;
if(@Ext)
{
$Content .= "<".$Tag;
my $P = 0;
while($P<=$#Ext-1)
{
$Content .= " ".$Ext[$P];
$Content .= "=\"".xmlSpecChars($Ext[$P+1])."\"";
$P+=2;
}
$Content .= ">\n";
}
else {
$Content .= "<".$Tag.">\n";
}
return $Content;
}
sub closeTag($)
{
my $Tag = $_[0];
my $Content = "";
$TAG_ID-=1;
foreach (1 .. $TAG_ID) {
$Content .= $INDENT;
}
$Content .= "</".$Tag.">\n";
return $Content;
}
sub checkTags()
{
if($TAG_ID!=0) {
printMsg("WARNING", "the number of opened tags is not equal to number of closed tags");
}
}
return 1;