11adf3a94fce500e0bda933e4b495a004d5789bd7Andrey Somov/** 211a89b445f3bde56bf07e6a0d04f0b0256dcb215Andrey Somov * Copyright (c) 2008, http://www.snakeyaml.org 31adf3a94fce500e0bda933e4b495a004d5789bd7Andrey Somov * 41adf3a94fce500e0bda933e4b495a004d5789bd7Andrey Somov * Licensed under the Apache License, Version 2.0 (the "License"); 51adf3a94fce500e0bda933e4b495a004d5789bd7Andrey Somov * you may not use this file except in compliance with the License. 61adf3a94fce500e0bda933e4b495a004d5789bd7Andrey Somov * You may obtain a copy of the License at 71adf3a94fce500e0bda933e4b495a004d5789bd7Andrey Somov * 81adf3a94fce500e0bda933e4b495a004d5789bd7Andrey Somov * http://www.apache.org/licenses/LICENSE-2.0 91adf3a94fce500e0bda933e4b495a004d5789bd7Andrey Somov * 101adf3a94fce500e0bda933e4b495a004d5789bd7Andrey Somov * Unless required by applicable law or agreed to in writing, software 111adf3a94fce500e0bda933e4b495a004d5789bd7Andrey Somov * distributed under the License is distributed on an "AS IS" BASIS, 121adf3a94fce500e0bda933e4b495a004d5789bd7Andrey Somov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 131adf3a94fce500e0bda933e4b495a004d5789bd7Andrey Somov * See the License for the specific language governing permissions and 141adf3a94fce500e0bda933e4b495a004d5789bd7Andrey Somov * limitations under the License. 159629be70863521bead138c295351f3dec926ab1Andrey Somov */ 169629be70863521bead138c295351f3dec926ab1Andrey Somovpackage org.yaml.snakeyaml.emitter; 179629be70863521bead138c295351f3dec926ab1Andrey Somov 189629be70863521bead138c295351f3dec926ab1Andrey Somovimport java.io.IOException; 199629be70863521bead138c295351f3dec926ab1Andrey Somovimport java.io.Writer; 209629be70863521bead138c295351f3dec926ab1Andrey Somovimport java.util.HashMap; 219629be70863521bead138c295351f3dec926ab1Andrey Somovimport java.util.Iterator; 229629be70863521bead138c295351f3dec926ab1Andrey Somovimport java.util.LinkedHashMap; 239629be70863521bead138c295351f3dec926ab1Andrey Somovimport java.util.Map; 249629be70863521bead138c295351f3dec926ab1Andrey Somovimport java.util.Queue; 259629be70863521bead138c295351f3dec926ab1Andrey Somovimport java.util.Set; 269629be70863521bead138c295351f3dec926ab1Andrey Somovimport java.util.TreeSet; 27c294eb822a2d69f64d2f1226d8a6f639b59a179aAndrey Somovimport java.util.concurrent.ArrayBlockingQueue; 289629be70863521bead138c295351f3dec926ab1Andrey Somovimport java.util.regex.Pattern; 299629be70863521bead138c295351f3dec926ab1Andrey Somov 309629be70863521bead138c295351f3dec926ab1Andrey Somovimport org.yaml.snakeyaml.DumperOptions; 315476b912d698337c3bd69e38cadf15f60986e269Andrey Somovimport org.yaml.snakeyaml.DumperOptions.Version; 3234f59d77fd0a29b085d4c642eb1db6b8925fc3c3Andrey Somovimport org.yaml.snakeyaml.error.YAMLException; 339629be70863521bead138c295351f3dec926ab1Andrey Somovimport org.yaml.snakeyaml.events.AliasEvent; 349629be70863521bead138c295351f3dec926ab1Andrey Somovimport org.yaml.snakeyaml.events.CollectionEndEvent; 359629be70863521bead138c295351f3dec926ab1Andrey Somovimport org.yaml.snakeyaml.events.CollectionStartEvent; 369629be70863521bead138c295351f3dec926ab1Andrey Somovimport org.yaml.snakeyaml.events.DocumentEndEvent; 379629be70863521bead138c295351f3dec926ab1Andrey Somovimport org.yaml.snakeyaml.events.DocumentStartEvent; 389629be70863521bead138c295351f3dec926ab1Andrey Somovimport org.yaml.snakeyaml.events.Event; 399629be70863521bead138c295351f3dec926ab1Andrey Somovimport org.yaml.snakeyaml.events.MappingEndEvent; 409629be70863521bead138c295351f3dec926ab1Andrey Somovimport org.yaml.snakeyaml.events.MappingStartEvent; 419629be70863521bead138c295351f3dec926ab1Andrey Somovimport org.yaml.snakeyaml.events.NodeEvent; 429629be70863521bead138c295351f3dec926ab1Andrey Somovimport org.yaml.snakeyaml.events.ScalarEvent; 439629be70863521bead138c295351f3dec926ab1Andrey Somovimport org.yaml.snakeyaml.events.SequenceEndEvent; 449629be70863521bead138c295351f3dec926ab1Andrey Somovimport org.yaml.snakeyaml.events.SequenceStartEvent; 459629be70863521bead138c295351f3dec926ab1Andrey Somovimport org.yaml.snakeyaml.events.StreamEndEvent; 469629be70863521bead138c295351f3dec926ab1Andrey Somovimport org.yaml.snakeyaml.events.StreamStartEvent; 4787ff57908e8ccf62ef984bb067a61b815a9a1074Andrey Somovimport org.yaml.snakeyaml.nodes.Tag; 487361ced8b2bc1e37c3064923b0ccc124af39b57aAndrey Somovimport org.yaml.snakeyaml.reader.StreamReader; 4965619eff85ddfd768e973825b34b2ed8bbde537dAndrey Somovimport org.yaml.snakeyaml.scanner.Constant; 5080ff61204231b1f307cf354618f876e8ca1d0f09Andrey Somovimport org.yaml.snakeyaml.util.ArrayStack; 519629be70863521bead138c295351f3dec926ab1Andrey Somov 529629be70863521bead138c295351f3dec926ab1Andrey Somov/** 539629be70863521bead138c295351f3dec926ab1Andrey Somov * <pre> 549629be70863521bead138c295351f3dec926ab1Andrey Somov * Emitter expects events obeying the following grammar: 559629be70863521bead138c295351f3dec926ab1Andrey Somov * stream ::= STREAM-START document* STREAM-END 569629be70863521bead138c295351f3dec926ab1Andrey Somov * document ::= DOCUMENT-START node DOCUMENT-END 579629be70863521bead138c295351f3dec926ab1Andrey Somov * node ::= SCALAR | sequence | mapping 589629be70863521bead138c295351f3dec926ab1Andrey Somov * sequence ::= SEQUENCE-START node* SEQUENCE-END 599629be70863521bead138c295351f3dec926ab1Andrey Somov * mapping ::= MAPPING-START (node node)* MAPPING-END 609629be70863521bead138c295351f3dec926ab1Andrey Somov * </pre> 619629be70863521bead138c295351f3dec926ab1Andrey Somov */ 6291afe6c6cb158fbf7b63481a60d68e8b98d57250Andrey Somovpublic final class Emitter implements Emitable { 639629be70863521bead138c295351f3dec926ab1Andrey Somov private static final Map<Character, String> ESCAPE_REPLACEMENTS = new HashMap<Character, String>(); 649629be70863521bead138c295351f3dec926ab1Andrey Somov public static final int MIN_INDENT = 1; 659629be70863521bead138c295351f3dec926ab1Andrey Somov public static final int MAX_INDENT = 10; 669629be70863521bead138c295351f3dec926ab1Andrey Somov 67d4c7e6efc571fe29d05cc8d0f6d0e713e8c4a35fAndrey Somov private static final char[] SPACE = { ' ' }; 68370faf2dd7606d5fe2f887012be73d40fa531559maslovalex 699629be70863521bead138c295351f3dec926ab1Andrey Somov static { 708fb5a7218a84a1f88abadf4bac8b9f8a4555d8e8Andrey Somov ESCAPE_REPLACEMENTS.put('\0', "0"); 718fb5a7218a84a1f88abadf4bac8b9f8a4555d8e8Andrey Somov ESCAPE_REPLACEMENTS.put('\u0007', "a"); 728fb5a7218a84a1f88abadf4bac8b9f8a4555d8e8Andrey Somov ESCAPE_REPLACEMENTS.put('\u0008', "b"); 738fb5a7218a84a1f88abadf4bac8b9f8a4555d8e8Andrey Somov ESCAPE_REPLACEMENTS.put('\u0009', "t"); 748fb5a7218a84a1f88abadf4bac8b9f8a4555d8e8Andrey Somov ESCAPE_REPLACEMENTS.put('\n', "n"); 758fb5a7218a84a1f88abadf4bac8b9f8a4555d8e8Andrey Somov ESCAPE_REPLACEMENTS.put('\u000B', "v"); 768fb5a7218a84a1f88abadf4bac8b9f8a4555d8e8Andrey Somov ESCAPE_REPLACEMENTS.put('\u000C', "f"); 778fb5a7218a84a1f88abadf4bac8b9f8a4555d8e8Andrey Somov ESCAPE_REPLACEMENTS.put('\r', "r"); 788fb5a7218a84a1f88abadf4bac8b9f8a4555d8e8Andrey Somov ESCAPE_REPLACEMENTS.put('\u001B', "e"); 798fb5a7218a84a1f88abadf4bac8b9f8a4555d8e8Andrey Somov ESCAPE_REPLACEMENTS.put('"', "\""); 808fb5a7218a84a1f88abadf4bac8b9f8a4555d8e8Andrey Somov ESCAPE_REPLACEMENTS.put('\\', "\\"); 818fb5a7218a84a1f88abadf4bac8b9f8a4555d8e8Andrey Somov ESCAPE_REPLACEMENTS.put('\u0085', "N"); 828fb5a7218a84a1f88abadf4bac8b9f8a4555d8e8Andrey Somov ESCAPE_REPLACEMENTS.put('\u00A0', "_"); 838fb5a7218a84a1f88abadf4bac8b9f8a4555d8e8Andrey Somov ESCAPE_REPLACEMENTS.put('\u2028', "L"); 848fb5a7218a84a1f88abadf4bac8b9f8a4555d8e8Andrey Somov ESCAPE_REPLACEMENTS.put('\u2029', "P"); 859629be70863521bead138c295351f3dec926ab1Andrey Somov } 869629be70863521bead138c295351f3dec926ab1Andrey Somov 879629be70863521bead138c295351f3dec926ab1Andrey Somov private final static Map<String, String> DEFAULT_TAG_PREFIXES = new LinkedHashMap<String, String>(); 889629be70863521bead138c295351f3dec926ab1Andrey Somov static { 899629be70863521bead138c295351f3dec926ab1Andrey Somov DEFAULT_TAG_PREFIXES.put("!", "!"); 9087ff57908e8ccf62ef984bb067a61b815a9a1074Andrey Somov DEFAULT_TAG_PREFIXES.put(Tag.PREFIX, "!!"); 919629be70863521bead138c295351f3dec926ab1Andrey Somov } 929629be70863521bead138c295351f3dec926ab1Andrey Somov // The stream should have the methods `write` and possibly `flush`. 939629be70863521bead138c295351f3dec926ab1Andrey Somov private final Writer stream; 949629be70863521bead138c295351f3dec926ab1Andrey Somov 959629be70863521bead138c295351f3dec926ab1Andrey Somov // Encoding is defined by Writer (cannot be overriden by STREAM-START.) 969629be70863521bead138c295351f3dec926ab1Andrey Somov // private Charset encoding; 979629be70863521bead138c295351f3dec926ab1Andrey Somov 989629be70863521bead138c295351f3dec926ab1Andrey Somov // Emitter is a state machine with a stack of states to handle nested 999629be70863521bead138c295351f3dec926ab1Andrey Somov // structures. 10080ff61204231b1f307cf354618f876e8ca1d0f09Andrey Somov private final ArrayStack<EmitterState> states; 1019629be70863521bead138c295351f3dec926ab1Andrey Somov private EmitterState state; 1029629be70863521bead138c295351f3dec926ab1Andrey Somov 1039629be70863521bead138c295351f3dec926ab1Andrey Somov // Current event and the event queue. 1049629be70863521bead138c295351f3dec926ab1Andrey Somov private final Queue<Event> events; 1059629be70863521bead138c295351f3dec926ab1Andrey Somov private Event event; 1069629be70863521bead138c295351f3dec926ab1Andrey Somov 1079629be70863521bead138c295351f3dec926ab1Andrey Somov // The current indentation level and the stack of previous indents. 10880ff61204231b1f307cf354618f876e8ca1d0f09Andrey Somov private final ArrayStack<Integer> indents; 1099629be70863521bead138c295351f3dec926ab1Andrey Somov private Integer indent; 1109629be70863521bead138c295351f3dec926ab1Andrey Somov 1119629be70863521bead138c295351f3dec926ab1Andrey Somov // Flow level. 1129629be70863521bead138c295351f3dec926ab1Andrey Somov private int flowLevel; 1139629be70863521bead138c295351f3dec926ab1Andrey Somov 1149629be70863521bead138c295351f3dec926ab1Andrey Somov // Contexts. 1159629be70863521bead138c295351f3dec926ab1Andrey Somov private boolean rootContext; 1169629be70863521bead138c295351f3dec926ab1Andrey Somov private boolean mappingContext; 1179629be70863521bead138c295351f3dec926ab1Andrey Somov private boolean simpleKeyContext; 1189629be70863521bead138c295351f3dec926ab1Andrey Somov 1199629be70863521bead138c295351f3dec926ab1Andrey Somov // 1209629be70863521bead138c295351f3dec926ab1Andrey Somov // Characteristics of the last emitted character: 1219629be70863521bead138c295351f3dec926ab1Andrey Somov // - current position. 1229629be70863521bead138c295351f3dec926ab1Andrey Somov // - is it a whitespace? 1239629be70863521bead138c295351f3dec926ab1Andrey Somov // - is it an indention character 1249629be70863521bead138c295351f3dec926ab1Andrey Somov // (indentation space, '-', '?', or ':')? 125a5424f52a32314d70897f06a0aec907cf9231963Andrey Somov // private int line; this variable is not used 1269629be70863521bead138c295351f3dec926ab1Andrey Somov private int column; 1279629be70863521bead138c295351f3dec926ab1Andrey Somov private boolean whitespace; 1289629be70863521bead138c295351f3dec926ab1Andrey Somov private boolean indention; 1299629be70863521bead138c295351f3dec926ab1Andrey Somov private boolean openEnded; 1309629be70863521bead138c295351f3dec926ab1Andrey Somov 1319629be70863521bead138c295351f3dec926ab1Andrey Somov // Formatting details. 1329629be70863521bead138c295351f3dec926ab1Andrey Somov private Boolean canonical; 1338cda6fba9cc20d9210a50e13a81b37affb84b39bobastard // pretty print flow by adding extra line breaks 134fd03e2da32bb87716104bcdfc5b454ae970b277aAndrey Somov private Boolean prettyFlow; 1358cda6fba9cc20d9210a50e13a81b37affb84b39bobastard 1369629be70863521bead138c295351f3dec926ab1Andrey Somov private boolean allowUnicode; 1379629be70863521bead138c295351f3dec926ab1Andrey Somov private int bestIndent; 138d1dd873170bcc2a9df0a512ae5fa5f073a8b64cftareq sha private int indicatorIndent; 1399629be70863521bead138c295351f3dec926ab1Andrey Somov private int bestWidth; 140370faf2dd7606d5fe2f887012be73d40fa531559maslovalex private char[] bestLineBreak; 1417fbc6562f9ae67c2b9de8b8c5c74c62c42006cebVille Koskela private boolean splitLines; 1429629be70863521bead138c295351f3dec926ab1Andrey Somov 1439629be70863521bead138c295351f3dec926ab1Andrey Somov // Tag prefixes. 1449629be70863521bead138c295351f3dec926ab1Andrey Somov private Map<String, String> tagPrefixes; 1459629be70863521bead138c295351f3dec926ab1Andrey Somov 1469629be70863521bead138c295351f3dec926ab1Andrey Somov // Prepared anchor and tag. 1479629be70863521bead138c295351f3dec926ab1Andrey Somov private String preparedAnchor; 1489629be70863521bead138c295351f3dec926ab1Andrey Somov private String preparedTag; 1499629be70863521bead138c295351f3dec926ab1Andrey Somov 1509629be70863521bead138c295351f3dec926ab1Andrey Somov // Scalar analysis and style. 1519629be70863521bead138c295351f3dec926ab1Andrey Somov private ScalarAnalysis analysis; 152d79a13b3448ff517eaa1a32ab5506db735d83c92as private Character style; 1539629be70863521bead138c295351f3dec926ab1Andrey Somov 1549629be70863521bead138c295351f3dec926ab1Andrey Somov public Emitter(Writer stream, DumperOptions opts) { 1559629be70863521bead138c295351f3dec926ab1Andrey Somov // The stream should have the methods `write` and possibly `flush`. 1569629be70863521bead138c295351f3dec926ab1Andrey Somov this.stream = stream; 1579629be70863521bead138c295351f3dec926ab1Andrey Somov // Emitter is a state machine with a stack of states to handle nested 1589629be70863521bead138c295351f3dec926ab1Andrey Somov // structures. 15980ff61204231b1f307cf354618f876e8ca1d0f09Andrey Somov this.states = new ArrayStack<EmitterState>(100); 1609629be70863521bead138c295351f3dec926ab1Andrey Somov this.state = new ExpectStreamStart(); 1619629be70863521bead138c295351f3dec926ab1Andrey Somov // Current event and the event queue. 162c294eb822a2d69f64d2f1226d8a6f639b59a179aAndrey Somov this.events = new ArrayBlockingQueue<Event>(100); 1639629be70863521bead138c295351f3dec926ab1Andrey Somov this.event = null; 1649629be70863521bead138c295351f3dec926ab1Andrey Somov // The current indentation level and the stack of previous indents. 16580ff61204231b1f307cf354618f876e8ca1d0f09Andrey Somov this.indents = new ArrayStack<Integer>(10); 1669629be70863521bead138c295351f3dec926ab1Andrey Somov this.indent = null; 1679629be70863521bead138c295351f3dec926ab1Andrey Somov // Flow level. 1689629be70863521bead138c295351f3dec926ab1Andrey Somov this.flowLevel = 0; 1699629be70863521bead138c295351f3dec926ab1Andrey Somov // Contexts. 1709629be70863521bead138c295351f3dec926ab1Andrey Somov mappingContext = false; 1719629be70863521bead138c295351f3dec926ab1Andrey Somov simpleKeyContext = false; 1729629be70863521bead138c295351f3dec926ab1Andrey Somov 1739629be70863521bead138c295351f3dec926ab1Andrey Somov // 1749629be70863521bead138c295351f3dec926ab1Andrey Somov // Characteristics of the last emitted character: 1759629be70863521bead138c295351f3dec926ab1Andrey Somov // - current position. 1769629be70863521bead138c295351f3dec926ab1Andrey Somov // - is it a whitespace? 1779629be70863521bead138c295351f3dec926ab1Andrey Somov // - is it an indention character 1789629be70863521bead138c295351f3dec926ab1Andrey Somov // (indentation space, '-', '?', or ':')? 1799629be70863521bead138c295351f3dec926ab1Andrey Somov column = 0; 1809629be70863521bead138c295351f3dec926ab1Andrey Somov whitespace = true; 1819629be70863521bead138c295351f3dec926ab1Andrey Somov indention = true; 1829629be70863521bead138c295351f3dec926ab1Andrey Somov 1839629be70863521bead138c295351f3dec926ab1Andrey Somov // Whether the document requires an explicit document indicator 1849629be70863521bead138c295351f3dec926ab1Andrey Somov openEnded = false; 1859629be70863521bead138c295351f3dec926ab1Andrey Somov 1869629be70863521bead138c295351f3dec926ab1Andrey Somov // Formatting details. 187fd03e2da32bb87716104bcdfc5b454ae970b277aAndrey Somov this.canonical = opts.isCanonical(); 188fd03e2da32bb87716104bcdfc5b454ae970b277aAndrey Somov this.prettyFlow = opts.isPrettyFlow(); 1899629be70863521bead138c295351f3dec926ab1Andrey Somov this.allowUnicode = opts.isAllowUnicode(); 1909629be70863521bead138c295351f3dec926ab1Andrey Somov this.bestIndent = 2; 1919629be70863521bead138c295351f3dec926ab1Andrey Somov if ((opts.getIndent() > MIN_INDENT) && (opts.getIndent() < MAX_INDENT)) { 1929629be70863521bead138c295351f3dec926ab1Andrey Somov this.bestIndent = opts.getIndent(); 1939629be70863521bead138c295351f3dec926ab1Andrey Somov } 194d1dd873170bcc2a9df0a512ae5fa5f073a8b64cftareq sha this.indicatorIndent = opts.getIndicatorIndent(); 1959629be70863521bead138c295351f3dec926ab1Andrey Somov this.bestWidth = 80; 1969629be70863521bead138c295351f3dec926ab1Andrey Somov if (opts.getWidth() > this.bestIndent * 2) { 1979629be70863521bead138c295351f3dec926ab1Andrey Somov this.bestWidth = opts.getWidth(); 1989629be70863521bead138c295351f3dec926ab1Andrey Somov } 199370faf2dd7606d5fe2f887012be73d40fa531559maslovalex this.bestLineBreak = opts.getLineBreak().getString().toCharArray(); 2007fbc6562f9ae67c2b9de8b8c5c74c62c42006cebVille Koskela this.splitLines = opts.getSplitLines(); 2019629be70863521bead138c295351f3dec926ab1Andrey Somov 2029629be70863521bead138c295351f3dec926ab1Andrey Somov // Tag prefixes. 2039629be70863521bead138c295351f3dec926ab1Andrey Somov this.tagPrefixes = new LinkedHashMap<String, String>(); 2049629be70863521bead138c295351f3dec926ab1Andrey Somov 2059629be70863521bead138c295351f3dec926ab1Andrey Somov // Prepared anchor and tag. 2069629be70863521bead138c295351f3dec926ab1Andrey Somov this.preparedAnchor = null; 2079629be70863521bead138c295351f3dec926ab1Andrey Somov this.preparedTag = null; 2089629be70863521bead138c295351f3dec926ab1Andrey Somov 2099629be70863521bead138c295351f3dec926ab1Andrey Somov // Scalar analysis and style. 2109629be70863521bead138c295351f3dec926ab1Andrey Somov this.analysis = null; 211d79a13b3448ff517eaa1a32ab5506db735d83c92as this.style = null; 2129629be70863521bead138c295351f3dec926ab1Andrey Somov } 2139629be70863521bead138c295351f3dec926ab1Andrey Somov 2149629be70863521bead138c295351f3dec926ab1Andrey Somov public void emit(Event event) throws IOException { 215c294eb822a2d69f64d2f1226d8a6f639b59a179aAndrey Somov this.events.add(event); 2169629be70863521bead138c295351f3dec926ab1Andrey Somov while (!needMoreEvents()) { 2179629be70863521bead138c295351f3dec926ab1Andrey Somov this.event = this.events.poll(); 2189629be70863521bead138c295351f3dec926ab1Andrey Somov this.state.expect(); 2199629be70863521bead138c295351f3dec926ab1Andrey Somov this.event = null; 2209629be70863521bead138c295351f3dec926ab1Andrey Somov } 2219629be70863521bead138c295351f3dec926ab1Andrey Somov } 2229629be70863521bead138c295351f3dec926ab1Andrey Somov 2239629be70863521bead138c295351f3dec926ab1Andrey Somov // In some cases, we wait for a few next events before emitting. 2249629be70863521bead138c295351f3dec926ab1Andrey Somov 2259629be70863521bead138c295351f3dec926ab1Andrey Somov private boolean needMoreEvents() { 2269629be70863521bead138c295351f3dec926ab1Andrey Somov if (events.isEmpty()) { 2279629be70863521bead138c295351f3dec926ab1Andrey Somov return true; 2289629be70863521bead138c295351f3dec926ab1Andrey Somov } 2299629be70863521bead138c295351f3dec926ab1Andrey Somov Event event = events.peek(); 2309629be70863521bead138c295351f3dec926ab1Andrey Somov if (event instanceof DocumentStartEvent) { 2319629be70863521bead138c295351f3dec926ab1Andrey Somov return needEvents(1); 2329629be70863521bead138c295351f3dec926ab1Andrey Somov } else if (event instanceof SequenceStartEvent) { 2339629be70863521bead138c295351f3dec926ab1Andrey Somov return needEvents(2); 2349629be70863521bead138c295351f3dec926ab1Andrey Somov } else if (event instanceof MappingStartEvent) { 2359629be70863521bead138c295351f3dec926ab1Andrey Somov return needEvents(3); 2369629be70863521bead138c295351f3dec926ab1Andrey Somov } else { 2379629be70863521bead138c295351f3dec926ab1Andrey Somov return false; 2389629be70863521bead138c295351f3dec926ab1Andrey Somov } 2399629be70863521bead138c295351f3dec926ab1Andrey Somov } 2409629be70863521bead138c295351f3dec926ab1Andrey Somov 2419629be70863521bead138c295351f3dec926ab1Andrey Somov private boolean needEvents(int count) { 2429629be70863521bead138c295351f3dec926ab1Andrey Somov int level = 0; 2439629be70863521bead138c295351f3dec926ab1Andrey Somov Iterator<Event> iter = events.iterator(); 2449629be70863521bead138c295351f3dec926ab1Andrey Somov iter.next(); 2459629be70863521bead138c295351f3dec926ab1Andrey Somov while (iter.hasNext()) { 2469629be70863521bead138c295351f3dec926ab1Andrey Somov Event event = iter.next(); 2479629be70863521bead138c295351f3dec926ab1Andrey Somov if (event instanceof DocumentStartEvent || event instanceof CollectionStartEvent) { 2489629be70863521bead138c295351f3dec926ab1Andrey Somov level++; 2499629be70863521bead138c295351f3dec926ab1Andrey Somov } else if (event instanceof DocumentEndEvent || event instanceof CollectionEndEvent) { 2509629be70863521bead138c295351f3dec926ab1Andrey Somov level--; 2519629be70863521bead138c295351f3dec926ab1Andrey Somov } else if (event instanceof StreamEndEvent) { 2529629be70863521bead138c295351f3dec926ab1Andrey Somov level = -1; 2539629be70863521bead138c295351f3dec926ab1Andrey Somov } 2549629be70863521bead138c295351f3dec926ab1Andrey Somov if (level < 0) { 2559629be70863521bead138c295351f3dec926ab1Andrey Somov return false; 2569629be70863521bead138c295351f3dec926ab1Andrey Somov } 2579629be70863521bead138c295351f3dec926ab1Andrey Somov } 2589629be70863521bead138c295351f3dec926ab1Andrey Somov return events.size() < count + 1; 2599629be70863521bead138c295351f3dec926ab1Andrey Somov } 2609629be70863521bead138c295351f3dec926ab1Andrey Somov 2619629be70863521bead138c295351f3dec926ab1Andrey Somov private void increaseIndent(boolean flow, boolean indentless) { 26280ff61204231b1f307cf354618f876e8ca1d0f09Andrey Somov indents.push(indent); 2639629be70863521bead138c295351f3dec926ab1Andrey Somov if (indent == null) { 2649629be70863521bead138c295351f3dec926ab1Andrey Somov if (flow) { 2659629be70863521bead138c295351f3dec926ab1Andrey Somov indent = bestIndent; 2669629be70863521bead138c295351f3dec926ab1Andrey Somov } else { 2679629be70863521bead138c295351f3dec926ab1Andrey Somov indent = 0; 2689629be70863521bead138c295351f3dec926ab1Andrey Somov } 2699629be70863521bead138c295351f3dec926ab1Andrey Somov } else if (!indentless) { 2709629be70863521bead138c295351f3dec926ab1Andrey Somov this.indent += bestIndent; 2719629be70863521bead138c295351f3dec926ab1Andrey Somov } 2729629be70863521bead138c295351f3dec926ab1Andrey Somov } 2739629be70863521bead138c295351f3dec926ab1Andrey Somov 2749629be70863521bead138c295351f3dec926ab1Andrey Somov // States 2759629be70863521bead138c295351f3dec926ab1Andrey Somov 2769629be70863521bead138c295351f3dec926ab1Andrey Somov // Stream handlers. 2779629be70863521bead138c295351f3dec926ab1Andrey Somov 2789629be70863521bead138c295351f3dec926ab1Andrey Somov private class ExpectStreamStart implements EmitterState { 2799629be70863521bead138c295351f3dec926ab1Andrey Somov public void expect() throws IOException { 2809629be70863521bead138c295351f3dec926ab1Andrey Somov if (event instanceof StreamStartEvent) { 2819629be70863521bead138c295351f3dec926ab1Andrey Somov writeStreamStart(); 2829629be70863521bead138c295351f3dec926ab1Andrey Somov state = new ExpectFirstDocumentStart(); 2839629be70863521bead138c295351f3dec926ab1Andrey Somov } else { 2849629be70863521bead138c295351f3dec926ab1Andrey Somov throw new EmitterException("expected StreamStartEvent, but got " + event); 2859629be70863521bead138c295351f3dec926ab1Andrey Somov } 2869629be70863521bead138c295351f3dec926ab1Andrey Somov } 2879629be70863521bead138c295351f3dec926ab1Andrey Somov } 2889629be70863521bead138c295351f3dec926ab1Andrey Somov 2899629be70863521bead138c295351f3dec926ab1Andrey Somov private class ExpectNothing implements EmitterState { 2909629be70863521bead138c295351f3dec926ab1Andrey Somov public void expect() throws IOException { 2919629be70863521bead138c295351f3dec926ab1Andrey Somov throw new EmitterException("expecting nothing, but got " + event); 2929629be70863521bead138c295351f3dec926ab1Andrey Somov } 2939629be70863521bead138c295351f3dec926ab1Andrey Somov } 2949629be70863521bead138c295351f3dec926ab1Andrey Somov 2959629be70863521bead138c295351f3dec926ab1Andrey Somov // Document handlers. 2969629be70863521bead138c295351f3dec926ab1Andrey Somov 2979629be70863521bead138c295351f3dec926ab1Andrey Somov private class ExpectFirstDocumentStart implements EmitterState { 2989629be70863521bead138c295351f3dec926ab1Andrey Somov public void expect() throws IOException { 2999629be70863521bead138c295351f3dec926ab1Andrey Somov new ExpectDocumentStart(true).expect(); 3009629be70863521bead138c295351f3dec926ab1Andrey Somov } 3019629be70863521bead138c295351f3dec926ab1Andrey Somov } 3029629be70863521bead138c295351f3dec926ab1Andrey Somov 3039629be70863521bead138c295351f3dec926ab1Andrey Somov private class ExpectDocumentStart implements EmitterState { 3049629be70863521bead138c295351f3dec926ab1Andrey Somov private boolean first; 3059629be70863521bead138c295351f3dec926ab1Andrey Somov 3069629be70863521bead138c295351f3dec926ab1Andrey Somov public ExpectDocumentStart(boolean first) { 3079629be70863521bead138c295351f3dec926ab1Andrey Somov this.first = first; 3089629be70863521bead138c295351f3dec926ab1Andrey Somov } 3099629be70863521bead138c295351f3dec926ab1Andrey Somov 3109629be70863521bead138c295351f3dec926ab1Andrey Somov public void expect() throws IOException { 3119629be70863521bead138c295351f3dec926ab1Andrey Somov if (event instanceof DocumentStartEvent) { 3129629be70863521bead138c295351f3dec926ab1Andrey Somov DocumentStartEvent ev = (DocumentStartEvent) event; 3139629be70863521bead138c295351f3dec926ab1Andrey Somov if ((ev.getVersion() != null || ev.getTags() != null) && openEnded) { 3149629be70863521bead138c295351f3dec926ab1Andrey Somov writeIndicator("...", true, false, false); 3159629be70863521bead138c295351f3dec926ab1Andrey Somov writeIndent(); 3169629be70863521bead138c295351f3dec926ab1Andrey Somov } 3179629be70863521bead138c295351f3dec926ab1Andrey Somov if (ev.getVersion() != null) { 3189629be70863521bead138c295351f3dec926ab1Andrey Somov String versionText = prepareVersion(ev.getVersion()); 3199629be70863521bead138c295351f3dec926ab1Andrey Somov writeVersionDirective(versionText); 3209629be70863521bead138c295351f3dec926ab1Andrey Somov } 3219629be70863521bead138c295351f3dec926ab1Andrey Somov tagPrefixes = new LinkedHashMap<String, String>(DEFAULT_TAG_PREFIXES); 3229629be70863521bead138c295351f3dec926ab1Andrey Somov if (ev.getTags() != null) { 3239629be70863521bead138c295351f3dec926ab1Andrey Somov Set<String> handles = new TreeSet<String>(ev.getTags().keySet()); 3249629be70863521bead138c295351f3dec926ab1Andrey Somov for (String handle : handles) { 3259629be70863521bead138c295351f3dec926ab1Andrey Somov String prefix = ev.getTags().get(handle); 3269629be70863521bead138c295351f3dec926ab1Andrey Somov tagPrefixes.put(prefix, handle); 3279629be70863521bead138c295351f3dec926ab1Andrey Somov String handleText = prepareTagHandle(handle); 3289629be70863521bead138c295351f3dec926ab1Andrey Somov String prefixText = prepareTagPrefix(prefix); 3299629be70863521bead138c295351f3dec926ab1Andrey Somov writeTagDirective(handleText, prefixText); 3309629be70863521bead138c295351f3dec926ab1Andrey Somov } 3319629be70863521bead138c295351f3dec926ab1Andrey Somov } 3329629be70863521bead138c295351f3dec926ab1Andrey Somov boolean implicit = first && !ev.getExplicit() && !canonical 333b0d589e0eaf2651114eaa7ffd48b753f466cff72Andrey Somov && ev.getVersion() == null 334b0d589e0eaf2651114eaa7ffd48b753f466cff72Andrey Somov && (ev.getTags() == null || ev.getTags().isEmpty()) 335b0d589e0eaf2651114eaa7ffd48b753f466cff72Andrey Somov && !checkEmptyDocument(); 3369629be70863521bead138c295351f3dec926ab1Andrey Somov if (!implicit) { 3379629be70863521bead138c295351f3dec926ab1Andrey Somov writeIndent(); 3389629be70863521bead138c295351f3dec926ab1Andrey Somov writeIndicator("---", true, false, false); 3399629be70863521bead138c295351f3dec926ab1Andrey Somov if (canonical) { 3409629be70863521bead138c295351f3dec926ab1Andrey Somov writeIndent(); 3419629be70863521bead138c295351f3dec926ab1Andrey Somov } 3429629be70863521bead138c295351f3dec926ab1Andrey Somov } 3439629be70863521bead138c295351f3dec926ab1Andrey Somov state = new ExpectDocumentRoot(); 3449629be70863521bead138c295351f3dec926ab1Andrey Somov } else if (event instanceof StreamEndEvent) { 3459629be70863521bead138c295351f3dec926ab1Andrey Somov // TODO fix 313 PyYAML changeset 3469629be70863521bead138c295351f3dec926ab1Andrey Somov // if (openEnded) { 3479629be70863521bead138c295351f3dec926ab1Andrey Somov // writeIndicator("...", true, false, false); 3489629be70863521bead138c295351f3dec926ab1Andrey Somov // writeIndent(); 3499629be70863521bead138c295351f3dec926ab1Andrey Somov // } 3509629be70863521bead138c295351f3dec926ab1Andrey Somov writeStreamEnd(); 3519629be70863521bead138c295351f3dec926ab1Andrey Somov state = new ExpectNothing(); 3529629be70863521bead138c295351f3dec926ab1Andrey Somov } else { 3539629be70863521bead138c295351f3dec926ab1Andrey Somov throw new EmitterException("expected DocumentStartEvent, but got " + event); 3549629be70863521bead138c295351f3dec926ab1Andrey Somov } 3559629be70863521bead138c295351f3dec926ab1Andrey Somov } 3569629be70863521bead138c295351f3dec926ab1Andrey Somov } 3579629be70863521bead138c295351f3dec926ab1Andrey Somov 3589629be70863521bead138c295351f3dec926ab1Andrey Somov private class ExpectDocumentEnd implements EmitterState { 3599629be70863521bead138c295351f3dec926ab1Andrey Somov public void expect() throws IOException { 3609629be70863521bead138c295351f3dec926ab1Andrey Somov if (event instanceof DocumentEndEvent) { 3619629be70863521bead138c295351f3dec926ab1Andrey Somov writeIndent(); 3629629be70863521bead138c295351f3dec926ab1Andrey Somov if (((DocumentEndEvent) event).getExplicit()) { 3639629be70863521bead138c295351f3dec926ab1Andrey Somov writeIndicator("...", true, false, false); 3649629be70863521bead138c295351f3dec926ab1Andrey Somov writeIndent(); 3659629be70863521bead138c295351f3dec926ab1Andrey Somov } 3669629be70863521bead138c295351f3dec926ab1Andrey Somov flushStream(); 3679629be70863521bead138c295351f3dec926ab1Andrey Somov state = new ExpectDocumentStart(false); 3689629be70863521bead138c295351f3dec926ab1Andrey Somov } else { 3699629be70863521bead138c295351f3dec926ab1Andrey Somov throw new EmitterException("expected DocumentEndEvent, but got " + event); 3709629be70863521bead138c295351f3dec926ab1Andrey Somov } 3719629be70863521bead138c295351f3dec926ab1Andrey Somov } 3729629be70863521bead138c295351f3dec926ab1Andrey Somov } 3739629be70863521bead138c295351f3dec926ab1Andrey Somov 3749629be70863521bead138c295351f3dec926ab1Andrey Somov private class ExpectDocumentRoot implements EmitterState { 3759629be70863521bead138c295351f3dec926ab1Andrey Somov public void expect() throws IOException { 37680ff61204231b1f307cf354618f876e8ca1d0f09Andrey Somov states.push(new ExpectDocumentEnd()); 377e46886ee2c0ee6d8819345e13b23baf91d82e2b0Andrey Somov expectNode(true, false, false); 3789629be70863521bead138c295351f3dec926ab1Andrey Somov } 3799629be70863521bead138c295351f3dec926ab1Andrey Somov } 3809629be70863521bead138c295351f3dec926ab1Andrey Somov 3819629be70863521bead138c295351f3dec926ab1Andrey Somov // Node handlers. 38265df777c9b28ba6d5c4d3ac5a437280bf112f622Andrey Somov 383e46886ee2c0ee6d8819345e13b23baf91d82e2b0Andrey Somov private void expectNode(boolean root, boolean mapping, boolean simpleKey) throws IOException { 3849629be70863521bead138c295351f3dec926ab1Andrey Somov rootContext = root; 3859629be70863521bead138c295351f3dec926ab1Andrey Somov mappingContext = mapping; 3869629be70863521bead138c295351f3dec926ab1Andrey Somov simpleKeyContext = simpleKey; 3879629be70863521bead138c295351f3dec926ab1Andrey Somov if (event instanceof AliasEvent) { 3889629be70863521bead138c295351f3dec926ab1Andrey Somov expectAlias(); 3899629be70863521bead138c295351f3dec926ab1Andrey Somov } else if (event instanceof ScalarEvent || event instanceof CollectionStartEvent) { 3909629be70863521bead138c295351f3dec926ab1Andrey Somov processAnchor("&"); 3919629be70863521bead138c295351f3dec926ab1Andrey Somov processTag(); 3929629be70863521bead138c295351f3dec926ab1Andrey Somov if (event instanceof ScalarEvent) { 3939629be70863521bead138c295351f3dec926ab1Andrey Somov expectScalar(); 3949629be70863521bead138c295351f3dec926ab1Andrey Somov } else if (event instanceof SequenceStartEvent) { 3959629be70863521bead138c295351f3dec926ab1Andrey Somov if (flowLevel != 0 || canonical || ((SequenceStartEvent) event).getFlowStyle() 3969629be70863521bead138c295351f3dec926ab1Andrey Somov || checkEmptySequence()) { 3979629be70863521bead138c295351f3dec926ab1Andrey Somov expectFlowSequence(); 3989629be70863521bead138c295351f3dec926ab1Andrey Somov } else { 3999629be70863521bead138c295351f3dec926ab1Andrey Somov expectBlockSequence(); 4009629be70863521bead138c295351f3dec926ab1Andrey Somov } 4019629be70863521bead138c295351f3dec926ab1Andrey Somov } else {// MappingStartEvent 4029629be70863521bead138c295351f3dec926ab1Andrey Somov if (flowLevel != 0 || canonical || ((MappingStartEvent) event).getFlowStyle() 4039629be70863521bead138c295351f3dec926ab1Andrey Somov || checkEmptyMapping()) { 4049629be70863521bead138c295351f3dec926ab1Andrey Somov expectFlowMapping(); 4059629be70863521bead138c295351f3dec926ab1Andrey Somov } else { 4069629be70863521bead138c295351f3dec926ab1Andrey Somov expectBlockMapping(); 4079629be70863521bead138c295351f3dec926ab1Andrey Somov } 4089629be70863521bead138c295351f3dec926ab1Andrey Somov } 4099629be70863521bead138c295351f3dec926ab1Andrey Somov } else { 4109629be70863521bead138c295351f3dec926ab1Andrey Somov throw new EmitterException("expected NodeEvent, but got " + event); 4119629be70863521bead138c295351f3dec926ab1Andrey Somov } 4129629be70863521bead138c295351f3dec926ab1Andrey Somov } 4139629be70863521bead138c295351f3dec926ab1Andrey Somov 4149629be70863521bead138c295351f3dec926ab1Andrey Somov private void expectAlias() throws IOException { 4159629be70863521bead138c295351f3dec926ab1Andrey Somov if (((NodeEvent) event).getAnchor() == null) { 4169629be70863521bead138c295351f3dec926ab1Andrey Somov throw new EmitterException("anchor is not specified for alias"); 4179629be70863521bead138c295351f3dec926ab1Andrey Somov } 4189629be70863521bead138c295351f3dec926ab1Andrey Somov processAnchor("*"); 41980ff61204231b1f307cf354618f876e8ca1d0f09Andrey Somov state = states.pop(); 4209629be70863521bead138c295351f3dec926ab1Andrey Somov } 4219629be70863521bead138c295351f3dec926ab1Andrey Somov 4229629be70863521bead138c295351f3dec926ab1Andrey Somov private void expectScalar() throws IOException { 4239629be70863521bead138c295351f3dec926ab1Andrey Somov increaseIndent(true, false); 4249629be70863521bead138c295351f3dec926ab1Andrey Somov processScalar(); 42580ff61204231b1f307cf354618f876e8ca1d0f09Andrey Somov indent = indents.pop(); 42680ff61204231b1f307cf354618f876e8ca1d0f09Andrey Somov state = states.pop(); 4279629be70863521bead138c295351f3dec926ab1Andrey Somov } 4289629be70863521bead138c295351f3dec926ab1Andrey Somov 4299629be70863521bead138c295351f3dec926ab1Andrey Somov // Flow sequence handlers. 4309629be70863521bead138c295351f3dec926ab1Andrey Somov 4319629be70863521bead138c295351f3dec926ab1Andrey Somov private void expectFlowSequence() throws IOException { 4329629be70863521bead138c295351f3dec926ab1Andrey Somov writeIndicator("[", true, true, false); 4339629be70863521bead138c295351f3dec926ab1Andrey Somov flowLevel++; 4349629be70863521bead138c295351f3dec926ab1Andrey Somov increaseIndent(true, false); 435fd03e2da32bb87716104bcdfc5b454ae970b277aAndrey Somov if (prettyFlow) { 4368cda6fba9cc20d9210a50e13a81b37affb84b39bobastard writeIndent(); 4378cda6fba9cc20d9210a50e13a81b37affb84b39bobastard } 438fd03e2da32bb87716104bcdfc5b454ae970b277aAndrey Somov state = new ExpectFirstFlowSequenceItem(); 4399629be70863521bead138c295351f3dec926ab1Andrey Somov } 4409629be70863521bead138c295351f3dec926ab1Andrey Somov 4419629be70863521bead138c295351f3dec926ab1Andrey Somov private class ExpectFirstFlowSequenceItem implements EmitterState { 4429629be70863521bead138c295351f3dec926ab1Andrey Somov public void expect() throws IOException { 4439629be70863521bead138c295351f3dec926ab1Andrey Somov if (event instanceof SequenceEndEvent) { 44480ff61204231b1f307cf354618f876e8ca1d0f09Andrey Somov indent = indents.pop(); 4459629be70863521bead138c295351f3dec926ab1Andrey Somov flowLevel--; 4469629be70863521bead138c295351f3dec926ab1Andrey Somov writeIndicator("]", false, false, false); 44780ff61204231b1f307cf354618f876e8ca1d0f09Andrey Somov state = states.pop(); 4489629be70863521bead138c295351f3dec926ab1Andrey Somov } else { 4497fbc6562f9ae67c2b9de8b8c5c74c62c42006cebVille Koskela if (canonical || (column > bestWidth && splitLines) || prettyFlow) { 4509629be70863521bead138c295351f3dec926ab1Andrey Somov writeIndent(); 4519629be70863521bead138c295351f3dec926ab1Andrey Somov } 45280ff61204231b1f307cf354618f876e8ca1d0f09Andrey Somov states.push(new ExpectFlowSequenceItem()); 453e46886ee2c0ee6d8819345e13b23baf91d82e2b0Andrey Somov expectNode(false, false, false); 4549629be70863521bead138c295351f3dec926ab1Andrey Somov } 4559629be70863521bead138c295351f3dec926ab1Andrey Somov } 4569629be70863521bead138c295351f3dec926ab1Andrey Somov } 4579629be70863521bead138c295351f3dec926ab1Andrey Somov 4589629be70863521bead138c295351f3dec926ab1Andrey Somov private class ExpectFlowSequenceItem implements EmitterState { 4599629be70863521bead138c295351f3dec926ab1Andrey Somov public void expect() throws IOException { 4609629be70863521bead138c295351f3dec926ab1Andrey Somov if (event instanceof SequenceEndEvent) { 46180ff61204231b1f307cf354618f876e8ca1d0f09Andrey Somov indent = indents.pop(); 4629629be70863521bead138c295351f3dec926ab1Andrey Somov flowLevel--; 4639629be70863521bead138c295351f3dec926ab1Andrey Somov if (canonical) { 4649629be70863521bead138c295351f3dec926ab1Andrey Somov writeIndicator(",", false, false, false); 4659629be70863521bead138c295351f3dec926ab1Andrey Somov writeIndent(); 4669629be70863521bead138c295351f3dec926ab1Andrey Somov } 4679629be70863521bead138c295351f3dec926ab1Andrey Somov writeIndicator("]", false, false, false); 468fd03e2da32bb87716104bcdfc5b454ae970b277aAndrey Somov if (prettyFlow) { 4698cda6fba9cc20d9210a50e13a81b37affb84b39bobastard writeIndent(); 4708cda6fba9cc20d9210a50e13a81b37affb84b39bobastard } 47180ff61204231b1f307cf354618f876e8ca1d0f09Andrey Somov state = states.pop(); 4729629be70863521bead138c295351f3dec926ab1Andrey Somov } else { 4739629be70863521bead138c295351f3dec926ab1Andrey Somov writeIndicator(",", false, false, false); 474c5a8071bf0313dfc294098d272dbecfdff7c98ceVille Koskela if (canonical || (column > bestWidth && splitLines) || prettyFlow) { 4759629be70863521bead138c295351f3dec926ab1Andrey Somov writeIndent(); 4769629be70863521bead138c295351f3dec926ab1Andrey Somov } 47780ff61204231b1f307cf354618f876e8ca1d0f09Andrey Somov states.push(new ExpectFlowSequenceItem()); 478e46886ee2c0ee6d8819345e13b23baf91d82e2b0Andrey Somov expectNode(false, false, false); 4799629be70863521bead138c295351f3dec926ab1Andrey Somov } 4809629be70863521bead138c295351f3dec926ab1Andrey Somov } 4819629be70863521bead138c295351f3dec926ab1Andrey Somov } 4829629be70863521bead138c295351f3dec926ab1Andrey Somov 4839629be70863521bead138c295351f3dec926ab1Andrey Somov // Flow mapping handlers. 4849629be70863521bead138c295351f3dec926ab1Andrey Somov 4859629be70863521bead138c295351f3dec926ab1Andrey Somov private void expectFlowMapping() throws IOException { 4869629be70863521bead138c295351f3dec926ab1Andrey Somov writeIndicator("{", true, true, false); 4879629be70863521bead138c295351f3dec926ab1Andrey Somov flowLevel++; 4889629be70863521bead138c295351f3dec926ab1Andrey Somov increaseIndent(true, false); 489fd03e2da32bb87716104bcdfc5b454ae970b277aAndrey Somov if (prettyFlow) { 4908cda6fba9cc20d9210a50e13a81b37affb84b39bobastard writeIndent(); 4918cda6fba9cc20d9210a50e13a81b37affb84b39bobastard } 4929629be70863521bead138c295351f3dec926ab1Andrey Somov state = new ExpectFirstFlowMappingKey(); 4939629be70863521bead138c295351f3dec926ab1Andrey Somov } 4949629be70863521bead138c295351f3dec926ab1Andrey Somov 4959629be70863521bead138c295351f3dec926ab1Andrey Somov private class ExpectFirstFlowMappingKey implements EmitterState { 4969629be70863521bead138c295351f3dec926ab1Andrey Somov public void expect() throws IOException { 4979629be70863521bead138c295351f3dec926ab1Andrey Somov if (event instanceof MappingEndEvent) { 49880ff61204231b1f307cf354618f876e8ca1d0f09Andrey Somov indent = indents.pop(); 4999629be70863521bead138c295351f3dec926ab1Andrey Somov flowLevel--; 5009629be70863521bead138c295351f3dec926ab1Andrey Somov writeIndicator("}", false, false, false); 50180ff61204231b1f307cf354618f876e8ca1d0f09Andrey Somov state = states.pop(); 5029629be70863521bead138c295351f3dec926ab1Andrey Somov } else { 5037fbc6562f9ae67c2b9de8b8c5c74c62c42006cebVille Koskela if (canonical || (column > bestWidth && splitLines) || prettyFlow) { 5049629be70863521bead138c295351f3dec926ab1Andrey Somov writeIndent(); 5059629be70863521bead138c295351f3dec926ab1Andrey Somov } 5069629be70863521bead138c295351f3dec926ab1Andrey Somov if (!canonical && checkSimpleKey()) { 50780ff61204231b1f307cf354618f876e8ca1d0f09Andrey Somov states.push(new ExpectFlowMappingSimpleValue()); 508e46886ee2c0ee6d8819345e13b23baf91d82e2b0Andrey Somov expectNode(false, true, true); 5099629be70863521bead138c295351f3dec926ab1Andrey Somov } else { 5109629be70863521bead138c295351f3dec926ab1Andrey Somov writeIndicator("?", true, false, false); 51180ff61204231b1f307cf354618f876e8ca1d0f09Andrey Somov states.push(new ExpectFlowMappingValue()); 512e46886ee2c0ee6d8819345e13b23baf91d82e2b0Andrey Somov expectNode(false, true, false); 5139629be70863521bead138c295351f3dec926ab1Andrey Somov } 5149629be70863521bead138c295351f3dec926ab1Andrey Somov } 5159629be70863521bead138c295351f3dec926ab1Andrey Somov } 5169629be70863521bead138c295351f3dec926ab1Andrey Somov } 5179629be70863521bead138c295351f3dec926ab1Andrey Somov 5189629be70863521bead138c295351f3dec926ab1Andrey Somov private class ExpectFlowMappingKey implements EmitterState { 5199629be70863521bead138c295351f3dec926ab1Andrey Somov public void expect() throws IOException { 5209629be70863521bead138c295351f3dec926ab1Andrey Somov if (event instanceof MappingEndEvent) { 52180ff61204231b1f307cf354618f876e8ca1d0f09Andrey Somov indent = indents.pop(); 5229629be70863521bead138c295351f3dec926ab1Andrey Somov flowLevel--; 5239629be70863521bead138c295351f3dec926ab1Andrey Somov if (canonical) { 5249629be70863521bead138c295351f3dec926ab1Andrey Somov writeIndicator(",", false, false, false); 5259629be70863521bead138c295351f3dec926ab1Andrey Somov writeIndent(); 5269629be70863521bead138c295351f3dec926ab1Andrey Somov } 527fd03e2da32bb87716104bcdfc5b454ae970b277aAndrey Somov if (prettyFlow) { 5288cda6fba9cc20d9210a50e13a81b37affb84b39bobastard writeIndent(); 5298cda6fba9cc20d9210a50e13a81b37affb84b39bobastard } 5309629be70863521bead138c295351f3dec926ab1Andrey Somov writeIndicator("}", false, false, false); 53180ff61204231b1f307cf354618f876e8ca1d0f09Andrey Somov state = states.pop(); 5329629be70863521bead138c295351f3dec926ab1Andrey Somov } else { 5339629be70863521bead138c295351f3dec926ab1Andrey Somov writeIndicator(",", false, false, false); 5347fbc6562f9ae67c2b9de8b8c5c74c62c42006cebVille Koskela if (canonical || (column > bestWidth && splitLines) || prettyFlow) { 5359629be70863521bead138c295351f3dec926ab1Andrey Somov writeIndent(); 5369629be70863521bead138c295351f3dec926ab1Andrey Somov } 5379629be70863521bead138c295351f3dec926ab1Andrey Somov if (!canonical && checkSimpleKey()) { 53880ff61204231b1f307cf354618f876e8ca1d0f09Andrey Somov states.push(new ExpectFlowMappingSimpleValue()); 539e46886ee2c0ee6d8819345e13b23baf91d82e2b0Andrey Somov expectNode(false, true, true); 5409629be70863521bead138c295351f3dec926ab1Andrey Somov } else { 5419629be70863521bead138c295351f3dec926ab1Andrey Somov writeIndicator("?", true, false, false); 54280ff61204231b1f307cf354618f876e8ca1d0f09Andrey Somov states.push(new ExpectFlowMappingValue()); 543e46886ee2c0ee6d8819345e13b23baf91d82e2b0Andrey Somov expectNode(false, true, false); 5449629be70863521bead138c295351f3dec926ab1Andrey Somov } 5459629be70863521bead138c295351f3dec926ab1Andrey Somov } 5469629be70863521bead138c295351f3dec926ab1Andrey Somov } 5479629be70863521bead138c295351f3dec926ab1Andrey Somov } 5489629be70863521bead138c295351f3dec926ab1Andrey Somov 5499629be70863521bead138c295351f3dec926ab1Andrey Somov private class ExpectFlowMappingSimpleValue implements EmitterState { 5509629be70863521bead138c295351f3dec926ab1Andrey Somov public void expect() throws IOException { 5519629be70863521bead138c295351f3dec926ab1Andrey Somov writeIndicator(":", false, false, false); 55280ff61204231b1f307cf354618f876e8ca1d0f09Andrey Somov states.push(new ExpectFlowMappingKey()); 553e46886ee2c0ee6d8819345e13b23baf91d82e2b0Andrey Somov expectNode(false, true, false); 5549629be70863521bead138c295351f3dec926ab1Andrey Somov } 5559629be70863521bead138c295351f3dec926ab1Andrey Somov } 5569629be70863521bead138c295351f3dec926ab1Andrey Somov 5579629be70863521bead138c295351f3dec926ab1Andrey Somov private class ExpectFlowMappingValue implements EmitterState { 5589629be70863521bead138c295351f3dec926ab1Andrey Somov public void expect() throws IOException { 5599cddfdc4dc0eb69b3c0e4f9f9a818177707e2ea0Andrey Somov if (canonical || (column > bestWidth) || prettyFlow) { 5609629be70863521bead138c295351f3dec926ab1Andrey Somov writeIndent(); 5619629be70863521bead138c295351f3dec926ab1Andrey Somov } 5629629be70863521bead138c295351f3dec926ab1Andrey Somov writeIndicator(":", true, false, false); 56380ff61204231b1f307cf354618f876e8ca1d0f09Andrey Somov states.push(new ExpectFlowMappingKey()); 564e46886ee2c0ee6d8819345e13b23baf91d82e2b0Andrey Somov expectNode(false, true, false); 5659629be70863521bead138c295351f3dec926ab1Andrey Somov } 5669629be70863521bead138c295351f3dec926ab1Andrey Somov } 5679629be70863521bead138c295351f3dec926ab1Andrey Somov 5689629be70863521bead138c295351f3dec926ab1Andrey Somov // Block sequence handlers. 5699629be70863521bead138c295351f3dec926ab1Andrey Somov 5709629be70863521bead138c295351f3dec926ab1Andrey Somov private void expectBlockSequence() throws IOException { 57125ac3b280b35ddb9167e0528626e2ec14488f173Andrey Somov boolean indentless = mappingContext && !indention; 5729629be70863521bead138c295351f3dec926ab1Andrey Somov increaseIndent(false, indentless); 5739629be70863521bead138c295351f3dec926ab1Andrey Somov state = new ExpectFirstBlockSequenceItem(); 5749629be70863521bead138c295351f3dec926ab1Andrey Somov } 5759629be70863521bead138c295351f3dec926ab1Andrey Somov 5769629be70863521bead138c295351f3dec926ab1Andrey Somov private class ExpectFirstBlockSequenceItem implements EmitterState { 5779629be70863521bead138c295351f3dec926ab1Andrey Somov public void expect() throws IOException { 5789629be70863521bead138c295351f3dec926ab1Andrey Somov new ExpectBlockSequenceItem(true).expect(); 5799629be70863521bead138c295351f3dec926ab1Andrey Somov } 5809629be70863521bead138c295351f3dec926ab1Andrey Somov } 5819629be70863521bead138c295351f3dec926ab1Andrey Somov 5829629be70863521bead138c295351f3dec926ab1Andrey Somov private class ExpectBlockSequenceItem implements EmitterState { 5839629be70863521bead138c295351f3dec926ab1Andrey Somov private boolean first; 5849629be70863521bead138c295351f3dec926ab1Andrey Somov 5859629be70863521bead138c295351f3dec926ab1Andrey Somov public ExpectBlockSequenceItem(boolean first) { 5869629be70863521bead138c295351f3dec926ab1Andrey Somov this.first = first; 5879629be70863521bead138c295351f3dec926ab1Andrey Somov } 5889629be70863521bead138c295351f3dec926ab1Andrey Somov 5899629be70863521bead138c295351f3dec926ab1Andrey Somov public void expect() throws IOException { 5909629be70863521bead138c295351f3dec926ab1Andrey Somov if (!this.first && event instanceof SequenceEndEvent) { 59180ff61204231b1f307cf354618f876e8ca1d0f09Andrey Somov indent = indents.pop(); 59280ff61204231b1f307cf354618f876e8ca1d0f09Andrey Somov state = states.pop(); 5939629be70863521bead138c295351f3dec926ab1Andrey Somov } else { 5949629be70863521bead138c295351f3dec926ab1Andrey Somov writeIndent(); 595d1dd873170bcc2a9df0a512ae5fa5f073a8b64cftareq sha writeWhitespace(indicatorIndent); 5969629be70863521bead138c295351f3dec926ab1Andrey Somov writeIndicator("-", true, false, true); 59780ff61204231b1f307cf354618f876e8ca1d0f09Andrey Somov states.push(new ExpectBlockSequenceItem(false)); 598e46886ee2c0ee6d8819345e13b23baf91d82e2b0Andrey Somov expectNode(false, false, false); 5999629be70863521bead138c295351f3dec926ab1Andrey Somov } 6009629be70863521bead138c295351f3dec926ab1Andrey Somov } 6019629be70863521bead138c295351f3dec926ab1Andrey Somov } 6029629be70863521bead138c295351f3dec926ab1Andrey Somov 6039629be70863521bead138c295351f3dec926ab1Andrey Somov // Block mapping handlers. 6049629be70863521bead138c295351f3dec926ab1Andrey Somov private void expectBlockMapping() throws IOException { 6059629be70863521bead138c295351f3dec926ab1Andrey Somov increaseIndent(false, false); 6069629be70863521bead138c295351f3dec926ab1Andrey Somov state = new ExpectFirstBlockMappingKey(); 6079629be70863521bead138c295351f3dec926ab1Andrey Somov } 6089629be70863521bead138c295351f3dec926ab1Andrey Somov 6099629be70863521bead138c295351f3dec926ab1Andrey Somov private class ExpectFirstBlockMappingKey implements EmitterState { 6109629be70863521bead138c295351f3dec926ab1Andrey Somov public void expect() throws IOException { 6119629be70863521bead138c295351f3dec926ab1Andrey Somov new ExpectBlockMappingKey(true).expect(); 6129629be70863521bead138c295351f3dec926ab1Andrey Somov } 6139629be70863521bead138c295351f3dec926ab1Andrey Somov } 6149629be70863521bead138c295351f3dec926ab1Andrey Somov 6159629be70863521bead138c295351f3dec926ab1Andrey Somov private class ExpectBlockMappingKey implements EmitterState { 6169629be70863521bead138c295351f3dec926ab1Andrey Somov private boolean first; 6179629be70863521bead138c295351f3dec926ab1Andrey Somov 6189629be70863521bead138c295351f3dec926ab1Andrey Somov public ExpectBlockMappingKey(boolean first) { 6199629be70863521bead138c295351f3dec926ab1Andrey Somov this.first = first; 6209629be70863521bead138c295351f3dec926ab1Andrey Somov } 6219629be70863521bead138c295351f3dec926ab1Andrey Somov 6229629be70863521bead138c295351f3dec926ab1Andrey Somov public void expect() throws IOException { 6239629be70863521bead138c295351f3dec926ab1Andrey Somov if (!this.first && event instanceof MappingEndEvent) { 62480ff61204231b1f307cf354618f876e8ca1d0f09Andrey Somov indent = indents.pop(); 62580ff61204231b1f307cf354618f876e8ca1d0f09Andrey Somov state = states.pop(); 6269629be70863521bead138c295351f3dec926ab1Andrey Somov } else { 6279629be70863521bead138c295351f3dec926ab1Andrey Somov writeIndent(); 6289629be70863521bead138c295351f3dec926ab1Andrey Somov if (checkSimpleKey()) { 62980ff61204231b1f307cf354618f876e8ca1d0f09Andrey Somov states.push(new ExpectBlockMappingSimpleValue()); 630e46886ee2c0ee6d8819345e13b23baf91d82e2b0Andrey Somov expectNode(false, true, true); 6319629be70863521bead138c295351f3dec926ab1Andrey Somov } else { 6329629be70863521bead138c295351f3dec926ab1Andrey Somov writeIndicator("?", true, false, true); 63380ff61204231b1f307cf354618f876e8ca1d0f09Andrey Somov states.push(new ExpectBlockMappingValue()); 634e46886ee2c0ee6d8819345e13b23baf91d82e2b0Andrey Somov expectNode(false, true, false); 6359629be70863521bead138c295351f3dec926ab1Andrey Somov } 6369629be70863521bead138c295351f3dec926ab1Andrey Somov } 6379629be70863521bead138c295351f3dec926ab1Andrey Somov } 6389629be70863521bead138c295351f3dec926ab1Andrey Somov } 6399629be70863521bead138c295351f3dec926ab1Andrey Somov 6409629be70863521bead138c295351f3dec926ab1Andrey Somov private class ExpectBlockMappingSimpleValue implements EmitterState { 6419629be70863521bead138c295351f3dec926ab1Andrey Somov public void expect() throws IOException { 6429629be70863521bead138c295351f3dec926ab1Andrey Somov writeIndicator(":", false, false, false); 64380ff61204231b1f307cf354618f876e8ca1d0f09Andrey Somov states.push(new ExpectBlockMappingKey(false)); 644e46886ee2c0ee6d8819345e13b23baf91d82e2b0Andrey Somov expectNode(false, true, false); 6459629be70863521bead138c295351f3dec926ab1Andrey Somov } 6469629be70863521bead138c295351f3dec926ab1Andrey Somov } 6479629be70863521bead138c295351f3dec926ab1Andrey Somov 6489629be70863521bead138c295351f3dec926ab1Andrey Somov private class ExpectBlockMappingValue implements EmitterState { 6499629be70863521bead138c295351f3dec926ab1Andrey Somov public void expect() throws IOException { 6509629be70863521bead138c295351f3dec926ab1Andrey Somov writeIndent(); 6519629be70863521bead138c295351f3dec926ab1Andrey Somov writeIndicator(":", true, false, true); 65280ff61204231b1f307cf354618f876e8ca1d0f09Andrey Somov states.push(new ExpectBlockMappingKey(false)); 653e46886ee2c0ee6d8819345e13b23baf91d82e2b0Andrey Somov expectNode(false, true, false); 6549629be70863521bead138c295351f3dec926ab1Andrey Somov } 6559629be70863521bead138c295351f3dec926ab1Andrey Somov } 6569629be70863521bead138c295351f3dec926ab1Andrey Somov 6579629be70863521bead138c295351f3dec926ab1Andrey Somov // Checkers. 6589629be70863521bead138c295351f3dec926ab1Andrey Somov 6599629be70863521bead138c295351f3dec926ab1Andrey Somov private boolean checkEmptySequence() { 66025ac3b280b35ddb9167e0528626e2ec14488f173Andrey Somov return event instanceof SequenceStartEvent && !events.isEmpty() && events.peek() instanceof SequenceEndEvent; 6619629be70863521bead138c295351f3dec926ab1Andrey Somov } 6629629be70863521bead138c295351f3dec926ab1Andrey Somov 6639629be70863521bead138c295351f3dec926ab1Andrey Somov private boolean checkEmptyMapping() { 66425ac3b280b35ddb9167e0528626e2ec14488f173Andrey Somov return event instanceof MappingStartEvent && !events.isEmpty() && events.peek() instanceof MappingEndEvent; 6659629be70863521bead138c295351f3dec926ab1Andrey Somov } 6669629be70863521bead138c295351f3dec926ab1Andrey Somov 6679629be70863521bead138c295351f3dec926ab1Andrey Somov private boolean checkEmptyDocument() { 6689629be70863521bead138c295351f3dec926ab1Andrey Somov if (!(event instanceof DocumentStartEvent) || events.isEmpty()) { 6699629be70863521bead138c295351f3dec926ab1Andrey Somov return false; 6709629be70863521bead138c295351f3dec926ab1Andrey Somov } 6719629be70863521bead138c295351f3dec926ab1Andrey Somov Event event = events.peek(); 6729629be70863521bead138c295351f3dec926ab1Andrey Somov if (event instanceof ScalarEvent) { 6739629be70863521bead138c295351f3dec926ab1Andrey Somov ScalarEvent e = (ScalarEvent) event; 67425ac3b280b35ddb9167e0528626e2ec14488f173Andrey Somov return e.getAnchor() == null && e.getTag() == null && e.getImplicit() != null && e 67525ac3b280b35ddb9167e0528626e2ec14488f173Andrey Somov .getValue().length() == 0; 6769629be70863521bead138c295351f3dec926ab1Andrey Somov } 677370faf2dd7606d5fe2f887012be73d40fa531559maslovalex return false; 6789629be70863521bead138c295351f3dec926ab1Andrey Somov } 6799629be70863521bead138c295351f3dec926ab1Andrey Somov 6809629be70863521bead138c295351f3dec926ab1Andrey Somov private boolean checkSimpleKey() { 6819629be70863521bead138c295351f3dec926ab1Andrey Somov int length = 0; 6829629be70863521bead138c295351f3dec926ab1Andrey Somov if (event instanceof NodeEvent && ((NodeEvent) event).getAnchor() != null) { 6839629be70863521bead138c295351f3dec926ab1Andrey Somov if (preparedAnchor == null) { 6849629be70863521bead138c295351f3dec926ab1Andrey Somov preparedAnchor = prepareAnchor(((NodeEvent) event).getAnchor()); 6859629be70863521bead138c295351f3dec926ab1Andrey Somov } 6869629be70863521bead138c295351f3dec926ab1Andrey Somov length += preparedAnchor.length(); 6879629be70863521bead138c295351f3dec926ab1Andrey Somov } 6889629be70863521bead138c295351f3dec926ab1Andrey Somov String tag = null; 6899629be70863521bead138c295351f3dec926ab1Andrey Somov if (event instanceof ScalarEvent) { 6909629be70863521bead138c295351f3dec926ab1Andrey Somov tag = ((ScalarEvent) event).getTag(); 6919629be70863521bead138c295351f3dec926ab1Andrey Somov } else if (event instanceof CollectionStartEvent) { 6929629be70863521bead138c295351f3dec926ab1Andrey Somov tag = ((CollectionStartEvent) event).getTag(); 6939629be70863521bead138c295351f3dec926ab1Andrey Somov } 6949629be70863521bead138c295351f3dec926ab1Andrey Somov if (tag != null) { 6959629be70863521bead138c295351f3dec926ab1Andrey Somov if (preparedTag == null) { 6969629be70863521bead138c295351f3dec926ab1Andrey Somov preparedTag = prepareTag(tag); 6979629be70863521bead138c295351f3dec926ab1Andrey Somov } 6989629be70863521bead138c295351f3dec926ab1Andrey Somov length += preparedTag.length(); 6999629be70863521bead138c295351f3dec926ab1Andrey Somov } 7009629be70863521bead138c295351f3dec926ab1Andrey Somov if (event instanceof ScalarEvent) { 7019629be70863521bead138c295351f3dec926ab1Andrey Somov if (analysis == null) { 7029629be70863521bead138c295351f3dec926ab1Andrey Somov analysis = analyzeScalar(((ScalarEvent) event).getValue()); 7039629be70863521bead138c295351f3dec926ab1Andrey Somov } 7049629be70863521bead138c295351f3dec926ab1Andrey Somov length += analysis.scalar.length(); 7059629be70863521bead138c295351f3dec926ab1Andrey Somov } 70625ac3b280b35ddb9167e0528626e2ec14488f173Andrey Somov return length < 128 && (event instanceof AliasEvent 7079629be70863521bead138c295351f3dec926ab1Andrey Somov || (event instanceof ScalarEvent && !analysis.empty && !analysis.multiline) 70825ac3b280b35ddb9167e0528626e2ec14488f173Andrey Somov || checkEmptySequence() || checkEmptyMapping()); 7099629be70863521bead138c295351f3dec926ab1Andrey Somov } 7109629be70863521bead138c295351f3dec926ab1Andrey Somov 7119629be70863521bead138c295351f3dec926ab1Andrey Somov // Anchor, Tag, and Scalar processors. 7129629be70863521bead138c295351f3dec926ab1Andrey Somov 7139629be70863521bead138c295351f3dec926ab1Andrey Somov private void processAnchor(String indicator) throws IOException { 7149629be70863521bead138c295351f3dec926ab1Andrey Somov NodeEvent ev = (NodeEvent) event; 7159629be70863521bead138c295351f3dec926ab1Andrey Somov if (ev.getAnchor() == null) { 7169629be70863521bead138c295351f3dec926ab1Andrey Somov preparedAnchor = null; 7179629be70863521bead138c295351f3dec926ab1Andrey Somov return; 7189629be70863521bead138c295351f3dec926ab1Andrey Somov } 7199629be70863521bead138c295351f3dec926ab1Andrey Somov if (preparedAnchor == null) { 7209629be70863521bead138c295351f3dec926ab1Andrey Somov preparedAnchor = prepareAnchor(ev.getAnchor()); 7219629be70863521bead138c295351f3dec926ab1Andrey Somov } 722d830de2dc8edea813a00c18193802d2bab3fded0Andrey Somov writeIndicator(indicator + preparedAnchor, true, false, false); 7239629be70863521bead138c295351f3dec926ab1Andrey Somov preparedAnchor = null; 7249629be70863521bead138c295351f3dec926ab1Andrey Somov } 7259629be70863521bead138c295351f3dec926ab1Andrey Somov 7269629be70863521bead138c295351f3dec926ab1Andrey Somov private void processTag() throws IOException { 7279629be70863521bead138c295351f3dec926ab1Andrey Somov String tag = null; 7289629be70863521bead138c295351f3dec926ab1Andrey Somov if (event instanceof ScalarEvent) { 7299629be70863521bead138c295351f3dec926ab1Andrey Somov ScalarEvent ev = (ScalarEvent) event; 7309629be70863521bead138c295351f3dec926ab1Andrey Somov tag = ev.getTag(); 731d79a13b3448ff517eaa1a32ab5506db735d83c92as if (style == null) { 7329629be70863521bead138c295351f3dec926ab1Andrey Somov style = chooseScalarStyle(); 7339629be70863521bead138c295351f3dec926ab1Andrey Somov } 73425ac3b280b35ddb9167e0528626e2ec14488f173Andrey Somov if ((!canonical || tag == null) && ((style == null && ev.getImplicit() 7358a6a5222f082f91aa99d15062e7ec8cd52125603Andrey Somov .canOmitTagInPlainScalar()) || (style != null && ev.getImplicit() 73625ac3b280b35ddb9167e0528626e2ec14488f173Andrey Somov .canOmitTagInNonPlainScalar()))) { 7379629be70863521bead138c295351f3dec926ab1Andrey Somov preparedTag = null; 7389629be70863521bead138c295351f3dec926ab1Andrey Somov return; 7399629be70863521bead138c295351f3dec926ab1Andrey Somov } 7408a6a5222f082f91aa99d15062e7ec8cd52125603Andrey Somov if (ev.getImplicit().canOmitTagInPlainScalar() && tag == null) { 7419629be70863521bead138c295351f3dec926ab1Andrey Somov tag = "!"; 7429629be70863521bead138c295351f3dec926ab1Andrey Somov preparedTag = null; 7439629be70863521bead138c295351f3dec926ab1Andrey Somov } 7449629be70863521bead138c295351f3dec926ab1Andrey Somov } else { 7459629be70863521bead138c295351f3dec926ab1Andrey Somov CollectionStartEvent ev = (CollectionStartEvent) event; 7469629be70863521bead138c295351f3dec926ab1Andrey Somov tag = ev.getTag(); 7479629be70863521bead138c295351f3dec926ab1Andrey Somov if ((!canonical || tag == null) && ev.getImplicit()) { 7489629be70863521bead138c295351f3dec926ab1Andrey Somov preparedTag = null; 7499629be70863521bead138c295351f3dec926ab1Andrey Somov return; 7509629be70863521bead138c295351f3dec926ab1Andrey Somov } 7519629be70863521bead138c295351f3dec926ab1Andrey Somov } 7529629be70863521bead138c295351f3dec926ab1Andrey Somov if (tag == null) { 7539629be70863521bead138c295351f3dec926ab1Andrey Somov throw new EmitterException("tag is not specified"); 7549629be70863521bead138c295351f3dec926ab1Andrey Somov } 7559629be70863521bead138c295351f3dec926ab1Andrey Somov if (preparedTag == null) { 7569629be70863521bead138c295351f3dec926ab1Andrey Somov preparedTag = prepareTag(tag); 7579629be70863521bead138c295351f3dec926ab1Andrey Somov } 758d830de2dc8edea813a00c18193802d2bab3fded0Andrey Somov writeIndicator(preparedTag, true, false, false); 7599629be70863521bead138c295351f3dec926ab1Andrey Somov preparedTag = null; 7609629be70863521bead138c295351f3dec926ab1Andrey Somov } 7619629be70863521bead138c295351f3dec926ab1Andrey Somov 762d79a13b3448ff517eaa1a32ab5506db735d83c92as private Character chooseScalarStyle() { 7639629be70863521bead138c295351f3dec926ab1Andrey Somov ScalarEvent ev = (ScalarEvent) event; 7649629be70863521bead138c295351f3dec926ab1Andrey Somov if (analysis == null) { 7659629be70863521bead138c295351f3dec926ab1Andrey Somov analysis = analyzeScalar(ev.getValue()); 7669629be70863521bead138c295351f3dec926ab1Andrey Somov } 7679629be70863521bead138c295351f3dec926ab1Andrey Somov if (ev.getStyle() != null && ev.getStyle() == '"' || this.canonical) { 7689629be70863521bead138c295351f3dec926ab1Andrey Somov return '"'; 7699629be70863521bead138c295351f3dec926ab1Andrey Somov } 7708a6a5222f082f91aa99d15062e7ec8cd52125603Andrey Somov if (ev.getStyle() == null && ev.getImplicit().canOmitTagInPlainScalar()) { 7719629be70863521bead138c295351f3dec926ab1Andrey Somov if (!(simpleKeyContext && (analysis.empty || analysis.multiline)) 7729629be70863521bead138c295351f3dec926ab1Andrey Somov && ((flowLevel != 0 && analysis.allowFlowPlain) || (flowLevel == 0 && analysis.allowBlockPlain))) { 773d79a13b3448ff517eaa1a32ab5506db735d83c92as return null; 7749629be70863521bead138c295351f3dec926ab1Andrey Somov } 7759629be70863521bead138c295351f3dec926ab1Andrey Somov } 7769629be70863521bead138c295351f3dec926ab1Andrey Somov if (ev.getStyle() != null && (ev.getStyle() == '|' || ev.getStyle() == '>')) { 7779629be70863521bead138c295351f3dec926ab1Andrey Somov if (flowLevel == 0 && !simpleKeyContext && analysis.allowBlock) { 7789629be70863521bead138c295351f3dec926ab1Andrey Somov return ev.getStyle(); 7799629be70863521bead138c295351f3dec926ab1Andrey Somov } 7809629be70863521bead138c295351f3dec926ab1Andrey Somov } 7819629be70863521bead138c295351f3dec926ab1Andrey Somov if (ev.getStyle() == null || ev.getStyle() == '\'') { 7829629be70863521bead138c295351f3dec926ab1Andrey Somov if (analysis.allowSingleQuoted && !(simpleKeyContext && analysis.multiline)) { 7839629be70863521bead138c295351f3dec926ab1Andrey Somov return '\''; 7849629be70863521bead138c295351f3dec926ab1Andrey Somov } 7859629be70863521bead138c295351f3dec926ab1Andrey Somov } 7869629be70863521bead138c295351f3dec926ab1Andrey Somov return '"'; 7879629be70863521bead138c295351f3dec926ab1Andrey Somov } 7889629be70863521bead138c295351f3dec926ab1Andrey Somov 7899629be70863521bead138c295351f3dec926ab1Andrey Somov private void processScalar() throws IOException { 7909629be70863521bead138c295351f3dec926ab1Andrey Somov ScalarEvent ev = (ScalarEvent) event; 7919629be70863521bead138c295351f3dec926ab1Andrey Somov if (analysis == null) { 7929629be70863521bead138c295351f3dec926ab1Andrey Somov analysis = analyzeScalar(ev.getValue()); 7939629be70863521bead138c295351f3dec926ab1Andrey Somov } 794d79a13b3448ff517eaa1a32ab5506db735d83c92as if (style == null) { 7959629be70863521bead138c295351f3dec926ab1Andrey Somov style = chooseScalarStyle(); 7969629be70863521bead138c295351f3dec926ab1Andrey Somov } 7977fbc6562f9ae67c2b9de8b8c5c74c62c42006cebVille Koskela boolean split = !simpleKeyContext && splitLines; 798d79a13b3448ff517eaa1a32ab5506db735d83c92as if (style == null) { 7999629be70863521bead138c295351f3dec926ab1Andrey Somov writePlain(analysis.scalar, split); 800d79a13b3448ff517eaa1a32ab5506db735d83c92as } else { 801d79a13b3448ff517eaa1a32ab5506db735d83c92as switch (style) { 802d79a13b3448ff517eaa1a32ab5506db735d83c92as case '"': 803d79a13b3448ff517eaa1a32ab5506db735d83c92as writeDoubleQuoted(analysis.scalar, split); 804d79a13b3448ff517eaa1a32ab5506db735d83c92as break; 805d79a13b3448ff517eaa1a32ab5506db735d83c92as case '\'': 806d79a13b3448ff517eaa1a32ab5506db735d83c92as writeSingleQuoted(analysis.scalar, split); 807d79a13b3448ff517eaa1a32ab5506db735d83c92as break; 808d79a13b3448ff517eaa1a32ab5506db735d83c92as case '>': 8097fbc6562f9ae67c2b9de8b8c5c74c62c42006cebVille Koskela writeFolded(analysis.scalar, split); 810d79a13b3448ff517eaa1a32ab5506db735d83c92as break; 811d79a13b3448ff517eaa1a32ab5506db735d83c92as case '|': 812d79a13b3448ff517eaa1a32ab5506db735d83c92as writeLiteral(analysis.scalar); 813d79a13b3448ff517eaa1a32ab5506db735d83c92as break; 81434f59d77fd0a29b085d4c642eb1db6b8925fc3c3Andrey Somov default: 81534f59d77fd0a29b085d4c642eb1db6b8925fc3c3Andrey Somov throw new YAMLException("Unexpected style: " + style); 816d79a13b3448ff517eaa1a32ab5506db735d83c92as } 8179629be70863521bead138c295351f3dec926ab1Andrey Somov } 8189629be70863521bead138c295351f3dec926ab1Andrey Somov analysis = null; 819d79a13b3448ff517eaa1a32ab5506db735d83c92as style = null; 8209629be70863521bead138c295351f3dec926ab1Andrey Somov } 8219629be70863521bead138c295351f3dec926ab1Andrey Somov 8229629be70863521bead138c295351f3dec926ab1Andrey Somov // Analyzers. 82365df777c9b28ba6d5c4d3ac5a437280bf112f622Andrey Somov 8245476b912d698337c3bd69e38cadf15f60986e269Andrey Somov private String prepareVersion(Version version) { 825591473df603cfa63f199ee5f7a75e57f39cf2840Andrey Somov if (version.major() != 1) { 8265476b912d698337c3bd69e38cadf15f60986e269Andrey Somov throw new EmitterException("unsupported YAML version: " + version); 8279629be70863521bead138c295351f3dec926ab1Andrey Somov } 8285476b912d698337c3bd69e38cadf15f60986e269Andrey Somov return version.getRepresentation(); 8299629be70863521bead138c295351f3dec926ab1Andrey Somov } 8309629be70863521bead138c295351f3dec926ab1Andrey Somov 8319629be70863521bead138c295351f3dec926ab1Andrey Somov private final static Pattern HANDLE_FORMAT = Pattern.compile("^![-_\\w]*!$"); 8329629be70863521bead138c295351f3dec926ab1Andrey Somov 8339629be70863521bead138c295351f3dec926ab1Andrey Somov private String prepareTagHandle(String handle) { 834d830de2dc8edea813a00c18193802d2bab3fded0Andrey Somov if (handle.length() == 0) { 8359629be70863521bead138c295351f3dec926ab1Andrey Somov throw new EmitterException("tag handle must not be empty"); 8369629be70863521bead138c295351f3dec926ab1Andrey Somov } else if (handle.charAt(0) != '!' || handle.charAt(handle.length() - 1) != '!') { 8379629be70863521bead138c295351f3dec926ab1Andrey Somov throw new EmitterException("tag handle must start and end with '!': " + handle); 8389629be70863521bead138c295351f3dec926ab1Andrey Somov } else if (!"!".equals(handle) && !HANDLE_FORMAT.matcher(handle).matches()) { 8399629be70863521bead138c295351f3dec926ab1Andrey Somov throw new EmitterException("invalid character in the tag handle: " + handle); 8409629be70863521bead138c295351f3dec926ab1Andrey Somov } 8419629be70863521bead138c295351f3dec926ab1Andrey Somov return handle; 8429629be70863521bead138c295351f3dec926ab1Andrey Somov } 8439629be70863521bead138c295351f3dec926ab1Andrey Somov 8449629be70863521bead138c295351f3dec926ab1Andrey Somov private String prepareTagPrefix(String prefix) { 845d830de2dc8edea813a00c18193802d2bab3fded0Andrey Somov if (prefix.length() == 0) { 8469629be70863521bead138c295351f3dec926ab1Andrey Somov throw new EmitterException("tag prefix must not be empty"); 8479629be70863521bead138c295351f3dec926ab1Andrey Somov } 848c5335b097ea783bac0429e0393e01c5450e479a6Andrey Somov StringBuilder chunks = new StringBuilder(); 8499629be70863521bead138c295351f3dec926ab1Andrey Somov int start = 0; 8509629be70863521bead138c295351f3dec926ab1Andrey Somov int end = 0; 8519629be70863521bead138c295351f3dec926ab1Andrey Somov if (prefix.charAt(0) == '!') { 8529629be70863521bead138c295351f3dec926ab1Andrey Somov end = 1; 8539629be70863521bead138c295351f3dec926ab1Andrey Somov } 8549629be70863521bead138c295351f3dec926ab1Andrey Somov while (end < prefix.length()) { 8559629be70863521bead138c295351f3dec926ab1Andrey Somov end++; 8569629be70863521bead138c295351f3dec926ab1Andrey Somov } 8579629be70863521bead138c295351f3dec926ab1Andrey Somov if (start < end) { 8589629be70863521bead138c295351f3dec926ab1Andrey Somov chunks.append(prefix.substring(start, end)); 8599629be70863521bead138c295351f3dec926ab1Andrey Somov } 8609629be70863521bead138c295351f3dec926ab1Andrey Somov return chunks.toString(); 8619629be70863521bead138c295351f3dec926ab1Andrey Somov } 8629629be70863521bead138c295351f3dec926ab1Andrey Somov 8639629be70863521bead138c295351f3dec926ab1Andrey Somov private String prepareTag(String tag) { 864d830de2dc8edea813a00c18193802d2bab3fded0Andrey Somov if (tag.length() == 0) { 8659629be70863521bead138c295351f3dec926ab1Andrey Somov throw new EmitterException("tag must not be empty"); 8669629be70863521bead138c295351f3dec926ab1Andrey Somov } 867a5424f52a32314d70897f06a0aec907cf9231963Andrey Somov if ("!".equals(tag)) { 8689629be70863521bead138c295351f3dec926ab1Andrey Somov return tag; 8699629be70863521bead138c295351f3dec926ab1Andrey Somov } 8709629be70863521bead138c295351f3dec926ab1Andrey Somov String handle = null; 8719629be70863521bead138c295351f3dec926ab1Andrey Somov String suffix = tag; 87234f59d77fd0a29b085d4c642eb1db6b8925fc3c3Andrey Somov // shall the tag prefixes be sorted as in PyYAML? 8739629be70863521bead138c295351f3dec926ab1Andrey Somov for (String prefix : tagPrefixes.keySet()) { 874a5424f52a32314d70897f06a0aec907cf9231963Andrey Somov if (tag.startsWith(prefix) && ("!".equals(prefix) || prefix.length() < tag.length())) { 875370faf2dd7606d5fe2f887012be73d40fa531559maslovalex handle = prefix; 8769629be70863521bead138c295351f3dec926ab1Andrey Somov } 8779629be70863521bead138c295351f3dec926ab1Andrey Somov } 878370faf2dd7606d5fe2f887012be73d40fa531559maslovalex if (handle != null) { 879370faf2dd7606d5fe2f887012be73d40fa531559maslovalex suffix = tag.substring(handle.length()); 880370faf2dd7606d5fe2f887012be73d40fa531559maslovalex handle = tagPrefixes.get(handle); 8819629be70863521bead138c295351f3dec926ab1Andrey Somov } 882370faf2dd7606d5fe2f887012be73d40fa531559maslovalex 883370faf2dd7606d5fe2f887012be73d40fa531559maslovalex int end = suffix.length(); 884370faf2dd7606d5fe2f887012be73d40fa531559maslovalex String suffixText = end > 0 ? suffix.substring(0, end) : ""; 885370faf2dd7606d5fe2f887012be73d40fa531559maslovalex 8869629be70863521bead138c295351f3dec926ab1Andrey Somov if (handle != null) { 8879629be70863521bead138c295351f3dec926ab1Andrey Somov return handle + suffixText; 8889629be70863521bead138c295351f3dec926ab1Andrey Somov } 889370faf2dd7606d5fe2f887012be73d40fa531559maslovalex return "!<" + suffixText + ">"; 8909629be70863521bead138c295351f3dec926ab1Andrey Somov } 8919629be70863521bead138c295351f3dec926ab1Andrey Somov 8929629be70863521bead138c295351f3dec926ab1Andrey Somov private final static Pattern ANCHOR_FORMAT = Pattern.compile("^[-_\\w]*$"); 8939629be70863521bead138c295351f3dec926ab1Andrey Somov 8949629be70863521bead138c295351f3dec926ab1Andrey Somov static String prepareAnchor(String anchor) { 895d830de2dc8edea813a00c18193802d2bab3fded0Andrey Somov if (anchor.length() == 0) { 8969629be70863521bead138c295351f3dec926ab1Andrey Somov throw new EmitterException("anchor must not be empty"); 8979629be70863521bead138c295351f3dec926ab1Andrey Somov } 8989629be70863521bead138c295351f3dec926ab1Andrey Somov if (!ANCHOR_FORMAT.matcher(anchor).matches()) { 8999629be70863521bead138c295351f3dec926ab1Andrey Somov throw new EmitterException("invalid character in the anchor: " + anchor); 9009629be70863521bead138c295351f3dec926ab1Andrey Somov } 9019629be70863521bead138c295351f3dec926ab1Andrey Somov return anchor; 9029629be70863521bead138c295351f3dec926ab1Andrey Somov } 9039629be70863521bead138c295351f3dec926ab1Andrey Somov 9049629be70863521bead138c295351f3dec926ab1Andrey Somov private ScalarAnalysis analyzeScalar(String scalar) { 9059629be70863521bead138c295351f3dec926ab1Andrey Somov // Empty scalar is a special case. 906d830de2dc8edea813a00c18193802d2bab3fded0Andrey Somov if (scalar.length() == 0) { 90787b055d1b6548ca3c6a605634b05b86134655a58Andrey Somov return new ScalarAnalysis(scalar, true, false, false, true, true, false); 9089629be70863521bead138c295351f3dec926ab1Andrey Somov } 9099629be70863521bead138c295351f3dec926ab1Andrey Somov // Indicators and special characters. 9109629be70863521bead138c295351f3dec926ab1Andrey Somov boolean blockIndicators = false; 9119629be70863521bead138c295351f3dec926ab1Andrey Somov boolean flowIndicators = false; 9129629be70863521bead138c295351f3dec926ab1Andrey Somov boolean lineBreaks = false; 9139629be70863521bead138c295351f3dec926ab1Andrey Somov boolean specialCharacters = false; 9149629be70863521bead138c295351f3dec926ab1Andrey Somov 9159629be70863521bead138c295351f3dec926ab1Andrey Somov // Important whitespace combinations. 9169629be70863521bead138c295351f3dec926ab1Andrey Somov boolean leadingSpace = false; 9179629be70863521bead138c295351f3dec926ab1Andrey Somov boolean leadingBreak = false; 9189629be70863521bead138c295351f3dec926ab1Andrey Somov boolean trailingSpace = false; 9199629be70863521bead138c295351f3dec926ab1Andrey Somov boolean trailingBreak = false; 9209629be70863521bead138c295351f3dec926ab1Andrey Somov boolean breakSpace = false; 9219629be70863521bead138c295351f3dec926ab1Andrey Somov boolean spaceBreak = false; 9229629be70863521bead138c295351f3dec926ab1Andrey Somov 9239629be70863521bead138c295351f3dec926ab1Andrey Somov // Check document indicators. 9249629be70863521bead138c295351f3dec926ab1Andrey Somov if (scalar.startsWith("---") || scalar.startsWith("...")) { 9259629be70863521bead138c295351f3dec926ab1Andrey Somov blockIndicators = true; 9269629be70863521bead138c295351f3dec926ab1Andrey Somov flowIndicators = true; 9279629be70863521bead138c295351f3dec926ab1Andrey Somov } 9289629be70863521bead138c295351f3dec926ab1Andrey Somov // First character or preceded by a whitespace. 9299629be70863521bead138c295351f3dec926ab1Andrey Somov boolean preceededByWhitespace = true; 93025ac3b280b35ddb9167e0528626e2ec14488f173Andrey Somov boolean followedByWhitespace = scalar.length() == 1 || Constant.NULL_BL_T_LINEBR.has(scalar.charAt(1)); 9319629be70863521bead138c295351f3dec926ab1Andrey Somov // The previous character is a space. 9329629be70863521bead138c295351f3dec926ab1Andrey Somov boolean previousSpace = false; 9339629be70863521bead138c295351f3dec926ab1Andrey Somov 9349629be70863521bead138c295351f3dec926ab1Andrey Somov // The previous character is a break. 9359629be70863521bead138c295351f3dec926ab1Andrey Somov boolean previousBreak = false; 9369629be70863521bead138c295351f3dec926ab1Andrey Somov 9379629be70863521bead138c295351f3dec926ab1Andrey Somov int index = 0; 9389629be70863521bead138c295351f3dec926ab1Andrey Somov 9399629be70863521bead138c295351f3dec926ab1Andrey Somov while (index < scalar.length()) { 9409629be70863521bead138c295351f3dec926ab1Andrey Somov char ch = scalar.charAt(index); 9419629be70863521bead138c295351f3dec926ab1Andrey Somov // Check for indicators. 9429629be70863521bead138c295351f3dec926ab1Andrey Somov if (index == 0) { 9439629be70863521bead138c295351f3dec926ab1Andrey Somov // Leading indicators are special characters. 9449629be70863521bead138c295351f3dec926ab1Andrey Somov if ("#,[]{}&*!|>\'\"%@`".indexOf(ch) != -1) { 9459629be70863521bead138c295351f3dec926ab1Andrey Somov flowIndicators = true; 9469629be70863521bead138c295351f3dec926ab1Andrey Somov blockIndicators = true; 9479629be70863521bead138c295351f3dec926ab1Andrey Somov } 9489629be70863521bead138c295351f3dec926ab1Andrey Somov if (ch == '?' || ch == ':') { 9499629be70863521bead138c295351f3dec926ab1Andrey Somov flowIndicators = true; 9509629be70863521bead138c295351f3dec926ab1Andrey Somov if (followedByWhitespace) { 9519629be70863521bead138c295351f3dec926ab1Andrey Somov blockIndicators = true; 9529629be70863521bead138c295351f3dec926ab1Andrey Somov } 9539629be70863521bead138c295351f3dec926ab1Andrey Somov } 9549629be70863521bead138c295351f3dec926ab1Andrey Somov if (ch == '-' && followedByWhitespace) { 9559629be70863521bead138c295351f3dec926ab1Andrey Somov flowIndicators = true; 9569629be70863521bead138c295351f3dec926ab1Andrey Somov blockIndicators = true; 9579629be70863521bead138c295351f3dec926ab1Andrey Somov } 9589629be70863521bead138c295351f3dec926ab1Andrey Somov } else { 9599629be70863521bead138c295351f3dec926ab1Andrey Somov // Some indicators cannot appear within a scalar as well. 9609629be70863521bead138c295351f3dec926ab1Andrey Somov if (",?[]{}".indexOf(ch) != -1) { 9619629be70863521bead138c295351f3dec926ab1Andrey Somov flowIndicators = true; 9629629be70863521bead138c295351f3dec926ab1Andrey Somov } 9639629be70863521bead138c295351f3dec926ab1Andrey Somov if (ch == ':') { 9649629be70863521bead138c295351f3dec926ab1Andrey Somov flowIndicators = true; 9659629be70863521bead138c295351f3dec926ab1Andrey Somov if (followedByWhitespace) { 9669629be70863521bead138c295351f3dec926ab1Andrey Somov blockIndicators = true; 9679629be70863521bead138c295351f3dec926ab1Andrey Somov } 9689629be70863521bead138c295351f3dec926ab1Andrey Somov } 9699629be70863521bead138c295351f3dec926ab1Andrey Somov if (ch == '#' && preceededByWhitespace) { 9709629be70863521bead138c295351f3dec926ab1Andrey Somov flowIndicators = true; 9719629be70863521bead138c295351f3dec926ab1Andrey Somov blockIndicators = true; 9729629be70863521bead138c295351f3dec926ab1Andrey Somov } 9739629be70863521bead138c295351f3dec926ab1Andrey Somov } 9749629be70863521bead138c295351f3dec926ab1Andrey Somov // Check for line breaks, special, and unicode characters. 975a6964fe528dbb6897698e75e3c0c6056f22b3e49Andrey Somov boolean isLineBreak = Constant.LINEBR.has(ch); 976a6964fe528dbb6897698e75e3c0c6056f22b3e49Andrey Somov if (isLineBreak) { 9779629be70863521bead138c295351f3dec926ab1Andrey Somov lineBreaks = true; 9789629be70863521bead138c295351f3dec926ab1Andrey Somov } 9799629be70863521bead138c295351f3dec926ab1Andrey Somov if (!(ch == '\n' || ('\u0020' <= ch && ch <= '\u007E'))) { 9809629be70863521bead138c295351f3dec926ab1Andrey Somov if ((ch == '\u0085' || ('\u00A0' <= ch && ch <= '\uD7FF') || ('\uE000' <= ch && ch <= '\uFFFD')) 9819629be70863521bead138c295351f3dec926ab1Andrey Somov && (ch != '\uFEFF')) { 9829629be70863521bead138c295351f3dec926ab1Andrey Somov // unicode is used 9839629be70863521bead138c295351f3dec926ab1Andrey Somov if (!this.allowUnicode) { 9849629be70863521bead138c295351f3dec926ab1Andrey Somov specialCharacters = true; 9859629be70863521bead138c295351f3dec926ab1Andrey Somov } 9869629be70863521bead138c295351f3dec926ab1Andrey Somov } else { 9879629be70863521bead138c295351f3dec926ab1Andrey Somov specialCharacters = true; 9889629be70863521bead138c295351f3dec926ab1Andrey Somov } 9899629be70863521bead138c295351f3dec926ab1Andrey Somov } 9909629be70863521bead138c295351f3dec926ab1Andrey Somov // Detect important whitespace combinations. 9919629be70863521bead138c295351f3dec926ab1Andrey Somov if (ch == ' ') { 9929629be70863521bead138c295351f3dec926ab1Andrey Somov if (index == 0) { 9939629be70863521bead138c295351f3dec926ab1Andrey Somov leadingSpace = true; 9949629be70863521bead138c295351f3dec926ab1Andrey Somov } 9959629be70863521bead138c295351f3dec926ab1Andrey Somov if (index == scalar.length() - 1) { 9969629be70863521bead138c295351f3dec926ab1Andrey Somov trailingSpace = true; 9979629be70863521bead138c295351f3dec926ab1Andrey Somov } 9989629be70863521bead138c295351f3dec926ab1Andrey Somov if (previousBreak) { 9999629be70863521bead138c295351f3dec926ab1Andrey Somov breakSpace = true; 10009629be70863521bead138c295351f3dec926ab1Andrey Somov } 10019629be70863521bead138c295351f3dec926ab1Andrey Somov previousSpace = true; 10029629be70863521bead138c295351f3dec926ab1Andrey Somov previousBreak = false; 1003a6964fe528dbb6897698e75e3c0c6056f22b3e49Andrey Somov } else if (isLineBreak) { 10049629be70863521bead138c295351f3dec926ab1Andrey Somov if (index == 0) { 10059629be70863521bead138c295351f3dec926ab1Andrey Somov leadingBreak = true; 10069629be70863521bead138c295351f3dec926ab1Andrey Somov } 10079629be70863521bead138c295351f3dec926ab1Andrey Somov if (index == scalar.length() - 1) { 10089629be70863521bead138c295351f3dec926ab1Andrey Somov trailingBreak = true; 10099629be70863521bead138c295351f3dec926ab1Andrey Somov } 10109629be70863521bead138c295351f3dec926ab1Andrey Somov if (previousSpace) { 10119629be70863521bead138c295351f3dec926ab1Andrey Somov spaceBreak = true; 10129629be70863521bead138c295351f3dec926ab1Andrey Somov } 10139629be70863521bead138c295351f3dec926ab1Andrey Somov previousSpace = false; 10149629be70863521bead138c295351f3dec926ab1Andrey Somov previousBreak = true; 10159629be70863521bead138c295351f3dec926ab1Andrey Somov } else { 10169629be70863521bead138c295351f3dec926ab1Andrey Somov previousSpace = false; 10179629be70863521bead138c295351f3dec926ab1Andrey Somov previousBreak = false; 10189629be70863521bead138c295351f3dec926ab1Andrey Somov } 10199629be70863521bead138c295351f3dec926ab1Andrey Somov 10209629be70863521bead138c295351f3dec926ab1Andrey Somov // Prepare for the next character. 10219629be70863521bead138c295351f3dec926ab1Andrey Somov index++; 1022a6964fe528dbb6897698e75e3c0c6056f22b3e49Andrey Somov preceededByWhitespace = Constant.NULL_BL_T.has(ch) || isLineBreak; 102325ac3b280b35ddb9167e0528626e2ec14488f173Andrey Somov followedByWhitespace = index + 1 >= scalar.length() 102425ac3b280b35ddb9167e0528626e2ec14488f173Andrey Somov || (Constant.NULL_BL_T.has(scalar.charAt(index + 1))) || isLineBreak; 10259629be70863521bead138c295351f3dec926ab1Andrey Somov } 10269629be70863521bead138c295351f3dec926ab1Andrey Somov // Let's decide what styles are allowed. 10279629be70863521bead138c295351f3dec926ab1Andrey Somov boolean allowFlowPlain = true; 10289629be70863521bead138c295351f3dec926ab1Andrey Somov boolean allowBlockPlain = true; 10299629be70863521bead138c295351f3dec926ab1Andrey Somov boolean allowSingleQuoted = true; 10309629be70863521bead138c295351f3dec926ab1Andrey Somov boolean allowBlock = true; 10319629be70863521bead138c295351f3dec926ab1Andrey Somov // Leading and trailing whitespaces are bad for plain scalars. 10329629be70863521bead138c295351f3dec926ab1Andrey Somov if (leadingSpace || leadingBreak || trailingSpace || trailingBreak) { 10339629be70863521bead138c295351f3dec926ab1Andrey Somov allowFlowPlain = allowBlockPlain = false; 10349629be70863521bead138c295351f3dec926ab1Andrey Somov } 10359629be70863521bead138c295351f3dec926ab1Andrey Somov // We do not permit trailing spaces for block scalars. 10369629be70863521bead138c295351f3dec926ab1Andrey Somov if (trailingSpace) { 10379629be70863521bead138c295351f3dec926ab1Andrey Somov allowBlock = false; 10389629be70863521bead138c295351f3dec926ab1Andrey Somov } 10399629be70863521bead138c295351f3dec926ab1Andrey Somov // Spaces at the beginning of a new line are only acceptable for block 10409629be70863521bead138c295351f3dec926ab1Andrey Somov // scalars. 10419629be70863521bead138c295351f3dec926ab1Andrey Somov if (breakSpace) { 10429629be70863521bead138c295351f3dec926ab1Andrey Somov allowFlowPlain = allowBlockPlain = allowSingleQuoted = false; 10439629be70863521bead138c295351f3dec926ab1Andrey Somov } 10449629be70863521bead138c295351f3dec926ab1Andrey Somov // Spaces followed by breaks, as well as special character are only 10459629be70863521bead138c295351f3dec926ab1Andrey Somov // allowed for double quoted scalars. 10469629be70863521bead138c295351f3dec926ab1Andrey Somov if (spaceBreak || specialCharacters) { 10479629be70863521bead138c295351f3dec926ab1Andrey Somov allowFlowPlain = allowBlockPlain = allowSingleQuoted = allowBlock = false; 10489629be70863521bead138c295351f3dec926ab1Andrey Somov } 10499629be70863521bead138c295351f3dec926ab1Andrey Somov // Although the plain scalar writer supports breaks, we never emit 1050a3e7b19e567f571f6be130b0b8779d7eb40c88e0Andrey Somov // multiline plain scalars in the flow context. 10519629be70863521bead138c295351f3dec926ab1Andrey Somov if (lineBreaks) { 1052a3e7b19e567f571f6be130b0b8779d7eb40c88e0Andrey Somov allowFlowPlain = false; 10539629be70863521bead138c295351f3dec926ab1Andrey Somov } 10549629be70863521bead138c295351f3dec926ab1Andrey Somov // Flow indicators are forbidden for flow plain scalars. 10559629be70863521bead138c295351f3dec926ab1Andrey Somov if (flowIndicators) { 10569629be70863521bead138c295351f3dec926ab1Andrey Somov allowFlowPlain = false; 10579629be70863521bead138c295351f3dec926ab1Andrey Somov } 10589629be70863521bead138c295351f3dec926ab1Andrey Somov // Block indicators are forbidden for block plain scalars. 10599629be70863521bead138c295351f3dec926ab1Andrey Somov if (blockIndicators) { 10609629be70863521bead138c295351f3dec926ab1Andrey Somov allowBlockPlain = false; 10619629be70863521bead138c295351f3dec926ab1Andrey Somov } 10629629be70863521bead138c295351f3dec926ab1Andrey Somov 10639629be70863521bead138c295351f3dec926ab1Andrey Somov return new ScalarAnalysis(scalar, false, lineBreaks, allowFlowPlain, allowBlockPlain, 106487b055d1b6548ca3c6a605634b05b86134655a58Andrey Somov allowSingleQuoted, allowBlock); 10659629be70863521bead138c295351f3dec926ab1Andrey Somov } 10669629be70863521bead138c295351f3dec926ab1Andrey Somov 10679629be70863521bead138c295351f3dec926ab1Andrey Somov // Writers. 10689629be70863521bead138c295351f3dec926ab1Andrey Somov 10699629be70863521bead138c295351f3dec926ab1Andrey Somov void flushStream() throws IOException { 10709629be70863521bead138c295351f3dec926ab1Andrey Somov stream.flush(); 10719629be70863521bead138c295351f3dec926ab1Andrey Somov } 10729629be70863521bead138c295351f3dec926ab1Andrey Somov 10739629be70863521bead138c295351f3dec926ab1Andrey Somov void writeStreamStart() { 10749629be70863521bead138c295351f3dec926ab1Andrey Somov // BOM is written by Writer. 10759629be70863521bead138c295351f3dec926ab1Andrey Somov } 10769629be70863521bead138c295351f3dec926ab1Andrey Somov 10779629be70863521bead138c295351f3dec926ab1Andrey Somov void writeStreamEnd() throws IOException { 10789629be70863521bead138c295351f3dec926ab1Andrey Somov flushStream(); 10799629be70863521bead138c295351f3dec926ab1Andrey Somov } 10809629be70863521bead138c295351f3dec926ab1Andrey Somov 10819629be70863521bead138c295351f3dec926ab1Andrey Somov void writeIndicator(String indicator, boolean needWhitespace, boolean whitespace, 10829629be70863521bead138c295351f3dec926ab1Andrey Somov boolean indentation) throws IOException { 1083370faf2dd7606d5fe2f887012be73d40fa531559maslovalex if (!this.whitespace && needWhitespace) { 1084370faf2dd7606d5fe2f887012be73d40fa531559maslovalex this.column++; 1085370faf2dd7606d5fe2f887012be73d40fa531559maslovalex stream.write(SPACE); 10869629be70863521bead138c295351f3dec926ab1Andrey Somov } 10879629be70863521bead138c295351f3dec926ab1Andrey Somov this.whitespace = whitespace; 10889629be70863521bead138c295351f3dec926ab1Andrey Somov this.indention = this.indention && indentation; 1089370faf2dd7606d5fe2f887012be73d40fa531559maslovalex this.column += indicator.length(); 10909629be70863521bead138c295351f3dec926ab1Andrey Somov openEnded = false; 1091370faf2dd7606d5fe2f887012be73d40fa531559maslovalex stream.write(indicator); 10929629be70863521bead138c295351f3dec926ab1Andrey Somov } 10939629be70863521bead138c295351f3dec926ab1Andrey Somov 10949629be70863521bead138c295351f3dec926ab1Andrey Somov void writeIndent() throws IOException { 10959629be70863521bead138c295351f3dec926ab1Andrey Somov int indent; 10969629be70863521bead138c295351f3dec926ab1Andrey Somov if (this.indent != null) { 10979629be70863521bead138c295351f3dec926ab1Andrey Somov indent = this.indent; 10989629be70863521bead138c295351f3dec926ab1Andrey Somov } else { 10999629be70863521bead138c295351f3dec926ab1Andrey Somov indent = 0; 11009629be70863521bead138c295351f3dec926ab1Andrey Somov } 11019629be70863521bead138c295351f3dec926ab1Andrey Somov 11029629be70863521bead138c295351f3dec926ab1Andrey Somov if (!this.indention || this.column > indent || (this.column == indent && !this.whitespace)) { 11039629be70863521bead138c295351f3dec926ab1Andrey Somov writeLineBreak(null); 11049629be70863521bead138c295351f3dec926ab1Andrey Somov } 11059629be70863521bead138c295351f3dec926ab1Andrey Somov 1106d1dd873170bcc2a9df0a512ae5fa5f073a8b64cftareq sha writeWhitespace(indent - this.column); 1107d1dd873170bcc2a9df0a512ae5fa5f073a8b64cftareq sha } 1108d1dd873170bcc2a9df0a512ae5fa5f073a8b64cftareq sha 1109d1dd873170bcc2a9df0a512ae5fa5f073a8b64cftareq sha private void writeWhitespace(int length) throws IOException { 1110d1dd873170bcc2a9df0a512ae5fa5f073a8b64cftareq sha if (length <= 0) { 1111d1dd873170bcc2a9df0a512ae5fa5f073a8b64cftareq sha return; 1112d1dd873170bcc2a9df0a512ae5fa5f073a8b64cftareq sha } 1113d1dd873170bcc2a9df0a512ae5fa5f073a8b64cftareq sha this.whitespace = true; 1114d1dd873170bcc2a9df0a512ae5fa5f073a8b64cftareq sha char[] data = new char[length]; 1115d1dd873170bcc2a9df0a512ae5fa5f073a8b64cftareq sha for (int i = 0; i < data.length; i++) { 1116d1dd873170bcc2a9df0a512ae5fa5f073a8b64cftareq sha data[i] = ' '; 11179629be70863521bead138c295351f3dec926ab1Andrey Somov } 1118d1dd873170bcc2a9df0a512ae5fa5f073a8b64cftareq sha this.column += length; 1119d1dd873170bcc2a9df0a512ae5fa5f073a8b64cftareq sha stream.write(data); 11209629be70863521bead138c295351f3dec926ab1Andrey Somov } 11219629be70863521bead138c295351f3dec926ab1Andrey Somov 11229629be70863521bead138c295351f3dec926ab1Andrey Somov private void writeLineBreak(String data) throws IOException { 11239629be70863521bead138c295351f3dec926ab1Andrey Somov this.whitespace = true; 11249629be70863521bead138c295351f3dec926ab1Andrey Somov this.indention = true; 11259629be70863521bead138c295351f3dec926ab1Andrey Somov this.column = 0; 1126370faf2dd7606d5fe2f887012be73d40fa531559maslovalex if (data == null) { 1127370faf2dd7606d5fe2f887012be73d40fa531559maslovalex stream.write(this.bestLineBreak); 1128370faf2dd7606d5fe2f887012be73d40fa531559maslovalex } else { 1129370faf2dd7606d5fe2f887012be73d40fa531559maslovalex stream.write(data); 1130370faf2dd7606d5fe2f887012be73d40fa531559maslovalex } 11319629be70863521bead138c295351f3dec926ab1Andrey Somov } 11329629be70863521bead138c295351f3dec926ab1Andrey Somov 11339629be70863521bead138c295351f3dec926ab1Andrey Somov void writeVersionDirective(String versionText) throws IOException { 1134370faf2dd7606d5fe2f887012be73d40fa531559maslovalex stream.write("%YAML "); 1135370faf2dd7606d5fe2f887012be73d40fa531559maslovalex stream.write(versionText); 11369629be70863521bead138c295351f3dec926ab1Andrey Somov writeLineBreak(null); 11379629be70863521bead138c295351f3dec926ab1Andrey Somov } 11389629be70863521bead138c295351f3dec926ab1Andrey Somov 11399629be70863521bead138c295351f3dec926ab1Andrey Somov void writeTagDirective(String handleText, String prefixText) throws IOException { 114065df777c9b28ba6d5c4d3ac5a437280bf112f622Andrey Somov // XXX: not sure 4 invocations better then StringBuilders created by str 114165df777c9b28ba6d5c4d3ac5a437280bf112f622Andrey Somov // + str 1142370faf2dd7606d5fe2f887012be73d40fa531559maslovalex stream.write("%TAG "); 1143370faf2dd7606d5fe2f887012be73d40fa531559maslovalex stream.write(handleText); 1144370faf2dd7606d5fe2f887012be73d40fa531559maslovalex stream.write(SPACE); 1145370faf2dd7606d5fe2f887012be73d40fa531559maslovalex stream.write(prefixText); 11469629be70863521bead138c295351f3dec926ab1Andrey Somov writeLineBreak(null); 11479629be70863521bead138c295351f3dec926ab1Andrey Somov } 11489629be70863521bead138c295351f3dec926ab1Andrey Somov 11499629be70863521bead138c295351f3dec926ab1Andrey Somov // Scalar streams. 11509629be70863521bead138c295351f3dec926ab1Andrey Somov private void writeSingleQuoted(String text, boolean split) throws IOException { 11519629be70863521bead138c295351f3dec926ab1Andrey Somov writeIndicator("'", true, false, false); 11529629be70863521bead138c295351f3dec926ab1Andrey Somov boolean spaces = false; 11539629be70863521bead138c295351f3dec926ab1Andrey Somov boolean breaks = false; 11549629be70863521bead138c295351f3dec926ab1Andrey Somov int start = 0, end = 0; 11559629be70863521bead138c295351f3dec926ab1Andrey Somov char ch; 11569629be70863521bead138c295351f3dec926ab1Andrey Somov while (end <= text.length()) { 11579629be70863521bead138c295351f3dec926ab1Andrey Somov ch = 0; 11589629be70863521bead138c295351f3dec926ab1Andrey Somov if (end < text.length()) { 11599629be70863521bead138c295351f3dec926ab1Andrey Somov ch = text.charAt(end); 11609629be70863521bead138c295351f3dec926ab1Andrey Somov } 11619629be70863521bead138c295351f3dec926ab1Andrey Somov if (spaces) { 11629629be70863521bead138c295351f3dec926ab1Andrey Somov if (ch == 0 || ch != ' ') { 11639629be70863521bead138c295351f3dec926ab1Andrey Somov if (start + 1 == end && this.column > this.bestWidth && split && start != 0 11649629be70863521bead138c295351f3dec926ab1Andrey Somov && end != text.length()) { 11659629be70863521bead138c295351f3dec926ab1Andrey Somov writeIndent(); 11669629be70863521bead138c295351f3dec926ab1Andrey Somov } else { 1167370faf2dd7606d5fe2f887012be73d40fa531559maslovalex int len = end - start; 1168370faf2dd7606d5fe2f887012be73d40fa531559maslovalex this.column += len; 1169370faf2dd7606d5fe2f887012be73d40fa531559maslovalex stream.write(text, start, len); 11709629be70863521bead138c295351f3dec926ab1Andrey Somov } 11719629be70863521bead138c295351f3dec926ab1Andrey Somov start = end; 11729629be70863521bead138c295351f3dec926ab1Andrey Somov } 11739629be70863521bead138c295351f3dec926ab1Andrey Somov } else if (breaks) { 1174b693d5a6b13314c20bee0e912ed209af6e0499efAndrey Somov if (ch == 0 || Constant.LINEBR.hasNo(ch)) { 11759629be70863521bead138c295351f3dec926ab1Andrey Somov if (text.charAt(start) == '\n') { 11769629be70863521bead138c295351f3dec926ab1Andrey Somov writeLineBreak(null); 11779629be70863521bead138c295351f3dec926ab1Andrey Somov } 11789629be70863521bead138c295351f3dec926ab1Andrey Somov String data = text.substring(start, end); 11799629be70863521bead138c295351f3dec926ab1Andrey Somov for (char br : data.toCharArray()) { 11809629be70863521bead138c295351f3dec926ab1Andrey Somov if (br == '\n') { 11819629be70863521bead138c295351f3dec926ab1Andrey Somov writeLineBreak(null); 11829629be70863521bead138c295351f3dec926ab1Andrey Somov } else { 11839629be70863521bead138c295351f3dec926ab1Andrey Somov writeLineBreak(String.valueOf(br)); 11849629be70863521bead138c295351f3dec926ab1Andrey Somov } 11859629be70863521bead138c295351f3dec926ab1Andrey Somov } 11869629be70863521bead138c295351f3dec926ab1Andrey Somov writeIndent(); 11879629be70863521bead138c295351f3dec926ab1Andrey Somov start = end; 11889629be70863521bead138c295351f3dec926ab1Andrey Somov } 11899629be70863521bead138c295351f3dec926ab1Andrey Somov } else { 11908e50e7a86555d3ef47829d853d254eace03e8157Andrey Somov if (Constant.LINEBR.has(ch, "\0 \'")) { 11919629be70863521bead138c295351f3dec926ab1Andrey Somov if (start < end) { 1192370faf2dd7606d5fe2f887012be73d40fa531559maslovalex int len = end - start; 1193370faf2dd7606d5fe2f887012be73d40fa531559maslovalex this.column += len; 1194370faf2dd7606d5fe2f887012be73d40fa531559maslovalex stream.write(text, start, len); 11959629be70863521bead138c295351f3dec926ab1Andrey Somov start = end; 11969629be70863521bead138c295351f3dec926ab1Andrey Somov } 11979629be70863521bead138c295351f3dec926ab1Andrey Somov } 11989629be70863521bead138c295351f3dec926ab1Andrey Somov } 11999629be70863521bead138c295351f3dec926ab1Andrey Somov if (ch == '\'') { 12009629be70863521bead138c295351f3dec926ab1Andrey Somov this.column += 2; 1201370faf2dd7606d5fe2f887012be73d40fa531559maslovalex stream.write("''"); 12029629be70863521bead138c295351f3dec926ab1Andrey Somov start = end + 1; 12039629be70863521bead138c295351f3dec926ab1Andrey Somov } 12049629be70863521bead138c295351f3dec926ab1Andrey Somov if (ch != 0) { 12059629be70863521bead138c295351f3dec926ab1Andrey Somov spaces = ch == ' '; 120665619eff85ddfd768e973825b34b2ed8bbde537dAndrey Somov breaks = Constant.LINEBR.has(ch); 12079629be70863521bead138c295351f3dec926ab1Andrey Somov } 12089629be70863521bead138c295351f3dec926ab1Andrey Somov end++; 12099629be70863521bead138c295351f3dec926ab1Andrey Somov } 12109629be70863521bead138c295351f3dec926ab1Andrey Somov writeIndicator("'", false, false, false); 12119629be70863521bead138c295351f3dec926ab1Andrey Somov } 12129629be70863521bead138c295351f3dec926ab1Andrey Somov 12139629be70863521bead138c295351f3dec926ab1Andrey Somov private void writeDoubleQuoted(String text, boolean split) throws IOException { 12149629be70863521bead138c295351f3dec926ab1Andrey Somov writeIndicator("\"", true, false, false); 12159629be70863521bead138c295351f3dec926ab1Andrey Somov int start = 0; 12169629be70863521bead138c295351f3dec926ab1Andrey Somov int end = 0; 12179629be70863521bead138c295351f3dec926ab1Andrey Somov while (end <= text.length()) { 12189629be70863521bead138c295351f3dec926ab1Andrey Somov Character ch = null; 12199629be70863521bead138c295351f3dec926ab1Andrey Somov if (end < text.length()) { 12209629be70863521bead138c295351f3dec926ab1Andrey Somov ch = text.charAt(end); 12219629be70863521bead138c295351f3dec926ab1Andrey Somov } 12229629be70863521bead138c295351f3dec926ab1Andrey Somov if (ch == null || "\"\\\u0085\u2028\u2029\uFEFF".indexOf(ch) != -1 12239629be70863521bead138c295351f3dec926ab1Andrey Somov || !('\u0020' <= ch && ch <= '\u007E')) { 12249629be70863521bead138c295351f3dec926ab1Andrey Somov if (start < end) { 1225370faf2dd7606d5fe2f887012be73d40fa531559maslovalex int len = end - start; 1226370faf2dd7606d5fe2f887012be73d40fa531559maslovalex this.column += len; 1227370faf2dd7606d5fe2f887012be73d40fa531559maslovalex stream.write(text, start, len); 12289629be70863521bead138c295351f3dec926ab1Andrey Somov start = end; 12299629be70863521bead138c295351f3dec926ab1Andrey Somov } 12309629be70863521bead138c295351f3dec926ab1Andrey Somov if (ch != null) { 12319629be70863521bead138c295351f3dec926ab1Andrey Somov String data; 1232d4c7e6efc571fe29d05cc8d0f6d0e713e8c4a35fAndrey Somov if (ESCAPE_REPLACEMENTS.containsKey(ch)) { 1233d4c7e6efc571fe29d05cc8d0f6d0e713e8c4a35fAndrey Somov data = "\\" + ESCAPE_REPLACEMENTS.get(ch); 12347361ced8b2bc1e37c3064923b0ccc124af39b57aAndrey Somov } else if (!this.allowUnicode || !StreamReader.isPrintable(ch)) { 12357361ced8b2bc1e37c3064923b0ccc124af39b57aAndrey Somov // if !allowUnicode or the character is not printable, 12367361ced8b2bc1e37c3064923b0ccc124af39b57aAndrey Somov // we must encode it 123718cc7805e3e5877e7e8659de766f246e0fc9c414Andrey Somov if (ch <= '\u00FF') { 123818cc7805e3e5877e7e8659de766f246e0fc9c414Andrey Somov String s = "0" + Integer.toString(ch, 16); 123918cc7805e3e5877e7e8659de766f246e0fc9c414Andrey Somov data = "\\x" + s.substring(s.length() - 2); 12407361ced8b2bc1e37c3064923b0ccc124af39b57aAndrey Somov } else if (ch >= '\uD800' && ch <= '\uDBFF') { 12417361ced8b2bc1e37c3064923b0ccc124af39b57aAndrey Somov if (end + 1 < text.length()) { 12427361ced8b2bc1e37c3064923b0ccc124af39b57aAndrey Somov Character ch2 = text.charAt(++end); 12437361ced8b2bc1e37c3064923b0ccc124af39b57aAndrey Somov String s = "000" + Long.toHexString(Character.toCodePoint(ch, ch2)); 12447361ced8b2bc1e37c3064923b0ccc124af39b57aAndrey Somov data = "\\U" + s.substring(s.length() - 8); 12457361ced8b2bc1e37c3064923b0ccc124af39b57aAndrey Somov } else { 12467361ced8b2bc1e37c3064923b0ccc124af39b57aAndrey Somov String s = "000" + Integer.toString(ch, 16); 12477361ced8b2bc1e37c3064923b0ccc124af39b57aAndrey Somov data = "\\u" + s.substring(s.length() - 4); 12487361ced8b2bc1e37c3064923b0ccc124af39b57aAndrey Somov } 124918cc7805e3e5877e7e8659de766f246e0fc9c414Andrey Somov } else { 125018cc7805e3e5877e7e8659de766f246e0fc9c414Andrey Somov String s = "000" + Integer.toString(ch, 16); 125118cc7805e3e5877e7e8659de766f246e0fc9c414Andrey Somov data = "\\u" + s.substring(s.length() - 4); 125218cc7805e3e5877e7e8659de766f246e0fc9c414Andrey Somov } 12539629be70863521bead138c295351f3dec926ab1Andrey Somov } else { 125418cc7805e3e5877e7e8659de766f246e0fc9c414Andrey Somov data = String.valueOf(ch); 12559629be70863521bead138c295351f3dec926ab1Andrey Somov } 12569629be70863521bead138c295351f3dec926ab1Andrey Somov this.column += data.length(); 12579629be70863521bead138c295351f3dec926ab1Andrey Somov stream.write(data); 12589629be70863521bead138c295351f3dec926ab1Andrey Somov start = end + 1; 12599629be70863521bead138c295351f3dec926ab1Andrey Somov } 12609629be70863521bead138c295351f3dec926ab1Andrey Somov } 12619629be70863521bead138c295351f3dec926ab1Andrey Somov if ((0 < end && end < (text.length() - 1)) && (ch == ' ' || start >= end) 12629629be70863521bead138c295351f3dec926ab1Andrey Somov && (this.column + (end - start)) > this.bestWidth && split) { 12639629be70863521bead138c295351f3dec926ab1Andrey Somov String data; 12649629be70863521bead138c295351f3dec926ab1Andrey Somov if (start >= end) { 12659629be70863521bead138c295351f3dec926ab1Andrey Somov data = "\\"; 12669629be70863521bead138c295351f3dec926ab1Andrey Somov } else { 12679629be70863521bead138c295351f3dec926ab1Andrey Somov data = text.substring(start, end) + "\\"; 12689629be70863521bead138c295351f3dec926ab1Andrey Somov } 12699629be70863521bead138c295351f3dec926ab1Andrey Somov if (start < end) { 12709629be70863521bead138c295351f3dec926ab1Andrey Somov start = end; 12719629be70863521bead138c295351f3dec926ab1Andrey Somov } 12729629be70863521bead138c295351f3dec926ab1Andrey Somov this.column += data.length(); 12739629be70863521bead138c295351f3dec926ab1Andrey Somov stream.write(data); 12749629be70863521bead138c295351f3dec926ab1Andrey Somov writeIndent(); 12759629be70863521bead138c295351f3dec926ab1Andrey Somov this.whitespace = false; 12769629be70863521bead138c295351f3dec926ab1Andrey Somov this.indention = false; 12779629be70863521bead138c295351f3dec926ab1Andrey Somov if (text.charAt(start) == ' ') { 12789629be70863521bead138c295351f3dec926ab1Andrey Somov data = "\\"; 12799629be70863521bead138c295351f3dec926ab1Andrey Somov this.column += data.length(); 12809629be70863521bead138c295351f3dec926ab1Andrey Somov stream.write(data); 12819629be70863521bead138c295351f3dec926ab1Andrey Somov } 12829629be70863521bead138c295351f3dec926ab1Andrey Somov } 12839629be70863521bead138c295351f3dec926ab1Andrey Somov end += 1; 12849629be70863521bead138c295351f3dec926ab1Andrey Somov } 12859629be70863521bead138c295351f3dec926ab1Andrey Somov writeIndicator("\"", false, false, false); 12869629be70863521bead138c295351f3dec926ab1Andrey Somov } 12879629be70863521bead138c295351f3dec926ab1Andrey Somov 12889629be70863521bead138c295351f3dec926ab1Andrey Somov private String determineBlockHints(String text) { 1289c5335b097ea783bac0429e0393e01c5450e479a6Andrey Somov StringBuilder hints = new StringBuilder(); 1290d830de2dc8edea813a00c18193802d2bab3fded0Andrey Somov if (Constant.LINEBR.has(text.charAt(0), " ")) { 1291d830de2dc8edea813a00c18193802d2bab3fded0Andrey Somov hints.append(bestIndent); 1292d830de2dc8edea813a00c18193802d2bab3fded0Andrey Somov } 1293d830de2dc8edea813a00c18193802d2bab3fded0Andrey Somov char ch1 = text.charAt(text.length() - 1); 1294d830de2dc8edea813a00c18193802d2bab3fded0Andrey Somov if (Constant.LINEBR.hasNo(ch1)) { 1295d830de2dc8edea813a00c18193802d2bab3fded0Andrey Somov hints.append("-"); 1296d830de2dc8edea813a00c18193802d2bab3fded0Andrey Somov } else if (text.length() == 1 || Constant.LINEBR.has(text.charAt(text.length() - 2))) { 1297d830de2dc8edea813a00c18193802d2bab3fded0Andrey Somov hints.append("+"); 12989629be70863521bead138c295351f3dec926ab1Andrey Somov } 12999629be70863521bead138c295351f3dec926ab1Andrey Somov return hints.toString(); 13009629be70863521bead138c295351f3dec926ab1Andrey Somov } 13019629be70863521bead138c295351f3dec926ab1Andrey Somov 13027fbc6562f9ae67c2b9de8b8c5c74c62c42006cebVille Koskela void writeFolded(String text, boolean split) throws IOException { 13039629be70863521bead138c295351f3dec926ab1Andrey Somov String hints = determineBlockHints(text); 13049629be70863521bead138c295351f3dec926ab1Andrey Somov writeIndicator(">" + hints, true, false, false); 13059629be70863521bead138c295351f3dec926ab1Andrey Somov if (hints.length() > 0 && (hints.charAt(hints.length() - 1) == '+')) { 13069629be70863521bead138c295351f3dec926ab1Andrey Somov openEnded = true; 13079629be70863521bead138c295351f3dec926ab1Andrey Somov } 13089629be70863521bead138c295351f3dec926ab1Andrey Somov writeLineBreak(null); 13099629be70863521bead138c295351f3dec926ab1Andrey Somov boolean leadingSpace = true; 13109629be70863521bead138c295351f3dec926ab1Andrey Somov boolean spaces = false; 13119629be70863521bead138c295351f3dec926ab1Andrey Somov boolean breaks = true; 13129629be70863521bead138c295351f3dec926ab1Andrey Somov int start = 0, end = 0; 13139629be70863521bead138c295351f3dec926ab1Andrey Somov while (end <= text.length()) { 13149629be70863521bead138c295351f3dec926ab1Andrey Somov char ch = 0; 13159629be70863521bead138c295351f3dec926ab1Andrey Somov if (end < text.length()) { 13169629be70863521bead138c295351f3dec926ab1Andrey Somov ch = text.charAt(end); 13179629be70863521bead138c295351f3dec926ab1Andrey Somov } 13189629be70863521bead138c295351f3dec926ab1Andrey Somov if (breaks) { 1319b693d5a6b13314c20bee0e912ed209af6e0499efAndrey Somov if (ch == 0 || Constant.LINEBR.hasNo(ch)) { 13209629be70863521bead138c295351f3dec926ab1Andrey Somov if (!leadingSpace && ch != 0 && ch != ' ' && text.charAt(start) == '\n') { 13219629be70863521bead138c295351f3dec926ab1Andrey Somov writeLineBreak(null); 13229629be70863521bead138c295351f3dec926ab1Andrey Somov } 132325ac3b280b35ddb9167e0528626e2ec14488f173Andrey Somov leadingSpace = ch == ' '; 13249629be70863521bead138c295351f3dec926ab1Andrey Somov String data = text.substring(start, end); 13259629be70863521bead138c295351f3dec926ab1Andrey Somov for (char br : data.toCharArray()) { 13269629be70863521bead138c295351f3dec926ab1Andrey Somov if (br == '\n') { 13279629be70863521bead138c295351f3dec926ab1Andrey Somov writeLineBreak(null); 13289629be70863521bead138c295351f3dec926ab1Andrey Somov } else { 13299629be70863521bead138c295351f3dec926ab1Andrey Somov writeLineBreak(String.valueOf(br)); 13309629be70863521bead138c295351f3dec926ab1Andrey Somov } 13319629be70863521bead138c295351f3dec926ab1Andrey Somov } 13329629be70863521bead138c295351f3dec926ab1Andrey Somov if (ch != 0) { 13339629be70863521bead138c295351f3dec926ab1Andrey Somov writeIndent(); 13349629be70863521bead138c295351f3dec926ab1Andrey Somov } 13359629be70863521bead138c295351f3dec926ab1Andrey Somov start = end; 13369629be70863521bead138c295351f3dec926ab1Andrey Somov } 13379629be70863521bead138c295351f3dec926ab1Andrey Somov } else if (spaces) { 13389629be70863521bead138c295351f3dec926ab1Andrey Somov if (ch != ' ') { 13397fbc6562f9ae67c2b9de8b8c5c74c62c42006cebVille Koskela if (start + 1 == end && this.column > this.bestWidth && split) { 13409629be70863521bead138c295351f3dec926ab1Andrey Somov writeIndent(); 13419629be70863521bead138c295351f3dec926ab1Andrey Somov } else { 1342370faf2dd7606d5fe2f887012be73d40fa531559maslovalex int len = end - start; 1343370faf2dd7606d5fe2f887012be73d40fa531559maslovalex this.column += len; 1344370faf2dd7606d5fe2f887012be73d40fa531559maslovalex stream.write(text, start, len); 13459629be70863521bead138c295351f3dec926ab1Andrey Somov } 13469629be70863521bead138c295351f3dec926ab1Andrey Somov start = end; 13479629be70863521bead138c295351f3dec926ab1Andrey Somov } 13489629be70863521bead138c295351f3dec926ab1Andrey Somov } else { 13498e50e7a86555d3ef47829d853d254eace03e8157Andrey Somov if (Constant.LINEBR.has(ch, "\0 ")) { 1350370faf2dd7606d5fe2f887012be73d40fa531559maslovalex int len = end - start; 1351370faf2dd7606d5fe2f887012be73d40fa531559maslovalex this.column += len; 1352370faf2dd7606d5fe2f887012be73d40fa531559maslovalex stream.write(text, start, len); 13539629be70863521bead138c295351f3dec926ab1Andrey Somov if (ch == 0) { 13549629be70863521bead138c295351f3dec926ab1Andrey Somov writeLineBreak(null); 13559629be70863521bead138c295351f3dec926ab1Andrey Somov } 13569629be70863521bead138c295351f3dec926ab1Andrey Somov start = end; 13579629be70863521bead138c295351f3dec926ab1Andrey Somov } 13589629be70863521bead138c295351f3dec926ab1Andrey Somov } 13599629be70863521bead138c295351f3dec926ab1Andrey Somov if (ch != 0) { 136065619eff85ddfd768e973825b34b2ed8bbde537dAndrey Somov breaks = Constant.LINEBR.has(ch); 136125ac3b280b35ddb9167e0528626e2ec14488f173Andrey Somov spaces = ch == ' '; 13629629be70863521bead138c295351f3dec926ab1Andrey Somov } 13639629be70863521bead138c295351f3dec926ab1Andrey Somov end++; 13649629be70863521bead138c295351f3dec926ab1Andrey Somov } 13659629be70863521bead138c295351f3dec926ab1Andrey Somov } 13669629be70863521bead138c295351f3dec926ab1Andrey Somov 13679629be70863521bead138c295351f3dec926ab1Andrey Somov void writeLiteral(String text) throws IOException { 13689629be70863521bead138c295351f3dec926ab1Andrey Somov String hints = determineBlockHints(text); 13699629be70863521bead138c295351f3dec926ab1Andrey Somov writeIndicator("|" + hints, true, false, false); 13709629be70863521bead138c295351f3dec926ab1Andrey Somov if (hints.length() > 0 && (hints.charAt(hints.length() - 1)) == '+') { 13719629be70863521bead138c295351f3dec926ab1Andrey Somov openEnded = true; 13729629be70863521bead138c295351f3dec926ab1Andrey Somov } 13739629be70863521bead138c295351f3dec926ab1Andrey Somov writeLineBreak(null); 13749629be70863521bead138c295351f3dec926ab1Andrey Somov boolean breaks = true; 13759629be70863521bead138c295351f3dec926ab1Andrey Somov int start = 0, end = 0; 13769629be70863521bead138c295351f3dec926ab1Andrey Somov while (end <= text.length()) { 13779629be70863521bead138c295351f3dec926ab1Andrey Somov char ch = 0; 13789629be70863521bead138c295351f3dec926ab1Andrey Somov if (end < text.length()) { 13799629be70863521bead138c295351f3dec926ab1Andrey Somov ch = text.charAt(end); 13809629be70863521bead138c295351f3dec926ab1Andrey Somov } 13819629be70863521bead138c295351f3dec926ab1Andrey Somov if (breaks) { 1382b693d5a6b13314c20bee0e912ed209af6e0499efAndrey Somov if (ch == 0 || Constant.LINEBR.hasNo(ch)) { 13839629be70863521bead138c295351f3dec926ab1Andrey Somov String data = text.substring(start, end); 13849629be70863521bead138c295351f3dec926ab1Andrey Somov for (char br : data.toCharArray()) { 13859629be70863521bead138c295351f3dec926ab1Andrey Somov if (br == '\n') { 13869629be70863521bead138c295351f3dec926ab1Andrey Somov writeLineBreak(null); 13879629be70863521bead138c295351f3dec926ab1Andrey Somov } else { 13889629be70863521bead138c295351f3dec926ab1Andrey Somov writeLineBreak(String.valueOf(br)); 13899629be70863521bead138c295351f3dec926ab1Andrey Somov } 13909629be70863521bead138c295351f3dec926ab1Andrey Somov } 13919629be70863521bead138c295351f3dec926ab1Andrey Somov if (ch != 0) { 13929629be70863521bead138c295351f3dec926ab1Andrey Somov writeIndent(); 13939629be70863521bead138c295351f3dec926ab1Andrey Somov } 13949629be70863521bead138c295351f3dec926ab1Andrey Somov start = end; 13959629be70863521bead138c295351f3dec926ab1Andrey Somov } 13969629be70863521bead138c295351f3dec926ab1Andrey Somov } else { 139765619eff85ddfd768e973825b34b2ed8bbde537dAndrey Somov if (ch == 0 || Constant.LINEBR.has(ch)) { 1398370faf2dd7606d5fe2f887012be73d40fa531559maslovalex stream.write(text, start, end - start); 13999629be70863521bead138c295351f3dec926ab1Andrey Somov if (ch == 0) { 14009629be70863521bead138c295351f3dec926ab1Andrey Somov writeLineBreak(null); 14019629be70863521bead138c295351f3dec926ab1Andrey Somov } 14029629be70863521bead138c295351f3dec926ab1Andrey Somov start = end; 14039629be70863521bead138c295351f3dec926ab1Andrey Somov } 14049629be70863521bead138c295351f3dec926ab1Andrey Somov } 14059629be70863521bead138c295351f3dec926ab1Andrey Somov if (ch != 0) { 140625ac3b280b35ddb9167e0528626e2ec14488f173Andrey Somov breaks = Constant.LINEBR.has(ch); 14079629be70863521bead138c295351f3dec926ab1Andrey Somov } 14089629be70863521bead138c295351f3dec926ab1Andrey Somov end++; 14099629be70863521bead138c295351f3dec926ab1Andrey Somov } 14109629be70863521bead138c295351f3dec926ab1Andrey Somov } 14119629be70863521bead138c295351f3dec926ab1Andrey Somov 14129629be70863521bead138c295351f3dec926ab1Andrey Somov void writePlain(String text, boolean split) throws IOException { 14139629be70863521bead138c295351f3dec926ab1Andrey Somov if (rootContext) { 14149629be70863521bead138c295351f3dec926ab1Andrey Somov openEnded = true; 14159629be70863521bead138c295351f3dec926ab1Andrey Somov } 1416d830de2dc8edea813a00c18193802d2bab3fded0Andrey Somov if (text.length() == 0) { 14179629be70863521bead138c295351f3dec926ab1Andrey Somov return; 14189629be70863521bead138c295351f3dec926ab1Andrey Somov } 14199629be70863521bead138c295351f3dec926ab1Andrey Somov if (!this.whitespace) { 1420370faf2dd7606d5fe2f887012be73d40fa531559maslovalex this.column++; 1421370faf2dd7606d5fe2f887012be73d40fa531559maslovalex stream.write(SPACE); 14229629be70863521bead138c295351f3dec926ab1Andrey Somov } 14239629be70863521bead138c295351f3dec926ab1Andrey Somov this.whitespace = false; 14249629be70863521bead138c295351f3dec926ab1Andrey Somov this.indention = false; 14259629be70863521bead138c295351f3dec926ab1Andrey Somov boolean spaces = false; 14269629be70863521bead138c295351f3dec926ab1Andrey Somov boolean breaks = false; 14279629be70863521bead138c295351f3dec926ab1Andrey Somov int start = 0, end = 0; 14289629be70863521bead138c295351f3dec926ab1Andrey Somov while (end <= text.length()) { 14299629be70863521bead138c295351f3dec926ab1Andrey Somov char ch = 0; 14309629be70863521bead138c295351f3dec926ab1Andrey Somov if (end < text.length()) { 14319629be70863521bead138c295351f3dec926ab1Andrey Somov ch = text.charAt(end); 14329629be70863521bead138c295351f3dec926ab1Andrey Somov } 14339629be70863521bead138c295351f3dec926ab1Andrey Somov if (spaces) { 14349629be70863521bead138c295351f3dec926ab1Andrey Somov if (ch != ' ') { 14359629be70863521bead138c295351f3dec926ab1Andrey Somov if (start + 1 == end && this.column > this.bestWidth && split) { 14369629be70863521bead138c295351f3dec926ab1Andrey Somov writeIndent(); 14379629be70863521bead138c295351f3dec926ab1Andrey Somov this.whitespace = false; 14389629be70863521bead138c295351f3dec926ab1Andrey Somov this.indention = false; 14399629be70863521bead138c295351f3dec926ab1Andrey Somov } else { 1440370faf2dd7606d5fe2f887012be73d40fa531559maslovalex int len = end - start; 1441370faf2dd7606d5fe2f887012be73d40fa531559maslovalex this.column += len; 1442370faf2dd7606d5fe2f887012be73d40fa531559maslovalex stream.write(text, start, len); 14439629be70863521bead138c295351f3dec926ab1Andrey Somov } 14449629be70863521bead138c295351f3dec926ab1Andrey Somov start = end; 14459629be70863521bead138c295351f3dec926ab1Andrey Somov } 14469629be70863521bead138c295351f3dec926ab1Andrey Somov } else if (breaks) { 1447b693d5a6b13314c20bee0e912ed209af6e0499efAndrey Somov if (Constant.LINEBR.hasNo(ch)) { 14489629be70863521bead138c295351f3dec926ab1Andrey Somov if (text.charAt(start) == '\n') { 14499629be70863521bead138c295351f3dec926ab1Andrey Somov writeLineBreak(null); 14509629be70863521bead138c295351f3dec926ab1Andrey Somov } 14519629be70863521bead138c295351f3dec926ab1Andrey Somov String data = text.substring(start, end); 14529629be70863521bead138c295351f3dec926ab1Andrey Somov for (char br : data.toCharArray()) { 14539629be70863521bead138c295351f3dec926ab1Andrey Somov if (br == '\n') { 14549629be70863521bead138c295351f3dec926ab1Andrey Somov writeLineBreak(null); 14559629be70863521bead138c295351f3dec926ab1Andrey Somov } else { 14569629be70863521bead138c295351f3dec926ab1Andrey Somov writeLineBreak(String.valueOf(br)); 14579629be70863521bead138c295351f3dec926ab1Andrey Somov } 14589629be70863521bead138c295351f3dec926ab1Andrey Somov } 14599629be70863521bead138c295351f3dec926ab1Andrey Somov writeIndent(); 14609629be70863521bead138c295351f3dec926ab1Andrey Somov this.whitespace = false; 14619629be70863521bead138c295351f3dec926ab1Andrey Somov this.indention = false; 14629629be70863521bead138c295351f3dec926ab1Andrey Somov start = end; 14639629be70863521bead138c295351f3dec926ab1Andrey Somov } 14649629be70863521bead138c295351f3dec926ab1Andrey Somov } else { 146565619eff85ddfd768e973825b34b2ed8bbde537dAndrey Somov if (ch == 0 || Constant.LINEBR.has(ch)) { 1466370faf2dd7606d5fe2f887012be73d40fa531559maslovalex int len = end - start; 1467370faf2dd7606d5fe2f887012be73d40fa531559maslovalex this.column += len; 1468370faf2dd7606d5fe2f887012be73d40fa531559maslovalex stream.write(text, start, len); 14699629be70863521bead138c295351f3dec926ab1Andrey Somov start = end; 14709629be70863521bead138c295351f3dec926ab1Andrey Somov } 14719629be70863521bead138c295351f3dec926ab1Andrey Somov } 14729629be70863521bead138c295351f3dec926ab1Andrey Somov if (ch != 0) { 147325ac3b280b35ddb9167e0528626e2ec14488f173Andrey Somov spaces = ch == ' '; 147425ac3b280b35ddb9167e0528626e2ec14488f173Andrey Somov breaks = Constant.LINEBR.has(ch); 14759629be70863521bead138c295351f3dec926ab1Andrey Somov } 14769629be70863521bead138c295351f3dec926ab1Andrey Somov end++; 14779629be70863521bead138c295351f3dec926ab1Andrey Somov } 14789629be70863521bead138c295351f3dec926ab1Andrey Somov } 14799629be70863521bead138c295351f3dec926ab1Andrey Somov} 1480