001 /*
002 * Copyright (c) Andrey Kuznetsov. All Rights Reserved.
003 *
004 * http://uio.imagero.com
005 *
006 * Redistribution and use in source and binary forms, with or without
007 * modification, are permitted provided that the following conditions are met:
008 *
009 * o Redistributions of source code must retain the above copyright notice,
010 * this list of conditions and the following disclaimer.
011 *
012 * o Redistributions in binary form must reproduce the above copyright notice,
013 * this list of conditions and the following disclaimer in the documentation
014 * and/or other materials provided with the distribution.
015 *
016 * o Neither the name of Andrey Kuznetsov nor the names of
017 * its contributors may be used to endorse or promote products derived
018 * from this software without specific prior written permission.
019 *
020 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
021 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
022 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
023 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
024 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
025 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
026 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
027 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
028 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
029 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
030 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
031 */
032
033 package com.imagero.uio.impl.array;
034
035 import com.imagero.uio.bio.BufferPosition;
036 import com.imagero.uio.bio.IOController;
037 import com.imagero.uio.bio.IOCInputStream;
038 import com.imagero.uio.bio.IOCOutputStream;
039 import com.imagero.uio.impl.AbstractRandomAccessIO;
040
041 import java.io.EOFException;
042 import java.io.IOException;
043 import java.io.InputStream;
044 import java.io.OutputStream;
045
046 /**
047 * @author Andrey Kuznetsov
048 */
049 public abstract class AbstractRandomAccessArray extends AbstractRandomAccessIO {
050
051 BufferPosition fp;
052 IOController controller;
053
054 int length;
055 int offset;
056
057 protected int[] BE_SHIFTS;
058 protected int[] LE_SHIFTS;
059 protected int[] shifts;
060
061 final int bytesPerUnit = getBytesPerUnit();
062 final int andMask = getAndMask();
063
064
065 public AbstractRandomAccessArray(int offset, int length, int byteOrder) {
066 this(offset, length, byteOrder, new BufferPosition(Integer.MAX_VALUE));
067 }
068
069 public AbstractRandomAccessArray(int offset, int length, int byteOrder, BufferPosition fp) {
070 this.offset = offset;
071 this.fp = fp != null ? fp : new BufferPosition(Integer.MAX_VALUE);
072 BE_SHIFTS = createShiftBE();
073 LE_SHIFTS = createShiftLE();
074 setByteOrder(byteOrder);
075 this.length = length * bytesPerUnit;
076 }
077
078 public void setByteOrder(int byteOrder) {
079 super.setByteOrder(byteOrder);
080 if (byteOrder == BIG_ENDIAN) {
081 shifts = BE_SHIFTS;
082 } else if (byteOrder == LITTLE_ENDIAN) {
083 shifts = LE_SHIFTS;
084 }
085 }
086
087 protected abstract int[] createShiftBE();
088
089 protected abstract int[] createShiftLE();
090
091 protected abstract int getBytesPerUnit();
092
093 protected abstract int getAndMask();
094
095 public long getFilePointer() {
096 return fp.pos - offset;
097 }
098
099 public long length() {
100 return length - offset;
101 }
102
103 public void seek(long offset) throws IOException {
104 if (offset + this.offset > Integer.MAX_VALUE) {
105 throw new IOException("Can't seek so far");
106 }
107 fp.pos = (int) offset + this.offset;
108 }
109
110 public long skip(long n) throws IOException {
111 long k = Math.min(fp.pos + n, length);//todo check conditions
112 fp.pos += k;
113 return k;
114 }
115
116 public void close() throws IOException {
117 }
118
119 public int read(byte[] b, int off, int len) throws IOException {
120 final int max = (int) Math.min(len, length() - fp.pos);//todo check conditions
121 if (max <= 0) {
122 return -1;
123 }
124 len = max;
125 while ((fp.pos & andMask) != 0) {
126 b[off++] = (byte) read();
127 len--;
128 }
129 int count = len / bytesPerUnit;
130 if (byteOrder == BIG_ENDIAN) {
131 readBE(/*offset + */fp.pos / bytesPerUnit, count, b, offset);
132 } else {
133 readLE(/*offset + */fp.pos / bytesPerUnit, count, b, offset);
134 }
135 int read = count * bytesPerUnit;
136 fp.pos += read;
137 off += read;
138 len -= read;
139 while (len-- > 0) {
140 b[off++] = (byte) read();
141 }
142 return max;
143 }
144
145 protected abstract void readBE(int srcOffset, int count, byte[] dest, int off);
146
147 protected abstract void readLE(int srcOffset, int count, byte[] dest, int off);
148
149
150 public void setLength(long newLength) throws IOException {
151 }
152
153 public void write(byte b[], int off, int len) throws IOException {
154 len = (int) Math.min(len, length() - fp.pos);//todo check conditions
155 if (len <= 0) {
156 throw new EOFException();
157 }
158 if ((fp.pos & andMask) != 0) {
159 write(b[off++]);
160 len--;
161 }
162 int l2 = len / bytesPerUnit;
163 write(b, off, len, fp.pos / bytesPerUnit, byteOrder == BIG_ENDIAN);
164 fp.pos += l2 * bytesPerUnit;
165 if ((len & andMask) != 0) {
166 write(b[off + len - 1]);
167 }
168 }
169
170 protected abstract void write(byte[] src, int srcOffset, int len, int destOffset, boolean bigEndian);
171
172 protected final long combine(long v, int b) {
173 int shift = shifts[(fp.pos & andMask)];
174 return (v & (0xFF << shift)) | ((b & 0xFF) << shift);
175 }
176
177 protected final int combine(int v, int b) {
178 int shift = shifts[(fp.pos & andMask)];
179 return (v & (0xFF << shift)) | ((b & 0xFF) << shift);
180 }
181
182 protected final int _read() throws IOException {
183 int k = read();
184 if (k == -1) {
185 throw new EOFException();
186 }
187 return k;
188 }
189
190 protected abstract IOController createController();
191
192 public IOController getController() {
193 if(controller == null) {
194 controller = createController();
195 }
196 return controller;
197 }
198
199 public InputStream createInputStream(long offset) {
200 return new IOCInputStream(getController(), offset);
201 }
202
203 public OutputStream createOutputStream(long offset) {
204 return new IOCOutputStream(getController(), offset);
205 }
206 }