KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > editor > LineSeparatorConversion


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.editor;
21
22 import java.io.IOException JavaDoc;
23 import java.io.Reader JavaDoc;
24 import javax.swing.text.Segment JavaDoc;
25
26 /**
27  * Converters handling the various line separators.
28  *
29  * @author Miloslav Metelka
30  * @version 1.00
31  */

32
33 public class LineSeparatorConversion {
34
35     /**
36      * Default size of the conversion buffers.
37      */

38     private static final int DEFAULT_CONVERSION_BUFFER_SIZE = 16384;
39
40     private LineSeparatorConversion() {
41         // no instances
42
}
43
44     /**
45      * Convert all the occurrences of '\r' and '\r\n' in the text to '\n'.
46      * @param text text being converted
47      * @return converted text with '\n' instead of '\r' and '\r\n'.
48      */

49     public static String JavaDoc convertToLineFeed(String JavaDoc text) {
50         StringBuffer JavaDoc output = new StringBuffer JavaDoc();
51         convertToLineFeed(text, 0, text.length(), output);
52         return output.toString();
53     }
54     
55     /**
56      * Convert all the occurrences of '\r' and '\r\n' in the text to '\n'.
57      * @param text text being converted
58      * @param offset offset of the first character in the text to be converted.
59      * @param length number of characters to be converted.
60      * @param output output buffer to which the converted characters are added.
61      */

62     public static void convertToLineFeed(String JavaDoc text, int offset, int length,
63     StringBuffer JavaDoc output) {
64
65         int endOffset = offset + length;
66         boolean lastCharCR = false; // whether last char was '\r'
67

68         while (offset < endOffset) {
69             char ch = text.charAt(offset++);
70             if (lastCharCR && ch == '\n') { // found CRLF sequence
71
lastCharCR = false;
72
73             } else { // not CRLF sequence
74
if (ch == '\r') {
75                     output.append('\n');
76                     lastCharCR = true;
77
78                 } else { // current char not '\r'
79
lastCharCR = false;
80                     output.append(ch);
81                 }
82             }
83         }
84     }
85
86     /**
87      * Convert all the occurrences of '\n' in the given text
88      * to the requested line separator.
89      * @param text text being converted
90      * @param lineFeedReplace characters that replace the '\n' character
91      * in the converted text.
92      * @return converted text with replaced '\n' by characters from lineFeedReplace string
93      */

94     public static String JavaDoc convertFromLineFeed(String JavaDoc text, String JavaDoc lineFeedReplace) {
95         StringBuffer JavaDoc output = new StringBuffer JavaDoc();
96         convertFromLineFeed(text, 0, text.length(), lineFeedReplace, output);
97         return output.toString();
98     }
99
100     /**
101      * Convert all the occurrences of '\n' in the given text
102      * to the requested line separator.
103      * @param text text being converted
104      * @param offset offset of the first character in the text to be converted.
105      * @param length number of characters to be converted.
106      * @param lineFeedReplace characters that replace the '\n' character in the output
107      * @param output output buffer to which the converted characters are added.
108      */

109     public static void convertFromLineFeed(String JavaDoc text, int offset, int length,
110     String JavaDoc lineFeedReplace, StringBuffer JavaDoc output) {
111         int lineFeedReplaceLength = lineFeedReplace.length();
112         int endOffset = offset + length;
113         while (offset < endOffset) {
114             char ch = text.charAt(offset++);
115             if (ch == '\n') {
116                 for (int i = 0; i < lineFeedReplaceLength; i++) {
117                     output.append(lineFeedReplace.charAt(i));
118                 }
119             } else {
120                 output.append(ch);
121             }
122         }
123     }
124
125     /**
126      * Convert all the occurrences of '\r' and '\r\n' in the text to '\n'.
127      * This class does conversion in chunks of fixed size
128      * and is therefore suitable for conversion of readers
129      * where the size is unknown.
130      */

131     public static class ToLineFeed {
132         
133         private Reader JavaDoc reader;
134         
135         private Segment JavaDoc convertedText;
136         
137         private boolean lastCharCR;
138
139         public ToLineFeed(Reader JavaDoc reader) {
140             this(reader, DEFAULT_CONVERSION_BUFFER_SIZE);
141         }
142
143         public ToLineFeed(Reader JavaDoc reader, int convertBufferSize) {
144             this.reader = reader;
145             convertedText = new Segment JavaDoc();
146             convertedText.array = new char[convertBufferSize];
147         }
148         
149         public Segment JavaDoc nextConverted() throws IOException JavaDoc {
150             if (reader == null) { // no more chars to read
151
return null;
152             }
153
154             int readOffset = 0;
155             int readSize = readBuffer(reader, convertedText.array, readOffset, true);
156             
157             if (readSize == 0) { // no more chars in reader
158
reader.close();
159                 reader = null;
160                 return null;
161             }
162
163             if (lastCharCR && readSize > 0 && convertedText.array[readOffset] == '\n') {
164                 /* the preceding '\r' was already converted to '\n'
165                  * in the previous buffer so here just skip initial '\n'
166                  */

167                 readOffset++;
168                 readSize--;
169             }
170
171             convertedText.offset = readOffset;
172             convertedText.count = readSize;
173             lastCharCR = convertSegmentToLineFeed(convertedText);
174             return convertedText;
175         }
176         
177         /**
178          * Convert all the '\r\n' or '\r' to '\n' (linefeed).
179          * This method
180          * @param text the text to be converted. Text is converted
181          * in the original array of the given segment.
182          * The <CODE>count</CODE> field
183          * of the text parameter will possibly be changed by the conversion
184          * if '\r\n' sequences are present.
185          * @return whether the last character in the text was the '\r' character.
186          * That character was already converted to '\n' and is present
187          * in the segment. However this notification is important
188          * because if there would be '\n' at the begining
189          * of the next buffer then that character should be skipped.
190          */

191         private static boolean convertSegmentToLineFeed(Segment JavaDoc text) {
192             char[] chars = text.array;
193             int storeOffset = text.offset; // offset at which chars are stored
194
int endOffset = storeOffset + text.count;
195             boolean storeChar = false; // to prevent copying same chars to same offsets
196
boolean lastCharCR = false; // whether last char was '\r'
197

198             for (int offset = storeOffset; offset < endOffset; offset++) {
199                 char ch = chars[offset];
200
201                 if (lastCharCR && ch == '\n') { // found CRLF sequence
202
lastCharCR = false;
203                     storeChar = true; // storeOffset now differs from offset
204

205                 } else { // not CRLF sequence
206
if (ch == '\r') {
207                         lastCharCR = true;
208                         chars[storeOffset++] = '\n'; // convert it to '\n'
209

210                     } else { // current char not '\r'
211
lastCharCR = false;
212                         if (storeChar) {
213                             chars[storeOffset] = ch;
214                         }
215                         storeOffset++;
216                     }
217                 }
218             }
219
220             text.count = storeOffset - text.offset;
221
222             return lastCharCR;
223         }
224
225         private static int readBuffer(Reader JavaDoc reader, char[] buffer, int offset,
226         boolean joinReads) throws IOException JavaDoc {
227             int maxReadSize = buffer.length - offset;
228             int totalReadSize = 0;
229
230             do {
231                 int readSize = 0;
232                 while (readSize == 0) { // eliminate empty reads
233
readSize = reader.read(buffer, offset, maxReadSize);
234                 }
235
236                 if (readSize == -1) {
237                     break; // no more chars in reader
238
}
239
240                 totalReadSize += readSize;
241                 offset += readSize;
242                 maxReadSize -= readSize;
243
244             } while (joinReads && maxReadSize > 0);
245
246             return totalReadSize;
247         }
248
249     }
250
251     /**
252      * Convert all the occurrences of '\n' in the given text
253      * to the requested line separator.
254      * This class does conversion in chunks of fixed size
255      * and is therefore suitable for conversion of large
256      * texts.
257      */

258     public static class FromLineFeed {
259         
260         private Object JavaDoc charArrayOrSequence;
261         
262         private int offset;
263         
264         private int endOffset;
265         
266         private String JavaDoc lineFeedReplace;
267
268         private Segment JavaDoc convertedText;
269         
270         public FromLineFeed(char[] source, int offset, int length,
271         String JavaDoc lineFeedReplace) {
272             this(source, offset, length, lineFeedReplace, DEFAULT_CONVERSION_BUFFER_SIZE);
273         }
274
275         public FromLineFeed(char[] source, int offset, int length,
276         String JavaDoc lineFeedReplace, int conversionSegmentSize) {
277             this((Object JavaDoc)source, offset, length, lineFeedReplace, conversionSegmentSize);
278         }
279
280         public FromLineFeed(String JavaDoc text, int offset, int length,
281         String JavaDoc lineFeedReplace) {
282             this(text, offset, length, lineFeedReplace, DEFAULT_CONVERSION_BUFFER_SIZE);
283         }
284
285         public FromLineFeed(String JavaDoc text, int offset, int length,
286         String JavaDoc lineFeedReplace, int conversionSegmentSize) {
287             this((Object JavaDoc)text, offset, length, lineFeedReplace, conversionSegmentSize);
288         }
289
290         private FromLineFeed(Object JavaDoc charArrayOrSequence, int offset, int length,
291         String JavaDoc lineFeedReplace, int conversionSegmentSize) {
292             
293             if (conversionSegmentSize < lineFeedReplace.length()) {
294                 throw new IllegalArgumentException JavaDoc("conversionSegmentSize=" // NOI18N
295
+ conversionSegmentSize + " < lineFeedReplace.length()=" // NOI18N
296
+ lineFeedReplace.length()
297                 );
298             }
299
300             this.charArrayOrSequence = charArrayOrSequence;
301             this.offset = offset;
302             this.endOffset = offset + length;
303             this.lineFeedReplace = lineFeedReplace;
304
305             convertedText = new Segment JavaDoc();
306             convertedText.array = new char[conversionSegmentSize];
307         }
308
309         public Segment JavaDoc nextConverted() {
310             if (offset == endOffset) { // no more chars to convert
311
return null;
312             }
313
314             // [PENDING-PERF] optimization for '\n' -> arraycopy
315

316             char[] convertedArray = convertedText.array;
317             int convertedArrayLength = convertedArray.length;
318             int convertedOffset = 0;
319
320             /* Determine whether the source is char-sequence
321              * or char buffer.
322              * Assign either sourceText or sourceArray but not both.
323              */

324             String JavaDoc sourceText;
325             char[] sourceArray;
326             if (charArrayOrSequence instanceof String JavaDoc) {
327                 sourceText = (String JavaDoc)charArrayOrSequence;
328                 sourceArray = null;
329
330             } else {
331                 sourceArray = (char[])charArrayOrSequence;
332                 sourceText = null;
333             }
334
335             int lineFeedReplaceLength = lineFeedReplace.length();
336             while (offset < endOffset
337                 && convertedArrayLength - convertedOffset >= lineFeedReplaceLength
338             ) {
339                 char ch = (sourceText != null)
340                     ? sourceText.charAt(offset++)
341                     : sourceArray[offset++];
342
343                 if (ch == '\n') {
344                     for (int i = 0; i < lineFeedReplaceLength; i++) {
345                         convertedArray[convertedOffset++] = lineFeedReplace.charAt(i);
346                     }
347                     
348
349                 } else {
350                     convertedArray[convertedOffset++] = ch;
351                 }
352             }
353
354             convertedText.offset = 0;
355             convertedText.count = convertedOffset;
356
357             return convertedText;
358         }
359         
360     }
361     
362     public static class InitialSeparatorReader extends Reader JavaDoc {
363         
364         private static final int AFTER_CR_STATUS = -1;
365         
366         private static final int INITIAL_STATUS = 0;
367         
368         private static final int CR_SEPARATOR = 1;
369         
370         private static final int LF_SEPARATOR = 2;
371         
372         private static final int CRLF_SEPARATOR = 3;
373         
374         private Reader JavaDoc delegate;
375         
376         private int status = INITIAL_STATUS;
377         
378         public InitialSeparatorReader(Reader JavaDoc delegate) {
379             this.delegate = delegate;
380         }
381         
382         public String JavaDoc getInitialSeparator() {
383             String JavaDoc separator;
384             switch (status) {
385                 case CR_SEPARATOR:
386                     separator = "\r"; // NOI18N
387
break;
388                     
389                 case LF_SEPARATOR:
390                     separator = "\n"; // NOI18N
391
break;
392                     
393                 case CRLF_SEPARATOR:
394                     separator = "\r\n"; // NOI18N
395
break;
396                     
397                 case AFTER_CR_STATUS: // '\r' was last char
398
separator = "\r"; // NOI18N
399
break;
400                     
401                 default:
402                     separator = "\n"; // default // NOI18N
403
break;
404             }
405
406             return separator;
407         }
408         
409         private void resolveSeparator(char ch) {
410             switch (status) {
411                 case INITIAL_STATUS:
412                     switch (ch) {
413                         case '\r':
414                             status = AFTER_CR_STATUS;
415                             break;
416                         case '\n':
417                             status = LF_SEPARATOR;
418                             break;
419                     }
420                     break;
421                     
422                 case AFTER_CR_STATUS:
423                     switch (ch) {
424                         case '\n':
425                             status = CRLF_SEPARATOR;
426                             break;
427                         default:
428                             status = CR_SEPARATOR;
429                             break;
430                     }
431                     break;
432
433                 default:
434                     switch (ch) {
435                         case '\r':
436                             status = AFTER_CR_STATUS;
437                             break;
438                         case '\n':
439                             status = LF_SEPARATOR;
440                             break;
441                     }
442                     break;
443             }
444         }
445         
446         private boolean isSeparatorResolved() {
447             return (status > 0);
448         }
449         
450         public void close() throws IOException JavaDoc {
451             if (delegate == null) {
452                 return;
453             }
454
455             delegate.close();
456             delegate = null;
457         }
458         
459         public int read(char[] cbuf, int off, int len) throws IOException JavaDoc {
460             if (delegate == null) {
461                 throw new IOException JavaDoc("Reader already closed."); // NOI18N
462
}
463
464             int readLen = delegate.read(cbuf, off, len);
465
466             for (int endOff = off + readLen;
467                 off < endOff && !isSeparatorResolved();
468                 off++
469             ) {
470                 resolveSeparator(cbuf[off]);
471             }
472
473             return readLen;
474         }
475
476         public int read() throws IOException JavaDoc {
477             if (delegate == null) {
478                 throw new IOException JavaDoc("Reader already closed."); // NOI18N
479
}
480
481             int r = delegate.read();
482             if (r != -1 && !isSeparatorResolved()) {
483                 resolveSeparator((char)r);
484             }
485             
486             return r;
487         }
488
489     }
490
491 }
492
Popular Tags