Home | History | Annotate | Download | only in Internals
      1 ###########################################################################
      2 # Module for ABI Compliance Checker to create ABI dumps in XML format
      3 #
      4 # Copyright (C) 2009-2011 Institute for System Programming, RAS
      5 # Copyright (C) 2011-2012 Nokia Corporation and/or its subsidiary(-ies)
      6 # Copyright (C) 2011-2012 ROSA Laboratory
      7 # Copyright (C) 2012-2015 Andrey Ponomarenko's ABI Laboratory
      8 #
      9 # Written by Andrey Ponomarenko
     10 #
     11 # This program is free software: you can redistribute it and/or modify
     12 # it under the terms of the GNU General Public License or the GNU Lesser
     13 # General Public License as published by the Free Software Foundation.
     14 #
     15 # This program is distributed in the hope that it will be useful,
     16 # but WITHOUT ANY WARRANTY; without even the implied warranty of
     17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     18 # GNU General Public License for more details.
     19 #
     20 # You should have received a copy of the GNU General Public License
     21 # and the GNU Lesser General Public License along with this program.
     22 # If not, see <http://www.gnu.org/licenses/>.
     23 ###########################################################################
     24 use strict;
     25 
     26 my $TAG_ID = 0;
     27 my $INDENT = "    ";
     28 
     29 sub createXmlDump($)
     30 {
     31     my $ABI = $_[0];
     32     my $ABI_DUMP = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
     33     
     34     $ABI_DUMP .= "<ABI_dump version=\"".$ABI->{"ABI_DUMP_VERSION"}."\"";
     35     $ABI_DUMP .= " xml_format=\"".$ABI->{"XML_ABI_DUMP_VERSION"}."\"";
     36     $ABI_DUMP .= " acc=\"".$ABI->{"ABI_COMPLIANCE_CHECKER_VERSION"}."\">\n";
     37     
     38     $ABI_DUMP .= addTag("library", $ABI->{"LibraryName"});
     39     $ABI_DUMP .= addTag("library_version", $ABI->{"LibraryVersion"});
     40     $ABI_DUMP .= addTag("language", $ABI->{"Language"});
     41     
     42     $ABI_DUMP .= addTag("gcc", $ABI->{"GccVersion"});
     43     $ABI_DUMP .= addTag("architecture", $ABI->{"Arch"});
     44     $ABI_DUMP .= addTag("target", $ABI->{"Target"});
     45     $ABI_DUMP .= addTag("word_size", $ABI->{"WordSize"});
     46     
     47     if($ABI->{"Mode"}) {
     48         $ABI_DUMP .= addTag("mode", $ABI->{"Mode"});
     49     }
     50     if($ABI->{"SrcBin"}) {
     51         $ABI_DUMP .= addTag("kind", "SrcBin");
     52     }
     53     elsif($ABI->{"BinOnly"}) {
     54         $ABI_DUMP .= addTag("kind", "BinOnly");
     55     }
     56     
     57     if(my @Headers = keys(%{$ABI->{"Headers"}}))
     58     {
     59         @Headers = sort {$ABI->{"Headers"}{$a}<=>$ABI->{"Headers"}{$b}} @Headers;
     60         $ABI_DUMP .= openTag("headers");
     61         foreach my $Name (@Headers) {
     62             $ABI_DUMP .= addTag("name", $Name);
     63         }
     64         $ABI_DUMP .= closeTag("headers");
     65     }
     66     
     67     if(my @NameSpaces = keys(%{$ABI->{"NameSpaces"}}))
     68     {
     69         $ABI_DUMP .= openTag("namespaces");
     70         foreach my $NameSpace (sort {lc($a) cmp lc($b)} @NameSpaces) {
     71             $ABI_DUMP .= addTag("name", $NameSpace);
     72         }
     73         $ABI_DUMP .= closeTag("namespaces");
     74     }
     75     
     76     if(my @TypeInfo = keys(%{$ABI->{"TypeInfo"}}))
     77     {
     78         $ABI_DUMP .= openTag("type_info");
     79         foreach my $ID (sort {$a<=>$b} @TypeInfo)
     80         {
     81             my %TInfo = %{$ABI->{"TypeInfo"}{$ID}};
     82             $ABI_DUMP .= openTag("data_type");
     83             $ABI_DUMP .= addTag("id", $ID);
     84             foreach my $Attr ("Name", "Type", "Size",
     85             "Header", "Line", "NameSpace", "Class", "Return", "Algn")
     86             {
     87                 if(defined $TInfo{$Attr}) {
     88                     $ABI_DUMP .= addTag(lc($Attr), $TInfo{$Attr});
     89                 }
     90             }
     91             if($TInfo{"Private"}) {
     92                 $ABI_DUMP .= addTag("access", "private");
     93             }
     94             if($TInfo{"Protected"}) {
     95                 $ABI_DUMP .= addTag("access", "protected");
     96             }
     97             if(my @Positions = keys(%{$TInfo{"Memb"}}))
     98             {
     99                 $ABI_DUMP .= openTag("members");
    100                 foreach my $Pos (sort { $a<=>$b } @Positions)
    101                 {
    102                     $ABI_DUMP .= openTag("field");
    103                     $ABI_DUMP .= addTag("name", $TInfo{"Memb"}{$Pos}{"name"});
    104                     if(my $MTid = $TInfo{"Memb"}{$Pos}{"type"}) {
    105                         $ABI_DUMP .= addTag("type", $MTid);
    106                     }
    107                     if(my $Access = $TInfo{"Memb"}{$Pos}{"access"}) {
    108                         $ABI_DUMP .= addTag("access", $Access);
    109                     }
    110                     my $Val = $TInfo{"Memb"}{$Pos}{"value"};
    111                     if(defined $Val) {
    112                         $ABI_DUMP .= addTag("value", $Val);
    113                     }
    114                     if(my $Align = $TInfo{"Memb"}{$Pos}{"algn"}) {
    115                         $ABI_DUMP .= addTag("algn", $Align);
    116                     }
    117                     if(my $Bitfield = $TInfo{"Memb"}{$Pos}{"bitfield"}) {
    118                         $ABI_DUMP .= addTag("bitfield", $Bitfield);
    119                     }
    120                     if($TInfo{"Memb"}{$Pos}{"mutable"}) {
    121                         $ABI_DUMP .= addTag("spec", "mutable");
    122                     }
    123                     $ABI_DUMP .= addTag("pos", $Pos);
    124                     $ABI_DUMP .= closeTag("field");
    125                 }
    126                 $ABI_DUMP .= closeTag("members");
    127             }
    128             if(my @Positions = keys(%{$TInfo{"Param"}}))
    129             {
    130                 $ABI_DUMP .= openTag("parameters");
    131                 foreach my $Pos (sort { $a<=>$b } @Positions)
    132                 {
    133                     $ABI_DUMP .= openTag("param");
    134                     if(my $PTid = $TInfo{"Param"}{$Pos}{"type"}) {
    135                         $ABI_DUMP .= addTag("type", $PTid);
    136                     }
    137                     $ABI_DUMP .= addTag("pos", $Pos);
    138                     $ABI_DUMP .= closeTag("param");
    139                 }
    140                 $ABI_DUMP .= closeTag("parameters");
    141             }
    142             if(my @Positions = keys(%{$TInfo{"TParam"}}))
    143             {
    144                 $ABI_DUMP .= openTag("template_parameters");
    145                 foreach my $Pos (sort { $a<=>$b } @Positions)
    146                 {
    147                     $ABI_DUMP .= openTag("param");
    148                     $ABI_DUMP .= addTag("name", $TInfo{"TParam"}{$Pos}{"name"});
    149                     $ABI_DUMP .= addTag("pos", $Pos);
    150                     $ABI_DUMP .= closeTag("param");
    151                 }
    152                 $ABI_DUMP .= closeTag("template_parameters");
    153             }
    154             if(my @Offsets = keys(%{$TInfo{"VTable"}}))
    155             {
    156                 $ABI_DUMP .= openTag("vtable");
    157                 foreach my $Offset (sort { $a<=>$b } @Offsets)
    158                 {
    159                     $ABI_DUMP .= openTag("entry");
    160                     $ABI_DUMP .= addTag("offset", $Offset);
    161                     $ABI_DUMP .= addTag("value", $TInfo{"VTable"}{$Offset});
    162                     $ABI_DUMP .= closeTag("entry");
    163                 }
    164                 $ABI_DUMP .= closeTag("vtable");
    165             }
    166             if(my $BTid = $TInfo{"BaseType"}) {
    167                 $ABI_DUMP .= addTag("base_type", $BTid);
    168             }
    169             if(my @BaseIDs = keys(%{$TInfo{"Base"}}))
    170             {
    171                 @BaseIDs = sort { $TInfo{"Base"}{$a}{"pos"}<=>$TInfo{"Base"}{$b}{"pos"} } @BaseIDs;
    172                 $ABI_DUMP .= openTag("base");
    173                 foreach my $BaseID (@BaseIDs)
    174                 {
    175                     $ABI_DUMP .= openTag("class");
    176                     $ABI_DUMP .= addTag("id", $BaseID);
    177                     if(my $Access = $TInfo{"Base"}{$BaseID}{"access"}) {
    178                         $ABI_DUMP .= addTag("access", $Access);
    179                     }
    180                     if(my $Virt = $TInfo{"Base"}{$BaseID}{"virtual"}) {
    181                         $ABI_DUMP .= addTag("inherit", "virtual");
    182                     }
    183                     $ABI_DUMP .= addTag("pos", $TInfo{"Base"}{$BaseID}{"pos"});
    184                     $ABI_DUMP .= closeTag("class");
    185                 }
    186                 $ABI_DUMP .= closeTag("base");
    187             }
    188             if($TInfo{"Copied"}) {
    189                 $ABI_DUMP .= addTag("note", "copied");
    190             }
    191             if($TInfo{"Spec"}) {
    192                 $ABI_DUMP .= addTag("note", "specialization");
    193             }
    194             if($TInfo{"Forward"}) {
    195                 $ABI_DUMP .= addTag("note", "forward");
    196             }
    197             $ABI_DUMP .= closeTag("data_type");
    198         }
    199         $ABI_DUMP .= closeTag("type_info");
    200     }
    201     
    202     if(my @Constants = keys(%{$ABI->{"Constants"}}))
    203     {
    204         $ABI_DUMP .= openTag("constants");
    205         foreach my $Constant (@Constants)
    206         {
    207             my %CInfo = %{$ABI->{"Constants"}{$Constant}};
    208             $ABI_DUMP .= openTag("constant");
    209             $ABI_DUMP .= addTag("name", $Constant);
    210             $ABI_DUMP .= addTag("value", $CInfo{"Value"});
    211             $ABI_DUMP .= addTag("header", $CInfo{"Header"});
    212             $ABI_DUMP .= closeTag("constant");
    213         }
    214         $ABI_DUMP .= closeTag("constants");
    215     }
    216     
    217     if(my @SymbolInfo = keys(%{$ABI->{"SymbolInfo"}}))
    218     {
    219         my %TR = (
    220             "MnglName" => "mangled",
    221             "ShortName" => "short"
    222         );
    223         $ABI_DUMP .= openTag("symbol_info");
    224         foreach my $ID (sort {$a<=>$b} @SymbolInfo)
    225         {
    226             my %SInfo = %{$ABI->{"SymbolInfo"}{$ID}};
    227             $ABI_DUMP .= openTag("symbol");
    228             $ABI_DUMP .= addTag("id", $ID);
    229             foreach my $Attr ("MnglName", "ShortName", "Class",
    230             "Header", "Line", "Return", "NameSpace", "Value")
    231             {
    232                 if(defined $SInfo{$Attr})
    233                 {
    234                     my $Tag = $Attr;
    235                     if($TR{$Attr}) {
    236                         $Tag = $TR{$Attr};
    237                     }
    238                     $ABI_DUMP .= addTag(lc($Tag), $SInfo{$Attr});
    239                 }
    240             }
    241             if($SInfo{"Constructor"}) {
    242                 $ABI_DUMP .= addTag("kind", "constructor");
    243             }
    244             if($SInfo{"Destructor"}) {
    245                 $ABI_DUMP .= addTag("kind", "destructor");
    246             }
    247             if($SInfo{"Data"}) {
    248                 $ABI_DUMP .= addTag("kind", "data");
    249             }
    250             if($SInfo{"Virt"}) {
    251                 $ABI_DUMP .= addTag("spec", "virtual");
    252             }
    253             elsif($SInfo{"PureVirt"}) {
    254                 $ABI_DUMP .= addTag("spec", "pure virtual");
    255             }
    256             elsif($SInfo{"Static"}) {
    257                 $ABI_DUMP .= addTag("spec", "static");
    258             }
    259             if($SInfo{"InLine"}) {
    260                 $ABI_DUMP .= addTag("spec", "inline");
    261             }
    262             if($SInfo{"Const"}) {
    263                 $ABI_DUMP .= addTag("spec", "const");
    264             }
    265             if($SInfo{"Volatile"}) {
    266                 $ABI_DUMP .= addTag("spec", "volatile");
    267             }
    268             if($SInfo{"Private"}) {
    269                 $ABI_DUMP .= addTag("access", "private");
    270             }
    271             if($SInfo{"Protected"}) {
    272                 $ABI_DUMP .= addTag("access", "protected");
    273             }
    274             if($SInfo{"Artificial"}) {
    275                 $ABI_DUMP .= addTag("note", "artificial");
    276             }
    277             if(my $Lang = $SInfo{"Lang"}) {
    278                 $ABI_DUMP .= addTag("lang", $Lang);
    279             }
    280             if(my @Positions = keys(%{$SInfo{"Param"}}))
    281             {
    282                 $ABI_DUMP .= openTag("parameters");
    283                 foreach my $Pos (sort { $a<=>$b } @Positions)
    284                 {
    285                     $ABI_DUMP .= openTag("param");
    286                     if(my $PName = $SInfo{"Param"}{$Pos}{"name"}) {
    287                         $ABI_DUMP .= addTag("name", $PName);
    288                     }
    289                     if(my $PTid = $SInfo{"Param"}{$Pos}{"type"}) {
    290                         $ABI_DUMP .= addTag("type", $PTid);
    291                     }
    292                     my $Default = $SInfo{"Param"}{$Pos}{"default"};
    293                     if(defined $Default) {
    294                         $ABI_DUMP .= addTag("default", $Default);
    295                     }
    296                     if(my $Align = $SInfo{"Param"}{$Pos}{"algn"}) {
    297                         $ABI_DUMP .= addTag("algn", $Align);
    298                     }
    299                     if(defined $SInfo{"Param"}{$Pos}{"reg"}) {
    300                         $ABI_DUMP .= addTag("call", "register");
    301                     }
    302                     $ABI_DUMP .= addTag("pos", $Pos);
    303                     $ABI_DUMP .= closeTag("param");
    304                 }
    305                 $ABI_DUMP .= closeTag("parameters");
    306             }
    307             if(my @Positions = keys(%{$SInfo{"TParam"}}))
    308             {
    309                 $ABI_DUMP .= openTag("template_parameters");
    310                 foreach my $Pos (sort { $a<=>$b } @Positions)
    311                 {
    312                     $ABI_DUMP .= openTag("param");
    313                     $ABI_DUMP .= addTag("name", $SInfo{"TParam"}{$Pos}{"name"});
    314                     $ABI_DUMP .= closeTag("param");
    315                 }
    316                 $ABI_DUMP .= closeTag("template_parameters");
    317             }
    318             $ABI_DUMP .= closeTag("symbol");
    319         }
    320         $ABI_DUMP .= closeTag("symbol_info");
    321     }
    322     
    323     if(my @Libs = keys(%{$ABI->{"Symbols"}}))
    324     {
    325         $ABI_DUMP .= openTag("symbols");
    326         foreach my $Lib (sort {lc($a) cmp lc($b)} @Libs)
    327         {
    328             $ABI_DUMP .= openTag("library", "name", $Lib);
    329             foreach my $Symbol (sort {lc($a) cmp lc($b)} keys(%{$ABI->{"Symbols"}{$Lib}}))
    330             {
    331                 if((my $Size = $ABI->{"Symbols"}{$Lib}{$Symbol})<0)
    332                 { # data
    333                     $ABI_DUMP .= addTag("symbol", $Symbol, "size", -$Size);
    334                 }
    335                 else
    336                 { # functions
    337                     $ABI_DUMP .= addTag("symbol", $Symbol);
    338                 }
    339             }
    340             $ABI_DUMP .= closeTag("library");
    341         }
    342         $ABI_DUMP .= closeTag("symbols");
    343     }
    344     
    345     if(my @DepLibs = keys(%{$ABI->{"DepSymbols"}}))
    346     {
    347         $ABI_DUMP .= openTag("dep_symbols");
    348         foreach my $Lib (sort {lc($a) cmp lc($b)} @DepLibs)
    349         {
    350             $ABI_DUMP .= openTag("library", "name", $Lib);
    351             foreach my $Symbol (sort {lc($a) cmp lc($b)} keys(%{$ABI->{"DepSymbols"}{$Lib}}))
    352             {
    353                 if((my $Size = $ABI->{"DepSymbols"}{$Lib}{$Symbol})<0)
    354                 { # data
    355                     $ABI_DUMP .= addTag("symbol", $Symbol, "size", -$Size);
    356                 }
    357                 else
    358                 { # functions
    359                     $ABI_DUMP .= addTag("symbol", $Symbol);
    360                 }
    361             }
    362             $ABI_DUMP .= closeTag("library");
    363         }
    364         $ABI_DUMP .= closeTag("dep_symbols");
    365     }
    366     
    367     if(my @VSymbols = keys(%{$ABI->{"SymbolVersion"}}))
    368     {
    369         $ABI_DUMP .= openTag("symbol_version");
    370         foreach my $Symbol (sort {lc($a) cmp lc($b)} @VSymbols)
    371         {
    372             $ABI_DUMP .= openTag("symbol");
    373             $ABI_DUMP .= addTag("name", $Symbol);
    374             $ABI_DUMP .= addTag("version", $ABI->{"SymbolVersion"}{$Symbol});
    375             $ABI_DUMP .= closeTag("symbol");
    376         }
    377         $ABI_DUMP .= closeTag("symbol_version");
    378     }
    379     
    380     if(my @SkipTypes = keys(%{$ABI->{"SkipTypes"}}))
    381     {
    382         $ABI_DUMP .= openTag("skip_types");
    383         foreach my $Name (sort {lc($a) cmp lc($b)} @SkipTypes) {
    384             $ABI_DUMP .= addTag("name", $Name);
    385         }
    386         $ABI_DUMP .= closeTag("skip_types");
    387     }
    388     
    389     if(my @SkipSymbols = keys(%{$ABI->{"SkipSymbols"}}))
    390     {
    391         $ABI_DUMP .= openTag("skip_symbols");
    392         foreach my $Name (sort {lc($a) cmp lc($b)} @SkipSymbols) {
    393             $ABI_DUMP .= addTag("name", $Name);
    394         }
    395         $ABI_DUMP .= closeTag("skip_symbols");
    396     }
    397     
    398     if(my @SkipNameSpaces = keys(%{$ABI->{"SkipNameSpaces"}}))
    399     {
    400         $ABI_DUMP .= openTag("skip_namespaces");
    401         foreach my $Name (sort {lc($a) cmp lc($b)} @SkipNameSpaces) {
    402             $ABI_DUMP .= addTag("name", $Name);
    403         }
    404         $ABI_DUMP .= closeTag("skip_namespaces");
    405     }
    406     
    407     if(my @SkipHeaders = keys(%{$ABI->{"SkipHeaders"}}))
    408     {
    409         $ABI_DUMP .= openTag("skip_headers");
    410         foreach my $Name (sort {lc($a) cmp lc($b)} @SkipHeaders) {
    411             $ABI_DUMP .= addTag("name", $Name);
    412         }
    413         $ABI_DUMP .= closeTag("skip_headers");
    414     }
    415     
    416     if(my @TargetHeaders = keys(%{$ABI->{"TargetHeaders"}}))
    417     {
    418         $ABI_DUMP .= openTag("target_headers");
    419         foreach my $Name (sort {lc($a) cmp lc($b)} @TargetHeaders) {
    420             $ABI_DUMP .= addTag("name", $Name);
    421         }
    422         $ABI_DUMP .= closeTag("target_headers");
    423     }
    424     
    425     $ABI_DUMP .= "</ABI_dump>\n";
    426     
    427     checkTags();
    428     
    429     return $ABI_DUMP;
    430 }
    431 
    432 sub readXmlDump($)
    433 {
    434     my $ABI_DUMP = readFile($_[0]);
    435     my %ABI = {};
    436     
    437     $ABI{"LibraryName"} = parseTag(\$ABI_DUMP, "library");
    438     $ABI{"LibraryVersion"} = parseTag(\$ABI_DUMP, "library_version");
    439     $ABI{"Language"} = parseTag(\$ABI_DUMP, "language");
    440     $ABI{"GccVersion"} = parseTag(\$ABI_DUMP, "gcc");
    441     $ABI{"Arch"} = parseTag(\$ABI_DUMP, "architecture");
    442     $ABI{"Target"} = parseTag(\$ABI_DUMP, "target");
    443     $ABI{"WordSize"} = parseTag(\$ABI_DUMP, "word_size");
    444     
    445     my $Pos = 0;
    446     
    447     if(my $Headers = parseTag(\$ABI_DUMP, "headers"))
    448     {
    449         while(my $Name = parseTag(\$Headers, "name")) {
    450             $ABI{"Headers"}{$Name} = $Pos++;
    451         }
    452     }
    453     
    454     if(my $NameSpaces = parseTag(\$ABI_DUMP, "namespaces"))
    455     {
    456         while(my $Name = parseTag(\$NameSpaces, "name")) {
    457             $ABI{"NameSpaces"}{$Name} = 1;
    458         }
    459     }
    460     
    461     if(my $TypeInfo = parseTag(\$ABI_DUMP, "type_info"))
    462     {
    463         while(my $DataType = parseTag(\$TypeInfo, "data_type"))
    464         {
    465             my %TInfo = ();
    466             my $ID = parseTag(\$DataType, "id");
    467             
    468             if(my $Members = parseTag(\$DataType, "members"))
    469             {
    470                 $Pos = 0;
    471                 while(my $Field = parseTag(\$Members, "field"))
    472                 {
    473                     my %MInfo = ();
    474                     $MInfo{"name"} = parseTag(\$Field, "name");
    475                     if(my $Tid = parseTag(\$Field, "type")) {
    476                         $MInfo{"type"} = $Tid;
    477                     }
    478                     if(my $Access = parseTag(\$Field, "access")) {
    479                         $MInfo{"access"} = $Access;
    480                     }
    481                     my $Val = parseTag(\$Field, "value");
    482                     if(defined $Val) {
    483                         $MInfo{"value"} = $Val;
    484                     }
    485                     if(my $Align = parseTag(\$Field, "algn")) {
    486                         $MInfo{"algn"} = $Align;
    487                     }
    488                     if(my $Bitfield = parseTag(\$Field, "bitfield")) {
    489                         $MInfo{"bitfield"} = $Bitfield;
    490                     }
    491                     if(my $Spec = parseTag(\$Field, "spec")) {
    492                         $MInfo{$Spec} = 1;
    493                     }
    494                     $TInfo{"Memb"}{$Pos++} = \%MInfo;
    495                 }
    496             }
    497             
    498             if(my $Parameters = parseTag(\$DataType, "parameters"))
    499             {
    500                 $Pos = 0;
    501                 while(my $Parameter = parseTag(\$Parameters, "param"))
    502                 {
    503                     my %PInfo = ();
    504                     if(my $Tid = parseTag(\$Parameter, "type")) {
    505                         $PInfo{"type"} = $Tid;
    506                     }
    507                     $TInfo{"Param"}{$Pos++} = \%PInfo;
    508                 }
    509             }
    510             if(my $TParams = parseTag(\$DataType, "template_parameters"))
    511             {
    512                 $Pos = 0;
    513                 while(my $TParam = parseTag(\$TParams, "param")) {
    514                     $TInfo{"TParam"}{$Pos++}{"name"} = parseTag(\$TParam, "name");
    515                 }
    516             }
    517             if(my $VTable = parseTag(\$DataType, "vtable"))
    518             {
    519                 $Pos = 0;
    520                 while(my $Entry = parseTag(\$VTable, "entry")) {
    521                     $TInfo{"VTable"}{parseTag(\$Entry, "offset")} = parseTag(\$Entry, "value");
    522                 }
    523             }
    524             if(my $BTid = parseTag(\$DataType, "base_type")) {
    525                 $TInfo{"BaseType"} = $BTid;
    526             }
    527             if(my $Base = parseTag(\$DataType, "base"))
    528             {
    529                 $Pos = 0;
    530                 while(my $Class = parseTag(\$Base, "class"))
    531                 {
    532                     my %CInfo = ();
    533                     $CInfo{"pos"} = parseTag(\$Class, "pos");
    534                     if(my $Access = parseTag(\$Class, "access")) {
    535                         $CInfo{"access"} = $Access;
    536                     }
    537                     if(my $Inherit = parseTag(\$Class, "inherit"))
    538                     {
    539                         if($Inherit eq "virtual") {
    540                             $CInfo{"virtual"} = 1;
    541                         }
    542                     }
    543                     $TInfo{"Base"}{parseTag(\$Class, "id")} = \%CInfo;
    544                 }
    545             }
    546             while(my $Note = parseTag(\$DataType, "note"))
    547             {
    548                 if($Note eq "copied") {
    549                     $TInfo{"Copied"} = 1;
    550                 }
    551                 elsif($Note eq "specialization") {
    552                     $TInfo{"Spec"} = 1;
    553                 }
    554                 elsif($Note eq "forward") {
    555                     $TInfo{"Forward"} = 1;
    556                 }
    557             }
    558             foreach my $Attr ("Name", "Type", "Size",
    559             "Header", "Line", "NameSpace", "Class", "Return", "Algn")
    560             {
    561                 my $Val = parseTag(\$DataType, lc($Attr));
    562                 if(defined $Val) {
    563                     $TInfo{$Attr} = $Val;
    564                 }
    565             }
    566             if(my $Access = parseTag(\$DataType, "access")) {
    567                 $TInfo{ucfirst($Access)} = 1;
    568             }
    569             $ABI{"TypeInfo"}{$ID} = \%TInfo;
    570         }
    571     }
    572     
    573     if(my $Constants = parseTag(\$ABI_DUMP, "constants"))
    574     {
    575         while(my $Constant = parseTag(\$Constants, "constant"))
    576         {
    577             if(my $Name = parseTag(\$Constant, "name"))
    578             {
    579                 my %CInfo = ();
    580                 $CInfo{"Value"} = parseTag(\$Constant, "value");
    581                 $CInfo{"Header"} = parseTag(\$Constant, "header");
    582                 $ABI{"Constants"}{$Name} = \%CInfo;
    583             }
    584         }
    585     }
    586     
    587     if(my $SymbolInfo = parseTag(\$ABI_DUMP, "symbol_info"))
    588     {
    589         my %TR = (
    590             "MnglName"=>"mangled",
    591             "ShortName"=>"short"
    592         );
    593         while(my $Symbol = parseTag(\$SymbolInfo, "symbol"))
    594         {
    595             my %SInfo = ();
    596             my $ID = parseTag(\$Symbol, "id");
    597             
    598             if(my $Parameters = parseTag(\$Symbol, "parameters"))
    599             {
    600                 $Pos = 0;
    601                 while(my $Parameter = parseTag(\$Parameters, "param"))
    602                 {
    603                     my %PInfo = ();
    604                     if(my $PName = parseTag(\$Parameter, "name")) {
    605                         $PInfo{"name"} = $PName;
    606                     }
    607                     if(my $PTid = parseTag(\$Parameter, "type")) {
    608                         $PInfo{"type"} = $PTid;
    609                     }
    610                     my $Default = parseTag(\$Parameter, "default", "spaces");
    611                     if(defined $Default) {
    612                         $PInfo{"default"} = $Default;
    613                     }
    614                     if(my $Align = parseTag(\$Parameter, "algn")) {
    615                         $PInfo{"algn"} = $Align;
    616                     }
    617                     if(my $Call = parseTag(\$Parameter, "call"))
    618                     {
    619                         if($Call eq "register") {
    620                             $PInfo{"reg"} = 1;
    621                         }
    622                     }
    623                     $SInfo{"Param"}{$Pos++} = \%PInfo;
    624                 }
    625             }
    626             if(my $TParams = parseTag(\$Symbol, "template_parameters"))
    627             {
    628                 $Pos = 0;
    629                 while(my $TParam = parseTag(\$TParams, "param")) {
    630                     $SInfo{"TParam"}{$Pos++}{"name"} = parseTag(\$TParam, "name");
    631                 }
    632             }
    633             
    634             foreach my $Attr ("MnglName", "ShortName", "Class",
    635             "Header", "Line", "Return", "NameSpace", "Value")
    636             {
    637                 my $Tag = lc($Attr);
    638                 if($TR{$Attr}) {
    639                     $Tag = $TR{$Attr};
    640                 }
    641                 my $Val = parseTag(\$Symbol, $Tag);
    642                 if(defined $Val) {
    643                     $SInfo{$Attr} = $Val;
    644                 }
    645             }
    646             if(my $Kind = parseTag(\$Symbol, "kind")) {
    647                 $SInfo{ucfirst($Kind)} = 1;
    648             }
    649             while(my $Spec = parseTag(\$Symbol, "spec"))
    650             {
    651                 if($Spec eq "virtual") {
    652                     $SInfo{"Virt"} = 1;
    653                 }
    654                 elsif($Spec eq "pure virtual") {
    655                     $SInfo{"PureVirt"} = 1;
    656                 }
    657                 elsif($Spec eq "inline") {
    658                     $SInfo{"InLine"} = 1;
    659                 }
    660                 else
    661                 { # const, volatile, static
    662                     $SInfo{ucfirst($Spec)} = 1;
    663                 }
    664             }
    665             if(my $Access = parseTag(\$Symbol, "access")) {
    666                 $SInfo{ucfirst($Access)} = 1;
    667             }
    668             if(my $Note = parseTag(\$Symbol, "note")) {
    669                 $SInfo{ucfirst($Note)} = 1;
    670             }
    671             if(my $Lang = parseTag(\$Symbol, "lang")) {
    672                 $SInfo{"Lang"} = $Lang;
    673             }
    674             $ABI{"SymbolInfo"}{$ID} = \%SInfo;
    675         }
    676     }
    677     
    678     if(my $Symbols = parseTag(\$ABI_DUMP, "symbols"))
    679     {
    680         my %LInfo = ();
    681         while(my $LibSymbols = parseTag_E(\$Symbols, "library", \%LInfo))
    682         {
    683             my %SInfo = ();
    684             while(my $Symbol = parseTag_E(\$LibSymbols, "symbol", \%SInfo))
    685             {
    686                 if(my $Size = $SInfo{"size"}) {
    687                     $ABI{"Symbols"}{$LInfo{"name"}}{$Symbol} = -$Size;
    688                 }
    689                 else {
    690                     $ABI{"Symbols"}{$LInfo{"name"}}{$Symbol} = 1;
    691                 }
    692                 %SInfo = ();
    693             }
    694             %LInfo = ();
    695         }
    696     }
    697     
    698     if(my $DepSymbols = parseTag(\$ABI_DUMP, "dep_symbols"))
    699     {
    700         my %LInfo = ();
    701         while(my $LibSymbols = parseTag_E(\$DepSymbols, "library", \%LInfo))
    702         {
    703             my %SInfo = ();
    704             while(my $Symbol = parseTag_E(\$LibSymbols, "symbol", \%SInfo))
    705             {
    706                 if(my $Size = $SInfo{"size"}) {
    707                     $ABI{"DepSymbols"}{$LInfo{"name"}}{$Symbol} = -$Size;
    708                 }
    709                 else {
    710                     $ABI{"DepSymbols"}{$LInfo{"name"}}{$Symbol} = 1;
    711                 }
    712                 %SInfo = ();
    713             }
    714             %LInfo = ();
    715         }
    716     }
    717     
    718     $ABI{"SymbolVersion"} = {};
    719     
    720     if(my $SymbolVersion = parseTag(\$ABI_DUMP, "symbol_version"))
    721     {
    722         while(my $Symbol = parseTag(\$SymbolVersion, "symbol")) {
    723             $ABI{"SymbolVersion"}{parseTag(\$Symbol, "name")} = parseTag(\$Symbol, "version");
    724         }
    725     }
    726     
    727     $ABI{"SkipTypes"} = {};
    728     
    729     if(my $SkipTypes = parseTag(\$ABI_DUMP, "skip_types"))
    730     {
    731         while(my $Name = parseTag(\$SkipTypes, "name")) {
    732             $ABI{"SkipTypes"}{$Name} = 1;
    733         }
    734     }
    735     
    736     $ABI{"SkipSymbols"} = {};
    737     
    738     if(my $SkipSymbols = parseTag(\$ABI_DUMP, "skip_symbols"))
    739     {
    740         while(my $Name = parseTag(\$SkipSymbols, "name")) {
    741             $ABI{"SkipSymbols"}{$Name} = 1;
    742         }
    743     }
    744     
    745     $ABI{"SkipNameSpaces"} = {};
    746     
    747     if(my $SkipNameSpaces = parseTag(\$ABI_DUMP, "skip_namespaces"))
    748     {
    749         while(my $Name = parseTag(\$SkipNameSpaces, "name")) {
    750             $ABI{"SkipNameSpaces"}{$Name} = 1;
    751         }
    752     }
    753     
    754     $ABI{"SkipHeaders"} = {};
    755     
    756     if(my $SkipHeaders = parseTag(\$ABI_DUMP, "skip_headers"))
    757     {
    758         while(my $Name = parseTag(\$SkipHeaders, "name")) {
    759             $ABI{"SkipHeaders"}{$Name} = 1;
    760         }
    761     }
    762     
    763     if(my $TargetHeaders = parseTag(\$ABI_DUMP, "target_headers"))
    764     {
    765         while(my $Name = parseTag(\$TargetHeaders, "name")) {
    766             $ABI{"TargetHeaders"}{$Name} = 1;
    767         }
    768     }
    769     
    770     if(my $Mode = parseTag(\$ABI_DUMP, "mode")) {
    771         $ABI{"Mode"} = $Mode;
    772     }
    773     if(my $Kind = parseTag(\$ABI_DUMP, "kind"))
    774     {
    775         if($Kind eq "BinOnly") {
    776             $ABI{"BinOnly"} = 1;
    777         }
    778         elsif($Kind eq "SrcBin") {
    779             $ABI{"SrcBin"} = 1;
    780         }
    781     }
    782     
    783     my %RInfo = ();
    784     parseTag_E(\$ABI_DUMP, "ABI_dump", \%RInfo);
    785     
    786     $ABI{"ABI_DUMP_VERSION"} = $RInfo{"version"};
    787     $ABI{"XML_ABI_DUMP_VERSION"} = $RInfo{"xml_format"};
    788     $ABI{"ABI_COMPLIANCE_CHECKER_VERSION"} = $RInfo{"acc"};
    789     
    790     return \%ABI;
    791 }
    792 
    793 sub parseTag_E($$$)
    794 {
    795     my ($CodeRef, $Tag, $Info) = @_;
    796     if(not $Tag or not $CodeRef
    797     or not $Info) {
    798         return undef;
    799     }
    800     if(${$CodeRef}=~s/\<\Q$Tag\E(\s+([^<>]+)|)\>((.|\n)*?)\<\/\Q$Tag\E\>//)
    801     {
    802         my ($Ext, $Content) = ($2, $3);
    803         $Content=~s/\A\s+//g;
    804         $Content=~s/\s+\Z//g;
    805         if($Ext)
    806         {
    807             while($Ext=~s/(\w+)\=\"([^\"]*)\"//)
    808             {
    809                 my ($K, $V) = ($1, $2);
    810                 $Info->{$K} = xmlSpecChars_R($V);
    811             }
    812         }
    813         if(substr($Content, 0, 1) ne "<") {
    814             $Content = xmlSpecChars_R($Content);
    815         }
    816         return $Content;
    817     }
    818     return undef;
    819 }
    820 
    821 sub addTag(@)
    822 {
    823     my $Tag = shift(@_);
    824     my $Val = shift(@_);
    825     my @Ext = @_;
    826     my $Content = openTag($Tag, @Ext);
    827     chomp($Content);
    828     $Content .= xmlSpecChars($Val);
    829     $Content .= "</$Tag>\n";
    830     $TAG_ID-=1;
    831     
    832     return $Content;
    833 }
    834 
    835 sub openTag(@)
    836 {
    837     my $Tag = shift(@_);
    838     my @Ext = @_;
    839     my $Content = "";
    840     foreach (1 .. $TAG_ID) {
    841         $Content .= $INDENT;
    842     }
    843     $TAG_ID+=1;
    844     if(@Ext)
    845     {
    846         $Content .= "<".$Tag;
    847         my $P = 0;
    848         while($P<=$#Ext-1)
    849         {
    850             $Content .= " ".$Ext[$P];
    851             $Content .= "=\"".xmlSpecChars($Ext[$P+1])."\"";
    852             $P+=2;
    853         }
    854         $Content .= ">\n";
    855     }
    856     else {
    857         $Content .= "<".$Tag.">\n";
    858     }
    859     return $Content;
    860 }
    861 
    862 sub closeTag($)
    863 {
    864     my $Tag = $_[0];
    865     my $Content = "";
    866     $TAG_ID-=1;
    867     foreach (1 .. $TAG_ID) {
    868         $Content .= $INDENT;
    869     }
    870     $Content .= "</".$Tag.">\n";
    871     return $Content;
    872 }
    873 
    874 sub checkTags()
    875 {
    876     if($TAG_ID!=0) {
    877         printMsg("WARNING", "the number of opened tags is not equal to number of closed tags");
    878     }
    879 }
    880 
    881 return 1;