xmlcanonicalizer 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.document CHANGED
@@ -1,5 +1,5 @@
1
- README.rdoc
2
- lib/**/*.rb
3
- bin/*
4
- features/**/*.feature
5
- LICENSE
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/Gemfile ADDED
@@ -0,0 +1,13 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem "activesupport", ">= 2.3.5"
5
+
6
+ # Add dependencies to develop your gem here.
7
+ # Include everything needed to run rake, tests, features, etc.
8
+ group :development do
9
+ gem "shoulda", ">= 0"
10
+ gem "bundler", "~> 1.0.0"
11
+ gem "jeweler", "~> 1.6.4"
12
+ gem "rcov", ">= 0"
13
+ end
data/LICENSE CHANGED
@@ -1,20 +1,20 @@
1
- Copyright (c) 2009 Andrew Ferk
2
-
3
- Permission is hereby granted, free of charge, to any person obtaining
4
- a copy of this software and associated documentation files (the
5
- "Software"), to deal in the Software without restriction, including
6
- without limitation the rights to use, copy, modify, merge, publish,
7
- distribute, sublicense, and/or sell copies of the Software, and to
8
- permit persons to whom the Software is furnished to do so, subject to
9
- the following conditions:
10
-
11
- The above copyright notice and this permission notice shall be
12
- included in all copies or substantial portions of the Software.
13
-
14
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1
+ Copyright (c) 2009 Andrew Ferk
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc CHANGED
@@ -1,19 +1,19 @@
1
- = xmlcanonicalizer
2
-
3
- XML Canonicalizer for Ruby >= 1.92
4
-
5
- This is taken from XMLCanonicalizer/WSS4R and http://github.com/borisnadion/xml-canonicalizer
6
-
7
- == Note on Patches/Pull Requests
8
-
9
- * Fork the project.
10
- * Make your feature addition or bug fix.
11
- * Add tests for it. This is important so I don't break it in a
12
- future version unintentionally.
13
- * Commit, do not mess with rakefile, version, or history.
14
- (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
15
- * Send me a pull request. Bonus points for topic branches.
16
-
17
- == Copyright
18
-
19
- Copyright (c) 2010 Andrew Ferk. See LICENSE for details.
1
+ = xmlcanonicalizer
2
+
3
+ XML Canonicalizer for Ruby >= 1.9.2
4
+
5
+ This is taken from XMLCanonicalizer/WSS4R and http://github.com/borisnadion/xml-canonicalizer
6
+
7
+ == Note on Patches/Pull Requests
8
+
9
+ * Fork the project.
10
+ * Make your feature addition or bug fix.
11
+ * Add tests for it. This is important so I don't break it in a
12
+ future version unintentionally.
13
+ * Commit, do not mess with rakefile, version, or history.
14
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
15
+ * Send me a pull request. Bonus points for topic branches.
16
+
17
+ == Copyright
18
+
19
+ Copyright (c) 2010 Andrew Ferk. See LICENSE for details.
data/Rakefile CHANGED
@@ -1,53 +1,51 @@
1
- require 'rubygems'
2
- require 'rake'
3
-
4
- begin
5
- require 'jeweler'
6
- Jeweler::Tasks.new do |gem|
7
- gem.name = "xmlcanonicalizer"
8
- gem.summary = %Q{XML Canonicalizer for Ruby >= 1.92}
9
- gem.description = %Q{This is taken from XMLCanonicalizer/WSS4R and http://github.com/borisnadion/xml-canonicalizer}
10
- gem.email = "andrewferk@gmail.com"
11
- gem.homepage = "http://github.com/andrewferk/xmlcanonicalizer"
12
- gem.authors = ["Andrew Ferk"]
13
- gem.add_development_dependency "thoughtbot-shoulda", ">= 0"
14
- # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
15
- end
16
- Jeweler::GemcutterTasks.new
17
- rescue LoadError
18
- puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
19
- end
20
-
21
- require 'rake/testtask'
22
- Rake::TestTask.new(:test) do |test|
23
- test.libs << 'lib' << 'test'
24
- test.pattern = 'test/**/test_*.rb'
25
- test.verbose = true
26
- end
27
-
28
- begin
29
- require 'rcov/rcovtask'
30
- Rcov::RcovTask.new do |test|
31
- test.libs << 'test'
32
- test.pattern = 'test/**/test_*.rb'
33
- test.verbose = true
34
- end
35
- rescue LoadError
36
- task :rcov do
37
- abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
38
- end
39
- end
40
-
41
- task :test => :check_dependencies
42
-
43
- task :default => :test
44
-
45
- require 'rake/rdoctask'
46
- Rake::RDocTask.new do |rdoc|
47
- version = File.exist?('VERSION') ? File.read('VERSION') : ""
48
-
49
- rdoc.rdoc_dir = 'rdoc'
50
- rdoc.title = "xmlcanonicalizer #{version}"
51
- rdoc.rdoc_files.include('README*')
52
- rdoc.rdoc_files.include('lib/**/*.rb')
53
- end
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "xmlcanonicalizer"
8
+ gem.summary = %Q{XML Canonicalizer for Ruby >= 1.9.2}
9
+ gem.description = %Q{This is taken from XMLCanonicalizer/WSS4R and http://github.com/borisnadion/xml-canonicalizer}
10
+ gem.email = "andrewferk@gmail.com"
11
+ gem.homepage = "http://github.com/andrewferk/xmlcanonicalizer"
12
+ gem.authors = ["Andrew Ferk"]
13
+ gem.add_development_dependency "thoughtbot-shoulda", ">= 0"
14
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
15
+ end
16
+ Jeweler::GemcutterTasks.new
17
+ rescue LoadError
18
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
19
+ end
20
+
21
+ require 'rake/testtask'
22
+ Rake::TestTask.new(:test) do |test|
23
+ test.libs << 'lib' << 'test'
24
+ test.pattern = 'test/**/test_*.rb'
25
+ test.verbose = true
26
+ end
27
+
28
+ begin
29
+ require 'rcov/rcovtask'
30
+ Rcov::RcovTask.new do |test|
31
+ test.libs << 'test'
32
+ test.pattern = 'test/**/test_*.rb'
33
+ test.verbose = true
34
+ end
35
+ rescue LoadError
36
+ task :rcov do
37
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
38
+ end
39
+ end
40
+
41
+ task :default => :test
42
+
43
+ require 'rake/rdoctask'
44
+ Rake::RDocTask.new do |rdoc|
45
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
46
+
47
+ rdoc.rdoc_dir = 'rdoc'
48
+ rdoc.title = "xmlcanonicalizer #{version}"
49
+ rdoc.rdoc_files.include('README*')
50
+ rdoc.rdoc_files.include('lib/**/*.rb')
51
+ end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.0
1
+ 0.1.1
@@ -1,429 +1,426 @@
1
- #require "rexml/document"
2
- #require "base64"
3
- #require "log4r"
4
-
5
- #include REXML
6
- #include Log4r
7
-
8
- require "rexml/document"
9
- require "base64"
10
-
11
- module XML
12
- include REXML
13
-
14
- module Util
15
-
16
- class REXML::Instruction
17
- def write(writer, indent=-1, transitive=false, ie_hack=false)
18
- indent(writer, indent)
19
- writer << START.sub(/\\/u, '')
20
- writer << @target
21
- writer << ' '
22
- writer << @content if @content != nil
23
- writer << STOP.sub(/\\/u, '')
24
- end
25
- end
26
-
27
- class REXML::Attribute
28
- def <=>(a2)
29
- if (self === a2)
30
- return 0
31
- elsif (self == nil)
32
- return -1
33
- elsif (a2 == nil)
34
- return 1
35
- elsif (self.prefix() == a2.prefix())
36
- return self.name()<=>a2.name()
37
- end
38
- if (self.prefix() == nil)
39
- return -1
40
- elsif (a2.prefix() == nil)
41
- return 1
42
- end
43
- ret = self.namespace()<=>a2.namespace()
44
- if (ret == 0)
45
- ret = self.prefix()<=>a2.prefix()
46
- end
47
- return ret
48
- end
49
- end
50
-
51
- class REXML::Element
52
- def search_namespace(prefix)
53
- if (self.namespace(prefix) == nil)
54
- return (self.parent().search_namespace(prefix)) if (self.parent() != nil)
55
- else
56
- return self.namespace(prefix)
57
- end
58
- end
59
- def rendered=(rendered)
60
- @rendered = rendered
61
- end
62
- def rendered?()
63
- return @rendered
64
- end
65
- def node_namespaces()
66
- ns = Array.new()
67
- ns.push(self.prefix())
68
- self.attributes().each_attribute{|a|
69
- if (a.prefix() != nil)
70
- ns.push(a.prefix())
71
- end
72
- if (a.prefix() == "" && a.local_name() == "xmlns")
73
- ns.push("xmlns")
74
- end
75
- }
76
- ns
77
- end
78
- end
79
-
80
- class NamespaceNode
81
- attr_reader :prefix, :uri
82
- def initialize(prefix, uri)
83
- @prefix = prefix
84
- @uri = uri
85
- end
86
- end
87
-
88
- class XmlCanonicalizer
89
- attr_accessor :prefix_list, :logger
90
-
91
- BEFORE_DOC_ELEMENT = 0
92
- INSIDE_DOC_ELEMENT = 1
93
- AFTER_DOC_ELEMENT = 2
94
-
95
- NODE_TYPE_ATTRIBUTE = 3
96
- NODE_TYPE_WHITESPACE = 4
97
- NODE_TYPE_COMMENT = 5
98
- NODE_TYPE_PI = 6
99
- NODE_TYPE_TEXT = 7
100
-
101
-
102
- def initialize(with_comments, excl_c14n)
103
- @with_comments = with_comments
104
- @exclusive = excl_c14n
105
- @res = ""
106
- @state = BEFORE_DOC_ELEMENT
107
- @xnl = Array.new()
108
- @prevVisibleNamespacesStart = 0
109
- @prevVisibleNamespacesEnd = 0
110
- @visibleNamespaces = Array.new()
111
- @inclusive_namespaces = Array.new()
112
- @prefix_list = nil
113
- @rendered_prefixes = Array.new()
114
- end
115
-
116
- def add_inclusive_namespaces(prefix_list, element, visible_namespaces)
117
- namespaces = element.attributes()
118
- namespaces.each_attribute{|ns|
119
- if (ns.prefix=="xmlns")
120
- if (prefix_list.include?(ns.local_name()))
121
- visible_namespaces.push(NamespaceNode.new("xmlns:"+ns.local_name(), ns.value()))
122
- end
123
- end
124
- }
125
- parent = element.parent()
126
- add_inclusive_namespaces(prefix_list, parent, visible_namespaces) if (parent)
127
- visible_namespaces
128
- end
129
-
130
- def canonicalize(document)
131
- write_document_node(document)
132
- @res
133
- end
134
-
135
- def canonicalize_element(element, logging = true)
136
- @inclusive_namespaces = add_inclusive_namespaces(@prefix_list, element, @inclusive_namespaces) if (@prefix_list)
137
- @preserve_document = element.document()
138
- tmp_parent = element.parent()
139
- body_string = remove_whitespace(element.to_s().gsub("\n","").gsub("\t","").gsub("\r",""))
140
- document = Document.new(body_string)
141
- tmp_parent.delete_element(element)
142
- element = tmp_parent.add_element(document.root())
143
- @preserve_element = element
144
- document = Document.new(element.to_s())
145
- ns = element.namespace(element.prefix())
146
- document.root().add_namespace(element.prefix(), ns)
147
- write_document_node(document)
148
- @res
149
- end
150
-
151
- def write_document_node(document)
152
- @state = BEFORE_DOC_ELEMENT
153
- if (document.class().to_s() == "REXML::Element")
154
- write_node(document)
155
- else
156
- document.each_child{|child|
157
- write_node(child)
158
- }
159
- end
160
- @res
161
- end
162
-
163
- def write_node(node)
164
- visible = is_node_visible(node)
165
- if ((node.node_type() == :text) && white_text?(node.value()))
166
- res = node.value()
167
- res.gsub("\r\n","\n")
168
- #res = res.delete(" ").delete("\t")
169
- res.delete("\r")
170
- @res = @res + res
171
- #write_text_node(node,visible) if (@state == INSIDE_DOC_ELEMENT)
172
- return
173
- end
174
- if (node.node_type() == :text)
175
- write_text_node(node, visible)
176
- return
177
- end
178
- if (node.node_type() == :element)
179
- write_element_node(node, visible) if (!node.rendered?())
180
- node.rendered=(true)
181
- end
182
- if (node.node_type() == :processing_instruction)
183
- end
184
- if (node.node_type() == :comment)
185
- end
186
- end
187
-
188
- def write_element_node(node, visible)
189
- savedPrevVisibleNamespacesStart = @prevVisibleNamespacesStart
190
- savedPrevVisibleNamespacesEnd = @prevVisibleNamespacesEnd
191
- savedVisibleNamespacesSize = @visibleNamespaces.size()
192
- state = @state
193
- state = INSIDE_DOC_ELEMENT if (visible && state == BEFORE_DOC_ELEMENT)
194
- @res = @res + "<" + node.expanded_name() if (visible)
195
- write_namespace_axis(node, visible)
196
- write_attribute_axis(node)
197
- @res = @res + ">" if (visible)
198
- node.each_child{|child|
199
- write_node(child)
200
- }
201
- @res = @res + "</" +node.expanded_name() + ">" if (visible)
202
- @state = AFTER_DOC_ELEMENT if (visible && state == BEFORE_DOC_ELEMENT)
203
- @prevVisibleNamespacesStart = savedPrevVisibleNamespacesStart
204
- @prevVisibleNamespacesEnd = savedPrevVisibleNamespacesEnd
205
- @visibleNamespaces.slice!(savedVisibleNamespacesSize, @visibleNamespaces.size() - savedVisibleNamespacesSize) if (@visibleNamespaces.size() > savedVisibleNamespacesSize)
206
- end
207
-
208
- def write_namespace_axis(node, visible)
209
- doc = node.document()
210
- has_empty_namespace = false
211
- list = Array.new()
212
- cur = node
213
- #while ((cur != nil) && (cur != doc) && (cur.node_type() != :document))
214
- namespaces = cur.node_namespaces()
215
- namespaces.each{|prefix|
216
- next if ((prefix == "xmlns") && (node.namespace(prefix) == ""))
217
- namespace = cur.namespace(prefix)
218
- next if (is_namespace_node(namespace))
219
- next if (node.namespace(prefix) != cur.namespace(prefix))
220
- next if (prefix == "xml" && namespace == "http://www.w3.org/XML/1998/namespace")
221
- next if (!is_node_visible(cur))
222
- rendered = is_namespace_rendered(prefix, namespace)
223
- @visibleNamespaces.push(NamespaceNode.new("xmlns:"+prefix,namespace)) if (visible)
224
- if ((!rendered) && !list.include?(prefix))
225
- list.push(prefix)
226
- end
227
- has_empty_namespace = true if (prefix == nil)
228
- }
229
- if (visible && !has_empty_namespace && !is_namespace_rendered(nil, nil))
230
- @res = @res + ' xmlns=""'
231
- end
232
- #TODO: ns of inclusive_list
233
- #=begin
234
- if ((@prefix_list) && (node.to_s() == node.parent().to_s()))
235
- #list.push(node.prefix())
236
- @inclusive_namespaces.each{|ns|
237
- prefix = ns.prefix().split(":")[1]
238
- list.push(prefix) if (!list.include?(prefix) && (!node.attributes.prefixes.include?(prefix)))
239
- }
240
- @prefix_list = nil
241
- end
242
- #=end
243
- list.sort!()
244
- list.each{|prefix|
245
- next if (prefix == "")
246
- next if (@rendered_prefixes.include?(prefix))
247
- @rendered_prefixes.push(prefix)
248
- ns = node.namespace(prefix)
249
- ns = @preserve_element.namespace(prefix) if (ns == nil)
250
- @res = @res + normalize_string(" " + prefix + '="' + ns + '"', NODE_TYPE_TEXT) if (prefix == "xmlns")
251
- @res = @res + normalize_string(" xmlns:" + prefix + '="' + ns + '"', NODE_TYPE_TEXT) if (prefix != nil && prefix != "xmlns")
252
- }
253
- if (visible)
254
- @prevVisibleNamespacesStart = @prevVisibleNamespacesEnd
255
- @prevVisibleNamespacesEnd = @visibleNamespaces.size()
256
- end
257
- end
258
-
259
- def write_attribute_axis(node)
260
- list = Array.new()
261
- node.attributes.keys.sort.each{|key|
262
- attr = node.attributes.get_attribute(key)
263
- list.push(attr) if (!is_namespace_node(attr.value()) && !is_namespace_decl(attr))
264
- }
265
- if (!@exclusive && node.parent() != nil && node.parent().parent() != nil)
266
- cur = node.parent()
267
- while (cur != nil)
268
- #next if (cur.attributes() == nil)
269
- cur.each_attribute{|attribute|
270
- next if (attribute.prefix() != "xml")
271
- next if (attribute.prefix().index("xmlns") == 0)
272
- next if (node.namespace(attribute.prefix()) == attribute.value())
273
- found = true
274
- list.each{|n|
275
- if (n.prefix() == "xml" && n.value() == attritbute.value())
276
- found = true
277
- break
278
- end
279
- }
280
- next if (found)
281
- list.push(attribute)
282
- }
283
- end
284
- end
285
- list.each{|attribute|
286
- if (attribute != nil)
287
- if (attribute.name() != "xmlns")
288
- @res = @res + " " + normalize_string(attribute.to_string(), NODE_TYPE_ATTRIBUTE).gsub("'",'"')
289
- end
290
- # else
291
- # @res = @res + " " + normalize_string(attribute.name()+'="'+attribute.to_s()+'"', NODE_TYPE_ATTRIBUTE).gsub("'",'"')
292
- #end
293
- end
294
- }
295
- end
296
-
297
- def is_namespace_node(namespace_uri)
298
- return (namespace_uri == "http://www.w3.org/2000/xmlns/")
299
- end
300
-
301
- def is_namespace_rendered(prefix, uri)
302
- is_empty_ns = prefix == nil && uri == nil
303
- if (is_empty_ns)
304
- start = 0
305
- else
306
- start = @prevVisibleNamespacesStart
307
- end
308
- @visibleNamespaces.each{|ns|
309
- if (ns.prefix() == "xmlns:"+prefix.to_s() && ns.uri() == uri)
310
- return true
311
- end
312
- }
313
- return is_empty_ns
314
- #(@visibleNamespaces.size()-1).downto(start) {|i|
315
- # ns = @visibleNamespaces[i]
316
- # return true if (ns.prefix() == "xmlns:"+prefix.to_s() && ns.uri() == uri)
317
- # #p = ns.prefix() if (ns.prefix().index("xmlns") == 0)
318
- # #return ns.uri() == uri if (p == prefix)
319
- #}
320
- #return is_empty_ns
321
- end
322
-
323
- def is_node_visible(node)
324
- return true if (@xnl.size() == 0)
325
- @xnl.each{|element|
326
- return true if (element == node)
327
- }
328
- return false
329
- end
330
-
331
- def normalize_string(input, type)
332
- sb = ""
333
- return input
334
- end
335
- #input.each_byte{|b|
336
- # if (b ==60 && (type == NODE_TYPE_ATTRIBUTE || is_text_node(type)))
337
- # sb = sb + "&lt;"
338
- # elsif (b == 62 && is_text_node(type))
339
- # sb = sb + "&gt;"
340
- # elsif (b == 38 && (is_text_node(type) || is_text_node(type))) #Ampersand
341
- # sb = sb + "&amp;"
342
- # elsif (b == 34 && is_text_node(type)) #Quote
343
- # sb = sb + "&quot;"
344
- # elsif (b == 9 && is_text_node(type)) #Tabulator
345
- # sb = sb + "&#x9;"
346
- # elsif (b == 11 && is_text_node(type)) #CR
347
- # sb = sb + "&#xA;"
348
- # elsif (b == 13 && (type == NODE_TYPE_ATTRIBUTE || (is_text_node(type) && type != NODE_TYPE_WHITESPACE) || type == NODE_TYPE_COMMENT || type == NODE_TYPE_PI))
349
- # sb = sb + "&#xD;"
350
- # elsif (b == 13)
351
- # next
352
- # else
353
- # sb = sb.concat(b)
354
- # end
355
- #}
356
- #sb
357
- #end
358
-
359
- def write_text_node(node, visible)
360
- if (visible)
361
- @res = @res + normalize_string(node.value(), node.node_type())
362
- end
363
- end
364
-
365
- def white_text?(text)
366
- return true if ((text.strip() == "") || (text.strip() == nil))
367
- return false
368
- end
369
-
370
- def is_namespace_decl(attribute)
371
- #return true if (attribute.name() == "xmlns")
372
- return true if (attribute.prefix().index("xmlns") == 0)
373
- return false
374
- end
375
-
376
- def is_text_node(type)
377
- return true if (type == NODE_TYPE_TEXT || type == NODE_TYPE_CDATA || type == NODE_TYPE_WHITESPACE)
378
- return false
379
- end
380
-
381
- def remove_whitespace(string)
382
- new_string = ""
383
- in_white = false
384
- string.each_byte{|b|
385
- #if (in_white && b == 32)
386
- #else
387
- if !(in_white && b == 32)
388
- new_string = new_string + b.chr()
389
- end
390
- if (b == 62) #>
391
- in_white = true
392
- end
393
- if (b == 60) #<
394
- in_white = false
395
- end
396
- }
397
- new_string
398
- end
399
- end
400
- end #Util
401
- end #XML
402
-
403
-
404
- if __FILE__ == $0
405
- document = Document.new(File.new(ARGV[0]))
406
- body = nil
407
- c = WSS4R::Security::Util::XmlCanonicalizer.new(false, true)
408
-
409
- if (ARGV.size() == 3)
410
- body = ARGV[2]
411
- if (body == "true")
412
- element = XPath.match(document, "/soap:Envelope/soap:Body")[0]
413
- element = XPath.first(document, "/soap:Envelope/soap:Header/wsse:Security/Signature/SignedInfo")
414
- result = c.canonicalize_element(element)
415
- puts("-----")
416
- puts(result)
417
- puts("-----")
418
- puts(result.size())
419
- puts("-----")
420
- puts(CryptHash.new().digest_b64(result))
421
- end
422
- else
423
- result = c.canonicalize(document)
424
- end
425
-
426
- file = File.new(ARGV[1], "wb")
427
- file.write(result)
428
- file.close()
429
- end
1
+ #require "rexml/document"
2
+ #require "base64"
3
+ #require "log4r"
4
+
5
+ #include REXML
6
+ #include Log4r
7
+
8
+ require "rexml/document"
9
+ require "base64"
10
+
11
+ module XML
12
+ include REXML
13
+
14
+ module Util
15
+
16
+ class REXML::Instruction
17
+ def write(writer, indent=-1, transitive=false, ie_hack=false)
18
+ indent(writer, indent)
19
+ writer << START.sub(/\\/u, '')
20
+ writer << @target
21
+ writer << ' '
22
+ writer << @content if @content != nil
23
+ writer << STOP.sub(/\\/u, '')
24
+ end
25
+ end
26
+
27
+ class REXML::Attribute
28
+ def <=>(a2)
29
+ if (self === a2)
30
+ return 0
31
+ elsif (self == nil)
32
+ return -1
33
+ elsif (a2 == nil)
34
+ return 1
35
+ elsif (self.prefix() == a2.prefix())
36
+ return self.name()<=>a2.name()
37
+ end
38
+ if (self.prefix() == nil)
39
+ return -1
40
+ elsif (a2.prefix() == nil)
41
+ return 1
42
+ end
43
+ ret = self.namespace()<=>a2.namespace()
44
+ if (ret == 0)
45
+ ret = self.prefix()<=>a2.prefix()
46
+ end
47
+ return ret
48
+ end
49
+ end
50
+
51
+ class REXML::Element
52
+ def search_namespace(prefix)
53
+ if (self.namespace(prefix) == nil)
54
+ return (self.parent().search_namespace(prefix)) if (self.parent() != nil)
55
+ else
56
+ return self.namespace(prefix)
57
+ end
58
+ end
59
+ def rendered=(rendered)
60
+ @rendered = rendered
61
+ end
62
+ def rendered?()
63
+ return @rendered
64
+ end
65
+ def node_namespaces()
66
+ ns = Array.new()
67
+ ns.push(self.prefix())
68
+ self.attributes().each_attribute{|a|
69
+ if (a.prefix() != nil)
70
+ ns.push(a.prefix())
71
+ end
72
+ if (a.prefix() == "" && a.local_name() == "xmlns")
73
+ ns.push("xmlns")
74
+ end
75
+ }
76
+ ns
77
+ end
78
+ end
79
+
80
+ class NamespaceNode
81
+ attr_reader :prefix, :uri
82
+ def initialize(prefix, uri)
83
+ @prefix = prefix
84
+ @uri = uri
85
+ end
86
+ end
87
+
88
+ class XmlCanonicalizer
89
+ attr_accessor :prefix_list, :logger
90
+
91
+ BEFORE_DOC_ELEMENT = 0
92
+ INSIDE_DOC_ELEMENT = 1
93
+ AFTER_DOC_ELEMENT = 2
94
+
95
+ NODE_TYPE_ATTRIBUTE = 3
96
+ NODE_TYPE_WHITESPACE = 4
97
+ NODE_TYPE_COMMENT = 5
98
+ NODE_TYPE_PI = 6
99
+ NODE_TYPE_TEXT = 7
100
+
101
+
102
+ def initialize(with_comments, excl_c14n)
103
+ @with_comments = with_comments
104
+ @exclusive = excl_c14n
105
+ @res = ""
106
+ @state = BEFORE_DOC_ELEMENT
107
+ @xnl = Array.new()
108
+ @prevVisibleNamespacesStart = 0
109
+ @prevVisibleNamespacesEnd = 0
110
+ @visibleNamespaces = Array.new()
111
+ @inclusive_namespaces = Array.new()
112
+ @prefix_list = nil
113
+ end
114
+
115
+ def add_inclusive_namespaces(prefix_list, element, visible_namespaces)
116
+ namespaces = element.attributes()
117
+ namespaces.each_attribute{|ns|
118
+ if (ns.prefix=="xmlns")
119
+ if (prefix_list.include?(ns.local_name()))
120
+ visible_namespaces.push(NamespaceNode.new("xmlns:"+ns.local_name(), ns.value()))
121
+ end
122
+ end
123
+ }
124
+ parent = element.parent()
125
+ add_inclusive_namespaces(prefix_list, parent, visible_namespaces) if (parent)
126
+ visible_namespaces
127
+ end
128
+
129
+ def canonicalize(document)
130
+ write_document_node(document)
131
+ @res
132
+ end
133
+
134
+ def canonicalize_element(element, logging = true)
135
+ @inclusive_namespaces = add_inclusive_namespaces(@prefix_list, element, @inclusive_namespaces) if (@prefix_list)
136
+ @preserve_document = element.document()
137
+ tmp_parent = element.parent()
138
+ body_string = remove_whitespace(element.to_s().gsub("\n","").gsub("\t","").gsub("\r",""))
139
+ document = Document.new(body_string)
140
+ tmp_parent.delete_element(element)
141
+ element = tmp_parent.add_element(document.root())
142
+ @preserve_element = element
143
+ document = Document.new(element.to_s())
144
+ ns = element.namespace(element.prefix())
145
+ document.root().add_namespace(element.prefix(), ns)
146
+ write_document_node(document)
147
+ @res
148
+ end
149
+
150
+ def write_document_node(document)
151
+ @state = BEFORE_DOC_ELEMENT
152
+ if (document.class().to_s() == "REXML::Element")
153
+ write_node(document)
154
+ else
155
+ document.each_child{|child|
156
+ write_node(child)
157
+ }
158
+ end
159
+ @res
160
+ end
161
+
162
+ def write_node(node)
163
+ visible = is_node_visible(node)
164
+ if ((node.node_type() == :text) && white_text?(node.value()))
165
+ res = node.value()
166
+ res.gsub("\r\n","\n")
167
+ #res = res.delete(" ").delete("\t")
168
+ res.delete("\r")
169
+ @res = @res + res
170
+ #write_text_node(node,visible) if (@state == INSIDE_DOC_ELEMENT)
171
+ return
172
+ end
173
+ if (node.node_type() == :text)
174
+ write_text_node(node, visible)
175
+ return
176
+ end
177
+ if (node.node_type() == :element)
178
+ write_element_node(node, visible) if (!node.rendered?())
179
+ node.rendered=(true)
180
+ end
181
+ if (node.node_type() == :processing_instruction)
182
+ end
183
+ if (node.node_type() == :comment)
184
+ end
185
+ end
186
+
187
+ def write_element_node(node, visible)
188
+ savedPrevVisibleNamespacesStart = @prevVisibleNamespacesStart
189
+ savedPrevVisibleNamespacesEnd = @prevVisibleNamespacesEnd
190
+ savedVisibleNamespacesSize = @visibleNamespaces.size()
191
+ state = @state
192
+ state = INSIDE_DOC_ELEMENT if (visible && state == BEFORE_DOC_ELEMENT)
193
+ @res = @res + "<" + node.expanded_name() if (visible)
194
+ write_namespace_axis(node, visible)
195
+ write_attribute_axis(node)
196
+ @res = @res + ">" if (visible)
197
+ node.each_child{|child|
198
+ write_node(child)
199
+ }
200
+ @res = @res + "</" +node.expanded_name() + ">" if (visible)
201
+ @state = AFTER_DOC_ELEMENT if (visible && state == BEFORE_DOC_ELEMENT)
202
+ @prevVisibleNamespacesStart = savedPrevVisibleNamespacesStart
203
+ @prevVisibleNamespacesEnd = savedPrevVisibleNamespacesEnd
204
+ @visibleNamespaces.slice!(savedVisibleNamespacesSize, @visibleNamespaces.size() - savedVisibleNamespacesSize) if (@visibleNamespaces.size() > savedVisibleNamespacesSize)
205
+ end
206
+
207
+ def write_namespace_axis(node, visible)
208
+ doc = node.document()
209
+ has_empty_namespace = false
210
+ list = Array.new()
211
+ cur = node
212
+ #while ((cur != nil) && (cur != doc) && (cur.node_type() != :document))
213
+ namespaces = cur.node_namespaces()
214
+ namespaces.each{|prefix|
215
+ next if ((prefix == "xmlns") && (node.namespace(prefix) == ""))
216
+ namespace = cur.namespace(prefix)
217
+ next if (is_namespace_node(namespace))
218
+ next if (node.namespace(prefix) != cur.namespace(prefix))
219
+ next if (prefix == "xml" && namespace == "http://www.w3.org/XML/1998/namespace")
220
+ next if (!is_node_visible(cur))
221
+ rendered = is_namespace_rendered(prefix, namespace)
222
+ @visibleNamespaces.push(NamespaceNode.new("xmlns:"+prefix,namespace)) if (visible)
223
+ if ((!rendered) && !list.include?(prefix))
224
+ list.push(prefix)
225
+ end
226
+ has_empty_namespace = true if (prefix == nil)
227
+ }
228
+ if (visible && !has_empty_namespace && !is_namespace_rendered(nil, nil))
229
+ @res = @res + ' xmlns=""'
230
+ end
231
+ #TODO: ns of inclusive_list
232
+ #=begin
233
+ if ((@prefix_list) && (node.to_s() == node.parent().to_s()))
234
+ #list.push(node.prefix())
235
+ @inclusive_namespaces.each{|ns|
236
+ prefix = ns.prefix().split(":")[1]
237
+ list.push(prefix) if (!list.include?(prefix) && (!node.attributes.prefixes.include?(prefix)))
238
+ }
239
+ @prefix_list = nil
240
+ end
241
+ #=end
242
+ list.sort!()
243
+ list.each{|prefix|
244
+ next if (prefix == "")
245
+ ns = node.namespace(prefix)
246
+ ns = @preserve_element.namespace(prefix) if (ns == nil)
247
+ @res = @res + normalize_string(" " + prefix + '="' + ns + '"', NODE_TYPE_TEXT) if (prefix == "xmlns")
248
+ @res = @res + normalize_string(" xmlns:" + prefix + '="' + ns + '"', NODE_TYPE_TEXT) if (prefix != nil && prefix != "xmlns")
249
+ }
250
+ if (visible)
251
+ @prevVisibleNamespacesStart = @prevVisibleNamespacesEnd
252
+ @prevVisibleNamespacesEnd = @visibleNamespaces.size()
253
+ end
254
+ end
255
+
256
+ def write_attribute_axis(node)
257
+ list = Array.new()
258
+ node.attributes.keys.sort.each{|key|
259
+ attr = node.attributes.get_attribute(key)
260
+ list.push(attr) if (!is_namespace_node(attr.value()) && !is_namespace_decl(attr))
261
+ }
262
+ if (!@exclusive && node.parent() != nil && node.parent().parent() != nil)
263
+ cur = node.parent()
264
+ while (cur != nil)
265
+ #next if (cur.attributes() == nil)
266
+ cur.each_attribute{|attribute|
267
+ next if (attribute.prefix() != "xml")
268
+ next if (attribute.prefix().index("xmlns") == 0)
269
+ next if (node.namespace(attribute.prefix()) == attribute.value())
270
+ found = true
271
+ list.each{|n|
272
+ if (n.prefix() == "xml" && n.value() == attritbute.value())
273
+ found = true
274
+ break
275
+ end
276
+ }
277
+ next if (found)
278
+ list.push(attribute)
279
+ }
280
+ end
281
+ end
282
+ list.each{|attribute|
283
+ if (attribute != nil)
284
+ if (attribute.name() != "xmlns")
285
+ @res = @res + " " + normalize_string(attribute.to_string(), NODE_TYPE_ATTRIBUTE).gsub("'",'"')
286
+ end
287
+ # else
288
+ # @res = @res + " " + normalize_string(attribute.name()+'="'+attribute.to_s()+'"', NODE_TYPE_ATTRIBUTE).gsub("'",'"')
289
+ #end
290
+ end
291
+ }
292
+ end
293
+
294
+ def is_namespace_node(namespace_uri)
295
+ return (namespace_uri == "http://www.w3.org/2000/xmlns/")
296
+ end
297
+
298
+ def is_namespace_rendered(prefix, uri)
299
+ is_empty_ns = prefix == nil && uri == nil
300
+ if (is_empty_ns)
301
+ start = 0
302
+ else
303
+ start = @prevVisibleNamespacesStart
304
+ end
305
+ @visibleNamespaces.each{|ns|
306
+ if (ns.prefix() == "xmlns:"+prefix.to_s() && ns.uri() == uri)
307
+ return true
308
+ end
309
+ }
310
+ return is_empty_ns
311
+ #(@visibleNamespaces.size()-1).downto(start) {|i|
312
+ # ns = @visibleNamespaces[i]
313
+ # return true if (ns.prefix() == "xmlns:"+prefix.to_s() && ns.uri() == uri)
314
+ # #p = ns.prefix() if (ns.prefix().index("xmlns") == 0)
315
+ # #return ns.uri() == uri if (p == prefix)
316
+ #}
317
+ #return is_empty_ns
318
+ end
319
+
320
+ def is_node_visible(node)
321
+ return true if (@xnl.size() == 0)
322
+ @xnl.each{|element|
323
+ return true if (element == node)
324
+ }
325
+ return false
326
+ end
327
+
328
+ def normalize_string(input, type)
329
+ sb = ""
330
+ return input
331
+ end
332
+ #input.each_byte{|b|
333
+ # if (b ==60 && (type == NODE_TYPE_ATTRIBUTE || is_text_node(type)))
334
+ # sb = sb + "&lt;"
335
+ # elsif (b == 62 && is_text_node(type))
336
+ # sb = sb + "&gt;"
337
+ # elsif (b == 38 && (is_text_node(type) || is_text_node(type))) #Ampersand
338
+ # sb = sb + "&amp;"
339
+ # elsif (b == 34 && is_text_node(type)) #Quote
340
+ # sb = sb + "&quot;"
341
+ # elsif (b == 9 && is_text_node(type)) #Tabulator
342
+ # sb = sb + "&#x9;"
343
+ # elsif (b == 11 && is_text_node(type)) #CR
344
+ # sb = sb + "&#xA;"
345
+ # elsif (b == 13 && (type == NODE_TYPE_ATTRIBUTE || (is_text_node(type) && type != NODE_TYPE_WHITESPACE) || type == NODE_TYPE_COMMENT || type == NODE_TYPE_PI))
346
+ # sb = sb + "&#xD;"
347
+ # elsif (b == 13)
348
+ # next
349
+ # else
350
+ # sb = sb.concat(b)
351
+ # end
352
+ #}
353
+ #sb
354
+ #end
355
+
356
+ def write_text_node(node, visible)
357
+ if (visible)
358
+ @res = @res + normalize_string(node.value(), node.node_type())
359
+ end
360
+ end
361
+
362
+ def white_text?(text)
363
+ return true if ((text.strip() == "") || (text.strip() == nil))
364
+ return false
365
+ end
366
+
367
+ def is_namespace_decl(attribute)
368
+ #return true if (attribute.name() == "xmlns")
369
+ return true if (attribute.prefix().index("xmlns") == 0)
370
+ return false
371
+ end
372
+
373
+ def is_text_node(type)
374
+ return true if (type == NODE_TYPE_TEXT || type == NODE_TYPE_CDATA || type == NODE_TYPE_WHITESPACE)
375
+ return false
376
+ end
377
+
378
+ def remove_whitespace(string)
379
+ new_string = ""
380
+ in_white = false
381
+ string.each_byte{|b|
382
+ #if (in_white && b == 32)
383
+ #else
384
+ if !(in_white && b == 32)
385
+ new_string = new_string + b.chr()
386
+ end
387
+ if (b == 62) #>
388
+ in_white = true
389
+ end
390
+ if (b == 60) #<
391
+ in_white = false
392
+ end
393
+ }
394
+ new_string
395
+ end
396
+ end
397
+ end #Util
398
+ end #XML
399
+
400
+
401
+ if __FILE__ == $0
402
+ document = Document.new(File.new(ARGV[0]))
403
+ body = nil
404
+ c = WSS4R::Security::Util::XmlCanonicalizer.new(false, true)
405
+
406
+ if (ARGV.size() == 3)
407
+ body = ARGV[2]
408
+ if (body == "true")
409
+ element = XPath.match(document, "/soap:Envelope/soap:Body")[0]
410
+ element = XPath.first(document, "/soap:Envelope/soap:Header/wsse:Security/Signature/SignedInfo")
411
+ result = c.canonicalize_element(element)
412
+ puts("-----")
413
+ puts(result)
414
+ puts("-----")
415
+ puts(result.size())
416
+ puts("-----")
417
+ puts(CryptHash.new().digest_b64(result))
418
+ end
419
+ else
420
+ result = c.canonicalize(document)
421
+ end
422
+
423
+ file = File.new(ARGV[1], "wb")
424
+ file.write(result)
425
+ file.close()
426
+ end