##### Coverage Report - org.yaml.snakeyaml.emitter.Emitter

Classes in this File | Line Coverage | Branch Coverage | Complexity
Emitter |
96% | 631/656
90% | 543/601
| 7.065573770491803;7.066
Emitter$1 |
N/A | N/A
N/A | N/A
| 7.065573770491803;7.066
Emitter$ExpectBlockMappingKey |
100% | 14/14
100% | 6/6
| 7.065573770491803;7.066
Emitter$ExpectBlockMappingSimpleValue |
100% | 5/5
N/A | N/A
| 7.065573770491803;7.066
Emitter$ExpectBlockMappingValue |
100% | 6/6
N/A | N/A
| 7.065573770491803;7.066
Emitter$ExpectBlockSequenceItem |
100% | 11/11
100% | 4/4
| 7.065573770491803;7.066
Emitter$ExpectDocumentEnd |
100% | 10/10
100% | 4/4
| 7.065573770491803;7.066
Emitter$ExpectDocumentRoot |
100% | 4/4
N/A | N/A
| 7.065573770491803;7.066
Emitter$ExpectDocumentStart |
100% | 33/33
96% | 31/32
| 7.065573770491803;7.066
Emitter$ExpectFirstBlockMappingKey |
100% | 3/3
N/A | N/A
| 7.065573770491803;7.066
Emitter$ExpectFirstBlockSequenceItem |
100% | 3/3
N/A | N/A
| 7.065573770491803;7.066
Emitter$ExpectFirstDocumentStart |
100% | 3/3
N/A | N/A
| 7.065573770491803;7.066
Emitter$ExpectFirstFlowMappingKey |
100% | 15/15
100% | 12/12
| 7.065573770491803;7.066
Emitter$ExpectFirstFlowSequenceItem |
100% | 11/11
100% | 8/8
| 7.065573770491803;7.066
Emitter$ExpectFlowMappingKey |
100% | 21/21
100% | 16/16
| 7.065573770491803;7.066
Emitter$ExpectFlowMappingSimpleValue |
100% | 5/5
N/A | N/A
| 7.065573770491803;7.066
Emitter$ExpectFlowMappingValue |
100% | 7/7
100% | 6/6
| 7.065573770491803;7.066
Emitter$ExpectFlowSequenceItem |
100% | 17/17
100% | 12/12
| 7.065573770491803;7.066
Emitter$ExpectNothing |
100% | 2/2
N/A | N/A
| 7.065573770491803;7.066
Emitter$ExpectStreamStart |
100% | 6/6
100% | 2/2
| 7.065573770491803;7.066

1 |  |
     /**
2 |  |
      * Copyright (c) 2008-2011, http://www.snakeyaml.org
3 |  |
      *
4 |  |
      * Licensed under the Apache License, Version 2.0 (the "License");
5 |  |
      * you may not use this file except in compliance with the License.
6 |  |
      * You may obtain a copy of the License at
7 |  |
      *
8 |  |
      *     http://www.apache.org/licenses/LICENSE-2.0
9 |  |
      *
10 |  |
      * Unless required by applicable law or agreed to in writing, software
11 |  |
      * distributed under the License is distributed on an "AS IS" BASIS,
12 |  |
      * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 |  |
      * See the License for the specific language governing permissions and
14 |  |
      * limitations under the License.
15 |  |
      */
16 |  |
17 |  |
     package org.yaml.snakeyaml.emitter;
18 |  |
19 |  |
     import java.io.IOException;
20 |  |
     import java.io.Writer;
21 |  |
     import java.util.HashMap;
22 |  |
     import java.util.Iterator;
23 |  |
     import java.util.LinkedHashMap;
24 |  |
     import java.util.Map;
25 |  |
     import java.util.Queue;
26 |  |
     import java.util.Set;
27 |  |
     import java.util.TreeSet;
28 |  |
     import java.util.concurrent.ArrayBlockingQueue;
29 |  |
     import java.util.regex.Pattern;
30 |  |
31 |  |
     import org.yaml.snakeyaml.DumperOptions;
32 |  |
     import org.yaml.snakeyaml.DumperOptions.ScalarStyle;
33 |  |
     import org.yaml.snakeyaml.events.AliasEvent;
34 |  |
     import org.yaml.snakeyaml.events.CollectionEndEvent;
35 |  |
     import org.yaml.snakeyaml.events.CollectionStartEvent;
36 |  |
     import org.yaml.snakeyaml.events.DocumentEndEvent;
37 |  |
     import org.yaml.snakeyaml.events.DocumentStartEvent;
38 |  |
     import org.yaml.snakeyaml.events.Event;
39 |  |
     import org.yaml.snakeyaml.events.MappingEndEvent;
40 |  |
     import org.yaml.snakeyaml.events.MappingStartEvent;
41 |  |
     import org.yaml.snakeyaml.events.NodeEvent;
42 |  |
     import org.yaml.snakeyaml.events.ScalarEvent;
43 |  |
     import org.yaml.snakeyaml.events.SequenceEndEvent;
44 |  |
     import org.yaml.snakeyaml.events.SequenceStartEvent;
45 |  |
     import org.yaml.snakeyaml.events.StreamEndEvent;
46 |  |
     import org.yaml.snakeyaml.events.StreamStartEvent;
47 |  |
     import org.yaml.snakeyaml.nodes.Tag;
48 |  |
     import org.yaml.snakeyaml.scanner.Constant;
49 |  |
     import org.yaml.snakeyaml.util.ArrayStack;
50 |  |
51 |  |
     /**
52 |  |
      * <pre>
53 |  |
      * Emitter expects events obeying the following grammar:
54 |  |
      * stream ::= STREAM-START document* STREAM-END
55 |  |
      * document ::= DOCUMENT-START node DOCUMENT-END
56 |  |
      * node ::= SCALAR | sequence | mapping
57 |  |
      * sequence ::= SEQUENCE-START node* SEQUENCE-END
58 |  |
      * mapping ::= MAPPING-START (node node)* MAPPING-END
59 |  |
      * </pre>
60 |  |
      */
