001: /*
002: * BufferLoadRequest.java - I/O request
003: * :tabSize=8:indentSize=8:noTabs=false:
004: * :folding=explicit:collapseFolds=1:
005: *
006: * Copyright (C) 2000, 2005 Slava Pestov
007: *
008: * This program is free software; you can redistribute it and/or
009: * modify it under the terms of the GNU General Public License
010: * as published by the Free Software Foundation; either version 2
011: * of the License, or any later version.
012: *
013: * This program is distributed in the hope that it will be useful,
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016: * GNU General Public License for more details.
017: *
018: * You should have received a copy of the GNU General Public License
019: * along with this program; if not, write to the Free Software
020: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
021: */
022:
023: package org.gjt.sp.jedit.bufferio;
024:
025: //{{{ Imports
026: import java.io.*;
027: import java.nio.charset.*;
028: import java.util.List;
029: import java.util.ArrayList;
030: import java.util.Set;
031: import java.util.HashSet;
032: import java.util.zip.GZIPInputStream;
033: import org.gjt.sp.jedit.io.*;
034: import org.gjt.sp.jedit.*;
035: import org.gjt.sp.jedit.buffer.JEditBuffer;
036: import org.gjt.sp.util.*;
037:
038: //}}}
039:
040: /**
041: * A buffer load request.
042: * @author Slava Pestov
043: * @version $Id: BufferLoadRequest.java 9855 2007-06-26 14:22:49Z k_satoda $
044: */
045: public class BufferLoadRequest extends BufferIORequest {
046: //{{{ BufferLoadRequest constructor
047: /**
048: * Creates a new buffer I/O request.
049: * @param view The view
050: * @param buffer The buffer
051: * @param session The VFS session
052: * @param vfs The VFS
053: * @param path The path
054: */
055: public BufferLoadRequest(View view, Buffer buffer, Object session,
056: VFS vfs, String path) {
057: super (view, buffer, session, vfs, path);
058: } //}}}
059:
060: //{{{ run() method
061: public void run() {
062: try {
063: setAbortable(true);
064: if (!buffer.isTemporary()) {
065: String[] args = { vfs.getFileName(path) };
066: setStatus(jEdit.getProperty("vfs.status.load", args));
067: setValue(0L);
068: }
069:
070: path = vfs._canonPath(session, path, view);
071:
072: readContents();
073: buffer.setNewFile(false);
074:
075: if (jEdit.getBooleanProperty("persistentMarkers")
076: && (vfs.isMarkersFileSupported())) {
077: InputStream markers = null;
078: try {
079: String[] args = { vfs.getFileName(path) };
080: if (!buffer.isTemporary())
081: setStatus(jEdit.getProperty(
082: "vfs.status.load-markers", args));
083: setAbortable(true);
084:
085: markers = vfs._createInputStream(session,
086: markersPath, true, view);
087: if (markers != null)
088: readMarkers(buffer, markers);
089: } catch (Exception e) {
090: // ignore
091: } finally {
092: IOUtilities.closeQuietly(markers);
093: }
094: }
095: } catch (Exception e) {
096: Log.log(Log.ERROR, this , e);
097: Object[] pp = { e.toString() };
098: VFSManager.error(view, path, "ioerror.read-error", pp);
099:
100: buffer.setBooleanProperty(ERROR_OCCURRED, true);
101: } catch (OutOfMemoryError oom) {
102: Log.log(Log.ERROR, this , oom);
103: VFSManager.error(view, path, "out-of-memory-error", null);
104:
105: buffer.setBooleanProperty(ERROR_OCCURRED, true);
106: } catch (WorkThread.Abort a) {
107: buffer.setBooleanProperty(ERROR_OCCURRED, true);
108: } finally {
109: try {
110: vfs._endVFSSession(session, view);
111: } catch (Exception e) {
112: Log.log(Log.ERROR, this , e);
113: String[] pp = { e.toString() };
114: VFSManager.error(view, path, "ioerror.read-error", pp);
115:
116: buffer.setBooleanProperty(ERROR_OCCURRED, true);
117: } catch (WorkThread.Abort a) {
118: buffer.setBooleanProperty(ERROR_OCCURRED, true);
119: }
120: }
121: } //}}}
122:
123: //{{{ getNakedStream() method
124: /**
125: * Returns the raw contents stream for this load request.
126: * This stream is not buffered or unzipped.
127: */
128: private InputStream getNakedStream() throws IOException {
129: InputStream in = vfs._createInputStream(session, path, false,
130: view);
131: if (in != null) {
132: return in;
133: }
134: throw new IOException("Unable to get a Stream for " + path);
135: } //}}}
136:
137: //{{{ getContentLength() method
138: /**
139: * Returns content length of this load request.
140: */
141: private long getContentLength() throws IOException {
142: VFSFile entry = vfs._getFile(session, path, view);
143: if (entry != null)
144: return entry.getLength();
145: else
146: return 0L;
147: } //}}}
148:
149: //{{{ rewindContentsStream() method
150: /**
151: * Returns rewinded contents stream.
152: * This method assumes the marked stream was made by
153: * getMarkedStream() method. The stream may be reopened if reset()
154: * failed.
155: */
156: private BufferedInputStream rewindContentsStream(
157: BufferedInputStream markedStream, boolean gzipped)
158: throws IOException {
159: try {
160: markedStream.reset();
161: return markedStream;
162: } catch (IOException e) {
163: Log.log(Log.NOTICE, this , path
164: + ": Reopening to rewind the stream");
165: // Reopen the stream because the mark has been
166: // invalidated while previous reading.
167: markedStream.close();
168: InputStream in = getNakedStream();
169: try {
170: if (gzipped) {
171: in = new GZIPInputStream(in);
172: }
173: BufferedInputStream result = AutoDetection
174: .getMarkedStream(in);
175: in = null;
176: return result;
177: } finally {
178: IOUtilities.closeQuietly(in);
179: }
180: }
181: } //}}}
182:
183: //{{{ readContents() method
184: /**
185: * Read the contents of this load request.
186: * Some auto detection is performed if enabled.
187: * - GZIPed file
188: * - The encoding
189: * If fallback encodings are specified, they are used on
190: * encoding errors.
191: */
192: private void readContents() throws IOException {
193: long length = getContentLength();
194:
195: BufferedInputStream markedStream = AutoDetection
196: .getMarkedStream(getNakedStream());
197: try {
198: boolean gzipped = false;
199: // encodingProviders is consist of given
200: // encodings as String or contents-aware
201: // detectors as EncodingDetector.
202: List<Object> encodingProviders = new ArrayList<Object>();
203:
204: boolean autodetect = buffer
205: .getBooleanProperty(Buffer.ENCODING_AUTODETECT);
206: if (autodetect) {
207: gzipped = AutoDetection.isGzipped(markedStream);
208: markedStream.reset();
209:
210: encodingProviders.addAll(AutoDetection
211: .getEncodingDetectors());
212: // If the detected encoding fail, fallback to
213: // the original encoding.
214: encodingProviders.add(buffer
215: .getStringProperty(Buffer.ENCODING));
216:
217: String fallbackEncodings = jEdit
218: .getProperty("fallbackEncodings");
219: if (fallbackEncodings != null
220: && fallbackEncodings.length() > 0) {
221: for (String encoding : fallbackEncodings
222: .split("\\s+")) {
223: encodingProviders.add(encoding);
224: }
225: }
226: } else {
227: gzipped = buffer.getBooleanProperty(Buffer.GZIPPED);
228: encodingProviders.add(buffer
229: .getStringProperty(Buffer.ENCODING));
230: }
231:
232: if (gzipped) {
233: Log.log(Log.DEBUG, this , path + ": Stream is gzipped.");
234: markedStream = AutoDetection
235: .getMarkedStream(new GZIPInputStream(
236: markedStream));
237: }
238:
239: Set<String> failedEncodings = new HashSet<String>();
240: Exception encodingError = null;
241: for (Object encodingProvider : encodingProviders) {
242: String encoding = null;
243: if (encodingProvider instanceof String) {
244: encoding = (String) encodingProvider;
245: } else if (encodingProvider instanceof EncodingDetector) {
246: markedStream = rewindContentsStream(markedStream,
247: gzipped);
248: encoding = ((EncodingDetector) encodingProvider)
249: .detectEncoding(new BufferedInputStream(
250: markedStream));
251: } else {
252: Log.log(Log.DEBUG, this ,
253: "Strange encodingProvider: "
254: + encodingProvider);
255: }
256:
257: if (encoding == null || encoding.length() <= 0
258: || failedEncodings.contains(encoding)) {
259: continue;
260: }
261:
262: markedStream = rewindContentsStream(markedStream,
263: gzipped);
264: try {
265: read(EncodingServer.getTextReader(markedStream,
266: encoding), length, false);
267: if (autodetect) {
268: // Store the successful properties.
269: if (gzipped) {
270: buffer.setBooleanProperty(Buffer.GZIPPED,
271: true);
272: }
273: buffer.setProperty(Buffer.ENCODING, encoding);
274: }
275: return;
276: } catch (CharConversionException e) {
277: encodingError = e;
278: } catch (CharacterCodingException e) {
279: encodingError = e;
280: } catch (UnsupportedEncodingException e) {
281: encodingError = e;
282: } catch (UnsupportedCharsetException e) {
283: encodingError = e;
284: }
285: Log.log(Log.NOTICE, this , path + ": " + encoding + ": "
286: + encodingError);
287: failedEncodings.add(encoding);
288: }
289: // All possible detectors and encodings failed.
290: Object[] pp = { TextUtilities.join(failedEncodings, ","),
291: "" };
292: if (failedEncodings.size() < 2) {
293: pp[1] = encodingError.toString();
294: } else {
295: pp[1] = "See details in Activity Log";
296: }
297: VFSManager.error(view, path, "ioerror.encoding-error", pp);
298: buffer.setBooleanProperty(ERROR_OCCURRED, true);
299: } finally {
300: markedStream.close();
301: }
302: } //}}}
303:
304: //{{{ readMarkers() method
305: private static void readMarkers(Buffer buffer, InputStream _in)
306: throws IOException {
307: // For `reload' command
308: buffer.removeAllMarkers();
309:
310: BufferedReader in = new BufferedReader(new InputStreamReader(
311: _in));
312:
313: try {
314: String line;
315: while ((line = in.readLine()) != null) {
316: // malformed marks file?
317: if (line.length() == 0)
318: continue;
319:
320: // compatibility kludge for jEdit 3.1 and earlier
321: if (line.charAt(0) != '!')
322: continue;
323:
324: char shortcut = line.charAt(1);
325: int start = line.indexOf(';');
326: int end = line.indexOf(';', start + 1);
327: int position = Integer.parseInt(line.substring(
328: start + 1, end));
329: buffer.addMarker(shortcut, position);
330: }
331: buffer.setMarkersChanged(false);
332: } finally {
333: in.close();
334: }
335: } //}}}
336: }
|