1 19 20 package org.netbeans.editor.ext; 21 22 import java.io.File ; 23 import java.io.IOException ; 24 import java.io.RandomAccessFile ; 25 import org.netbeans.editor.Analyzer; 26 27 33 34 public class FileStorage { 35 36 40 private static final int MAX_STRING = 60000; 41 42 private static final int BYTES_INCREMENT = 2048; 43 44 private static final byte[] EMPTY_BYTES = new byte[0]; 45 46 Thread currentLock; 47 48 protected boolean openedForWrite; 49 50 public boolean fileNotFound = false; 51 52 protected DataAccessor da; 53 protected boolean opened = false; 54 55 56 protected int offset; 57 58 59 protected byte[] bytes = EMPTY_BYTES; 60 61 62 char[] chars = Analyzer.EMPTY_CHAR_ARRAY; 63 64 65 StringCache strCache; 66 67 68 private int lockDeep; 69 70 71 private static final String WRITE_LOCK_MISSING 72 = "Unlock file without previous lock file"; 74 75 private int version = 1; 77 81 private static final int BIT7 = (1 << 7); 82 83 90 private static final int BIT6 = (1 << 6); 91 private static final int BIT5 = (1 << 5); 92 93 95 public FileStorage(String fileName) { 96 this(fileName, new StringCache()); 97 } 98 99 public FileStorage(String fileName, StringCache strCache) { 100 da = new FileAccessor(new File (fileName)); 101 this.strCache = strCache; 102 } 103 104 public FileStorage(DataAccessor da, StringCache strCache){ 105 this.da = da; 106 this.strCache = strCache; 107 } 108 109 110 public void setVersion(int ver){ 111 version = ver; 112 } 113 114 public void open(boolean requestWrite) throws IOException { 115 if (openedForWrite == requestWrite) { 116 ensureOpen(requestWrite); 117 da.seek(getFileLength()); 118 return; } else { close(); 121 } 122 123 ensureOpen(requestWrite); 125 da.seek(getFileLength()); 126 openedForWrite = requestWrite; 127 offset = 0; 128 } 129 130 private void ensureOpen(boolean requestWrite) throws IOException { 131 if (!opened) { 132 da.open(requestWrite); 133 opened = true; 134 } 135 } 136 137 138 public void close() throws IOException { 139 opened = false; 140 da.close(); 141 } 142 143 144 protected void checkBytesSize(int len) { 145 if (bytes.length < len) { 146 byte[] newBytes = new byte[len + BYTES_INCREMENT]; 147 System.arraycopy(bytes, 0, newBytes, 0, bytes.length); 148 bytes = newBytes; 149 } 150 } 151 152 155 public void read(int len) throws IOException { 156 checkBytesSize(len); 157 da.read(bytes, 0, len); 158 offset = 0; 159 } 160 161 162 public void write() throws IOException { 163 if (offset > 0) { 164 da.append(bytes, 0, offset); 165 } 166 offset = 0; 167 } 168 169 public void seek(int filePointer) throws IOException { 170 da.seek(filePointer); 171 } 172 173 public String getFileName() { 174 return da.toString(); 175 } 176 177 public int getFilePointer() throws IOException { 178 return (int)da.getFilePointer(); 179 } 180 181 public void setOffset(int offset) { 182 this.offset = offset; 183 } 184 185 public int getOffset() { 186 return offset; 187 } 188 189 public int getFileLength() throws IOException { 190 return da.getFileLength(); 191 } 192 193 public void resetBytes() { 194 bytes = EMPTY_BYTES; 195 } 196 197 198 public void resetFile() throws IOException { 199 open(true); 200 offset = 0; 201 da.resetFile(); 202 close(); 203 } 204 205 206 public int getInteger() { 207 if (version == 1){ 208 int i = bytes[offset++]; 209 i = (i << 8) + (bytes[offset++] & 255); 210 i = (i << 8) + (bytes[offset++] & 255); 211 i = (i << 8) + (bytes[offset++] & 255); 212 return i; 213 } 214 215 if (version == 2){ 216 return decodeInteger(); 217 } 218 return 0; 219 } 220 221 222 public String getString() { 223 int len = getInteger(); 225 if (len < 0) { 226 throw new RuntimeException ("Consistency error: read string length=" + len); } 228 229 if (len > MAX_STRING) { 230 throw new RuntimeException ("FileStorage: String len is " + len + ". There's probably a corruption in the file '" + getFileName() + "'."); } 234 235 if(version == 1){ 236 if (chars.length < len) { chars = new char[2 * len]; 238 } 239 for (int i = 0; i < len; i++) { 240 chars[i] = (char)((bytes[offset] << 8) + (bytes[offset + 1] & 255)); 241 offset += 2; 242 } 243 244 String s = null; 245 if (len >= 0) { 246 if (strCache != null) { 247 s = strCache.getString(chars, 0, len); 248 } else { s = new String (chars, 0, len); 250 } 251 } 252 253 return s; 254 255 }else if (version == 2){ 256 try{ 257 String s = new String (bytes,offset,len,getEncoding()); 258 offset += len; 259 return s; 260 }catch(java.io.UnsupportedEncodingException e){ 261 e.printStackTrace(); 262 return ""; 263 } 264 catch(ArrayIndexOutOfBoundsException ex){ 265 StringBuffer sb = new StringBuffer (len); 266 for (int i=0;i<len;i++){ 267 sb.append((char)bytes[offset+i]); 268 } 269 String st = sb.toString(); 270 271 throw new RuntimeException ("Debug of #12932: If this bug occurs, please send the stacktrace as attachment to Issuezilla's #12932."+"\n"+ "http://www.netbeans.org/issues/show_bug.cgi?id=12932"+"\n"+ "debug 2"+"\n"+ "File:"+this.toString()+"\n"+ "File Version:"+version+"\n"+ "Offest: "+offset+"\n"+ "Read length: "+len+"\n"+ "bytes.length: "+bytes.length+"\n"+ "String:"+st+"\n"+ "Error:"+ex); } 282 } 283 return ""; 284 } 285 286 289 public void putInteger(int i) { 290 if (version == 1){ 291 checkBytesSize(offset + 4); bytes[offset + 3] = (byte)(i & 255); 293 i >>>= 8; 294 bytes[offset + 2] = (byte)(i & 255); 295 i >>>= 8; 296 bytes[offset + 1] = (byte)(i & 255); 297 i >>>= 8; 298 bytes[offset] = (byte)i; 299 offset += 4; 300 } 301 302 if (version == 2){ 303 encodeInteger(i); 304 } 305 } 306 307 311 public void putString(String s) { 312 if (s == null) { 313 return; 314 } 315 316 if (version == 1){ 317 int len = s.length(); 318 putInteger(len); 319 320 if (len > 0) { 321 checkBytesSize(offset + len * 2); 322 for (int i = 0; i < len; i++) { 323 char ch = s.charAt(i); 324 bytes[offset + 1] = (byte)(ch & 255); 325 ch >>>= 8; 326 bytes[offset] = (byte)(ch & 255); 327 offset += 2; 328 } 329 } 330 }else if (version == 2){ 331 333 byte encodedBytes[]; 334 try{ 335 encodedBytes = s.getBytes(getEncoding()); 336 }catch(java.io.UnsupportedEncodingException e){ 337 return; 338 } 339 340 341 int len = java.lang.reflect.Array.getLength(encodedBytes); 342 if (len < 0) { 343 return; 344 } 345 putInteger(len); 346 347 checkBytesSize(offset + len); 348 System.arraycopy(encodedBytes,0,bytes,offset,len); 349 offset += len; 350 } 351 } 352 353 354 private int decodeInteger(){ 355 int i = bytes[offset++]&255; 356 if ((i & BIT7) == 0){ 357 return i; 358 } 359 int level = 1; 360 if ((i & BIT6)!= 0) level +=2; 361 if ((i & BIT5)!= 0) level +=1; 362 i &= ~(BIT7 | BIT6 | BIT5); 364 for(int j=1; j<=level; j++){ 365 i = (i << 8) + (bytes[offset++]&255); 366 } 367 return i; 368 } 369 370 371 372 private void encodeInteger(int y){ 373 int level = 0; 374 375 if (y >= 536870912) level += 4; else if (y >= 2097152) level += 3; else if (y >= 8192) level += 2; else if (y >= 128) level += 1; 380 checkBytesSize(offset + level + 1); 382 for (int j=level; j>0; j--){ 383 bytes[offset+j] = (byte) (y & 255); 384 y >>>= 8; 385 } 386 387 bytes[offset] = (byte) y; 388 389 switch( level ) { 391 case 2: 392 bytes[offset] |= BIT5; 393 break; 394 case 3: 395 bytes[offset] |= BIT6; 396 break; 397 case 4: 398 bytes[offset] |= BIT5; 399 bytes[offset] |= BIT6; 400 break; 401 } 402 if (level > 0) bytes[offset] |= BIT7; level++; 404 offset += level; 405 } 406 407 408 private String getEncoding(){ 409 switch( version ) { 410 case 1: 411 return "UTF-16BE"; case 2: 413 return "UTF-8"; default: 415 return "UTF-16BE"; } 417 } 418 419 420 public synchronized final void lockFile() { 421 if ((currentLock == null) || (Thread.currentThread() != currentLock)) { 422 try{ 423 if (currentLock == null){ 424 currentLock = Thread.currentThread(); 425 lockDeep = 0; 426 }else{ 427 wait(); 428 } 429 }catch(InterruptedException ie){ 430 throw new RuntimeException (ie.toString()); 431 }catch(IllegalMonitorStateException imse){ 432 throw new RuntimeException (imse.toString()); 433 } 434 } else { lockDeep++; } 437 } 438 439 440 public synchronized final void unlockFile() { 441 if (Thread.currentThread() != currentLock) { 442 throw new RuntimeException (WRITE_LOCK_MISSING); 443 } 444 if (lockDeep == 0) { resetBytes(); 446 notify(); 447 currentLock=null; 448 } else { lockDeep--; 450 } 451 } 452 453 454 public String toString(){ 455 return getFileName(); 456 } 457 458 } 459 | Popular Tags |