[Jsxe-cvs] SF.net SVN: jsxe: [1079] branches/jsxe2
Status: Inactive
Brought to you by:
ian_lewis
|
From: <ian...@us...> - 2006-07-27 19:00:15
|
Revision: 1079 Author: ian_lewis Date: 2006-07-27 11:59:59 -0700 (Thu, 27 Jul 2006) ViewCVS: http://svn.sourceforge.net/jsxe/?rev=1079&view=rev Log Message: ----------- Added classes for IO. Though they are ignored by the build atm Modified Paths: -------------- branches/jsxe2/build.xml Added Paths: ----------- branches/jsxe2/src/net/sourceforge/jsxe/dom2/ls/XMLDocumentIORequest.java branches/jsxe2/src/net/sourceforge/jsxe/io/ branches/jsxe2/src/net/sourceforge/jsxe/io/FileRootsVFS.java branches/jsxe2/src/net/sourceforge/jsxe/io/FileVFS.java branches/jsxe2/src/net/sourceforge/jsxe/io/UrlVFS.java branches/jsxe2/src/net/sourceforge/jsxe/io/VFS.java branches/jsxe2/src/net/sourceforge/jsxe/io/VFSManager.java branches/jsxe2/src/net/sourceforge/jsxe/io/package.html Modified: branches/jsxe2/build.xml =================================================================== --- branches/jsxe2/build.xml 2006-07-27 18:02:07 UTC (rev 1078) +++ branches/jsxe2/build.xml 2006-07-27 18:59:59 UTC (rev 1079) @@ -118,6 +118,10 @@ <!--<include name="**/*.dtd"/>--> <include name="**/*.jpg"/> <include name="**/*.png"/> + + <!-- files in the source directory to ignore --> + <exclude name="net/sourceforge/jsxe/dom2/ls/XMLDocumentIORequest.java"/> + <exclude name="net/sourceforge/jsxe/io/**/*"/> </fileset> </copy> <mkdir dir="${build.messages}"/> Added: branches/jsxe2/src/net/sourceforge/jsxe/dom2/ls/XMLDocumentIORequest.java =================================================================== --- branches/jsxe2/src/net/sourceforge/jsxe/dom2/ls/XMLDocumentIORequest.java (rev 0) +++ branches/jsxe2/src/net/sourceforge/jsxe/dom2/ls/XMLDocumentIORequest.java 2006-07-27 18:59:59 UTC (rev 1079) @@ -0,0 +1,1036 @@ +/* +XMLDocumentIORequest.java +:tabSize=4:indentSize=4:noTabs=true: +:folding=explicit:collapseFolds=1: + +Copyright (C) 2000, 2003 Slava Pestov +Copyright (C) 2006 Ian Lewis (Ian...@me...) + +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 (at your option) 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. +Optionally, you may find a copy of the GNU General Public License +from http://www.fsf.org/copyleft/gpl.txt +*/ + +package org.gjt.sp.jedit.buffer; + +//{{{ Imports +import 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 document I/O request. + * @author Slava Pestov + * @version $Id: BufferIORequest.java,v 1.28 2004/08/29 02:58:43 spestov Exp $ + */ +public class XMLDocumentIORequest 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.<p> + * <?xml version="1.0" encoding="................"?> + */ + public static final int XML_PI_LENGTH = 50; + //}}} + + //{{{ XMLDocumentIORequest 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 XMLDocumentIORequest(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); + // auto-detect encoding within the gzip stream. + return autodetect(in); + } + 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 + // trailing \n into account + lastLine = i + 1; + break; + case '\n': + // If lastWasCR is true, + // we just read a \r followed + // by a \n. We specify that + // this is a Windows file, + // but take no further + // action and just ignore + // the \r. + if(lastWasCR) + { + CROnly = false; + CRLF = true; + lastWasCR = false; + // Bump lastLine so + // that the next line + // doesn't erronously + // pick up the \r + lastLine = i + 1; + } + // Otherwise, we found a \n + // that follows some other + // character, hence we have + // a Unix file + else + { + CROnly = false; + CRLF = false; + seg.append(buf,lastLine, + i - lastLine); + seg.append('\n'); + endOffsets.add(seg.count); + if(trackProgress && lineCount++ % PROGRESS_INTERVAL == 0) + setProgressValue(seg.count); + lastLine = i + 1; + } + break; + default: + // If we find some other + // character that follows + // a \r, so it is not a + // Windows file, and probably + // a Mac file + if(lastWasCR) + { + CROnly = true; + CRLF = false; + lastWasCR = false; + } + break; + } + } + + if(trackProgress) + setProgressValue(seg.count); + + // Add remaining stuff from buffer + seg.append(buf,lastLine,len - lastLine); + } + + setAbortable(false); + + String lineSeparator; + if(seg.count == 0) + { + // fix for "[ 865589 ] 0-byte files should open using + // the default line seperator" + lineSeparator = jEdit.getProperty( + "buffer.lineSeparator", + System.getProperty("line.separator")); + } + else if(CRLF) + lineSeparator = "\r\n"; + else if(CROnly) + lineSeparator = "\r"; + else + lineSeparator = "\n"; + + in.close(); + + // Chop trailing newline and/or ^Z (if any) + int bufferLength = seg.count; + if(bufferLength != 0) + { + char ch = seg.array[bufferLength - 1]; + if(ch == 0x1a /* DOS ^Z */) + seg.count--; + } + + buffer.setBooleanProperty(Buffer.TRAILING_EOL,false); + if(bufferLength != 0 && jEdit.getBooleanProperty("stripTrailingEOL")) + { + char ch = seg.array[bufferLength - 1]; + if(ch == '\n') + { + buffer.setBooleanProperty(Buffer.TRAILING_EOL,true); + seg.count--; + endOffsets.setSize(endOffsets.getSize() - 1); + } + } + + // add a line marker at the end for proper offset manager + // operation + endOffsets.add(seg.count + 1); + + // to avoid having to deal with read/write locks and such, + // we insert the loaded data into the buffer in the + // post-load cleanup runnable, which runs in the AWT thread. + if(!insert) + { + buffer.setProperty(LOAD_DATA,seg); + buffer.setProperty(END_OFFSETS,endOffsets); + buffer.setProperty(NEW_PATH,path); + if(lineSeparator != null) + buffer.setProperty(Buffer.LINESEP,lineSeparator); + } + + // used in insert() + return seg; + } //}}} + + //{{{ readMarkers() method + private void readMarkers(Buffer buffer, InputStream _in) + throws IOException + { + // For `reload' command + buffer.removeAllMarkers(); + + BufferedReader in = new BufferedReader(new InputStreamReader(_in)); + + try + { + String line; + while((line = in.readLine()) != null) + { + // compatibility kludge for jEdit 3.1 and earlier + if(!line.startsWith("!")) + continue; + + char shortcut = line.charAt(1); + int start = line.indexOf(';'); + int end = line.indexOf(';',start + 1); + int position = Integer.parseInt(line.substring(start + 1,end)); + buffer.addMarker(shortcut,position); + } + } + finally + { + in.close(); + } + } //}}} + + //{{{ save() method + private void save() + { + OutputStream out = null; + + try + { + String[] args = { vfs.getFileName(path) }; + setStatus(jEdit.getProperty("vfs.status.save",args)); + + // the entire save operation can be aborted... + setAbortable(true); + + path = vfs._canonPath(session,path,view); if(!MiscUtilities.isURL(path)) + path = MiscUtilities.resolveSymlinks(path); + + // Only backup once per session + if(buffer.getProperty(Buffer.BACKED_UP) == null + || jEdit.getBooleanProperty("backupEverySave")) + { + vfs._backup(session,path,view); + buffer.setBooleanProperty(Buffer.BACKED_UP,true); + } + + /* if the VFS supports renaming files, we first + * save to #<filename>#save#, then rename that + * to <filename>, so that if the save fails, + * data will not be lost. + * + * as of 4.1pre7 we now call vfs.getTwoStageSaveName() + * instead of constructing the path directly + * since some VFS's might not allow # in filenames. + */ + String savePath; + + boolean twoStageSave = (vfs.getCapabilities() & VFS.RENAME_CAP) != 0 + && jEdit.getBooleanProperty("twoStageSave"); + if(twoStageSave) + savePath = vfs.getTwoStageSaveName(path); + else + savePath = path; + + out = vfs._createOutputStream(session,savePath,view); + + try + { + // this must be after the stream is created or + // we deadlock with SSHTools. + buffer.readLock(); + if(out != null) + { + // Can't use buffer.getName() here because + // it is not changed until the save is + // complete + if(savePath.endsWith(".gz")) + buffer.setBooleanProperty(Buffer.GZIPPED,true); + + if(buffer.getBooleanProperty(Buffer.GZIPPED)) + out = new GZIPOutputStream(out); + + write(buffer,out); + + if(twoStageSave) + { + if(!vfs._rename(session,savePath,path,view)) + throw new IOException("Rename failed: " + savePath); + } + + // We only save markers to VFS's that support deletion. + // Otherwise, we will accumilate stale marks files. + if((vfs.getCapabilities() & VFS.DELETE_CAP) != 0) + { + if(jEdit.getBooleanProperty("persistentMarkers") + && buffer.getMarkers().size() != 0) + { + setStatus(jEdit.getProperty("vfs.status.save-markers",args)); + setProgressValue(0); + out = vfs._createOutputStream(session,markersPath,view); + if(out != null) + writeMarkers(buffer,out); + } + else + vfs._delete(session,markersPath,view); + } + } + else + buffer.setBooleanProperty(ERROR_OCCURRED,true); + + if(!twoStageSave) + VFSManager.sendVFSUpdate(vfs,path,true); + } + finally + { + buffer.readUnlock(); + } + } + catch(IOException io) + { + Log.log(Log.ERROR,this,io); + String[] pp = { io.toString() }; + VFSManager.error(view,path,"ioerror.write-error",pp); + + buffer.setBooleanProperty(ERROR_OCCURRED,true); + } + catch(WorkThread.Abort a) + { + if(out != null) + { + try + { + out.close(); + } + catch(IOException io) + { + } + } + + buffer.setBooleanProperty(ERROR_OCCURRED,true); + } + finally + { + try + { + vfs._saveComplete(session,buffer,path,view); + vfs._endVFSSession(session,view); + } + catch(IOException io) + { + Log.log(Log.ERROR,this,io); + String[] pp = { io.toString() }; + VFSManager.error(view,path,"ioerror.write-error",pp); + + buffer.setBooleanProperty(ERROR_OCCURRED,true); + } + catch(WorkThread.Abort a) + { + buffer.setBooleanProperty(ERROR_OCCURRED,true); + } + } + } //}}} + + //{{{ autosave() method + private void autosave() + { + OutputStream out = null; + + try + { + String[] args = { vfs.getFileName(path) }; + setStatus(jEdit.getProperty("vfs.status.autosave",args)); + + // the entire save operation can be aborted... + setAbortable(true); + + try + { + //buffer.readLock(); + + if(!buffer.isDirty()) + { + // buffer has been saved while we + // were waiting. + return; + } + + out = vfs._createOutputStream(session,path,view); + if(out == null) + return; + + write(buffer,out); + } + catch(Exception e) + { + } + finally + { + //buffer.readUnlock(); + } + } + catch(WorkThread.Abort a) + { + if(out != null) + { + try + { + out.close(); + } + catch(IOException io) + { + } + } + } + } //}}} + + //{{{ write() method + private void write(Buffer buffer, OutputStream _out) + throws IOException + { + BufferedWriter out = null; + + try + { + String encoding = buffer.getStringProperty(Buffer.ENCODING); + if(encoding.equals(MiscUtilities.UTF_8_Y)) + { + // not supported by Java... + _out.write(UTF8_MAGIC_1); + _out.write(UTF8_MAGIC_2); + _out.write(UTF8_MAGIC_3); + _out.flush(); + encoding = "UTF-8"; + } + + out = new BufferedWriter( + new OutputStreamWriter(_out,encoding), + IOBUFSIZE); + + Segment lineSegment = new Segment(); + String newline = buffer.getStringProperty(Buffer.LINESEP); + if(newline == null) + newline = System.getProperty("line.separator"); + + setProgressMaximum(buffer.getLineCount() / PROGRESS_INTERVAL); + setProgressValue(0); + + int i = 0; + while(i < buffer.getLineCount()) + { + buffer.getLineText(i,lineSegment); + out.write(lineSegment.array,lineSegment.offset, + lineSegment.count); + + if(i != buffer.getLineCount() - 1) + { + out.write(newline); + } + + if(++i % PROGRESS_INTERVAL == 0) + setProgressValue(i / PROGRESS_INTERVAL); + } + + if(jEdit.getBooleanProperty("stripTrailingEOL") + && buffer.getBooleanProperty(Buffer.TRAILING_EOL)) + { + out.write(newline); + } + } + finally + { + if(out != null) + out.close(); + else + _out.close(); + } + } //}}} + + //{{{ writeMarkers() method + private void writeMarkers(Buffer buffer, OutputStream out) + throws IOException + { + Writer o = new BufferedWriter(new OutputStreamWriter(out)); + try + { + Vector markers = buffer.getMarkers(); + for(int i = 0; i < markers.size(); i++) + { + Marker marker = (Marker)markers.elementAt(i); + o.write('!'); + o.write(marker.getShortcut()); + o.write(';'); + + String pos = String.valueOf(marker.getPosition()); + o.write(pos); + o.write(';'); + o.write(pos); + o.write('\n'); + } + } + finally + { + o.close(); + } + } //}}} + + //{{{ insert() method + private void insert() + { + InputStream in = null; + + try + { + try + { + String[] args = { vfs.getFileName(path) }; + setStatus(jEdit.getProperty("vfs.status.load",args)); + setAbortable(true); + + 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; + + final SegmentBuffer seg = read( + autodetect(in),length,true); + + /* we don't do this in Buffer.insert() so that + we can insert multiple files at once */ + VFSManager.runInAWTThread(new Runnable() + { + public void run() + { + view.getTextArea().setSelectedText( + seg.toString()); + } + }); + } + 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) + { + 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); + } + } + } //}}} + + //}}} +} Property changes on: branches/jsxe2/src/net/sourceforge/jsxe/dom2/ls/XMLDocumentIORequest.java ___________________________________________________________________ Name: svn:executable + * Added: branches/jsxe2/src/net/sourceforge/jsxe/io/FileRootsVFS.java =================================================================== --- branches/jsxe2/src/net/sourceforge/jsxe/io/FileRootsVFS.java (rev 0) +++ branches/jsxe2/src/net/sourceforge/jsxe/io/FileRootsVFS.java 2006-07-27 18:59:59 UTC (rev 1079) @@ -0,0 +1,256 @@ +/* +FileVFS.java +:tabSize=4:indentSize=4:noTabs=true: +:folding=explicit:collapseFolds=1: + +Copyright (C) 2000, 2003 Slava Pestov +Portions copyright (C) 2002 Kris Kopicki +Portions copyright (C) 2002 Carmine Lucarelli +Portions Copyright (C) 2004 Ian Lewis (Ian...@me...) + +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 (at your option) 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. +Optionally, you may find a copy of the GNU General Public License +from http://www.fsf.org/copyleft/gpl.txt +*/ + +package org.gjt.sp.jedit.io; + +//{{{ Imports +import javax.swing.filechooser.FileSystemView; +import java.awt.Component; +import java.lang.reflect.*; +import java.io.File; +import java.util.LinkedList; +import net.sourceforge.jsxe.util.MiscUtilities; +import net.sourceforge.jsxe.OperatingSystem; +import net.sourceforge.jsxe.util.Log; +//}}} + +/** + * A VFS that lists local root filesystems. + * @author Slava Pestov + * @author Kris Kopicki + * @author Carmine Lucarelli + * @author Ian Lewis (<a href="mailto:Ian...@me...">Ian...@me...</a>) + * @version $Id$ + * @since jsXe 0.5 pre3 + */ +public class FileRootsVFS extends VFS { + + public static final String PROTOCOL = "roots"; + + //{{{ FileRootsVFS constructor + public FileRootsVFS() { + + super("roots",LOW_LATENCY_CAP,new String[] { + EA_TYPE }); + + try { + getSystemDisplayName = FileSystemView.class.getMethod("getSystemDisplayName", + new Class[] { java.io.File.class }); + getRoots = FileSystemView.class.getMethod("getRoots", + new Class[0]); + isFileSystemRoot = FileSystemView.class.getMethod("isFileSystemRoot", + new Class[] { java.io.File.class }); + isFloppyDrive = FileSystemView.class.getMethod("isFloppyDrive", + new Class[] { java.io.File.class }); + isDrive = FileSystemView.class.getMethod("isDrive", + new Class[] { java.io.File.class }); + fsView = FileSystemView.getFileSystemView(); + Log.log(Log.DEBUG,this,"Java 1.4 FileSystemView detected"); + } + catch(Exception e) + { + Log.log(Log.DEBUG,this,"Java 1.4 FileSystemView not detected"); + } + } //}}} + + //{{{ getParentOfPath() method + public String getParentOfPath(String path) { + return PROTOCOL + ":"; + } //}}} + + //{{{ _listDirectory() method + public VFS.DirectoryEntry[] _listDirectory(Object session, String url, + Component comp) + { + File[] roots = listRoots(); + + if (roots == null) { + return null; + } + + VFS.DirectoryEntry[] rootDE = new VFS.DirectoryEntry[roots.length]; + for (int i = 0; i < roots.length; i++) { + rootDE[i] = new RootsEntry(roots[i]); + } + + return rootDE; + } //}}} + + //{{{ _getDirectoryEntry() method + public DirectoryEntry _getDirectoryEntry(Object session, String path, + Component comp) + { + return new RootsEntry(new File(path)); + } //}}} + + //{{{ Private members + private static FileSystemView fsView; + private static Method getSystemDisplayName; + private static Method getRoots; + private static Method isFileSystemRoot; + private static Method isFloppyDrive; + private static Method isDrive; + + //{{{ listRoots() method + private static File[] listRoots() { + + if (OperatingSystem.isMacOS()) { + // Nasty hardcoded values + File[] volumes = new File("/Volumes").listFiles(); + LinkedList roots = new LinkedList(); + + roots.add(new File("/")); + + for (int i=0; i<volumes.length; i++) { + // Make sure people don't do stupid things like putting files in /Volumes + if (volumes[i].isDirectory()) + roots.add(volumes[i]); + } + + return (File[])roots.toArray(new File[0]); + } else { + File[] roots = File.listRoots(); + File[] desktop = null; + + if (getRoots != null) { + try { + desktop = (File[])getRoots.invoke(fsView, + new Object[0]); + } catch(Exception e) { + Log.log(Log.ERROR, FileRootsVFS.class, "Error getting Desktop: " + e.getMessage()); + desktop = null; + } + } + + if (desktop == null) { + return roots; + } + + File[] rootsPlus = new File[roots.length + desktop.length]; + System.arraycopy(desktop, 0, rootsPlus, 0, desktop.length); + System.arraycopy(roots, 0, rootsPlus, 1, roots.length); + return rootsPlus; + } + } //}}} + + //}}} + + //{{{ RootsEntry class + static class RootsEntry extends VFS.DirectoryEntry { + + RootsEntry(File file) { + // REMIND: calling isDirectory() on a floppy drive + // displays stupid I/O error dialog box on Windows + + this.path = this.deletePath = this.symlinkPath = file.getPath(); + + if (isFloppy(file)) { + type = VFS.DirectoryEntry.FILESYSTEM; + name = path; + } else { + if(isDrive(file)) { + + type = VFS.DirectoryEntry.FILESYSTEM; + + if (getSystemDisplayName != null) { + try { + name = path + " " + (String)getSystemDisplayName + .invoke(fsView,new Object[] { file }); + } catch(Exception e) { + Log.log(Log.ERROR,this,e); + name = path; + } + } + } else { + if (file.isDirectory()) { + + type = VFS.DirectoryEntry.FILESYSTEM; + + if (isFileSystemRoot != null) { + try { + if (Boolean.FALSE.equals(isFileSystemRoot + .invoke(fsView,new Object[] { file }))) + { + type = VFS.DirectoryEntry.DIRECTORY; + } + } + catch(Exception e) {} + } + + if (OperatingSystem.isMacOS()) { + name = MiscUtilities.getFileName(path); + } else { + name = path; + } + } else { + type = VFS.DirectoryEntry.FILE; + } + } + } + } + + public String getExtendedAttribute(String name) { + if (name.equals(EA_TYPE)) { + return super.getExtendedAttribute(name); + } else { + // don't want it to show "0 bytes" for size, + // etc. + return null; + } + } + + private boolean isFloppy(File file) { + // to prevent windows looking for a disk in the floppy drive + if (isFloppyDrive != null) { + try { + return Boolean.TRUE.equals(isFloppyDrive. + invoke(fsView, new Object[] { file })); + } catch(Exception e) { + Log.log(Log.ERROR,this,e); + return false; + } + } else { + return path.startsWith("A:") || path.startsWith("B:"); + } + } + + private boolean isDrive(File file) { + // so an empty cd drive is not reported as a file + if (isDrive != null) { + try { + return Boolean.TRUE.equals(isDrive. + invoke(fsView, new Object[] { file })); + } catch(Exception e) { + Log.log(Log.ERROR,this,e); + return false; + } + } else { + return true; + } + } + } //}}} +} Property changes on: branches/jsxe2/src/net/sourceforge/jsxe/io/FileRootsVFS.java ___________________________________________________________________ Name: svn:executable + * Added: branches/jsxe2/src/net/sourceforge/jsxe/io/FileVFS.java =================================================================== --- branches/jsxe2/src/net/sourceforge/jsxe/io/FileVFS.java (rev 0) +++ branches/jsxe2/src/net/sourceforge/jsxe/io/FileVFS.java 2006-07-27 18:59:59 UTC (rev 1079) @@ -0,0 +1,483 @@ +/* +FileVFS.java +:tabSize=4:indentSize=4:noTabs=true: +:folding=explicit:collapseFolds=1: + +Copyright (C) 1998, 1999, 2000, 2001, 2002 Slava Pestov +Portions Copyright (C) 2004 Ian Lewis (Ian...@me...) + +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 (at your option) 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. +Optionally, you may find a copy of the GNU General Public License +from http://www.fsf.org/copyleft/gpl.txt +*/ + +package net.sourceforge.jsxe.io; + +//{{{ Imports +import java.awt.Component; +import java.io.*; +import java.text.*; +import java.util.Date; +import net.sourceforge.jsxe.util.Log; +//}}} + +/** + * Local filesystem VFS. + * @author Slava Pestov + * @author Ian Lewis (<a href="mailto:Ian...@me...">Ian...@me...</a>) + * @since jsXe 0.5 pre3 + * @version $Id: FileVFS.java,v 1.47 2004/06/09 16:48:40 spestov Exp $ + */ +public class FileVFS extends VFS { + + public static final String PERMISSIONS_PROPERTY = "FileVFS__perms"; + + //{{{ FileVFS method + public FileVFS() + { + super("file",READ_CAP | WRITE_CAP | DELETE_CAP + | RENAME_CAP | MKDIR_CAP | LOW_LATENCY_CAP + | ((OperatingSystem.isMacOS() + || OperatingSystem.isDOSDerived()) + ? CASE_INSENSITIVE_CAP : 0), + new String[] { EA_TYPE, EA_SIZE, EA_STATUS, + EA_MODIFIED }); + } //}}} + + //{{{ getParentOfPath() method + public String getParentOfPath(String path) + { + if(OperatingSystem.isDOSDerived()) + { + if(path.length() == 2 && path.charAt(1) == ':') + return FileRootsVFS.PROTOCOL + ":"; + else if(path.length() == 3 && path.endsWith(":\\")) + return FileRootsVFS.PROTOCOL + ":"; + else if(path.startsWith("\\\\") && path.indexOf('\\',2) == -1) + return path; + } + + return super.getParentOfPath(path); + } //}}} + + //{{{ constructPath() method + public String constructPath(String parent, String path) + { + if(parent.endsWith(File.separator) + || parent.endsWith("/")) + return parent + path; + else + return parent + File.separator + path; + } //}}} + + //{{{ getFileSeparator() method + public char getFileSeparator() + { + return File.separatorChar; + } //}}} + + //{{{ save() method + public boolean save(View view, Buffer buffer, String path) + { + if(OperatingSystem.isUnix()) + { + int permissions = getPermissions(buffer.getPath()); + Log.log(Log.DEBUG,this,buffer.getPath() + " has permissions 0" + + Integer.toString(permissions,8)); + buffer.setIntegerProperty(PERMISSIONS_PROPERTY,permissions); + } + + return super.save(view,buffer,path); + } //}}} + + //{{{ insert() method + public boolean insert(View view, Buffer buffer, String path) + { + File file = new File(path); + + //{{{ Check if file is valid + if(!file.exists()) + return false; + + if(file.isDirectory()) + { + VFSManager.error(view,file.getPath(), + "ioerror.open-directory",null); + return false; + } + + if(!file.canRead()) + { + VFSManager.error(view,file.getPath(), + "ioerror.no-read",null); + return false; + } //}}} + + return super.insert(view,buffer,path); + } //}}} + + //{{{ _canonPath() method + /** + * Returns the canonical form if the specified path name. For example, + * <code>~</code> might be expanded to the user's home directory. + * @param session The session + * @param path The path + * @param comp The component that will parent error dialog boxes + * @exception IOException if an I/O error occurred + */ + public String _canonPath(Object session, String path, Component comp) + throws IOException + { + return MiscUtilities.canonPath(path); + } //}}} + + //{{{ LocalDirectoryEntry class + public static class LocalDirectoryEntry extends VFS.DirectoryEntry + { + // use system default short format + public static DateFormat DATE_FORMAT + = DateFormat.getInstance(); + + public long modified; + + public LocalDirectoryEntry(File file) + { + super(file.getName(),file.getPath(), + file.getPath(),file.isDirectory() ? DIRECTORY : FILE,file.length(),file.isHidden()); + this.modified = file.lastModified(); + this.canRead = file.canRead(); + this.canWrite = file.canWrite(); + this.symlinkPath = MiscUtilities.resolveSymlinks(path); + } + + public String getExtendedAttribute(String name) + { + if(name.equals(EA_MODIFIED)) + return DATE_FORMAT.format(new Date(modified)); + else + return super.getExtendedAttribute(name); + } + } //}}} + + //{{{ _listDirectory() method + public VFS.DirectoryEntry[] _listDirectory(Object session, String path, + Component comp) + { + //{{{ Windows work around + /* On Windows, paths of the form X: list the last *working + * directory* on that drive. To list the root of the drive, + * you must use X:\. + * + * However, the VFS browser and friends strip off trailing + * path separators, for various reasons. So to work around + * that, we add a '\' to drive letter paths on Windows. + */ + if(OperatingSystem.isWindows()) + { + if(path.length() == 2 && path.charAt(1) == ':') + path = path.concat(File.separator); + } //}}} + + File directory = new File(path); + File[] list = directory.listFiles(); + if(list == null) + { + VFSManager.error(comp,path,"ioerror.directory-error-nomsg",null); + return null; + } + + VFS.DirectoryEntry[] list2 = new VFS.DirectoryEntry[list.length]; + for(int i = 0; i < list.length; i++) + list2[i] = new LocalDirectoryEntry(list[i]); + + return list2; + } //}}} + + //{{{ _getDirectoryEntry() method + public DirectoryEntry _getDirectoryEntry(Object session, String path, + Component comp) + { + if(path.equals("/") && OperatingSystem.isUnix()) + { + return new VFS.DirectoryEntry(path,path,path, + VFS.DirectoryEntry.DIRECTORY,0L,false); + } + + File file = new File(path); + if(!file.exists()) + return null; + + return new LocalDirectoryEntry(file); + } //}}} + + //{{{ _delete() method + public boolean _delete(Object session, String path, Component comp) + { + File file = new File(path); + // do some platforms throw exceptions if the file does not exist + // when we ask for the canonical path? + String canonPath; + try + { + canonPath = file.getCanonicalPath(); + } + catch(IOException io) + { + canonPath = path; + } + + boolean retVal = file.delete(); + if(retVal) + VFSManager.sendVFSUpdate(this,canonPath,true); + return retVal; + } //}}} + + //{{{ _rename() method + public boolean _rename(Object session, String from, String to, + Component comp) + { + File _to = new File(to); + + String toCanonPath; + try + { + toCanonPath = _to.getCanonicalPath(); + } + catch(IOException io) + { + toCanonPath = to; + } + + // this is needed because on OS X renaming to a non-existent + // directory causes problems + File parent = new File(_to.getParent()); + if(parent.exists()) + { + if(!parent.isDirectory()) + return false; + } + else + { + parent.mkdirs(); + if(!parent.exists()) + return false; + } + + File _from = new File(from); + + String fromCanonPath; + try + { + fromCanonPath = _from.getCanonicalPath(); + } + catch(IOException io) + { + fromCanonPath = from; + } + + // Case-insensitive fs workaround + if(!fromCanonPath.equalsIgnoreCase(toCanonPath)) + _to.delete(); + + boolean retVal = _from.renameTo(_to); + VFSManager.sendVFSUpdate(this,fromCanonPath,true); + VFSManager.sendVFSUpdate(this,toCanonPath,true); + return retVal; + } //}}} + + //{{{ _mkdir() method + public boolean _mkdir(Object session, String directory, Component comp) + { + String parent = getParentOfPath(directory); + if(!new File(parent).exists()) + { + if(!_mkdir(session,parent,comp)) + return false; + } + + File file = new File(directory); + + boolean retVal = file.mkdir(); + String canonPath; + try + { + canonPath = file.getCanonicalPath(); + } + catch(IOException io) + { + canonPath = directory; + } + VFSManager.sendVFSUpdate(this,canonPath,true); + return retVal; + } //}}} + + //{{{ _backup() method + public void _backup(Object session, String path, Component comp) + throws IOException + { + // Fetch properties + int backups = jEdit.getIntegerProperty("backups",1); + + if(backups == 0) + return; + + String backupPrefix = jEdit.getProperty("backup.prefix"); + String backupSuffix = jEdit.getProperty("backup.suffix"); + + String backupDirectory = jEdit.getProperty("backup.directory"); + + int backupTimeDistance = jEdit.getIntegerProperty("backup.minTime",0); + File file = new File(path); + + // Check for backup.directory, and create that + // directory if it doesn't exist + if(backupDirectory == null || backupDirectory.length() == 0) + backupDirectory = file.getParent(); + else + { + backupDirectory = MiscUtilities.constructPath( + System.getProperty("user.home"),backupDirectory); + + // Perhaps here we would want to guard with + // a property for parallel backups or not. + backupDirectory = MiscUtilities.concatPath( + backupDirectory,file.getParent()); + + File dir = new File(backupDirectory); + + if (!dir.exists()) + dir.mkdirs(); + } + + MiscUtilities.saveBackup(file,backups,backupPrefix, + backupSuffix,backupDirectory,backupTimeDistance); + } //}}} + + //{{{ _createInputStream() method + public InputStream _createInputStream(Object session, String path, + boolean ignoreErrors, Component comp) throws IOException + { + try + { + return new FileInputStream(path); + } + catch(IOException io) + { + if(ignoreErrors) + return null; + else + throw io; + } + } //}}} + + //{{{ _createOutputStream() method + public OutputStream _createOutputStream(Object session, String path, + Component comp) throws IOException + { + return new FileOutputStream(path); + } //}}} + + //{{{ _saveComplete() method + public void _saveComplete(Object session, Buffer buffer, String path, + Component comp) + { + int permissions = buffer.getIntegerProperty(PERMISSIONS_PROPERTY,0); + setPermissions(path,permissions); + } //}}} + + //{{{ Permission preservation code + + /** Code borrowed from j text editor (http://www.armedbear.org) */ + /** I made some changes to make it support suid, sgid and sticky files */ + + //{{{ getPermissions() method + /** + * Returns numeric permissions of a file. On non-Unix systems, always + * returns zero. + */ + public static int getPermissions(String path) { + int permissions = 0; + + if (jEdit.getBooleanProperty("chmodDisabled")) { + return permissions; + } + + if (OperatingSystem.isUnix()) { + String[] cmdarray = { "ls", "-ld", path }; + + try { + Process process = Runtime.getRuntime().exec(cmdarray); + + BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); + + String output = reader.readLine(); + + if (output != null) { + String s = output.substring(1, 10); + + permissions = MiscUtilities.parsePermissions(s); + } + } + + // Feb 4 2000 5:30 PM + // Catch Throwable here rather than Exception. + // Kaffe's implementation of Runtime.exec throws java.lang.InternalError. + catch (Throwable t) + { + } + } + + return permissions; + } //}}} + + //{{{ setPermissions() method + /** + * Sets numeric permissions of a file. On non-Unix platforms, + * does nothing. + */ + public static void setPermissions(String path, int permissions) { + if (jEdit.getBooleanProperty("chmodDisabled")) + return; + + if (permissions != 0) { + if (OperatingSystem.isUnix()) { + + String[] cmdarray = { "chmod", Integer.toString(permissions, 8), path }; + + try { + Process process = Runtime.getRuntime().exec(cmdarray); + process.getInputStream().close(); + process.getOutputStream().close(); + process.getErrorStream().close(); + // Jun 9 2004 12:40 PM + // waitFor() hangs on some Java + // implementations. + /* int exitCode = process.waitFor(); + if(exitCode != 0) + Log.log(Log.NOTICE,FileVFS.class,"chmod exited with code " + exitCode); */ + } + + // Feb 4 2000 5:30 PM + // Catch Throwable here rather than Exception. + // Kaffe's implementation of Runtime.exec throws java.lang.InternalError. + catch (Throwable t) + { + } + } + } + } //}}} + + //}}} +} Property changes on: branches/jsxe2/src/net/sourceforge/jsxe/io/FileVFS.java ___________________________________________________________________ Name: svn:executable + * Added: branches/jsxe2/src/net/sourceforge/jsxe/io/UrlVFS.java =================================================================== --- branches/jsxe2/src/net/sourceforge/jsxe/io/UrlVFS.java (rev 0) +++ branches/jsxe2/src/net/sourceforge/jsxe/io/UrlVFS.java 2006-07-27 18:59:59 UTC (rev 1079) @@ -0,0 +... [truncated message content] |