001: /* Copyright (c) 2001-2005, The HSQL Development Group
002: * All rights reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, are permitted provided that the following conditions are met:
006: *
007: * Redistributions of source code must retain the above copyright notice, this
008: * list of conditions and the following disclaimer.
009: *
010: * Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: *
014: * Neither the name of the HSQL Development Group nor the names of its
015: * contributors may be used to endorse or promote products derived from this
016: * software without specific prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
021: * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
022: * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
023: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
024: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
025: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
026: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
027: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
028: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029: */
030:
031: package org.hsqldb.persist;
032:
033: import java.io.DataInputStream;
034: import java.io.FileNotFoundException;
035: import java.io.IOException;
036: import java.io.InputStream;
037:
038: import org.hsqldb.Database;
039: import org.hsqldb.lib.HsqlByteArrayInputStream;
040:
041: /**
042: * This class is a random access wrapper around a DataInputStream object and
043: * enables access to cached tables when a database is included in a jar.
044: *
045: * A proof-of-concept prototype was first contributed by winfriedthom@users.
046: *
047: * @author fredt@users
048: * @version 1.8.0
049: * @since 1.8.0
050: */
051: class ScaledRAFileInJar implements ScaledRAInterface {
052:
053: DataInputStream file;
054: final String fileName;
055: long fileLength;
056: boolean bufferDirty = true;
057: byte[] buffer = new byte[4096];
058: HsqlByteArrayInputStream ba = new HsqlByteArrayInputStream(buffer);
059: long bufferOffset;
060:
061: //
062: long seekPosition;
063: long realPosition;
064:
065: ScaledRAFileInJar(String name) throws FileNotFoundException,
066: IOException {
067:
068: fileName = name;
069:
070: resetStream();
071: file.skip(DataFileCache.LONG_FREE_POS_POS);
072:
073: fileLength = file.readLong();
074:
075: resetStream();
076: }
077:
078: public long length() throws IOException {
079: return fileLength;
080: }
081:
082: /**
083: * Some JVM's do not allow seek beyond end of file, so zeros are written
084: * first in that case. Reported by bohgammer@users in Open Disucssion
085: * Forum.
086: */
087: public void seek(long position) throws IOException {
088: seekPosition = position;
089: }
090:
091: public long getFilePointer() throws IOException {
092: return seekPosition;
093: }
094:
095: private void readIntoBuffer() throws IOException {
096:
097: long filePos = seekPosition;
098:
099: bufferDirty = false;
100:
101: long subOffset = filePos % buffer.length;
102: long readLength = fileLength - (filePos - subOffset);
103:
104: if (readLength <= 0) {
105: throw new IOException("read beyond end of file");
106: }
107:
108: if (readLength > buffer.length) {
109: readLength = buffer.length;
110: }
111:
112: fileSeek(filePos - subOffset);
113: file.readFully(buffer, 0, (int) readLength);
114:
115: bufferOffset = filePos - subOffset;
116: realPosition = bufferOffset + readLength;
117: }
118:
119: public int read() throws IOException {
120:
121: if (seekPosition >= fileLength) {
122: return -1;
123: }
124:
125: if (bufferDirty || seekPosition < bufferOffset
126: || seekPosition >= bufferOffset + buffer.length) {
127: readIntoBuffer();
128: }
129:
130: ba.reset();
131: ba.skip(seekPosition - bufferOffset);
132:
133: int val = ba.read();
134:
135: seekPosition++;
136:
137: return val;
138: }
139:
140: public long readLong() throws IOException {
141:
142: long hi = readInt();
143: long lo = readInt();
144:
145: return (hi << 32) + (lo & 0xffffffffL);
146: }
147:
148: public int readInt() throws IOException {
149:
150: if (bufferDirty || seekPosition < bufferOffset
151: || seekPosition >= bufferOffset + buffer.length) {
152: readIntoBuffer();
153: }
154:
155: ba.reset();
156: ba.skip(seekPosition - bufferOffset);
157:
158: int val = ba.readInt();
159:
160: seekPosition += 4;
161:
162: return val;
163: }
164:
165: public void read(byte[] b, int offset, int length)
166: throws IOException {
167:
168: if (bufferDirty || seekPosition < bufferOffset
169: || seekPosition >= bufferOffset + buffer.length) {
170: readIntoBuffer();
171: }
172:
173: ba.reset();
174: ba.skip(seekPosition - bufferOffset);
175:
176: int bytesRead = ba.read(b, offset, length);
177:
178: seekPosition += bytesRead;
179:
180: if (bytesRead < length) {
181: if (seekPosition != realPosition) {
182: fileSeek(seekPosition);
183: }
184:
185: file.readFully(b, offset + bytesRead, length - bytesRead);
186:
187: seekPosition += (length - bytesRead);
188: realPosition = seekPosition;
189: }
190: }
191:
192: public void write(byte[] b, int off, int len) throws IOException {
193: }
194:
195: public void writeInt(int i) throws IOException {
196: }
197:
198: public void writeLong(long i) throws IOException {
199: }
200:
201: public void close() throws IOException {
202: file.close();
203: }
204:
205: public boolean isReadOnly() {
206: return true;
207: }
208:
209: public boolean wasNio() {
210: return false;
211: }
212:
213: private void resetStream() throws IOException {
214:
215: if (file != null) {
216: file.close();
217: }
218:
219: InputStream fis = getClass().getResourceAsStream(fileName);
220:
221: file = new DataInputStream(fis);
222: }
223:
224: private void fileSeek(long position) throws IOException {
225:
226: long skipPosition = realPosition;
227:
228: if (position < skipPosition) {
229: resetStream();
230:
231: skipPosition = 0;
232: }
233:
234: while (position > skipPosition) {
235: skipPosition += file.skip(position - skipPosition);
236: }
237: }
238:
239: public boolean canAccess(int length) {
240: return false;
241: }
242:
243: public boolean canSeek(long position) {
244: return false;
245: }
246:
247: public Database getDatabase() {
248: return null;
249: }
250: }
|