61 | 2841808 |
     public final class Emitter implements Emitable {
62 | 1 |
         private static final Map<Character, String> ESCAPE_REPLACEMENTS = new HashMap<Character, String>();
63 |  |
         public static final int MIN_INDENT = 1;
64 |  |
         public static final int MAX_INDENT = 10;
65 |  |
66 | 1 |
         public static final char[] SPACE = { ' ' };
67 |  |
68 |  |
         static {
69 | 1 |
             ESCAPE_REPLACEMENTS.put(new Character('\0'), "0");
70 | 1 |
             ESCAPE_REPLACEMENTS.put(new Character('\u0007'), "a");
71 | 1 |
             ESCAPE_REPLACEMENTS.put(new Character('\u0008'), "b");
72 | 1 |
             ESCAPE_REPLACEMENTS.put(new Character('\u0009'), "t");
73 | 1 |
             ESCAPE_REPLACEMENTS.put(new Character('\n'), "n");
74 | 1 |
             ESCAPE_REPLACEMENTS.put(new Character('\u000B'), "v");
75 | 1 |
             ESCAPE_REPLACEMENTS.put(new Character('\u000C'), "f");
76 | 1 |
             ESCAPE_REPLACEMENTS.put(new Character('\r'), "r");
77 | 1 |
             ESCAPE_REPLACEMENTS.put(new Character('\u001B'), "e");
78 | 1 |
             ESCAPE_REPLACEMENTS.put(new Character('"'), "\"");
79 | 1 |
             ESCAPE_REPLACEMENTS.put(new Character('\\'), "\\");
80 | 1 |
             ESCAPE_REPLACEMENTS.put(new Character('\u0085'), "N");
81 | 1 |
             ESCAPE_REPLACEMENTS.put(new Character('\u00A0'), "_");
82 | 1 |
             ESCAPE_REPLACEMENTS.put(new Character('\u2028'), "L");
83 | 1 |
             ESCAPE_REPLACEMENTS.put(new Character('\u2029'), "P");
84 |  |
         }
85 |  |
86 | 1 |
         private final static Map<String, String> DEFAULT_TAG_PREFIXES = new LinkedHashMap<String, String>();
87 |  |
         static {
88 | 1 |
             DEFAULT_TAG_PREFIXES.put("!", "!");
89 | 1 |
             DEFAULT_TAG_PREFIXES.put(Tag.PREFIX, "!!");
90 |  |
         }
91 |  |
         // The stream should have the methods `write` and possibly `flush`.
92 |  |
         private final Writer stream;
93 |  |
94 |  |
         // Encoding is defined by Writer (cannot be overriden by STREAM-START.)
95 |  |
         // private Charset encoding;
96 |  |
97 |  |
         // Emitter is a state machine with a stack of states to handle nested
98 |  |
         // structures.
99 |  |
         private final ArrayStack<EmitterState> states;
100 |  |
         private EmitterState state;
101 |  |
102 |  |
         // Current event and the event queue.
103 |  |
         private final Queue<Event> events;
104 |  |
         private Event event;
105 |  |
106 |  |
         // The current indentation level and the stack of previous indents.
107 |  |
         private final ArrayStack<Integer> indents;
108 |  |
         private Integer indent;
109 |  |
110 |  |
         // Flow level.
111 |  |
         private int flowLevel;
112 |  |
113 |  |
         // Contexts.
114 |  |
         private boolean rootContext;
115 |  |
         private boolean mappingContext;
116 |  |
         private boolean simpleKeyContext;
117 |  |
118 |  |
         //
119 |  |
         // Characteristics of the last emitted character:
120 |  |
         // - current position.
121 |  |
         // - is it a whitespace?
122 |  |
         // - is it an indention character
123 |  |
         // (indentation space, '-', '?', or ':')?
124 |  |
         // private int line; this variable is not used
125 |  |
         private int column;
126 |  |
         private boolean whitespace;
127 |  |
         private boolean indention;
128 |  |
         private boolean openEnded;
129 |  |
130 |  |
         // Formatting details.
131 |  |
         private Boolean canonical;
132 |  |
         // pretty print flow by adding extra line breaks
133 |  |
         private Boolean prettyFlow;
134 |  |
135 |  |
         private boolean allowUnicode;
136 |  |
         private int bestIndent;
137 |  |
         private int bestWidth;
138 |  |
         private char[] bestLineBreak;
139 |  |
140 |  |
         // Tag prefixes.
141 |  |
         private Map<String, String> tagPrefixes;
142 |  |
143 |  |
         // Prepared anchor and tag.
144 |  |
         private String preparedAnchor;
145 |  |
         private String preparedTag;
146 |  |
147 |  |
         // Scalar analysis and style.
148 |  |
         private ScalarAnalysis analysis;
149 |  |
         private Character style;
150 |  |
         private DumperOptions options;
151 |  |
152 | 18507 |
         public Emitter(Writer stream, DumperOptions opts) {
153 |  |
             // The stream should have the methods `write` and possibly `flush`.
154 | 18507 |
             this.stream = stream;
155 |  |
             // Emitter is a state machine with a stack of states to handle nested
156 |  |
             // structures.
157 | 18507 |
             this.states = new ArrayStack<EmitterState>(100);
158 | 18507 |
             this.state = new ExpectStreamStart();
159 |  |
             // Current event and the event queue.
160 | 18507 |
             this.events = new ArrayBlockingQueue<Event>(100);
161 | 18507 |
             this.event = null;
162 |  |
             // The current indentation level and the stack of previous indents.
163 | 18507 |
             this.indents = new ArrayStack<Integer>(10);
164 | 18507 |
             this.indent = null;
165 |  |
             // Flow level.
166 | 18507 |
             this.flowLevel = 0;
167 |  |
             // Contexts.
168 | 18507 |
             mappingContext = false;
169 | 18507 |
             simpleKeyContext = false;
170 |  |
171 |  |
             //
172 |  |
             // Characteristics of the last emitted character:
173 |  |
             // - current position.
174 |  |
             // - is it a whitespace?
175 |  |
             // - is it an indention character
176 |  |
             // (indentation space, '-', '?', or ':')?
177 | 18507 |
             column = 0;
178 | 18507 |
             whitespace = true;
179 | 18507 |
             indention = true;
180 |  |
181 |  |
             // Whether the document requires an explicit document indicator
182 | 18507 |
             openEnded = false;
183 |  |
184 |  |
             // Formatting details.
185 | 18507 |
             this.canonical = opts.isCanonical();
186 | 18507 |
             this.prettyFlow = opts.isPrettyFlow();
187 | 18507 |
             this.allowUnicode = opts.isAllowUnicode();
188 | 18507 |
             this.bestIndent = 2;
189 | 18507 |
             if ((opts.getIndent() > MIN_INDENT) && (opts.getIndent() < MAX_INDENT)) {
190 | 18507 |
                 this.bestIndent = opts.getIndent();
191 |  |
             }
192 | 18507 |
             this.bestWidth = 80;
193 | 18507 |
             if (opts.getWidth() > this.bestIndent * 2) {
194 | 18507 |
                 this.bestWidth = opts.getWidth();
195 |  |
             }
196 | 18507 |
             this.bestLineBreak = opts.getLineBreak().getString().toCharArray();
197 |  |
198 |  |
             // Tag prefixes.
199 | 18507 |
             this.tagPrefixes = new LinkedHashMap<String, String>();
200 |  |
201 |  |
             // Prepared anchor and tag.
202 | 18507 |
             this.preparedAnchor = null;
203 | 18507 |
             this.preparedTag = null;
204 |  |
205 |  |
             // Scalar analysis and style.
206 | 18507 |
             this.analysis = null;
207 | 18507 |
             this.style = null;
208 | 18507 |
             this.options = opts;
209 | 18507 |
         }
210 |  |
211 |  |
         public void emit(Event event) throws IOException {
212 | 827876 |
             this.events.add(event);
213 | 1655727 |
             while (!needMoreEvents()) {
214 | 827869 |
                 this.event = this.events.poll();
215 | 827869 |
                 this.state.expect();
216 | 827851 |
                 this.event = null;
217 |  |
             }
218 | 827858 |
         }
219 |  |
220 |  |
         // In some cases, we wait for a few next events before emitting.
221 |  |
222 |  |
         private boolean needMoreEvents() {
223 | 1655727 |
             if (events.isEmpty()) {
224 | 633369 |
                 return true;
225 |  |
             }
226 | 1022358 |
             Event event = events.peek();
227 | 1022358 |
             if (event instanceof DocumentStartEvent) {
228 | 37646 |
                 return needEvents(1);
229 | 984712 |
             } else if (event instanceof SequenceStartEvent) {
230 | 51221 |
                 return needEvents(2);
231 | 933491 |
             } else if (event instanceof MappingStartEvent) {
232 | 195012 |
                 return needEvents(3);
233 |  |
             } else {
234 | 738479 |
                 return false;
235 |  |
             }
236 |  |
         }
237 |  |
238 |  |
         private boolean needEvents(int count) {
239 | 283879 |
             int level = 0;
240 | 283879 |
             Iterator<Event> iter = events.iterator();
241 | 283879 |
             iter.next();
242 | 672478 |
             while (iter.hasNext()) {
243 | 390510 |
                 Event event = iter.next();
244 | 390510 |
                 if (event instanceof DocumentStartEvent || event instanceof CollectionStartEvent) {
245 | 55476 |
                     level++;
246 | 335034 |
                 } else if (event instanceof DocumentEndEvent || event instanceof CollectionEndEvent) {
247 | 1918 |
                     level--;
248 | 333116 |
                 } else if (event instanceof StreamEndEvent) {
249 | 0 |
                     level = -1;
250 |  |
                 }
251 | 390510 |
                 if (level < 0) {
252 | 1911 |
                     return false;
253 |  |
                 }
254 | 388599 |
             }
255 | 281968 |
             return events.size() < count + 1;
256 |  |
         }
257 |  |
258 |  |
         private void increaseIndent(boolean flow, boolean indentless) {
259 | 675436 |
             indents.push(indent);
260 | 675436 |
             if (indent == null) {
261 | 18812 |
                 if (flow) {
262 | 1925 |
                     indent = bestIndent;
263 |  |
                 } else {
264 | 16887 |
                     indent = 0;
265 |  |
                 }
266 | 656624 |
             } else if (!indentless) {
267 | 640441 |
                 this.indent += bestIndent;
268 |  |
             }
269 | 675436 |
         }
270 |  |
271 |  |
         // States
272 |  |
273 |  |
         // Stream handlers.
274 |  |
275 | 37014 |
         private class ExpectStreamStart implements EmitterState {
276 |  |
             public void expect() throws IOException {
277 | 18504 |
                 if (event instanceof StreamStartEvent) {
278 | 18503 |
                     writeStreamStart();
279 | 18503 |
                     state = new ExpectFirstDocumentStart();
280 |  |
                 } else {
281 | 1 |
                     throw new EmitterException("expected StreamStartEvent, but got " + event);
282 |  |
                 }
283 | 18503 |
             }
284 |  |
         }
285 |  |
286 | 36954 |
         private class ExpectNothing implements EmitterState {
287 |  |
             public void expect() throws IOException {
288 | 1 |
                 throw new EmitterException("expecting nothing, but got " + event);
289 |  |
             }
290 |  |
         }
291 |  |
292 |  |
         // Document handlers.
293 |  |
294 | 37006 |
         private class ExpectFirstDocumentStart implements EmitterState {
295 |  |
             public void expect() throws IOException {
296 | 18493 |
                 new ExpectDocumentStart(true).expect();
297 | 18487 |
             }
298 |  |
         }
299 |  |
300 |  |
         private class ExpectDocumentStart implements EmitterState {
301 |  |
             private boolean first;
302 |  |
303 | 37300 |
             public ExpectDocumentStart(boolean first) {
304 | 37300 |
                 this.first = first;
305 | 37300 |
             }
306 |  |
307 |  |
             public void expect() throws IOException {
308 | 37300 |
                 if (event instanceof DocumentStartEvent) {
309 | 18822 |
                     DocumentStartEvent ev = (DocumentStartEvent) event;
310 | 18822 |
                     if ((ev.getVersion() != null || ev.getTags() != null) && openEnded) {
311 | 7 |
                         writeIndicator("...", true, false, false);
312 | 7 |
                         writeIndent();
313 |  |
                     }
314 | 18822 |
                     if (ev.getVersion() != null) {
315 | 1213 |
                         String versionText = prepareVersion(ev.getVersion());
316 | 1212 |
                         writeVersionDirective(versionText);
317 |  |
                     }
318 | 18821 |
                     tagPrefixes = new LinkedHashMap<String, String>(DEFAULT_TAG_PREFIXES);
319 | 18821 |
                     if (ev.getTags() != null) {
320 | 1596 |
                         Set<String> handles = new TreeSet<String>(ev.getTags().keySet());
321 | 1596 |
                         for (String handle : handles) {
322 | 107 |
                             String prefix = ev.getTags().get(handle);
323 | 107 |
                             tagPrefixes.put(prefix, handle);
324 | 107 |
                             String handleText = prepareTagHandle(handle);
325 | 104 |
                             String prefixText = prepareTagPrefix(prefix);
326 | 103 |
                             writeTagDirective(handleText, prefixText);
327 | 103 |
                         }
328 |  |
                     }
329 | 18817 |
                     boolean implicit = first && !ev.getExplicit() && !canonical
330 |  |
                             && ev.getVersion() == null && ev.getTags() == null && !checkEmptyDocument();
331 | 18817 |
                     if (!implicit) {
332 | 1624 |
                         writeIndent();
333 | 1624 |
                         writeIndicator("---", true, false, false);
334 | 1624 |
                         if (canonical) {
335 | 112 |
                             writeIndent();
336 |  |
                         }
337 |  |
                     }
338 | 18817 |
                     state = new ExpectDocumentRoot();
339 | 18817 |
                 } else if (event instanceof StreamEndEvent) {
340 |  |
                     // TODO fix 313 PyYAML changeset
341 |  |
                     // if (openEnded) {
342 |  |
                     // writeIndicator("...", true, false, false);
343 |  |
                     // writeIndent();
344 |  |
                     // }
345 | 18477 |
                     writeStreamEnd();
346 | 18477 |
                     state = new ExpectNothing();
347 |  |
                 } else {
348 | 1 |
                     throw new EmitterException("expected DocumentStartEvent, but got " + event);
349 |  |
                 }
350 | 37294 |
             }
351 |  |
         }
352 |  |
353 | 37634 |
         private class ExpectDocumentEnd implements EmitterState {
354 |  |
             public void expect() throws IOException {
355 | 18808 |
                 if (event instanceof DocumentEndEvent) {
356 | 18807 |
                     writeIndent();
357 | 18807 |
                     if (((DocumentEndEvent) event).getExplicit()) {
358 | 83 |
                         writeIndicator("...", true, false, false);
359 | 83 |
                         writeIndent();
360 |  |
                     }
361 | 18807 |
                     flushStream();
362 | 18807 |
                     state = new ExpectDocumentStart(false);
363 |  |
                 } else {
364 | 1 |
                     throw new EmitterException("expected DocumentEndEvent, but got " + event);
365 |  |
                 }
366 | 18807 |
             }
367 |  |
         }
368 |  |
369 | 37634 |
         private class ExpectDocumentRoot implements EmitterState {
370 |  |
             public void expect() throws IOException {
371 | 18817 |
                 states.push(new ExpectDocumentEnd());
372 | 18817 |
                 expectNode(true, false, false, false);
373 | 18810 |
             }
374 |  |
         }
375 |  |
376 |  |
         // Node handlers.
377 |  |
378 |  |
         private void expectNode(boolean root, boolean sequence, boolean mapping, boolean simpleKey)
379 |  |
                 throws IOException {
380 | 682692 |
             rootContext = root;
381 | 682692 |
             mappingContext = mapping;
382 | 682692 |
             simpleKeyContext = simpleKey;
383 | 682692 |
             if (event instanceof AliasEvent) {
384 | 7250 |
                 expectAlias();
385 | 675442 |
             } else if (event instanceof ScalarEvent || event instanceof CollectionStartEvent) {
386 | 675440 |
                 processAnchor("&");
387 | 675438 |
                 processTag();
388 | 675436 |
                 if (event instanceof ScalarEvent) {
389 | 604870 |
                     expectScalar();
390 | 70566 |
                 } else if (event instanceof SequenceStartEvent) {
391 | 17166 |
                     if (flowLevel != 0 || canonical || ((SequenceStartEvent) event).getFlowStyle()
392 |  |
                             || checkEmptySequence()) {
393 | 621 |
                         expectFlowSequence();
394 |  |
                     } else {
395 | 16545 |
                         expectBlockSequence();
396 |  |
                     }
397 |  |
                 } else {// MappingStartEvent
398 | 53400 |
                     if (flowLevel != 0 || canonical || ((MappingStartEvent) event).getFlowStyle()
399 |  |
                             || checkEmptyMapping()) {
400 | 11193 |
                         expectFlowMapping();
401 |  |
                     } else {
402 | 42207 |
                         expectBlockMapping();
403 |  |
                     }
404 |  |
                 }
405 |  |
             } else {
406 | 2 |
                 throw new EmitterException("expected NodeEvent, but got " + event);
407 |  |
             }
408 | 682683 |
         }
409 |  |
410 |  |
         private void expectAlias() throws IOException {
411 | 7250 |
             if (((NodeEvent) event).getAnchor() == null) {
412 | 1 |
                 throw new EmitterException("anchor is not specified for alias");
413 |  |
             }
414 | 7249 |
             processAnchor("*");
415 | 7249 |
             state = states.pop();
416 | 7249 |
         }
417 |  |
418 |  |
         private void expectScalar() throws IOException {
419 | 604870 |
             increaseIndent(true, false);
420 | 604870 |
             processScalar();
421 | 604868 |
             indent = indents.pop();
422 | 604868 |
             state = states.pop();
423 | 604868 |
         }
424 |  |
425 |  |
         // Flow sequence handlers.
426 |  |
427 |  |
         private void expectFlowSequence() throws IOException {
428 | 621 |
             writeIndicator("[", true, true, false);
429 | 621 |
             flowLevel++;
430 | 621 |
             increaseIndent(true, false);
431 | 621 |
             if (prettyFlow) {
432 | 4 |
                 writeIndent();
433 |  |
             }
434 | 621 |
             state = new ExpectFirstFlowSequenceItem();
435 | 621 |
         }
436 |  |
437 | 1242 |
         private class ExpectFirstFlowSequenceItem implements EmitterState {
438 |  |
             public void expect() throws IOException {
439 | 621 |
                 if (event instanceof SequenceEndEvent) {
440 | 24 |
                     indent = indents.pop();
441 | 24 |
                     flowLevel--;
442 | 24 |
                     writeIndicator("]", false, false, false);
443 | 24 |
                     state = states.pop();
444 |  |
                 } else {
445 | 597 |
                     if (canonical || column > bestWidth || prettyFlow) {
446 | 66 |
                         writeIndent();
447 |  |
                     }
448 | 597 |
                     states.push(new ExpectFlowSequenceItem());
449 | 597 |
                     expectNode(false, true, false, false);
450 |  |
                 }
451 | 621 |
             }
452 |  |
         }
453 |  |
454 | 2301 |
         private class ExpectFlowSequenceItem implements EmitterState {
455 |  |
             public void expect() throws IOException {
456 | 1704 |
                 if (event instanceof SequenceEndEvent) {
457 | 597 |
                     indent = indents.pop();
458 | 597 |
                     flowLevel--;
459 | 597 |
                     if (canonical) {
460 | 45 |
                         writeIndicator(",", false, false, false);
461 | 45 |
                         writeIndent();
462 |  |
                     }
463 | 597 |
                     writeIndicator("]", false, false, false);
464 | 597 |
                     if (prettyFlow) {
465 | 4 |
                         writeIndent();
466 |  |
                     }
467 | 597 |
                     state = states.pop();
468 |  |
                 } else {
469 | 1107 |
                     writeIndicator(",", false, false, false);
470 | 1107 |
                     if (canonical || column > bestWidth || prettyFlow) {
471 | 118 |
                         writeIndent();
472 |  |
                     }
473 | 1107 |
                     states.push(new ExpectFlowSequenceItem());
474 | 1107 |
                     expectNode(false, true, false, false);
475 |  |
                 }
476 | 1704 |
             }
477 |  |
         }
478 |  |
479 |  |
         // Flow mapping handlers.
480 |  |
481 |  |
         private void expectFlowMapping() throws IOException {
482 | 11193 |
             writeIndicator("{", true, true, false);
483 | 11193 |
             flowLevel++;
484 | 11193 |
             increaseIndent(true, false);
485 | 11193 |
             if (prettyFlow) {
486 | 14 |
                 writeIndent();
487 |  |
             }
488 | 11193 |
             state = new ExpectFirstFlowMappingKey();
489 | 11193 |
         }
490 |  |
491 | 22386 |
         private class ExpectFirstFlowMappingKey implements EmitterState {
492 |  |
             public void expect() throws IOException {
493 | 11193 |
                 if (event instanceof MappingEndEvent) {
494 | 21 |
                     indent = indents.pop();
495 | 21 |
                     flowLevel--;
496 | 21 |
                     writeIndicator("}", false, false, false);
497 | 21 |
                     state = states.pop();
498 |  |
                 } else {
499 | 11172 |
                     if (canonical || column > bestWidth || prettyFlow) {
500 | 163 |
                         writeIndent();
501 |  |
                     }
502 | 11172 |
                     if (!canonical && checkSimpleKey()) {
503 | 11059 |
                         states.push(new ExpectFlowMappingSimpleValue());
504 | 11059 |
                         expectNode(false, false, true, true);
505 |  |
                     } else {
506 | 113 |
                         writeIndicator("?", true, false, false);
507 | 113 |
                         states.push(new ExpectFlowMappingValue());
508 | 113 |
                         expectNode(false, false, true, false);
509 |  |
                     }
510 |  |
                 }
511 | 11193 |
             }
512 |  |
         }
513 |  |
514 | 77902 |
         private class ExpectFlowMappingKey implements EmitterState {
515 |  |
             public void expect() throws IOException {
516 | 38951 |
                 if (event instanceof MappingEndEvent) {
517 | 11172 |
                     indent = indents.pop();
518 | 11172 |
                     flowLevel--;
519 | 11172 |
                     if (canonical) {
520 | 79 |
                         writeIndicator(",", false, false, false);
521 | 79 |
                         writeIndent();
522 |  |
                     }
523 | 11172 |
                     if (prettyFlow) {
524 | 10 |
                         writeIndent();
525 |  |
                     }
526 | 11172 |
                     writeIndicator("}", false, false, false);
527 | 11172 |
                     state = states.pop();
528 |  |
                 } else {
529 | 27779 |
                     writeIndicator(",", false, false, false);
530 | 27779 |
                     if (canonical || column > bestWidth || prettyFlow) {
531 | 149 |
                         writeIndent();
532 |  |
                     }
533 | 27779 |
                     if (!canonical && checkSimpleKey()) {
534 | 27674 |
                         states.push(new ExpectFlowMappingSimpleValue());
535 | 27674 |
                         expectNode(false, false, true, true);
536 |  |
                     } else {
537 | 105 |
                         writeIndicator("?", true, false, false);
538 | 105 |
                         states.push(new ExpectFlowMappingValue());
539 | 105 |
                         expectNode(false, false, true, false);
540 |  |
                     }
541 |  |
                 }
542 | 38951 |
             }
543 |  |
         }
544 |  |
545 | 77466 |
         private class ExpectFlowMappingSimpleValue implements EmitterState {
546 |  |
             public void expect() throws IOException {
547 | 38733 |
                 writeIndicator(":", false, false, false);
548 | 38733 |
                 states.push(new ExpectFlowMappingKey());
549 | 38733 |
                 expectNode(false, false, true, false);
550 | 38733 |
             }
551 |  |
         }
552 |  |
553 | 436 |
         private class ExpectFlowMappingValue implements EmitterState {
554 |  |
             public void expect() throws IOException {
555 | 218 |
                 if (canonical || column > bestWidth || prettyFlow) {
556 | 138 |
                     writeIndent();
557 |  |
                 }
558 | 218 |
                 writeIndicator(":", true, false, false);
559 | 218 |
                 states.push(new ExpectFlowMappingKey());
560 | 218 |
                 expectNode(false, false, true, false);
561 | 218 |
             }
562 |  |
         }
563 |  |
564 |  |
         // Block sequence handlers.
565 |  |
566 |  |
         private void expectBlockSequence() throws IOException {
567 | 16545 |
             boolean indentless = (mappingContext && !indention);
568 | 16545 |
             increaseIndent(false, indentless);
569 | 16545 |
             state = new ExpectFirstBlockSequenceItem();
570 | 16545 |
         }
571 |  |
572 | 33090 |
         private class ExpectFirstBlockSequenceItem implements EmitterState {
573 |  |
             public void expect() throws IOException {
574 | 16545 |
                 new ExpectBlockSequenceItem(true).expect();
575 | 16545 |
             }
576 |  |
         }
577 |  |
578 |  |
         private class ExpectBlockSequenceItem implements EmitterState {
579 |  |
             private boolean first;
580 |  |
581 | 131994 |
             public ExpectBlockSequenceItem(boolean first) {
582 | 131994 |
                 this.first = first;
583 | 131994 |
             }
584 |  |
585 |  |
             public void expect() throws IOException {
586 | 131993 |
                 if (!this.first && event instanceof SequenceEndEvent) {
587 | 16544 |
                     indent = indents.pop();
588 | 16544 |
                     state = states.pop();
589 |  |
                 } else {
590 | 115449 |
                     writeIndent();
591 | 115449 |
                     writeIndicator("-", true, false, true);
592 | 115449 |
                     states.push(new ExpectBlockSequenceItem(false));
593 | 115449 |
                     expectNode(false, true, false, false);
594 |  |
                 }
595 | 131992 |
             }
596 |  |
         }
597 |  |
598 |  |
         // Block mapping handlers.
599 |  |
         private void expectBlockMapping() throws IOException {
600 | 42207 |
             increaseIndent(false, false);
601 | 42207 |
             state = new ExpectFirstBlockMappingKey();
602 | 42207 |
         }
603 |  |
604 | 84414 |
         private class ExpectFirstBlockMappingKey implements EmitterState {
605 |  |
             public void expect() throws IOException {
606 | 42207 |
                 new ExpectBlockMappingKey(true).expect();
607 | 42207 |
             }
608 |  |
         }
609 |  |
610 |  |
         private class ExpectBlockMappingKey implements EmitterState {
611 |  |
             private boolean first;
612 |  |
613 | 276617 |
             public ExpectBlockMappingKey(boolean first) {
614 | 276617 |
                 this.first = first;
615 | 276617 |
             }
616 |  |
617 |  |
             public void expect() throws IOException {
618 | 276616 |
                 if (!this.first && event instanceof MappingEndEvent) {
619 | 42206 |
                     indent = indents.pop();
620 | 42206 |
                     state = states.pop();
621 |  |
                 } else {
622 | 234410 |
                     writeIndent();
623 | 234410 |
                     if (checkSimpleKey()) {
624 | 234298 |
                         states.push(new ExpectBlockMappingSimpleValue());
625 | 234298 |
                         expectNode(false, false, true, true);
626 |  |
                     } else {
627 | 112 |
                         writeIndicator("?", true, false, true);
628 | 112 |
                         states.push(new ExpectBlockMappingValue());
629 | 112 |
                         expectNode(false, false, true, false);
630 |  |
                     }
631 |  |
                 }
632 | 276616 |
             }
633 |  |
         }
634 |  |
635 | 468596 |
         private class ExpectBlockMappingSimpleValue implements EmitterState {
636 |  |
             public void expect() throws IOException {
637 | 234298 |
                 writeIndicator(":", false, false, false);
638 | 234298 |
                 states.push(new ExpectBlockMappingKey(false));
639 | 234298 |
                 expectNode(false, false, true, false);
640 | 234297 |
             }
641 |  |
         }
642 |  |
643 | 224 |
         private class ExpectBlockMappingValue implements EmitterState {
644 |  |
             public void expect() throws IOException {
645 | 112 |
                 writeIndent();
646 | 112 |
                 writeIndicator(":", true, false, true);
647 | 112 |
                 states.push(new ExpectBlockMappingKey(false));
648 | 112 |
                 expectNode(false, false, true, false);
649 | 112 |
             }
650 |  |
         }
651 |  |
652 |  |
         // Checkers.
653 |  |
654 |  |
         private boolean checkEmptySequence() {
655 | 16759 |
             return (event instanceof SequenceStartEvent && !events.isEmpty() && events.peek() instanceof SequenceEndEvent);
656 |  |
         }
657 |  |
658 |  |
         private boolean checkEmptyMapping() {
659 | 42417 |
             return (event instanceof MappingStartEvent && !events.isEmpty() && events.peek() instanceof MappingEndEvent);
660 |  |
         }
661 |  |
662 |  |
         private boolean checkEmptyDocument() {
663 | 17193 |
             if (!(event instanceof DocumentStartEvent) || events.isEmpty()) {
664 | 0 |
                 return false;
665 |  |
             }
666 | 17193 |
             Event event = events.peek();
667 | 17193 |
             if (event instanceof ScalarEvent) {
668 | 315 |
                 ScalarEvent e = (ScalarEvent) event;
669 | 315 |
                 return (e.getAnchor() == null && e.getTag() == null && e.getImplicit() != null && e
670 |  |
                         .getValue() == "");
671 |  |
             }
672 | 16878 |
             return false;
673 |  |
         }
674 |  |
675 |  |
         private boolean checkSimpleKey() {
676 | 273235 |
             int length = 0;
677 | 273235 |
             if (event instanceof NodeEvent && ((NodeEvent) event).getAnchor() != null) {
678 | 54 |
                 if (preparedAnchor == null) {
679 | 54 |
                     preparedAnchor = prepareAnchor(((NodeEvent) event).getAnchor());
680 |  |
                 }
681 | 54 |
                 length += preparedAnchor.length();
682 |  |
             }
683 | 273235 |
             String tag = null;
684 | 273235 |
             if (event instanceof ScalarEvent) {
685 | 273110 |
                 tag = ((ScalarEvent) event).getTag();
686 | 125 |
             } else if (event instanceof CollectionStartEvent) {
687 | 116 |
                 tag = ((CollectionStartEvent) event).getTag();
688 |  |
             }
689 | 273235 |
             if (tag != null) {
690 | 271835 |
                 if (preparedTag == null) {
691 | 271835 |
                     preparedTag = prepareTag(tag);
692 |  |
                 }
693 | 271835 |
                 length += preparedTag.length();
694 |  |
             }
695 | 273235 |
             if (event instanceof ScalarEvent) {
696 | 273110 |
                 if (analysis == null) {
697 | 273110 |
                     analysis = analyzeScalar(((ScalarEvent) event).getValue());
698 |  |
                 }
699 | 273110 |
                 length += analysis.scalar.length();
700 |  |
             }
701 | 273235 |
             return (length < 128 && (event instanceof AliasEvent
702 |  |
                     || (event instanceof ScalarEvent && !analysis.empty && !analysis.multiline)
703 |  |
                     || checkEmptySequence() || checkEmptyMapping()));
704 |  |
         }
705 |  |
706 |  |
         // Anchor, Tag, and Scalar processors.
707 |  |
708 |  |
         private void processAnchor(String indicator) throws IOException {
709 | 682689 |
             NodeEvent ev = (NodeEvent) event;
710 | 682689 |
             if (ev.getAnchor() == null) {
711 | 668221 |
                 preparedAnchor = null;
712 | 668221 |
                 return;
713 |  |
             }
714 | 14468 |
             if (preparedAnchor == null) {
715 | 14414 |
                 preparedAnchor = prepareAnchor(ev.getAnchor());
716 |  |
             }
717 | 14466 |
             writeIndicator(indicator + preparedAnchor, true, false, false);
718 | 14466 |
             preparedAnchor = null;
719 | 14466 |
         }
720 |  |
721 |  |
         private void processTag() throws IOException {
722 | 675438 |
             String tag = null;
723 | 675438 |
             if (event instanceof ScalarEvent) {
724 | 604872 |
                 ScalarEvent ev = (ScalarEvent) event;
725 | 604872 |
                 tag = ev.getTag();
726 | 604872 |
                 if (style == null) {
727 | 604872 |
                     style = chooseScalarStyle();
728 |  |
                 }
729 | 604872 |
                 if (((!canonical || tag == null) && ((style == null && ev.getImplicit()
730 |  |
                         .canOmitTagInPlainScalar()) || (style != null && ev.getImplicit()
731 |  |
                         .canOmitTagInNonPlainScalar())))) {
732 | 598361 |
                     preparedTag = null;
733 | 598361 |
                     return;
734 |  |
                 }
735 | 6511 |
                 if (ev.getImplicit().canOmitTagInPlainScalar() && tag == null) {
736 | 2025 |
                     tag = "!";
737 | 2025 |
                     preparedTag = null;
738 |  |
                 }
739 | 6511 |
             } else {
740 | 70566 |
                 CollectionStartEvent ev = (CollectionStartEvent) event;
741 | 70566 |
                 tag = ev.getTag();
742 | 70566 |
                 if ((!canonical || tag == null) && ev.getImplicit()) {
743 | 64887 |
                     preparedTag = null;
744 | 64887 |
                     return;
745 |  |
                 }
746 |  |
             }
747 | 12190 |
             if (tag == null) {
748 | 1 |
                 throw new EmitterException("tag is not specified");
749 |  |
             }
750 | 12189 |
             if (preparedTag == null) {
751 | 10774 |
                 preparedTag = prepareTag(tag);
752 |  |
             }
753 | 12188 |
             writeIndicator(preparedTag, true, false, false);
754 | 12188 |
             preparedTag = null;
755 | 12188 |
         }
756 |  |
757 |  |
         private Character chooseScalarStyle() {
758 | 984048 |
             ScalarEvent ev = (ScalarEvent) event;
759 | 984048 |
             if (analysis == null) {
760 | 331762 |
                 analysis = analyzeScalar(ev.getValue());
761 |  |
             }
762 | 984048 |
             if (ev.getStyle() != null && ev.getStyle() == '"' || this.canonical) {
763 | 2195 |
                 return '"';
764 |  |
             }
765 | 981853 |
             if (ev.getStyle() == null && ev.getImplicit().canOmitTagInPlainScalar()) {
766 | 764442 |
                 if (!(simpleKeyContext && (analysis.empty || analysis.multiline))
767 |  |
                         && ((flowLevel != 0 && analysis.allowFlowPlain) || (flowLevel == 0 && analysis.allowBlockPlain))) {
768 | 758352 |
                     return null;
769 |  |
                 }
770 |  |
             }
771 | 223501 |
             if (ev.getStyle() != null && (ev.getStyle() == '|' || ev.getStyle() == '>')) {
772 | 2772 |
                 if (flowLevel == 0 && !simpleKeyContext && analysis.allowBlock) {
773 | 933 |
                     return ev.getStyle();
774 |  |
                 }
775 |  |
             }
776 | 222568 |
             if (ev.getStyle() == null || ev.getStyle() == '\'') {
777 | 220497 |
                 if (analysis.allowSingleQuoted && !(simpleKeyContext && analysis.multiline)) {
778 | 220364 |
                     return '\'';
779 |  |
                 }
780 |  |
             }
781 | 2204 |
             return '"';
782 |  |
         }
783 |  |
784 |  |
         private void processScalar() throws IOException {
785 | 604870 |
             ScalarEvent ev = (ScalarEvent) event;
786 | 604870 |
             if (analysis == null) {
787 | 0 |
                 analysis = analyzeScalar(ev.getValue());
788 |  |
             }
789 | 604870 |
             if (style == null) {
790 | 379176 |
                 style = chooseScalarStyle();
791 |  |
             }
792 | 604870 |
             style = options.calculateScalarStyle(analysis, ScalarStyle.createStyle(style)).getChar();
793 | 604870 |
             boolean split = !simpleKeyContext;
794 | 604870 |
             if (style == null) {
795 | 379176 |
                 writePlain(analysis.scalar, split);
796 |  |
             } else {
797 | 225694 |
                 switch (style) {
798 |  |
                 case '"':
799 | 4398 |
                     writeDoubleQuoted(analysis.scalar, split);
800 | 4398 |
                     break;
801 |  |
                 case '\'':
802 | 220362 |
                     writeSingleQuoted(analysis.scalar, split);
803 | 220362 |
                     break;
804 |  |
                 case '>':
805 | 458 |
                     writeFolded(analysis.scalar);
806 | 458 |
                     break;
807 |  |
                 case '|':
808 | 476 |
                     writeLiteral(analysis.scalar);
809 |  |
                     break;
810 |  |
                 }
811 |  |
             }
812 | 604868 |
             analysis = null;
813 | 604868 |
             style = null;
814 | 604868 |
         }
815 |  |
816 |  |
         // Analyzers.
817 |  |
818 |  |
         private String prepareVersion(Integer[] version) {
819 | 1213 |
             Integer major = version[0];
820 | 1213 |
             Integer minor = version[1];
821 | 1213 |
             if (major != 1) {
822 | 1 |
                 throw new EmitterException("unsupported YAML version: " + version[0] + "." + version[1]);
823 |  |
             }
824 | 1212 |
             return major.toString() + "." + minor.toString();
825 |  |
         }
826 |  |
827 | 1 |
         private final static Pattern HANDLE_FORMAT = Pattern.compile("^![-_\\w]*!$");
828 |  |
829 |  |
         private String prepareTagHandle(String handle) {
830 | 107 |
             if (handle.length() == 0) {
831 | 1 |
                 throw new EmitterException("tag handle must not be empty");
832 | 106 |
             } else if (handle.charAt(0) != '!' || handle.charAt(handle.length() - 1) != '!') {
833 | 1 |
                 throw new EmitterException("tag handle must start and end with '!': " + handle);
834 | 105 |
             } else if (!"!".equals(handle) && !HANDLE_FORMAT.matcher(handle).matches()) {
835 | 1 |
                 throw new EmitterException("invalid character in the tag handle: " + handle);
836 |  |
             }
837 | 104 |
             return handle;
838 |  |
         }
839 |  |
840 |  |
         private String prepareTagPrefix(String prefix) {
841 | 104 |
             if (prefix.length() == 0) {
842 | 1 |
                 throw new EmitterException("tag prefix must not be empty");
843 |  |
             }
844 | 103 |
             StringBuilder chunks = new StringBuilder();
845 | 103 |
             int start = 0;
846 | 103 |
             int end = 0;
847 | 103 |
             if (prefix.charAt(0) == '!') {
848 | 35 |
                 end = 1;
849 |  |
             }
850 | 1563 |
             while (end < prefix.length()) {
851 | 1460 |
                 end++;
852 |  |
             }
853 | 103 |
             if (start < end) {
854 | 103 |
                 chunks.append(prefix.substring(start, end));
855 |  |
             }
856 | 103 |
             return chunks.toString();
857 |  |
         }
858 |  |
859 |  |
         private String prepareTag(String tag) {
860 | 282609 |
             if (tag.length() == 0) {
861 | 1 |
                 throw new EmitterException("tag must not be empty");
862 |  |
             }
863 | 282608 |
             if ("!".equals(tag)) {
864 | 2043 |
                 return tag;
865 |  |
             }
866 | 280565 |
             String handle = null;
867 | 280565 |
             String suffix = tag;
868 | 280565 |
             for (String prefix : tagPrefixes.keySet()) {
869 | 561240 |
                 if (tag.startsWith(prefix) && ("!".equals(prefix) || prefix.length() < tag.length())) {
870 | 280550 |
                     handle = prefix;
871 |  |
                 }
872 |  |
             }
873 | 280565 |
             if (handle != null) {
874 | 280528 |
                 suffix = tag.substring(handle.length());
875 | 280528 |
                 handle = tagPrefixes.get(handle);
876 |  |
             }
877 |  |
878 | 280565 |
             int end = suffix.length();
879 | 280565 |
             String suffixText = end > 0 ? suffix.substring(0, end) : "";
880 |  |
881 | 280565 |
             if (handle != null) {
882 | 280528 |
                 return handle + suffixText;
883 |  |
             }
884 | 37 |
             return "!<" + suffixText + ">";
885 |  |
         }
886 |  |
887 | 1 |
         private final static Pattern ANCHOR_FORMAT = Pattern.compile("^[-_\\w]*$");
888 |  |
889 |  |
         static String prepareAnchor(String anchor) {
890 | 14468 |
             if (anchor.length() == 0) {
891 | 1 |
                 throw new EmitterException("anchor must not be empty");
892 |  |
             }
893 | 14467 |
             if (!ANCHOR_FORMAT.matcher(anchor).matches()) {
894 | 1 |
                 throw new EmitterException("invalid character in the anchor: " + anchor);
895 |  |
             }
896 | 14466 |
             return anchor;
897 |  |
         }
898 |  |
899 |  |
         private ScalarAnalysis analyzeScalar(String scalar) {
900 |  |
             // Empty scalar is a special case.
901 | 604872 |
             if (scalar.length() == 0) {
902 | 565 |
                 return new ScalarAnalysis(scalar, true, false, false, true, true, true, false);
903 |  |
             }
904 |  |
             // Indicators and special characters.
905 | 604307 |
             boolean blockIndicators = false;
906 | 604307 |
             boolean flowIndicators = false;
907 | 604307 |
             boolean lineBreaks = false;
908 | 604307 |
             boolean specialCharacters = false;
909 |  |
910 |  |
             // Important whitespace combinations.
911 | 604307 |
             boolean leadingSpace = false;
912 | 604307 |
             boolean leadingBreak = false;
913 | 604307 |
             boolean trailingSpace = false;
914 | 604307 |
             boolean trailingBreak = false;
915 | 604307 |
             boolean breakSpace = false;
916 | 604307 |
             boolean spaceBreak = false;
917 |  |
918 |  |
             // Check document indicators.
919 | 604307 |
             if (scalar.startsWith("---") || scalar.startsWith("...")) {
920 | 138 |
                 blockIndicators = true;
921 | 138 |
                 flowIndicators = true;
922 |  |
             }
923 |  |
             // First character or preceded by a whitespace.
924 | 604307 |
             boolean preceededByWhitespace = true;
925 | 604307 |
             boolean followedByWhitespace = (scalar.length() == 1 || Constant.NULL_BL_T_LINEBR
926 |  |
                     .has(scalar.charAt(1)));
927 |  |
             // The previous character is a space.
928 | 604307 |
             boolean previousSpace = false;
929 |  |
930 |  |
             // The previous character is a break.
931 | 604307 |
             boolean previousBreak = false;
932 |  |
933 | 604307 |
             int index = 0;
934 |  |
935 | 3710213 |
             while (index < scalar.length()) {
936 | 3105906 |
                 char ch = scalar.charAt(index);
937 |  |
                 // Check for indicators.
938 | 3105906 |
                 if (index == 0) {
939 |  |
                     // Leading indicators are special characters.
940 | 604307 |
                     if ("#,[]{}&*!|>\'\"%@`".indexOf(ch) != -1) {
941 | 98 |
                         flowIndicators = true;
942 | 98 |
                         blockIndicators = true;
943 |  |
                     }
944 | 604307 |
                     if (ch == '?' || ch == ':') {
945 | 46 |
                         flowIndicators = true;
946 | 46 |
                         if (followedByWhitespace) {
947 | 0 |
                             blockIndicators = true;
948 |  |
                         }
949 |  |
                     }
950 | 604307 |
                     if (ch == '-' && followedByWhitespace) {
951 | 0 |
                         flowIndicators = true;
952 | 0 |
                         blockIndicators = true;
953 |  |
                     }
954 |  |
                 } else {
955 |  |
                     // Some indicators cannot appear within a scalar as well.
956 | 2501599 |
                     if (",?[]{}".indexOf(ch) != -1) {
957 | 115 |
                         flowIndicators = true;
958 |  |
                     }
959 | 2501599 |
                     if (ch == ':') {
960 | 332 |
                         flowIndicators = true;
961 | 332 |
                         if (followedByWhitespace) {
962 | 6 |
                             blockIndicators = true;
963 |  |
                         }
964 |  |
                     }
965 | 2501599 |
                     if (ch == '#' && preceededByWhitespace) {
966 | 6027 |
                         flowIndicators = true;
967 | 6027 |
                         blockIndicators = true;
968 |  |
                     }
969 |  |
                 }
970 |  |
                 // Check for line breaks, special, and unicode characters.
971 | 3105906 |
                 boolean isLineBreak = Constant.LINEBR.has(ch);
972 | 3105906 |
                 if (isLineBreak) {
973 | 14590 |
                     lineBreaks = true;
974 |  |
                 }
975 | 3105906 |
                 if (!(ch == '\n' || ('\u0020' <= ch && ch <= '\u007E'))) {
976 | 697 |
                     if ((ch == '\u0085' || ('\u00A0' <= ch && ch <= '\uD7FF') || ('\uE000' <= ch && ch <= '\uFFFD'))
977 |  |
                             && (ch != '\uFEFF')) {
978 |  |
                         // unicode is used
979 | 283 |
                         if (!this.allowUnicode) {
980 | 1 |
                             specialCharacters = true;
981 |  |
                         }
982 |  |
                     } else {
983 | 414 |
                         specialCharacters = true;
984 |  |
                     }
985 |  |
                 }
986 |  |
                 // Detect important whitespace combinations.
987 | 3105906 |
                 if (ch == ' ') {
988 | 96236 |
                     if (index == 0) {
989 | 209 |
                         leadingSpace = true;
990 |  |
                     }
991 | 96236 |
                     if (index == scalar.length() - 1) {
992 | 46 |
                         trailingSpace = true;
993 |  |
                     }
994 | 96236 |
                     if (previousBreak) {
995 | 343 |
                         breakSpace = true;
996 |  |
                     }
997 | 96236 |
                     previousSpace = true;
998 | 96236 |
                     previousBreak = false;
999 | 3009670 |
                 } else if (isLineBreak) {
1000 | 14590 |
                     if (index == 0) {
1001 | 121 |
                         leadingBreak = true;
1002 |  |
                     }
1003 | 14590 |
                     if (index == scalar.length() - 1) {
1004 | 6850 |
                         trailingBreak = true;
1005 |  |
                     }
1006 | 14590 |
                     if (previousSpace) {
1007 | 92 |
                         spaceBreak = true;
1008 |  |
                     }
1009 | 14590 |
                     previousSpace = false;
1010 | 14590 |
                     previousBreak = true;
1011 |  |
                 } else {
1012 | 2995080 |
                     previousSpace = false;
1013 | 2995080 |
                     previousBreak = false;
1014 |  |
                 }
1015 |  |
1016 |  |
                 // Prepare for the next character.
1017 | 3105906 |
                 index++;
1018 | 3105906 |
                 preceededByWhitespace = Constant.NULL_BL_T.has(ch) || isLineBreak;
1019 | 3105906 |
                 followedByWhitespace = (index + 1 >= scalar.length()
1020 |  |
                         || (Constant.NULL_BL_T.has(scalar.charAt(index + 1))) || isLineBreak);
1021 | 3105906 |
             }
1022 |  |
             // Let's decide what styles are allowed.
1023 | 604307 |
             boolean allowFlowPlain = true;
1024 | 604307 |
             boolean allowBlockPlain = true;
1025 | 604307 |
             boolean allowSingleQuoted = true;
1026 | 604307 |
             boolean allowDoubleQuoted = true;
1027 | 604307 |
             boolean allowBlock = true;
1028 |  |
             // Leading and trailing whitespaces are bad for plain scalars.
1029 | 604307 |
             if (leadingSpace || leadingBreak || trailingSpace || trailingBreak) {
1030 | 7063 |
                 allowFlowPlain = allowBlockPlain = false;
1031 |  |
             }
1032 |  |
             // We do not permit trailing spaces for block scalars.
1033 | 604307 |
             if (trailingSpace) {
1034 | 46 |
                 allowBlock = false;
1035 |  |
             }
1036 |  |
             // Spaces at the beginning of a new line are only acceptable for block
1037 |  |
             // scalars.
1038 | 604307 |
             if (breakSpace) {
1039 | 169 |
                 allowFlowPlain = allowBlockPlain = allowSingleQuoted = false;
1040 |  |
             }
1041 |  |
             // Spaces followed by breaks, as well as special character are only
1042 |  |
             // allowed for double quoted scalars.
1043 | 604307 |
             if (spaceBreak || specialCharacters) {
1044 | 238 |
                 allowFlowPlain = allowBlockPlain = allowSingleQuoted = allowBlock = false;
1045 |  |
             }
1046 |  |
             // Although the plain scalar writer supports breaks, we never emit
1047 |  |
             // multiline plain scalars.
1048 | 604307 |
             if (lineBreaks) {
1049 | 7090 |
                 allowFlowPlain = allowBlockPlain = false;
1050 |  |
             }
1051 |  |
             // Flow indicators are forbidden for flow plain scalars.
1052 | 604307 |
             if (flowIndicators) {
1053 | 6442 |
                 allowFlowPlain = false;
1054 |  |
             }
1055 |  |
             // Block indicators are forbidden for block plain scalars.
1056 | 604307 |
             if (blockIndicators) {
1057 | 6266 |
                 allowBlockPlain = false;
1058 |  |
             }
1059 |  |
1060 | 604307 |
             return new ScalarAnalysis(scalar, false, lineBreaks, allowFlowPlain, allowBlockPlain,
1061 |  |
                     allowSingleQuoted, allowDoubleQuoted, allowBlock);
1062 |  |
         }
1063 |  |
1064 |  |
         // Writers.
1065 |  |
1066 |  |
         void flushStream() throws IOException {
1067 | 37284 |
             stream.flush();
1068 | 37284 |
         }
1069 |  |
1070 |  |
         void writeStreamStart() {
1071 |  |
             // BOM is written by Writer.
1072 | 18503 |
         }
1073 |  |
1074 |  |
         void writeStreamEnd() throws IOException {
1075 | 18477 |
             flushStream();
1076 | 18477 |
         }
1077 |  |
1078 |  |
         void writeIndicator(String indicator, boolean needWhitespace, boolean whitespace,
1079 |  |
                 boolean indentation) throws IOException {
1080 | 920600 |
             if (!this.whitespace && needWhitespace) {
1081 | 157795 |
                 this.column++;
1082 | 157795 |
                 stream.write(SPACE);
1083 |  |
             }
1084 | 920600 |
             this.whitespace = whitespace;
1085 | 920600 |
             this.indention = this.indention && indentation;
1086 | 920600 |
             this.column += indicator.length();
1087 | 920600 |
             openEnded = false;
1088 | 920600 |
             stream.write(indicator);
1089 | 920600 |
         }
1090 |  |
1091 |  |
         void writeIndent() throws IOException {
1092 |  |
             int indent;
1093 | 385115 |
             if (this.indent != null) {
1094 | 364409 |
                 indent = this.indent;
1095 |  |
             } else {
1096 | 20706 |
                 indent = 0;
1097 |  |
             }
1098 |  |
1099 | 385115 |
             if (!this.indention || this.column > indent || (this.column == indent && !this.whitespace)) {
1100 | 349265 |
                 writeLineBreak(null);
1101 |  |
             }
1102 |  |
1103 | 385115 |
             if (this.column < indent) {
1104 | 169864 |
                 this.whitespace = true;
1105 | 169864 |
                 char[] data = new char[indent - this.column];
1106 | 578515 |
                 for (int i = 0; i < data.length; i++) {
1107 | 408651 |
                     data[i] = ' ';
1108 |  |
                 }
1109 | 169864 |
                 this.column = indent;
1110 | 169864 |
                 stream.write(data);
1111 |  |
             }
1112 | 385115 |
         }
1113 |  |
1114 |  |
         private void writeLineBreak(String data) throws IOException {
1115 | 377900 |
             this.whitespace = true;
1116 | 377900 |
             this.indention = true;
1117 | 377900 |
             this.column = 0;
1118 | 377900 |
             if (data == null) {
1119 | 377790 |
                 stream.write(this.bestLineBreak);
1120 |  |
             } else {
1121 | 110 |
                 stream.write(data);
1122 |  |
             }
1123 | 377900 |
         }
1124 |  |
1125 |  |
         void writeVersionDirective(String versionText) throws IOException {
1126 | 1212 |
             stream.write("%YAML ");
1127 | 1212 |
             stream.write(versionText);
1128 | 1212 |
             writeLineBreak(null);
1129 | 1212 |
         }
1130 |  |
1131 |  |
         void writeTagDirective(String handleText, String prefixText) throws IOException {
1132 |  |
             // XXX: not sure 4 invocations better then StringBuilders created by str
1133 |  |
             // + str
1134 | 103 |
             stream.write("%TAG ");
1135 | 103 |
             stream.write(handleText);
1136 | 103 |
             stream.write(SPACE);
1137 | 103 |
             stream.write(prefixText);
1138 | 103 |
             writeLineBreak(null);
1139 | 103 |
         }
1140 |  |
1141 |  |
         // Scalar streams.
1142 |  |
         private void writeSingleQuoted(String text, boolean split) throws IOException {
1143 | 220362 |
             writeIndicator("'", true, false, false);
1144 | 220362 |
             boolean spaces = false;
1145 | 220362 |
             boolean breaks = false;
1146 | 220362 |
             int start = 0, end = 0;
1147 |  |
             char ch;
1148 | 1189821 |
             while (end <= text.length()) {
1149 | 969459 |
                 ch = 0;
1150 | 969459 |
                 if (end < text.length()) {
1151 | 749097 |
                     ch = text.charAt(end);
1152 |  |
                 }
1153 | 969459 |
                 if (spaces) {
1154 | 19314 |
                     if (ch == 0 || ch != ' ') {
1155 | 19305 |
                         if (start + 1 == end && this.column > this.bestWidth && split && start != 0
1156 |  |
                                 && end != text.length()) {
1157 | 13 |
                             writeIndent();
1158 |  |
                         } else {
1159 | 19292 |
                             int len = end - start;
1160 | 19292 |
                             this.column += len;
1161 | 19292 |
                             stream.write(text, start, len);
1162 |  |
                         }
1163 | 19305 |
                         start = end;
1164 |  |
                     }
1165 | 950145 |
                 } else if (breaks) {
1166 | 12528 |
                     if (ch == 0 || Constant.LINEBR.hasNo(ch)) {
1167 | 12414 |
                         if (text.charAt(start) == '\n') {
1168 | 12357 |
                             writeLineBreak(null);
1169 |  |
                         }
1170 | 12414 |
                         String data = text.substring(start, end);
1171 | 24942 |
                         for (char br : data.toCharArray()) {
1172 | 12528 |
                             if (br == '\n') {
1173 | 12471 |
                                 writeLineBreak(null);
1174 |  |
                             } else {
1175 | 57 |
                                 writeLineBreak(String.valueOf(br));
1176 |  |
                             }
1177 |  |
                         }
1178 | 12414 |
                         writeIndent();
1179 | 12414 |
                         start = end;
1180 | 12414 |
                     }
1181 |  |
                 } else {
1182 | 937617 |
                     if (Constant.LINEBR.has(ch, "\0 \'")) {
1183 | 245851 |
                         if (start < end) {
1184 | 245570 |
                             int len = end - start;
1185 | 245570 |
                             this.column += len;
1186 | 245570 |
                             stream.write(text, start, len);
1187 | 245570 |
                             start = end;
1188 |  |
                         }
1189 |  |
                     }
1190 |  |
                 }
1191 | 969459 |
                 if (ch == '\'') {
1192 | 15 |
                     this.column += 2;
1193 | 15 |
                     stream.write("''");
1194 | 15 |
                     start = end + 1;
1195 |  |
                 }
1196 | 969459 |
                 if (ch != 0) {
1197 | 749097 |
                     spaces = ch == ' ';
1198 | 749097 |
                     breaks = Constant.LINEBR.has(ch);
1199 |  |
                 }
1200 | 969459 |
                 end++;
1201 |  |
             }
1202 | 220362 |
             writeIndicator("'", false, false, false);
1203 | 220362 |
         }
1204 |  |
1205 |  |
         private void writeDoubleQuoted(String text, boolean split) throws IOException {
1206 | 4398 |
             writeIndicator("\"", true, false, false);
1207 | 4398 |
             int start = 0;
1208 | 4398 |
             int end = 0;
1209 | 49508 |
             while (end <= text.length()) {
1210 | 45110 |
                 Character ch = null;
1211 | 45110 |
                 if (end < text.length()) {
1212 | 40712 |
                     ch = text.charAt(end);
1213 |  |
                 }
1214 | 45110 |
                 if (ch == null || "\"\\\u0085\u2028\u2029\uFEFF".indexOf(ch) != -1
1215 |  |
                         || !('\u0020' <= ch && ch <= '\u007E')) {
1216 | 6289 |
                     if (start < end) {
1217 | 5084 |
                         int len = end - start;
1218 | 5084 |
                         this.column += len;
1219 | 5084 |
                         stream.write(text, start, len);
1220 | 5084 |
                         start = end;
1221 |  |
                     }
1222 | 6289 |
                     if (ch != null) {
1223 |  |
                         String data;
1224 | 1891 |
                         if (ESCAPE_REPLACEMENTS.containsKey(new Character(ch))) {
1225 | 1889 |
                             data = "\\" + ESCAPE_REPLACEMENTS.get(new Character(ch));
1226 | 2 |
                         } else if (!this.allowUnicode) {
1227 |  |
                             // this is different from PyYAML which escapes all
1228 |  |
                             // non-ASCII characters
1229 | 1 |
                             if (ch <= '\u00FF') {
1230 | 1 |
                                 String s = "0" + Integer.toString(ch, 16);
1231 | 1 |
                                 data = "\\x" + s.substring(s.length() - 2);
1232 | 1 |
                             } else {
1233 | 0 |
                                 String s = "000" + Integer.toString(ch, 16);
1234 | 0 |
                                 data = "\\u" + s.substring(s.length() - 4);
1235 | 0 |
                             }
1236 |  |
                         } else {
1237 | 1 |
                             data = String.valueOf(ch);
1238 |  |
                         }
1239 | 1891 |
                         this.column += data.length();
1240 | 1891 |
                         stream.write(data);
1241 | 1891 |
                         start = end + 1;
1242 |  |
                     }
1243 |  |
                 }
1244 | 45110 |
                 if ((0 < end && end < (text.length() - 1)) && (ch == ' ' || start >= end)
1245 |  |
                         && (this.column + (end - start)) > this.bestWidth && split) {
1246 |  |
                     String data;
1247 | 79 |
                     if (start >= end) {
1248 | 36 |
                         data = "\\";
1249 |  |
                     } else {
1250 | 43 |
                         data = text.substring(start, end) + "\\";
1251 |  |
                     }
1252 | 79 |
                     if (start < end) {
1253 | 43 |
                         start = end;
1254 |  |
                     }
1255 | 79 |
                     this.column += data.length();
1256 | 79 |
                     stream.write(data);
1257 | 79 |
                     writeIndent();
1258 | 79 |
                     this.whitespace = false;
1259 | 79 |
                     this.indention = false;
1260 | 79 |
                     if (text.charAt(start) == ' ') {
1261 | 55 |
                         data = "\\";
1262 | 55 |
                         this.column += data.length();
1263 | 55 |
                         stream.write(data);
1264 |  |
                     }
1265 |  |
                 }
1266 | 45110 |
                 end += 1;
1267 | 45110 |
             }
1268 | 4398 |
             writeIndicator("\"", false, false, false);
1269 | 4398 |
         }
1270 |  |
1271 |  |
         private String determineBlockHints(String text) {
1272 | 934 |
             StringBuilder hints = new StringBuilder();
1273 | 934 |
             if (Constant.LINEBR.has(text.charAt(0), " ")) {
1274 | 70 |
                 hints.append(bestIndent);
1275 |  |
             }
1276 | 934 |
             char ch1 = text.charAt(text.length() - 1);
1277 | 934 |
             if (Constant.LINEBR.hasNo(ch1)) {
1278 | 727 |
                 hints.append("-");
1279 | 207 |
             } else if (text.length() == 1 || Constant.LINEBR.has(text.charAt(text.length() - 2))) {
1280 | 15 |
                 hints.append("+");
1281 |  |
             }
1282 | 934 |
             return hints.toString();
1283 |  |
         }
1284 |  |
1285 |  |
         void writeFolded(String text) throws IOException {
1286 | 458 |
             String hints = determineBlockHints(text);
1287 | 458 |
             writeIndicator(">" + hints, true, false, false);
1288 | 458 |
             if (hints.length() > 0 && (hints.charAt(hints.length() - 1) == '+')) {
1289 | 6 |
                 openEnded = true;
1290 |  |
             }
1291 | 458 |
             writeLineBreak(null);
1292 | 458 |
             boolean leadingSpace = true;
1293 | 458 |
             boolean spaces = false;
1294 | 458 |
             boolean breaks = true;
1295 | 458 |
             int start = 0, end = 0;
1296 | 6878 |
             while (end <= text.length()) {
1297 | 6420 |
                 char ch = 0;
1298 | 6420 |
                 if (end < text.length()) {
1299 | 5962 |
                     ch = text.charAt(end);
1300 |  |
                 }
1301 | 6420 |
                 if (breaks) {
1302 | 812 |
                     if (ch == 0 || Constant.LINEBR.hasNo(ch)) {
1303 | 703 |
                         if (!leadingSpace && ch != 0 && ch != ' ' && text.charAt(start) == '\n') {
1304 | 68 |
                             writeLineBreak(null);
1305 |  |
                         }
1306 | 703 |
                         leadingSpace = (ch == ' ');
1307 | 703 |
                         String data = text.substring(start, end);
1308 | 1057 |
                         for (char br : data.toCharArray()) {
1309 | 354 |
                             if (br == '\n') {
1310 | 329 |
                                 writeLineBreak(null);
1311 |  |
                             } else {
1312 | 25 |
                                 writeLineBreak(String.valueOf(br));
1313 |  |
                             }
1314 |  |
                         }
1315 | 703 |
                         if (ch != 0) {
1316 | 604 |
                             writeIndent();
1317 |  |
                         }
1318 | 703 |
                         start = end;
1319 | 703 |
                     }
1320 | 5608 |
                 } else if (spaces) {
1321 | 574 |
                     if (ch != ' ') {
1322 | 528 |
                         if (start + 1 == end && this.column > this.bestWidth) {
1323 | 1 |
                             writeIndent();
1324 |  |
                         } else {
1325 | 527 |
                             int len = end - start;
1326 | 527 |
                             this.column += len;
1327 | 527 |
                             stream.write(text, start, len);
1328 |  |
                         }
1329 | 528 |
                         start = end;
1330 |  |
                     }
1331 |  |
                 } else {
1332 | 5034 |
                     if (Constant.LINEBR.has(ch, "\0 ")) {
1333 | 1073 |
                         int len = end - start;
1334 | 1073 |
                         this.column += len;
1335 | 1073 |
                         stream.write(text, start, len);
1336 | 1073 |
                         if (ch == 0) {
1337 | 359 |
                             writeLineBreak(null);
1338 |  |
                         }
1339 | 1073 |
                         start = end;
1340 |  |
                     }
1341 |  |
                 }
1342 | 6420 |
                 if (ch != 0) {
1343 | 5962 |
                     breaks = Constant.LINEBR.has(ch);
1344 | 5962 |
                     spaces = (ch == ' ');
1345 |  |
                 }
1346 | 6420 |
                 end++;
1347 | 6420 |
             }
1348 | 458 |
         }
1349 |  |
1350 |  |
         void writeLiteral(String text) throws IOException {
1351 | 476 |
             String hints = determineBlockHints(text);
1352 | 476 |
             writeIndicator("|" + hints, true, false, false);
1353 | 476 |
             if (hints.length() > 0 && (hints.charAt(hints.length() - 1)) == '+') {
1354 | 9 |
                 openEnded = true;
1355 |  |
             }
1356 | 476 |
             writeLineBreak(null);
1357 | 476 |
             boolean breaks = true;
1358 | 476 |
             int start = 0, end = 0;
1359 | 6951 |
             while (end <= text.length()) {
1360 | 6475 |
                 char ch = 0;
1361 | 6475 |
                 if (end < text.length()) {
1362 | 5999 |
                     ch = text.charAt(end);
1363 |  |
                 }
1364 | 6475 |
                 if (breaks) {
1365 | 828 |
                     if (ch == 0 || Constant.LINEBR.hasNo(ch)) {
1366 | 718 |
                         String data = text.substring(start, end);
1367 | 1070 |
                         for (char br : data.toCharArray()) {
1368 | 352 |
                             if (br == '\n') {
1369 | 324 |
                                 writeLineBreak(null);
1370 |  |
                             } else {
1371 | 28 |
                                 writeLineBreak(String.valueOf(br));
1372 |  |
                             }
1373 |  |
                         }
1374 | 718 |
                         if (ch != 0) {
1375 | 610 |
                             writeIndent();
1376 |  |
                         }
1377 | 718 |
                         start = end;
1378 | 718 |
                     }
1379 |  |
                 } else {
1380 | 5647 |
                     if (ch == 0 || Constant.LINEBR.has(ch)) {
1381 | 610 |
                         stream.write(text, start, end - start);
1382 | 610 |
                         if (ch == 0) {
1383 | 368 |
                             writeLineBreak(null);
1384 |  |
                         }
1385 | 610 |
                         start = end;
1386 |  |
                     }
1387 |  |
                 }
1388 | 6475 |
                 if (ch != 0) {
1389 | 5999 |
                     breaks = (Constant.LINEBR.has(ch));
1390 |  |
                 }
1391 | 6475 |
                 end++;
1392 | 6475 |
             }
1393 | 476 |
         }
1394 |  |
1395 |  |
         void writePlain(String text, boolean split) throws IOException {
1396 | 379176 |
             if (rootContext) {
1397 | 53 |
                 openEnded = true;
1398 |  |
             }
1399 | 379176 |
             if (text.length() == 0) {
1400 | 27 |
                 return;
1401 |  |
             }
1402 | 379149 |
             if (!this.whitespace) {
1403 | 235609 |
                 this.column++;
1404 | 235609 |
                 stream.write(SPACE);
1405 |  |
             }
1406 | 379149 |
             this.whitespace = false;
1407 | 379149 |
             this.indention = false;
1408 | 379149 |
             boolean spaces = false;
1409 | 379149 |
             boolean breaks = false;
1410 | 379149 |
             int start = 0, end = 0;
1411 | 3062426 |
             while (end <= text.length()) {
1412 | 2683279 |
                 char ch = 0;
1413 | 2683279 |
                 if (end < text.length()) {
1414 | 2304130 |
                     ch = text.charAt(end);
1415 |  |
                 }
1416 | 2683279 |
                 if (spaces) {
1417 | 72404 |
                     if (ch != ' ') {
1418 | 72404 |
                         if (start + 1 == end && this.column > this.bestWidth && split) {
1419 | 0 |
                             writeIndent();
1420 | 0 |
                             this.whitespace = false;
1421 | 0 |
                             this.indention = false;
1422 |  |
                         } else {
1423 | 72404 |
                             int len = end - start;
1424 | 72404 |
                             this.column += len;
1425 | 72404 |
                             stream.write(text, start, len);
1426 |  |
                         }
1427 | 72404 |
                         start = end;
1428 |  |
                     }
1429 | 2610875 |
                 } else if (breaks) {
1430 | 0 |
                     if (Constant.LINEBR.hasNo(ch)) {
1431 | 0 |
                         if (text.charAt(start) == '\n') {
1432 | 0 |
                             writeLineBreak(null);
1433 |  |
                         }
1434 | 0 |
                         String data = text.substring(start, end);
1435 | 0 |
                         for (char br : data.toCharArray()) {
1436 | 0 |
                             if (br == '\n') {
1437 | 0 |
                                 writeLineBreak(null);
1438 |  |
                             } else {
1439 | 0 |
                                 writeLineBreak(String.valueOf(br));
1440 |  |
                             }
1441 |  |
                         }
1442 | 0 |
                         writeIndent();
1443 | 0 |
                         this.whitespace = false;
1444 | 0 |
                         this.indention = false;
1445 | 0 |
                         start = end;
1446 | 0 |
                     }
1447 |  |
                 } else {
1448 | 2610875 |
                     if (ch == 0 || Constant.LINEBR.has(ch)) {
1449 | 379149 |
                         int len = end - start;
1450 | 379149 |
                         this.column += len;
1451 | 379149 |
                         stream.write(text, start, len);
1452 | 379147 |
                         start = end;
1453 |  |
                     }
1454 |  |
                 }
1455 | 2683277 |
                 if (ch != 0) {
1456 | 2304130 |
                     spaces = (ch == ' ');
1457 | 2304130 |
                     breaks = (Constant.LINEBR.has(ch));
1458 |  |
                 }
1459 | 2683277 |
                 end++;
1460 | 2683277 |
             }
1461 | 379147 |
         }
1462 |  |
     }