1 /* 2 * Copyright (c) 2014, 2016, 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 private final BasicImageReader reader; 42 43 ImageStringsReader(BasicImageReader reader) { 44 this.reader = Objects.requireNonNull(reader); 45 } 46 47 @Override 48 public String get(int offset) { 49 return reader.getString(offset); 50 } 51 52 @Override 53 public int add(final String string) { 54 throw new InternalError("Can not add strings at runtime"); 55 } 56 57 private static int hashCode(byte[] bytes, int offset, int count, int seed) { 58 Objects.requireNonNull(bytes); 59 60 if (offset < 0 || count < 0 || offset > bytes.length - count) { 61 throw new IndexOutOfBoundsException("offset=" + offset + ", count=" + count); 62 } 63 64 int limit = offset + count; 65 66 if (limit < 0 || limit > bytes.length) { 67 throw new IndexOutOfBoundsException("limit=" + limit); 68 } 69 70 for (int i = offset; i < limit; i++) { 71 seed = (seed * HASH_MULTIPLIER) ^ (bytes[i] & 0xFF); 72 } 73 74 return seed & 0x7FFFFFFF; 75 } 76 77 public static int hashCode(byte[] bytes, int seed) { 78 return hashCode(bytes, 0, bytes.length, seed); 79 } 80 81 public static int hashCode(byte[] bytes) { 82 return hashCode(bytes, 0, bytes.length, HASH_MULTIPLIER); 83 } 84 85 public static int hashCode(String string, int seed) { 86 return hashCode(mutf8FromString(string), seed); 87 } 88 89 public static int hashCode(String string) { 90 return hashCode(mutf8FromString(string), HASH_MULTIPLIER); 91 } 92 93 static int charsFromMUTF8Length(byte[] bytes, int offset, int count) { 94 int length = 0; 95 96 for (int i = offset; i < offset + count; i++) { 97 byte ch = bytes[i]; 98 99 if (ch == 0) { 100 break; 101 } 102 103 if ((ch & 0xC0) != 0x80) { 104 length++; 105 } 106 } 107 108 return length; 109 } 110 111 static void charsFromMUTF8(char[] chars, byte[] bytes, int offset, int count) throws UTFDataFormatException { 112 int j = 0; 113 114 for (int i = offset; i < offset + count; i++) { 115 byte ch = bytes[i]; 116 117 if (ch == 0) { 118 break; 119 } 120 121 boolean is_unicode = (ch & 0x80) != 0; 122 int uch = ch & 0x7F; 123 124 if (is_unicode) { 125 int mask = 0x40; 126 127 while ((uch & mask) != 0) { 128 ch = bytes[++i]; 129 130 if ((ch & 0xC0) != 0x80) { 131 throw new UTFDataFormatException("bad continuation 0x" + Integer.toHexString(ch)); 132 } 133 134 uch = ((uch & ~mask) << 6) | (ch & 0x3F); 135 mask <<= 6 - 1; 136 } 137 138 if ((uch & 0xFFFF) != uch) { 139 throw new UTFDataFormatException("character out of range \\u" + Integer.toHexString(uch)); 140 } 141 } 142 143 chars[j++] = (char)uch; 144 } 145 } 146 147 public static String stringFromMUTF8(byte[] bytes, int offset, int count) { 148 int length = charsFromMUTF8Length(bytes, offset, count); 149 char[] chars = new char[length]; 150 151 try { 152 charsFromMUTF8(chars, bytes, offset, count); 153 } catch (UTFDataFormatException ex) { 154 throw new InternalError("Attempt to convert non modified UTF-8 byte sequence", ex); 155 } 156 157 return new String(chars); 158 } 159 160 public static String stringFromMUTF8(byte[] bytes) { 161 return stringFromMUTF8(bytes, 0, bytes.length); 162 } 163 164 static int charsFromByteBufferLength(ByteBuffer buffer) { 165 int length = 0; 166 167 while(buffer.hasRemaining()) { 168 byte ch = buffer.get(); 169 170 if (ch == 0) { 171 return length; 172 } 173 174 if ((ch & 0xC0) != 0x80) { 175 length++; 176 } 177 } 178 179 throw new InternalError("No terminating zero byte for modified UTF-8 byte sequence"); 180 } 181 182 static void charsFromByteBuffer(char chars[], ByteBuffer buffer) { 183 int j = 0; 184 185 while(buffer.hasRemaining()) { 186 byte ch = buffer.get(); 187 188 if (ch == 0) { 189 return; 190 } 191 192 boolean is_unicode = (ch & 0x80) != 0; 193 int uch = ch & 0x7F; 194 195 if (is_unicode) { 196 int mask = 0x40; 197 198 while ((uch & mask) != 0) { 199 ch = buffer.get(); 200 201 if ((ch & 0xC0) != 0x80) { 202 throw new InternalError("Bad continuation in " + 203 "modified UTF-8 byte sequence: " + ch); 204 } 205 206 uch = ((uch & ~mask) << 6) | (ch & 0x3F); 207 mask <<= 6 - 1; 208 } 209 } 210 211 if ((uch & 0xFFFF) != uch) { 212 throw new InternalError("UTF-32 char in modified UTF-8 " + 213 "byte sequence: " + uch); 214 } 215 216 chars[j++] = (char)uch; 217 } 218 219 throw new InternalError("No terminating zero byte for modified UTF-8 byte sequence"); 220 } 221 222 public static String stringFromByteBuffer(ByteBuffer buffer) { 223 int length = charsFromByteBufferLength(buffer); 224 buffer.rewind(); 225 char[] chars = new char[length]; 226 charsFromByteBuffer(chars, buffer); 227 228 return new String(chars); 229 } 230 231 static int mutf8FromCharsLength(char chars[]) { 232 int length = 0; 233 234 for (char ch : chars) { 235 int uch = ch & 0xFFFF; 236 237 if ((uch & ~0x7F) != 0) { 238 int mask = ~0x3F; 239 int n = 0; 240 241 do { 242 n++; 243 uch >>= 6; 244 mask >>= 1; 245 } while ((uch & mask) != 0); 246 247 length += n + 1; 248 } else if (uch == 0) { 249 length += 2; 250 } else { 251 length++; 252 } 253 } 254 255 return length; 256 } 257 258 static void mutf8FromChars(byte[] bytes, int offset, char chars[]) { 259 int j = offset; 260 byte[] buffer = new byte[8]; 261 262 for (char ch : chars) { 263 int uch = ch & 0xFFFF; 264 265 if ((uch & ~0x7F) != 0) { 266 int mask = ~0x3F; 267 int n = 0; 268 269 do { 270 buffer[n++] = (byte)(0x80 | (uch & 0x3F)); 271 uch >>= 6; 272 mask >>= 1; 273 } while ((uch & mask) != 0); 274 275 buffer[n] = (byte)((mask << 1) | uch); 276 277 do { 278 bytes[j++] = buffer[n--]; 279 } while (0 <= n); 280 } else if (uch == 0) { 281 bytes[j++] = (byte)0xC0; 282 bytes[j++] = (byte)0x80; 283 } else { 284 bytes[j++] = (byte)uch; 285 } 286 } 287 } 288 289 public static byte[] mutf8FromString(String string) { 290 char[] chars = string.toCharArray(); 291 int length = mutf8FromCharsLength(chars); 292 byte[] bytes = new byte[length]; 293 mutf8FromChars(bytes, 0, chars); 294 295 return bytes; 296 } 297 }