1 11 package org.eclipse.core.internal.filebuffers; 12 13 import java.io.BufferedReader ; 14 import java.io.ByteArrayInputStream ; 15 import java.io.IOException ; 16 import java.io.InputStream ; 17 import java.io.InputStreamReader ; 18 import java.io.OutputStream ; 19 import java.io.Reader ; 20 import java.io.SequenceInputStream ; 21 import java.nio.ByteBuffer ; 22 import java.nio.CharBuffer ; 23 import java.nio.charset.CharacterCodingException ; 24 import java.nio.charset.Charset ; 25 import java.nio.charset.CharsetEncoder ; 26 import java.nio.charset.CodingErrorAction ; 27 import java.nio.charset.IllegalCharsetNameException ; 28 import java.nio.charset.UnmappableCharacterException ; 29 import java.nio.charset.UnsupportedCharsetException ; 30 31 import org.eclipse.core.filesystem.EFS; 32 import org.eclipse.core.filesystem.IFileInfo; 33 import org.eclipse.core.filesystem.IFileStore; 34 35 import org.eclipse.core.runtime.Assert; 36 import org.eclipse.core.runtime.CoreException; 37 import org.eclipse.core.runtime.IPath; 38 import org.eclipse.core.runtime.IProgressMonitor; 39 import org.eclipse.core.runtime.IStatus; 40 import org.eclipse.core.runtime.Path; 41 import org.eclipse.core.runtime.Platform; 42 import org.eclipse.core.runtime.QualifiedName; 43 import org.eclipse.core.runtime.Status; 44 import org.eclipse.core.runtime.content.IContentDescription; 45 import org.eclipse.core.runtime.content.IContentType; 46 47 import org.eclipse.core.filebuffers.IFileBufferStatusCodes; 48 import org.eclipse.core.filebuffers.IPersistableAnnotationModel; 49 import org.eclipse.core.filebuffers.ITextFileBuffer; 50 import org.eclipse.core.filebuffers.LocationKind; 51 52 import org.eclipse.jface.text.DocumentEvent; 53 import org.eclipse.jface.text.IDocument; 54 import org.eclipse.jface.text.IDocumentListener; 55 import org.eclipse.jface.text.source.IAnnotationModel; 56 57 60 public class FileStoreTextFileBuffer extends FileStoreFileBuffer implements ITextFileBuffer { 61 62 63 private class DocumentListener implements IDocumentListener { 64 65 68 public void documentAboutToBeChanged(DocumentEvent event) { 69 } 70 71 74 public void documentChanged(DocumentEvent event) { 75 fCanBeSaved= true; 76 removeFileBufferContentListeners(); 77 fManager.fireDirtyStateChanged(FileStoreTextFileBuffer.this, fCanBeSaved); 78 } 79 } 80 81 84 private static final int READER_CHUNK_SIZE= 2048; 85 88 private static final int BUFFER_SIZE= 8 * READER_CHUNK_SIZE; 89 92 private static final IStatus STATUS_OK= new Status(IStatus.OK, FileBuffersPlugin.PLUGIN_ID, IStatus.OK, FileBuffersMessages.FileBuffer_status_ok, null); 93 96 private static final IStatus STATUS_ERROR= new Status(IStatus.ERROR, FileBuffersPlugin.PLUGIN_ID, IStatus.OK, FileBuffersMessages.FileBuffer_status_error, null); 97 100 private static final String CHARSET_UTF_8= "UTF-8"; 102 106 private static final QualifiedName[] NO_PROPERTIES= new QualifiedName[0]; 107 108 109 110 protected IDocument fDocument; 111 112 protected String fEncoding; 113 114 protected IDocumentListener fDocumentListener= new DocumentListener(); 115 116 private String fExplicitEncoding; 117 118 private boolean fHasBOM; 119 120 private IAnnotationModel fAnnotationModel; 121 125 private final Object fAnnotationModelCreationLock= new Object (); 126 130 private boolean fIsCacheUpdated= false; 131 132 133 public FileStoreTextFileBuffer(TextFileBufferManager manager) { 134 super(manager); 135 } 136 137 140 public IDocument getDocument() { 141 return fDocument; 142 } 143 144 147 public IAnnotationModel getAnnotationModel() { 148 synchronized (fAnnotationModelCreationLock) { 149 if (fAnnotationModel == null && !isDisconnected()) { 150 fAnnotationModel= fManager.createAnnotationModel(getLocationOrName(), LocationKind.LOCATION); 151 if (fAnnotationModel != null) 152 fAnnotationModel.connect(fDocument); 153 } 154 } 155 return fAnnotationModel; 156 } 157 158 161 public String getEncoding() { 162 if (!fIsCacheUpdated) 163 cacheEncodingState(null); 164 return fEncoding; 165 } 166 167 170 public void setEncoding(String encoding) { 171 fExplicitEncoding= encoding; 172 if (encoding == null || encoding.equals(fEncoding)) 173 fIsCacheUpdated= false; 174 else { 175 fEncoding= encoding; 176 fHasBOM= false; 177 } 178 } 179 180 183 public IStatus getStatus() { 184 if (!isDisconnected()) { 185 if (fStatus != null) 186 return fStatus; 187 return (fDocument == null ? STATUS_ERROR : STATUS_OK); 188 } 189 return STATUS_ERROR; 190 } 191 192 private InputStream getFileContents(IFileStore fileStore, IProgressMonitor monitor) throws CoreException { 193 if (!fFileStore.fetchInfo().exists()) 194 return null; 195 196 return fileStore.openInputStream(EFS.NONE, null); 197 } 198 199 private void setFileContents(InputStream stream, boolean overwrite, IProgressMonitor monitor) throws CoreException { 200 OutputStream out= fFileStore.openOutputStream(EFS.NONE, null); 201 try { 202 byte[] buffer= new byte[8192]; 203 while (true) { 204 int bytesRead= -1; 205 try { 206 bytesRead= stream.read(buffer); 207 } catch (IOException e) { 208 } 209 if (bytesRead == -1) 210 break; 211 try { 212 out.write(buffer, 0, bytesRead); 213 } catch (IOException e) { 214 } 215 if (monitor != null) 216 monitor.worked(1); 217 } 218 } finally { 219 try { 220 stream.close(); 221 } catch (IOException e) { 222 } finally { 223 try { 224 out.close(); 225 } catch (IOException e) { 226 } 227 } 228 } 229 } 230 231 234 public void revert(IProgressMonitor monitor) throws CoreException { 235 if (isDisconnected()) 236 return; 237 238 IDocument original= null; 239 fStatus= null; 240 241 try { 242 original= fManager.createEmptyDocument(getLocationOrName(), LocationKind.LOCATION); 243 cacheEncodingState(monitor); 244 setDocumentContent(original, fFileStore, fEncoding, fHasBOM, monitor); 245 } catch (CoreException x) { 246 fStatus= x.getStatus(); 247 } 248 249 if (original == null) 250 return; 251 252 String originalContents= original.get(); 253 boolean replaceContents= !originalContents.equals(fDocument.get()); 254 255 if (!replaceContents && !fCanBeSaved) 256 return; 257 258 fManager.fireStateChanging(this); 259 try { 260 261 if (replaceContents) { 262 fManager.fireBufferContentAboutToBeReplaced(this); 263 fDocument.set(original.get()); 264 } 265 266 boolean fireDirtyStateChanged= fCanBeSaved; 267 if (fCanBeSaved) { 268 fCanBeSaved= false; 269 addFileBufferContentListeners(); 270 } 271 272 if (replaceContents) 273 fManager.fireBufferContentReplaced(this); 274 275 IFileInfo info= fFileStore.fetchInfo(); 276 if (info.exists()) 277 fSynchronizationStamp= fFileStore.fetchInfo().getLastModified(); 278 279 if (fAnnotationModel instanceof IPersistableAnnotationModel) { 280 IPersistableAnnotationModel persistableModel= (IPersistableAnnotationModel) fAnnotationModel; 281 try { 282 persistableModel.revert(fDocument); 283 } catch (CoreException x) { 284 fStatus= x.getStatus(); 285 } 286 } 287 288 if (fireDirtyStateChanged) 289 fManager.fireDirtyStateChanged(this, fCanBeSaved); 290 291 } catch (RuntimeException x) { 292 fManager.fireStateChangeFailed(this); 293 throw x; 294 } 295 } 296 297 301 public IContentType getContentType () throws CoreException { 302 InputStream stream= null; 303 try { 304 if (isDirty()) { 305 Reader reader= new DocumentReader(getDocument()); 306 try { 307 IContentDescription desc= Platform.getContentTypeManager().getDescriptionFor(reader, fFileStore.getName(), NO_PROPERTIES); 308 if (desc != null && desc.getContentType() != null) 309 return desc.getContentType(); 310 } finally { 311 try { 312 if (reader != null) 313 reader.close(); 314 } catch (IOException ex) { 315 } 316 } 317 } 318 stream= fFileStore.openInputStream(EFS.NONE, null); 319 IContentDescription desc= Platform.getContentTypeManager().getDescriptionFor(stream, fFileStore.getName(), NO_PROPERTIES); 320 if (desc != null && desc.getContentType() != null) 321 return desc.getContentType(); 322 return null; 323 } catch (IOException x) { 324 throw new CoreException(new Status(IStatus.ERROR, FileBuffersPlugin.PLUGIN_ID, IStatus.OK, NLSUtility.format(FileBuffersMessages.FileBuffer_error_queryContentDescription, fFileStore.toString()), x)); 325 } finally { 326 try { 327 if (stream != null) 328 stream.close(); 329 } catch (IOException x) { 330 } 331 } 332 } 333 334 337 protected void addFileBufferContentListeners() { 338 if (fDocument != null) 339 fDocument.addDocumentListener(fDocumentListener); 340 } 341 342 345 protected void removeFileBufferContentListeners() { 346 if (fDocument != null) 347 fDocument.removeDocumentListener(fDocumentListener); 348 } 349 350 353 protected void initializeFileBufferContent(IProgressMonitor monitor) throws CoreException { 354 try { 355 fDocument= fManager.createEmptyDocument(getLocationOrName(), LocationKind.LOCATION); 356 cacheEncodingState(monitor); 357 setDocumentContent(fDocument, fFileStore, fEncoding, fHasBOM, monitor); 358 } catch (CoreException x) { 359 fDocument= fManager.createEmptyDocument(getLocationOrName(), LocationKind.LOCATION); 360 fStatus= x.getStatus(); 361 } 362 } 363 364 367 protected void connected() { 368 super.connected(); 369 if (fAnnotationModel != null) 370 fAnnotationModel.connect(fDocument); 371 } 372 373 376 protected void disconnected() { 377 if (fAnnotationModel != null) 378 fAnnotationModel.disconnect(fDocument); 379 super.disconnected(); 380 } 381 382 protected void cacheEncodingState(IProgressMonitor monitor) { 383 fEncoding= fExplicitEncoding; 384 fHasBOM= false; 385 fIsCacheUpdated= true; 386 387 InputStream stream= null; 388 try { 389 stream= getFileContents(fFileStore, monitor); 390 if (stream == null) 391 return; 392 393 QualifiedName[] options= new QualifiedName[] { IContentDescription.CHARSET, IContentDescription.BYTE_ORDER_MARK }; 394 IContentDescription description= Platform.getContentTypeManager().getDescriptionFor(stream, fFileStore.getName(), options); 395 if (description != null) { 396 fHasBOM= description.getProperty(IContentDescription.BYTE_ORDER_MARK) != null; 397 if (fEncoding == null) 398 fEncoding= description.getCharset(); 399 } 400 } catch (CoreException e) { 401 } catch (IOException e) { 403 } finally { 405 try { 406 if (stream != null) 407 stream.close(); 408 } catch (IOException ex) { 409 FileBuffersPlugin.getDefault().getLog().log(new Status(IStatus.ERROR, FileBuffersPlugin.PLUGIN_ID, IStatus.OK, FileBuffersMessages.JavaTextFileBuffer_error_closeStream, ex)); 410 } 411 } 412 } 413 414 417 protected void commitFileBufferContent(IProgressMonitor monitor, boolean overwrite) throws CoreException { 418 String encoding= computeEncoding(); 419 420 Charset charset; 421 try { 422 charset= Charset.forName(encoding); 423 } catch (UnsupportedCharsetException ex) { 424 String message= NLSUtility.format(FileBuffersMessages.ResourceTextFileBuffer_error_unsupported_encoding_message_arg, encoding); 425 IStatus s= new Status(IStatus.ERROR, FileBuffersPlugin.PLUGIN_ID, IStatus.OK, message, ex); 426 throw new CoreException(s); 427 } catch (IllegalCharsetNameException ex) { 428 String message= NLSUtility.format(FileBuffersMessages.ResourceTextFileBuffer_error_illegal_encoding_message_arg, encoding); 429 IStatus s= new Status(IStatus.ERROR, FileBuffersPlugin.PLUGIN_ID, IStatus.OK, message, ex); 430 throw new CoreException(s); 431 } 432 433 CharsetEncoder encoder= charset.newEncoder(); 434 encoder.onMalformedInput(CodingErrorAction.REPLACE); 435 encoder.onUnmappableCharacter(CodingErrorAction.REPORT); 436 437 byte[] bytes; 438 int bytesLength; 439 440 try { 441 ByteBuffer byteBuffer= encoder.encode(CharBuffer.wrap(fDocument.get())); 442 bytesLength= byteBuffer.limit(); 443 if (byteBuffer.hasArray()) 444 bytes= byteBuffer.array(); 445 else { 446 bytes= new byte[bytesLength]; 447 byteBuffer.get(bytes); 448 } 449 } catch (CharacterCodingException ex) { 450 Assert.isTrue(ex instanceof UnmappableCharacterException ); 451 String message= NLSUtility.format(FileBuffersMessages.ResourceTextFileBuffer_error_charset_mapping_failed_message_arg, encoding); 452 IStatus s= new Status(IStatus.ERROR, FileBuffersPlugin.PLUGIN_ID, IFileBufferStatusCodes.CHARSET_MAPPING_FAILED, message, null); 453 throw new CoreException(s); 454 } 455 456 IFileInfo fileInfo= fFileStore.fetchInfo(); 457 if (fileInfo != null && fileInfo.exists()) { 458 459 if (!overwrite) 460 checkSynchronizationState(); 461 462 InputStream stream= new ByteArrayInputStream (bytes, 0, bytesLength); 463 464 469 if (fHasBOM && CHARSET_UTF_8.equals(encoding)) 470 stream= new SequenceInputStream (new ByteArrayInputStream (IContentDescription.BOM_UTF_8), stream); 471 472 473 setFileContents(stream, overwrite, monitor); 476 fSynchronizationStamp= fFileStore.fetchInfo().getLastModified(); 478 479 if (fAnnotationModel instanceof IPersistableAnnotationModel) { 480 IPersistableAnnotationModel persistableModel= (IPersistableAnnotationModel) fAnnotationModel; 481 persistableModel.commit(fDocument); 482 } 483 484 } else { 485 fFileStore.getParent().mkdir(EFS.NONE, null); 486 OutputStream out= fFileStore.openOutputStream(EFS.NONE, null); 487 try { 488 493 if (fHasBOM && CHARSET_UTF_8.equals(encoding)) 494 out.write(IContentDescription.BOM_UTF_8); 495 496 out.write(bytes, 0, bytesLength); 497 out.flush(); 498 } catch (IOException x) { 499 IStatus s= new Status(IStatus.ERROR, FileBuffersPlugin.PLUGIN_ID, IStatus.OK, x.getLocalizedMessage(), x); 500 throw new CoreException(s); 501 } finally { 502 try { 503 out.close(); 504 } catch (IOException x) { 505 } 506 } 507 508 fSynchronizationStamp= fFileStore.fetchInfo().getLastModified(); 510 511 } 512 } 513 514 private String computeEncoding() { 515 if (!fIsCacheUpdated) 517 cacheEncodingState(null); 518 519 if (fExplicitEncoding != null) 521 return fExplicitEncoding; 522 523 Reader reader= new DocumentReader(fDocument); 525 try { 526 QualifiedName[] options= new QualifiedName[] { IContentDescription.CHARSET, IContentDescription.BYTE_ORDER_MARK }; 527 IContentDescription description= Platform.getContentTypeManager().getDescriptionFor(reader, fFileStore.getName(), options); 528 if (description != null) { 529 String encoding= description.getCharset(); 530 if (encoding != null) 531 return encoding; 532 } 533 } catch (IOException ex) { 534 } finally { 536 try { 537 if (reader != null) 538 reader.close(); 539 } catch (IOException x) { 540 } 541 } 542 543 if (fHasBOM) 545 return fEncoding; 546 547 return fManager.getDefaultEncoding(); 549 } 550 551 561 private void setDocumentContent(IDocument document, IFileStore file, String encoding, boolean hasBOM, IProgressMonitor monitor) throws CoreException { 562 InputStream contentStream= getFileContents(file, monitor); 563 if (contentStream == null) 564 return; 565 566 Reader in= null; 567 try { 568 569 if (encoding == null) 570 encoding= fManager.getDefaultEncoding(); 571 572 577 if (hasBOM && CHARSET_UTF_8.equals(encoding)) { 578 int n= 0; 579 do { 580 int bytes= contentStream.read(new byte[IContentDescription.BOM_UTF_8.length]); 581 if (bytes == -1) 582 throw new IOException (); 583 n += bytes; 584 } while (n < IContentDescription.BOM_UTF_8.length); 585 } 586 587 in= new BufferedReader (new InputStreamReader (contentStream, encoding), BUFFER_SIZE); 588 StringBuffer buffer= new StringBuffer (BUFFER_SIZE); 589 char[] readBuffer= new char[READER_CHUNK_SIZE]; 590 int n= in.read(readBuffer); 591 while (n > 0) { 592 buffer.append(readBuffer, 0, n); 593 n= in.read(readBuffer); 594 } 595 596 document.set(buffer.toString()); 597 598 } catch (IOException x) { 599 String msg= x.getMessage() == null ? "" : x.getMessage(); IStatus s= new Status(IStatus.ERROR, FileBuffersPlugin.PLUGIN_ID, IStatus.OK, msg, x); 601 throw new CoreException(s); 602 } finally { 603 try { 604 if (in != null) 605 in.close(); 606 else 607 contentStream.close(); 608 } catch (IOException x) { 609 } 610 } 611 } 612 613 619 private void checkSynchronizationState() throws CoreException { 620 if (!isSynchronized()) { 621 Status status= new Status(IStatus.ERROR, FileBuffersPlugin.PLUGIN_ID, 274 , FileBuffersMessages.FileBuffer_error_outOfSync, null); 622 throw new CoreException(status); 623 } 624 } 625 626 633 private IPath getLocationOrName() { 634 IPath path= getLocation(); 635 if (path == null) 636 path= new Path(fFileStore.getName()); 637 return path; 638 } 639 } 640 | Popular Tags |