/
package.scala
247 lines (203 loc) · 6.97 KB
/
package.scala
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
package hector
import java.util.UUID
package object util {
// Utility methods should perform as fast as possible. Therefore you will not find many use
// of Scala features like for-comprehension in here.
//
val HexDigits: Array[Char] = "0123456789abcdef".toCharArray
/**
* Converts an array of bytes into a string.
*
* For instance <code>Array(0xff, 0xa0, 0x08, 0x00)</code> would result in the string "ffa00800".
*
* @param hash The array of bytes to convert.
*
* @return The converted string with. The length is exactly twice the one of the given array.
*/
def convertBytesToHexString(hash: Array[Byte]): String =
convertBytesToHexString(new StringBuilder(hash.length << 1), hash)
/**
* Appends a given array of bytes to a StringBuilder by converting and returns the resulting string.
*
* @param stringBuilder StringBuilder to append to.
* @param hash The array of bytes to append.
*
* @return The resulting string.
*/
def convertBytesToHexString(stringBuilder: StringBuilder, hash: Array[Byte]): String = {
var i = 0
val n = hash.length
while(i < n) {
val value = hash(i) & 0xff
if(value < 0x10) {
stringBuilder append '0'
}
stringBuilder append Integer.toString(value, 16)
i += 1
}
stringBuilder.toString()
}
private[this] val LetItCrashEnabled = System.getProperty("hector.enableLIC", "false").toBoolean
/**
* Creates and throws a RuntimeException with the message "Let it Crash!" for a given probability.
*
* <p>In order to enable this feature the JVM must be started with the parameter <code>-Dhector.enableLIC=true</code>.</p>
*
* <p>This is disabled by default.</p>
*
* <p>An exception is throw if <code>scala.math.random</code> returns a value less than the
* given probability.</p>
*
* @param probability The probability value in [0, 1).
*/
def letItCrash(probability: Double = 0.06125) {
if(LetItCrashEnabled && math.random < probability) {
println("Simulated exception.")
throw new RuntimeException("Let it Crash!")
}
}
/**
* Trims a string and returns None in case the result is empty.
*
* <p>In case <code>null</code> is passed to this method <code>None</code> will be returned.</p>
*
* {{{
* trimToOption(null) == None
* trimToOption("") == None
* trimToOption(" ") == None
* trimToOption(" foo ") == Some("foo")
* trimToOption("bar") == Some("bar")
* }}}
*
* @param value The string to trim.
*
* @return <code>Some</code> value if not empty after trimming; <code>None</code> otherwise.
*/
def trimToOption(value: String): Option[String] =
if(null == value || value.length == 0) {
None
} else {
val trimmedString = value.trim
if(trimmedString.length == 0) {
None
} else {
Some(trimmedString)
}
}
/**
* Generates and returns JavaScript code which will evaluate to the given value.
*
* @param value The string to escape.
*
* @return JavaScript code which will evaluate to the given string.
*/
def escapeJavaScriptString(value: String): String = {
// This code is a shameless adoption of GWT's awesome javaScriptString function in
// their JsToStringGenerationVisitor which is itself an adoption of Rhino's escapeString.
val chars = value.toCharArray
val n = chars.length
var i = 0
// Count the number of quotes and apostrophes. Use the least used so less characters need to
// be escaped.
//
// We could use quoteCount = chars count { _ == '"' } but in that case we would have to
// traverse the array twice. One time for quotes, one time for apostrophes.
var quoteCount = 0
var aposCount = 0
while(i < n) {
chars(i) match {
case '"' ⇒ quoteCount += 1
case '\'' ⇒ aposCount += 1
case _ ⇒
}
i += 1
}
val result = new StringBuilder(value.length + 0x10)
val quoteChar = if(quoteCount < aposCount) '"' else '\''
// Append opening quote character.
result.append(quoteChar)
// Append all characters
i = 0
while(i < n) {
val char = chars(i)
if(' ' <= char && char <= '~' && char != quoteChar && char != '\\') {
// An ordinary print character (like C isprint())
result.append(char)
} else {
// Character needs to be escaped. It is either a standard escape character like \n or it
// might be a unicode character. If it is not a standard escape character we will use
// either octal, hexadecimal or unicode encoding depending on which variant is shorter.
//
// Note that octal encoding might be used only if we are at the end of the string or
// when the subsequent character is not a number since it would be misinterpreted otherwise.
val escape: Int =
char match {
case '\b' ⇒ 'b'
case '\f' ⇒ 'f'
case '\n' ⇒ 'n'
case '\r' ⇒ 'r'
case '\t' ⇒ 'r'
case '"' ⇒ '"' // Will be reached only if c == quoteChar
case '\'' ⇒ '\'' // Will be reached only if c == quoteChar
case '\\' ⇒ '\\'
case _ ⇒ -1
}
result.append('\\')
if(escape >= 0) {
// An \escape sort of character
result.append(escape.asInstanceOf[Char])
} else {
if(char < ' ' && (i == (n-1) || chars(i + 1) < '0' || chars(i + 1) > '9')) {
if(char > 0x7) {
result.append(('0' + (0x7 & (char >> 3))).asInstanceOf[Char])
}
result.append(('0' + (0x7 & char)).asInstanceOf[Char])
} else {
val hexSize =
if(char < 0x100) {
result.append('x')
2
} else {
result.append('u')
4
}
var shift = (hexSize - 1) << 2
while(shift >= 0) {
val digit = 0xf & (char >> shift)
result.append(HexDigits(digit))
shift -= 4
}
}
}
}
i += 1
}
// Append closing quote character.
result.append(quoteChar)
// Escape all closing XML tags
escapeClosingTags(result)
result.toString()
}
/**
* Helper method for <code>escapeJavaScriptString</code>.
*
* Escapes any closing XML tags embedded in the given StringBuilder which could
* potentially cause a parser failure in a browser.
*
* @param stringBuilder The string builder. May be <code>null</code>.
*/
private[this] def escapeClosingTags(stringBuilder: StringBuilder) {
if(null != stringBuilder) {
var index = 0
//TODO(joa): check bytecode
while({index = stringBuilder.indexOf("</"); index} != -1) {
stringBuilder.insert(index + 1, '\\')
}
}
}
def randomHash(): String = {
import java.util.{UUID ⇒ JUUID}
val uuid = JUUID.randomUUID().toString
uuid.replace("-", "")
}
}