1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.io.input;
18
19 import static org.apache.commons.io.IOUtils.CR;
20 import static org.apache.commons.io.IOUtils.EOF;
21 import static org.apache.commons.io.IOUtils.LF;
22
23 import java.io.IOException;
24 import java.io.InputStream;
25
26
27
28
29
30
31 public class WindowsLineEndingInputStream extends InputStream {
32
33 private boolean atEos;
34
35 private boolean atSlashCr;
36
37 private boolean atSlashLf;
38
39 private final InputStream in;
40
41 private boolean injectSlashLf;
42
43 private final boolean lineFeedAtEos;
44
45
46
47
48
49
50
51 public WindowsLineEndingInputStream(final InputStream in, final boolean lineFeedAtEos) {
52 this.in = in;
53 this.lineFeedAtEos = lineFeedAtEos;
54 }
55
56
57
58
59
60
61 @Override
62 public void close() throws IOException {
63 super.close();
64 in.close();
65 }
66
67
68
69
70
71
72 private int handleEos() {
73 if (!lineFeedAtEos) {
74 return EOF;
75 }
76 if (!atSlashLf && !atSlashCr) {
77 atSlashCr = true;
78 return CR;
79 }
80 if (!atSlashLf) {
81 atSlashCr = false;
82 atSlashLf = true;
83 return LF;
84 }
85 return EOF;
86 }
87
88
89
90
91 @Override
92 public synchronized void mark(final int readLimit) {
93 throw UnsupportedOperationExceptions.mark();
94 }
95
96
97
98
99 @Override
100 public int read() throws IOException {
101 if (atEos) {
102 return handleEos();
103 }
104 if (injectSlashLf) {
105 injectSlashLf = false;
106 return LF;
107 }
108 final boolean prevWasSlashR = atSlashCr;
109 final int target = in.read();
110 atEos = target == EOF;
111 if (!atEos) {
112 atSlashCr = target == CR;
113 atSlashLf = target == LF;
114 }
115 if (atEos) {
116 return handleEos();
117 }
118 if (target == LF && !prevWasSlashR) {
119 injectSlashLf = true;
120 return CR;
121 }
122 return target;
123 }
124 }