All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.fasterxml.jackson.dataformat.yaml.YAMLGenerator Maven / Gradle / Ivy

Go to download

Easy Redis Java client and Real-Time Data Platform. Valkey compatible. Sync/Async/RxJava3/Reactive API. Client side caching. Over 50 Redis based Java objects and services: JCache API, Apache Tomcat, Hibernate, Spring, Set, Multimap, SortedSet, Map, List, Queue, Deque, Semaphore, Lock, AtomicLong, Map Reduce, Bloom filter, Scheduler, RPC

The newest version!
package com.fasterxml.jackson.dataformat.yaml;

import java.io.*;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.Collections;
import java.util.Map;
import java.util.regex.Pattern;

import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.DumperOptions.FlowStyle;
import org.yaml.snakeyaml.emitter.Emitter;
import org.yaml.snakeyaml.events.*;
import org.yaml.snakeyaml.nodes.Tag;

import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.core.base.GeneratorBase;
import com.fasterxml.jackson.core.json.JsonWriteContext;
import com.fasterxml.jackson.core.util.JacksonFeatureSet;
import com.fasterxml.jackson.dataformat.yaml.util.StringQuotingChecker;
import com.fasterxml.jackson.core.io.IOContext;

public class YAMLGenerator extends GeneratorBase
{
    /**
     * Enumeration that defines all togglable features for YAML generators
     */
    public enum Feature implements FormatFeature // since 2.9
    {
        /**
         * Whether we are to write an explicit document start marker ("---")
         * or not.
         *
         * @since 2.3
         */
        WRITE_DOC_START_MARKER(true),

        /**
         * Whether to use YAML native Object Id construct for indicating type (true);
         * or "generic" Object Id mechanism (false). Former works better for systems that
         * are YAML-centric; latter may be better choice for interoperability, when
         * converting between formats or accepting other formats.
         *
         * @since 2.5
         */
        USE_NATIVE_OBJECT_ID(true),

        /**
         * Whether to use YAML native Type Id construct for indicating type (true);
         * or "generic" type property (false). Former works better for systems that
         * are YAML-centric; latter may be better choice for interoperability, when
         * converting between formats or accepting other formats.
         *
         * @since 2.5
         */
        USE_NATIVE_TYPE_ID(true),

