1 package SQLite; 2 3 import java.io.*; 4 5 /** 6 * Internal class implementing java.io.InputStream on 7 * SQLite 3.4.0 incremental blob I/O interface. 8 */ 9 10 class BlobR extends InputStream { 11 12 /** 13 * Blob instance 14 */ 15 16 private Blob blob; 17 18 /** 19 * Read position, file pointer. 20 */ 21 22 private int pos; 23 24 /** 25 * Contruct InputStream from blob instance. 26 */ 27 28 BlobR(Blob blob) { 29 this.blob = blob; 30 this.pos = 0; 31 } 32 33 /** 34 * Return number of available bytes for reading. 35 * @return available input bytes 36 */ 37 38 public int available() throws IOException { 39 int ret = blob.size - pos; 40 return (ret < 0) ? 0 : ret; 41 } 42 43 /** 44 * Mark method; dummy to satisfy InputStream class. 45 */ 46 47 public void mark(int limit) { 48 } 49 50 /** 51 * Reset method; dummy to satisfy InputStream class. 52 */ 53 54 public void reset() throws IOException { 55 } 56 57 /** 58 * Mark support; not for this class. 59 * @return always false 60 */ 61 62 public boolean markSupported() { 63 return false; 64 } 65 66 /** 67 * Close this blob InputStream. 68 */ 69 70 public void close() throws IOException { 71 blob.close(); 72 blob = null; 73 pos = 0; 74 } 75 76 /** 77 * Skip over blob data. 78 */ 79 80 public long skip(long n) throws IOException { 81 long ret = pos + n; 82 if (ret < 0) { 83 ret = 0; 84 pos = 0; 85 } else if (ret > blob.size) { 86 ret = blob.size; 87 pos = blob.size; 88 } else { 89 pos = (int) ret; 90 } 91 return ret; 92 } 93 94 /** 95 * Read single byte from blob. 96 * @return byte read 97 */ 98 99 public int read() throws IOException { 100 byte b[] = new byte[1]; 101 int n = blob.read(b, 0, pos, b.length); 102 if (n > 0) { 103 pos += n; 104 return b[0]; 105 } 106 return -1; 107 } 108 109 /** 110 * Read byte array from blob. 111 * @param b byte array to be filled 112 * @return number of bytes read 113 */ 114 115 public int read(byte b[]) throws IOException { 116 int n = blob.read(b, 0, pos, b.length); 117 if (n > 0) { 118 pos += n; 119 return n; 120 } 121 return -1; 122 } 123 124 /** 125 * Read slice of byte array from blob. 126 * @param b byte array to be filled 127 * @param off offset into byte array 128 * @param len length to be read 129 * @return number of bytes read 130 */ 131 132 public int read(byte b[], int off, int len) throws IOException { 133 if (off + len > b.length) { 134 len = b.length - off; 135 } 136 if (len < 0) { 137 return -1; 138 } 139 if (len == 0) { 140 return 0; 141 } 142 int n = blob.read(b, off, pos, len); 143 if (n > 0) { 144 pos += n; 145 return n; 146 } 147 return -1; 148 } 149 } 150 151 /** 152 * Internal class implementing java.io.OutputStream on 153 * SQLite 3.4.0 incremental blob I/O interface. 154 */ 155 156 class BlobW extends OutputStream { 157 158 /** 159 * Blob instance 160 */ 161 162 private Blob blob; 163 164 /** 165 * Read position, file pointer. 166 */ 167 168 private int pos; 169 170 /** 171 * Contruct OutputStream from blob instance. 172 */ 173 174 BlobW(Blob blob) { 175 this.blob = blob; 176 this.pos = 0; 177 } 178 179 /** 180 * Flush blob; dummy to satisfy OutputStream class. 181 */ 182 183 public void flush() throws IOException { 184 } 185 186 /** 187 * Close this blob OutputStream. 188 */ 189 190 public void close() throws IOException { 191 blob.close(); 192 blob = null; 193 pos = 0; 194 } 195 196 /** 197 * Write blob data. 198 * @param v byte to be written at current position. 199 */ 200 201 public void write(int v) throws IOException { 202 byte b[] = new byte[1]; 203 b[0] = (byte) v; 204 pos += blob.write(b, 0, pos, 1); 205 } 206 207 /** 208 * Write blob data. 209 * @param b byte array to be written at current position. 210 */ 211 212 public void write(byte[] b) throws IOException { 213 if (b != null && b.length > 0) { 214 pos += blob.write(b, 0, pos, b.length); 215 } 216 } 217 218 /** 219 * Write blob data. 220 * @param b byte array to be written. 221 * @param off offset within byte array 222 * @param len length of data to be written 223 */ 224 225 public void write(byte[] b, int off, int len) throws IOException { 226 if (b != null) { 227 if (off + len > b.length) { 228 len = b.length - off; 229 } 230 if (len <= 0) { 231 return; 232 } 233 pos += blob.write(b, off, pos, len); 234 } 235 } 236 } 237 238 /** 239 * Class to represent SQLite3 3.4.0 incremental blob I/O interface. 240 * 241 * Note, that all native methods of this class are 242 * not synchronized, i.e. it is up to the caller 243 * to ensure that only one thread is in these 244 * methods at any one time. 245 */ 246 247 public class Blob { 248 249 /** 250 * Internal handle for the SQLite3 blob. 251 */ 252 253 private long handle = 0; 254 255 /** 256 * Cached size of blob, setup right after blob 257 * has been opened. 258 */ 259 260 protected int size = 0; 261 262 /** 263 * Return InputStream for this blob 264 * @return InputStream 265 */ 266 267 public InputStream getInputStream() { 268 return (InputStream) new BlobR(this); 269 } 270 271 /** 272 * Return OutputStream for this blob 273 * @return OutputStream 274 */ 275 276 public OutputStream getOutputStream() { 277 return (OutputStream) new BlobW(this); 278 } 279 280 /** 281 * Close blob. 282 */ 283 284 public native void close(); 285 286 /** 287 * Internal blob write method. 288 * @param b byte array to be written 289 * @param off offset into byte array 290 * @param pos offset into blob 291 * @param len length to be written 292 * @return number of bytes written to blob 293 */ 294 295 native int write(byte[] b, int off, int pos, int len) throws IOException; 296 297 /** 298 * Internal blob read method. 299 * @param b byte array to be written 300 * @param off offset into byte array 301 * @param pos offset into blob 302 * @param len length to be written 303 * @return number of bytes written to blob 304 */ 305 306 native int read(byte[] b, int off, int pos, int len) throws IOException; 307 308 /** 309 * Destructor for object. 310 */ 311 312 protected native void finalize(); 313 314 /** 315 * Internal native initializer. 316 */ 317 318 private static native void internal_init(); 319 320 static { 321 internal_init(); 322 } 323 } 324