1 | /* | |
2 | * $Id: MappedRandomAccessFile.java 3314 2008-05-01 23:48:39Z xlv $ | |
3 | * | |
4 | * Copyright 2006 Joakim Sandstroem | |
5 | * | |
6 | * The contents of this file are subject to the Mozilla Public License Version 1.1 | |
7 | * (the "License"); you may not use this file except in compliance with the License. | |
8 | * You may obtain a copy of the License at http://www.mozilla.org/MPL/ | |
9 | * | |
10 | * Software distributed under the License is distributed on an "AS IS" basis, | |
11 | * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License | |
12 | * for the specific language governing rights and limitations under the License. | |
13 | * | |
14 | * The Original Code is 'iText, a free JAVA-PDF library'. | |
15 | * | |
16 | * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by | |
17 | * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. | |
18 | * All Rights Reserved. | |
19 | * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer | |
20 | * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. | |
21 | * | |
22 | * Contributor(s): all the names of the contributors are added in the source code | |
23 | * where applicable. | |
24 | * | |
25 | * Alternatively, the contents of this file may be used under the terms of the | |
26 | * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the | |
27 | * provisions of LGPL are applicable instead of those above. If you wish to | |
28 | * allow use of your version of this file only under the terms of the LGPL | |
29 | * License and not to allow others to use your version of this file under | |
30 | * the MPL, indicate your decision by deleting the provisions above and | |
31 | * replace them with the notice and other provisions required by the LGPL. | |
32 | * If you do not delete the provisions above, a recipient may use your version | |
33 | * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. | |
34 | * | |
35 | * This library is free software; you can redistribute it and/or modify it | |
36 | * under the terms of the MPL as stated above or under the terms of the GNU | |
37 | * Library General Public License as published by the Free Software Foundation; | |
38 | * either version 2 of the License, or any later version. | |
39 | * | |
40 | * This library is distributed in the hope that it will be useful, but WITHOUT | |
41 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | |
42 | * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more | |
43 | * details. | |
44 | * | |
45 | * If you didn't download this code from the following link, you should check if | |
46 | * you aren't using an obsolete version: | |
47 | * http://www.lowagie.com/iText/ | |
48 | */ | |
49 | package com.lowagie.text.pdf; | |
50 | ||
51 | import java.io.FileInputStream; | |
52 | import java.io.FileNotFoundException; | |
53 | import java.io.IOException; | |
54 | import java.lang.reflect.Field; | |
55 | import java.lang.reflect.Method; | |
56 | import java.nio.BufferUnderflowException; | |
57 | import java.nio.ByteBuffer; | |
58 | import java.nio.MappedByteBuffer; | |
59 | import java.nio.channels.FileChannel; | |
60 | import java.security.AccessController; | |
61 | import java.security.PrivilegedAction; | |
62 | ||
63 | /** | |
64 | * A {@link java.nio.MappedByteBuffer} wrapped as a {@link java.io.RandomAccessFile} | |
65 | * | |
66 | * @author Joakim Sandstroem | |
67 | * Created on 6.9.2006 | |
68 | */ | |
69 | public class MappedRandomAccessFile { | |
70 | | |
71 | private MappedByteBuffer mappedByteBuffer = null; | |
72 | private FileChannel channel = null; | |
73 | | |
74 | /** | |
75 | * Constructs a new MappedRandomAccessFile instance | |
76 | * @param filename String | |
77 | * @param mode String r, w or rw | |
78 | * @throws FileNotFoundException | |
79 | * @throws IOException | |
80 | */ | |
81 | public MappedRandomAccessFile(String filename, String mode) | |
82 | throws IOException { | |
83 | | |
84 |
1
1. |
if (mode.equals("rw")) |
85 |
1
1. |
init( |
86 | new java.io.RandomAccessFile(filename, mode).getChannel(), | |
87 | FileChannel.MapMode.READ_WRITE); | |
88 | else | |
89 |
1
1. |
init( |
90 | new FileInputStream(filename).getChannel(), | |
91 | FileChannel.MapMode.READ_ONLY); | |
92 | | |
93 | } | |
94 | | |
95 | /** | |
96 | * initializes the channel and mapped bytebuffer | |
97 | * @param channel FileChannel | |
98 | * @param mapMode FileChannel.MapMode | |
99 | * @throws IOException | |
100 | */ | |
101 | private void init(FileChannel channel, FileChannel.MapMode mapMode) | |
102 | throws IOException { | |
103 | | |
104 | this.channel = channel; | |
105 | this.mappedByteBuffer = channel.map(mapMode, 0L, channel.size()); | |
106 | mappedByteBuffer.load(); | |
107 | } | |
108 | ||
109 | /** | |
110 | * @since 2.0.8 | |
111 | */ | |
112 | public FileChannel getChannel() { | |
113 | return channel; | |
114 | } | |
115 | | |
116 | /** | |
117 | * @see java.io.RandomAccessFile#read() | |
118 | * @return int next integer or -1 on EOF | |
119 | */ | |
120 | public int read() { | |
121 | try { | |
122 | byte b = mappedByteBuffer.get(); | |
123 |
1
1. read : Replaced bitwise AND with OR → NO_COVERAGE |
int n = b & 0xff; |
124 | | |
125 |
1
1. read : replaced return of integer sized value with (x == 0 ? 1 : 0) → NO_COVERAGE |
return n; |
126 | } catch (BufferUnderflowException e) { | |
127 |
1
1. read : replaced return of integer sized value with (x == 0 ? 1 : 0) → NO_COVERAGE |
return -1; // EOF |
128 | } | |
129 | } | |
130 | | |
131 | /** | |
132 | * @see java.io.RandomAccessFile#read(byte[], int, int) | |
133 | * @param bytes byte[] | |
134 | * @param off int offset | |
135 | * @param len int length | |
136 | * @return int bytes read or -1 on EOF | |
137 | */ | |
138 | public int read(byte[] bytes, int off, int len) { | |
139 | int pos = mappedByteBuffer.position(); | |
140 | int limit = mappedByteBuffer.limit(); | |
141 |
1
1. read : negated conditional → NO_COVERAGE |
if (pos == limit) |
142 |
1
1. read : replaced return of integer sized value with (x == 0 ? 1 : 0) → NO_COVERAGE |
return -1; // EOF |
143 |
2
1. read : Replaced integer addition with subtraction → NO_COVERAGE 2. read : Replaced integer subtraction with addition → NO_COVERAGE |
int newlimit = pos + len - off; |
144 |
2
1. read : changed conditional boundary → NO_COVERAGE 2. read : negated conditional → NO_COVERAGE |
if (newlimit > limit) { |
145 |
1
1. read : Replaced integer subtraction with addition → NO_COVERAGE |
len = limit - pos; // don't read beyond EOF |
146 | } | |
147 | mappedByteBuffer.get(bytes, off, len); | |
148 |
1
1. read : replaced return of integer sized value with (x == 0 ? 1 : 0) → NO_COVERAGE |
return len; |
149 | } | |
150 | | |
151 | /** | |
152 | * @see java.io.RandomAccessFile#getFilePointer() | |
153 | * @return long | |
154 | */ | |
155 | public long getFilePointer() { | |
156 |
1
1. getFilePointer : replaced return of long value with value + 1 for com/lowagie/text/pdf/MappedRandomAccessFile::getFilePointer → NO_COVERAGE |
return mappedByteBuffer.position(); |
157 | } | |
158 | | |
159 | /** | |
160 | * @see java.io.RandomAccessFile#seek(long) | |
161 | * @param pos long position | |
162 | */ | |
163 | public void seek(long pos) { | |
164 | mappedByteBuffer.position((int) pos); | |
165 | } | |
166 | | |
167 | /** | |
168 | * @see java.io.RandomAccessFile#length() | |
169 | * @return long length | |
170 | */ | |
171 | public long length() { | |
172 |
1
1. length : replaced return of long value with value + 1 for com/lowagie/text/pdf/MappedRandomAccessFile::length → NO_COVERAGE |
return mappedByteBuffer.limit(); |
173 | } | |
174 | | |
175 | /** | |
176 | * @see java.io.RandomAccessFile#close() | |
177 | * Cleans the mapped bytebuffer and closes the channel | |
178 | */ | |
179 | public void close() throws IOException { | |
180 | clean(mappedByteBuffer); | |
181 | mappedByteBuffer = null; | |
182 |
1
1. close : negated conditional → NO_COVERAGE |
if (channel != null) |
183 |
1
1. close : removed call to java/nio/channels/FileChannel::close → NO_COVERAGE |
channel.close(); |
184 | channel = null; | |
185 | } | |
186 | | |
187 | /** | |
188 | * invokes the close method | |
189 | * @see java.lang.Object#finalize() | |
190 | */ | |
191 | protected void finalize() throws Throwable { | |
192 |
1
1. finalize : removed call to com/lowagie/text/pdf/MappedRandomAccessFile::close → NO_COVERAGE |
close(); |
193 |
1
1. finalize : removed call to java/lang/Object::finalize → NO_COVERAGE |
super.finalize(); |
194 | } | |
195 | | |
196 | /** | |
197 | * invokes the clean method on the ByteBuffer's cleaner | |
198 | * @param buffer ByteBuffer | |
199 | * @return boolean true on success | |
200 | */ | |
201 | public static boolean clean(final java.nio.ByteBuffer buffer) { | |
202 |
2
1. clean : negated conditional → NO_COVERAGE 2. clean : negated conditional → NO_COVERAGE |
if (buffer == null || !buffer.isDirect()) { |
203 |
1
1. clean : replaced return of integer sized value with (x == 0 ? 1 : 0) → NO_COVERAGE |
return false; |
204 | } | |
205 |
1
1. clean : negated conditional → NO_COVERAGE |
if (cleanJava9(buffer)) { |
206 |
1
1. clean : replaced return of integer sized value with (x == 0 ? 1 : 0) → NO_COVERAGE |
return true; |
207 | } | |
208 |
1
1. clean : replaced return of integer sized value with (x == 0 ? 1 : 0) → NO_COVERAGE |
return cleanOldsJDK(buffer); |
209 | } | |
210 | | |
211 | private static boolean cleanJava9(final java.nio.ByteBuffer buffer) { | |
212 | Boolean b = AccessController.doPrivileged((PrivilegedAction<Boolean>) () -> { | |
213 | Boolean success = Boolean.FALSE; | |
214 | try { | |
215 | final Class<?> unsafeClass = Class.forName("sun.misc.Unsafe"); | |
216 | final Field theUnsafeField = unsafeClass.getDeclaredField("theUnsafe"); | |
217 | theUnsafeField.setAccessible(true); | |
218 | final Object theUnsafe = theUnsafeField.get(null); | |
219 | final Method invokeCleanerMethod = unsafeClass.getMethod("invokeCleaner", ByteBuffer.class); | |
220 | invokeCleanerMethod.invoke(theUnsafe, buffer); | |
221 | success = Boolean.TRUE; | |
222 | } catch (Exception ignore) { | |
223 | // Ignore | |
224 | } | |
225 | return success; | |
226 | }); | |
227 | | |
228 |
1
1. cleanJava9 : replaced return of integer sized value with (x == 0 ? 1 : 0) → NO_COVERAGE |
return b; |
229 | } | |
230 | ||
231 | private static boolean cleanOldsJDK(final java.nio.ByteBuffer buffer) { | |
232 | Boolean b = AccessController.doPrivileged((PrivilegedAction<Boolean>) () -> { | |
233 | Boolean success = Boolean.FALSE; | |
234 | try { | |
235 | Method getCleanerMethod = buffer.getClass().getMethod("cleaner", (Class[])null); | |
236 | if (!getCleanerMethod.isAccessible()) { | |
237 | getCleanerMethod.setAccessible(true); | |
238 | } | |
239 | Object cleaner = getCleanerMethod.invoke(buffer, (Object[])null); | |
240 | Method clean = cleaner.getClass().getMethod("clean", (Class[])null); | |
241 | clean.invoke(cleaner, (Object[])null); | |
242 | success = Boolean.TRUE; | |
243 | } catch (Exception e) { | |
244 | // Ignore | |
245 | } | |
246 | return success; | |
247 | }); | |
248 | | |
249 |
1
1. cleanOldsJDK : replaced return of integer sized value with (x == 0 ? 1 : 0) → NO_COVERAGE |
return b; |
250 | } | |
251 | | |
252 | } | |
Mutations | ||
84 |
1.1 |
|
85 |
1.1 |
|
89 |
1.1 |
|
123 |
1.1 |
|
125 |
1.1 |
|
127 |
1.1 |
|
141 |
1.1 |
|
142 |
1.1 |
|
143 |
1.1 2.2 |
|
144 |
1.1 2.2 |
|
145 |
1.1 |
|
148 |
1.1 |
|
156 |
1.1 |
|
172 |
1.1 |
|
182 |
1.1 |
|
183 |
1.1 |
|
192 |
1.1 |
|
193 |
1.1 |
|
202 |
1.1 2.2 |
|
203 |
1.1 |
|
205 |
1.1 |
|
206 |
1.1 |
|
208 |
1.1 |
|
228 |
1.1 |
|
249 |
1.1 |