aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/org/yaml/snakeyaml/emitter
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org/yaml/snakeyaml/emitter')
-rw-r--r--src/main/java/org/yaml/snakeyaml/emitter/Emitter.java1422
-rw-r--r--src/main/java/org/yaml/snakeyaml/emitter/EmitterException.java17
-rwxr-xr-xsrc/main/java/org/yaml/snakeyaml/emitter/EmitterState.java15
-rw-r--r--src/main/java/org/yaml/snakeyaml/emitter/ScalarAnalysis.java31
4 files changed, 1485 insertions, 0 deletions
diff --git a/src/main/java/org/yaml/snakeyaml/emitter/Emitter.java b/src/main/java/org/yaml/snakeyaml/emitter/Emitter.java
new file mode 100644
index 00000000..36b62e92
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/emitter/Emitter.java
@@ -0,0 +1,1422 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.emitter;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Queue;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.regex.Pattern;
+
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.events.AliasEvent;
+import org.yaml.snakeyaml.events.CollectionEndEvent;
+import org.yaml.snakeyaml.events.CollectionStartEvent;
+import org.yaml.snakeyaml.events.DocumentEndEvent;
+import org.yaml.snakeyaml.events.DocumentStartEvent;
+import org.yaml.snakeyaml.events.Event;
+import org.yaml.snakeyaml.events.MappingEndEvent;
+import org.yaml.snakeyaml.events.MappingStartEvent;
+import org.yaml.snakeyaml.events.NodeEvent;
+import org.yaml.snakeyaml.events.ScalarEvent;
+import org.yaml.snakeyaml.events.SequenceEndEvent;
+import org.yaml.snakeyaml.events.SequenceStartEvent;
+import org.yaml.snakeyaml.events.StreamEndEvent;
+import org.yaml.snakeyaml.events.StreamStartEvent;
+
+/**
+ * <pre>
+ * Emitter expects events obeying the following grammar:
+ * stream ::= STREAM-START document* STREAM-END
+ * document ::= DOCUMENT-START node DOCUMENT-END
+ * node ::= SCALAR | sequence | mapping
+ * sequence ::= SEQUENCE-START node* SEQUENCE-END
+ * mapping ::= MAPPING-START (node node)* MAPPING-END
+ * </pre>
+ *
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public final class Emitter {
+ private static final Map<Character, String> ESCAPE_REPLACEMENTS = new HashMap<Character, String>();
+ public static final int MIN_INDENT = 1;
+ public static final int MAX_INDENT = 10;
+
+ static {
+ ESCAPE_REPLACEMENTS.put(new Character('\0'), "0");
+ ESCAPE_REPLACEMENTS.put(new Character('\u0007'), "a");
+ ESCAPE_REPLACEMENTS.put(new Character('\u0008'), "b");
+ ESCAPE_REPLACEMENTS.put(new Character('\u0009'), "t");
+ ESCAPE_REPLACEMENTS.put(new Character('\n'), "n");
+ ESCAPE_REPLACEMENTS.put(new Character('\u000B'), "v");
+ ESCAPE_REPLACEMENTS.put(new Character('\u000C'), "f");
+ ESCAPE_REPLACEMENTS.put(new Character('\r'), "r");
+ ESCAPE_REPLACEMENTS.put(new Character('\u001B'), "e");
+ ESCAPE_REPLACEMENTS.put(new Character('"'), "\"");
+ ESCAPE_REPLACEMENTS.put(new Character('\\'), "\\");
+ ESCAPE_REPLACEMENTS.put(new Character('\u0085'), "N");
+ ESCAPE_REPLACEMENTS.put(new Character('\u00A0'), "_");
+ ESCAPE_REPLACEMENTS.put(new Character('\u2028'), "L");
+ ESCAPE_REPLACEMENTS.put(new Character('\u2029'), "P");
+ }
+
+ private final static Map<String, String> DEFAULT_TAG_PREFIXES = new LinkedHashMap<String, String>();
+ static {
+ DEFAULT_TAG_PREFIXES.put("!", "!");
+ DEFAULT_TAG_PREFIXES.put("tag:yaml.org,2002:", "!!");
+ }
+ // The stream should have the methods `write` and possibly `flush`.
+ private final Writer stream;
+
+ // Encoding is defined by Writer (cannot be overriden by STREAM-START.)
+ // private Charset encoding;
+
+ // Emitter is a state machine with a stack of states to handle nested
+ // structures.
+ private final LinkedList<EmitterState> states;
+ private EmitterState state;
+
+ // Current event and the event queue.
+ private final Queue<Event> events;
+ private Event event;
+
+ // The current indentation level and the stack of previous indents.
+ private final LinkedList<Integer> indents;
+ private Integer indent;
+
+ // Flow level.
+ private int flowLevel;
+
+ // Contexts.
+ private boolean rootContext;
+ private boolean mappingContext;
+ private boolean simpleKeyContext;
+
+ //
+ // Characteristics of the last emitted character:
+ // - current position.
+ // - is it a whitespace?
+ // - is it an indention character
+ // (indentation space, '-', '?', or ':')?
+ private int line;
+ private int column;
+ private boolean whitespace;
+ private boolean indention;
+ private boolean openEnded;
+
+ // Formatting details.
+ private Boolean canonical;
+ private boolean allowUnicode;
+ private int bestIndent;
+ private int bestWidth;
+ private String bestLineBreak;
+
+ // Tag prefixes.
+ private Map<String, String> tagPrefixes;
+
+ // Prepared anchor and tag.
+ private String preparedAnchor;
+ private String preparedTag;
+
+ // Scalar analysis and style.
+ private ScalarAnalysis analysis;
+ private char style = 0;
+
+ public Emitter(Writer stream, DumperOptions opts) {
+ // The stream should have the methods `write` and possibly `flush`.
+ this.stream = stream;
+ // Emitter is a state machine with a stack of states to handle nested
+ // structures.
+ this.states = new LinkedList<EmitterState>();
+ this.state = new ExpectStreamStart();
+ // Current event and the event queue.
+ this.events = new LinkedList<Event>();
+ this.event = null;
+ // The current indentation level and the stack of previous indents.
+ this.indents = new LinkedList<Integer>();
+ this.indent = null;
+ // Flow level.
+ this.flowLevel = 0;
+ // Contexts.
+ mappingContext = false;
+ simpleKeyContext = false;
+
+ //
+ // Characteristics of the last emitted character:
+ // - current position.
+ // - is it a whitespace?
+ // - is it an indention character
+ // (indentation space, '-', '?', or ':')?
+ line = 0;
+ column = 0;
+ whitespace = true;
+ indention = true;
+
+ // Whether the document requires an explicit document indicator
+ openEnded = false;
+
+ // Formatting details.
+ this.canonical = opts.isCanonical();
+ this.allowUnicode = opts.isAllowUnicode();
+ this.bestIndent = 2;
+ if ((opts.getIndent() > MIN_INDENT) && (opts.getIndent() < MAX_INDENT)) {
+ this.bestIndent = opts.getIndent();
+ }
+ this.bestWidth = 80;
+ if (opts.getWidth() > this.bestIndent * 2) {
+ this.bestWidth = opts.getWidth();
+ }
+ this.bestLineBreak = opts.getLineBreak().getString();
+
+ // Tag prefixes.
+ this.tagPrefixes = new LinkedHashMap<String, String>();
+
+ // Prepared anchor and tag.
+ this.preparedAnchor = null;
+ this.preparedTag = null;
+
+ // Scalar analysis and style.
+ this.analysis = null;
+ this.style = (char) 0;
+ }
+
+ public void emit(Event event) throws IOException {
+ this.events.offer(event);
+ while (!needMoreEvents()) {
+ this.event = this.events.poll();
+ this.state.expect();
+ this.event = null;
+ }
+ }
+
+ // In some cases, we wait for a few next events before emitting.
+
+ private boolean needMoreEvents() {
+ if (events.isEmpty()) {
+ return true;
+ }
+ Event event = events.peek();
+ if (event instanceof DocumentStartEvent) {
+ return needEvents(1);
+ } else if (event instanceof SequenceStartEvent) {
+ return needEvents(2);
+ } else if (event instanceof MappingStartEvent) {
+ return needEvents(3);
+ } else {
+ return false;
+ }
+ }
+
+ private boolean needEvents(int count) {
+ int level = 0;
+ Iterator<Event> iter = events.iterator();
+ iter.next();
+ while (iter.hasNext()) {
+ Event event = iter.next();
+ if (event instanceof DocumentStartEvent || event instanceof CollectionStartEvent) {
+ level++;
+ } else if (event instanceof DocumentEndEvent || event instanceof CollectionEndEvent) {
+ level--;
+ } else if (event instanceof StreamEndEvent) {
+ level = -1;
+ }
+ if (level < 0) {
+ return false;
+ }
+ }
+ return events.size() < count + 1;
+ }
+
+ private void increaseIndent(boolean flow, boolean indentless) {
+ indents.addFirst(indent);
+ if (indent == null) {
+ if (flow) {
+ indent = bestIndent;
+ } else {
+ indent = 0;
+ }
+ } else if (!indentless) {
+ this.indent += bestIndent;
+ }
+ }
+
+ // States
+
+ // Stream handlers.
+
+ private class ExpectStreamStart implements EmitterState {
+ public void expect() throws IOException {
+ if (event instanceof StreamStartEvent) {
+ writeStreamStart();
+ state = new ExpectFirstDocumentStart();
+ } else {
+ throw new EmitterException("expected StreamStartEvent, but got " + event);
+ }
+ }
+ }
+
+ private class ExpectNothing implements EmitterState {
+ public void expect() throws IOException {
+ throw new EmitterException("expecting nothing, but got " + event);
+ }
+ }
+
+ // Document handlers.
+
+ private class ExpectFirstDocumentStart implements EmitterState {
+ public void expect() throws IOException {
+ new ExpectDocumentStart(true).expect();
+ }
+ }
+
+ private class ExpectDocumentStart implements EmitterState {
+ private boolean first;
+
+ public ExpectDocumentStart(boolean first) {
+ this.first = first;
+ }
+
+ public void expect() throws IOException {
+ if (event instanceof DocumentStartEvent) {
+ DocumentStartEvent ev = (DocumentStartEvent) event;
+ if ((ev.getVersion() != null || ev.getTags() != null) && openEnded) {
+ writeIndicator("...", true, false, false);
+ writeIndent();
+ }
+ if (ev.getVersion() != null) {
+ String versionText = prepareVersion(ev.getVersion());
+ writeVersionDirective(versionText);
+ }
+ tagPrefixes = new LinkedHashMap<String, String>(DEFAULT_TAG_PREFIXES);
+ if (ev.getTags() != null) {
+ Set<String> handles = new TreeSet<String>(ev.getTags().keySet());
+ for (String handle : handles) {
+ String prefix = ev.getTags().get(handle);
+ tagPrefixes.put(prefix, handle);
+ String handleText = prepareTagHandle(handle);
+ String prefixText = prepareTagPrefix(prefix);
+ writeTagDirective(handleText, prefixText);
+ }
+ }
+ boolean implicit = first && !ev.getExplicit() && !canonical
+ && ev.getVersion() == null && ev.getTags() == null && !checkEmptyDocument();
+ if (!implicit) {
+ writeIndent();
+ writeIndicator("---", true, false, false);
+ if (canonical) {
+ writeIndent();
+ }
+ }
+ state = new ExpectDocumentRoot();
+ } else if (event instanceof StreamEndEvent) {
+ // TODO fix 313 PyYAML changeset
+ // if (openEnded) {
+ // writeIndicator("...", true, false, false);
+ // writeIndent();
+ // }
+ writeStreamEnd();
+ state = new ExpectNothing();
+ } else {
+ throw new EmitterException("expected DocumentStartEvent, but got " + event);
+ }
+ }
+ }
+
+ private class ExpectDocumentEnd implements EmitterState {
+ public void expect() throws IOException {
+ if (event instanceof DocumentEndEvent) {
+ writeIndent();
+ if (((DocumentEndEvent) event).getExplicit()) {
+ writeIndicator("...", true, false, false);
+ writeIndent();
+ }
+ flushStream();
+ state = new ExpectDocumentStart(false);
+ } else {
+ throw new EmitterException("expected DocumentEndEvent, but got " + event);
+ }
+ }
+ }
+
+ private class ExpectDocumentRoot implements EmitterState {
+ public void expect() throws IOException {
+ states.addFirst(new ExpectDocumentEnd());
+ expectNode(true, false, false, false);
+ }
+ }
+
+ // Node handlers.
+
+ private void expectNode(boolean root, boolean sequence, boolean mapping, boolean simpleKey)
+ throws IOException {
+ rootContext = root;
+ mappingContext = mapping;
+ simpleKeyContext = simpleKey;
+ if (event instanceof AliasEvent) {
+ expectAlias();
+ } else if (event instanceof ScalarEvent || event instanceof CollectionStartEvent) {
+ processAnchor("&");
+ processTag();
+ if (event instanceof ScalarEvent) {
+ expectScalar();
+ } else if (event instanceof SequenceStartEvent) {
+ if (flowLevel != 0 || canonical || ((SequenceStartEvent) event).getFlowStyle()
+ || checkEmptySequence()) {
+ expectFlowSequence();
+ } else {
+ expectBlockSequence();
+ }
+ } else {// MappingStartEvent
+ if (flowLevel != 0 || canonical || ((MappingStartEvent) event).getFlowStyle()
+ || checkEmptyMapping()) {
+ expectFlowMapping();
+ } else {
+ expectBlockMapping();
+ }
+ }
+ } else {
+ throw new EmitterException("expected NodeEvent, but got " + event);
+ }
+ }
+
+ private void expectAlias() throws IOException {
+ if (((NodeEvent) event).getAnchor() == null) {
+ throw new EmitterException("anchor is not specified for alias");
+ }
+ processAnchor("*");
+ state = states.removeFirst();
+ }
+
+ private void expectScalar() throws IOException {
+ increaseIndent(true, false);
+ processScalar();
+ indent = indents.removeFirst();
+ state = states.removeFirst();
+ }
+
+ // Flow sequence handlers.
+
+ private void expectFlowSequence() throws IOException {
+ writeIndicator("[", true, true, false);
+ flowLevel++;
+ increaseIndent(true, false);
+ state = new ExpectFirstFlowSequenceItem();
+ }
+
+ private class ExpectFirstFlowSequenceItem implements EmitterState {
+ public void expect() throws IOException {
+ if (event instanceof SequenceEndEvent) {
+ indent = indents.removeFirst();
+ flowLevel--;
+ writeIndicator("]", false, false, false);
+ state = states.removeFirst();
+ } else {
+ if (canonical || column > bestWidth) {
+ writeIndent();
+ }
+ states.addFirst(new ExpectFlowSequenceItem());
+ expectNode(false, true, false, false);
+ }
+ }
+ }
+
+ private class ExpectFlowSequenceItem implements EmitterState {
+ public void expect() throws IOException {
+ if (event instanceof SequenceEndEvent) {
+ indent = indents.removeFirst();
+ flowLevel--;
+ if (canonical) {
+ writeIndicator(",", false, false, false);
+ writeIndent();
+ }
+ writeIndicator("]", false, false, false);
+ state = states.removeFirst();
+ } else {
+ writeIndicator(",", false, false, false);
+ if (canonical || column > bestWidth) {
+ writeIndent();
+ }
+ states.addFirst(new ExpectFlowSequenceItem());
+ expectNode(false, true, false, false);
+ }
+ }
+ }
+
+ // Flow mapping handlers.
+
+ private void expectFlowMapping() throws IOException {
+ writeIndicator("{", true, true, false);
+ flowLevel++;
+ increaseIndent(true, false);
+ state = new ExpectFirstFlowMappingKey();
+ }
+
+ private class ExpectFirstFlowMappingKey implements EmitterState {
+ public void expect() throws IOException {
+ if (event instanceof MappingEndEvent) {
+ indent = indents.removeFirst();
+ flowLevel--;
+ writeIndicator("}", false, false, false);
+ state = states.removeFirst();
+ } else {
+ if (canonical || column > bestWidth) {
+ writeIndent();
+ }
+ if (!canonical && checkSimpleKey()) {
+ states.addFirst(new ExpectFlowMappingSimpleValue());
+ expectNode(false, false, true, true);
+ } else {
+ writeIndicator("?", true, false, false);
+ states.addFirst(new ExpectFlowMappingValue());
+ expectNode(false, false, true, false);
+ }
+ }
+ }
+ }
+
+ private class ExpectFlowMappingKey implements EmitterState {
+ public void expect() throws IOException {
+ if (event instanceof MappingEndEvent) {
+ indent = indents.removeFirst();
+ flowLevel--;
+ if (canonical) {
+ writeIndicator(",", false, false, false);
+ writeIndent();
+ }
+ writeIndicator("}", false, false, false);
+ state = states.removeFirst();
+ } else {
+ writeIndicator(",", false, false, false);
+ if (canonical || column > bestWidth) {
+ writeIndent();
+ }
+ if (!canonical && checkSimpleKey()) {
+ states.addFirst(new ExpectFlowMappingSimpleValue());
+ expectNode(false, false, true, true);
+ } else {
+ writeIndicator("?", true, false, false);
+ states.addFirst(new ExpectFlowMappingValue());
+ expectNode(false, false, true, false);
+ }
+ }
+ }
+ }
+
+ private class ExpectFlowMappingSimpleValue implements EmitterState {
+ public void expect() throws IOException {
+ writeIndicator(":", false, false, false);
+ states.addFirst(new ExpectFlowMappingKey());
+ expectNode(false, false, true, false);
+ }
+ }
+
+ private class ExpectFlowMappingValue implements EmitterState {
+ public void expect() throws IOException {
+ if (canonical || column > bestWidth) {
+ writeIndent();
+ }
+ writeIndicator(":", true, false, false);
+ states.addFirst(new ExpectFlowMappingKey());
+ expectNode(false, false, true, false);
+ }
+ }
+
+ // Block sequence handlers.
+
+ private void expectBlockSequence() throws IOException {
+ boolean indentless = (mappingContext && !indention);
+ increaseIndent(false, indentless);
+ state = new ExpectFirstBlockSequenceItem();
+ }
+
+ private class ExpectFirstBlockSequenceItem implements EmitterState {
+ public void expect() throws IOException {
+ new ExpectBlockSequenceItem(true).expect();
+ }
+ }
+
+ private class ExpectBlockSequenceItem implements EmitterState {
+ private boolean first;
+
+ public ExpectBlockSequenceItem(boolean first) {
+ this.first = first;
+ }
+
+ public void expect() throws IOException {
+ if (!this.first && event instanceof SequenceEndEvent) {
+ indent = indents.removeFirst();
+ state = states.removeFirst();
+ } else {
+ writeIndent();
+ writeIndicator("-", true, false, true);
+ states.addFirst(new ExpectBlockSequenceItem(false));
+ expectNode(false, true, false, false);
+ }
+ }
+ }
+
+ // Block mapping handlers.
+ private void expectBlockMapping() throws IOException {
+ increaseIndent(false, false);
+ state = new ExpectFirstBlockMappingKey();
+ }
+
+ private class ExpectFirstBlockMappingKey implements EmitterState {
+ public void expect() throws IOException {
+ new ExpectBlockMappingKey(true).expect();
+ }
+ }
+
+ private class ExpectBlockMappingKey implements EmitterState {
+ private boolean first;
+
+ public ExpectBlockMappingKey(boolean first) {
+ this.first = first;
+ }
+
+ public void expect() throws IOException {
+ if (!this.first && event instanceof MappingEndEvent) {
+ indent = indents.removeFirst();
+ state = states.removeFirst();
+ } else {
+ writeIndent();
+ if (checkSimpleKey()) {
+ states.addFirst(new ExpectBlockMappingSimpleValue());
+ expectNode(false, false, true, true);
+ } else {
+ writeIndicator("?", true, false, true);
+ states.addFirst(new ExpectBlockMappingValue());
+ expectNode(false, false, true, false);
+ }
+ }
+ }
+ }
+
+ private class ExpectBlockMappingSimpleValue implements EmitterState {
+ public void expect() throws IOException {
+ writeIndicator(":", false, false, false);
+ states.addFirst(new ExpectBlockMappingKey(false));
+ expectNode(false, false, true, false);
+ }
+ }
+
+ private class ExpectBlockMappingValue implements EmitterState {
+ public void expect() throws IOException {
+ writeIndent();
+ writeIndicator(":", true, false, true);
+ states.addFirst(new ExpectBlockMappingKey(false));
+ expectNode(false, false, true, false);
+ }
+ }
+
+ // Checkers.
+
+ private boolean checkEmptySequence() {
+ return (event instanceof SequenceStartEvent && !events.isEmpty() && events.peek() instanceof SequenceEndEvent);
+ }
+
+ private boolean checkEmptyMapping() {
+ return (event instanceof MappingStartEvent && !events.isEmpty() && events.peek() instanceof MappingEndEvent);
+ }
+
+ private boolean checkEmptyDocument() {
+ if (!(event instanceof DocumentStartEvent) || events.isEmpty()) {
+ return false;
+ }
+ Event event = events.peek();
+ if (event instanceof ScalarEvent) {
+ ScalarEvent e = (ScalarEvent) event;
+ return (e.getAnchor() == null && e.getTag() == null && e.getImplicit() != null && e
+ .getValue() == "");
+ } else {
+ return false;
+ }
+ }
+
+ private boolean checkSimpleKey() {
+ int length = 0;
+ if (event instanceof NodeEvent && ((NodeEvent) event).getAnchor() != null) {
+ if (preparedAnchor == null) {
+ preparedAnchor = prepareAnchor(((NodeEvent) event).getAnchor());
+ }
+ length += preparedAnchor.length();
+ }
+ String tag = null;
+ if (event instanceof ScalarEvent) {
+ tag = ((ScalarEvent) event).getTag();
+ } else if (event instanceof CollectionStartEvent) {
+ tag = ((CollectionStartEvent) event).getTag();
+ }
+ if (tag != null) {
+ if (preparedTag == null) {
+ preparedTag = prepareTag(tag);
+ }
+ length += preparedTag.length();
+ }
+ if (event instanceof ScalarEvent) {
+ if (analysis == null) {
+ analysis = analyzeScalar(((ScalarEvent) event).getValue());
+ }
+ length += analysis.scalar.length();
+ }
+ return (length < 128 && (event instanceof AliasEvent
+ || (event instanceof ScalarEvent && !analysis.empty && !analysis.multiline)
+ || checkEmptySequence() || checkEmptyMapping()));
+ }
+
+ // Anchor, Tag, and Scalar processors.
+
+ private void processAnchor(String indicator) throws IOException {
+ NodeEvent ev = (NodeEvent) event;
+ if (ev.getAnchor() == null) {
+ preparedAnchor = null;
+ return;
+ }
+ if (preparedAnchor == null) {
+ preparedAnchor = prepareAnchor(ev.getAnchor());
+ }
+ if (preparedAnchor != null && !"".equals(preparedAnchor)) {
+ writeIndicator(indicator + preparedAnchor, true, false, false);
+ }
+ preparedAnchor = null;
+ }
+
+ private void processTag() throws IOException {
+ String tag = null;
+ if (event instanceof ScalarEvent) {
+ ScalarEvent ev = (ScalarEvent) event;
+ tag = ev.getTag();
+ if (style == 0) {
+ style = chooseScalarStyle();
+ }
+ if (((!canonical || tag == null) && ((style == 0 && ev.getImplicit()[0]) || (style != 0 && ev
+ .getImplicit()[1])))) {
+ preparedTag = null;
+ return;
+ }
+ if (ev.getImplicit()[0] && tag == null) {
+ tag = "!";
+ preparedTag = null;
+ }
+ } else {
+ CollectionStartEvent ev = (CollectionStartEvent) event;
+ tag = ev.getTag();
+ if ((!canonical || tag == null) && ev.getImplicit()) {
+ preparedTag = null;
+ return;
+ }
+ }
+ if (tag == null) {
+ throw new EmitterException("tag is not specified");
+ }
+ if (preparedTag == null) {
+ preparedTag = prepareTag(tag);
+ }
+ if (preparedTag != null && !"".equals(preparedTag)) {
+ writeIndicator(preparedTag, true, false, false);
+ }
+ preparedTag = null;
+ }
+
+ private char chooseScalarStyle() {
+ ScalarEvent ev = (ScalarEvent) event;
+ if (analysis == null) {
+ analysis = analyzeScalar(ev.getValue());
+ }
+ if (ev.getStyle() != null && ev.getStyle() == '"' || this.canonical) {
+ return '"';
+ }
+ if (ev.getStyle() == null && ev.getImplicit()[0]) {
+ if (!(simpleKeyContext && (analysis.empty || analysis.multiline))
+ && ((flowLevel != 0 && analysis.allowFlowPlain) || (flowLevel == 0 && analysis.allowBlockPlain))) {
+ return 0;
+ }
+ }
+ if (ev.getStyle() != null && (ev.getStyle() == '|' || ev.getStyle() == '>')) {
+ if (flowLevel == 0 && !simpleKeyContext && analysis.allowBlock) {
+ return ev.getStyle();
+ }
+ }
+ if (ev.getStyle() == null || ev.getStyle() == '\'') {
+ if (analysis.allowSingleQuoted && !(simpleKeyContext && analysis.multiline)) {
+ return '\'';
+ }
+ }
+ return '"';
+ }
+
+ private void processScalar() throws IOException {
+ ScalarEvent ev = (ScalarEvent) event;
+ if (analysis == null) {
+ analysis = analyzeScalar(ev.getValue());
+ }
+ if (style == 0) {
+ style = chooseScalarStyle();
+ }
+ boolean split = !simpleKeyContext;
+ if (style == '"') {
+ writeDoubleQuoted(analysis.scalar, split);
+ } else if (style == '\'') {
+ writeSingleQuoted(analysis.scalar, split);
+ } else if (style == '>') {
+ writeFolded(analysis.scalar);
+ } else if (style == '|') {
+ writeLiteral(analysis.scalar);
+ } else {
+ writePlain(analysis.scalar, split);
+ }
+ analysis = null;
+ style = 0;
+ }
+
+ // Analyzers.
+
+ private String prepareVersion(Integer[] version) {
+ Integer major = version[0];
+ Integer minor = version[1];
+ if (major != 1) {
+ throw new EmitterException("unsupported YAML version: " + version[0] + "." + version[1]);
+ }
+ return major.toString() + "." + minor.toString();
+ }
+
+ private final static Pattern HANDLE_FORMAT = Pattern.compile("^![-_\\w]*!$");
+
+ private String prepareTagHandle(String handle) {
+ if (handle == null || "".equals(handle)) {
+ throw new EmitterException("tag handle must not be empty");
+ } else if (handle.charAt(0) != '!' || handle.charAt(handle.length() - 1) != '!') {
+ throw new EmitterException("tag handle must start and end with '!': " + handle);
+ } else if (!"!".equals(handle) && !HANDLE_FORMAT.matcher(handle).matches()) {
+ throw new EmitterException("invalid character in the tag handle: " + handle);
+ }
+ return handle;
+ }
+
+ private String prepareTagPrefix(String prefix) {
+ if (prefix == null || "".equals(prefix)) {
+ throw new EmitterException("tag prefix must not be empty");
+ }
+ StringBuffer chunks = new StringBuffer();
+ int start = 0;
+ int end = 0;
+ if (prefix.charAt(0) == '!') {
+ end = 1;
+ }
+ while (end < prefix.length()) {
+ end++;
+ }
+ if (start < end) {
+ chunks.append(prefix.substring(start, end));
+ }
+ return chunks.toString();
+ }
+
+ private String prepareTag(String tag) {
+ if (tag == null || "".equals(tag)) {
+ throw new EmitterException("tag must not be empty");
+ }
+ if (tag.equals("!")) {
+ return tag;
+ }
+ String handle = null;
+ String suffix = tag;
+ for (String prefix : tagPrefixes.keySet()) {
+ if (tag.startsWith(prefix) && (prefix.equals("!") || prefix.length() < tag.length())) {
+ handle = tagPrefixes.get(prefix);
+ suffix = tag.substring(prefix.length());
+ }
+ }
+ StringBuffer chunks = new StringBuffer();
+ int start = 0;
+ int end = 0;
+ while (end < suffix.length()) {
+ end++;
+ }
+ if (start < end) {
+ chunks.append(suffix.substring(start, end));
+ }
+ String suffixText = chunks.toString();
+ if (handle != null) {
+ return handle + suffixText;
+ } else {
+ return "!<" + suffixText + ">";
+ }
+ }
+
+ private final static Pattern ANCHOR_FORMAT = Pattern.compile("^[-_\\w]*$");
+
+ static String prepareAnchor(String anchor) {
+ if (anchor == null || "".equals(anchor)) {
+ throw new EmitterException("anchor must not be empty");
+ }
+ if (!ANCHOR_FORMAT.matcher(anchor).matches()) {
+ throw new EmitterException("invalid character in the anchor: " + anchor);
+ }
+ return anchor;
+ }
+
+ private ScalarAnalysis analyzeScalar(String scalar) {
+ // Empty scalar is a special case.
+ if (scalar == null || "".equals(scalar)) {
+ return new ScalarAnalysis(scalar, true, false, false, true, true, true, false);
+ }
+ // Indicators and special characters.
+ boolean blockIndicators = false;
+ boolean flowIndicators = false;
+ boolean lineBreaks = false;
+ boolean specialCharacters = false;
+
+ // Important whitespace combinations.
+ boolean leadingSpace = false;
+ boolean leadingBreak = false;
+ boolean trailingSpace = false;
+ boolean trailingBreak = false;
+ boolean breakSpace = false;
+ boolean spaceBreak = false;
+
+ // Check document indicators.
+ if (scalar.startsWith("---") || scalar.startsWith("...")) {
+ blockIndicators = true;
+ flowIndicators = true;
+ }
+ // First character or preceded by a whitespace.
+ boolean preceededByWhitespace = true;
+ boolean followedByWhitespace = (scalar.length() == 1 || "\0 \t\r\n\u0085\u2029\u2029"
+ .indexOf(scalar.charAt(1)) != -1);
+ // The previous character is a space.
+ boolean previousSpace = false;
+
+ // The previous character is a break.
+ boolean previousBreak = false;
+
+ int index = 0;
+
+ while (index < scalar.length()) {
+ char ch = scalar.charAt(index);
+ // Check for indicators.
+ if (index == 0) {
+ // Leading indicators are special characters.
+ if ("#,[]{}&*!|>\'\"%@`".indexOf(ch) != -1) {
+ flowIndicators = true;
+ blockIndicators = true;
+ }
+ if (ch == '?' || ch == ':') {
+ flowIndicators = true;
+ if (followedByWhitespace) {
+ blockIndicators = true;
+ }
+ }
+ if (ch == '-' && followedByWhitespace) {
+ flowIndicators = true;
+ blockIndicators = true;
+ }
+ } else {
+ // Some indicators cannot appear within a scalar as well.
+ if (",?[]{}".indexOf(ch) != -1) {
+ flowIndicators = true;
+ }
+ if (ch == ':') {
+ flowIndicators = true;
+ if (followedByWhitespace) {
+ blockIndicators = true;
+ }
+ }
+ if (ch == '#' && preceededByWhitespace) {
+ flowIndicators = true;
+ blockIndicators = true;
+ }
+ }
+ // Check for line breaks, special, and unicode characters.
+ if (ch == '\n' || ch == '\u0085' || ch == '\u2028' || ch == '\u2029') {
+ lineBreaks = true;
+ }
+ if (!(ch == '\n' || ('\u0020' <= ch && ch <= '\u007E'))) {
+ if ((ch == '\u0085' || ('\u00A0' <= ch && ch <= '\uD7FF') || ('\uE000' <= ch && ch <= '\uFFFD'))
+ && (ch != '\uFEFF')) {
+ // unicode is used
+ if (!this.allowUnicode) {
+ specialCharacters = true;
+ }
+ } else {
+ specialCharacters = true;
+ }
+ }
+ // Detect important whitespace combinations.
+ if (ch == ' ') {
+ if (index == 0) {
+ leadingSpace = true;
+ }
+ if (index == scalar.length() - 1) {
+ trailingSpace = true;
+ }
+ if (previousBreak) {
+ breakSpace = true;
+ }
+ previousSpace = true;
+ previousBreak = false;
+ } else if ("\n\u0085\u2028\u2029".indexOf(ch) != -1) {
+ if (index == 0) {
+ leadingBreak = true;
+ }
+ if (index == scalar.length() - 1) {
+ trailingBreak = true;
+ }
+ if (previousSpace) {
+ spaceBreak = true;
+ }
+ previousSpace = false;
+ previousBreak = true;
+ } else {
+ previousSpace = false;
+ previousBreak = false;
+ }
+
+ // Prepare for the next character.
+ index++;
+ preceededByWhitespace = "\0 \t\r\n\u0085\u2028\u2029".indexOf(ch) != -1;
+ followedByWhitespace = (index + 1 >= scalar.length() || "\0 \t\r\n\u0085\u2028\u2029"
+ .indexOf(scalar.charAt(index + 1)) != -1);
+ }
+ // Let's decide what styles are allowed.
+ boolean allowFlowPlain = true;
+ boolean allowBlockPlain = true;
+ boolean allowSingleQuoted = true;
+ boolean allowDoubleQuoted = true;
+ boolean allowBlock = true;
+ // Leading and trailing whitespaces are bad for plain scalars.
+ if (leadingSpace || leadingBreak || trailingSpace || trailingBreak) {
+ allowFlowPlain = allowBlockPlain = false;
+ }
+ // We do not permit trailing spaces for block scalars.
+ if (trailingSpace) {
+ allowBlock = false;
+ }
+ // Spaces at the beginning of a new line are only acceptable for block
+ // scalars.
+ if (breakSpace) {
+ allowFlowPlain = allowBlockPlain = allowSingleQuoted = false;
+ }
+ // Spaces followed by breaks, as well as special character are only
+ // allowed for double quoted scalars.
+ if (spaceBreak || specialCharacters) {
+ allowFlowPlain = allowBlockPlain = allowSingleQuoted = allowBlock = false;
+ }
+ // Although the plain scalar writer supports breaks, we never emit
+ // multiline plain scalars.
+ if (lineBreaks) {
+ allowFlowPlain = allowBlockPlain = false;
+ }
+ // Flow indicators are forbidden for flow plain scalars.
+ if (flowIndicators) {
+ allowFlowPlain = false;
+ }
+ // Block indicators are forbidden for block plain scalars.
+ if (blockIndicators) {
+ allowBlockPlain = false;
+ }
+
+ return new ScalarAnalysis(scalar, false, lineBreaks, allowFlowPlain, allowBlockPlain,
+ allowSingleQuoted, allowDoubleQuoted, allowBlock);
+ }
+
+ // Writers.
+
+ void flushStream() throws IOException {
+ stream.flush();
+ }
+
+ void writeStreamStart() {
+ // BOM is written by Writer.
+ }
+
+ void writeStreamEnd() throws IOException {
+ flushStream();
+ }
+
+ void writeIndicator(String indicator, boolean needWhitespace, boolean whitespace,
+ boolean indentation) throws IOException {
+ String data = null;
+ if (this.whitespace || !needWhitespace) {
+ data = indicator;
+ } else {
+ data = " " + indicator;
+ }
+ this.whitespace = whitespace;
+ this.indention = this.indention && indentation;
+ this.column += data.length();
+ openEnded = false;
+ stream.write(data);
+ }
+
+ void writeIndent() throws IOException {
+ int indent;
+ if (this.indent != null) {
+ indent = this.indent;
+ } else {
+ indent = 0;
+ }
+
+ if (!this.indention || this.column > indent || (this.column == indent && !this.whitespace)) {
+ writeLineBreak(null);
+ }
+
+ if (this.column < indent) {
+ this.whitespace = true;
+ StringBuffer data = new StringBuffer();
+ for (int i = 0; i < indent - this.column; i++) {
+ data.append(" ");
+ }
+ this.column = indent;
+ stream.write(data.toString());
+ }
+ }
+
+ private void writeLineBreak(String data) throws IOException {
+ if (data == null) {
+ data = this.bestLineBreak;
+ }
+ this.whitespace = true;
+ this.indention = true;
+ this.line++;
+ this.column = 0;
+ stream.write(data);
+ }
+
+ void writeVersionDirective(String versionText) throws IOException {
+ stream.write("%YAML " + versionText);
+ writeLineBreak(null);
+ }
+
+ void writeTagDirective(String handleText, String prefixText) throws IOException {
+ stream.write("%TAG " + handleText + " " + prefixText);
+ writeLineBreak(null);
+ }
+
+ // Scalar streams.
+ private void writeSingleQuoted(String text, boolean split) throws IOException {
+ writeIndicator("'", true, false, false);
+ boolean spaces = false;
+ boolean breaks = false;
+ int start = 0, end = 0;
+ char ch;
+ while (end <= text.length()) {
+ ch = 0;
+ if (end < text.length()) {
+ ch = text.charAt(end);
+ }
+ if (spaces) {
+ if (ch == 0 || ch != ' ') {
+ if (start + 1 == end && this.column > this.bestWidth && split && start != 0
+ && end != text.length()) {
+ writeIndent();
+ } else {
+ String data = text.substring(start, end);
+ this.column += data.length();
+ stream.write(data);
+ }
+ start = end;
+ }
+ } else if (breaks) {
+ if (ch == 0 || "\n\u0085\u2028\u2029".indexOf(ch) == -1) {
+ if (text.charAt(start) == '\n') {
+ writeLineBreak(null);
+ }
+ String data = text.substring(start, end);
+ for (char br : data.toCharArray()) {
+ if (br == '\n') {
+ writeLineBreak(null);
+ } else {
+ writeLineBreak(String.valueOf(br));
+ }
+ }
+ writeIndent();
+ start = end;
+ }
+ } else {
+ if (ch == 0 || " \n\u0085\u2028\u2029".indexOf(ch) != -1 || ch == '\'') {
+ if (start < end) {
+ String data = text.substring(start, end);
+ this.column += data.length();
+ stream.write(data);
+ start = end;
+ }
+ }
+ }
+ if (ch == '\'') {
+ String data = "''";
+ this.column += 2;
+ stream.write(data);
+ start = end + 1;
+ }
+ if (ch != 0) {
+ spaces = ch == ' ';
+ breaks = "\n\u0085\u2028\u2029".indexOf(ch) != -1;
+ }
+ end++;
+ }
+ writeIndicator("'", false, false, false);
+ }
+
+ private void writeDoubleQuoted(String text, boolean split) throws IOException {
+ writeIndicator("\"", true, false, false);
+ int start = 0;
+ int end = 0;
+ while (end <= text.length()) {
+ Character ch = null;
+ if (end < text.length()) {
+ ch = text.charAt(end);
+ }
+ if (ch == null || "\"\\\u0085\u2028\u2029\uFEFF".indexOf(ch) != -1
+ || !('\u0020' <= ch && ch <= '\u007E')) {
+ if (start < end) {
+ String data = text.substring(start, end);
+ this.column += data.length();
+ stream.write(data);
+ start = end;
+ }
+ if (ch != null) {
+ String data;
+ if (ESCAPE_REPLACEMENTS.containsKey(new Character(ch))) {
+ data = "\\" + ESCAPE_REPLACEMENTS.get(new Character(ch));
+ } else if (ch <= '\u00FF') {
+ String s = "0" + Integer.toString(ch, 16);
+ data = "\\x" + s.substring(s.length() - 2);
+ } else {
+ String s = "000" + Integer.toString(ch, 16);
+ data = "\\u" + s.substring(s.length() - 4);
+ }
+ this.column += data.length();
+ stream.write(data);
+ start = end + 1;
+ }
+ }
+ if ((0 < end && end < (text.length() - 1)) && (ch == ' ' || start >= end)
+ && (this.column + (end - start)) > this.bestWidth && split) {
+ String data;
+ if (start >= end) {
+ data = "\\";
+ } else {
+ data = text.substring(start, end) + "\\";
+ }
+ if (start < end) {
+ start = end;
+ }
+ this.column += data.length();
+ stream.write(data);
+ writeIndent();
+ this.whitespace = false;
+ this.indention = false;
+ if (text.charAt(start) == ' ') {
+ data = "\\";
+ this.column += data.length();
+ stream.write(data);
+ }
+ }
+ end += 1;
+ }
+ writeIndicator("\"", false, false, false);
+ }
+
+ private String determineBlockHints(String text) {
+ StringBuffer hints = new StringBuffer();
+ if (text != null && text.length() > 0) {
+ if (" \n\u0085\u2028\u2029".indexOf(text.charAt(0)) != -1) {
+ hints.append(bestIndent);
+ }
+ char ch1 = text.charAt(text.length() - 1);
+ if ("\n\u0085\u2028\u2029".indexOf(ch1) == -1) {
+ hints.append("-");
+ } else if (text.length() == 1
+ || ("\n\u0085\u2028\u2029".indexOf(text.charAt(text.length() - 2)) != -1)) {
+ hints.append("+");
+ }
+ }
+ return hints.toString();
+ }
+
+ void writeFolded(String text) throws IOException {
+ String hints = determineBlockHints(text);
+ writeIndicator(">" + hints, true, false, false);
+ if (hints.length() > 0 && (hints.charAt(hints.length() - 1) == '+')) {
+ openEnded = true;
+ }
+ writeLineBreak(null);
+ boolean leadingSpace = true;
+ boolean spaces = false;
+ boolean breaks = true;
+ int start = 0, end = 0;
+ while (end <= text.length()) {
+ char ch = 0;
+ if (end < text.length()) {
+ ch = text.charAt(end);
+ }
+ if (breaks) {
+ if (ch == 0 || ("\n\0085\u2028\u2029".indexOf(ch) == -1)) {
+ if (!leadingSpace && ch != 0 && ch != ' ' && text.charAt(start) == '\n') {
+ writeLineBreak(null);
+ }
+ leadingSpace = (ch == ' ');
+ String data = text.substring(start, end);
+ for (char br : data.toCharArray()) {
+ if (br == '\n') {
+ writeLineBreak(null);
+ } else {
+ writeLineBreak(String.valueOf(br));
+ }
+ }
+ if (ch != 0) {
+ writeIndent();
+ }
+ start = end;
+ }
+ } else if (spaces) {
+ if (ch != ' ') {
+ if (start + 1 == end && this.column > this.bestWidth) {
+ writeIndent();
+ } else {
+ String data = text.substring(start, end);
+ this.column += data.length();
+ stream.write(data);
+ }
+ start = end;
+ }
+ } else {
+ if (ch == 0 || " \n\0085\u2028\u2029".indexOf(ch) != -1) {
+ String data = text.substring(start, end);
+ stream.write(data);
+ if (ch == 0) {
+ writeLineBreak(null);
+ }
+ start = end;
+ }
+ }
+ if (ch != 0) {
+ breaks = ("\n\u0085\u2028\u2029".indexOf(ch) != -1);
+ spaces = (ch == ' ');
+ }
+ end++;
+ }
+ }
+
+ void writeLiteral(String text) throws IOException {
+ String hints = determineBlockHints(text);
+ writeIndicator("|" + hints, true, false, false);
+ if (hints.length() > 0 && (hints.charAt(hints.length() - 1)) == '+') {
+ openEnded = true;
+ }
+ writeLineBreak(null);
+ boolean breaks = true;
+ int start = 0, end = 0;
+ while (end <= text.length()) {
+ char ch = 0;
+ if (end < text.length()) {
+ ch = text.charAt(end);
+ }
+ if (breaks) {
+ if (ch == 0 || "\n\u0085\u2028\u2029".indexOf(ch) == -1) {
+ String data = text.substring(start, end);
+ for (char br : data.toCharArray()) {
+ if (br == '\n') {
+ writeLineBreak(null);
+ } else {
+ writeLineBreak(String.valueOf(br));
+ }
+ }
+ if (ch != 0) {
+ writeIndent();
+ }
+ start = end;
+ }
+ } else {
+ if (ch == 0 || "\n\u0085\u2028\u2029".indexOf(ch) != -1) {
+ String data = text.substring(start, end);
+ stream.write(data);
+ if (ch == 0) {
+ writeLineBreak(null);
+ }
+ start = end;
+ }
+ }
+ if (ch != 0) {
+ breaks = ("\n\u0085\u2028\u2029".indexOf(ch) != -1);
+ }
+ end++;
+ }
+ }
+
+ void writePlain(String text, boolean split) throws IOException {
+ if (rootContext) {
+ openEnded = true;
+ }
+ if (text == null || "".equals(text)) {
+ return;
+ }
+ if (!this.whitespace) {
+ String data = " ";
+ this.column += data.length();
+ stream.write(data);
+ }
+ this.whitespace = false;
+ this.indention = false;
+ boolean spaces = false;
+ boolean breaks = false;
+ int start = 0, end = 0;
+ while (end <= text.length()) {
+ char ch = 0;
+ if (end < text.length()) {
+ ch = text.charAt(end);
+ }
+ if (spaces) {
+ if (ch != ' ') {
+ if (start + 1 == end && this.column > this.bestWidth && split) {
+ writeIndent();
+ this.whitespace = false;
+ this.indention = false;
+ } else {
+ String data = text.substring(start, end);
+ this.column += data.length();
+ stream.write(data);
+ }
+ start = end;
+ }
+ } else if (breaks) {
+ if ("\n\u0085\u2028\u2029".indexOf(ch) == -1) {
+ if (text.charAt(start) == '\n') {
+ writeLineBreak(null);
+ }
+ String data = text.substring(start, end);
+ for (char br : data.toCharArray()) {
+ if (br == '\n') {
+ writeLineBreak(null);
+ } else {
+ writeLineBreak(String.valueOf(br));
+ }
+ }
+ writeIndent();
+ this.whitespace = false;
+ this.indention = false;
+ start = end;
+ }
+ } else {
+ if (ch == 0 || "\n\u0085\u2028\u2029".indexOf(ch) != -1) {
+ String data = text.substring(start, end);
+ this.column += data.length();
+ stream.write(data);
+ start = end;
+ }
+ }
+ if (ch != 0) {
+ spaces = (ch == ' ');
+ breaks = ("\n\u0085\u2028\u2029".indexOf(ch) != -1);
+ }
+ end++;
+ }
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/emitter/EmitterException.java b/src/main/java/org/yaml/snakeyaml/emitter/EmitterException.java
new file mode 100644
index 00000000..b63e0c4e
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/emitter/EmitterException.java
@@ -0,0 +1,17 @@
+/*
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.emitter;
+
+import org.yaml.snakeyaml.error.YAMLException;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+public class EmitterException extends YAMLException {
+ private static final long serialVersionUID = -8280070025452995908L;
+
+ public EmitterException(String msg) {
+ super(msg);
+ }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/emitter/EmitterState.java b/src/main/java/org/yaml/snakeyaml/emitter/EmitterState.java
new file mode 100755
index 00000000..e7667fb5
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/emitter/EmitterState.java
@@ -0,0 +1,15 @@
+/**
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.emitter;
+
+import java.io.IOException;
+
+/**
+ * Python's methods are first class object. Java needs a class.
+ *
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+interface EmitterState {
+ void expect() throws IOException;
+} \ No newline at end of file
diff --git a/src/main/java/org/yaml/snakeyaml/emitter/ScalarAnalysis.java b/src/main/java/org/yaml/snakeyaml/emitter/ScalarAnalysis.java
new file mode 100644
index 00000000..61ea599b
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/emitter/ScalarAnalysis.java
@@ -0,0 +1,31 @@
+/**
+ * See LICENSE file in distribution for copyright and licensing information.
+ */
+package org.yaml.snakeyaml.emitter;
+
+/**
+ * @see <a href="http://pyyaml.org/wiki/PyYAML">PyYAML</a> for more information
+ */
+final class ScalarAnalysis {
+ public String scalar;
+ public boolean empty;
+ public boolean multiline;
+ public boolean allowFlowPlain;
+ public boolean allowBlockPlain;
+ public boolean allowSingleQuoted;
+ public boolean allowDoubleQuoted;
+ public boolean allowBlock;
+
+ public ScalarAnalysis(String scalar, boolean empty, boolean multiline, boolean allowFlowPlain,
+ boolean allowBlockPlain, boolean allowSingleQuoted, boolean allowDoubleQuoted,
+ boolean allowBlock) {
+ this.scalar = scalar;
+ this.empty = empty;
+ this.multiline = multiline;
+ this.allowFlowPlain = allowFlowPlain;
+ this.allowBlockPlain = allowBlockPlain;
+ this.allowSingleQuoted = allowSingleQuoted;
+ this.allowDoubleQuoted = allowDoubleQuoted;
+ this.allowBlock = allowBlock;
+ }
+} \ No newline at end of file