📄 bufferiorequest.java
字号:
/* * BufferIORequest.java - I/O request * :tabSize=8:indentSize=8:noTabs=false: * :folding=explicit:collapseFolds=1: * * Copyright (C) 2000, 2003 Slava Pestov * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */package org.gjt.sp.jedit.buffer;//{{{ Importsimport javax.swing.text.Segment;import java.io.*;import java.util.zip.*;import java.util.Vector;import org.gjt.sp.jedit.io.*;import org.gjt.sp.jedit.*;import org.gjt.sp.util.*;//}}}/** * A buffer I/O request. * @author Slava Pestov * @version $Id: BufferIORequest.java,v 1.24 2003/12/27 05:13:54 spestov Exp $ */public class BufferIORequest extends WorkRequest{ //{{{ Constants /** * Size of I/O buffers. */ public static final int IOBUFSIZE = 32768; /** * Number of lines per progress increment. */ public static final int PROGRESS_INTERVAL = 300; public static final String LOAD_DATA = "BufferIORequest__loadData"; public static final String END_OFFSETS = "BufferIORequest__endOffsets"; public static final String NEW_PATH = "BufferIORequest__newPath"; /** * Buffer boolean property set when an error occurs. */ public static final String ERROR_OCCURRED = "BufferIORequest__error"; /** * A file load request. */ public static final int LOAD = 0; /** * A file save request. */ public static final int SAVE = 1; /** * An autosave request. Only supported for local files. */ public static final int AUTOSAVE = 2; /** * An insert file request. */ public static final int INSERT = 3; /** * Magic numbers used for auto-detecting Unicode and GZIP files. */ public static final int GZIP_MAGIC_1 = 0x1f; public static final int GZIP_MAGIC_2 = 0x8b; public static final int UNICODE_MAGIC_1 = 0xfe; public static final int UNICODE_MAGIC_2 = 0xff; public static final int UTF8_MAGIC_1 = 0xef; public static final int UTF8_MAGIC_2 = 0xbb; public static final int UTF8_MAGIC_3 = 0xbf; /** * Length of longest XML PI used for encoding detection. * <?xml version="1.0" encoding="................"?> */ public static final int XML_PI_LENGTH = 50; //}}} //{{{ BufferIORequest constructor /** * Creates a new buffer I/O request. * @param type The request type * @param view The view * @param buffer The buffer * @param session The VFS session * @param vfs The VFS * @param path The path */ public BufferIORequest(int type, View view, Buffer buffer, Object session, VFS vfs, String path) { this.type = type; this.view = view; this.buffer = buffer; this.session = session; this.vfs = vfs; this.path = path; markersPath = vfs.getParentOfPath(path) + '.' + vfs.getFileName(path) + ".marks"; } //}}} //{{{ run() method public void run() { switch(type) { case LOAD: load(); break; case SAVE: save(); break; case AUTOSAVE: autosave(); break; case INSERT: insert(); break; default: throw new InternalError(); } } //}}} //{{{ toString() method public String toString() { String typeString; switch(type) { case LOAD: typeString = "LOAD"; break; case SAVE: typeString = "SAVE"; break; case AUTOSAVE: typeString = "AUTOSAVE"; break; default: typeString = "UNKNOWN!!!"; } return getClass().getName() + "[type=" + typeString + ",buffer=" + buffer + "]"; } //}}} //{{{ Private members //{{{ Instance variables private int type; private View view; private Buffer buffer; private Object session; private VFS vfs; private String path; private String markersPath; //}}} //{{{ load() method private void load() { InputStream in = null; try { try { String[] args = { vfs.getFileName(path) }; setAbortable(true); if(!buffer.isTemporary()) { setStatus(jEdit.getProperty("vfs.status.load",args)); setProgressValue(0); } path = vfs._canonPath(session,path,view); VFS.DirectoryEntry entry = vfs._getDirectoryEntry( session,path,view); long length; if(entry != null) length = entry.length; else length = 0L; in = vfs._createInputStream(session,path, false,view); if(in == null) return; read(autodetect(in),length,false); buffer.setNewFile(false); } catch(CharConversionException ch) { Log.log(Log.ERROR,this,ch); Object[] pp = { buffer.getProperty(Buffer.ENCODING), ch.toString() }; VFSManager.error(view,path,"ioerror.encoding-error",pp); buffer.setBooleanProperty(ERROR_OCCURRED,true); } catch(UnsupportedEncodingException uu) { Log.log(Log.ERROR,this,uu); Object[] pp = { buffer.getProperty(Buffer.ENCODING), uu.toString() }; VFSManager.error(view,path,"ioerror.encoding-error",pp); buffer.setBooleanProperty(ERROR_OCCURRED,true); } catch(IOException io) { Log.log(Log.ERROR,this,io); Object[] pp = { io.toString() }; VFSManager.error(view,path,"ioerror.read-error",pp); buffer.setBooleanProperty(ERROR_OCCURRED,true); } catch(OutOfMemoryError oom) { Log.log(Log.ERROR,this,oom); VFSManager.error(view,path,"out-of-memory-error",null); buffer.setBooleanProperty(ERROR_OCCURRED,true); } if(jEdit.getBooleanProperty("persistentMarkers")) { try { String[] args = { vfs.getFileName(path) }; if(!buffer.isTemporary()) setStatus(jEdit.getProperty("vfs.status.load-markers",args)); setAbortable(true); in = vfs._createInputStream(session,markersPath,true,view); if(in != null) readMarkers(buffer,in); } catch(IOException io) { // ignore } } } catch(WorkThread.Abort a) { if(in != null) { try { in.close(); } catch(IOException io) { } } buffer.setBooleanProperty(ERROR_OCCURRED,true); } finally { try { vfs._endVFSSession(session,view); } catch(IOException io) { Log.log(Log.ERROR,this,io); String[] pp = { io.toString() }; VFSManager.error(view,path,"ioerror.read-error",pp); buffer.setBooleanProperty(ERROR_OCCURRED,true); } catch(WorkThread.Abort a) { buffer.setBooleanProperty(ERROR_OCCURRED,true); } } } //}}} //{{{ autodetect() method /** * Tries to detect if the stream is gzipped, and if it has an encoding * specified with an XML PI. */ private Reader autodetect(InputStream in) throws IOException { in = new BufferedInputStream(in); String encoding = buffer.getStringProperty(Buffer.ENCODING); if(!in.markSupported()) Log.log(Log.WARNING,this,"Mark not supported: " + in); else if(buffer.getBooleanProperty(Buffer.ENCODING_AUTODETECT)) { in.mark(XML_PI_LENGTH); int b1 = in.read(); int b2 = in.read(); int b3 = in.read(); if(encoding.equals(MiscUtilities.UTF_8_Y)) { // Java does not support this encoding so // we have to handle it manually. if(b1 != UTF8_MAGIC_1 || b2 != UTF8_MAGIC_2 || b3 != UTF8_MAGIC_3) { // file does not begin with UTF-8-Y // signature. reset stream, read as // UTF-8. in.reset(); } else { // file begins with UTF-8-Y signature. // discard the signature, and read // the remainder as UTF-8. } encoding = "UTF-8"; } else if(b1 == GZIP_MAGIC_1 && b2 == GZIP_MAGIC_2) { in.reset(); in = new GZIPInputStream(in); buffer.setBooleanProperty(Buffer.GZIPPED,true); } else if((b1 == UNICODE_MAGIC_1 && b2 == UNICODE_MAGIC_2) || (b1 == UNICODE_MAGIC_2 && b2 == UNICODE_MAGIC_1)) { in.reset(); encoding = "UTF-16"; buffer.setProperty(Buffer.ENCODING,encoding); } else if(b1 == UTF8_MAGIC_1 && b2 == UTF8_MAGIC_2 && b3 == UTF8_MAGIC_3) { // do not reset the stream and just treat it // like a normal UTF-8 file. buffer.setProperty(Buffer.ENCODING, MiscUtilities.UTF_8_Y); encoding = "UTF-8"; } else { in.reset(); byte[] _xmlPI = new byte[XML_PI_LENGTH]; int offset = 0; int count; while((count = in.read(_xmlPI,offset, XML_PI_LENGTH - offset)) != -1) { offset += count; if(offset == XML_PI_LENGTH) break; } String xmlPI = new String(_xmlPI,0,offset, "ASCII"); if(xmlPI.startsWith("<?xml")) { int index = xmlPI.indexOf("encoding="); if(index != -1 && index + 9 != xmlPI.length()) { char ch = xmlPI.charAt(index + 9); int endIndex = xmlPI.indexOf(ch, index + 10); encoding = xmlPI.substring( index + 10,endIndex); if(MiscUtilities.isSupportedEncoding(encoding)) { buffer.setProperty(Buffer.ENCODING,encoding); } else { Log.log(Log.WARNING,this,"XML PI specifies unsupported encoding: " + encoding); } } } in.reset(); } } return new InputStreamReader(in,encoding); } //}}} //{{{ read() method private SegmentBuffer read(Reader in, long length, boolean insert) throws IOException { /* we guess an initial size for the array */ IntegerArray endOffsets = new IntegerArray( Math.max(1,(int)(length / 50))); // only true if the file size is known boolean trackProgress = (!buffer.isTemporary() && length != 0); if(trackProgress) { setProgressValue(0); setProgressMaximum((int)length); } // if the file size is not known, start with a resonable // default buffer size if(length == 0) length = IOBUFSIZE; SegmentBuffer seg = new SegmentBuffer((int)length + 1); char[] buf = new char[IOBUFSIZE]; // Number of characters in 'buf' array. // InputStream.read() doesn't always fill the // array (eg, the file size is not a multiple of // IOBUFSIZE, or it is a GZipped file, etc) int len; // True if a \n was read after a \r. Usually // means this is a DOS/Windows file boolean CRLF = false; // A \r was read, hence a MacOS file boolean CROnly = false; // Was the previous read character a \r? // If we read a \n and this is true, we assume // we have a DOS/Windows file boolean lastWasCR = false; // Number of lines read. Every 100 lines, we update the // progress bar int lineCount = 0; while((len = in.read(buf,0,buf.length)) != -1) { // Offset of previous line, relative to // the start of the I/O buffer (NOT // relative to the start of the document) int lastLine = 0; for(int i = 0; i < len; i++) { // Look for line endings. switch(buf[i]) { case '\r': // If we read a \r and // lastWasCR is also true, // it is probably a Mac file // (\r\r in stream) if(lastWasCR) { CROnly = true; CRLF = false; } // Otherwise set a flag, // so that \n knows that last // was a \r else { lastWasCR = true; } // Insert a line seg.append(buf,lastLine,i - lastLine); seg.append('\n'); endOffsets.add(seg.count); if(trackProgress && lineCount++ % PROGRESS_INTERVAL == 0) setProgressValue(seg.count); // This is i+1 to take the
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -