File: encode.rb

package info (click to toggle)
ruby-mdurl-rb 1.0.5-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 156 kB
  • sloc: ruby: 1,077; makefile: 7
file content (100 lines) | stat: -rwxr-xr-x 2,562 bytes parent folder | download
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
module MDUrl
  module Encode

    DEFAULT_CHARACTERS   = ";/?:@&=+$,-_.!~*'()#"
    COMPONENT_CHARACTERS = "-_.!~*'()"

    @@encodeCache = {}


    # Create a lookup array where anything but characters in `chars` string
    # and alphanumeric chars is percent-encoded.
    #------------------------------------------------------------------------------
    def self.getEncodeCache(exclude)
      cache = @@encodeCache[exclude]
      return cache if (cache)

      cache = @@encodeCache[exclude] = []

      (0...128).each do |i|
        ch = i.chr

        if (/^[0-9a-z]$/i =~ ch)
          # always allow unencoded alphanumeric characters
          cache.push(ch)
        else
          cache.push('%' + ('0' + i.to_s(16).upcase).slice(-2, 2))
        end
      end

      (0...exclude.length).each do |i|
        cache[exclude[i].ord] = exclude[i]
      end

      return cache
    end


    # Encode unsafe characters with percent-encoding, skipping already
    # encoded sequences.
    #
    #  - string       - string to encode
    #  - exclude      - list of characters to ignore (in addition to a-zA-Z0-9)
    #  - keepEscaped  - don't encode '%' in a correct escape sequence (default: true)
    #------------------------------------------------------------------------------
    def self.encode(string, exclude = nil, keepEscaped = nil)
      result = ''

      if !exclude.is_a? String
        # encode(string, keepEscaped)
        keepEscaped = exclude
        exclude = DEFAULT_CHARACTERS
      end

      if keepEscaped == nil
        keepEscaped = true
      end

      cache = getEncodeCache(exclude)

      i = 0
      l = string.length
      while i < l
        code = string[i].ord

        if (keepEscaped && code == 0x25 && i + 2 < l) #  %
          if (/^[0-9a-f]{2}$/i =~ (string.slice((i + 1)...(i + 3))))
            result += string.slice(i...(i + 3))
            i += 3
            next
          end
        end

        if (code < 128)
          result += cache[code]
          i += 1
          next
        end

        if (code >= 0xD800 && code <= 0xDFFF)
          if (code >= 0xD800 && code <= 0xDBFF && i + 1 < l)
            nextCode = string[i + 1].ord
            if (nextCode >= 0xDC00 && nextCode <= 0xDFFF)
              result += CGI::escape(string[i] + string[i + 1])
              i += 2
              next
            end
          end
          result += '%EF%BF%BD'
          i += 1
          next
        end

        result += CGI::escape(string[i])
        i += 1
      end

      return result
    end
  end
end