misc/vim: inform the user when no results are found
[nit.git] / lib / base64.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2013 Alexis Laferrière <alexis.laf@xymus.net>
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16
17 # Offers the base 64 encoding and decoding algorithms
18 module base64
19
20 redef class String
21
22 # Alphabet used by the base64 algorithm
23 private fun base64_chars : String
24 do
25 return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
26 end
27 private fun inverted_base64_chars : HashMap[Char,Int]
28 do
29 var inv_base64_chars = new HashMap[Char,Int]
30 for k in [0..base64_chars.length[ do
31 inv_base64_chars[ base64_chars.chars[k] ] = k
32 end
33 return inv_base64_chars
34 end
35
36 # Encodes the receiver string to base64.
37 # By default, uses "=" for padding.
38 fun encode_base64 : String do return encode_base64_custom_padding( '=' )
39
40 # Encodes the receiver string to base64 using a custom padding character.
41 #
42 # If using the default padding character `=`, see `encode_base64`.
43 fun encode_base64_custom_padding( padding : Char ) : String
44 do
45 var base64_chars = once base64_chars
46 var length = length
47
48 var steps = length / 3
49 var chars_in_last_step = length % 3
50 var result_length = steps*4
51 if chars_in_last_step > 0 then result_length += 4
52 var result = (padding.to_s*result_length).to_cstring
53
54 var mask_6bit = 63
55
56 for s in [0..steps[ do
57 var e = 0
58 for ss in [0..3[ do
59 e += self.chars[s*3+ss].ascii.lshift((2-ss)*8)
60 end
61 for ss in [0..4[ do
62 result[s*4+3-ss] = base64_chars.chars[ e.rshift(ss*6).bin_and( mask_6bit ) ]
63 end
64 end
65
66 if chars_in_last_step == 1 then
67 var e = self.chars[length-1].ascii.lshift(16)
68 for ss in [0..2[ do
69 result[steps*4+1-ss] = base64_chars.chars[ e.rshift((ss+2)*6).bin_and( mask_6bit ) ]
70 end
71 else if chars_in_last_step == 2 then
72 var e = self.chars[length-2].ascii.lshift(16) +
73 self.chars[length-1].ascii.lshift(8)
74 for ss in [0..3[ do
75 result[steps*4+2-ss] = base64_chars.chars[ e.rshift((ss+1)*6).bin_and( mask_6bit ) ]
76 end
77 end
78
79 return result.to_s
80 end
81
82 # Decodes the receiver string from base64.
83 # By default, uses "=" for padding.
84 fun decode_base64 : String do return decode_base64_custom_padding( '=' )
85
86 # Decodes the receiver string to base64 using a custom padding character.
87 #
88 # If using the default padding character `=`, see `decode_base64`.
89 fun decode_base64_custom_padding( padding : Char ) : String
90 do
91 var inverted_base64_chars = once inverted_base64_chars
92 var length = length
93 assert length % 4 == 0 else print "base64::decode_base64 only supports strings of length multiple of 4"
94
95 var steps = length / 4
96 var result_length = steps*3
97
98 var padding_begin = self.search(padding)
99 var padding_count : Int
100 if padding_begin == null then
101 padding_count = 0
102 else
103 padding_count = length - padding_begin.from
104 steps -= 1
105 result_length -= padding_count
106 end
107
108 var result = ("#"*result_length).to_cstring
109
110 var mask_8bit = 255
111
112 for s in [0..steps[ do
113 var e = 0
114 for ss in [0..4[ do
115 e += inverted_base64_chars[self.chars[s*4+ss]].lshift((3-ss)*6)
116 end
117
118 for ss in [0..3[ do
119 result[s*3+ss] = e.rshift((2-ss)*8).bin_and( mask_8bit ).ascii
120 end
121 end
122
123 var s = steps
124 if padding_count == 1 then
125 var e = 0
126 for ss in [0..3[ do
127 e += inverted_base64_chars[self.chars[s*4+ss]].lshift((3-ss)*6)
128 end
129
130 for ss in [0..2[ do
131 result[s*3+ss] = e.rshift((2-ss)*8).bin_and( mask_8bit ).ascii
132 end
133 else if padding_count == 2 then
134 var e = 0
135 for ss in [0..2[ do
136 e += inverted_base64_chars[self.chars[s*4+ss]].lshift((3-ss)*6)
137 end
138
139 result[s*3] = e.rshift(2*8).bin_and( mask_8bit ).ascii
140 end
141
142 return result.to_s
143 end
144 end