001/* 002 * $Id: MappedRandomAccessFile.java 4784 2011-03-15 08:33:00Z blowagie $ 003 * 004 * This file is part of the iText (R) project. 005 * Copyright (c) 1998-2011 1T3XT BVBA 006 * Authors: Bruno Lowagie, Paulo Soares, et al. 007 * 008 * This program is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU Affero General Public License version 3 010 * as published by the Free Software Foundation with the addition of the 011 * following permission added to Section 15 as permitted in Section 7(a): 012 * FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY 1T3XT, 013 * 1T3XT DISCLAIMS THE WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. 014 * 015 * This program is distributed in the hope that it will be useful, but 016 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 017 * or FITNESS FOR A PARTICULAR PURPOSE. 018 * See the GNU Affero General Public License for more details. 019 * You should have received a copy of the GNU Affero General Public License 020 * along with this program; if not, see http://www.gnu.org/licenses or write to 021 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 022 * Boston, MA, 02110-1301 USA, or download the license from the following URL: 023 * http://itextpdf.com/terms-of-use/ 024 * 025 * The interactive user interfaces in modified source and object code versions 026 * of this program must display Appropriate Legal Notices, as required under 027 * Section 5 of the GNU Affero General Public License. 028 * 029 * In accordance with Section 7(b) of the GNU Affero General Public License, 030 * a covered work must retain the producer line in every PDF that is created 031 * or manipulated using iText. 032 * 033 * You can be released from the requirements of the license by purchasing 034 * a commercial license. Buying such a license is mandatory as soon as you 035 * develop commercial activities involving the iText software without 036 * disclosing the source code of your own applications. 037 * These activities include: offering paid services to customers as an ASP, 038 * serving PDFs on the fly in a web application, shipping iText with a closed 039 * source product. 040 * 041 * For more information, please contact iText Software Corp. at this 042 * address: sales@itextpdf.com 043 */ 044package com.itextpdf.text.pdf; 045 046import java.io.FileInputStream; 047import java.io.FileNotFoundException; 048import java.io.IOException; 049import java.lang.reflect.Method; 050import java.nio.BufferUnderflowException; 051import java.nio.MappedByteBuffer; 052import java.nio.channels.FileChannel; 053import java.security.AccessController; 054import java.security.PrivilegedAction; 055 056/** 057 * A {@link java.nio.MappedByteBuffer} wrapped as a {@link java.io.RandomAccessFile} 058 * 059 * @author Joakim Sandstroem 060 * Created on 6.9.2006 061 */ 062public class MappedRandomAccessFile { 063 064 private MappedByteBuffer mappedByteBuffer = null; 065 private FileChannel channel = null; 066 067 /** 068 * Constructs a new MappedRandomAccessFile instance 069 * @param filename String 070 * @param mode String r, w or rw 071 * @throws FileNotFoundException 072 * @throws IOException 073 */ 074 public MappedRandomAccessFile(String filename, String mode) 075 throws FileNotFoundException, IOException { 076 077 if (mode.equals("rw")) 078 init( 079 new java.io.RandomAccessFile(filename, mode).getChannel(), 080 FileChannel.MapMode.READ_WRITE); 081 else 082 init( 083 new FileInputStream(filename).getChannel(), 084 FileChannel.MapMode.READ_ONLY); 085 086 } 087 088 /** 089 * initializes the channel and mapped bytebuffer 090 * @param channel FileChannel 091 * @param mapMode FileChannel.MapMode 092 * @throws IOException 093 */ 094 private void init(FileChannel channel, FileChannel.MapMode mapMode) 095 throws IOException { 096 097 this.channel = channel; 098 this.mappedByteBuffer = channel.map(mapMode, 0L, channel.size()); 099 mappedByteBuffer.load(); 100 } 101 102 /** 103 * @since 2.0.8 104 */ 105 public FileChannel getChannel() { 106 return channel; 107 } 108 109 /** 110 * @see java.io.RandomAccessFile#read() 111 * @return int next integer or -1 on EOF 112 */ 113 public int read() { 114 try { 115 byte b = mappedByteBuffer.get(); 116 int n = b & 0xff; 117 118 return n; 119 } catch (BufferUnderflowException e) { 120 return -1; // EOF 121 } 122 } 123 124 /** 125 * @see java.io.RandomAccessFile#read(byte[], int, int) 126 * @param bytes byte[] 127 * @param off int offset 128 * @param len int length 129 * @return int bytes read or -1 on EOF 130 */ 131 public int read(byte bytes[], int off, int len) { 132 int pos = mappedByteBuffer.position(); 133 int limit = mappedByteBuffer.limit(); 134 if (pos == limit) 135 return -1; // EOF 136 int newlimit = pos + len - off; 137 if (newlimit > limit) { 138 len = limit - pos; // don't read beyond EOF 139 } 140 mappedByteBuffer.get(bytes, off, len); 141 return len; 142 } 143 144 /** 145 * @see java.io.RandomAccessFile#getFilePointer() 146 * @return long 147 */ 148 public long getFilePointer() { 149 return mappedByteBuffer.position(); 150 } 151 152 /** 153 * @see java.io.RandomAccessFile#seek(long) 154 * @param pos long position 155 */ 156 public void seek(long pos) { 157 mappedByteBuffer.position((int) pos); 158 } 159 160 /** 161 * @see java.io.RandomAccessFile#length() 162 * @return long length 163 */ 164 public long length() { 165 return mappedByteBuffer.limit(); 166 } 167 168 /** 169 * @see java.io.RandomAccessFile#close() 170 * Cleans the mapped bytebuffer and closes the channel 171 */ 172 public void close() throws IOException { 173 clean(mappedByteBuffer); 174 mappedByteBuffer = null; 175 if (channel != null) 176 channel.close(); 177 channel = null; 178 } 179 180 /** 181 * invokes the close method 182 * @see java.lang.Object#finalize() 183 */ 184 @Override 185 protected void finalize() throws Throwable { 186 close(); 187 super.finalize(); 188 } 189 190 /** 191 * invokes the clean method on the ByteBuffer's cleaner 192 * @param buffer ByteBuffer 193 * @return boolean true on success 194 */ 195 public static boolean clean(final java.nio.ByteBuffer buffer) { 196 if (buffer == null || !buffer.isDirect()) 197 return false; 198 199 Boolean b = (Boolean) AccessController.doPrivileged(new PrivilegedAction<Boolean>() { 200 public Boolean run() { 201 Boolean success = Boolean.FALSE; 202 try { 203 Method getCleanerMethod = buffer.getClass().getMethod("cleaner", (Class<?>[])null); 204 getCleanerMethod.setAccessible(true); 205 Object cleaner = getCleanerMethod.invoke(buffer, (Object[])null); 206 Method clean = cleaner.getClass().getMethod("clean", (Class<?>[])null); 207 clean.invoke(cleaner, (Object[])null); 208 success = Boolean.TRUE; 209 } catch (Exception e) { 210 // This really is a show stopper on windows 211 //e.printStackTrace(); 212 } 213 return success; 214 } 215 }); 216 217 return b.booleanValue(); 218 } 219 220}