        /**
         * Do we try to force so-called canonical output or not.
         * 

* Ignored if you provide your own {@code DumperOptions}. *

*/ CANONICAL_OUTPUT(false), /** * Options passed to SnakeYAML that determines whether longer textual content * gets automatically split into multiple lines or not. *

* Feature is enabled by default to conform to SnakeYAML defaults as well as * backwards compatibility with 2.5 and earlier versions. *

*

* Ignored if you provide your own {@code DumperOptions}. *

* * @since 2.6 */ SPLIT_LINES(true), /** * Whether strings will be rendered without quotes (true) or * with quotes (false, default). *

* Minimized quote usage makes for more human readable output; however, content is * limited to printable characters according to the rules of * literal block style. *

* * @since 2.7 */ MINIMIZE_QUOTES(false), /** * Whether numbers stored as strings will be rendered with quotes (true) or * without quotes (false, default) when MINIMIZE_QUOTES is enabled. *

* Minimized quote usage makes for more human readable output; however, content is * limited to printable characters according to the rules of * literal block style. *

* * @since 2.8.2 */ ALWAYS_QUOTE_NUMBERS_AS_STRINGS(false), /** * Whether for string containing newlines a * literal block style * should be used. This automatically enabled when {@link #MINIMIZE_QUOTES} is set. *

* The content of such strings is limited to printable characters according to the rules of * literal block style. *

* * @since 2.9 */ LITERAL_BLOCK_STYLE(false), /** * Feature enabling of which adds indentation for array entry generation * (default indentation being 2 spaces). *

* Default value is {@code false} for backwards compatibility *

*

* Ignored if you provide your own {@code DumperOptions}. *

* * @since 2.9 */ INDENT_ARRAYS(false), /** * Feature enabling of which adds indentation with indicator for array entry generation * (default indentation being 2 spaces). *

* Default value is {@code false} for backwards compatibility *

*

* Ignored if you provide your own {@code DumperOptions}. *

* * @since 2.12 */ INDENT_ARRAYS_WITH_INDICATOR(false), /** * Option passed to SnakeYAML that determines if the line breaks used for * serialization should be same as what the default is for current platform. * If disabled, Unix linefeed ({@code \n}) will be used. *

* Default value is {@code false} for backwards compatibility *

*

* Ignored if you provide your own {@code DumperOptions}. *

* * @since 2.9.6 */ USE_PLATFORM_LINE_BREAKS(false), /** * Option passed to SnakeYAML to allows writing key longer that 128 characters * (up to 1024 characters). * If disabled, the max key length is left as 128 characters: longer names * are truncated. If enabled, limit is raised to 1024 characters. *

* Default value is {@code false} for backwards-compatibility (same as behavior * before this feature was added). *

*

* Ignored if you provide your own {@code DumperOptions}. *

* * @since 2.14 */ ALLOW_LONG_KEYS(false), ; protected final boolean _defaultState; protected final int _mask; /** * Method that calculates bit set (flags) of all features that * are enabled by default. */ public static int collectDefaults() { int flags = 0; for (Feature f : values()) { if (f.enabledByDefault()) { flags |= f.getMask(); } } return flags; } private Feature(boolean defaultState) { _defaultState = defaultState; _mask = (1 << ordinal()); } @Override public boolean enabledByDefault() { return _defaultState; } @Override public boolean enabledIn(int flags) { return (flags & _mask) != 0; } @Override public int getMask() { return _mask; } } /* /********************************************************************** /* Internal constants /********************************************************************** */ protected final static long MIN_INT_AS_LONG = (long) Integer.MIN_VALUE; protected final static long MAX_INT_AS_LONG = (long) Integer.MAX_VALUE; protected final static Pattern PLAIN_NUMBER_P = Pattern.compile("[+-]?[0-9]*(\\.[0-9]*)?"); protected final static String TAG_BINARY = Tag.BINARY.toString(); /* /********************************************************************** /* Configuration /********************************************************************** */ /** * @since 2.16 */ protected final StreamWriteConstraints _streamWriteConstraints; /** * Bit flag composed of bits that indicate which * {@link YAMLGenerator.Feature}s * are enabled. */ protected int _formatFeatures; protected Writer _writer; protected DumperOptions _outputOptions; protected final org.yaml.snakeyaml.DumperOptions.Version _docVersion; // for field names, leave out quotes private final static DumperOptions.ScalarStyle STYLE_UNQUOTED_NAME = DumperOptions.ScalarStyle.PLAIN; // numbers, booleans, should use implicit private final static DumperOptions.ScalarStyle STYLE_SCALAR = DumperOptions.ScalarStyle.PLAIN; // Strings quoted for fun private final static DumperOptions.ScalarStyle STYLE_QUOTED = DumperOptions.ScalarStyle.DOUBLE_QUOTED; // Strings in literal (block) style private final static DumperOptions.ScalarStyle STYLE_LITERAL = DumperOptions.ScalarStyle.LITERAL; // Which flow style to use for Base64? Maybe basic quoted? // 29-Nov-2017, tatu: Actually SnakeYAML uses block style so: private final static DumperOptions.ScalarStyle STYLE_BASE64 = STYLE_LITERAL; private final static DumperOptions.ScalarStyle STYLE_PLAIN = DumperOptions.ScalarStyle.PLAIN; /* /********************************************************************** /* Output state /********************************************************************** */ protected Emitter _emitter; /** * YAML supports native Object identifiers, so databinder may indicate * need to output one. */ protected String _objectId; /** * YAML supports native Type identifiers, so databinder may indicate * need to output one. */ protected String _typeId; protected int _rootValueCount; protected final StringQuotingChecker _quotingChecker; /* /********************************************************** /* Life-cycle /********************************************************** */ public YAMLGenerator(IOContext ctxt, int jsonFeatures, int yamlFeatures, StringQuotingChecker quotingChecker, ObjectCodec codec, Writer out, org.yaml.snakeyaml.DumperOptions.Version version) throws IOException { super(jsonFeatures, codec, ctxt); _streamWriteConstraints = ctxt.streamWriteConstraints(); _formatFeatures = yamlFeatures; _quotingChecker = (quotingChecker == null) ? StringQuotingChecker.Default.instance() : quotingChecker; _writer = out; _docVersion = version; _outputOptions = buildDumperOptions(jsonFeatures, yamlFeatures, version); _emitter = new Emitter(_writer, _outputOptions); // should we start output now, or try to defer? _emit(new StreamStartEvent(null, null)); _emitStartDocument(); } /** * @since 2.14 */ public YAMLGenerator(IOContext ctxt, int jsonFeatures, int yamlFeatures, StringQuotingChecker quotingChecker, ObjectCodec codec, Writer out, org.yaml.snakeyaml.DumperOptions dumperOptions) throws IOException { super(jsonFeatures, codec, ctxt); _streamWriteConstraints = ctxt.streamWriteConstraints(); _formatFeatures = yamlFeatures; _quotingChecker = (quotingChecker == null) ? StringQuotingChecker.Default.instance() : quotingChecker; _writer = out; _docVersion = dumperOptions.getVersion(); _outputOptions = dumperOptions; _emitter = new Emitter(_writer, _outputOptions); // should we start output now, or try to defer? _emit(new StreamStartEvent(null, null)); _emitStartDocument(); } @Deprecated // since 2.12 public YAMLGenerator(IOContext ctxt, int jsonFeatures, int yamlFeatures, ObjectCodec codec, Writer out, org.yaml.snakeyaml.DumperOptions.Version version) throws IOException { this(ctxt, jsonFeatures, yamlFeatures, null, codec, out, version); } protected DumperOptions buildDumperOptions(int jsonFeatures, int yamlFeatures, org.yaml.snakeyaml.DumperOptions.Version version) { DumperOptions opt = new DumperOptions(); // would we want canonical? if (Feature.CANONICAL_OUTPUT.enabledIn(_formatFeatures)) { opt.setCanonical(true); } else { opt.setCanonical(false); // if not, MUST specify flow styles opt.setDefaultFlowStyle(FlowStyle.BLOCK); } // split-lines for text blocks? opt.setSplitLines(Feature.SPLIT_LINES.enabledIn(_formatFeatures)); // array indentation? if (Feature.INDENT_ARRAYS.enabledIn(_formatFeatures)) { // But, wrt [dataformats-text#34]: need to set both to diff values to work around bug // (otherwise indentation level is "invisible". Note that this should NOT be necessary // but is needed up to at least SnakeYAML 1.18. // Also looks like all kinds of values do work, except for both being 2... weird. opt.setIndicatorIndent(1); opt.setIndent(2); } // [dataformats-text#175]: further configurability that overrides prev setting if (Feature.INDENT_ARRAYS_WITH_INDICATOR.enabledIn(_formatFeatures)) { opt.setIndicatorIndent(2); opt.setIndentWithIndicator(true); } // 14-May-2018: [dataformats-text#84] allow use of platform linefeed if (Feature.USE_PLATFORM_LINE_BREAKS.enabledIn(_formatFeatures)) { opt.setLineBreak(DumperOptions.LineBreak.getPlatformLineBreak()); } if (Feature.ALLOW_LONG_KEYS.enabledIn(_formatFeatures)) { opt.setMaxSimpleKeyLength(1024); } return opt; } @Override public StreamWriteConstraints streamWriteConstraints() { return _streamWriteConstraints; } /* /********************************************************************** /* Versioned /********************************************************************** */ @Override public Version version() { return PackageVersion.VERSION; } /* /********************************************************************** /* Overridden methods, configuration /********************************************************************** */ /** * Not sure what to do here; could reset indentation to some value maybe? */ @Override public YAMLGenerator useDefaultPrettyPrinter() { return this; } /** * Not sure what to do here; will always indent, but uses * YAML-specific settings etc. */ @Override public YAMLGenerator setPrettyPrinter(PrettyPrinter pp) { return this; } @Override public Object getOutputTarget() { return _writer; } /** * SnakeYAML does not expose buffered content amount, so we can only return * -1 from here */ @Override public int getOutputBuffered() { return -1; } @Override public int getFormatFeatures() { return _formatFeatures; } @Override public JsonGenerator overrideFormatFeatures(int values, int mask) { // 14-Mar-2016, tatu: Should re-configure, but unfortunately most // settings passed via options passed to constructor of Emitter _formatFeatures = (_formatFeatures & ~mask) | (values & mask); return this; } @Override public boolean canUseSchema(FormatSchema schema) { return false; } @Override public boolean canWriteFormattedNumbers() { return true; } @Override // @since 2.12 public JacksonFeatureSet getWriteCapabilities() { return DEFAULT_TEXTUAL_WRITE_CAPABILITIES; } /* /********************************************************************** /* Extended API, configuration /********************************************************************** */ public YAMLGenerator enable(YAMLGenerator.Feature f) { _formatFeatures |= f.getMask(); return this; } public YAMLGenerator disable(YAMLGenerator.Feature f) { _formatFeatures &= ~f.getMask(); return this; } public final boolean isEnabled(YAMLGenerator.Feature f) { return (_formatFeatures & f.getMask()) != 0; } public YAMLGenerator configure(YAMLGenerator.Feature f, boolean state) { if (state) { enable(f); } else { disable(f); } return this; } /* /********************************************************************** /* Overridden methods; writing field names /********************************************************************** */ /* And then methods overridden to make final, streamline some * aspects... */ @Override public final void writeFieldName(String name) throws IOException { if (_writeContext.writeFieldName(name) == JsonWriteContext.STATUS_EXPECT_VALUE) { _reportError("Can not write a field name, expecting a value"); } _writeFieldName(name); } @Override public final void writeFieldName(SerializableString name) throws IOException { // Object is a value, need to verify it's allowed if (_writeContext.writeFieldName(name.getValue()) == JsonWriteContext.STATUS_EXPECT_VALUE) { _reportError("Can not write a field name, expecting a value"); } _writeFieldName(name.getValue()); } @Override // override since 2.10 (method added in 2.8) public void writeFieldId(long id) throws IOException { // 24-Jul-2019, tatu: Should not force construction of a String here... String idStr = Long.valueOf(id).toString(); // since instances for small values cached if (_writeContext.writeFieldName(idStr) == JsonWriteContext.STATUS_EXPECT_VALUE) { _reportError("Can not write a field id, expecting a value"); } // to avoid quoting // _writeFieldName(idStr); _writeScalar(idStr, "int", STYLE_SCALAR); } private final void _writeFieldName(String name) throws IOException { _writeScalar(name, "string", _quotingChecker.needToQuoteName(name) ? STYLE_QUOTED : STYLE_UNQUOTED_NAME); } /* /********************************************************************** /* Public API: low-level I/O /********************************************************************** */ @Override public final void flush() throws IOException { if (isEnabled(JsonGenerator.Feature.FLUSH_PASSED_TO_STREAM)) { _writer.flush(); } } @Override public void close() throws IOException { if (!isClosed()) { // 11-Dec-2019, tatu: Should perhaps check if content is to be auto-closed... // but need END_DOCUMENT regardless _emitEndDocument(); _emit(new StreamEndEvent(null, null)); /* 25-Nov-2008, tatus: As per [JACKSON-16] we are not to call close() * on the underlying Reader, unless we "own" it, or auto-closing * feature is enabled. * One downside: when using UTF8Writer, underlying buffer(s) * may not be properly recycled if we don't close the writer. */ if (_writer != null) { if (_ioContext.isResourceManaged() || isEnabled(JsonGenerator.Feature.AUTO_CLOSE_TARGET)) { _writer.close(); } else if (isEnabled(JsonGenerator.Feature.FLUSH_PASSED_TO_STREAM)) { // If we can't close it, we should at least flush _writer.flush(); } } super.close(); } } /* /********************************************************************** /* Public API: structural output /********************************************************************** */ @Override public final void writeStartArray() throws IOException { _verifyValueWrite("start an array"); _writeContext = _writeContext.createChildArrayContext(); _streamWriteConstraints.validateNestingDepth(_writeContext.getNestingDepth()); FlowStyle style = _outputOptions.getDefaultFlowStyle(); String yamlTag = _typeId; boolean implicit = (yamlTag == null); String anchor = _objectId; if (anchor != null) { _objectId = null; } _emit(new SequenceStartEvent(anchor, yamlTag, implicit, null, null, style)); } @Override public final void writeEndArray() throws IOException { if (!_writeContext.inArray()) { _reportError("Current context not Array but "+_writeContext.typeDesc()); } // just to make sure we don't "leak" type ids _typeId = null; _writeContext = _writeContext.getParent(); _emit(new SequenceEndEvent(null, null)); } @Override public final void writeStartObject() throws IOException { _verifyValueWrite("start an object"); _writeContext = _writeContext.createChildObjectContext(); _streamWriteConstraints.validateNestingDepth(_writeContext.getNestingDepth()); FlowStyle style = _outputOptions.getDefaultFlowStyle(); String yamlTag = _typeId; boolean implicit = (yamlTag == null); String anchor = _objectId; if (anchor != null) { _objectId = null; } _emit(new MappingStartEvent(anchor, yamlTag, implicit, null, null, style)); } @Override public final void writeEndObject() throws IOException { if (!_writeContext.inObject()) { _reportError("Current context not Object but "+_writeContext.typeDesc()); } // just to make sure we don't "leak" type ids _typeId = null; _writeContext = _writeContext.getParent(); _emit(new MappingEndEvent(null, null)); } /* /********************************************************************** /* Output method implementations, textual /********************************************************************** */ @Override public void writeString(String text) throws IOException,JsonGenerationException { if (text == null) { writeNull(); return; } _verifyValueWrite("write String value"); // [dataformats-text#50]: Empty String always quoted if (text.isEmpty()) { _writeScalar(text, "string", STYLE_QUOTED); return; } DumperOptions.ScalarStyle style; if (Feature.MINIMIZE_QUOTES.enabledIn(_formatFeatures)) { if (text.indexOf('\n') >= 0) { style = STYLE_LITERAL; // If one of reserved values ("true", "null"), or, number, preserve quoting: } else if (_quotingChecker.needToQuoteValue(text) || (Feature.ALWAYS_QUOTE_NUMBERS_AS_STRINGS.enabledIn(_formatFeatures) && PLAIN_NUMBER_P.matcher(text).matches()) ) { style = STYLE_QUOTED; } else { style = STYLE_PLAIN; } } else { if (Feature.LITERAL_BLOCK_STYLE.enabledIn(_formatFeatures) && text.indexOf('\n') >= 0) { style = STYLE_LITERAL; } else { style = STYLE_QUOTED; } } _writeScalar(text, "string", style); } @Override public void writeString(char[] text, int offset, int len) throws IOException { writeString(new String(text, offset, len)); } @Override public final void writeString(SerializableString sstr) throws IOException { writeString(sstr.toString()); } @Override public void writeRawUTF8String(byte[] text, int offset, int len) throws IOException { _reportUnsupportedOperation(); } @Override public final void writeUTF8String(byte[] text, int offset, int len) throws IOException { writeString(new String(text, offset, len, "UTF-8")); } /* /********************************************************************** /* Output method implementations, unprocessed ("raw") /********************************************************************** */ @Override public void writeRaw(String text) throws IOException { _reportUnsupportedOperation(); } @Override public void writeRaw(String text, int offset, int len) throws IOException { _reportUnsupportedOperation(); } @Override public void writeRaw(char[] text, int offset, int len) throws IOException { _reportUnsupportedOperation(); } @Override public void writeRaw(char c) throws IOException { _reportUnsupportedOperation(); } @Override public void writeRawValue(String text) throws IOException { _reportUnsupportedOperation(); } @Override public void writeRawValue(String text, int offset, int len) throws IOException { _reportUnsupportedOperation(); } @Override public void writeRawValue(char[] text, int offset, int len) throws IOException { _reportUnsupportedOperation(); } /* /********************************************************************** /* Output method implementations, base64-encoded binary /********************************************************************** */ @Override public void writeBinary(Base64Variant b64variant, byte[] data, int offset, int len) throws IOException { if (data == null) { writeNull(); return; } _verifyValueWrite("write Binary value"); if (offset > 0 || (offset+len) != data.length) { data = Arrays.copyOfRange(data, offset, offset+len); } _writeScalarBinary(b64variant, data); } /* /********************************************************************** /* Output method implementations, scalars /********************************************************************** */ @Override public void writeBoolean(boolean state) throws IOException { _verifyValueWrite("write boolean value"); _writeScalar(state ? "true" : "false", "bool", STYLE_SCALAR); } @Override public void writeNumber(int i) throws IOException { _verifyValueWrite("write number"); _writeScalar(String.valueOf(i), "int", STYLE_SCALAR); } @Override public void writeNumber(long l) throws IOException { // First: maybe 32 bits is enough? if (l <= MAX_INT_AS_LONG && l >= MIN_INT_AS_LONG) { writeNumber((int) l); return; } _verifyValueWrite("write number"); _writeScalar(String.valueOf(l), "long", STYLE_SCALAR); } @Override public void writeNumber(BigInteger v) throws IOException { if (v == null) { writeNull(); return; } _verifyValueWrite("write number"); _writeScalar(String.valueOf(v.toString()), "java.math.BigInteger", STYLE_SCALAR); } @Override public void writeNumber(double d) throws IOException { _verifyValueWrite("write number"); _writeScalar(String.valueOf(d), "double", STYLE_SCALAR); } @Override public void writeNumber(float f) throws IOException { _verifyValueWrite("write number"); _writeScalar(String.valueOf(f), "float", STYLE_SCALAR); } @Override public void writeNumber(BigDecimal dec) throws IOException { if (dec == null) { writeNull(); return; } _verifyValueWrite("write number"); String str = isEnabled(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN) ? dec.toPlainString() : dec.toString(); _writeScalar(str, "java.math.BigDecimal", STYLE_SCALAR); } @Override public void writeNumber(String encodedValue) throws IOException,JsonGenerationException, UnsupportedOperationException { if (encodedValue == null) { writeNull(); return; } _verifyValueWrite("write number"); _writeScalar(encodedValue, "number", STYLE_SCALAR); } @Override public void writeNull() throws IOException { _verifyValueWrite("write null value"); // no real type for this, is there? _writeScalar("null", "object", STYLE_SCALAR); } /* /********************************************************************** /* Public API, write methods, Native Ids /********************************************************************** */ @Override public boolean canWriteObjectId() { // yes, YAML does support Native Type Ids! // 10-Sep-2014, tatu: Except as per [#23] might not want to... return Feature.USE_NATIVE_OBJECT_ID.enabledIn(_formatFeatures); } @Override public boolean canWriteTypeId() { // yes, YAML does support Native Type Ids! // 10-Sep-2014, tatu: Except as per [#22] might not want to... return Feature.USE_NATIVE_TYPE_ID.enabledIn(_formatFeatures); } @Override public void writeTypeId(Object id) throws IOException { // should we verify there's no preceding type id? _typeId = String.valueOf(id); } @Override public void writeObjectRef(Object id) throws IOException { _verifyValueWrite("write Object reference"); AliasEvent evt = new AliasEvent(String.valueOf(id), null, null); _emit(evt); } @Override public void writeObjectId(Object id) throws IOException { // should we verify there's no preceding id? _objectId = (id == null) ? null : String.valueOf(id); } /* /********************************************************************** /* Implementations for methods from base class /********************************************************************** */ @Override protected final void _verifyValueWrite(String typeMsg) throws IOException { int status = _writeContext.writeValue(); if (status == JsonWriteContext.STATUS_EXPECT_NAME) { _reportError("Can not "+typeMsg+", expecting field name"); } if (_writeContext.inRoot()) { // Start-doc emitted when creating generator, but otherwise need it; similarly, // need matching end-document to close earlier open one if (_writeContext.getCurrentIndex() > 0) { _emitEndDocument(); _emitStartDocument(); } } } @Override protected void _releaseBuffers() { // nothing special to do... } /* /********************************************************************** /* Internal methods /********************************************************************** */ // Implicit means that (type) tags won't be shown, right? private final static ImplicitTuple NO_TAGS = new ImplicitTuple(true, true); // ... and sometimes we specifically DO want explicit tag: private final static ImplicitTuple EXPLICIT_TAGS = new ImplicitTuple(false, false); protected void _writeScalar(String value, String type, DumperOptions.ScalarStyle style) throws IOException { _emit(_scalarEvent(value, style)); } private void _writeScalarBinary(Base64Variant b64variant, byte[] data) throws IOException { // 15-Dec-2017, tatu: as per [dataformats-text#62], can not use SnakeYAML's internal // codec. Also: force use of linefeed variant if using default if (b64variant == Base64Variants.getDefaultVariant()) { b64variant = Base64Variants.MIME; } final String lf = _lf(); String encoded = _base64encode(b64variant, data, lf); _emit(new ScalarEvent(null, TAG_BINARY, EXPLICIT_TAGS, encoded, null, null, STYLE_BASE64)); } protected ScalarEvent _scalarEvent(String value, DumperOptions.ScalarStyle style) { String yamlTag = _typeId; if (yamlTag != null) { _typeId = null; } String anchor = _objectId; if (anchor != null) { _objectId = null; } // 29-Nov-2017, tatu: Not 100% sure why we don't force explicit tags for // type id, but trying to do so seems to double up tag output... return new ScalarEvent(anchor, yamlTag, NO_TAGS, value, null, null, style); } // // // 26-Feb-2019, tatu: Copied temporarily (for 2.10) from `Base64Variant` to prevent // // // hard dependency for same minor version private String _base64encode(final Base64Variant b64v, final byte[] input, final String linefeed) { final int inputEnd = input.length; final StringBuilder sb = new StringBuilder(inputEnd + (inputEnd >> 2) + (inputEnd >> 3)); int chunksBeforeLF = b64v.getMaxLineLength() >> 2; int inputPtr = 0; int safeInputEnd = inputEnd-3; while (inputPtr <= safeInputEnd) { int b24 = ((int) input[inputPtr++]) << 8; b24 |= ((int) input[inputPtr++]) & 0xFF; b24 = (b24 << 8) | (((int) input[inputPtr++]) & 0xFF); b64v.encodeBase64Chunk(sb, b24); if (--chunksBeforeLF <= 0) { sb.append(linefeed); chunksBeforeLF = b64v.getMaxLineLength() >> 2; } } int inputLeft = inputEnd - inputPtr; if (inputLeft > 0) { int b24 = ((int) input[inputPtr++]) << 16; if (inputLeft == 2) { b24 |= (((int) input[inputPtr++]) & 0xFF) << 8; } b64v.encodeBase64Partial(sb, b24, inputLeft); } return sb.toString(); } protected String _lf() { return _outputOptions.getLineBreak().getString(); } // @since 2.10.2 protected void _emitStartDocument() throws IOException { Map noTags = Collections.emptyMap(); boolean startMarker = Feature.WRITE_DOC_START_MARKER.enabledIn(_formatFeatures); _emit(new DocumentStartEvent(null, null, startMarker, _docVersion, // for 1.10 was: ((version == null) ? null : version.getArray()), noTags)); } // @since 2.10.2 protected void _emitEndDocument() throws IOException { _emit(new DocumentEndEvent(null, null, false)); } // @since 2.10.2 protected final void _emit(Event e) throws IOException { _emitter.emit(e); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy