PageRenderTime 39ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 1ms

/jEdit/tags/jedit-4-2-pre14/org/gjt/sp/jedit/buffer/BufferIORequest.java

#
Java | 1031 lines | 727 code | 118 blank | 186 comment | 134 complexity | c451cf14d3e44826e518606fc5b0daf5 MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, Apache-2.0, LGPL-2.0, LGPL-3.0, GPL-2.0, CC-BY-SA-3.0, LGPL-2.1, GPL-3.0, MPL-2.0-no-copyleft-exception, IPL-1.0
  1. /*
  2. * BufferIORequest.java - I/O request
  3. * :tabSize=8:indentSize=8:noTabs=false:
  4. * :folding=explicit:collapseFolds=1:
  5. *
  6. * Copyright (C) 2000, 2003 Slava Pestov
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License
  10. * as published by the Free Software Foundation; either version 2
  11. * of the License, or any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  21. */
  22. package org.gjt.sp.jedit.buffer;
  23. //{{{ Imports
  24. import javax.swing.text.Segment;
  25. import java.io.*;
  26. import java.util.zip.*;
  27. import java.util.Vector;
  28. import org.gjt.sp.jedit.io.*;
  29. import org.gjt.sp.jedit.*;
  30. import org.gjt.sp.util.*;
  31. //}}}
  32. /**
  33. * A buffer I/O request.
  34. * @author Slava Pestov
  35. * @version $Id: BufferIORequest.java 5053 2004-05-29 01:55:26Z spestov $
  36. */
  37. public class BufferIORequest extends WorkRequest
  38. {
  39. //{{{ Constants
  40. /**
  41. * Size of I/O buffers.
  42. */
  43. public static final int IOBUFSIZE = 32768;
  44. /**
  45. * Number of lines per progress increment.
  46. */
  47. public static final int PROGRESS_INTERVAL = 300;
  48. public static final String LOAD_DATA = "BufferIORequest__loadData";
  49. public static final String END_OFFSETS = "BufferIORequest__endOffsets";
  50. public static final String NEW_PATH = "BufferIORequest__newPath";
  51. /**
  52. * Buffer boolean property set when an error occurs.
  53. */
  54. public static final String ERROR_OCCURRED = "BufferIORequest__error";
  55. /**
  56. * A file load request.
  57. */
  58. public static final int LOAD = 0;
  59. /**
  60. * A file save request.
  61. */
  62. public static final int SAVE = 1;
  63. /**
  64. * An autosave request. Only supported for local files.
  65. */
  66. public static final int AUTOSAVE = 2;
  67. /**
  68. * An insert file request.
  69. */
  70. public static final int INSERT = 3;
  71. /**
  72. * Magic numbers used for auto-detecting Unicode and GZIP files.
  73. */
  74. public static final int GZIP_MAGIC_1 = 0x1f;
  75. public static final int GZIP_MAGIC_2 = 0x8b;
  76. public static final int UNICODE_MAGIC_1 = 0xfe;
  77. public static final int UNICODE_MAGIC_2 = 0xff;
  78. public static final int UTF8_MAGIC_1 = 0xef;
  79. public static final int UTF8_MAGIC_2 = 0xbb;
  80. public static final int UTF8_MAGIC_3 = 0xbf;
  81. /**
  82. * Length of longest XML PI used for encoding detection.<p>
  83. * &lt;?xml version="1.0" encoding="................"?&gt;
  84. */
  85. public static final int XML_PI_LENGTH = 50;
  86. //}}}
  87. //{{{ BufferIORequest constructor
  88. /**
  89. * Creates a new buffer I/O request.
  90. * @param type The request type
  91. * @param view The view
  92. * @param buffer The buffer
  93. * @param session The VFS session
  94. * @param vfs The VFS
  95. * @param path The path
  96. */
  97. public BufferIORequest(int type, View view, Buffer buffer,
  98. Object session, VFS vfs, String path)
  99. {
  100. this.type = type;
  101. this.view = view;
  102. this.buffer = buffer;
  103. this.session = session;
  104. this.vfs = vfs;
  105. this.path = path;
  106. markersPath = vfs.getParentOfPath(path)
  107. + '.' + vfs.getFileName(path)
  108. + ".marks";
  109. } //}}}
  110. //{{{ run() method
  111. public void run()
  112. {
  113. switch(type)
  114. {
  115. case LOAD:
  116. load();
  117. break;
  118. case SAVE:
  119. save();
  120. break;
  121. case AUTOSAVE:
  122. autosave();
  123. break;
  124. case INSERT:
  125. insert();
  126. break;
  127. default:
  128. throw new InternalError();
  129. }
  130. } //}}}
  131. //{{{ toString() method
  132. public String toString()
  133. {
  134. String typeString;
  135. switch(type)
  136. {
  137. case LOAD:
  138. typeString = "LOAD";
  139. break;
  140. case SAVE:
  141. typeString = "SAVE";
  142. break;
  143. case AUTOSAVE:
  144. typeString = "AUTOSAVE";
  145. break;
  146. default:
  147. typeString = "UNKNOWN!!!";
  148. }
  149. return getClass().getName() + "[type=" + typeString
  150. + ",buffer=" + buffer + "]";
  151. } //}}}
  152. //{{{ Private members
  153. //{{{ Instance variables
  154. private int type;
  155. private View view;
  156. private Buffer buffer;
  157. private Object session;
  158. private VFS vfs;
  159. private String path;
  160. private String markersPath;
  161. //}}}
  162. //{{{ load() method
  163. private void load()
  164. {
  165. InputStream in = null;
  166. try
  167. {
  168. try
  169. {
  170. String[] args = { vfs.getFileName(path) };
  171. setAbortable(true);
  172. if(!buffer.isTemporary())
  173. {
  174. setStatus(jEdit.getProperty("vfs.status.load",args));
  175. setProgressValue(0);
  176. }
  177. path = vfs._canonPath(session,path,view);
  178. VFS.DirectoryEntry entry = vfs._getDirectoryEntry(
  179. session,path,view);
  180. long length;
  181. if(entry != null)
  182. length = entry.length;
  183. else
  184. length = 0L;
  185. in = vfs._createInputStream(session,path,
  186. false,view);
  187. if(in == null)
  188. return;
  189. read(autodetect(in),length,false);
  190. buffer.setNewFile(false);
  191. }
  192. catch(CharConversionException ch)
  193. {
  194. Log.log(Log.ERROR,this,ch);
  195. Object[] pp = { buffer.getProperty(Buffer.ENCODING),
  196. ch.toString() };
  197. VFSManager.error(view,path,"ioerror.encoding-error",pp);
  198. buffer.setBooleanProperty(ERROR_OCCURRED,true);
  199. }
  200. catch(UnsupportedEncodingException uu)
  201. {
  202. Log.log(Log.ERROR,this,uu);
  203. Object[] pp = { buffer.getProperty(Buffer.ENCODING),
  204. uu.toString() };
  205. VFSManager.error(view,path,"ioerror.encoding-error",pp);
  206. buffer.setBooleanProperty(ERROR_OCCURRED,true);
  207. }
  208. catch(IOException io)
  209. {
  210. Log.log(Log.ERROR,this,io);
  211. Object[] pp = { io.toString() };
  212. VFSManager.error(view,path,"ioerror.read-error",pp);
  213. buffer.setBooleanProperty(ERROR_OCCURRED,true);
  214. }
  215. catch(OutOfMemoryError oom)
  216. {
  217. Log.log(Log.ERROR,this,oom);
  218. VFSManager.error(view,path,"out-of-memory-error",null);
  219. buffer.setBooleanProperty(ERROR_OCCURRED,true);
  220. }
  221. if(jEdit.getBooleanProperty("persistentMarkers"))
  222. {
  223. try
  224. {
  225. String[] args = { vfs.getFileName(path) };
  226. if(!buffer.isTemporary())
  227. setStatus(jEdit.getProperty("vfs.status.load-markers",args));
  228. setAbortable(true);
  229. in = vfs._createInputStream(session,markersPath,true,view);
  230. if(in != null)
  231. readMarkers(buffer,in);
  232. }
  233. catch(IOException io)
  234. {
  235. // ignore
  236. }
  237. }
  238. }
  239. catch(WorkThread.Abort a)
  240. {
  241. if(in != null)
  242. {
  243. try
  244. {
  245. in.close();
  246. }
  247. catch(IOException io)
  248. {
  249. }
  250. }
  251. buffer.setBooleanProperty(ERROR_OCCURRED,true);
  252. }
  253. finally
  254. {
  255. try
  256. {
  257. vfs._endVFSSession(session,view);
  258. }
  259. catch(IOException io)
  260. {
  261. Log.log(Log.ERROR,this,io);
  262. String[] pp = { io.toString() };
  263. VFSManager.error(view,path,"ioerror.read-error",pp);
  264. buffer.setBooleanProperty(ERROR_OCCURRED,true);
  265. }
  266. catch(WorkThread.Abort a)
  267. {
  268. buffer.setBooleanProperty(ERROR_OCCURRED,true);
  269. }
  270. }
  271. } //}}}
  272. //{{{ autodetect() method
  273. /**
  274. * Tries to detect if the stream is gzipped, and if it has an encoding
  275. * specified with an XML PI.
  276. */
  277. private Reader autodetect(InputStream in) throws IOException
  278. {
  279. in = new BufferedInputStream(in);
  280. String encoding = buffer.getStringProperty(Buffer.ENCODING);
  281. if(!in.markSupported())
  282. Log.log(Log.WARNING,this,"Mark not supported: " + in);
  283. else if(buffer.getBooleanProperty(Buffer.ENCODING_AUTODETECT))
  284. {
  285. in.mark(XML_PI_LENGTH);
  286. int b1 = in.read();
  287. int b2 = in.read();
  288. int b3 = in.read();
  289. if(encoding.equals(MiscUtilities.UTF_8_Y))
  290. {
  291. // Java does not support this encoding so
  292. // we have to handle it manually.
  293. if(b1 != UTF8_MAGIC_1 || b2 != UTF8_MAGIC_2
  294. || b3 != UTF8_MAGIC_3)
  295. {
  296. // file does not begin with UTF-8-Y
  297. // signature. reset stream, read as
  298. // UTF-8.
  299. in.reset();
  300. }
  301. else
  302. {
  303. // file begins with UTF-8-Y signature.
  304. // discard the signature, and read
  305. // the remainder as UTF-8.
  306. }
  307. encoding = "UTF-8";
  308. }
  309. else if(b1 == GZIP_MAGIC_1 && b2 == GZIP_MAGIC_2)
  310. {
  311. in.reset();
  312. in = new GZIPInputStream(in);
  313. buffer.setBooleanProperty(Buffer.GZIPPED,true);
  314. }
  315. else if((b1 == UNICODE_MAGIC_1
  316. && b2 == UNICODE_MAGIC_2)
  317. || (b1 == UNICODE_MAGIC_2
  318. && b2 == UNICODE_MAGIC_1))
  319. {
  320. in.reset();
  321. encoding = "UTF-16";
  322. buffer.setProperty(Buffer.ENCODING,encoding);
  323. }
  324. else if(b1 == UTF8_MAGIC_1 && b2 == UTF8_MAGIC_2
  325. && b3 == UTF8_MAGIC_3)
  326. {
  327. // do not reset the stream and just treat it
  328. // like a normal UTF-8 file.
  329. buffer.setProperty(Buffer.ENCODING,
  330. MiscUtilities.UTF_8_Y);
  331. encoding = "UTF-8";
  332. }
  333. else
  334. {
  335. in.reset();
  336. byte[] _xmlPI = new byte[XML_PI_LENGTH];
  337. int offset = 0;
  338. int count;
  339. while((count = in.read(_xmlPI,offset,
  340. XML_PI_LENGTH - offset)) != -1)
  341. {
  342. offset += count;
  343. if(offset == XML_PI_LENGTH)
  344. break;
  345. }
  346. String xmlPI = new String(_xmlPI,0,offset,
  347. "ASCII");
  348. if(xmlPI.startsWith("<?xml"))
  349. {
  350. int index = xmlPI.indexOf("encoding=");
  351. if(index != -1
  352. && index + 9 != xmlPI.length())
  353. {
  354. char ch = xmlPI.charAt(index
  355. + 9);
  356. int endIndex = xmlPI.indexOf(ch,
  357. index + 10);
  358. encoding = xmlPI.substring(
  359. index + 10,endIndex);
  360. if(MiscUtilities.isSupportedEncoding(encoding))
  361. {
  362. buffer.setProperty(Buffer.ENCODING,encoding);
  363. }
  364. else
  365. {
  366. Log.log(Log.WARNING,this,"XML PI specifies unsupported encoding: " + encoding);
  367. }
  368. }
  369. }
  370. in.reset();
  371. }
  372. }
  373. return new InputStreamReader(in,encoding);
  374. } //}}}
  375. //{{{ read() method
  376. private SegmentBuffer read(Reader in, long length,
  377. boolean insert) throws IOException
  378. {
  379. /* we guess an initial size for the array */
  380. IntegerArray endOffsets = new IntegerArray(
  381. Math.max(1,(int)(length / 50)));
  382. // only true if the file size is known
  383. boolean trackProgress = (!buffer.isTemporary() && length != 0);
  384. if(trackProgress)
  385. {
  386. setProgressValue(0);
  387. setProgressMaximum((int)length);
  388. }
  389. // if the file size is not known, start with a resonable
  390. // default buffer size
  391. if(length == 0)
  392. length = IOBUFSIZE;
  393. SegmentBuffer seg = new SegmentBuffer((int)length + 1);
  394. char[] buf = new char[IOBUFSIZE];
  395. // Number of characters in 'buf' array.
  396. // InputStream.read() doesn't always fill the
  397. // array (eg, the file size is not a multiple of
  398. // IOBUFSIZE, or it is a GZipped file, etc)
  399. int len;
  400. // True if a \n was read after a \r. Usually
  401. // means this is a DOS/Windows file
  402. boolean CRLF = false;
  403. // A \r was read, hence a MacOS file
  404. boolean CROnly = false;
  405. // Was the previous read character a \r?
  406. // If we read a \n and this is true, we assume
  407. // we have a DOS/Windows file
  408. boolean lastWasCR = false;
  409. // Number of lines read. Every 100 lines, we update the
  410. // progress bar
  411. int lineCount = 0;
  412. while((len = in.read(buf,0,buf.length)) != -1)
  413. {
  414. // Offset of previous line, relative to
  415. // the start of the I/O buffer (NOT
  416. // relative to the start of the document)
  417. int lastLine = 0;
  418. for(int i = 0; i < len; i++)
  419. {
  420. // Look for line endings.
  421. switch(buf[i])
  422. {
  423. case '\r':
  424. // If we read a \r and
  425. // lastWasCR is also true,
  426. // it is probably a Mac file
  427. // (\r\r in stream)
  428. if(lastWasCR)
  429. {
  430. CROnly = true;
  431. CRLF = false;
  432. }
  433. // Otherwise set a flag,
  434. // so that \n knows that last
  435. // was a \r
  436. else
  437. {
  438. lastWasCR = true;
  439. }
  440. // Insert a line
  441. seg.append(buf,lastLine,i -
  442. lastLine);
  443. seg.append('\n');
  444. endOffsets.add(seg.count);
  445. if(trackProgress && lineCount++ % PROGRESS_INTERVAL == 0)
  446. setProgressValue(seg.count);
  447. // This is i+1 to take the
  448. // trailing \n into account
  449. lastLine = i + 1;
  450. break;
  451. case '\n':
  452. // If lastWasCR is true,
  453. // we just read a \r followed
  454. // by a \n. We specify that
  455. // this is a Windows file,
  456. // but take no further
  457. // action and just ignore
  458. // the \r.
  459. if(lastWasCR)
  460. {
  461. CROnly = false;
  462. CRLF = true;
  463. lastWasCR = false;
  464. // Bump lastLine so
  465. // that the next line
  466. // doesn't erronously
  467. // pick up the \r
  468. lastLine = i + 1;
  469. }
  470. // Otherwise, we found a \n
  471. // that follows some other
  472. // character, hence we have
  473. // a Unix file
  474. else
  475. {
  476. CROnly = false;
  477. CRLF = false;
  478. seg.append(buf,lastLine,
  479. i - lastLine);
  480. seg.append('\n');
  481. endOffsets.add(seg.count);
  482. if(trackProgress && lineCount++ % PROGRESS_INTERVAL == 0)
  483. setProgressValue(seg.count);
  484. lastLine = i + 1;
  485. }
  486. break;
  487. default:
  488. // If we find some other
  489. // character that follows
  490. // a \r, so it is not a
  491. // Windows file, and probably
  492. // a Mac file
  493. if(lastWasCR)
  494. {
  495. CROnly = true;
  496. CRLF = false;
  497. lastWasCR = false;
  498. }
  499. break;
  500. }
  501. }
  502. if(trackProgress)
  503. setProgressValue(seg.count);
  504. // Add remaining stuff from buffer
  505. seg.append(buf,lastLine,len - lastLine);
  506. }
  507. setAbortable(false);
  508. String lineSeparator;
  509. if(seg.count == 0)
  510. {
  511. // fix for "[ 865589 ] 0-byte files should open using
  512. // the default line seperator"
  513. lineSeparator = jEdit.getProperty(
  514. "buffer.lineSeparator",
  515. System.getProperty("line.separator"));
  516. }
  517. else if(CRLF)
  518. lineSeparator = "\r\n";
  519. else if(CROnly)
  520. lineSeparator = "\r";
  521. else
  522. lineSeparator = "\n";
  523. in.close();
  524. // Chop trailing newline and/or ^Z (if any)
  525. int bufferLength = seg.count;
  526. if(bufferLength != 0)
  527. {
  528. char ch = seg.array[bufferLength - 1];
  529. if(ch == 0x1a /* DOS ^Z */)
  530. seg.count--;
  531. }
  532. buffer.setBooleanProperty(Buffer.TRAILING_EOL,false);
  533. if(bufferLength != 0 && jEdit.getBooleanProperty("stripTrailingEOL"))
  534. {
  535. char ch = seg.array[bufferLength - 1];
  536. if(ch == '\n')
  537. {
  538. buffer.setBooleanProperty(Buffer.TRAILING_EOL,true);
  539. seg.count--;
  540. endOffsets.setSize(endOffsets.getSize() - 1);
  541. }
  542. }
  543. // add a line marker at the end for proper offset manager
  544. // operation
  545. endOffsets.add(seg.count + 1);
  546. // to avoid having to deal with read/write locks and such,
  547. // we insert the loaded data into the buffer in the
  548. // post-load cleanup runnable, which runs in the AWT thread.
  549. if(!insert)
  550. {
  551. buffer.setProperty(LOAD_DATA,seg);
  552. buffer.setProperty(END_OFFSETS,endOffsets);
  553. buffer.setProperty(NEW_PATH,path);
  554. if(lineSeparator != null)
  555. buffer.setProperty(Buffer.LINESEP,lineSeparator);
  556. }
  557. // used in insert()
  558. return seg;
  559. } //}}}
  560. //{{{ readMarkers() method
  561. private void readMarkers(Buffer buffer, InputStream _in)
  562. throws IOException
  563. {
  564. // For `reload' command
  565. buffer.removeAllMarkers();
  566. BufferedReader in = new BufferedReader(new InputStreamReader(_in));
  567. try
  568. {
  569. String line;
  570. while((line = in.readLine()) != null)
  571. {
  572. // compatibility kludge for jEdit 3.1 and earlier
  573. if(!line.startsWith("!"))
  574. continue;
  575. char shortcut = line.charAt(1);
  576. int start = line.indexOf(';');
  577. int end = line.indexOf(';',start + 1);
  578. int position = Integer.parseInt(line.substring(start + 1,end));
  579. buffer.addMarker(shortcut,position);
  580. }
  581. }
  582. finally
  583. {
  584. in.close();
  585. }
  586. } //}}}
  587. //{{{ save() method
  588. private void save()
  589. {
  590. OutputStream out = null;
  591. try
  592. {
  593. String[] args = { vfs.getFileName(path) };
  594. setStatus(jEdit.getProperty("vfs.status.save",args));
  595. // the entire save operation can be aborted...
  596. setAbortable(true);
  597. path = vfs._canonPath(session,path,view); if(!MiscUtilities.isURL(path))
  598. path = MiscUtilities.resolveSymlinks(path);
  599. // Only backup once per session
  600. if(buffer.getProperty(Buffer.BACKED_UP) == null
  601. || jEdit.getBooleanProperty("backupEverySave"))
  602. {
  603. vfs._backup(session,path,view);
  604. buffer.setBooleanProperty(Buffer.BACKED_UP,true);
  605. }
  606. /* if the VFS supports renaming files, we first
  607. * save to #<filename>#save#, then rename that
  608. * to <filename>, so that if the save fails,
  609. * data will not be lost.
  610. *
  611. * as of 4.1pre7 we now call vfs.getTwoStageSaveName()
  612. * instead of constructing the path directly
  613. * since some VFS's might not allow # in filenames.
  614. */
  615. String savePath;
  616. boolean twoStageSave = (vfs.getCapabilities() & VFS.RENAME_CAP) != 0
  617. && jEdit.getBooleanProperty("twoStageSave");
  618. if(twoStageSave)
  619. savePath = vfs.getTwoStageSaveName(path);
  620. else
  621. savePath = path;
  622. out = vfs._createOutputStream(session,savePath,view);
  623. try
  624. {
  625. // this must be after the stream is created or
  626. // we deadlock with SSHTools.
  627. buffer.readLock();
  628. if(out != null)
  629. {
  630. // Can't use buffer.getName() here because
  631. // it is not changed until the save is
  632. // complete
  633. if(savePath.endsWith(".gz"))
  634. buffer.setBooleanProperty(Buffer.GZIPPED,true);
  635. if(buffer.getBooleanProperty(Buffer.GZIPPED))
  636. out = new GZIPOutputStream(out);
  637. write(buffer,out);
  638. if(twoStageSave)
  639. {
  640. if(!vfs._rename(session,savePath,path,view))
  641. throw new IOException("Rename failed: " + savePath);
  642. }
  643. // We only save markers to VFS's that support deletion.
  644. // Otherwise, we will accumilate stale marks files.
  645. if((vfs.getCapabilities() & VFS.DELETE_CAP) != 0)
  646. {
  647. if(jEdit.getBooleanProperty("persistentMarkers")
  648. && buffer.getMarkers().size() != 0)
  649. {
  650. setStatus(jEdit.getProperty("vfs.status.save-markers",args));
  651. setProgressValue(0);
  652. out = vfs._createOutputStream(session,markersPath,view);
  653. if(out != null)
  654. writeMarkers(buffer,out);
  655. }
  656. else
  657. vfs._delete(session,markersPath,view);
  658. }
  659. }
  660. else
  661. buffer.setBooleanProperty(ERROR_OCCURRED,true);
  662. if(!twoStageSave)
  663. VFSManager.sendVFSUpdate(vfs,path,true);
  664. }
  665. finally
  666. {
  667. buffer.readUnlock();
  668. }
  669. }
  670. catch(IOException io)
  671. {
  672. Log.log(Log.ERROR,this,io);
  673. String[] pp = { io.toString() };
  674. VFSManager.error(view,path,"ioerror.write-error",pp);
  675. buffer.setBooleanProperty(ERROR_OCCURRED,true);
  676. }
  677. catch(WorkThread.Abort a)
  678. {
  679. if(out != null)
  680. {
  681. try
  682. {
  683. out.close();
  684. }
  685. catch(IOException io)
  686. {
  687. }
  688. }
  689. buffer.setBooleanProperty(ERROR_OCCURRED,true);
  690. }
  691. finally
  692. {
  693. try
  694. {
  695. vfs._saveComplete(session,buffer,path,view);
  696. vfs._endVFSSession(session,view);
  697. }
  698. catch(IOException io)
  699. {
  700. Log.log(Log.ERROR,this,io);
  701. String[] pp = { io.toString() };
  702. VFSManager.error(view,path,"ioerror.write-error",pp);
  703. buffer.setBooleanProperty(ERROR_OCCURRED,true);
  704. }
  705. catch(WorkThread.Abort a)
  706. {
  707. buffer.setBooleanProperty(ERROR_OCCURRED,true);
  708. }
  709. }
  710. } //}}}
  711. //{{{ autosave() method
  712. private void autosave()
  713. {
  714. OutputStream out = null;
  715. try
  716. {
  717. String[] args = { vfs.getFileName(path) };
  718. setStatus(jEdit.getProperty("vfs.status.autosave",args));
  719. // the entire save operation can be aborted...
  720. setAbortable(true);
  721. try
  722. {
  723. //buffer.readLock();
  724. if(!buffer.isDirty())
  725. {
  726. // buffer has been saved while we
  727. // were waiting.
  728. return;
  729. }
  730. out = vfs._createOutputStream(session,path,view);
  731. if(out == null)
  732. return;
  733. write(buffer,out);
  734. }
  735. catch(Exception e)
  736. {
  737. }
  738. finally
  739. {
  740. //buffer.readUnlock();
  741. }
  742. }
  743. catch(WorkThread.Abort a)
  744. {
  745. if(out != null)
  746. {
  747. try
  748. {
  749. out.close();
  750. }
  751. catch(IOException io)
  752. {
  753. }
  754. }
  755. }
  756. } //}}}
  757. //{{{ write() method
  758. private void write(Buffer buffer, OutputStream _out)
  759. throws IOException
  760. {
  761. BufferedWriter out = null;
  762. try
  763. {
  764. String encoding = buffer.getStringProperty(Buffer.ENCODING);
  765. if(encoding.equals(MiscUtilities.UTF_8_Y))
  766. {
  767. // not supported by Java...
  768. _out.write(UTF8_MAGIC_1);
  769. _out.write(UTF8_MAGIC_2);
  770. _out.write(UTF8_MAGIC_3);
  771. _out.flush();
  772. encoding = "UTF-8";
  773. }
  774. out = new BufferedWriter(
  775. new OutputStreamWriter(_out,encoding),
  776. IOBUFSIZE);
  777. Segment lineSegment = new Segment();
  778. String newline = buffer.getStringProperty(Buffer.LINESEP);
  779. if(newline == null)
  780. newline = System.getProperty("line.separator");
  781. setProgressMaximum(buffer.getLineCount() / PROGRESS_INTERVAL);
  782. setProgressValue(0);
  783. int i = 0;
  784. while(i < buffer.getLineCount())
  785. {
  786. buffer.getLineText(i,lineSegment);
  787. out.write(lineSegment.array,lineSegment.offset,
  788. lineSegment.count);
  789. if(i != buffer.getLineCount() - 1)
  790. {
  791. out.write(newline);
  792. }
  793. if(++i % PROGRESS_INTERVAL == 0)
  794. setProgressValue(i / PROGRESS_INTERVAL);
  795. }
  796. if(jEdit.getBooleanProperty("stripTrailingEOL")
  797. && buffer.getBooleanProperty(Buffer.TRAILING_EOL))
  798. {
  799. out.write(newline);
  800. }
  801. }
  802. finally
  803. {
  804. if(out != null)
  805. out.close();
  806. else
  807. _out.close();
  808. }
  809. } //}}}
  810. //{{{ writeMarkers() method
  811. private void writeMarkers(Buffer buffer, OutputStream out)
  812. throws IOException
  813. {
  814. Writer o = new BufferedWriter(new OutputStreamWriter(out));
  815. try
  816. {
  817. Vector markers = buffer.getMarkers();
  818. for(int i = 0; i < markers.size(); i++)
  819. {
  820. Marker marker = (Marker)markers.elementAt(i);
  821. o.write('!');
  822. o.write(marker.getShortcut());
  823. o.write(';');
  824. String pos = String.valueOf(marker.getPosition());
  825. o.write(pos);
  826. o.write(';');
  827. o.write(pos);
  828. o.write('\n');
  829. }
  830. }
  831. finally
  832. {
  833. o.close();
  834. }
  835. } //}}}
  836. //{{{ insert() method
  837. private void insert()
  838. {
  839. InputStream in = null;
  840. try
  841. {
  842. try
  843. {
  844. String[] args = { vfs.getFileName(path) };
  845. setStatus(jEdit.getProperty("vfs.status.load",args));
  846. setAbortable(true);
  847. path = vfs._canonPath(session,path,view);
  848. VFS.DirectoryEntry entry = vfs._getDirectoryEntry(
  849. session,path,view);
  850. long length;
  851. if(entry != null)
  852. length = entry.length;
  853. else
  854. length = 0L;
  855. in = vfs._createInputStream(session,path,false,view);
  856. if(in == null)
  857. return;
  858. final SegmentBuffer seg = read(
  859. autodetect(in),length,true);
  860. /* we don't do this in Buffer.insert() so that
  861. we can insert multiple files at once */
  862. VFSManager.runInAWTThread(new Runnable()
  863. {
  864. public void run()
  865. {
  866. view.getTextArea().setSelectedText(
  867. seg.toString());
  868. }
  869. });
  870. }
  871. catch(IOException io)
  872. {
  873. Log.log(Log.ERROR,this,io);
  874. String[] pp = { io.toString() };
  875. VFSManager.error(view,path,"ioerror.read-error",pp);
  876. buffer.setBooleanProperty(ERROR_OCCURRED,true);
  877. }
  878. }
  879. catch(WorkThread.Abort a)
  880. {
  881. if(in != null)
  882. {
  883. try
  884. {
  885. in.close();
  886. }
  887. catch(IOException io)
  888. {
  889. }
  890. }
  891. buffer.setBooleanProperty(ERROR_OCCURRED,true);
  892. }
  893. finally
  894. {
  895. try
  896. {
  897. vfs._endVFSSession(session,view);
  898. }
  899. catch(IOException io)
  900. {
  901. Log.log(Log.ERROR,this,io);
  902. String[] pp = { io.toString() };
  903. VFSManager.error(view,path,"ioerror.read-error",pp);
  904. buffer.setBooleanProperty(ERROR_OCCURRED,true);
  905. }
  906. catch(WorkThread.Abort a)
  907. {
  908. buffer.setBooleanProperty(ERROR_OCCURRED,true);
  909. }
  910. }
  911. } //}}}
  912. //}}}
  913. }