Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/make/src/classes/build/tools/generatecharacter/Utility.java
32287 views
1
/*
2
* Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package build.tools.generatecharacter;
27
28
import java.text.*;
29
import java.util.*;
30
31
public class Utility {
32
static byte peekByte(String s, int index) {
33
char c = s.charAt(index/2);
34
return ((index&1)==0)?(byte)(c>>8):(byte)c;
35
}
36
37
static short peekShort(String s, int index) {
38
return (short)s.charAt(index);
39
}
40
41
static int peekInt(String s, int index) {
42
index *= 2;
43
return (((int)s.charAt(index)) << 16) | s.charAt(index+1);
44
}
45
46
static void poke(String s, int index, byte value) {
47
int mask = 0xFF00;
48
int ivalue = value;
49
if ((index&1)==0) {
50
ivalue <<= 8;
51
mask = 0x00FF;
52
}
53
index /= 2;
54
if (index == s.length()) {
55
s = s + (char)ivalue;
56
}
57
else if (index == 0) {
58
s = (char)(ivalue|(s.charAt(0)&mask)) + s.substring(1);
59
}
60
else {
61
s = s.substring(0, index) + (char)(ivalue|(s.charAt(index)&mask))
62
+ s.substring(index+1);
63
}
64
}
65
66
static void poke(String s, int index, short value) {
67
if (index == s.length()) {
68
s = s + (char)value;
69
}
70
else if (index == 0) {
71
s = (char)value + s.substring(1);
72
}
73
else {
74
s = s.substring(0, index) + (char)value + s.substring(index+1);
75
}
76
}
77
78
static void poke(String s, int index, int value) {
79
index *= 2;
80
char hi = (char)(value >> 16);
81
if (index == s.length()) {
82
s = s + hi + (char)value;
83
}
84
else if (index == 0) {
85
s = hi + (char)value + s.substring(2);
86
}
87
else {
88
s = s.substring(0, index) + hi + (char)value + s.substring(index+2);
89
}
90
}
91
92
/**
93
* The ESCAPE character is used during run-length encoding. It signals
94
* a run of identical chars.
95
*/
96
static final char ESCAPE = '\uA5A5';
97
98
/**
99
* The ESCAPE_BYTE character is used during run-length encoding. It signals
100
* a run of identical bytes.
101
*/
102
static final byte ESCAPE_BYTE = (byte)0xA5;
103
104
/**
105
* Construct a string representing a short array. Use run-length encoding.
106
* A character represents itself, unless it is the ESCAPE character. Then
107
* the following notations are possible:
108
* ESCAPE ESCAPE ESCAPE literal
109
* ESCAPE n c n instances of character c
110
* Since an encoded run occupies 3 characters, we only encode runs of 4 or
111
* more characters. Thus we have n > 0 and n != ESCAPE and n <= 0xFFFF.
112
* If we encounter a run where n == ESCAPE, we represent this as:
113
* c ESCAPE n-1 c
114
* The ESCAPE value is chosen so as not to collide with commonly
115
* seen values.
116
*/
117
static final String arrayToRLEString(short[] a) {
118
StringBuffer buffer = new StringBuffer();
119
// for (int i=0; i<a.length; ++i) buffer.append((char) a[i]);
120
buffer.append((char) (a.length >> 16));
121
buffer.append((char) a.length);
122
short runValue = a[0];
123
int runLength = 1;
124
for (int i=1; i<a.length; ++i) {
125
short s = a[i];
126
if (s == runValue && runLength < 0xFFFF) ++runLength;
127
else {
128
encodeRun(buffer, runValue, runLength);
129
runValue = s;
130
runLength = 1;
131
}
132
}
133
encodeRun(buffer, runValue, runLength);
134
return buffer.toString();
135
}
136
137
/**
138
* Construct a string representing a byte array. Use run-length encoding.
139
* Two bytes are packed into a single char, with a single extra zero byte at
140
* the end if needed. A byte represents itself, unless it is the
141
* ESCAPE_BYTE. Then the following notations are possible:
142
* ESCAPE_BYTE ESCAPE_BYTE ESCAPE_BYTE literal
143
* ESCAPE_BYTE n b n instances of byte b
144
* Since an encoded run occupies 3 bytes, we only encode runs of 4 or
145
* more bytes. Thus we have n > 0 and n != ESCAPE_BYTE and n <= 0xFF.
146
* If we encounter a run where n == ESCAPE_BYTE, we represent this as:
147
* b ESCAPE_BYTE n-1 b
148
* The ESCAPE_BYTE value is chosen so as not to collide with commonly
149
* seen values.
150
*/
151
static final String arrayToRLEString(byte[] a) {
152
StringBuffer buffer = new StringBuffer();
153
buffer.append((char) (a.length >> 16));
154
buffer.append((char) a.length);
155
byte runValue = a[0];
156
int runLength = 1;
157
byte[] state = new byte[2];
158
for (int i=1; i<a.length; ++i) {
159
byte b = a[i];
160
if (b == runValue && runLength < 0xFF) ++runLength;
161
else {
162
encodeRun(buffer, runValue, runLength, state);
163
runValue = b;
164
runLength = 1;
165
}
166
}
167
encodeRun(buffer, runValue, runLength, state);
168
169
// We must save the final byte, if there is one, by padding
170
// an extra zero.
171
if (state[0] != 0) appendEncodedByte(buffer, (byte)0, state);
172
173
return buffer.toString();
174
}
175
176
/**
177
* Encode a run, possibly a degenerate run (of < 4 values).
178
* @param length The length of the run; must be > 0 && <= 0xFFFF.
179
*/
180
private static final void encodeRun(StringBuffer buffer, short value, int length) {
181
if (length < 4) {
182
for (int j=0; j<length; ++j) {
183
if (value == (int) ESCAPE) buffer.append(ESCAPE);
184
buffer.append((char) value);
185
}
186
}
187
else {
188
if (length == (int) ESCAPE) {
189
if (value == (int) ESCAPE) buffer.append(ESCAPE);
190
buffer.append((char) value);
191
--length;
192
}
193
buffer.append(ESCAPE);
194
buffer.append((char) length);
195
buffer.append((char) value); // Don't need to escape this value
196
}
197
}
198
199
/**
200
* Encode a run, possibly a degenerate run (of < 4 values).
201
* @param length The length of the run; must be > 0 && <= 0xFF.
202
*/
203
private static final void encodeRun(StringBuffer buffer, byte value, int length,
204
byte[] state) {
205
if (length < 4) {
206
for (int j=0; j<length; ++j) {
207
if (value == ESCAPE_BYTE) appendEncodedByte(buffer, ESCAPE_BYTE, state);
208
appendEncodedByte(buffer, value, state);
209
}
210
}
211
else {
212
if (length == ESCAPE_BYTE) {
213
if (value == ESCAPE_BYTE) appendEncodedByte(buffer, ESCAPE_BYTE, state);
214
appendEncodedByte(buffer, value, state);
215
--length;
216
}
217
appendEncodedByte(buffer, ESCAPE_BYTE, state);
218
appendEncodedByte(buffer, (byte)length, state);
219
appendEncodedByte(buffer, value, state); // Don't need to escape this value
220
}
221
}
222
223
/**
224
* Append a byte to the given StringBuffer, packing two bytes into each
225
* character. The state parameter maintains intermediary data between
226
* calls.
227
* @param state A two-element array, with state[0] == 0 if this is the
228
* first byte of a pair, or state[0] != 0 if this is the second byte
229
* of a pair, in which case state[1] is the first byte.
230
*/
231
private static final void appendEncodedByte(StringBuffer buffer, byte value,
232
byte[] state) {
233
if (state[0] != 0) {
234
char c = (char) ((state[1] << 8) | (((int) value) & 0xFF));
235
buffer.append(c);
236
state[0] = 0;
237
}
238
else {
239
state[0] = 1;
240
state[1] = value;
241
}
242
}
243
244
/**
245
* Construct an array of shorts from a run-length encoded string.
246
*/
247
static final short[] RLEStringToShortArray(String s) {
248
int length = (((int) s.charAt(0)) << 16) | ((int) s.charAt(1));
249
short[] array = new short[length];
250
int ai = 0;
251
for (int i=2; i<s.length(); ++i) {
252
char c = s.charAt(i);
253
if (c == ESCAPE) {
254
c = s.charAt(++i);
255
if (c == ESCAPE) array[ai++] = (short) c;
256
else {
257
int runLength = (int) c;
258
short runValue = (short) s.charAt(++i);
259
for (int j=0; j<runLength; ++j) array[ai++] = runValue;
260
}
261
}
262
else {
263
array[ai++] = (short) c;
264
}
265
}
266
267
if (ai != length)
268
throw new InternalError("Bad run-length encoded short array");
269
270
return array;
271
}
272
273
/**
274
* Construct an array of bytes from a run-length encoded string.
275
*/
276
static final byte[] RLEStringToByteArray(String s) {
277
int length = (((int) s.charAt(0)) << 16) | ((int) s.charAt(1));
278
byte[] array = new byte[length];
279
boolean nextChar = true;
280
char c = 0;
281
int node = 0;
282
int runLength = 0;
283
int i = 2;
284
for (int ai=0; ai<length; ) {
285
// This part of the loop places the next byte into the local
286
// variable 'b' each time through the loop. It keeps the
287
// current character in 'c' and uses the boolean 'nextChar'
288
// to see if we've taken both bytes out of 'c' yet.
289
byte b;
290
if (nextChar) {
291
c = s.charAt(i++);
292
b = (byte) (c >> 8);
293
nextChar = false;
294
}
295
else {
296
b = (byte) (c & 0xFF);
297
nextChar = true;
298
}
299
300
// This part of the loop is a tiny state machine which handles
301
// the parsing of the run-length encoding. This would be simpler
302
// if we could look ahead, but we can't, so we use 'node' to
303
// move between three nodes in the state machine.
304
switch (node) {
305
case 0:
306
// Normal idle node
307
if (b == ESCAPE_BYTE) {
308
node = 1;
309
}
310
else {
311
array[ai++] = b;
312
}
313
break;
314
case 1:
315
// We have seen one ESCAPE_BYTE; we expect either a second
316
// one, or a run length and value.
317
if (b == ESCAPE_BYTE) {
318
array[ai++] = ESCAPE_BYTE;
319
node = 0;
320
}
321
else {
322
runLength = b;
323
// Interpret signed byte as unsigned
324
if (runLength < 0) runLength += 0x100;
325
node = 2;
326
}
327
break;
328
case 2:
329
// We have seen an ESCAPE_BYTE and length byte. We interpret
330
// the next byte as the value to be repeated.
331
for (int j=0; j<runLength; ++j) array[ai++] = b;
332
node = 0;
333
break;
334
}
335
}
336
337
if (node != 0)
338
throw new InternalError("Bad run-length encoded byte array");
339
340
if (i != s.length())
341
throw new InternalError("Excess data in RLE byte array string");
342
343
return array;
344
}
345
346
/**
347
* Format a String for representation in a source file. This includes
348
* breaking it into lines escaping characters using octal notation
349
* when necessary (control characters and double quotes).
350
*/
351
static final String formatForSource(String s) {
352
return formatForSource(s, " ");
353
}
354
355
/**
356
* Format a String for representation in a source file. This includes
357
* breaking it into lines escaping characters using octal notation
358
* when necessary (control characters and double quotes).
359
*/
360
static final String formatForSource(String s, String indent) {
361
StringBuffer buffer = new StringBuffer();
362
for (int i=0; i<s.length();) {
363
if (i > 0) buffer.append("+\n");
364
int limit = buffer.length() + 78; // Leave 2 for trailing <"+>
365
buffer.append(indent + '"');
366
while (i<s.length() && buffer.length()<limit) {
367
char c = s.charAt(i++);
368
/* This works too but it's kind of unnecessary; might as
369
well keep things simple.
370
if (c == '\\' || c == '"') {
371
// Escape backslash and double-quote. Don't need to
372
// escape single-quote.
373
buffer.append("\\" + c);
374
}
375
else if (c >= '\u0020' && c <= '\u007E') {
376
// Printable ASCII ranges from ' ' to '~'
377
buffer.append(c);
378
}
379
else
380
*/
381
if (c <= '\377') {
382
// Represent control characters
383
// using octal notation; otherwise the string we form
384
// won't compile, since Unicode escape sequences are
385
// processed before tokenization.
386
buffer.append('\\');
387
buffer.append(HEX_DIGIT[(c & 0700) >> 6]); // HEX_DIGIT works for octal
388
buffer.append(HEX_DIGIT[(c & 0070) >> 3]);
389
buffer.append(HEX_DIGIT[(c & 0007)]);
390
}
391
else {
392
// Handle the rest with Unicode
393
buffer.append("\\u");
394
buffer.append(HEX_DIGIT[(c & 0xF000) >> 12]);
395
buffer.append(HEX_DIGIT[(c & 0x0F00) >> 8]);
396
buffer.append(HEX_DIGIT[(c & 0x00F0) >> 4]);
397
buffer.append(HEX_DIGIT[(c & 0x000F)]);
398
}
399
}
400
buffer.append('"');
401
}
402
return buffer.toString();
403
}
404
405
static final char[] HEX_DIGIT = {'0','1','2','3','4','5','6','7',
406
'8','9','A','B','C','D','E','F'};
407
}
408
409