194 return result;
195 }
196
197 private static ByteBuffer slice(ByteBuffer buffer, int position, int capacity) {
198 // Note that this is the only limit and position manipulation of
199 // BasicImageReader private ByteBuffers. The synchronize could be avoided
200 // by cloning the buffer to make a local copy, but at the cost of creating
201 // a new object.
202 synchronized(buffer) {
203 buffer.limit(position + capacity);
204 buffer.position(position);
205 return buffer.slice();
206 }
207 }
208
209 private IntBuffer intBuffer(ByteBuffer buffer, int offset, int size) {
210 return slice(buffer, offset, size).order(byteOrder).asIntBuffer();
211 }
212
213 public static void releaseByteBuffer(ByteBuffer buffer) {
214 if (!MAP_ALL) {
215 ImageBufferCache.releaseBuffer(buffer);
216 }
217 }
218
219 public String getName() {
220 return name;
221 }
222
223 public ByteOrder getByteOrder() {
224 return byteOrder;
225 }
226
227 public Path getImagePath() {
228 return imagePath;
229 }
230
231 @Override
232 public void close() throws IOException {
233 if (channel != null) {
234 channel.close();
235 }
236 }
237
238 public ImageStringsReader getStrings() {
239 return stringsReader;
240 }
241
242 public ImageLocation findLocation(String mn, String rn) {
243 return findLocation("/" + mn + "/" + rn);
244 }
245
246 public synchronized ImageLocation findLocation(String name) {
247 // Details of the algorithm used here can be found in
248 // jdk.tools.jlink.internal.PerfectHashBuilder.
249 byte[] bytes = ImageStringsReader.mutf8FromString(name);
250 int count = header.getTableLength();
251 int index = redirect.get(ImageStringsReader.hashCode(bytes) % count);
252
253 if (index < 0) {
254 // index is twos complement of location attributes index.
255 index = -index - 1;
256 } else if (index > 0) {
257 // index is hash seed needed to compute location attributes index.
258 index = ImageStringsReader.hashCode(bytes, index) % count;
259 } else {
260 // No entry.
261 return null;
262 }
263
264 long[] attributes = getAttributes(offsets.get(index));
265
266 ImageLocation imageLocation = new ImageLocation(attributes, stringsReader);
270 }
271
272 return imageLocation;
273 }
274
275 public String[] getEntryNames() {
276 int[] attributeOffsets = new int[offsets.capacity()];
277 offsets.get(attributeOffsets);
278 return IntStream.of(attributeOffsets)
279 .filter(o -> o != 0)
280 .mapToObj(o -> ImageLocation.readFrom(this, o).getFullName())
281 .sorted()
282 .toArray(String[]::new);
283 }
284
285 ImageLocation getLocation(int offset) {
286 return ImageLocation.readFrom(this, offset);
287 }
288
289 public long[] getAttributes(int offset) {
290 ByteBuffer buffer = slice(locations, offset, locations.limit() - offset);
291 return ImageLocation.decompress(buffer);
292 }
293
294 public String getString(int offset) {
295 ByteBuffer buffer = slice(strings, offset, strings.limit() - offset);
296 return ImageStringsReader.stringFromByteBuffer(buffer);
297 }
298
299 private byte[] getBufferBytes(ByteBuffer buffer) {
300 byte[] bytes = new byte[buffer.limit()];
301 buffer.get(bytes);
302
303 return bytes;
304 }
305
306 private ByteBuffer readBuffer(long offset, long size) {
307 if (offset < 0 || Integer.MAX_VALUE <= offset) {
308 throw new IndexOutOfBoundsException("offset");
309 }
310
311 if (size < 0 || Integer.MAX_VALUE <= size) {
312 throw new IndexOutOfBoundsException("size");
313 }
314
315 if (MAP_ALL) {
316 ByteBuffer buffer = slice(memoryMap, (int)offset, (int)size);
317 buffer.order(ByteOrder.BIG_ENDIAN);
318
319 return buffer;
326 int read;
327 try {
328 read = channel.read(buffer, offset);
329 buffer.rewind();
330 } catch (IOException ex) {
331 ImageBufferCache.releaseBuffer(buffer);
332 throw new RuntimeException(ex);
333 }
334
335 if (read != size) {
336 ImageBufferCache.releaseBuffer(buffer);
337 throw new RuntimeException("Short read: " + read +
338 " instead of " + size + " bytes");
339 }
340
341 return buffer;
342 }
343 }
344
345 public byte[] getResource(String name) {
346 ImageLocation location = findLocation(name);
347
348 return location != null ? getResource(location) : null;
349 }
350
351 public byte[] getResource(ImageLocation loc) {
352 ByteBuffer buffer = getResourceBuffer(loc);
353
354 if (buffer != null) {
355 byte[] bytes = getBufferBytes(buffer);
356 ImageBufferCache.releaseBuffer(buffer);
357
358 return bytes;
359 }
360
361 return null;
362 }
363
364 public ByteBuffer getResourceBuffer(ImageLocation loc) {
365 long offset = loc.getContentOffset() + indexSize;
366 long compressedSize = loc.getCompressedSize();
367 long uncompressedSize = loc.getUncompressedSize();
368
369 if (compressedSize < 0 || Integer.MAX_VALUE < compressedSize) {
370 throw new IndexOutOfBoundsException("Compressed size");
371 }
372
373 if (uncompressedSize < 0 || Integer.MAX_VALUE < uncompressedSize) {
374 throw new IndexOutOfBoundsException("Uncompressed size");
375 }
376
377 if (compressedSize == 0) {
378 return readBuffer(offset, uncompressedSize);
379 } else {
380 ByteBuffer buffer = readBuffer(offset, compressedSize);
381
382 if (buffer != null) {
383 byte[] bytesIn = getBufferBytes(buffer);
384 ImageBufferCache.releaseBuffer(buffer);
385 byte[] bytesOut;
386
387 try {
388 bytesOut = decompressor.decompressResource(byteOrder,
389 (int strOffset) -> getString(strOffset), bytesIn);
390 } catch (IOException ex) {
391 throw new RuntimeException(ex);
392 }
393
394 return ByteBuffer.wrap(bytesOut);
395 }
396 }
397
398 return null;
399 }
400
401 public InputStream getResourceStream(ImageLocation loc) {
402 byte[] bytes = getResource(loc);
403
404 return new ByteArrayInputStream(bytes);
405 }
406 }
|
194 return result;
195 }
196
197 private static ByteBuffer slice(ByteBuffer buffer, int position, int capacity) {
198 // Note that this is the only limit and position manipulation of
199 // BasicImageReader private ByteBuffers. The synchronize could be avoided
200 // by cloning the buffer to make a local copy, but at the cost of creating
201 // a new object.
202 synchronized(buffer) {
203 buffer.limit(position + capacity);
204 buffer.position(position);
205 return buffer.slice();
206 }
207 }
208
209 private IntBuffer intBuffer(ByteBuffer buffer, int offset, int size) {
210 return slice(buffer, offset, size).order(byteOrder).asIntBuffer();
211 }
212
213 public static void releaseByteBuffer(ByteBuffer buffer) {
214 Objects.requireNonNull(buffer);
215
216 if (!MAP_ALL) {
217 ImageBufferCache.releaseBuffer(buffer);
218 }
219 }
220
221 public String getName() {
222 return name;
223 }
224
225 public ByteOrder getByteOrder() {
226 return byteOrder;
227 }
228
229 public Path getImagePath() {
230 return imagePath;
231 }
232
233 @Override
234 public void close() throws IOException {
235 if (channel != null) {
236 channel.close();
237 }
238 }
239
240 public ImageStringsReader getStrings() {
241 return stringsReader;
242 }
243
244 public ImageLocation findLocation(String mn, String rn) {
245 Objects.requireNonNull(mn);
246 Objects.requireNonNull(rn);
247
248 return findLocation("/" + mn + "/" + rn);
249 }
250
251 public synchronized ImageLocation findLocation(String name) {
252 Objects.requireNonNull(name);
253 // Details of the algorithm used here can be found in
254 // jdk.tools.jlink.internal.PerfectHashBuilder.
255 byte[] bytes = ImageStringsReader.mutf8FromString(name);
256 int count = header.getTableLength();
257 int index = redirect.get(ImageStringsReader.hashCode(bytes) % count);
258
259 if (index < 0) {
260 // index is twos complement of location attributes index.
261 index = -index - 1;
262 } else if (index > 0) {
263 // index is hash seed needed to compute location attributes index.
264 index = ImageStringsReader.hashCode(bytes, index) % count;
265 } else {
266 // No entry.
267 return null;
268 }
269
270 long[] attributes = getAttributes(offsets.get(index));
271
272 ImageLocation imageLocation = new ImageLocation(attributes, stringsReader);
276 }
277
278 return imageLocation;
279 }
280
281 public String[] getEntryNames() {
282 int[] attributeOffsets = new int[offsets.capacity()];
283 offsets.get(attributeOffsets);
284 return IntStream.of(attributeOffsets)
285 .filter(o -> o != 0)
286 .mapToObj(o -> ImageLocation.readFrom(this, o).getFullName())
287 .sorted()
288 .toArray(String[]::new);
289 }
290
291 ImageLocation getLocation(int offset) {
292 return ImageLocation.readFrom(this, offset);
293 }
294
295 public long[] getAttributes(int offset) {
296 if (offset < 0 || offset >= locations.limit()) {
297 throw new IndexOutOfBoundsException("offset");
298 }
299
300 ByteBuffer buffer = slice(locations, offset, locations.limit() - offset);
301 return ImageLocation.decompress(buffer);
302 }
303
304 public String getString(int offset) {
305 if (offset < 0 || offset >= strings.limit()) {
306 throw new IndexOutOfBoundsException("offset");
307 }
308
309 ByteBuffer buffer = slice(strings, offset, strings.limit() - offset);
310 return ImageStringsReader.stringFromByteBuffer(buffer);
311 }
312
313 private byte[] getBufferBytes(ByteBuffer buffer) {
314 Objects.requireNonNull(buffer);
315 byte[] bytes = new byte[buffer.limit()];
316 buffer.get(bytes);
317
318 return bytes;
319 }
320
321 private ByteBuffer readBuffer(long offset, long size) {
322 if (offset < 0 || Integer.MAX_VALUE <= offset) {
323 throw new IndexOutOfBoundsException("offset");
324 }
325
326 if (size < 0 || Integer.MAX_VALUE <= size) {
327 throw new IndexOutOfBoundsException("size");
328 }
329
330 if (MAP_ALL) {
331 ByteBuffer buffer = slice(memoryMap, (int)offset, (int)size);
332 buffer.order(ByteOrder.BIG_ENDIAN);
333
334 return buffer;
341 int read;
342 try {
343 read = channel.read(buffer, offset);
344 buffer.rewind();
345 } catch (IOException ex) {
346 ImageBufferCache.releaseBuffer(buffer);
347 throw new RuntimeException(ex);
348 }
349
350 if (read != size) {
351 ImageBufferCache.releaseBuffer(buffer);
352 throw new RuntimeException("Short read: " + read +
353 " instead of " + size + " bytes");
354 }
355
356 return buffer;
357 }
358 }
359
360 public byte[] getResource(String name) {
361 Objects.requireNonNull(name);
362 ImageLocation location = findLocation(name);
363
364 return location != null ? getResource(location) : null;
365 }
366
367 public byte[] getResource(ImageLocation loc) {
368 ByteBuffer buffer = getResourceBuffer(loc);
369
370 if (buffer != null) {
371 byte[] bytes = getBufferBytes(buffer);
372 ImageBufferCache.releaseBuffer(buffer);
373
374 return bytes;
375 }
376
377 return null;
378 }
379
380 public ByteBuffer getResourceBuffer(ImageLocation loc) {
381 Objects.requireNonNull(loc);
382 long offset = loc.getContentOffset() + indexSize;
383 long compressedSize = loc.getCompressedSize();
384 long uncompressedSize = loc.getUncompressedSize();
385
386 if (compressedSize < 0 || Integer.MAX_VALUE < compressedSize) {
387 throw new IndexOutOfBoundsException("Compressed size");
388 }
389
390 if (uncompressedSize < 0 || Integer.MAX_VALUE < uncompressedSize) {
391 throw new IndexOutOfBoundsException("Uncompressed size");
392 }
393
394 if (compressedSize == 0) {
395 return readBuffer(offset, uncompressedSize);
396 } else {
397 ByteBuffer buffer = readBuffer(offset, compressedSize);
398
399 if (buffer != null) {
400 byte[] bytesIn = getBufferBytes(buffer);
401 ImageBufferCache.releaseBuffer(buffer);
402 byte[] bytesOut;
403
404 try {
405 bytesOut = decompressor.decompressResource(byteOrder,
406 (int strOffset) -> getString(strOffset), bytesIn);
407 } catch (IOException ex) {
408 throw new RuntimeException(ex);
409 }
410
411 return ByteBuffer.wrap(bytesOut);
412 }
413 }
414
415 return null;
416 }
417
418 public InputStream getResourceStream(ImageLocation loc) {
419 Objects.requireNonNull(loc);
420 byte[] bytes = getResource(loc);
421
422 return new ByteArrayInputStream(bytes);
423 }
424 }
|