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