KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > gjt > sp > jedit > bufferio > BufferIORequest


1 /*
2  * BufferIORequest.java - I/O request
3  * :tabSize=8:indentSize=8:noTabs=false:
4  * :folding=explicit:collapseFolds=1:
5  *
6  * Copyright (C) 2000, 2004 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
23 package org.gjt.sp.jedit.bufferio;
24
25 //{{{ Imports
26
import javax.swing.text.Segment JavaDoc;
27 import java.io.*;
28 import java.nio.charset.*;
29 import java.nio.CharBuffer JavaDoc;
30 import java.nio.ByteBuffer JavaDoc;
31 import org.gjt.sp.jedit.io.*;
32 import org.gjt.sp.jedit.*;
33 import org.gjt.sp.jedit.buffer.JEditBuffer;
34 import org.gjt.sp.util.*;
35 //}}}
36

37 /**
38  * A buffer I/O request.
39  * @author Slava Pestov
40  * @version $Id: BufferIORequest.java 8592 2007-01-15 20:10:19Z kpouer $
41  */

42 public abstract class BufferIORequest extends WorkRequest
43 {
44     //{{{ Constants
45
public static final int UTF8_MAGIC_1 = 0xef;
46     public static final int UTF8_MAGIC_2 = 0xbb;
47     public static final int UTF8_MAGIC_3 = 0xbf;
48
49     /**
50      * Magic numbers used for auto-detecting Unicode and GZIP files.
51      */

52     public static final int GZIP_MAGIC_1 = 0x1f;
53     public static final int GZIP_MAGIC_2 = 0x8b;
54     public static final int UNICODE_MAGIC_1 = 0xfe;
55     public static final int UNICODE_MAGIC_2 = 0xff;
56
57     /**
58      * Length of longest XML PI used for encoding detection.<p>
59      * &lt;?xml version="1.0" encoding="................"?&gt;
60      */

61     public static final int XML_PI_LENGTH = 50;
62
63     /**
64      * Size of I/O buffers.
65      */

66     public static final int IOBUFSIZE = 32768;
67
68     /**
69      * Number of lines per progress increment.
70      */

71     public static final int PROGRESS_INTERVAL = 300;
72
73     public static final String JavaDoc LOAD_DATA = "BufferIORequest__loadData";
74     public static final String JavaDoc END_OFFSETS = "BufferIORequest__endOffsets";
75     public static final String JavaDoc NEW_PATH = "BufferIORequest__newPath";
76
77     /**
78      * Buffer boolean property set when an error occurs.
79      */

80     public static final String JavaDoc ERROR_OCCURRED = "BufferIORequest__error";
81
82     //}}}
83

84     //{{{ BufferIORequest constructor
85
/**
86      * Creates a new buffer I/O request.
87      * @param view The view
88      * @param buffer The buffer
89      * @param session The VFS session
90      * @param vfs The VFS
91      * @param path The path
92      */

93     protected BufferIORequest(View view, Buffer JavaDoc buffer,
94         Object JavaDoc session, VFS vfs, String JavaDoc path)
95     {
96         this.view = view;
97         this.buffer = buffer;
98         this.session = session;
99         this.vfs = vfs;
100         this.path = path;
101
102         markersPath = vfs.getParentOfPath(path)
103             + '.' + vfs.getFileName(path)
104             + ".marks";
105     } //}}}
106

107     //{{{ toString() method
108
public String JavaDoc toString()
109     {
110         return getClass().getName() + '[' + buffer + ']';
111     } //}}}
112

113     //{{{ Private members
114

115     //{{{ Instance variables
116
protected final View view;
117     protected final Buffer JavaDoc buffer;
118     protected final Object JavaDoc session;
119     protected final VFS vfs;
120     protected String JavaDoc path;
121     protected final String JavaDoc markersPath;
122     //}}}
123

124     //{{{ autodetect() method
125
/**
126      * Tries to detect if the stream is gzipped, and if it has an encoding
127      * specified with an XML PI.
128      */

129     protected Reader autodetect(InputStream in) throws IOException
130     {
131         return MiscUtilities.autodetect(in, buffer);
132     } //}}}
133

134     //{{{ read() method
135
protected SegmentBuffer read(Reader in, long length,
136         boolean insert) throws IOException
137     {
138         /* we guess an initial size for the array */
139         IntegerArray endOffsets = new IntegerArray(
140             Math.max(1,(int)(length / 50)));
141
142         // only true if the file size is known
143
boolean trackProgress = !buffer.isTemporary() && length != 0;
144
145         if(trackProgress)
146         {
147             setMaximum(length);
148             setValue(0);
149         }
150
151         // if the file size is not known, start with a resonable
152
// default buffer size
153
if(length == 0)
154             length = IOBUFSIZE;
155
156         SegmentBuffer seg = new SegmentBuffer((int)length + 1);
157
158         char[] buf = new char[IOBUFSIZE];
159
160         // Number of characters in 'buf' array.
161
// InputStream.read() doesn't always fill the
162
// array (eg, the file size is not a multiple of
163
// IOBUFSIZE, or it is a GZipped file, etc)
164
int len;
165
166         // True if a \n was read after a \r. Usually
167
// means this is a DOS/Windows file
168
boolean CRLF = false;
169
170         // A \r was read, hence a MacOS file
171
boolean CROnly = false;
172
173         // Was the previous read character a \r?
174
// If we read a \n and this is true, we assume
175
// we have a DOS/Windows file
176
boolean lastWasCR = false;
177
178         // Number of lines read. Every 100 lines, we update the
179
// progress bar
180
int lineCount = 0;
181
182         while((len = in.read(buf,0,buf.length)) != -1)
183         {
184             // Offset of previous line, relative to
185
// the start of the I/O buffer (NOT
186
// relative to the start of the document)
187
int lastLine = 0;
188
189             for(int i = 0; i < len; i++)
190             {
191                 // Look for line endings.
192
switch(buf[i])
193                 {
194                 case '\r':
195                     // If we read a \r and
196
// lastWasCR is also true,
197
// it is probably a Mac file
198
// (\r\r in stream)
199
if(lastWasCR)
200                     {
201                         CROnly = true;
202                         CRLF = false;
203                     }
204                     // Otherwise set a flag,
205
// so that \n knows that last
206
// was a \r
207
else
208                     {
209                         lastWasCR = true;
210                     }
211
212                     // Insert a line
213
seg.append(buf,lastLine,i -
214                         lastLine);
215                     seg.append('\n');
216                     endOffsets.add(seg.count);
217                     if(trackProgress && lineCount++ % PROGRESS_INTERVAL == 0)
218                         setValue(seg.count);
219
220                     // This is i+1 to take the
221
// trailing \n into account
222
lastLine = i + 1;
223                     break;
224                 case '\n':
225                     // If lastWasCR is true,
226
// we just read a \r followed
227
// by a \n. We specify that
228
// this is a Windows file,
229
// but take no further
230
// action and just ignore
231
// the \r.
232
if(lastWasCR)
233                     {
234                         CROnly = false;
235                         CRLF = true;
236                         lastWasCR = false;
237                         // Bump lastLine so
238
// that the next line
239
// doesn't erronously
240
// pick up the \r
241
lastLine = i + 1;
242                     }
243                     // Otherwise, we found a \n
244
// that follows some other
245
// character, hence we have
246
// a Unix file
247
else
248                     {
249                         CROnly = false;
250                         CRLF = false;
251                         seg.append(buf,lastLine,
252                             i - lastLine);
253                         seg.append('\n');
254                         endOffsets.add(seg.count);
255                         if(trackProgress && lineCount++ % PROGRESS_INTERVAL == 0)
256                             setValue(seg.count);
257                         lastLine = i + 1;
258                     }
259                     break;
260                 default:
261                     // If we find some other
262
// character that follows
263
// a \r, so it is not a
264
// Windows file, and probably
265
// a Mac file
266
if(lastWasCR)
267                     {
268                         CROnly = true;
269                         CRLF = false;
270                         lastWasCR = false;
271                     }
272                     break;
273                 }
274             }
275
276             if(trackProgress)
277                 setValue(seg.count);
278
279             // Add remaining stuff from buffer
280
seg.append(buf,lastLine,len - lastLine);
281         }
282
283         setAbortable(false);
284
285         String JavaDoc lineSeparator;
286         if(seg.count == 0)
287         {
288             // fix for "[ 865589 ] 0-byte files should open using
289
// the default line seperator"
290
lineSeparator = jEdit.getProperty(
291                 "buffer.lineSeparator",
292                 System.getProperty("line.separator"));
293         }
294         else if(CRLF)
295             lineSeparator = "\r\n";
296         else if(CROnly)
297             lineSeparator = "\r";
298         else
299             lineSeparator = "\n";
300
301         in.close();
302
303         // Chop trailing newline and/or ^Z (if any)
304
int bufferLength = seg.count;
305         if(bufferLength != 0)
306         {
307             char ch = seg.array[bufferLength - 1];
308             if(ch == 0x1a /* DOS ^Z */)
309                 seg.count--;
310         }
311
312         buffer.setBooleanProperty(Buffer.TRAILING_EOL,false);
313         if(bufferLength != 0 && jEdit.getBooleanProperty("stripTrailingEOL"))
314         {
315             char ch = seg.array[bufferLength - 1];
316             if(ch == '\n')
317             {
318                 buffer.setBooleanProperty(Buffer.TRAILING_EOL,true);
319                 seg.count--;
320                 endOffsets.setSize(endOffsets.getSize() - 1);
321             }
322         }
323
324         // add a line marker at the end for proper offset manager
325
// operation
326
endOffsets.add(seg.count + 1);
327
328         // to avoid having to deal with read/write locks and such,
329
// we insert the loaded data into the buffer in the
330
// post-load cleanup runnable, which runs in the AWT thread.
331
if(!insert)
332         {
333             buffer.setProperty(LOAD_DATA,seg);
334             buffer.setProperty(END_OFFSETS,endOffsets);
335             buffer.setProperty(NEW_PATH,path);
336             if(lineSeparator != null)
337                 buffer.setProperty(JEditBuffer.LINESEP,lineSeparator);
338         }
339
340         // used in insert()
341
return seg;
342     } //}}}
343

344     //{{{ write() method
345
protected void write(Buffer JavaDoc buffer, OutputStream out)
346         throws IOException
347     {
348         try
349         {
350             out = new BufferedOutputStream(out);
351             String JavaDoc encoding = buffer.getStringProperty(JEditBuffer.ENCODING);
352             if(encoding.equals(MiscUtilities.UTF_8_Y))
353             {
354                 // not supported by Java...
355
out.write(UTF8_MAGIC_1);
356                 out.write(UTF8_MAGIC_2);
357                 out.write(UTF8_MAGIC_3);
358                 out.flush();
359                 encoding = "UTF-8";
360             }
361             else if (encoding.equals("UTF-16LE"))
362             {
363                 out.write(UNICODE_MAGIC_2);
364                 out.write(UNICODE_MAGIC_1);
365                 out.flush();
366             }
367             else if (encoding.equals("UTF-16BE"))
368             {
369                 out.write(UNICODE_MAGIC_1);
370                 out.write(UNICODE_MAGIC_2);
371                 out.flush();
372             }
373             CharsetEncoder encoder = Charset.forName(encoding).newEncoder();
374
375             Segment JavaDoc lineSegment = new Segment JavaDoc();
376             String JavaDoc newline = buffer.getStringProperty(JEditBuffer.LINESEP);
377             if(newline == null)
378                 newline = System.getProperty("line.separator");
379             // Convert newline to bytes here to not get bothered
380
// with encoding at every newline.
381
ByteBuffer JavaDoc newlineBuffer = encoder.encode(CharBuffer.wrap(newline));
382             byte[] newlineBytes = new byte[newlineBuffer.limit()];
383             newlineBuffer.get(newlineBytes);
384             encoder.reset();
385
386             // This buffer is required to report encoding error
387
// with the line number. Without this, some lines are
388
// buffered in the Writer, and encoded together when
389
// the Writer is flushed.
390
ByteArrayOutputStream lineBuffer = new ByteArrayOutputStream(IOBUFSIZE);
391             // Pass the encoder explicitly to report a encode error
392
// as an exception.
393
// The form "OutputStreamWriter(..., encoding)" seemed
394
// to use CodingErrorAction.REPLACE internally.
395
Writer lineWriter = new OutputStreamWriter(lineBuffer, encoder);
396
397             setMaximum(buffer.getLineCount() / PROGRESS_INTERVAL);
398             setValue(0);
399
400             int i = 0;
401             while(i < buffer.getLineCount())
402             {
403                 buffer.getLineText(i,lineSegment);
404                 try
405                 {
406                     lineWriter.write(lineSegment.array,
407                         lineSegment.offset,
408                         lineSegment.count);
409                     lineWriter.flush();
410                 }
411                 catch(CharacterCodingException e)
412                 {
413                     String JavaDoc message = "Failed to encode the line " + (i + 1);
414                     IOException wrapping = new CharConversionException(message);
415                     wrapping.initCause(e);
416                     throw wrapping;
417                 }
418                 lineBuffer.writeTo(out);
419                 lineBuffer.reset();
420
421                 if(i != buffer.getLineCount() - 1)
422                 {
423                     out.write(newlineBytes);
424                 }
425
426                 if(++i % PROGRESS_INTERVAL == 0)
427                     setValue(i / PROGRESS_INTERVAL);
428             }
429
430             if(jEdit.getBooleanProperty("stripTrailingEOL")
431                 && buffer.getBooleanProperty(Buffer.TRAILING_EOL))
432             {
433                 out.write(newlineBytes);
434             }
435         }
436         finally
437         {
438             IOUtilities.closeQuietly(out);
439         }
440     } //}}}
441

442     //}}}
443
}
444
Popular Tags