55import java .util .Objects ;
66import java .util .Spliterators ;
77import java .util .function .Consumer ;
8- import java .util .function .Supplier ;
8+ import java .util .function .Function ;
99import java .util .stream .Stream ;
1010import java .util .stream .StreamSupport ;
1111
@@ -72,50 +72,46 @@ public String toString() {
7272 private final Reader rdr ;
7373
7474 private Type state ;
75- private int ch ;
7675 private int pch ;
77- StringBuilder chr ;
7876 StringBuilder str ;
7977 boolean hasEscapes ;
8078
8179 public PropertiesParser (Reader rdr ) throws IOException {
8280 this .rdr = rdr ;
8381 state = null ;
84- chr = new StringBuilder ();
8582 str = new StringBuilder ();
86- pch = -1 ;
87- nextChar ();
83+ readChar ();
8884 }
8985
9086 public Token nextToken () throws IOException {
91- Supplier <Boolean > isValid = () -> false ;
87+ int ch = peekChar ();
88+ if (isEof (ch )) {
89+ return null ;
90+ }
91+ Function <Integer , Boolean > isValid = (c ) -> false ;
9292 Type nextState = null ;
93- while (true ) {
94- if (state == null ) {
95- if (isCommentChar (ch )) {
96- state = Type .COMMENT ;
97- isValid = () -> !isEol (ch );
98- nextState = null ;
99- } else if (isWhitespaceChar (ch )) {
100- state = Type .WHITESPACE ;
101- isValid = () -> isWhitespaceChar (ch );
102- nextState = null ;
103- } else if (isEof (ch )) {
104- return null ;
105- } else {
106- state = Type .KEY ;
107- isValid = () -> !isSeparatorChar (ch );
108- nextState = Type .SEPARATOR ;
109- }
110- } else if (state == Type .SEPARATOR ) {
111- isValid = () -> isSeparatorChar (ch );
112- nextState = Type .VALUE ;
113- } else if (state == Type .VALUE ) {
114- isValid = () -> !isEol (ch );
115- nextState = null ;
93+ if (state == null ) {
94+ if (isCommentChar (ch )) {
95+ state = Type .COMMENT ;
96+ isValid = this ::isNotEol ;
97+ } else if (isWhitespaceChar (ch )) {
98+ state = Type .WHITESPACE ;
99+ isValid = this ::isWhitespaceChar ;
100+ } else {
101+ state = Type .KEY ;
102+ isValid = (c ) -> !isSeparatorChar (c );
103+ nextState = Type .SEPARATOR ;
116104 }
117- if (isValid .get ()) {
118- nextChar ();
105+ } else if (state == Type .SEPARATOR ) {
106+ isValid = this ::isSeparatorChar ;
107+ nextState = Type .VALUE ;
108+ } else if (state == Type .VALUE ) {
109+ isValid = this ::isNotEol ;
110+ }
111+ while (true ) {
112+ if (isValid .apply (ch )) {
113+ addChar (readChar ());
114+ ch = peekChar ();
119115 } else {
120116 String text = (state == Type .VALUE || state == Type .COMMENT ) ? trimmedString () : string ();
121117 Token token = hasEscapes ? new Token (state , text , unescape (text )) : new Token (state , text );
@@ -126,29 +122,29 @@ public Token nextToken() throws IOException {
126122 }
127123 }
128124
129- private void nextChar () throws IOException {
130- str .append (chr );
131- if (chr .length () > 0 && chr .charAt (0 ) == '\\' ) {
132- hasEscapes = true ;
133- }
134- if (pch == -1 ) {
135- ch = rdr .read ();
136- } else {
137- ch = pch ;
138- pch = -1 ;
139- }
140- chr .setLength (0 );
141- chr .append ((char ) ch );
125+ private int peekChar () {
126+ return pch ;
127+ }
128+
129+ private int readChar () throws IOException {
130+ int ch = pch ;
131+ pch = rdr .read ();
132+ return ch ;
133+ }
134+
135+ private void addChar (int ch ) throws IOException {
136+ str .append ((char ) ch );
142137 if (ch == '\\' ) {
143- int ch2 = rdr .read ();
144- chr .append ((char ) ch2 );
138+ hasEscapes = true ;
139+ int ch2 = readChar ();
140+ str .append ((char ) ch2 );
145141 if (ch2 == 'u' ) {
146142 for (int i = 0 ; i < 4 ; i ++) {
147- int chu = rdr . read ();
143+ int chu = readChar ();
148144 if (!isHexDigitChar (chu )) {
149145 throw new IOException ("Invalid unicode escape character: " + chu );
150146 }
151- chr .append ((char ) chu );
147+ str .append ((char ) chu );
152148 }
153149 } else {
154150 readEol (ch2 );
@@ -193,16 +189,10 @@ private static String unescape(String escape) {
193189 return txt .toString ();
194190 }
195191
196- private void readEol (int cch ) throws IOException {
197- if (cch == '\n' ) {
198- // If the next char is a \r we'll add it
199- // to the current char buffer, otherwise
200- // we'll save the character for next time.
201- int nch = rdr .read ();
202- if (nch == '\r' ) {
203- chr .append ((char ) nch );
204- } else {
205- pch = nch ;
192+ private void readEol (int ch ) throws IOException {
193+ if (ch == '\n' ) {
194+ if (peekChar () == '\r' ) {
195+ str .append ((char ) readChar ());
206196 }
207197 }
208198 }
@@ -243,8 +233,8 @@ private boolean isHexDigitChar(int ch) {
243233 return Character .isDigit (ch ) || (uch >= 'A' && uch <= 'F' );
244234 }
245235
246- private boolean isEol (int ch ) {
247- return ch == '\n' || ch == '\r' || isEof (ch );
236+ private boolean isNotEol (int ch ) {
237+ return ch != '\n' && ch != '\r' && ! isEof (ch );
248238 }
249239
250240 private boolean isEof (int ch ) {
0 commit comments