line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
=pod |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
=head1 NAME |
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
Net::OSCAR::XML -- XML functions for Net::OSCAR |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
=head1 VERSION |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
version 1.928 |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
=head1 DESCRIPTION |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
We're doing the fancy-schmancy Protocol.xml stuff here, so I'll explain it here. |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
Protocol.xml contains a number of "OSCAR protocol elements". One EdefineE block |
16
|
|
|
|
|
|
|
is one OSCAR protocol elemennt. |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
When the module is first loaded, Protocol.xml is parsed and two hashes are created, |
19
|
|
|
|
|
|
|
one whose keys are the names the the elements and whose values are the contents |
20
|
|
|
|
|
|
|
of the XML::Parser tree which represents the contents of those elements; the other |
21
|
|
|
|
|
|
|
hash has a family/subtype tuple as a key and element names as a value. |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
To do something with an element, given its name, Net::OSCAR calls C. |
24
|
|
|
|
|
|
|
This returns a C object, which has C and C methods. |
25
|
|
|
|
|
|
|
C takes a hash and returns a string of binary characters, and C goes the |
26
|
|
|
|
|
|
|
other way around. The objects are cached, so C only has to do actual work once |
27
|
|
|
|
|
|
|
for every protocol element. |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
=cut |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
package Net::OSCAR::XML; |
32
|
|
|
|
|
|
|
BEGIN { |
33
|
5
|
|
|
5
|
|
21548
|
$Net::OSCAR::XML::VERSION = '1.928'; |
34
|
|
|
|
|
|
|
} |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
$REVISION = '$Revision$'; |
37
|
|
|
|
|
|
|
|
38
|
5
|
|
|
5
|
|
28
|
use strict; |
|
5
|
|
|
|
|
8
|
|
|
5
|
|
|
|
|
159
|
|
39
|
5
|
|
|
5
|
|
22
|
use vars qw(@ISA @EXPORT); |
|
5
|
|
|
|
|
9
|
|
|
5
|
|
|
|
|
270
|
|
40
|
5
|
|
|
5
|
|
25
|
use Carp; |
|
5
|
|
|
|
|
8
|
|
|
5
|
|
|
|
|
319
|
|
41
|
5
|
|
|
5
|
|
5437
|
use Data::Dumper; |
|
5
|
|
|
|
|
35763
|
|
|
5
|
|
|
|
|
421
|
|
42
|
|
|
|
|
|
|
|
43
|
5
|
|
|
5
|
|
505
|
use Net::OSCAR::TLV; |
|
5
|
|
|
|
|
10
|
|
|
5
|
|
|
|
|
227
|
|
44
|
5
|
|
|
5
|
|
3273
|
use Net::OSCAR::XML::Template; |
|
5
|
|
|
|
|
15
|
|
|
5
|
|
|
|
|
10930
|
|
45
|
|
|
|
|
|
|
our(%xmlmap, %xml_revmap, $PROTOPARSE_DEBUG, $NO_XML_CACHE); |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
require Exporter; |
48
|
|
|
|
|
|
|
@ISA = qw(Exporter); |
49
|
|
|
|
|
|
|
@EXPORT = qw( |
50
|
|
|
|
|
|
|
protoparse protobit_to_snac snac_to_protobit |
51
|
|
|
|
|
|
|
); |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
$PROTOPARSE_DEBUG = 0; |
54
|
|
|
|
|
|
|
$NO_XML_CACHE = 0; |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
sub _protopack($$;@); |
57
|
|
|
|
|
|
|
sub _xmlnode_to_template($$); |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
sub load_xml(;$) { |
60
|
|
|
|
|
|
|
# Look for parsed-xml file |
61
|
5
|
50
|
|
5
|
0
|
41
|
if(!$NO_XML_CACHE) { |
62
|
5
|
|
|
|
|
24
|
foreach (@INC) { |
63
|
50
|
50
|
|
|
|
1713
|
next unless -f "$_/Net/OSCAR/XML/Protocol.parsed-xml"; |
64
|
|
|
|
|
|
|
|
65
|
0
|
0
|
|
|
|
0
|
open(XMLCACHE, "$_/Net/OSCAR/XML/Protocol.parsed-xml") or next; |
66
|
0
|
|
|
|
|
0
|
my $xmlcache = join("", ); |
67
|
0
|
|
|
|
|
0
|
close(XMLCACHE); |
68
|
|
|
|
|
|
|
|
69
|
0
|
|
|
|
|
0
|
my $xmlparse; |
70
|
0
|
0
|
|
|
|
0
|
eval $xmlcache or die "Coldn't load xml cache: $@\n"; |
71
|
0
|
0
|
|
|
|
0
|
die $@ if $@; |
72
|
0
|
|
|
|
|
0
|
return parse_xml($xmlparse); |
73
|
|
|
|
|
|
|
} |
74
|
|
|
|
|
|
|
} |
75
|
|
|
|
|
|
|
|
76
|
5
|
50
|
|
|
|
17
|
eval { |
77
|
5
|
|
|
|
|
2727
|
require XML::Parser; |
78
|
|
|
|
|
|
|
} or die "Couldn't load XML::Parser ($@)\n"; |
79
|
0
|
0
|
|
|
|
|
die $@ if $@; |
80
|
|
|
|
|
|
|
|
81
|
0
|
|
|
|
|
|
my $xmlparser = new XML::Parser(Style => "Tree"); |
82
|
|
|
|
|
|
|
|
83
|
0
|
|
|
|
|
|
my $xmlfile = ""; |
84
|
0
|
0
|
|
|
|
|
if($_[0]) { |
85
|
0
|
|
|
|
|
|
$xmlfile = shift; |
86
|
|
|
|
|
|
|
} else { |
87
|
0
|
|
|
|
|
|
foreach (@INC) { |
88
|
0
|
0
|
|
|
|
|
next unless -f "$_/Net/OSCAR/XML/Protocol.xml"; |
89
|
0
|
|
|
|
|
|
$xmlfile = "$_/Net/OSCAR/XML/Protocol.xml"; |
90
|
0
|
|
|
|
|
|
last; |
91
|
|
|
|
|
|
|
} |
92
|
0
|
0
|
|
|
|
|
croak "Couldn't find Net/OSCAR/XML/Protocol.xml in search path: " . join(" ", @INC) unless $xmlfile; |
93
|
|
|
|
|
|
|
} |
94
|
|
|
|
|
|
|
|
95
|
0
|
0
|
|
|
|
|
open(XMLFILE, $xmlfile) or croak "Couldn't open $xmlfile: $!"; |
96
|
0
|
|
|
|
|
|
my $xml = join("", ); |
97
|
0
|
|
|
|
|
|
close XMLFILE; |
98
|
0
|
0
|
|
|
|
|
my $xmlparse = $xmlparser->parse($xml) or croak "Couldn't parse XML from $xmlfile: $@"; |
99
|
|
|
|
|
|
|
|
100
|
0
|
|
|
|
|
|
parse_xml($xmlparse); |
101
|
|
|
|
|
|
|
} |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
sub add_xml_data($) { |
104
|
0
|
|
|
0
|
0
|
|
my $xmlparse = shift; |
105
|
|
|
|
|
|
|
|
106
|
0
|
|
|
|
|
|
my @tags = @{$xmlparse->[1]}; # Get contents of |
|
0
|
|
|
|
|
|
|
107
|
0
|
|
|
|
|
|
shift @tags; |
108
|
0
|
|
|
|
|
|
while(@tags) { |
109
|
0
|
|
|
|
|
|
my($name, $value); |
110
|
0
|
|
|
|
|
|
(undef, undef, $name, $value) = splice(@tags, 0, 4); |
111
|
0
|
0
|
0
|
|
|
|
next unless $name and $name eq "define"; |
112
|
|
|
|
|
|
|
|
113
|
0
|
|
|
|
|
|
my %protobit = (xml => $value); |
114
|
0
|
|
|
|
|
|
my %attrs = %{$value->[0]}; |
|
0
|
|
|
|
|
|
|
115
|
0
|
|
|
|
|
|
$protobit{$_} = $attrs{$_} foreach keys %attrs; |
116
|
0
|
0
|
0
|
|
|
|
$xml_revmap{$attrs{family}}->{$attrs{subtype}} = $attrs{name} if exists($attrs{family}) and exists($attrs{subtype}); |
117
|
0
|
|
|
|
|
|
$xmlmap{$attrs{name}} = \%protobit; |
118
|
|
|
|
|
|
|
} |
119
|
|
|
|
|
|
|
} |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
sub parse_xml($) { |
122
|
0
|
|
|
0
|
0
|
|
my $xmlparse = shift; |
123
|
|
|
|
|
|
|
|
124
|
0
|
|
|
|
|
|
%xmlmap = (); |
125
|
0
|
|
|
|
|
|
%xml_revmap = (); |
126
|
|
|
|
|
|
|
# We set the autovivification so that keys of xml_revmap are Net::OSCAR::TLV hashrefs. |
127
|
0
|
0
|
|
|
|
|
if(!tied(%xml_revmap)) { |
128
|
0
|
|
|
|
|
|
tie %xml_revmap, "Net::OSCAR::TLV", 'tie %$value, ref($self)'; |
129
|
|
|
|
|
|
|
} |
130
|
|
|
|
|
|
|
|
131
|
0
|
|
|
|
|
|
add_xml_data($xmlparse); |
132
|
|
|
|
|
|
|
|
133
|
0
|
|
|
|
|
|
return 1; |
134
|
|
|
|
|
|
|
} |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
sub _num_to_packlen($$) { |
137
|
0
|
|
|
0
|
|
|
my($type, $order) = @_; |
138
|
0
|
|
0
|
|
|
|
$order ||= "network"; |
139
|
|
|
|
|
|
|
|
140
|
0
|
0
|
|
|
|
|
if($type eq "byte") { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
141
|
0
|
|
|
|
|
|
return ("C", 1); |
142
|
|
|
|
|
|
|
} elsif($type eq "word") { |
143
|
0
|
0
|
|
|
|
|
if($order eq "vax") { |
144
|
0
|
|
|
|
|
|
return ("v", 2); |
145
|
|
|
|
|
|
|
} else { |
146
|
0
|
|
|
|
|
|
return ("n", 2); |
147
|
|
|
|
|
|
|
} |
148
|
|
|
|
|
|
|
} elsif($type eq "dword") { |
149
|
0
|
0
|
|
|
|
|
if($order eq "vax") { |
150
|
0
|
|
|
|
|
|
return ("V", 4); |
151
|
|
|
|
|
|
|
} else { |
152
|
0
|
|
|
|
|
|
return ("N", 4); |
153
|
|
|
|
|
|
|
} |
154
|
|
|
|
|
|
|
} |
155
|
|
|
|
|
|
|
|
156
|
0
|
|
|
|
|
|
confess "Invalid num type: $type"; |
157
|
|
|
|
|
|
|
} |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
# Specification for OSCAR protocol template: |
160
|
|
|
|
|
|
|
# -Listref whose elements are hashrefs. |
161
|
|
|
|
|
|
|
# -Hashrefs have following keys: |
162
|
|
|
|
|
|
|
# type: "ref", "num", "data", or "tlvchain" |
163
|
|
|
|
|
|
|
# If type = "num": |
164
|
|
|
|
|
|
|
# packlet: Pack template letter (C, n, N, v, V) |
165
|
|
|
|
|
|
|
# len: Length of datum, in bytes |
166
|
|
|
|
|
|
|
# enum_byname: If this is an enum, map of names to values. |
167
|
|
|
|
|
|
|
# enum_byval: If this is an enum, map of values to names. |
168
|
|
|
|
|
|
|
# If type = "data": |
169
|
|
|
|
|
|
|
# Arbitrary data |
170
|
|
|
|
|
|
|
# If prefix isn't present, all available data will be gobbled. |
171
|
|
|
|
|
|
|
# len (optional): Size of datum, in bytes |
172
|
|
|
|
|
|
|
# null_terminated (optional): Data is terminated by a null (0x00) byte |
173
|
|
|
|
|
|
|
# If type = "ref": |
174
|
|
|
|
|
|
|
# name: Name of protocol bit to punt to |
175
|
|
|
|
|
|
|
# If type = "tlvchain": |
176
|
|
|
|
|
|
|
# subtyped: If true, this is a 'subtyped' TLV, as per Protocol.dtd. |
177
|
|
|
|
|
|
|
# prefix: If present, "count" or "length", and "packlet" and "len" will also be present. |
178
|
|
|
|
|
|
|
# items: Listref containing TLVs, hashrefs in format identical to these, with extra key 'num' (and 'subtype', for subtyped TLVs.) |
179
|
|
|
|
|
|
|
# value: If present, default value of this datum. |
180
|
|
|
|
|
|
|
# name: If present, name in parameter list that this datum gets. |
181
|
|
|
|
|
|
|
# count: If present, number of repetitions of this datum. count==-1 represents |
182
|
|
|
|
|
|
|
# infinite. If a count is present when unpacking, the data will be encapsulated in a listref. If the user |
183
|
|
|
|
|
|
|
# wants to pass in multiple data when packing, they should do so via a listref. Listref-encapsulated data with |
184
|
|
|
|
|
|
|
# too many elements for the 'count' will trigger an exception when packing. |
185
|
|
|
|
|
|
|
# prefix: If present, either "count" or "length", and indicates that datum has a prefix indicating its length. |
186
|
|
|
|
|
|
|
# prefix_packet, prefix_len: As per "num". |
187
|
|
|
|
|
|
|
# |
188
|
|
|
|
|
|
|
sub _xmlnode_to_template($$) { |
189
|
0
|
|
|
0
|
|
|
my($tag, $value) = @_; |
190
|
|
|
|
|
|
|
|
191
|
0
|
0
|
|
|
|
|
confess "Invalid value in xmlnode_to_template!" unless ref($value); |
192
|
0
|
|
|
|
|
|
my $attrs = shift @$value; |
193
|
|
|
|
|
|
|
|
194
|
0
|
|
|
|
|
|
my $datum = {}; |
195
|
0
|
0
|
|
|
|
|
$datum->{name} = $attrs->{name} if $attrs->{name}; |
196
|
0
|
0
|
0
|
|
|
|
$datum->{value} = "" if $attrs->{default_generate} and $attrs->{default_generate} ne "no"; |
197
|
0
|
0
|
0
|
|
|
|
$datum->{value} = $value->[1] if @$value and $value->[1] =~ /\S/; |
198
|
|
|
|
|
|
|
|
199
|
0
|
0
|
|
|
|
|
$datum->{count} = $attrs->{count} if $attrs->{count}; |
200
|
0
|
0
|
0
|
|
|
|
if($attrs->{count_prefix} || $attrs->{length_prefix}) { |
201
|
0
|
|
0
|
|
|
|
my($packlet, $len) = _num_to_packlen($attrs->{count_prefix} || $attrs->{length_prefix}, $attrs->{prefix_order}); |
202
|
0
|
|
|
|
|
|
$datum->{prefix_packlet} = $packlet; |
203
|
0
|
|
|
|
|
|
$datum->{prefix_len} = $len; |
204
|
0
|
0
|
|
|
|
|
$datum->{prefix} = $attrs->{count_prefix} ? "count" : "length"; |
205
|
|
|
|
|
|
|
} |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
|
208
|
0
|
0
|
0
|
|
|
|
if($tag eq "ref") { |
|
|
0
|
0
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
0
|
|
|
|
|
|
209
|
0
|
|
|
|
|
|
$datum->{type} = "ref"; |
210
|
|
|
|
|
|
|
} elsif($tag eq "byte" or $tag eq "word" or $tag eq "dword" or $tag eq "enum") { |
211
|
0
|
|
|
|
|
|
$datum->{type} = "num"; |
212
|
|
|
|
|
|
|
|
213
|
0
|
|
|
|
|
|
my $enum = 0; |
214
|
0
|
0
|
|
|
|
|
if($tag eq "enum") { |
215
|
0
|
|
|
|
|
|
$tag = $attrs->{type}; |
216
|
0
|
|
|
|
|
|
$enum = 1; |
217
|
|
|
|
|
|
|
} |
218
|
|
|
|
|
|
|
|
219
|
0
|
|
|
|
|
|
my($packlet, $len) = _num_to_packlen($tag, $attrs->{order}); |
220
|
0
|
|
|
|
|
|
$datum->{packlet} = $packlet; |
221
|
0
|
|
|
|
|
|
$datum->{len} = $len; |
222
|
|
|
|
|
|
|
|
223
|
0
|
0
|
|
|
|
|
if($enum) { |
224
|
0
|
|
|
|
|
|
$datum->{enum_byname} = {}; |
225
|
0
|
|
|
|
|
|
$datum->{enum_byval} = {}; |
226
|
|
|
|
|
|
|
|
227
|
0
|
|
|
|
|
|
while(@$value) { |
228
|
0
|
|
|
|
|
|
my($subtag, $subval) = splice(@$value, 0, 2); |
229
|
0
|
0
|
|
|
|
|
next if $subtag eq "0"; |
230
|
|
|
|
|
|
|
|
231
|
0
|
|
|
|
|
|
my $attrs = shift @$subval; |
232
|
0
|
|
|
|
|
|
my($name, $value, $default) = ($attrs->{name}, $attrs->{value}, $attrs->{default}); |
233
|
0
|
|
|
|
|
|
$datum->{enum_byname}->{$name} = $value; |
234
|
0
|
|
|
|
|
|
$datum->{enum_byval}->{$value} = $name; |
235
|
0
|
0
|
|
|
|
|
$datum->{value} = $value if $default; |
236
|
|
|
|
|
|
|
} |
237
|
|
|
|
|
|
|
} else { |
238
|
0
|
0
|
|
|
|
|
$datum->{value} = $value->[1] if @$value; |
239
|
|
|
|
|
|
|
} |
240
|
|
|
|
|
|
|
} elsif($tag eq "data") { |
241
|
0
|
|
|
|
|
|
$datum->{type} = "data"; |
242
|
0
|
0
|
|
|
|
|
$datum->{len} = $attrs->{length} if $attrs->{length}; |
243
|
0
|
0
|
|
|
|
|
$datum->{pad} = $attrs->{pad} if exists($attrs->{pad}); |
244
|
0
|
0
|
0
|
|
|
|
$datum->{null_terminated} = 1 if $attrs->{null_terminated} and $attrs->{null_terminated} eq "yes"; |
245
|
|
|
|
|
|
|
|
246
|
0
|
|
|
|
|
|
while(@$value) { |
247
|
0
|
|
|
|
|
|
my($subtag, $subval) = splice(@$value, 0, 2); |
248
|
0
|
0
|
|
|
|
|
if($subtag eq "0") { |
249
|
0
|
0
|
0
|
|
|
|
$datum->{value} ||= $subval if $subval =~ /\S/; |
250
|
0
|
|
|
|
|
|
next; |
251
|
|
|
|
|
|
|
} |
252
|
|
|
|
|
|
|
|
253
|
0
|
|
|
|
|
|
my $item = _xmlnode_to_template($subtag, $subval); |
254
|
0
|
|
0
|
|
|
|
$datum->{items} ||= []; |
255
|
0
|
|
|
|
|
|
push @{$datum->{items}}, $item; |
|
0
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
} |
257
|
|
|
|
|
|
|
} elsif($tag eq "tlvchain") { |
258
|
0
|
|
|
|
|
|
$datum->{type} = "tlvchain"; |
259
|
0
|
0
|
|
|
|
|
$datum->{len} = $attrs->{length} if $attrs->{length}; |
260
|
0
|
0
|
0
|
|
|
|
$datum->{subtyped} = 1 if $attrs->{subtyped} and $attrs->{subtyped} eq "yes"; |
261
|
|
|
|
|
|
|
|
262
|
0
|
|
|
|
|
|
my($subtag, $subval); |
263
|
|
|
|
|
|
|
|
264
|
0
|
|
|
|
|
|
while(@$value) { |
265
|
0
|
|
|
|
|
|
my($tlvtag, $tlvval) = splice(@$value, 0, 2); |
266
|
0
|
0
|
|
|
|
|
next if $tlvtag ne "tlv"; |
267
|
0
|
|
|
|
|
|
my $tlvattrs = shift @$tlvval; |
268
|
|
|
|
|
|
|
|
269
|
0
|
|
|
|
|
|
my $item = {}; |
270
|
0
|
|
|
|
|
|
$item->{type} = "data"; |
271
|
0
|
0
|
|
|
|
|
$item->{name} = $tlvattrs->{name} if $tlvattrs->{name}; |
272
|
0
|
|
|
|
|
|
$item->{num} = $tlvattrs->{type}; |
273
|
0
|
0
|
|
|
|
|
$item->{subtype} = $tlvattrs->{subtype} if $tlvattrs->{subtype}; |
274
|
0
|
0
|
|
|
|
|
$item->{count} = $tlvattrs->{count} if $tlvattrs->{count}; |
275
|
0
|
0
|
0
|
|
|
|
$item->{value} = "" if $tlvattrs->{default_generate} and $tlvattrs->{default_generate} ne "no"; |
276
|
0
|
|
|
|
|
|
$item->{items} = []; |
277
|
|
|
|
|
|
|
|
278
|
0
|
|
|
|
|
|
while(@$tlvval) { |
279
|
0
|
|
|
|
|
|
my($subtag, $subval) = splice(@$tlvval, 0, 2); |
280
|
0
|
0
|
|
|
|
|
next if $subtag eq "0"; |
281
|
0
|
|
|
|
|
|
my $tlvitem = _xmlnode_to_template($subtag, $subval); |
282
|
|
|
|
|
|
|
|
283
|
0
|
|
|
|
|
|
push @{$item->{items}}, $tlvitem; |
|
0
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
} |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
|
287
|
0
|
|
|
|
|
|
push @{$datum->{items}}, $item; |
|
0
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
} |
289
|
|
|
|
|
|
|
} |
290
|
|
|
|
|
|
|
|
291
|
0
|
|
|
|
|
|
return $datum; |
292
|
|
|
|
|
|
|
} |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
our(%PROTOCACHE); |
297
|
|
|
|
|
|
|
sub protoparse($$) { |
298
|
0
|
|
|
0
|
0
|
|
my ($oscar, $wanted) = @_; |
299
|
0
|
0
|
|
|
|
|
return $PROTOCACHE{$wanted}->set_oscar($oscar) if exists($PROTOCACHE{$wanted}); |
300
|
|
|
|
|
|
|
|
301
|
0
|
0
|
|
|
|
|
my $xml = $xmlmap{$wanted}->{xml} or croak "Couldn't find requested protocol element '$wanted'."; |
302
|
|
|
|
|
|
|
|
303
|
0
|
0
|
|
|
|
|
confess "No oscar!" unless $oscar; |
304
|
|
|
|
|
|
|
|
305
|
0
|
|
|
|
|
|
my $attrs = shift @$xml; |
306
|
|
|
|
|
|
|
|
307
|
0
|
|
|
|
|
|
my @template = (); |
308
|
|
|
|
|
|
|
|
309
|
0
|
|
|
|
|
|
while(@$xml) { |
310
|
0
|
|
|
|
|
|
my $tag = shift @$xml; |
311
|
0
|
|
|
|
|
|
my $value = shift @$xml; |
312
|
0
|
0
|
|
|
|
|
next if $tag eq "0"; |
313
|
0
|
|
|
|
|
|
push @template, _xmlnode_to_template($tag, $value); |
314
|
|
|
|
|
|
|
} |
315
|
|
|
|
|
|
|
|
316
|
0
|
0
|
|
|
|
|
return @template if $PROTOPARSE_DEBUG; |
317
|
0
|
|
|
|
|
|
my $obj = Net::OSCAR::XML::Template->new(\@template); |
318
|
0
|
|
|
|
|
|
$PROTOCACHE{$wanted} = $obj; |
319
|
0
|
|
|
|
|
|
return $obj->set_oscar($oscar); |
320
|
|
|
|
|
|
|
} |
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
# Map a "protobit" (XML ) to SNAC (family => foo, subtype => bar) |
325
|
|
|
|
|
|
|
sub protobit_to_snac($) { |
326
|
0
|
|
|
0
|
0
|
|
my $protobit = shift; |
327
|
0
|
0
|
|
|
|
|
confess "Unknown protobit $protobit" unless $xmlmap{$protobit}; |
328
|
|
|
|
|
|
|
|
329
|
0
|
|
|
|
|
|
my %ret = %{$xmlmap{$protobit}}; |
|
0
|
|
|
|
|
|
|
330
|
0
|
|
|
|
|
|
delete $ret{xml}; |
331
|
0
|
|
|
|
|
|
return %ret; |
332
|
|
|
|
|
|
|
} |
333
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
# Map a SNAC (family => foo, subtype => bar) to "protobit" (XML ) |
335
|
|
|
|
|
|
|
sub snac_to_protobit(%) { |
336
|
0
|
|
|
0
|
0
|
|
my(%snac) = @_; |
337
|
0
|
0
|
0
|
|
|
|
if($xml_revmap{$snac{family}} and $xml_revmap{$snac{family}}->{$snac{subtype}}) { |
|
|
0
|
0
|
|
|
|
|
338
|
0
|
|
|
|
|
|
return $xml_revmap{$snac{family}}->{$snac{subtype}}; |
339
|
|
|
|
|
|
|
} elsif($xml_revmap{'-1'} and $xml_revmap{'-1'}->{$snac{subtype}}) { |
340
|
0
|
|
|
|
|
|
return $xml_revmap{'-1'}->{$snac{subtype}}; |
341
|
|
|
|
|
|
|
} else { |
342
|
0
|
|
|
|
|
|
return undef; |
343
|
|
|
|
|
|
|
} |
344
|
|
|
|
|
|
|
} |
345
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
1; |