1 /*
2  * Copyright (c) 2014, 2017, 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 jdk.internal.jimage;
27 
28 import java.io.UTFDataFormatException;
29 import java.nio.ByteBuffer;
30 import java.util.Objects;
31 
32 /**
33  * @implNote This class needs to maintain JDK 8 source compatibility.
34  *
35  * It is used internally in the JDK to implement jimage/jrtfs access,
36  * but also compiled and delivered as part of the jrtfs.jar to support access
37  * to the jimage file provided by the shipped JDK by tools running on JDK 8.
38  */
39 public class ImageStringsReader implements ImageStrings {
40     public static final int HASH_MULTIPLIER = 0x01000193;
41     public static final int POSITIVE_MASK = 0x7FFFFFFF;
42 
43     private final BasicImageReader reader;
44 
ImageStringsReader(BasicImageReader reader)45     ImageStringsReader(BasicImageReader reader) {
46         this.reader = Objects.requireNonNull(reader);
47     }
48 
49     @Override
get(int offset)50     public String get(int offset) {
51         return reader.getString(offset);
52     }
53 
54     @Override
add(final String string)55     public int add(final String string) {
56         throw new InternalError("Can not add strings at runtime");
57     }
58 
hashCode(String s)59     public static int hashCode(String s) {
60         return hashCode(s, HASH_MULTIPLIER);
61     }
62 
hashCode(String s, int seed)63     public static int hashCode(String s, int seed) {
64         return unmaskedHashCode(s, seed) & POSITIVE_MASK;
65     }
66 
hashCode(String module, String name)67     public static int hashCode(String module, String name) {
68         return hashCode(module, name, HASH_MULTIPLIER);
69     }
70 
hashCode(String module, String name, int seed)71     public static int hashCode(String module, String name, int seed) {
72         seed = unmaskedHashCode("/", seed);
73         seed = unmaskedHashCode(module, seed);
74         seed = unmaskedHashCode("/", seed);
75         seed = unmaskedHashCode(name, seed);
76         return seed & POSITIVE_MASK;
77     }
78 
unmaskedHashCode(String s, int seed)79     public static int unmaskedHashCode(String s, int seed) {
80         int slen = s.length();
81         byte[] buffer = null;
82 
83         for (int i = 0; i < slen; i++) {
84             char ch = s.charAt(i);
85             int uch = ch & 0xFFFF;
86 
87             if ((uch & ~0x7F) != 0) {
88                 if (buffer == null) {
89                     buffer = new byte[8];
90                 }
91                 int mask = ~0x3F;
92                 int n = 0;
93 
94                 do {
95                     buffer[n++] = (byte)(0x80 | (uch & 0x3F));
96                     uch >>= 6;
97                     mask >>= 1;
98                 } while ((uch & mask) != 0);
99 
100                 buffer[n] = (byte)((mask << 1) | uch);
101 
102                 do {
103                     seed = (seed * HASH_MULTIPLIER) ^ (buffer[n--] & 0xFF);
104                 } while (0 <= n);
105             } else if (uch == 0) {
106                 seed = (seed * HASH_MULTIPLIER) ^ (0xC0);
107                 seed = (seed * HASH_MULTIPLIER) ^ (0x80);
108             } else {
109                 seed = (seed * HASH_MULTIPLIER) ^ (uch);
110             }
111         }
112         return seed;
113     }
114 
charsFromMUTF8Length(byte[] bytes, int offset, int count)115     static int charsFromMUTF8Length(byte[] bytes, int offset, int count) {
116         int length = 0;
117 
118         for (int i = offset; i < offset + count; i++) {
119             byte ch = bytes[i];
120 
121             if (ch == 0) {
122                 break;
123             }
124 
125             if ((ch & 0xC0) != 0x80) {
126                 length++;
127             }
128         }
129 
130         return length;
131     }
132 
charsFromMUTF8(char[] chars, byte[] bytes, int offset, int count)133     static void charsFromMUTF8(char[] chars, byte[] bytes, int offset, int count) throws UTFDataFormatException {
134         int j = 0;
135 
136         for (int i = offset; i < offset + count; i++) {
137             byte ch = bytes[i];
138 
139             if (ch == 0) {
140                 break;
141             }
142 
143             boolean is_unicode = (ch & 0x80) != 0;
144             int uch = ch & 0x7F;
145 
146             if (is_unicode) {
147                 int mask = 0x40;
148 
149                 while ((uch & mask) != 0) {
150                     ch = bytes[++i];
151 
152                     if ((ch & 0xC0) != 0x80) {
153                         throw new UTFDataFormatException("bad continuation 0x" + Integer.toHexString(ch));
154                     }
155 
156                     uch = ((uch & ~mask) << 6) | (ch & 0x3F);
157                     mask <<= 6 - 1;
158                 }
159 
160                 if ((uch & 0xFFFF) != uch) {
161                     throw new UTFDataFormatException("character out of range \\u" + Integer.toHexString(uch));
162                 }
163             }
164 
165             chars[j++] = (char)uch;
166         }
167     }
168 
stringFromMUTF8(byte[] bytes, int offset, int count)169     public static String stringFromMUTF8(byte[] bytes, int offset, int count) {
170         int length = charsFromMUTF8Length(bytes, offset, count);
171         char[] chars = new char[length];
172 
173         try {
174             charsFromMUTF8(chars, bytes, offset, count);
175         } catch (UTFDataFormatException ex) {
176             throw new InternalError("Attempt to convert non modified UTF-8 byte sequence", ex);
177         }
178 
179         return new String(chars);
180     }
181 
stringFromMUTF8(byte[] bytes)182     public static String stringFromMUTF8(byte[] bytes) {
183         return stringFromMUTF8(bytes, 0, bytes.length);
184     }
185 
charsFromByteBufferLength(ByteBuffer buffer)186     static int charsFromByteBufferLength(ByteBuffer buffer) {
187         int length = 0;
188 
189         while(buffer.hasRemaining()) {
190             byte ch = buffer.get();
191 
192             if (ch == 0) {
193                 return length;
194             }
195 
196             if ((ch & 0xC0) != 0x80) {
197                 length++;
198             }
199         }
200 
201         throw new InternalError("No terminating zero byte for modified UTF-8 byte sequence");
202     }
203 
charsFromByteBuffer(char[] chars, ByteBuffer buffer)204     static void charsFromByteBuffer(char[] chars, ByteBuffer buffer) {
205         int j = 0;
206 
207         while(buffer.hasRemaining()) {
208             byte ch = buffer.get();
209 
210             if (ch == 0) {
211                 return;
212             }
213 
214             boolean is_unicode = (ch & 0x80) != 0;
215             int uch = ch & 0x7F;
216 
217             if (is_unicode) {
218                 int mask = 0x40;
219 
220                 while ((uch & mask) != 0) {
221                     ch = buffer.get();
222 
223                     if ((ch & 0xC0) != 0x80) {
224                         throw new InternalError("Bad continuation in " +
225                             "modified UTF-8 byte sequence: " + ch);
226                     }
227 
228                     uch = ((uch & ~mask) << 6) | (ch & 0x3F);
229                     mask <<= 6 - 1;
230                 }
231             }
232 
233             if ((uch & 0xFFFF) != uch) {
234                 throw new InternalError("UTF-32 char in modified UTF-8 " +
235                     "byte sequence: " + uch);
236             }
237 
238             chars[j++] = (char)uch;
239         }
240 
241         throw new InternalError("No terminating zero byte for modified UTF-8 byte sequence");
242     }
243 
stringFromByteBuffer(ByteBuffer buffer)244     public static String stringFromByteBuffer(ByteBuffer buffer) {
245         int length = charsFromByteBufferLength(buffer);
246         buffer.rewind();
247         char[] chars = new char[length];
248         charsFromByteBuffer(chars, buffer);
249 
250         return new String(chars);
251     }
252 
mutf8FromStringLength(String s)253     static int mutf8FromStringLength(String s) {
254         int length = 0;
255         int slen = s.length();
256 
257         for (int i = 0; i < slen; i++) {
258             char ch = s.charAt(i);
259             int uch = ch & 0xFFFF;
260 
261             if ((uch & ~0x7F) != 0) {
262                 int mask = ~0x3F;
263                 int n = 0;
264 
265                 do {
266                     n++;
267                     uch >>= 6;
268                     mask >>= 1;
269                 } while ((uch & mask) != 0);
270 
271                 length += n + 1;
272             } else if (uch == 0) {
273                 length += 2;
274             } else {
275                 length++;
276             }
277         }
278 
279         return length;
280     }
281 
mutf8FromString(byte[] bytes, int offset, String s)282     static void mutf8FromString(byte[] bytes, int offset, String s) {
283         int j = offset;
284         byte[] buffer = null;
285         int slen = s.length();
286 
287         for (int i = 0; i < slen; i++) {
288             char ch = s.charAt(i);
289             int uch = ch & 0xFFFF;
290 
291             if ((uch & ~0x7F) != 0) {
292                 if (buffer == null) {
293                     buffer = new byte[8];
294                 }
295                 int mask = ~0x3F;
296                 int n = 0;
297 
298                 do {
299                     buffer[n++] = (byte)(0x80 | (uch & 0x3F));
300                     uch >>= 6;
301                     mask >>= 1;
302                 } while ((uch & mask) != 0);
303 
304                 buffer[n] = (byte)((mask << 1) | uch);
305 
306                 do {
307                     bytes[j++] = buffer[n--];
308                 } while (0 <= n);
309             } else if (uch == 0) {
310                 bytes[j++] = (byte)0xC0;
311                 bytes[j++] = (byte)0x80;
312             } else {
313                 bytes[j++] = (byte)uch;
314             }
315         }
316     }
317 
mutf8FromString(String string)318     public static byte[] mutf8FromString(String string) {
319         int length = mutf8FromStringLength(string);
320         byte[] bytes = new byte[length];
321         mutf8FromString(bytes, 0, string);
322 
323         return bytes;
324     }
325 }
326