1cdf0e10cSrcweir:
2cdf0e10cSrcweireval 'exec perl -wS $0 ${1+"$@"}'
3cdf0e10cSrcweir    if 0;
4*7e90fac2SAndrew Rist#**************************************************************
5*7e90fac2SAndrew Rist#
6*7e90fac2SAndrew Rist#  Licensed to the Apache Software Foundation (ASF) under one
7*7e90fac2SAndrew Rist#  or more contributor license agreements.  See the NOTICE file
8*7e90fac2SAndrew Rist#  distributed with this work for additional information
9*7e90fac2SAndrew Rist#  regarding copyright ownership.  The ASF licenses this file
10*7e90fac2SAndrew Rist#  to you under the Apache License, Version 2.0 (the
11*7e90fac2SAndrew Rist#  "License"); you may not use this file except in compliance
12*7e90fac2SAndrew Rist#  with the License.  You may obtain a copy of the License at
13*7e90fac2SAndrew Rist#
14*7e90fac2SAndrew Rist#    http://www.apache.org/licenses/LICENSE-2.0
15*7e90fac2SAndrew Rist#
16*7e90fac2SAndrew Rist#  Unless required by applicable law or agreed to in writing,
17*7e90fac2SAndrew Rist#  software distributed under the License is distributed on an
18*7e90fac2SAndrew Rist#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
19*7e90fac2SAndrew Rist#  KIND, either express or implied.  See the License for the
20*7e90fac2SAndrew Rist#  specific language governing permissions and limitations
21*7e90fac2SAndrew Rist#  under the License.
22*7e90fac2SAndrew Rist#
23*7e90fac2SAndrew Rist#**************************************************************
24*7e90fac2SAndrew Rist
25*7e90fac2SAndrew Rist
26cdf0e10cSrcweir
27cdf0e10cSrcweir#here the definition for d would be written into dependencies. The reason is that when the event handler
28cdf0e10cSrcweir#for the element is called, we can only find out the namespace but not the prefix. So we cannot
29cdf0e10cSrcweir#distinguish if the namespace is used because the element was prefixed or because it uses the default
30cdf0e10cSrcweir#namespace.
31cdf0e10cSrcweiruse warnings;
32cdf0e10cSrcweiruse strict;
33cdf0e10cSrcweir
34cdf0e10cSrcweiruse XML::Parser;
35cdf0e10cSrcweiruse Getopt::Long;
36cdf0e10cSrcweiruse Carp;
37cdf0e10cSrcweir
38cdf0e10cSrcweirsub getUpdateInfoFileName($);
39cdf0e10cSrcweirsub writeUpdateInformationData($);
40cdf0e10cSrcweirsub findAttribute($$);
41cdf0e10cSrcweirsub getNotDefPrefs($$$);
42cdf0e10cSrcweirsub collectPrefixes($$$$);
43cdf0e10cSrcweirsub determineNsDefinitions($$$);
44cdf0e10cSrcweirsub determineNsDefinitionForItem($$$);
45cdf0e10cSrcweir
46cdf0e10cSrcweirmy $inDescription = 0;
47cdf0e10cSrcweirmy $inDependencies = 0;
48cdf0e10cSrcweirmy $inIdentifier = 0;
49cdf0e10cSrcweirmy $inVersion = 0;
50cdf0e10cSrcweirmy $descNS = "http://openoffice.org/extensions/description/2006";
51cdf0e10cSrcweir                   my $indent;
52cdf0e10cSrcweirmy $identifier;
53cdf0e10cSrcweirmy $version;
54cdf0e10cSrcweir
55cdf0e10cSrcweir#contains prefixes and the corresponding namespaces which are used in the <dependencies>
56cdf0e10cSrcweir#element and all children of the description.xml
57cdf0e10cSrcweirmy @usedNsInDependencies;
58cdf0e10cSrcweir
59cdf0e10cSrcweir#Maps  prefix to namespaces which are valid in <dependencies>. That is, they are
60cdf0e10cSrcweir#either defined in <dependencies> or in the hirarchy above <dependencies>
61cdf0e10cSrcweirmy %validPrefsInDep;
62cdf0e10cSrcweir#Contains the prefixes which are defined in <dependencies>
63cdf0e10cSrcweirmy @newPrefsInDep;
64cdf0e10cSrcweir#Contains the prefixes/namespaces which need to be defined in <dependencies> but which are currently
65cdf0e10cSrcweir#not. For example a prefix is defined in the parent and is used in a child of <dependencies>
66cdf0e10cSrcweirmy %notDefInDep;
67cdf0e10cSrcweir
68cdf0e10cSrcweir#prefix used in start and end element
69cdf0e10cSrcweirmy $prefix;
70cdf0e10cSrcweir
71cdf0e10cSrcweir#The default namespace valid in <dependencies>
72cdf0e10cSrcweirmy $defNsInDep;
73cdf0e10cSrcweir#The prefix which we use for the default namespace used in <dependencies>
74cdf0e10cSrcweirmy $generatedPrefix;
75cdf0e10cSrcweir
76cdf0e10cSrcweirmy $helptext =
77cdf0e10cSrcweir"make_ext_update_info.pl produces an update information file for an extension. ".
78cdf0e10cSrcweir"It will use a dummy URL as URL for the extension update unless a URL has been ".
79cdf0e10cSrcweir"provided with the --update_url option. The name of the update ".
80cdf0e10cSrcweir"information file, which must be provided with the --out switch, should be formed ".
81cdf0e10cSrcweir"according to this scheme: \n\n".
82cdf0e10cSrcweir"extension_identifier.update.xml\n\n".
83cdf0e10cSrcweir"extension_identifier should correspond to the extension identifier. In some cases ".
84cdf0e10cSrcweir"this may not be possible because the identifier may contain characters which are not ".
85cdf0e10cSrcweir"allowd in file names.\n\n".
86cdf0e10cSrcweir"usage:\n".
87cdf0e10cSrcweir"perl make_ext_update_info.pl [--help][--update_url url] --out update_information_file description.xml \n\n".
88cdf0e10cSrcweir"Options: \n".
89cdf0e10cSrcweir"--help - prints the help message and exits \n".
90cdf0e10cSrcweir"--out file - the update information file to be written including the path \n".
91cdf0e10cSrcweir"--update-url url - inserts the url under the <update-download> element. It may be necessary to enclose the urls in quotes in case they contain characters such as \"?\". ".
92cdf0e10cSrcweir"It can be used multiple times\n\n";
93cdf0e10cSrcweir
94cdf0e10cSrcweir#handling of arguments
95cdf0e10cSrcweirmy $help = 0;
96cdf0e10cSrcweirmy $out;
97cdf0e10cSrcweirmy @update_urls;
98cdf0e10cSrcweirif (!GetOptions('help|?' => \$help,
99cdf0e10cSrcweir                'out=s' => \$out,
100cdf0e10cSrcweir                'update-url=s'=> \@update_urls))
101cdf0e10cSrcweir{
102cdf0e10cSrcweir    print $helptext;
103cdf0e10cSrcweir    exit -1;
104cdf0e10cSrcweir}
105cdf0e10cSrcweirmy $cArgs = scalar @ARGV;
106cdf0e10cSrcweirdie "You need to provide a description.xml\n\n$helptext" if $cArgs ==0;
107cdf0e10cSrcweirdie "You need to provide the name of the update information file ".
108cdf0e10cSrcweir    "with the --out switch.\n" unless ($out);
109cdf0e10cSrcweirdie "Too many arguments. \n\n$helptext" if $cArgs > 1;
110cdf0e10cSrcweirprint $helptext if $help;
111cdf0e10cSrcweir
112cdf0e10cSrcweir
113cdf0e10cSrcweir#open the update information file for writing
114cdf0e10cSrcweirmy $FH;
115cdf0e10cSrcweiropen $FH, "> $out" or die $!;
116cdf0e10cSrcweir
117cdf0e10cSrcweir#write the xml header and root element
118cdf0e10cSrcweirprint $FH '<?xml version="1.0" encoding="UTF-8"?>', "\n";
119cdf0e10cSrcweirprint $FH '<description xmlns="http://openoffice.org/extensions/update/2006"', "\n";
120cdf0e10cSrcweirprint $FH '    xmlns:xlink="http://www.w3.org/1999/xlink">', "\n";
121cdf0e10cSrcweir
122cdf0e10cSrcweir#obtain from description.xml the data for the update information
123cdf0e10cSrcweirwriteUpdateInformationData($ARGV[0]);
124cdf0e10cSrcweir#We will die if there is no <version> or <identifier> in the description.xml
125cdf0e10cSrcweirdie "Error: The description.xml does not contain a <identifier> element.\n" unless $identifier;
126cdf0e10cSrcweirdie "Error: The description.xml does not contain a <version> element. \n" unless $version;
127cdf0e10cSrcweir
128cdf0e10cSrcweir#write the write the update-download element and the children.
129cdf0e10cSrcweir#the indention of <update-download> corresponds to that of <version>
130cdf0e10cSrcweirprint $FH ' 'x$indent, '<update-download>', "\n";
131cdf0e10cSrcweir#check if update-urls have been provided through --update-url option
132cdf0e10cSrcweirif (scalar @update_urls)
133cdf0e10cSrcweir{
134cdf0e10cSrcweir    my $urlIndent = $indent > 8 ? 8 : 2 * $indent;
135cdf0e10cSrcweir    #use provided urls
136cdf0e10cSrcweir    for (@update_urls)
137cdf0e10cSrcweir    {
138cdf0e10cSrcweir        print $FH ' 'x$urlIndent, '<src xlink:href="'.$_.'" />', "\n";
139cdf0e10cSrcweir    }
140cdf0e10cSrcweir}
141cdf0e10cSrcweirelse
142cdf0e10cSrcweir{
143cdf0e10cSrcweir    #use dummy update url
144cdf0e10cSrcweir    print $FH ' 'x8, '<src xlink:href="http://extensions.openoffice.org/testarea/dummy.oxt" />', "\n";
145cdf0e10cSrcweir}
146cdf0e10cSrcweirprint $FH ' 'x$indent, '</update-download>', "\n";
147cdf0e10cSrcweir
148cdf0e10cSrcweirprint $FH '</description>', "\n";
149cdf0e10cSrcweirclose $FH;
150cdf0e10cSrcweir
151cdf0e10cSrcweirexit 0;
152cdf0e10cSrcweir
153cdf0e10cSrcweir
154cdf0e10cSrcweir
155cdf0e10cSrcweirsub start_handler
156cdf0e10cSrcweir{
157cdf0e10cSrcweir    my $parser = shift;
158cdf0e10cSrcweir    my $name = shift;
159cdf0e10cSrcweir
160cdf0e10cSrcweir    if ($name eq "description"
161cdf0e10cSrcweir        && $descNS eq $parser->namespace($name))
162cdf0e10cSrcweir    {
163cdf0e10cSrcweir        $inDescription = 1;
164cdf0e10cSrcweir    }
165cdf0e10cSrcweir    elsif ($inDescription
166cdf0e10cSrcweir           && $name eq "version"
167cdf0e10cSrcweir           && $descNS eq  $parser->namespace($name))
168cdf0e10cSrcweir    {
169cdf0e10cSrcweir        $inVersion = 1;
170cdf0e10cSrcweir        $version = 1;
171cdf0e10cSrcweir        $indent = $parser->current_column();
172cdf0e10cSrcweir        print $FH " "x$indent, $parser->original_string();
173cdf0e10cSrcweir    }
174cdf0e10cSrcweir    elsif ($inDescription
175cdf0e10cSrcweir           && $name eq "identifier"
176cdf0e10cSrcweir           && $descNS eq  $parser->namespace($name))
177cdf0e10cSrcweir    {
178cdf0e10cSrcweir        $inIdentifier = 1;
179cdf0e10cSrcweir        $identifier = 1;
180cdf0e10cSrcweir        print $FH " "x$parser->current_column(), $parser->original_string();
181cdf0e10cSrcweir    }
182cdf0e10cSrcweir    elsif ($inDescription
183cdf0e10cSrcweir           && $name eq "dependencies"
184cdf0e10cSrcweir           && $descNS eq  $parser->namespace($name))
185cdf0e10cSrcweir    {
186cdf0e10cSrcweir        $inDependencies = 1;
187cdf0e10cSrcweir        my $dep = $parser->original_string();
188cdf0e10cSrcweir        #add the additional namespace definitions, which we have discovered during the first
189cdf0e10cSrcweir        #parsing
190cdf0e10cSrcweir        #cut of the closing > or /> from the start element, so we can append the namespace definitions
191cdf0e10cSrcweir        $dep =~ /(\s*<.*) ((\s*\/>)|(\s*>))/x;
192cdf0e10cSrcweir        my $dep1 = $1;
193cdf0e10cSrcweir        $dep1.= " xmlns:".$_.'="'.$notDefInDep{$_}.'"' for (keys %notDefInDep);
194cdf0e10cSrcweir        $dep1.= $2;
195cdf0e10cSrcweir        print $FH " "x$parser->current_column(), $dep1;
196cdf0e10cSrcweir    }
197cdf0e10cSrcweir    elsif ($inDependencies)
198cdf0e10cSrcweir    {
199cdf0e10cSrcweir        #$prefix is global because we need to use it in the end element as well.
200cdf0e10cSrcweir        $prefix = "";
201cdf0e10cSrcweir        my $fullString;
202cdf0e10cSrcweir        my $orig = $parser->original_string();
203cdf0e10cSrcweir        #Split up the string so we can insert the prefix for the element.
204cdf0e10cSrcweir        # <OpenOffice.org-minimal-version>
205cdf0e10cSrcweir        # <d:OpenOffice.org-minimal-version>
206cdf0e10cSrcweir        $orig=~/(\s*<)(.*?)\s/x;
207cdf0e10cSrcweir        #in $2 is the element name, look for the prefix
208cdf0e10cSrcweir        if ($2 !~/(.*?):/ && $parser->namespace($name)) {
209cdf0e10cSrcweir            #no prefix, that is element uses default namespace.
210cdf0e10cSrcweir            #Now check if the default namespace in <dependencies> is the same as the one in this
211cdf0e10cSrcweir            #element. If not, then the default ns was defined "after" <dependencies>. Because all
212cdf0e10cSrcweir            #children of <dependencies> are copied into the update information, so will this default
213cdf0e10cSrcweir            #namespace definition. Hence this element will have the same default namespace in the
214cdf0e10cSrcweir            #update information.
215cdf0e10cSrcweir            my $defNsDep = $validPrefsInDep{"#default"};
216cdf0e10cSrcweir            #we must have #default, see the if statement above
217cdf0e10cSrcweir            my $defNsCur = $parser->expand_ns_prefix("#default");
218cdf0e10cSrcweir
219cdf0e10cSrcweir            if ($defNsDep eq $defNsCur) {
220cdf0e10cSrcweir                #Determine if there is in <dependency> a prefix defined (only valid there and need not
221cdf0e10cSrcweir                #directly defined in this element). If there is no prefix defined then we will
222cdf0e10cSrcweir                #add a new definition to <dependencies>.
223cdf0e10cSrcweir                for (keys %validPrefsInDep) {
224cdf0e10cSrcweir                    if (($validPrefsInDep{$_} eq $defNsDep) && $_ ne "#default") {
225cdf0e10cSrcweir                        $prefix = $_; last;
226cdf0e10cSrcweir                    }
227cdf0e10cSrcweir                }
228cdf0e10cSrcweir                if (! $prefix) {
229cdf0e10cSrcweir                    #If there was no prefix, we will add new prefix definition to <dependency>
230cdf0e10cSrcweir                    #Which prefix this is has been determined during the first parsing.
231cdf0e10cSrcweir                    for (keys %notDefInDep) {
232cdf0e10cSrcweir                        if (($notDefInDep{$_} eq $defNsCur) && $_ ne "#default") {
233cdf0e10cSrcweir                            $prefix = $_; last;
234cdf0e10cSrcweir                        }
235cdf0e10cSrcweir                    }
236cdf0e10cSrcweir                }
237cdf0e10cSrcweir                #die if we have no prefix
238cdf0e10cSrcweir                confess "No prefix defined for default namespace " unless $prefix;
239cdf0e10cSrcweir                #get the full part after <
240cdf0e10cSrcweir                $orig=~/(\s*<)(.*)/x;
241cdf0e10cSrcweir                $fullString= $1.$prefix.":".$2;
242cdf0e10cSrcweir            }
243cdf0e10cSrcweir
244cdf0e10cSrcweir        }
245cdf0e10cSrcweir        $fullString = $orig unless $fullString;
246cdf0e10cSrcweir
247cdf0e10cSrcweir        # We record anything within <dependencies> </dependencies>.
248cdf0e10cSrcweir        print $FH $fullString;
249cdf0e10cSrcweir    }
250cdf0e10cSrcweir}
251cdf0e10cSrcweir
252cdf0e10cSrcweirsub end_handler
253cdf0e10cSrcweir{
254cdf0e10cSrcweir    my $parser = shift;
255cdf0e10cSrcweir    my $name = shift;
256cdf0e10cSrcweir
257cdf0e10cSrcweir    if ($name eq "description"
258cdf0e10cSrcweir        && $descNS eq  $parser->namespace($name))
259cdf0e10cSrcweir    {
260cdf0e10cSrcweir        $inDescription = 0;
261cdf0e10cSrcweir    }
262cdf0e10cSrcweir    elsif ($inDescription
263cdf0e10cSrcweir           && $name eq "version"
264cdf0e10cSrcweir           && $descNS eq  $parser->namespace($name))
265cdf0e10cSrcweir    {
266cdf0e10cSrcweir        $inVersion = 0;
267cdf0e10cSrcweir        print $FH  $parser->original_string(), "\n";
268cdf0e10cSrcweir    }
269cdf0e10cSrcweir    elsif ($inDescription
270cdf0e10cSrcweir           && $name eq "identifier"
271cdf0e10cSrcweir           && $descNS eq  $parser->namespace($name))
272cdf0e10cSrcweir    {
273cdf0e10cSrcweir        $inIdentifier = 0;
274cdf0e10cSrcweir        print $FH $parser->original_string(), "\n";
275cdf0e10cSrcweir    }
276cdf0e10cSrcweir    elsif($inDescription
277cdf0e10cSrcweir          && $name eq "dependencies"
278cdf0e10cSrcweir          && $descNS eq $parser->namespace($name))
279cdf0e10cSrcweir    {
280cdf0e10cSrcweir        $inDependencies = 0;
281cdf0e10cSrcweir        print $FH $parser->original_string(), "\n";
282cdf0e10cSrcweir    }
283cdf0e10cSrcweir    elsif ($inDependencies)
284cdf0e10cSrcweir    {
285cdf0e10cSrcweir        my $orig = $parser->original_string();
286cdf0e10cSrcweir        #$orig is empty if we have tags like this: <name />
287cdf0e10cSrcweir        if ($orig && $prefix) {
288cdf0e10cSrcweir            $orig=~/(\s*<\/)(.*)/x;
289cdf0e10cSrcweir            $orig= $1.$prefix.":".$2;
290cdf0e10cSrcweir        }
291cdf0e10cSrcweir        print $FH $orig;
292cdf0e10cSrcweir    }
293cdf0e10cSrcweir}
294cdf0e10cSrcweir
295cdf0e10cSrcweir#We write the complete content between start and end tags of
296cdf0e10cSrcweir# <identifier>, <version>, <dependencies>
297cdf0e10cSrcweirsub default_handler
298cdf0e10cSrcweir{
299cdf0e10cSrcweir    my $parser = shift;
300cdf0e10cSrcweir    my $name = shift;
301cdf0e10cSrcweir    if ($inIdentifier || $inVersion) {
302cdf0e10cSrcweir        print $FH $parser->original_string();
303cdf0e10cSrcweir    } elsif ($inDependencies) {
304cdf0e10cSrcweir        print $FH  $parser->original_string();
305cdf0e10cSrcweir    }
306cdf0e10cSrcweir
307cdf0e10cSrcweir}  # End of default_handler
308cdf0e10cSrcweir
309cdf0e10cSrcweir#sax handler used for the first parsing to recognize the used prefixes in <dependencies > and its
310cdf0e10cSrcweir#children and to find out if we need to define a new prefix for the current default namespace.
311cdf0e10cSrcweirsub start_handler_infos
312cdf0e10cSrcweir{
313cdf0e10cSrcweir    my $parser = shift;
314cdf0e10cSrcweir    my $name = shift;
315cdf0e10cSrcweir    if ($name eq "description"
316cdf0e10cSrcweir        && $descNS eq $parser->namespace($name)) {
317cdf0e10cSrcweir        $inDescription = 1;
318cdf0e10cSrcweir    }
319cdf0e10cSrcweir    elsif ($inDescription
320cdf0e10cSrcweir           && $name eq "dependencies"
321cdf0e10cSrcweir           && $descNS eq  $parser->namespace($name)) {
322cdf0e10cSrcweir        $inDependencies = 1;
323cdf0e10cSrcweir        #build the map of prefix/namespace which are valid in <dependencies>
324cdf0e10cSrcweir        my @cur = $parser->current_ns_prefixes();
325cdf0e10cSrcweir        for (@cur) {
326cdf0e10cSrcweir            $validPrefsInDep{$_} = $parser->expand_ns_prefix($_);
327cdf0e10cSrcweir        }
328cdf0e10cSrcweir        #remember the prefixes defined in <dependencies>
329cdf0e10cSrcweir        @newPrefsInDep = $parser->new_ns_prefixes();
330cdf0e10cSrcweir
331cdf0e10cSrcweir        collectPrefixes($parser, $name, \@_, \@usedNsInDependencies);
332cdf0e10cSrcweir        return if  $generatedPrefix;
333cdf0e10cSrcweir
334cdf0e10cSrcweir        #determine if need to create a new prefix for the current element if it uses a default ns.
335cdf0e10cSrcweir        #Split up the string so we can see if there is a prefix used
336cdf0e10cSrcweir        # <OpenOffice.org-minimal-version>
337cdf0e10cSrcweir        # <d:OpenOffice.org-minimal-version>
338cdf0e10cSrcweir        my $orig = $parser->original_string();
339cdf0e10cSrcweir        $orig=~/(\s*<)(.*?)\s/x;
340cdf0e10cSrcweir        #in $2 is the element name, look for the prefix
341cdf0e10cSrcweir        if ($2 !~/(.*?):/ && $parser->namespace($name)) {
342cdf0e10cSrcweir            #no prefix, that is element uses default namespace.
343cdf0e10cSrcweir            #Now check if the default namespace in <dependencies> is the same as the one in this
344cdf0e10cSrcweir            #element. If not, then the default ns was defined "after" <dependencies>. Because all
345cdf0e10cSrcweir            #children of <dependencies> are copied into the update information, so will this default
346cdf0e10cSrcweir            #namespace definition. Hence this element will have the same default namespace in the
347cdf0e10cSrcweir            #update information.
348cdf0e10cSrcweir            my $defNsDep = $validPrefsInDep{"#default"};
349cdf0e10cSrcweir            #we must have #default, see the if statement above
350cdf0e10cSrcweir            my $defNsCur = $parser->expand_ns_prefix("#default");
351cdf0e10cSrcweir
352cdf0e10cSrcweir            if ($defNsDep eq $defNsCur) {
353cdf0e10cSrcweir                #Determine if there is in <dependency> a prefix defined (only valid there and need not
354cdf0e10cSrcweir                #directly defined in this element). If there is no prefix defined then we will
355cdf0e10cSrcweir                #add a new definition to <dependencies>.
356cdf0e10cSrcweir                for (keys %validPrefsInDep) {
357cdf0e10cSrcweir                    if (($validPrefsInDep{$_} eq $defNsDep) && $_ ne "#default") {
358cdf0e10cSrcweir                        $prefix = $_; last;
359cdf0e10cSrcweir                    }
360cdf0e10cSrcweir                }
361cdf0e10cSrcweir
362cdf0e10cSrcweir                if (! $prefix) {
363cdf0e10cSrcweir
364cdf0e10cSrcweir                    #define a new prefix
365cdf0e10cSrcweir                    #actually there can be only onle prefix, which is the case when the element
366cdf0e10cSrcweir                    #uses the same default namespace as <dependencies> otherwise, the default
367cdf0e10cSrcweir                    #namespace was redefined by the children of <dependencies>. These are completely
368cdf0e10cSrcweir                    #copied and still valid in the update information file
369cdf0e10cSrcweir                    $generatedPrefix = "a";
370cdf0e10cSrcweir                    $defNsInDep = $defNsDep;
371cdf0e10cSrcweir                }
372cdf0e10cSrcweir            }
373cdf0e10cSrcweir        }
374cdf0e10cSrcweir
375cdf0e10cSrcweir    }
376cdf0e10cSrcweir    elsif ($inDependencies) {
377cdf0e10cSrcweir        determineNsDefinitions($parser, $name, \@_);
378cdf0e10cSrcweir        collectPrefixes($parser, $name, \@_, \@usedNsInDependencies);
379cdf0e10cSrcweir    }
380cdf0e10cSrcweir}
381cdf0e10cSrcweir#sax handler used for the first parsing to recognize the used prefixes in <dependencies > and its
382cdf0e10cSrcweir#children
383cdf0e10cSrcweirsub end_handler_infos
384cdf0e10cSrcweir{
385cdf0e10cSrcweir    my $parser = shift;
386cdf0e10cSrcweir    my $name = shift;
387cdf0e10cSrcweir
388cdf0e10cSrcweir    if ($name eq "description"
389cdf0e10cSrcweir        && $descNS eq  $parser->namespace($name)) {
390cdf0e10cSrcweir        $inDescription = 0;
391cdf0e10cSrcweir    }
392cdf0e10cSrcweir    elsif($inDescription
393cdf0e10cSrcweir          && $name eq "dependencies"
394cdf0e10cSrcweir          && $descNS eq $parser->namespace($name)) {
395cdf0e10cSrcweir        $inDependencies = 0;
396cdf0e10cSrcweir    }
397cdf0e10cSrcweir}
398cdf0e10cSrcweir
399cdf0e10cSrcweirsub writeUpdateInformationData($)
400cdf0e10cSrcweir{
401cdf0e10cSrcweir    my $desc = shift;
402cdf0e10cSrcweir    {
403cdf0e10cSrcweir        #parse description xml to collect information about all used
404cdf0e10cSrcweir        #prefixes and names within <dependencies>
405cdf0e10cSrcweir
406cdf0e10cSrcweir        my $parser = new XML::Parser(ErrorContext => 2,
407cdf0e10cSrcweir                                     Namespaces => 1);
408cdf0e10cSrcweir        $parser->setHandlers(Start => \&start_handler_infos,
409cdf0e10cSrcweir                             End => \&end_handler_infos);
410cdf0e10cSrcweir
411cdf0e10cSrcweir        $parser->parsefile($desc);
412cdf0e10cSrcweir
413cdf0e10cSrcweir
414cdf0e10cSrcweir    }
415cdf0e10cSrcweir    #remove duplicates in the array containing the prefixes
416cdf0e10cSrcweir    if ($generatedPrefix) {
417cdf0e10cSrcweir        my %hashtmp;
418cdf0e10cSrcweir        @usedNsInDependencies = grep(!$hashtmp{$_}++, @usedNsInDependencies);
419cdf0e10cSrcweir
420cdf0e10cSrcweir        #check that the prefix for the default namespace in <dependencies> does not clash
421cdf0e10cSrcweir        #with any other prefixes
422cdf0e10cSrcweir        my $clash;
423cdf0e10cSrcweir        do {
424cdf0e10cSrcweir            $clash = 0;
425cdf0e10cSrcweir            for (@usedNsInDependencies) {
426cdf0e10cSrcweir                if ($_ eq $generatedPrefix) {
427cdf0e10cSrcweir                    $generatedPrefix++;
428cdf0e10cSrcweir                    $clash = 1; last;
429cdf0e10cSrcweir                }
430cdf0e10cSrcweir            }
431cdf0e10cSrcweir        } while ($clash);
432cdf0e10cSrcweir        $notDefInDep{$generatedPrefix} = $defNsInDep;
433cdf0e10cSrcweir    }
434cdf0e10cSrcweir    #if $notDefInDep contains the prefix #default then we need to add the generated prefix as well
435cdf0e10cSrcweir
436cdf0e10cSrcweir    #add the special prefix for the default namespace into the map of prefixes that will be
437cdf0e10cSrcweir    #added to the <dependencies> element in the update information file
438cdf0e10cSrcweir
439cdf0e10cSrcweir
440cdf0e10cSrcweir    ($inDependencies, $inDescription) = (0,0);
441cdf0e10cSrcweir    {
442cdf0e10cSrcweir        my $parser = new XML::Parser(ErrorContext => 2,
443cdf0e10cSrcweir                                     Namespaces => 1);
444cdf0e10cSrcweir        $parser->setHandlers(
445cdf0e10cSrcweir                             Start => \&start_handler,
446cdf0e10cSrcweir                             End => \&end_handler,
447cdf0e10cSrcweir                             Default => \&default_handler);
448cdf0e10cSrcweir        $parser->parsefile($desc);
449cdf0e10cSrcweir    }
450cdf0e10cSrcweir}
451cdf0e10cSrcweir
452cdf0e10cSrcweir# param 1: name of the attribute we look for
453cdf0e10cSrcweir# param 2: array of name value pairs, the first subscript is the attribute and the second
454cdf0e10cSrcweir# is the value.
455cdf0e10cSrcweirsub findAttribute($$)
456cdf0e10cSrcweir{
457cdf0e10cSrcweir    my ($name, $args_r) = @_;
458cdf0e10cSrcweir    my @args = @{$args_r};
459cdf0e10cSrcweir    my $value;
460cdf0e10cSrcweir    while (my $attr = shift(@args))
461cdf0e10cSrcweir    {
462cdf0e10cSrcweir        if ($attr eq $name) {
463cdf0e10cSrcweir            $value = shift(@args);
464cdf0e10cSrcweir            die "href attribut has no valid URL" unless $value;
465cdf0e10cSrcweir            last;
466cdf0e10cSrcweir        } else { # shift away the following value for the attribute
467cdf0e10cSrcweir            shift(@args);
468cdf0e10cSrcweir        }
469cdf0e10cSrcweir    }
470cdf0e10cSrcweir    return $value;
471cdf0e10cSrcweir}
472cdf0e10cSrcweir
473cdf0e10cSrcweir#collect the prefixes used in an xml element
474cdf0e10cSrcweir#param 1: parser,
475cdf0e10cSrcweir#param 2: element name,
476cdf0e10cSrcweir#param 3: array of name and values of attributes
477cdf0e10cSrcweir#param 4: out parameter, the array containing the prefixes
478cdf0e10cSrcweirsub collectPrefixes($$$$)
479cdf0e10cSrcweir{
480cdf0e10cSrcweir    my $parser = shift;
481cdf0e10cSrcweir    my $name = shift;
482cdf0e10cSrcweir    my $attr_r = shift;
483cdf0e10cSrcweir    my $out_r = shift;
484cdf0e10cSrcweir    #get the prefixes which are currently valid
485cdf0e10cSrcweir    my @cur = $parser->current_ns_prefixes();
486cdf0e10cSrcweir    my %map_ns;
487cdf0e10cSrcweir    #get the namespaces for the prefixes
488cdf0e10cSrcweir    for (@cur) {
489cdf0e10cSrcweir        if ($_ eq '#default') {
490cdf0e10cSrcweir            next;
491cdf0e10cSrcweir        }
492cdf0e10cSrcweir        my $ns = $parser->expand_ns_prefix($_);
493cdf0e10cSrcweir        $map_ns{$ns} = $_;
494cdf0e10cSrcweir    }
495cdf0e10cSrcweir    #investigat ns of element
496cdf0e10cSrcweir    my $pref = $map_ns{$parser->namespace($name)};
497cdf0e10cSrcweir    push(@{$out_r}, $pref) if $pref;
498cdf0e10cSrcweir    #now go over the attributes
499cdf0e10cSrcweir
500cdf0e10cSrcweir    while (my $attr = shift(@{$attr_r})) {
501cdf0e10cSrcweir        my $ns = $parser->namespace($attr);
502cdf0e10cSrcweir        if (! $ns) {
503cdf0e10cSrcweir            shift(@{$attr_r});
504cdf0e10cSrcweir            next;
505cdf0e10cSrcweir        }
506cdf0e10cSrcweir        $pref = $map_ns{$ns};
507cdf0e10cSrcweir        push( @{$out_r}, $pref) if $pref;
508cdf0e10cSrcweir        shift(@{$attr_r});
509cdf0e10cSrcweir    }
510cdf0e10cSrcweir    #also add newly defined prefixes
511cdf0e10cSrcweir    my @newNs = $parser->new_ns_prefixes();
512cdf0e10cSrcweir    for (@newNs) {
513cdf0e10cSrcweir        if ($_ eq '#default') {
514cdf0e10cSrcweir            next;
515cdf0e10cSrcweir        }
516cdf0e10cSrcweir        push (@{$out_r}, $_);
517cdf0e10cSrcweir    }
518cdf0e10cSrcweir}
519cdf0e10cSrcweir
520cdf0e10cSrcweir#The function is called for each child element of dependencies. It finds out the prefixes
521cdf0e10cSrcweir#which are used by the children and which are defined by the parents of <dependencies>. These
522cdf0e10cSrcweir#would be lost when copying the children of <dependencies> into the update information file.
523cdf0e10cSrcweir#Therefore these definitions are collected so that they then can be written in the <dependencies>
524cdf0e10cSrcweir#element of the update information file.
525cdf0e10cSrcweir#param 1: parser
526cdf0e10cSrcweir#param 2: namsepace
527cdf0e10cSrcweir#param 3: the @_ received in the start handler
528cdf0e10cSrcweirsub determineNsDefinitions($$$)
529cdf0e10cSrcweir{
530cdf0e10cSrcweir    my ($parser, $name, $attr_r) = @_;
531cdf0e10cSrcweir    my @attr = @{$attr_r};
532cdf0e10cSrcweir
533cdf0e10cSrcweir    determineNsDefinitionForItem($parser, $name, 1);
534cdf0e10cSrcweir
535cdf0e10cSrcweir    while (my $attr = shift(@attr)) {
536cdf0e10cSrcweir        determineNsDefinitionForItem($parser, $attr, 0);
537cdf0e10cSrcweir        shift @attr;
538cdf0e10cSrcweir    }
539cdf0e10cSrcweir}
540cdf0e10cSrcweir
541cdf0e10cSrcweir#do not call this function for the element that does not use a prefix
542cdf0e10cSrcweir#param 1: parser
543cdf0e10cSrcweir#param 2: name of the element or attribute
544cdf0e10cSrcweir#param 3: 1 if called for an elment name and 0 when called for attribue
545cdf0e10cSrcweirsub determineNsDefinitionForItem($$$)
546cdf0e10cSrcweir{
547cdf0e10cSrcweir    my ($parser, $name) = @_;
548cdf0e10cSrcweir    my $ns = $parser->namespace($name);
549cdf0e10cSrcweir    if (! $ns) {
550cdf0e10cSrcweir        return;
551cdf0e10cSrcweir    }
552cdf0e10cSrcweir    #If the namespace was not kwown in <dependencies> then it was defined in one of its children
553cdf0e10cSrcweir    #or in this element. Then we are done since this namespace definition is copied into the
554cdf0e10cSrcweir    #update information.
555cdf0e10cSrcweir    my $bNsKnownInDep;
556cdf0e10cSrcweir    for ( keys %validPrefsInDep) {
557cdf0e10cSrcweir        if ( $validPrefsInDep{$_} eq $ns) {
558cdf0e10cSrcweir            $bNsKnownInDep = 1;
559cdf0e10cSrcweir            last;
560cdf0e10cSrcweir        }
561cdf0e10cSrcweir    }
562cdf0e10cSrcweir    #If the namespace of the current element is known in <dependencies> then check if the same
563cdf0e10cSrcweir    #prefix is used. If not, then the prefix was defined in one of the children of <dependencies>
564cdf0e10cSrcweir    #and was assigned the same namespace. Because we copy of children into the update information,
565cdf0e10cSrcweir    #this definition is also copied.
566cdf0e10cSrcweir    if ($bNsKnownInDep) {
567cdf0e10cSrcweir        #create a map of currently valid prefix/namespace
568cdf0e10cSrcweir        my %curPrefToNs;
569cdf0e10cSrcweir        my @curNs = $parser->current_ns_prefixes();
570cdf0e10cSrcweir        for (@curNs) {
571cdf0e10cSrcweir            $curPrefToNs{$_} = $parser->expand_ns_prefix($_);
572cdf0e10cSrcweir        }
573cdf0e10cSrcweir        #find the prefix used in <dependencies> to define the namespace of the current element
574cdf0e10cSrcweir        my $validDepPref;
575cdf0e10cSrcweir        for (keys %validPrefsInDep) {
576cdf0e10cSrcweir            if ($validPrefsInDep{$_} eq $ns) {
577cdf0e10cSrcweir                #ignore #default
578cdf0e10cSrcweir                next if $_ eq "#default";
579cdf0e10cSrcweir                $validDepPref = $_;
580cdf0e10cSrcweir                last;
581cdf0e10cSrcweir            }
582cdf0e10cSrcweir        }
583cdf0e10cSrcweir        #find the prefix defined in the current element used for the namespace of the element
584cdf0e10cSrcweir        my $curPref;
585cdf0e10cSrcweir        for (keys %curPrefToNs) {
586cdf0e10cSrcweir            if ($curPrefToNs{$_} eq $ns) {
587cdf0e10cSrcweir                #ignore #default
588cdf0e10cSrcweir                next if $_ eq "#default";
589cdf0e10cSrcweir                $curPref = $_;
590cdf0e10cSrcweir                last;
591cdf0e10cSrcweir            }
592cdf0e10cSrcweir        }
593cdf0e10cSrcweir        if ($curPref && $validDepPref && ($curPref eq $validDepPref)) {
594cdf0e10cSrcweir            #If the prefixes and ns are the same, then the prefix definition of <dependencies> or its
595cdf0e10cSrcweir            #parent can be used. However, we need to find out which prefixed are NOT defined in
596cdf0e10cSrcweir            #<dependencies> so we can add them to it when we write the update information.
597cdf0e10cSrcweir            my $bDefined = 0;
598cdf0e10cSrcweir            for (@newPrefsInDep) {
599cdf0e10cSrcweir                if ($curPref eq $_) {
600cdf0e10cSrcweir                    $bDefined = 1;
601cdf0e10cSrcweir                    last;
602cdf0e10cSrcweir                }
603cdf0e10cSrcweir            }
604cdf0e10cSrcweir            if (! $bDefined) {
605cdf0e10cSrcweir                $notDefInDep{$curPref} = $ns;
606cdf0e10cSrcweir            }
607cdf0e10cSrcweir        }
608cdf0e10cSrcweir    }
609cdf0e10cSrcweir}
610