forked from ruby/ruby
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathutil.rb
258 lines (240 loc) · 8.07 KB
/
util.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
# frozen_string_literal: true
class CGI
module Util; end
include Util
extend Util
end
module CGI::Util
@@accept_charset = Encoding::UTF_8 unless defined?(@@accept_charset)
# URL-encode a string into application/x-www-form-urlencoded.
# Space characters (+" "+) are encoded with plus signs (+"+"+)
# url_encoded_string = CGI.escape("'Stop!' said Fred")
# # => "%27Stop%21%27+said+Fred"
def escape(string)
encoding = string.encoding
buffer = string.b
buffer.gsub!(/([^ a-zA-Z0-9_.\-~]+)/) do |m|
'%' + m.unpack('H2' * m.bytesize).join('%').upcase
end
buffer.tr!(' ', '+')
buffer.force_encoding(encoding)
end
# URL-decode an application/x-www-form-urlencoded string with encoding(optional).
# string = CGI.unescape("%27Stop%21%27+said+Fred")
# # => "'Stop!' said Fred"
def unescape(string, encoding = @@accept_charset)
str = string.tr('+', ' ')
str = str.b
str.gsub!(/((?:%[0-9a-fA-F]{2})+)/) do |m|
[m.delete('%')].pack('H*')
end
str.force_encoding(encoding)
str.valid_encoding? ? str : str.force_encoding(string.encoding)
end
# URL-encode a string following RFC 3986
# Space characters (+" "+) are encoded with (+"%20"+)
# url_encoded_string = CGI.escapeURIComponent("'Stop!' said Fred")
# # => "%27Stop%21%27%20said%20Fred"
def escapeURIComponent(string)
encoding = string.encoding
buffer = string.b
buffer.gsub!(/([^a-zA-Z0-9_.\-~]+)/) do |m|
'%' + m.unpack('H2' * m.bytesize).join('%').upcase
end
buffer.force_encoding(encoding)
end
alias escape_uri_component escapeURIComponent
# URL-decode a string following RFC 3986 with encoding(optional).
# string = CGI.unescapeURIComponent("%27Stop%21%27+said%20Fred")
# # => "'Stop!'+said Fred"
def unescapeURIComponent(string, encoding = @@accept_charset)
str = string.b
str.gsub!(/((?:%[0-9a-fA-F]{2})+)/) do |m|
[m.delete('%')].pack('H*')
end
str.force_encoding(encoding)
str.valid_encoding? ? str : str.force_encoding(string.encoding)
end
alias unescape_uri_component unescapeURIComponent
# The set of special characters and their escaped values
TABLE_FOR_ESCAPE_HTML__ = {
"'" => ''',
'&' => '&',
'"' => '"',
'<' => '<',
'>' => '>',
}
# Escape special characters in HTML, namely '&\"<>
# CGI.escapeHTML('Usage: foo "bar" <baz>')
# # => "Usage: foo "bar" <baz>"
def escapeHTML(string)
enc = string.encoding
unless enc.ascii_compatible?
if enc.dummy?
origenc = enc
enc = Encoding::Converter.asciicompat_encoding(enc)
string = enc ? string.encode(enc) : string.b
end
table = Hash[TABLE_FOR_ESCAPE_HTML__.map {|pair|pair.map {|s|s.encode(enc)}}]
string = string.gsub(/#{"['&\"<>]".encode(enc)}/, table)
string.encode!(origenc) if origenc
string
else
string = string.b
string.gsub!(/['&\"<>]/, TABLE_FOR_ESCAPE_HTML__)
string.force_encoding(enc)
end
end
# TruffleRuby runs the pure-Ruby variant faster, do not use the C extension there
unless RUBY_ENGINE == 'truffleruby'
begin
require 'cgi/escape'
rescue LoadError
end
end
# Unescape a string that has been HTML-escaped
# CGI.unescapeHTML("Usage: foo "bar" <baz>")
# # => "Usage: foo \"bar\" <baz>"
def unescapeHTML(string)
enc = string.encoding
unless enc.ascii_compatible?
if enc.dummy?
origenc = enc
enc = Encoding::Converter.asciicompat_encoding(enc)
string = enc ? string.encode(enc) : string.b
end
string = string.gsub(Regexp.new('&(apos|amp|quot|gt|lt|#[0-9]+|#x[0-9A-Fa-f]+);'.encode(enc))) do
case $1.encode(Encoding::US_ASCII)
when 'apos' then "'".encode(enc)
when 'amp' then '&'.encode(enc)
when 'quot' then '"'.encode(enc)
when 'gt' then '>'.encode(enc)
when 'lt' then '<'.encode(enc)
when /\A#0*(\d+)\z/ then $1.to_i.chr(enc)
when /\A#x([0-9a-f]+)\z/i then $1.hex.chr(enc)
end
end
string.encode!(origenc) if origenc
return string
end
return string unless string.include? '&'
charlimit = case enc
when Encoding::UTF_8; 0x10ffff
when Encoding::ISO_8859_1; 256
else 128
end
string = string.b
string.gsub!(/&(apos|amp|quot|gt|lt|\#[0-9]+|\#[xX][0-9A-Fa-f]+);/) do
match = $1.dup
case match
when 'apos' then "'"
when 'amp' then '&'
when 'quot' then '"'
when 'gt' then '>'
when 'lt' then '<'
when /\A#0*(\d+)\z/
n = $1.to_i
if n < charlimit
n.chr(enc)
else
"&##{$1};"
end
when /\A#x([0-9a-f]+)\z/i
n = $1.hex
if n < charlimit
n.chr(enc)
else
"&#x#{$1};"
end
else
"&#{match};"
end
end
string.force_encoding enc
end
# Synonym for CGI.escapeHTML(str)
alias escape_html escapeHTML
# Synonym for CGI.unescapeHTML(str)
alias unescape_html unescapeHTML
# Escape only the tags of certain HTML elements in +string+.
#
# Takes an element or elements or array of elements. Each element
# is specified by the name of the element, without angle brackets.
# This matches both the start and the end tag of that element.
# The attribute list of the open tag will also be escaped (for
# instance, the double-quotes surrounding attribute values).
#
# print CGI.escapeElement('<BR><A HREF="url"></A>', "A", "IMG")
# # "<BR><A HREF="url"></A>"
#
# print CGI.escapeElement('<BR><A HREF="url"></A>', ["A", "IMG"])
# # "<BR><A HREF="url"></A>"
def escapeElement(string, *elements)
elements = elements[0] if elements[0].kind_of?(Array)
unless elements.empty?
string.gsub(/<\/?(?:#{elements.join("|")})\b[^<>]*+>?/im) do
CGI.escapeHTML($&)
end
else
string
end
end
# Undo escaping such as that done by CGI.escapeElement()
#
# print CGI.unescapeElement(
# CGI.escapeHTML('<BR><A HREF="url"></A>'), "A", "IMG")
# # "<BR><A HREF="url"></A>"
#
# print CGI.unescapeElement(
# CGI.escapeHTML('<BR><A HREF="url"></A>'), ["A", "IMG"])
# # "<BR><A HREF="url"></A>"
def unescapeElement(string, *elements)
elements = elements[0] if elements[0].kind_of?(Array)
unless elements.empty?
string.gsub(/<\/?(?:#{elements.join("|")})\b(?>[^&]+|&(?![gl]t;)\w+;)*(?:>)?/im) do
unescapeHTML($&)
end
else
string
end
end
# Synonym for CGI.escapeElement(str)
alias escape_element escapeElement
# Synonym for CGI.unescapeElement(str)
alias unescape_element unescapeElement
# Format a +Time+ object as a String using the format specified by RFC 1123.
#
# CGI.rfc1123_date(Time.now)
# # Sat, 01 Jan 2000 00:00:00 GMT
def rfc1123_date(time)
time.getgm.strftime("%a, %d %b %Y %T GMT")
end
# Prettify (indent) an HTML string.
#
# +string+ is the HTML string to indent. +shift+ is the indentation
# unit to use; it defaults to two spaces.
#
# print CGI.pretty("<HTML><BODY></BODY></HTML>")
# # <HTML>
# # <BODY>
# # </BODY>
# # </HTML>
#
# print CGI.pretty("<HTML><BODY></BODY></HTML>", "\t")
# # <HTML>
# # <BODY>
# # </BODY>
# # </HTML>
#
def pretty(string, shift = " ")
lines = string.gsub(/(?!\A)<.*?>/m, "\n\\0").gsub(/<.*?>(?!\n)/m, "\\0\n")
end_pos = 0
while end_pos = lines.index(/^<\/(\w+)/, end_pos)
element = $1.dup
start_pos = lines.rindex(/^\s*<#{element}/i, end_pos)
lines[start_pos ... end_pos] = "__" + lines[start_pos ... end_pos].gsub(/\n(?!\z)/, "\n" + shift) + "__"
end
lines.gsub(/^((?:#{Regexp::quote(shift)})*)__(?=<\/?\w)/, '\1')
end
alias h escapeHTML
end