@@ -44,20 +44,24 @@ This file is part of the iText (R) project.
44
44
package com .itextpdf .io .source ;
45
45
46
46
import java .lang .reflect .Method ;
47
- import java .nio .Buffer ;
48
47
import java .nio .BufferUnderflowException ;
49
48
import java .security .AccessController ;
50
49
import java .security .PrivilegedAction ;
51
50
import org .slf4j .Logger ;
52
51
import org .slf4j .LoggerFactory ;
53
52
54
-
55
53
/**
56
- * A RandomAccessSource that is based on an underlying {@link java.nio.ByteBuffer}. This class takes steps to ensure that the byte buffer
54
+ * A RandomAccessSource that is based on an underlying {@link java.nio.ByteBuffer}. This class takes steps to ensure
55
+ * that the byte buffer
57
56
* is completely freed from memory during {@link ByteBufferRandomAccessSource#close()}
58
57
*/
59
58
class ByteBufferRandomAccessSource implements IRandomAccessSource {
60
59
60
+ /**
61
+ * A flag to allow unmapping hack for cleaning mapped buffer
62
+ */
63
+ private static boolean allowUnmapping = true ;
64
+
61
65
/**
62
66
* Internal cache of memory mapped buffers
63
67
*/
@@ -72,6 +76,13 @@ public ByteBufferRandomAccessSource(java.nio.ByteBuffer byteBuffer) {
72
76
this .byteBuffer = byteBuffer ;
73
77
}
74
78
79
+ /**
80
+ * Enables unmapping hack
81
+ */
82
+ public static void disableUnmapping () {
83
+ allowUnmapping = false ;
84
+ }
85
+
75
86
/**
76
87
* {@inheritDoc}
77
88
* <p>
@@ -80,14 +91,15 @@ public ByteBufferRandomAccessSource(java.nio.ByteBuffer byteBuffer) {
80
91
* @param position the position to read the byte from - must be less than Integer.MAX_VALUE
81
92
*/
82
93
public int get (long position ) {
83
- if (position > Integer .MAX_VALUE )
94
+ if (position > Integer .MAX_VALUE ) {
84
95
throw new IllegalArgumentException ("Position must be less than Integer.MAX_VALUE" );
96
+ }
85
97
try {
86
98
87
- if (position >= (( Buffer ) byteBuffer ) .limit ())
99
+ if (position >= byteBuffer .limit ()) {
88
100
return -1 ;
89
- byte b = byteBuffer . get (( int ) position );
90
- return b & 0xff ;
101
+ }
102
+ return byteBuffer . duplicate (). get (( int ) position ) & 0xff ;
91
103
} catch (BufferUnderflowException e ) {
92
104
// EOF
93
105
return -1 ;
@@ -102,16 +114,18 @@ public int get(long position) {
102
114
* @param position the position to read the byte from - must be less than Integer.MAX_VALUE
103
115
*/
104
116
public int get (long position , byte [] bytes , int off , int len ) {
105
- if (position > Integer .MAX_VALUE )
117
+ if (position > Integer .MAX_VALUE ) {
106
118
throw new IllegalArgumentException ("Position must be less than Integer.MAX_VALUE" );
119
+ }
107
120
108
- if (position >= (( Buffer ) byteBuffer ) .limit ())
121
+ if (position >= byteBuffer .limit ()) {
109
122
return -1 ;
123
+ }
110
124
111
- // Not thread safe!
112
- (( Buffer ) byteBuffer ) .position ((int ) position );
113
- int bytesFromThisBuffer = Math .min (len , byteBuffer .remaining ());
114
- byteBuffer .get (bytes , off , bytesFromThisBuffer );
125
+ final java . nio . ByteBuffer byteBufferCopy = byteBuffer . duplicate ();
126
+ byteBufferCopy .position ((int ) position );
127
+ final int bytesFromThisBuffer = Math .min (len , byteBufferCopy .remaining ());
128
+ byteBufferCopy .get (bytes , off , bytesFromThisBuffer );
115
129
116
130
return bytesFromThisBuffer ;
117
131
}
@@ -121,15 +135,17 @@ public int get(long position, byte[] bytes, int off, int len) {
121
135
* {@inheritDoc}
122
136
*/
123
137
public long length () {
124
- return (( Buffer ) byteBuffer ) .limit ();
138
+ return byteBuffer .limit ();
125
139
}
126
140
127
141
/**
128
142
* @see java.io.RandomAccessFile#close()
129
143
* Cleans the mapped bytebuffers and closes the channel
130
144
*/
131
145
public void close () throws java .io .IOException {
132
- clean (byteBuffer );
146
+ if (allowUnmapping ) {
147
+ clean (byteBuffer );
148
+ }
133
149
}
134
150
135
151
@@ -144,11 +160,8 @@ public void close() throws java.io.IOException {
144
160
private static final BufferCleaner CLEANER ;
145
161
146
162
static {
147
- final Object hack = AccessController .doPrivileged (new PrivilegedAction <Object >() {
148
- public Object run () {
149
- return BufferCleaner .unmapHackImpl ();
150
- }
151
- });
163
+ final Object hack = AccessController .doPrivileged (
164
+ (PrivilegedAction <Object >) BufferCleaner ::unmapHackImpl );
152
165
if (hack instanceof BufferCleaner ) {
153
166
CLEANER = (BufferCleaner ) hack ;
154
167
UNMAP_SUPPORTED = true ;
@@ -162,37 +175,38 @@ public Object run() {
162
175
* invokes the clean method on the ByteBuffer's cleaner
163
176
*
164
177
* @param buffer ByteBuffer
178
+ *
165
179
* @return boolean true on success
166
180
*/
167
181
private static boolean clean (final java .nio .ByteBuffer buffer ) {
168
- if (buffer == null || !buffer .isDirect ())
182
+ if (buffer == null || !buffer .isDirect ()) {
169
183
return false ;
184
+ }
170
185
171
- Boolean b = AccessController .doPrivileged (new PrivilegedAction <Boolean >() {
172
- public Boolean run () {
173
- Boolean success = Boolean .FALSE ;
174
- try {
175
- // java 9
176
- if (UNMAP_SUPPORTED )
177
- CLEANER .freeBuffer (buffer .toString (), buffer );
178
- // java 8 and lower
179
- else {
180
- Method getCleanerMethod = buffer .getClass ().getMethod ("cleaner" , (Class <?>[]) null );
181
- getCleanerMethod .setAccessible (true );
182
- Object cleaner = getCleanerMethod .invoke (buffer , (Object []) null );
183
- Method clean = cleaner .getClass ().getMethod ("clean" , (Class <?>[]) null );
184
- clean .invoke (cleaner , (Object []) null );
185
- }
186
- success = Boolean .TRUE ;
187
- } catch (Exception e ) {
188
- // This really is a show stopper on windows
189
- Logger logger = LoggerFactory .getLogger (ByteBufferRandomAccessSource .class );
190
- logger .debug (e .getMessage ());
191
- }
192
- return success ;
193
- }
194
- });
186
+ return AccessController .doPrivileged ((PrivilegedAction <Boolean >) () -> cleanByUnmapping (buffer ));
187
+ }
195
188
196
- return b ;
189
+ private static boolean cleanByUnmapping (final java .nio .ByteBuffer buffer ) {
190
+ Boolean success = Boolean .FALSE ;
191
+ try {
192
+ // java 9
193
+ if (UNMAP_SUPPORTED ) {
194
+ CLEANER .freeBuffer (buffer .toString (), buffer );
195
+ }
196
+ // java 8 and lower
197
+ else {
198
+ Method getCleanerMethod = buffer .getClass ().getMethod ("cleaner" , (Class <?>[]) null );
199
+ getCleanerMethod .setAccessible (true );
200
+ Object cleaner = getCleanerMethod .invoke (buffer , (Object []) null );
201
+ Method clean = cleaner .getClass ().getMethod ("clean" , (Class <?>[]) null );
202
+ clean .invoke (cleaner , (Object []) null );
203
+ }
204
+ success = Boolean .TRUE ;
205
+ } catch (Exception e ) {
206
+ // This really is a show stopper on windows
207
+ Logger logger = LoggerFactory .getLogger (ByteBufferRandomAccessSource .class );
208
+ logger .debug (e .getMessage ());
209
+ }
210
+ return success ;
197
211
}
198
212
}
0 commit comments