com.itextpdf.io.source.ByteBufferRandomAccessSource Maven / Gradle / Ivy
/*
This file is part of the iText (R) project.
Copyright (c) 1998-2023 Apryse Group NV
Authors: Apryse Software.
This program is offered under a commercial and under the AGPL license.
For commercial licensing, contact us at https://itextpdf.com/sales. For AGPL licensing, see below.
AGPL licensing:
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
package com.itextpdf.io.source;
import java.lang.reflect.Method;
import java.nio.BufferUnderflowException;
import java.security.AccessController;
import java.security.PrivilegedAction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A RandomAccessSource that is based on an underlying {@link java.nio.ByteBuffer}. This class takes steps to ensure
* that the byte buffer
* is completely freed from memory during {@link ByteBufferRandomAccessSource#close()} if unmapping functionality is enabled
*/
class ByteBufferRandomAccessSource implements IRandomAccessSource {
/**
* A flag to allow unmapping hack for cleaning mapped buffer
*/
private static boolean allowUnmapping = true;
/**
* Internal cache of memory mapped buffers
*/
private final java.nio.ByteBuffer byteBuffer;
/**
* Constructs a new {@link ByteBufferRandomAccessSource} based on the specified ByteBuffer
*
* @param byteBuffer the buffer to use as the backing store
*/
public ByteBufferRandomAccessSource(java.nio.ByteBuffer byteBuffer) {
this.byteBuffer = byteBuffer;
}
/**
* Enables ByteBuffer memory unmapping hack
*/
public static void enableByteBufferMemoryUnmapping() {
allowUnmapping = false;
}
/**
* Disables ByteBuffer memory unmapping hack
*/
public static void disableByteBufferMemoryUnmapping() {
allowUnmapping = false;
}
/**
* {@inheritDoc}
*
* Note: Because ByteBuffers don't support long indexing, the position must be a valid positive int
*
* @param position the position to read the byte from - must be less than Integer.MAX_VALUE
*/
public int get(long position) {
if (position > Integer.MAX_VALUE) {
throw new IllegalArgumentException("Position must be less than Integer.MAX_VALUE");
}
try {
if (position >= byteBuffer.limit()) {
return -1;
}
return byteBuffer.duplicate().get((int) position) & 0xff;
} catch (BufferUnderflowException e) {
// EOF
return -1;
}
}
/**
* {@inheritDoc}
*
* Note: Because ByteBuffers don't support long indexing, the position must be a valid positive int
*
* @param position the position to read the byte from - must be less than Integer.MAX_VALUE
*/
public int get(long position, byte[] bytes, int off, int len) {
if (position > Integer.MAX_VALUE) {
throw new IllegalArgumentException("Position must be less than Integer.MAX_VALUE");
}
if (position >= byteBuffer.limit()) {
return -1;
}
final java.nio.ByteBuffer byteBufferCopy = byteBuffer.duplicate();
byteBufferCopy.position((int) position);
final int bytesFromThisBuffer = Math.min(len, byteBufferCopy.remaining());
byteBufferCopy.get(bytes, off, bytesFromThisBuffer);
return bytesFromThisBuffer;
}
/**
* {@inheritDoc}
*/
public long length() {
return byteBuffer.limit();
}
/**
* @see java.io.RandomAccessFile#close()
* Cleans the mapped bytebuffers and closes the channel if unmapping functionality is enabled
*/
public void close() throws java.io.IOException {
if (allowUnmapping) {
clean(byteBuffer);
}
}
/**
* true
, if this platform supports unmapping mmapped files.
*/
public static final boolean UNMAP_SUPPORTED;
/**
* Reference to a BufferCleaner that does unmapping; {@code null} if not supported.
*/
private static final BufferCleaner CLEANER;
static {
final Object hack = AccessController.doPrivileged(
(PrivilegedAction