1 /* 2 * Copyright 2010 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy of 6 * the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations under 14 * the License. 15 */ 16 17 package java.io; 18 19 import com.google.gwt.storage.client.Storage; 20 21 /** Saves binary data to the local storage; currently using hex encoding. The string is prefixed with "hex:" 22 * @author haustein */ 23 public class RandomAccessFile /* implements DataOutput, DataInput, Closeable */{ 24 25 /* 26 * public final FileDescriptor getFD() throws IOException { } public final FileChannel getChannel() { } 27 */ 28 final String name; 29 final boolean writeable; 30 boolean dirty; 31 String data; 32 int newDataPos; 33 StringBuilder newData; 34 int pos; 35 int len; 36 37 DataInputStream dis = new DataInputStream(new RafInputStream()); 38 DataOutputStream dos = new DataOutputStream(new RafOutputStream()); 39 RandomAccessFile(String name, String mode)40 public RandomAccessFile (String name, String mode) throws FileNotFoundException { 41 this(new File(name), mode); 42 } 43 RandomAccessFile(File file, String mode)44 public RandomAccessFile (File file, String mode) throws FileNotFoundException { 45 name = file.getCanonicalPath(); 46 47 mode = mode.toLowerCase(); 48 if (!mode.equals("r") && !mode.equals("rw")) { 49 throw new IllegalArgumentException("mode: '" + mode + "'"); 50 } 51 writeable = mode.equals("rw"); 52 if (file.exists()) { 53 data = atob(File.LocalStorage.getItem(name)); 54 len = data.length(); 55 } else if (writeable) { 56 data = ""; 57 dirty = true; 58 try { 59 flush(); 60 } catch (IOException e) { 61 throw new FileNotFoundException("" + e); 62 } 63 } else { 64 throw new FileNotFoundException(name); 65 } 66 } 67 btoa(String s)68 static native String btoa (String s) /*-{ 69 return $wnd.btoa(s); 70 }-*/; 71 atob(String s)72 static native String atob (String s) /*-{ 73 return $wnd.atob(s); 74 }-*/; 75 read()76 public int read () throws IOException { 77 return dis.read(); 78 } 79 read(byte b[], int off, int len)80 public int read (byte b[], int off, int len) throws IOException { 81 return dis.read(b, off, len); 82 } 83 read(byte b[])84 public int read (byte b[]) throws IOException { 85 return dis.read(b); 86 } 87 readFully(byte b[])88 public final void readFully (byte b[]) throws IOException { 89 dis.readFully(b); 90 } 91 readFully(byte b[], int off, int len)92 public final void readFully (byte b[], int off, int len) throws IOException { 93 dis.readFully(b, off, len); 94 } 95 skipBytes(int n)96 public int skipBytes (int n) throws IOException { 97 return dis.skipBytes(n); 98 } 99 write(int b)100 public void write (int b) throws IOException { 101 dos.write(b); 102 }; 103 write(byte b[])104 public void write (byte b[]) throws IOException { 105 dos.write(b); 106 } 107 write(byte b[], int off, int len)108 public void write (byte b[], int off, int len) throws IOException { 109 dos.write(b, off, len); 110 } 111 getFilePointer()112 public long getFilePointer () throws IOException { 113 return pos; 114 } 115 seek(long pos)116 public void seek (long pos) throws IOException { 117 if (pos < 0) { 118 throw new IllegalArgumentException(); 119 } 120 this.pos = (int)pos; 121 } 122 length()123 public long length () throws IOException { 124 return len; 125 } 126 setLength(long newLength)127 public void setLength (long newLength) throws IOException { 128 if (len != newLength) { 129 consolidate(); 130 if (data.length() > newLength) { 131 data = data.substring(0, (int)newLength); 132 len = (int)newLength; 133 } else { 134 // System.out.println("padding " + (newLength - len) + " zeros in setLength to " + newLength); 135 while (len < newLength) { 136 write(0); 137 } 138 } 139 } 140 } 141 close()142 public void close () throws IOException { 143 if (data != null) { 144 flush(); 145 data = null; 146 } 147 } 148 consolidate()149 void consolidate () { 150 if (newData == null) { 151 return; 152 } 153 154 // System.out.println("consolidate(); ndp: " + newDataPos + " nd-len: " + newData.length()); 155 156 if (data.length() < newDataPos) { 157 StringBuilder filler = new StringBuilder(); 158 while (data.length() + filler.length() < newDataPos) { 159 filler.append('\0'); 160 } 161 // System.out.println("padding " + (filler.length()) + " zeros in consolidate "); 162 163 data += filler.toString(); 164 } 165 166 int p2 = newDataPos + newData.length(); 167 data = data.substring(0, newDataPos) + newData.toString() + (p2 < data.length() ? data.substring(p2) : ""); 168 newData = null; 169 } 170 flush()171 void flush () throws IOException { 172 if (!dirty) { 173 return; 174 } 175 consolidate(); 176 File.LocalStorage.setItem(name, btoa(data)); 177 dirty = false; 178 } 179 readBoolean()180 public final boolean readBoolean () throws IOException { 181 return dis.readBoolean(); 182 } 183 readByte()184 public final byte readByte () throws IOException { 185 return dis.readByte(); 186 } 187 readUnsignedByte()188 public final int readUnsignedByte () throws IOException { 189 return dis.readUnsignedByte(); 190 } 191 readShort()192 public final short readShort () throws IOException { 193 return dis.readShort(); 194 } 195 readUnsignedShort()196 public final int readUnsignedShort () throws IOException { 197 return dis.readUnsignedShort(); 198 } 199 readChar()200 public final char readChar () throws IOException { 201 return dis.readChar(); 202 } 203 readInt()204 public final int readInt () throws IOException { 205 return dis.readInt(); 206 } 207 readLong()208 public final long readLong () throws IOException { 209 return dis.readLong(); 210 } 211 readFloat()212 public final float readFloat () throws IOException { 213 return dis.readFloat(); 214 } 215 readDouble()216 public final double readDouble () throws IOException { 217 return dis.readDouble(); 218 } 219 readLine()220 public final String readLine () throws IOException { 221 return dis.readLine(); 222 } 223 readUTF()224 public final String readUTF () throws IOException { 225 return dis.readUTF(); 226 } 227 writeBoolean(boolean v)228 public final void writeBoolean (boolean v) throws IOException { 229 dos.writeBoolean(v); 230 } 231 writeByte(int v)232 public final void writeByte (int v) throws IOException { 233 dos.writeByte(v); 234 } 235 writeShort(int v)236 public final void writeShort (int v) throws IOException { 237 dos.writeShort(v); 238 } 239 writeChar(int v)240 public final void writeChar (int v) throws IOException { 241 dos.writeChar(v); 242 } 243 writeInt(int v)244 public final void writeInt (int v) throws IOException { 245 dos.writeInt(v); 246 } 247 writeLong(long v)248 public final void writeLong (long v) throws IOException { 249 dos.writeLong(v); 250 } 251 writeFloat(float v)252 public final void writeFloat (float v) throws IOException { 253 dos.writeFloat(v); 254 } 255 writeDouble(double v)256 public final void writeDouble (double v) throws IOException { 257 dos.writeDouble(v); 258 } 259 writeBytes(String s)260 public final void writeBytes (String s) throws IOException { 261 dos.writeBytes(s); 262 } 263 writeChars(String s)264 public final void writeChars (String s) throws IOException { 265 dos.writeChars(s); 266 } 267 writeUTF(String str)268 public final void writeUTF (String str) throws IOException { 269 dos.writeUTF(str); 270 } 271 272 // public final FileChannel getChannel() throws IOException { } 273 274 class RafInputStream extends InputStream { 275 @Override read()276 public int read () throws IOException { 277 if (pos >= len) { 278 return -1; 279 } else { 280 consolidate(); 281 return data.charAt(pos++); 282 // int p2 = (pos << 1); 283 // int result = Character.digit(data.charAt(p2), 16) * 16 + 284 // Character.digit(data.charAt(p2 + 1), 16); 285 // pos++; 286 // return result; 287 } 288 } 289 } 290 291 class RafOutputStream extends OutputStream { 292 write(int b)293 public void write (int b) throws IOException { 294 if (!writeable) { 295 throw new IOException("not writeable"); 296 } 297 298 if (newData == null) { 299 newDataPos = pos; 300 newData = new StringBuilder(); 301 // System.out.println("no buf; newDataPos: " + pos); 302 } else if (newDataPos + newData.length() != pos) { 303 consolidate(); 304 newDataPos = pos; 305 newData = new StringBuilder(); 306 // System.out.println("pos mismatch; newDataPos: " + pos); 307 } 308 309 newData.append((char)(b & 255)); 310 // newData.append("" + Character.forDigit((b >> 4) & 15, 16) + 311 // Character.forDigit(b & 15, 16)); 312 pos++; 313 len = Math.max(pos, len); 314 dirty = true; 315 } 316 } 317 } 318