instiki/vendor/plugins/erubis-2.6.5/lib/erubis/converter.rb
Jacques Distler a5e08f7bcc Rails_xss Plugin
I installed the rails_xss plugin, for
the main purpose of seeing what will
break with Rails 3.0 (where the behaviour
of the plugin is the default). I think
I've fixed everything, but let me know if you
see stuff that is HTML-escaped, which
shouldn't be.

As a side benefit, we now use Erubis,
rather than ERB, to render templates.
They tell me it's faster ...
2010-05-26 00:27:49 -05:00

358 lines
10 KiB
Ruby

##
## $Release: 2.6.5 $
## copyright(c) 2006-2009 kuwata-lab.com all rights reserved.
##
require 'abstract'
module Erubis
##
## convert
##
module Converter
attr_accessor :preamble, :postamble, :escape
def self.supported_properties # :nodoc:
return [
[:preamble, nil, "preamble (no preamble when false)"],
[:postamble, nil, "postamble (no postamble when false)"],
[:escape, nil, "escape expression or not in default"],
]
end
def init_converter(properties={})
@preamble = properties[:preamble]
@postamble = properties[:postamble]
@escape = properties[:escape]
end
## convert input string into target language
def convert(input)
codebuf = "" # or []
@preamble.nil? ? add_preamble(codebuf) : (@preamble && (codebuf << @preamble))
convert_input(codebuf, input)
@postamble.nil? ? add_postamble(codebuf) : (@postamble && (codebuf << @postamble))
@_proc = nil # clear cached proc object
return codebuf # or codebuf.join()
end
protected
##
## detect spaces at beginning of line
##
def detect_spaces_at_bol(text, is_bol)
lspace = nil
if text.empty?
lspace = "" if is_bol
elsif text[-1] == ?\n
lspace = ""
else
rindex = text.rindex(?\n)
if rindex
s = text[rindex+1..-1]
if s =~ /\A[ \t]*\z/
lspace = s
#text = text[0..rindex]
text[rindex+1..-1] = ''
end
else
if is_bol && text =~ /\A[ \t]*\z/
#lspace = text
#text = nil
lspace = text.dup
text[0..-1] = ''
end
end
end
return lspace
end
##
## (abstract) convert input to code
##
def convert_input(codebuf, input)
not_implemented
end
end
module Basic
end
##
## basic converter which supports '<% ... %>' notation.
##
module Basic::Converter
include Erubis::Converter
def self.supported_properties # :nodoc:
return [
[:pattern, '<% %>', "embed pattern"],
[:trim, true, "trim spaces around <% ... %>"],
]
end
attr_accessor :pattern, :trim
def init_converter(properties={})
super(properties)
@pattern = properties[:pattern]
@trim = properties[:trim] != false
end
protected
## return regexp of pattern to parse eRuby script
def pattern_regexp(pattern)
@prefix, @postfix = pattern.split() # '<% %>' => '<%', '%>'
#return /(.*?)(^[ \t]*)?#{@prefix}(=+|\#)?(.*?)-?#{@postfix}([ \t]*\r?\n)?/m
#return /(^[ \t]*)?#{@prefix}(=+|\#)?(.*?)-?#{@postfix}([ \t]*\r?\n)?/m
return /#{@prefix}(=+|-|\#|%)?(.*?)([-=])?#{@postfix}([ \t]*\r?\n)?/m
end
module_function :pattern_regexp
#DEFAULT_REGEXP = /(.*?)(^[ \t]*)?<%(=+|\#)?(.*?)-?%>([ \t]*\r?\n)?/m
#DEFAULT_REGEXP = /(^[ \t]*)?<%(=+|\#)?(.*?)-?%>([ \t]*\r?\n)?/m
#DEFAULT_REGEXP = /<%(=+|\#)?(.*?)-?%>([ \t]*\r?\n)?/m
DEFAULT_REGEXP = pattern_regexp('<% %>')
public
def convert_input(src, input)
pat = @pattern
regexp = pat.nil? || pat == '<% %>' ? DEFAULT_REGEXP : pattern_regexp(pat)
pos = 0
is_bol = true # is beginning of line
input.scan(regexp) do |indicator, code, tailch, rspace|
match = Regexp.last_match()
len = match.begin(0) - pos
text = input[pos, len]
pos = match.end(0)
ch = indicator ? indicator[0] : nil
lspace = ch == ?= ? nil : detect_spaces_at_bol(text, is_bol)
is_bol = rspace ? true : false
add_text(src, text) if text && !text.empty?
## * when '<%= %>', do nothing
## * when '<% %>' or '<%# %>', delete spaces iff only spaces are around '<% %>'
if ch == ?= # <%= %>
rspace = nil if tailch && !tailch.empty?
add_text(src, lspace) if lspace
add_expr(src, code, indicator)
add_text(src, rspace) if rspace
elsif ch == ?\# # <%# %>
n = code.count("\n") + (rspace ? 1 : 0)
if @trim && lspace && rspace
add_stmt(src, "\n" * n)
else
add_text(src, lspace) if lspace
add_stmt(src, "\n" * n)
add_text(src, rspace) if rspace
end
elsif ch == ?% # <%% %>
s = "#{lspace}#{@prefix||='<%'}#{code}#{tailch}#{@postfix||='%>'}#{rspace}"
add_text(src, s)
else # <% %>
if @trim && lspace && rspace
add_stmt(src, "#{lspace}#{code}#{rspace}")
else
add_text(src, lspace) if lspace
add_stmt(src, code)
add_text(src, rspace) if rspace
end
end
end
#rest = $' || input # ruby1.8
rest = pos == 0 ? input : input[pos..-1] # ruby1.9
add_text(src, rest)
end
## add expression code to src
def add_expr(src, code, indicator)
case indicator
when '='
@escape ? add_expr_escaped(src, code) : add_expr_literal(src, code)
when '=='
@escape ? add_expr_literal(src, code) : add_expr_escaped(src, code)
when '==='
add_expr_debug(src, code)
end
end
end
module PI
end
##
## Processing Instructions (PI) converter for XML.
## this class converts '<?rb ... ?>' and '${...}' notation.
##
module PI::Converter
include Erubis::Converter
def self.desc # :nodoc:
"use processing instructions (PI) instead of '<% %>'"
end
def self.supported_properties # :nodoc:
return [
[:trim, true, "trim spaces around <% ... %>"],
[:pi, 'rb', "PI (Processing Instrunctions) name"],
[:embchar, '@', "char for embedded expression pattern('@{...}@')"],
[:pattern, '<% %>', "embed pattern"],
]
end
attr_accessor :pi, :prefix
def init_converter(properties={})
super(properties)
@trim = properties.fetch(:trim, true)
@pi = properties[:pi] if properties[:pi]
@embchar = properties[:embchar] || '@'
@pattern = properties[:pattern]
@pattern = '<% %>' if @pattern.nil? #|| @pattern == true
end
def convert(input)
code = super(input)
return @header || @footer ? "#{@header}#{code}#{@footer}" : code
end
protected
def convert_input(codebuf, input)
unless @regexp
@pi ||= 'e'
ch = Regexp.escape(@embchar)
if @pattern
left, right = @pattern.split(' ')
@regexp = /<\?#{@pi}(?:-(\w+))?(\s.*?)\?>([ \t]*\r?\n)?|#{ch}(!*)?\{(.*?)\}#{ch}|#{left}(=+)(.*?)#{right}/m
else
@regexp = /<\?#{@pi}(?:-(\w+))?(\s.*?)\?>([ \t]*\r?\n)?|#{ch}(!*)?\{(.*?)\}#{ch}/m
end
end
#
is_bol = true
pos = 0
input.scan(@regexp) do |pi_arg, stmt, rspace,
indicator1, expr1, indicator2, expr2|
match = Regexp.last_match
len = match.begin(0) - pos
text = input[pos, len]
pos = match.end(0)
lspace = stmt ? detect_spaces_at_bol(text, is_bol) : nil
is_bol = stmt && rspace ? true : false
add_text(codebuf, text) # unless text.empty?
#
if stmt
if @trim && lspace && rspace
add_pi_stmt(codebuf, "#{lspace}#{stmt}#{rspace}", pi_arg)
else
add_text(codebuf, lspace) if lspace
add_pi_stmt(codebuf, stmt, pi_arg)
add_text(codebuf, rspace) if rspace
end
else
add_pi_expr(codebuf, expr1 || expr2, indicator1 || indicator2)
end
end
#rest = $' || input # ruby1.8
rest = pos == 0 ? input : input[pos..-1] # ruby1.9
add_text(codebuf, rest)
end
#--
#def convert_input(codebuf, input)
# parse_stmts(codebuf, input)
# #parse_stmts2(codebuf, input)
#end
#
#def parse_stmts(codebuf, input)
# #regexp = pattern_regexp(@pattern)
# @pi ||= 'e'
# @stmt_pattern ||= /<\?#{@pi}(?:-(\w+))?(\s.*?)\?>([ \t]*\r?\n)?/m
# is_bol = true
# pos = 0
# input.scan(@stmt_pattern) do |pi_arg, code, rspace|
# match = Regexp.last_match
# len = match.begin(0) - pos
# text = input[pos, len]
# pos = match.end(0)
# lspace = detect_spaces_at_bol(text, is_bol)
# is_bol = rspace ? true : false
# parse_exprs(codebuf, text) # unless text.empty?
# if @trim && lspace && rspace
# add_pi_stmt(codebuf, "#{lspace}#{code}#{rspace}", pi_arg)
# else
# add_text(codebuf, lspace)
# add_pi_stmt(codebuf, code, pi_arg)
# add_text(codebuf, rspace)
# end
# end
# rest = $' || input
# parse_exprs(codebuf, rest)
#end
#
#def parse_exprs(codebuf, input)
# unless @expr_pattern
# ch = Regexp.escape(@embchar)
# if @pattern
# left, right = @pattern.split(' ')
# @expr_pattern = /#{ch}(!*)?\{(.*?)\}#{ch}|#{left}(=+)(.*?)#{right}/
# else
# @expr_pattern = /#{ch}(!*)?\{(.*?)\}#{ch}/
# end
# end
# pos = 0
# input.scan(@expr_pattern) do |indicator1, code1, indicator2, code2|
# indicator = indicator1 || indicator2
# code = code1 || code2
# match = Regexp.last_match
# len = match.begin(0) - pos
# text = input[pos, len]
# pos = match.end(0)
# add_text(codebuf, text) # unless text.empty?
# add_pi_expr(codebuf, code, indicator)
# end
# rest = $' || input
# add_text(codebuf, rest)
#end
#++
def add_pi_stmt(codebuf, code, pi_arg) # :nodoc:
case pi_arg
when nil ; add_stmt(codebuf, code)
when 'header' ; @header = code
when 'footer' ; @footer = code
when 'comment'; add_stmt(codebuf, "\n" * code.count("\n"))
when 'value' ; add_expr_literal(codebuf, code)
else ; add_stmt(codebuf, code)
end
end
def add_pi_expr(codebuf, code, indicator) # :nodoc:
case indicator
when nil, '', '==' # @{...}@ or <%== ... %>
@escape == false ? add_expr_literal(codebuf, code) : add_expr_escaped(codebuf, code)
when '!', '=' # @!{...}@ or <%= ... %>
@escape == false ? add_expr_escaped(codebuf, code) : add_expr_literal(codebuf, code)
when '!!', '===' # @!!{...}@ or <%=== ... %>
add_expr_debug(codebuf, code)
else
# ignore
end
end
end
end