rexml 3.4.1 → 3.4.2
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.
- checksums.yaml +4 -4
- data/NEWS.md +103 -1
- data/lib/rexml/attribute.rb +7 -8
- data/lib/rexml/cdata.rb +1 -1
- data/lib/rexml/child.rb +2 -3
- data/lib/rexml/comment.rb +1 -1
- data/lib/rexml/doctype.rb +3 -8
- data/lib/rexml/document.rb +18 -4
- data/lib/rexml/element.rb +53 -59
- data/lib/rexml/encoding.rb +3 -6
- data/lib/rexml/functions.rb +3 -3
- data/lib/rexml/instruction.rb +1 -1
- data/lib/rexml/namespace.rb +4 -4
- data/lib/rexml/node.rb +2 -2
- data/lib/rexml/parsers/baseparser.rb +138 -81
- data/lib/rexml/parsers/xpathparser.rb +4 -4
- data/lib/rexml/quickpath.rb +19 -18
- data/lib/rexml/rexml.rb +1 -1
- data/lib/rexml/security.rb +2 -2
- data/lib/rexml/source.rb +6 -1
- data/lib/rexml/text.rb +14 -17
- data/lib/rexml/validation/relaxng.rb +27 -26
- data/lib/rexml/validation/validation.rb +8 -8
- data/lib/rexml/xpath.rb +2 -13
- data/lib/rexml/xpath_parser.rb +44 -42
- metadata +4 -4
@@ -144,6 +144,7 @@ module REXML
|
|
144
144
|
PEREFERENCE_PATTERN = /#{PEREFERENCE}/um
|
145
145
|
TAG_PATTERN = /((?>#{QNAME_STR}))\s*/um
|
146
146
|
CLOSE_PATTERN = /(#{QNAME_STR})\s*>/um
|
147
|
+
EQUAL_PATTERN = /\s*=\s*/um
|
147
148
|
ATTLISTDECL_END = /\s+#{NAME}(?:#{ATTDEF})*\s*>/um
|
148
149
|
NAME_PATTERN = /#{NAME}/um
|
149
150
|
GEDECL_PATTERN = "\\s+#{NAME}\\s+#{ENTITYDEF}\\s*>"
|
@@ -168,6 +169,7 @@ module REXML
|
|
168
169
|
@entity_expansion_limit = Security.entity_expansion_limit
|
169
170
|
@entity_expansion_text_limit = Security.entity_expansion_text_limit
|
170
171
|
@source.ensure_buffer
|
172
|
+
@version = nil
|
171
173
|
end
|
172
174
|
|
173
175
|
def add_listener( listener )
|
@@ -206,12 +208,12 @@ module REXML
|
|
206
208
|
|
207
209
|
# Returns true if there are no more events
|
208
210
|
def empty?
|
209
|
-
|
211
|
+
(@source.empty? and @stack.empty?)
|
210
212
|
end
|
211
213
|
|
212
214
|
# Returns true if there are more events. Synonymous with !empty?
|
213
215
|
def has_next?
|
214
|
-
|
216
|
+
!(@source.empty? and @stack.empty?)
|
215
217
|
end
|
216
218
|
|
217
219
|
# Push an event back on the head of the stream. This method
|
@@ -277,17 +279,10 @@ module REXML
|
|
277
279
|
return process_instruction
|
278
280
|
elsif @source.match?("<!", true)
|
279
281
|
if @source.match?("--", true)
|
280
|
-
|
281
|
-
if md.nil?
|
282
|
-
raise REXML::ParseException.new("Unclosed comment", @source)
|
283
|
-
end
|
284
|
-
if /--|-\z/.match?(md[1])
|
285
|
-
raise REXML::ParseException.new("Malformed comment", @source)
|
286
|
-
end
|
287
|
-
return [ :comment, md[1] ]
|
282
|
+
return [ :comment, process_comment ]
|
288
283
|
elsif @source.match?("DOCTYPE", true)
|
289
284
|
base_error_message = "Malformed DOCTYPE"
|
290
|
-
unless @source.
|
285
|
+
unless @source.skip_spaces
|
291
286
|
if @source.match?(">")
|
292
287
|
message = "#{base_error_message}: name is missing"
|
293
288
|
else
|
@@ -297,7 +292,7 @@ module REXML
|
|
297
292
|
raise REXML::ParseException.new(message, @source)
|
298
293
|
end
|
299
294
|
name = parse_name(base_error_message)
|
300
|
-
@source.
|
295
|
+
@source.skip_spaces
|
301
296
|
if @source.match?("[", true)
|
302
297
|
id = [nil, nil, nil]
|
303
298
|
@document_status = :in_doctype
|
@@ -313,7 +308,7 @@ module REXML
|
|
313
308
|
# For backward compatibility
|
314
309
|
id[1], id[2] = id[2], nil
|
315
310
|
end
|
316
|
-
@source.
|
311
|
+
@source.skip_spaces
|
317
312
|
if @source.match?("[", true)
|
318
313
|
@document_status = :in_doctype
|
319
314
|
elsif @source.match?(">", true)
|
@@ -326,7 +321,7 @@ module REXML
|
|
326
321
|
end
|
327
322
|
args = [:start_doctype, name, *id]
|
328
323
|
if @document_status == :after_doctype
|
329
|
-
@source.
|
324
|
+
@source.skip_spaces
|
330
325
|
@stack << [ :end_doctype ]
|
331
326
|
end
|
332
327
|
return args
|
@@ -337,7 +332,7 @@ module REXML
|
|
337
332
|
end
|
338
333
|
end
|
339
334
|
if @document_status == :in_doctype
|
340
|
-
@source.
|
335
|
+
@source.skip_spaces
|
341
336
|
start_position = @source.position
|
342
337
|
if @source.match?("<!", true)
|
343
338
|
if @source.match?("ELEMENT", true)
|
@@ -398,7 +393,7 @@ module REXML
|
|
398
393
|
return [ :attlistdecl, element, pairs, contents ]
|
399
394
|
elsif @source.match?("NOTATION", true)
|
400
395
|
base_error_message = "Malformed notation declaration"
|
401
|
-
unless @source.
|
396
|
+
unless @source.skip_spaces
|
402
397
|
if @source.match?(">")
|
403
398
|
message = "#{base_error_message}: name is missing"
|
404
399
|
else
|
@@ -411,31 +406,28 @@ module REXML
|
|
411
406
|
id = parse_id(base_error_message,
|
412
407
|
accept_external_id: true,
|
413
408
|
accept_public_id: true)
|
414
|
-
@source.
|
409
|
+
@source.skip_spaces
|
415
410
|
unless @source.match?(">", true)
|
416
411
|
message = "#{base_error_message}: garbage before end >"
|
417
412
|
raise REXML::ParseException.new(message, @source)
|
418
413
|
end
|
419
414
|
return [:notationdecl, name, *id]
|
420
|
-
elsif
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
end
|
425
|
-
return [ :comment, md[1] ] if md
|
415
|
+
elsif @source.match?("--", true)
|
416
|
+
return [ :comment, process_comment ]
|
417
|
+
else
|
418
|
+
raise REXML::ParseException.new("Malformed node: Started with '<!' but not a comment nor ELEMENT,ENTITY,ATTLIST,NOTATION", @source)
|
426
419
|
end
|
427
420
|
elsif match = @source.match(/(%.*?;)\s*/um, true)
|
428
421
|
return [ :externalentity, match[1] ]
|
429
422
|
elsif @source.match?(/\]\s*>/um, true)
|
430
423
|
@document_status = :after_doctype
|
431
424
|
return [ :end_doctype ]
|
432
|
-
|
433
|
-
if @document_status == :in_doctype
|
425
|
+
else
|
434
426
|
raise ParseException.new("Malformed DOCTYPE: invalid declaration", @source)
|
435
427
|
end
|
436
428
|
end
|
437
429
|
if @document_status == :after_doctype
|
438
|
-
@source.
|
430
|
+
@source.skip_spaces
|
439
431
|
end
|
440
432
|
begin
|
441
433
|
start_position = @source.position
|
@@ -460,23 +452,19 @@ module REXML
|
|
460
452
|
end
|
461
453
|
return [ :end_element, last_tag ]
|
462
454
|
elsif @source.match?("!", true)
|
463
|
-
md = @source.match(/([^>]*>)/um)
|
464
455
|
#STDERR.puts "SOURCE BUFFER = #{source.buffer}, #{source.buffer.size}"
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
if
|
470
|
-
|
456
|
+
if @source.match?("--", true)
|
457
|
+
return [ :comment, process_comment ]
|
458
|
+
elsif @source.match?("[CDATA[", true)
|
459
|
+
text = @source.read_until("]]>")
|
460
|
+
if text.chomp!("]]>")
|
461
|
+
return [ :cdata, text ]
|
462
|
+
else
|
463
|
+
raise REXML::ParseException.new("Malformed CDATA: Missing end ']]>'", @source)
|
471
464
|
end
|
472
|
-
|
473
|
-
return [ :comment, md[1] ]
|
474
465
|
else
|
475
|
-
|
476
|
-
return [ :cdata, md[1] ] if md
|
466
|
+
raise REXML::ParseException.new("Malformed node: Started with '<!' but not a comment nor CDATA", @source)
|
477
467
|
end
|
478
|
-
raise REXML::ParseException.new( "Declarations can only occur "+
|
479
|
-
"in the doctype declaration.", @source)
|
480
468
|
elsif @source.match?("?", true)
|
481
469
|
return process_instruction
|
482
470
|
else
|
@@ -536,7 +524,8 @@ module REXML
|
|
536
524
|
raise REXML::ParseException.new( "Exception parsing",
|
537
525
|
@source, self, (error ? error : $!) )
|
538
526
|
end
|
539
|
-
|
527
|
+
# NOTE: The end of the method never runs, because it is unreachable.
|
528
|
+
# All branches of code above have explicit unconditional return or raise statements.
|
540
529
|
end
|
541
530
|
private :pull_event
|
542
531
|
|
@@ -655,6 +644,10 @@ module REXML
|
|
655
644
|
true
|
656
645
|
end
|
657
646
|
|
647
|
+
def normalize_xml_declaration_encoding(xml_declaration_encoding)
|
648
|
+
/\AUTF-16(?:BE|LE)\z/i.match?(xml_declaration_encoding) ? "UTF-16" : nil
|
649
|
+
end
|
650
|
+
|
658
651
|
def parse_name(base_error_message)
|
659
652
|
md = @source.match(Private::NAME_PATTERN, true)
|
660
653
|
unless md
|
@@ -734,39 +727,99 @@ module REXML
|
|
734
727
|
end
|
735
728
|
end
|
736
729
|
|
730
|
+
def process_comment
|
731
|
+
text = @source.read_until("-->")
|
732
|
+
unless text.chomp!("-->")
|
733
|
+
raise REXML::ParseException.new("Unclosed comment: Missing end '-->'", @source)
|
734
|
+
end
|
735
|
+
|
736
|
+
if text.include? "--" or text.end_with?("-")
|
737
|
+
raise REXML::ParseException.new("Malformed comment", @source)
|
738
|
+
end
|
739
|
+
text
|
740
|
+
end
|
741
|
+
|
737
742
|
def process_instruction
|
738
743
|
name = parse_name("Malformed XML: Invalid processing instruction node")
|
739
|
-
if
|
740
|
-
|
741
|
-
|
742
|
-
|
744
|
+
if name == "xml"
|
745
|
+
xml_declaration
|
746
|
+
else # PITarget
|
747
|
+
if @source.skip_spaces # e.g. <?name content?>
|
748
|
+
start_position = @source.position
|
749
|
+
content = @source.read_until("?>")
|
750
|
+
unless content.chomp!("?>")
|
751
|
+
@source.position = start_position
|
752
|
+
raise ParseException.new("Malformed XML: Unclosed processing instruction: <#{name}>", @source)
|
753
|
+
end
|
754
|
+
else # e.g. <?name?>
|
755
|
+
content = nil
|
756
|
+
unless @source.match?("?>", true)
|
757
|
+
raise ParseException.new("Malformed XML: Unclosed processing instruction: <#{name}>", @source)
|
758
|
+
end
|
743
759
|
end
|
744
|
-
|
745
|
-
|
746
|
-
|
760
|
+
[:processing_instruction, name, content]
|
761
|
+
end
|
762
|
+
end
|
763
|
+
|
764
|
+
def xml_declaration
|
765
|
+
unless @version.nil?
|
766
|
+
raise ParseException.new("Malformed XML: XML declaration is duplicated", @source)
|
767
|
+
end
|
768
|
+
if @document_status
|
769
|
+
raise ParseException.new("Malformed XML: XML declaration is not at the start", @source)
|
770
|
+
end
|
771
|
+
unless @source.skip_spaces
|
772
|
+
raise ParseException.new("Malformed XML: XML declaration misses spaces before version", @source)
|
773
|
+
end
|
774
|
+
unless @source.match?("version", true)
|
775
|
+
raise ParseException.new("Malformed XML: XML declaration misses version", @source)
|
776
|
+
end
|
777
|
+
@version = parse_attribute_value_with_equal("xml")
|
778
|
+
unless @source.skip_spaces
|
747
779
|
unless @source.match?("?>", true)
|
748
|
-
raise ParseException.new("Malformed XML: Unclosed
|
780
|
+
raise ParseException.new("Malformed XML: Unclosed XML declaration", @source)
|
749
781
|
end
|
782
|
+
encoding = normalize_xml_declaration_encoding(@source.encoding)
|
783
|
+
return [ :xmldecl, @version, encoding, nil ] # e.g. <?xml version="1.0"?>
|
750
784
|
end
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
785
|
+
|
786
|
+
if @source.match?("encoding", true)
|
787
|
+
encoding = parse_attribute_value_with_equal("xml")
|
788
|
+
unless @source.skip_spaces
|
789
|
+
unless @source.match?("?>", true)
|
790
|
+
raise ParseException.new("Malformed XML: Unclosed XML declaration", @source)
|
791
|
+
end
|
792
|
+
if need_source_encoding_update?(encoding)
|
793
|
+
@source.encoding = encoding
|
794
|
+
end
|
795
|
+
encoding ||= normalize_xml_declaration_encoding(@source.encoding)
|
796
|
+
return [ :xmldecl, @version, encoding, nil ] # e.g. <?xml version="1.1" encoding="UTF-8"?>
|
761
797
|
end
|
762
|
-
|
763
|
-
|
798
|
+
end
|
799
|
+
|
800
|
+
if @source.match?("standalone", true)
|
801
|
+
standalone = parse_attribute_value_with_equal("xml")
|
802
|
+
case standalone
|
803
|
+
when "yes", "no"
|
804
|
+
else
|
805
|
+
raise ParseException.new("Malformed XML: XML declaration standalone is not yes or no : <#{standalone}>", @source)
|
764
806
|
end
|
765
|
-
standalone = STANDALONE.match(content)
|
766
|
-
standalone = standalone[1] unless standalone.nil?
|
767
|
-
return [ :xmldecl, version, encoding, standalone ]
|
768
807
|
end
|
769
|
-
|
808
|
+
@source.skip_spaces
|
809
|
+
unless @source.match?("?>", true)
|
810
|
+
raise ParseException.new("Malformed XML: Unclosed XML declaration", @source)
|
811
|
+
end
|
812
|
+
|
813
|
+
if need_source_encoding_update?(encoding)
|
814
|
+
@source.encoding = encoding
|
815
|
+
end
|
816
|
+
encoding ||= normalize_xml_declaration_encoding(@source.encoding)
|
817
|
+
|
818
|
+
# e.g. <?xml version="1.0" ?>
|
819
|
+
# <?xml version="1.1" encoding="UTF-8" ?>
|
820
|
+
# <?xml version="1.1" standalone="yes"?>
|
821
|
+
# <?xml version="1.1" encoding="UTF-8" standalone="yes" ?>
|
822
|
+
[ :xmldecl, @version, encoding, standalone ]
|
770
823
|
end
|
771
824
|
|
772
825
|
if StringScanner::Version < "3.1.1"
|
@@ -788,6 +841,25 @@ module REXML
|
|
788
841
|
end
|
789
842
|
end
|
790
843
|
|
844
|
+
def parse_attribute_value_with_equal(name)
|
845
|
+
unless @source.match?(Private::EQUAL_PATTERN, true)
|
846
|
+
message = "Missing attribute equal: <#{name}>"
|
847
|
+
raise REXML::ParseException.new(message, @source)
|
848
|
+
end
|
849
|
+
unless quote = scan_quote
|
850
|
+
message = "Missing attribute value start quote: <#{name}>"
|
851
|
+
raise REXML::ParseException.new(message, @source)
|
852
|
+
end
|
853
|
+
start_position = @source.position
|
854
|
+
value = @source.read_until(quote)
|
855
|
+
unless value.chomp!(quote)
|
856
|
+
@source.position = start_position
|
857
|
+
message = "Missing attribute value end quote: <#{name}>: <#{quote}>"
|
858
|
+
raise REXML::ParseException.new(message, @source)
|
859
|
+
end
|
860
|
+
value
|
861
|
+
end
|
862
|
+
|
791
863
|
def parse_attributes(prefixes)
|
792
864
|
attributes = {}
|
793
865
|
expanded_names = {}
|
@@ -802,23 +874,8 @@ module REXML
|
|
802
874
|
name = match[1]
|
803
875
|
prefix = match[2]
|
804
876
|
local_part = match[3]
|
805
|
-
|
806
|
-
|
807
|
-
message = "Missing attribute equal: <#{name}>"
|
808
|
-
raise REXML::ParseException.new(message, @source)
|
809
|
-
end
|
810
|
-
unless quote = scan_quote
|
811
|
-
message = "Missing attribute value start quote: <#{name}>"
|
812
|
-
raise REXML::ParseException.new(message, @source)
|
813
|
-
end
|
814
|
-
start_position = @source.position
|
815
|
-
value = @source.read_until(quote)
|
816
|
-
unless value.chomp!(quote)
|
817
|
-
@source.position = start_position
|
818
|
-
message = "Missing attribute value end quote: <#{name}>: <#{quote}>"
|
819
|
-
raise REXML::ParseException.new(message, @source)
|
820
|
-
end
|
821
|
-
@source.match?(/\s*/um, true)
|
877
|
+
value = parse_attribute_value_with_equal(name)
|
878
|
+
@source.skip_spaces
|
822
879
|
if prefix == "xmlns"
|
823
880
|
if local_part == "xml"
|
824
881
|
if value != Private::XML_PREFIXED_NAMESPACE
|
@@ -215,7 +215,7 @@ module REXML
|
|
215
215
|
else
|
216
216
|
path << yield( parsed )
|
217
217
|
end
|
218
|
-
|
218
|
+
path.squeeze(" ")
|
219
219
|
end
|
220
220
|
# For backward compatibility
|
221
221
|
alias_method :preciate_to_string, :predicate_to_path
|
@@ -252,7 +252,7 @@ module REXML
|
|
252
252
|
path = path[1..-1]
|
253
253
|
end
|
254
254
|
end
|
255
|
-
|
255
|
+
RelativeLocationPath( path, parsed ) if path.size > 0
|
256
256
|
end
|
257
257
|
|
258
258
|
#RelativeLocationPath
|
@@ -388,7 +388,7 @@ module REXML
|
|
388
388
|
else
|
389
389
|
path = original_path
|
390
390
|
end
|
391
|
-
|
391
|
+
path
|
392
392
|
end
|
393
393
|
|
394
394
|
# Filters the supplied nodeset on the predicate(s)
|
@@ -600,7 +600,7 @@ module REXML
|
|
600
600
|
end
|
601
601
|
rest = LocationPath(rest, n) if rest =~ /\A[\/\.\@\[\w*]/
|
602
602
|
parsed.concat(n)
|
603
|
-
|
603
|
+
rest
|
604
604
|
end
|
605
605
|
|
606
606
|
#| FilterExpr Predicate
|
data/lib/rexml/quickpath.rb
CHANGED
@@ -41,7 +41,7 @@ module REXML
|
|
41
41
|
else
|
42
42
|
results = filter([element], path)
|
43
43
|
end
|
44
|
-
|
44
|
+
results
|
45
45
|
end
|
46
46
|
|
47
47
|
# Given an array of nodes it filters the array based on the path. The
|
@@ -51,18 +51,18 @@ module REXML
|
|
51
51
|
return elements if path.nil? or path == '' or elements.size == 0
|
52
52
|
case path
|
53
53
|
when /^\/\//u # Descendant
|
54
|
-
|
54
|
+
axe( elements, "descendant-or-self", $' )
|
55
55
|
when /^\/?\b(\w[-\w]*)\b::/u # Axe
|
56
|
-
|
56
|
+
axe( elements, $1, $' )
|
57
57
|
when /^\/(?=\b([:!\w][-\.\w]*:)?[-!\*\.\w]*\b([^:(]|$)|\*)/u # Child
|
58
58
|
rest = $'
|
59
59
|
results = []
|
60
60
|
elements.each do |element|
|
61
61
|
results |= filter( element.to_a, rest )
|
62
62
|
end
|
63
|
-
|
63
|
+
results
|
64
64
|
when /^\/?(\w[-\w]*)\(/u # / Function
|
65
|
-
|
65
|
+
function( elements, $1, $' )
|
66
66
|
when Namespace::NAMESPLIT # Element name
|
67
67
|
name = $2
|
68
68
|
ns = $1
|
@@ -73,21 +73,21 @@ module REXML
|
|
73
73
|
(element.name == name and
|
74
74
|
element.namespace == Functions.namespace_context[ns])))
|
75
75
|
end
|
76
|
-
|
76
|
+
filter( elements, rest )
|
77
77
|
when /^\/\[/u
|
78
78
|
matches = []
|
79
79
|
elements.each do |element|
|
80
80
|
matches |= predicate( element.to_a, path[1..-1] ) if element.kind_of? Element
|
81
81
|
end
|
82
|
-
|
82
|
+
matches
|
83
83
|
when /^\[/u # Predicate
|
84
|
-
|
84
|
+
predicate( elements, path )
|
85
85
|
when /^\/?\.\.\./u # Ancestor
|
86
|
-
|
86
|
+
axe( elements, "ancestor", $' )
|
87
87
|
when /^\/?\.\./u # Parent
|
88
|
-
|
88
|
+
filter( elements.collect{|e|e.parent}, $' )
|
89
89
|
when /^\/?\./u # Self
|
90
|
-
|
90
|
+
filter( elements, $' )
|
91
91
|
when /^\*/u # Any
|
92
92
|
results = []
|
93
93
|
elements.each do |element|
|
@@ -98,9 +98,10 @@ module REXML
|
|
98
98
|
# results |= filter( children, $' )
|
99
99
|
#end
|
100
100
|
end
|
101
|
-
|
101
|
+
results
|
102
|
+
else
|
103
|
+
[]
|
102
104
|
end
|
103
|
-
return []
|
104
105
|
end
|
105
106
|
|
106
107
|
def QuickPath::axe( elements, axe_name, rest )
|
@@ -138,7 +139,7 @@ module REXML
|
|
138
139
|
matches = filter(elements.collect{|element|
|
139
140
|
element.previous_sibling}.uniq, rest )
|
140
141
|
end
|
141
|
-
|
142
|
+
matches.uniq
|
142
143
|
end
|
143
144
|
|
144
145
|
OPERAND_ = '((?=(?:(?!and|or).)*[^\s<>=])[^\s<>=]+)'
|
@@ -200,15 +201,15 @@ module REXML
|
|
200
201
|
results << element
|
201
202
|
end
|
202
203
|
end
|
203
|
-
|
204
|
+
filter( results, rest )
|
204
205
|
end
|
205
206
|
|
206
207
|
def QuickPath::attribute( name )
|
207
|
-
|
208
|
+
Functions.node.attributes[name] if Functions.node.kind_of? Element
|
208
209
|
end
|
209
210
|
|
210
211
|
def QuickPath::name()
|
211
|
-
|
212
|
+
Functions.node.name if Functions.node.kind_of? Element
|
212
213
|
end
|
213
214
|
|
214
215
|
def QuickPath::method_missing( id, *args )
|
@@ -234,7 +235,7 @@ module REXML
|
|
234
235
|
results << element if Functions.pair[0] == res
|
235
236
|
end
|
236
237
|
end
|
237
|
-
|
238
|
+
results
|
238
239
|
end
|
239
240
|
|
240
241
|
def QuickPath::parse_args( element, string )
|
data/lib/rexml/rexml.rb
CHANGED
data/lib/rexml/security.rb
CHANGED
@@ -10,7 +10,7 @@ module REXML
|
|
10
10
|
|
11
11
|
# Get the entity expansion limit. By default the limit is set to 10000.
|
12
12
|
def self.entity_expansion_limit
|
13
|
-
|
13
|
+
@@entity_expansion_limit
|
14
14
|
end
|
15
15
|
|
16
16
|
@@entity_expansion_text_limit = 10_240
|
@@ -22,7 +22,7 @@ module REXML
|
|
22
22
|
|
23
23
|
# Get the entity expansion limit. By default the limit is set to 10240.
|
24
24
|
def self.entity_expansion_text_limit
|
25
|
-
|
25
|
+
@@entity_expansion_text_limit
|
26
26
|
end
|
27
27
|
end
|
28
28
|
end
|
data/lib/rexml/source.rb
CHANGED
@@ -65,9 +65,10 @@ module REXML
|
|
65
65
|
attr_reader :encoding
|
66
66
|
|
67
67
|
module Private
|
68
|
+
SPACES_PATTERN = /\s+/um
|
68
69
|
SCANNER_RESET_SIZE = 100000
|
69
70
|
PRE_DEFINED_TERM_PATTERNS = {}
|
70
|
-
pre_defined_terms = ["'", '"', "<"]
|
71
|
+
pre_defined_terms = ["'", '"', "<", "]]>", "?>"]
|
71
72
|
if StringScanner::Version < "3.1.1"
|
72
73
|
pre_defined_terms.each do |term|
|
73
74
|
PRE_DEFINED_TERM_PATTERNS[term] = /#{Regexp.escape(term)}/
|
@@ -150,6 +151,10 @@ module REXML
|
|
150
151
|
end
|
151
152
|
end
|
152
153
|
|
154
|
+
def skip_spaces
|
155
|
+
@scanner.skip(Private::SPACES_PATTERN) ? true : false
|
156
|
+
end
|
157
|
+
|
153
158
|
def position
|
154
159
|
@scanner.pos
|
155
160
|
end
|
data/lib/rexml/text.rb
CHANGED
@@ -104,16 +104,16 @@ module REXML
|
|
104
104
|
@entity_filter = entity_filter if entity_filter
|
105
105
|
clear_cache
|
106
106
|
|
107
|
-
Text.check(@string, illegal
|
107
|
+
Text.check(@string, illegal) if @raw
|
108
108
|
end
|
109
109
|
|
110
110
|
def parent= parent
|
111
111
|
super(parent)
|
112
|
-
Text.check(@string, NEEDS_A_SECOND_CHECK
|
112
|
+
Text.check(@string, NEEDS_A_SECOND_CHECK) if @raw and @parent
|
113
113
|
end
|
114
114
|
|
115
115
|
# check for illegal characters
|
116
|
-
def Text.check string, pattern, doctype
|
116
|
+
def Text.check string, pattern, doctype = nil
|
117
117
|
|
118
118
|
# illegal anywhere
|
119
119
|
if !string.match?(VALID_XML_CHARS)
|
@@ -177,7 +177,7 @@ module REXML
|
|
177
177
|
|
178
178
|
|
179
179
|
def clone
|
180
|
-
|
180
|
+
Text.new(self, true)
|
181
181
|
end
|
182
182
|
|
183
183
|
|
@@ -200,10 +200,7 @@ module REXML
|
|
200
200
|
end
|
201
201
|
|
202
202
|
def doctype
|
203
|
-
|
204
|
-
doc = @parent.document
|
205
|
-
doc.doctype if doc
|
206
|
-
end
|
203
|
+
@parent&.document&.doctype
|
207
204
|
end
|
208
205
|
|
209
206
|
REFERENCE = /#{Entity::REFERENCE}/
|
@@ -264,30 +261,32 @@ module REXML
|
|
264
261
|
# Recursively wrap string at width.
|
265
262
|
return string if string.length <= width
|
266
263
|
place = string.rindex(' ', width) # Position in string with last ' ' before cutoff
|
267
|
-
if addnewline
|
268
|
-
|
264
|
+
if addnewline
|
265
|
+
"\n" + string[0,place] + "\n" + wrap(string[place+1..-1], width)
|
269
266
|
else
|
270
|
-
|
267
|
+
string[0,place] + "\n" + wrap(string[place+1..-1], width)
|
271
268
|
end
|
272
269
|
end
|
273
270
|
|
274
271
|
def indent_text(string, level=1, style="\t", indentfirstline=true)
|
272
|
+
Kernel.warn("#{self.class.name}#indent_text is deprecated. See REXML::Formatters", uplevel: 1)
|
275
273
|
return string if level < 0
|
276
|
-
|
274
|
+
|
275
|
+
new_string = +''
|
277
276
|
string.each_line { |line|
|
278
277
|
indent_string = style * level
|
279
278
|
new_line = (indent_string + line).sub(/[\s]+$/,'')
|
280
279
|
new_string << new_line
|
281
280
|
}
|
282
281
|
new_string.strip! unless indentfirstline
|
283
|
-
|
282
|
+
new_string
|
284
283
|
end
|
285
284
|
|
286
285
|
# == DEPRECATED
|
287
286
|
# See REXML::Formatters
|
288
287
|
#
|
289
288
|
def write( writer, indent=-1, transitive=false, ie_hack=false )
|
290
|
-
Kernel.warn("#{self.class.name}
|
289
|
+
Kernel.warn("#{self.class.name}#write is deprecated. See REXML::Formatters", uplevel: 1)
|
291
290
|
formatter = if indent > -1
|
292
291
|
REXML::Formatters::Pretty.new( indent )
|
293
292
|
else
|
@@ -299,9 +298,7 @@ module REXML
|
|
299
298
|
# FIXME
|
300
299
|
# This probably won't work properly
|
301
300
|
def xpath
|
302
|
-
|
303
|
-
path += "/text()"
|
304
|
-
return path
|
301
|
+
@parent.xpath + "/text()"
|
305
302
|
end
|
306
303
|
|
307
304
|
# Writes out text, substituting special characters beforehand.
|